diff --git a/app/main_dev/launch.js b/app/main_dev/launch.js index 50c317bb8b..8460484597 100644 --- a/app/main_dev/launch.js +++ b/app/main_dev/launch.js @@ -15,6 +15,10 @@ const logger = createLogger(debug); let dcrdPID; let dcrwPID; +// windows-only stuff +let dcrwPipeRx; +let dcrdPipeRx; + let dcrwPort; function closeClis() { @@ -30,6 +34,13 @@ function closeDCRD() { if (require("is-running")(dcrdPID) && os.platform() != "win32") { logger.log("info", "Sending SIGINT to dcrd at pid:" + dcrdPID); process.kill(dcrdPID, "SIGINT"); + } else if (require("is-running")(dcrdPID)) { + try { + const win32ipc = require("../node_modules/win32ipc/build/Release/win32ipc.node"); + win32ipc.closePipe(dcrdPipeRx); + } catch (e) { + logger.log("error", "Error closing dcrd piperx: " + e); + } } } @@ -38,6 +49,13 @@ export const closeDCRW = () => { if (require("is-running")(dcrwPID) && os.platform() != "win32") { logger.log("info", "Sending SIGINT to dcrwallet at pid:" + dcrwPID); process.kill(dcrwPID, "SIGINT"); + } else if (require("is-running")(dcrwPID)) { + try { + const win32ipc = require("../node_modules/win32ipc/build/Release/win32ipc.node"); + win32ipc.closePipe(dcrwPipeRx); + } catch (e) { + logger.log("error", "Error closing dcrwallet piperx: " + e); + } } dcrwPID = null; return true; @@ -105,8 +123,8 @@ export const launchDCRD = (mainWindow, daemonIsAdvanced, daemonPath, appdata, te try { const util = require("util"); const win32ipc = require("../node_modules/win32ipc/build/Release/win32ipc.node"); - var pipe = win32ipc.createPipe("out"); - args.push(util.format("--piperx=%d", pipe.readEnd)); + dcrdPipeRx = win32ipc.createPipe("out"); + args.push(util.format("--piperx=%d", dcrdPipeRx.readEnd)); } catch (e) { logger.log("error", "can't find proper module to launch dcrd: " + e); } @@ -191,8 +209,8 @@ export const launchDCRWallet = (mainWindow, daemonIsAdvanced, walletPath, testne try { const util = require("util"); const win32ipc = require("../node_modules/win32ipc/build/Release/win32ipc.node"); - const pipe = win32ipc.createPipe("out"); - args.push(util.format("--piperx=%d", pipe.readEnd)); + dcrwPipeRx = win32ipc.createPipe("out"); + args.push(util.format("--piperx=%d", dcrwPipeRx.readEnd)); } catch (e) { logger.log("error", "can't find proper module to launch dcrwallet: " + e); } diff --git a/app/modules/win32ipc/module.cc b/app/modules/win32ipc/module.cc index 6ed8b05e72..82eeb25ed7 100644 --- a/app/modules/win32ipc/module.cc +++ b/app/modules/win32ipc/module.cc @@ -6,7 +6,7 @@ void CreatePipe(v8::FunctionCallbackInfo const& args) { auto isolate = v8::Isolate::GetCurrent(); - + if (args.Length() != 1) { isolate->ThrowException(v8::Exception::TypeError( v8::String::NewFromUtf8(isolate, "Wrong number of arguments"))); @@ -56,10 +56,58 @@ void CreatePipe(v8::FunctionCallbackInfo const& args) { args.GetReturnValue().Set(obj); } +void ClosePipe(v8::FunctionCallbackInfo const& args) { + auto isolate = v8::Isolate::GetCurrent(); + + if (args.Length() != 1) { + isolate->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(isolate, "Wrong number of arguments"))); + return; + } + + if (!args[0]->IsObject()) { + isolate->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(isolate, "Argument type error"))); + return; + } + + auto obj = args[0]->ToObject(); + auto read_end_prop = v8::String::NewFromUtf8(isolate, "readEnd"); + auto write_end_prop = v8::String::NewFromUtf8(isolate, "writeEnd"); + auto context = isolate->GetCurrentContext(); + + if (!obj->Has(context, read_end_prop).ToChecked()) { + isolate->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(isolate, "Object does not have readEnd prop"))); + return; + } + + if (!obj->Has(context, write_end_prop).ToChecked()) { + isolate->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(isolate, "Object does not have writeEnd prop"))); + return; + } + + uintptr_t read_end_handle = (uintptr_t) obj->Get(context, read_end_prop) + .ToLocalChecked()->Int32Value(context).ToChecked(); + uintptr_t write_end_handle = (uintptr_t) obj->Get(context, write_end_prop) + .ToLocalChecked()->Int32Value(context).ToChecked(); + char const *close_error_msg = pipe_wrapper::close_pipe_end(read_end_handle, write_end_handle); + + if (close_error_msg != nullptr) { + isolate->ThrowException(v8::Exception::Error( + v8::String::NewFromUtf8(isolate, close_error_msg))); + return; + } +} + + void Init(v8::Handle exports) { auto isolate = v8::Isolate::GetCurrent(); exports->Set(v8::String::NewFromUtf8(isolate, "createPipe"), v8::FunctionTemplate::New(isolate, CreatePipe)->GetFunction()); + exports->Set(v8::String::NewFromUtf8(isolate, "closePipe"), + v8::FunctionTemplate::New(isolate, ClosePipe)->GetFunction()); } NODE_MODULE(win32ipc, Init) diff --git a/app/modules/win32ipc/moduleTestWallet.js b/app/modules/win32ipc/moduleTestWallet.js new file mode 100644 index 0000000000..92b9ff9e68 --- /dev/null +++ b/app/modules/win32ipc/moduleTestWallet.js @@ -0,0 +1,40 @@ +// Sample script to test the namedpiperx option of dcrwallet in windows. +// Requires that a wallet config exists in the default decrediton config dir, +// with a wallet name "default-wallet". + +const childProcess = require("child_process"); +const addon = require("./build/Release/win32ipc"); +const path = require("path"); +const os = require("os"); + +//const pipeFname = "\\\\.\\pipe\\dcrwallet-test"; +const walletConfPath = path.join(os.homedir(), "AppData", "Local", "Decrediton", + "wallets", "testnet", "default-wallet", "dcrwallet.conf"); + +function sleep(milli) { + return new Promise(resolve => setTimeout(resolve, milli)); +} + +async function test() { + try { + const pipe = addon.createPipe("out"); + childProcess.spawn("dcrwallet", [ + `-C ${walletConfPath}`, + `--piperx ${pipe.readEnd}`, "--debuglevel DCRW=TRACE" + ], { "detached": true, "shell": true }); + + console.log(pipe); + await sleep(7000); + console.log("Slept to test some. Will try to close the pipe."); + console.log(addon.closePipe(pipe)); + console.log("Closed the pipe!"); + } catch (error) { + console.log("Error"); + console.log(error); + return; + } +} + +setTimeout(test, 3000); + +setTimeout(function () { process.exit(0); }, 15000); diff --git a/app/modules/win32ipc/pipe_wrapper.cc b/app/modules/win32ipc/pipe_wrapper.cc index cdf47f8e28..165620ab1d 100644 --- a/app/modules/win32ipc/pipe_wrapper.cc +++ b/app/modules/win32ipc/pipe_wrapper.cc @@ -48,5 +48,18 @@ result create_pipe(pipe_direction direction) { err: return result::error(err_msg); } - + +char const* close_pipe_end(uintptr_t read_end_handle, uintptr_t write_end_handle) { + if (!CloseHandle((HANDLE) read_end_handle)) { + return "Close(read_end_handle)"; + } + + + if (!CloseHandle((HANDLE) write_end_handle)) { + return "Close(write_end_handle)"; + } + + return nullptr; +} + } // namespace pipe_wrapper diff --git a/app/modules/win32ipc/pipe_wrapper.h b/app/modules/win32ipc/pipe_wrapper.h index cb31abcc5d..4ed2fa5ac1 100644 --- a/app/modules/win32ipc/pipe_wrapper.h +++ b/app/modules/win32ipc/pipe_wrapper.h @@ -31,5 +31,6 @@ struct pipe { }; result create_pipe(pipe_direction direction); +char const* close_pipe_end(uintptr_t read_end_handle, uintptr_t write_end_handle); } // namespace pipe_wrapper