// This BG process is the first one and will be the only one. // It has to maintain connection to the UWP app, watch lifecycle and child processes, // and try to re-establish the connection with the APP if it's closed and opened again. static void StartAsMaster() { // Kickstart static constructors. // NOTE: All classes are static instead of instance, because they're tightly coupled singletons. // But static constructors are called on demand (at first access or call to the class), not at startup. IPC.Init(); // Open named pipe that is used exclusively by this background broker process and potentional future // broker instances. It is used to signal wheter there's already existing broker to ensure there's always // only one broker at a time. It's necessary because new instance of UWP app cannot reconnect to preexisting // background process that was spawned by previous instance of the app. var slavePipe = new NamedPipe(UWP.name, 100); // If new connection occurs on the pipe, it means another broker process has been spawned by a new UWP instance // that has no way of knowing of existence of (let alone connecting to) this broker process. // But we can connect to the UWP from here. slavePipe.Connection += () => UWP.Connect(); // Lifecycle & selfclose watchdog. WatchReferences(); // Open exclusive mutex to signify that this is the master mutex process for the app. mutex = new Mutex(false, UWP.name); // TODO: is this even needed? Application.EnableVisualStyles(); // TODO: remove? Application.SetCompatibleTextRenderingDefault(false); // TODO: remove? // Run blockingly. And release the mutex when the app quits. Application.Run(); Close(); }
private async void OnJson(string reqJson) { //Console.WriteLine($"### OnJson {reqJson}"); var req = Converters.JsonToValueSet(reqJson); // Publish the message as if it was from UWP. await UWP.EmitMessage(req); }
// TODO: do not pass stdio/pipe related messages down to pipes static public void Init() { // Try to establish connection between UWP app and this broker process is established. // Not awaiting because we're attaching message listeners anyway even if the connection // isn't available yet because it might/will be eventually. UWP.Connect(); PassDataBetweenUwpAndChildren(); HandleLifecycle(); }
static private void OnMessage(string cmd, object arg = null) { switch (cmd) { case "uwp-open": UWP.Open(); break; // Close cmd will trickle up to the app which will close itself. // TODO: use arg argument as a force-close case "uwp-close": if (arg != null) { UWP.Close(true); } break; } }
static private void PassDataBetweenUwpAndChildren() { // Pass the IIPC messages from UWP down to child process. UWP.Message += async(ValueSet req) => { //Console.WriteLine("----- UWP MESSAGE -----"); //foreach (var pair in req) // Console.WriteLine($"{pair.Key}: {pair.Value}"); if (req.ContainsKey("iipc")) { var cmd = req["iipc"] as string; await ChildProcesses.Send(cmd); } }; // Receive Internal IPC messages (IIPC) from child's uwp-node.js lib // and propagate them to UWP app as well as (potential) other child processes. ChildProcesses.Message += (message, pipe) => { //Console.WriteLine("----- CHILD MESSAGE -----"); //Console.WriteLine(message); var vs = new ValueSet(); vs.Add("iipc", message); UWP.Send(vs); ChildProcesses.Send(message, pipe); }; }
static public void Send(string message) { UWP.Send(message); ChildProcesses.Send(message, null); }
private async Task Report(ValueSet message) { message.Add("cid", Cid); await UWP.Send(message); }