Example #1
0
        private async Task <Message> RunLoop(CancellationToken loopCt)
        {
            TaskUtilities.AssertIsOnBackgroundThread();
            var cancelAllCtsLink = CancellationTokenSource.CreateLinkedTokenSource(loopCt, _cancelAllCts.Token);
            var ct = cancelAllCtsLink.Token;

            try {
                Log.EnterRLoop(_rLoopDepth++);
                while (!loopCt.IsCancellationRequested)
                {
                    var message = await ReceiveMessageAsync(loopCt);

                    if (message == null)
                    {
                        return(null);
                    }
                    else if (message.IsResponse)
                    {
                        Request request;
                        if (!_requests.TryRemove(message.RequestId, out request))
                        {
                            throw ProtocolError($"Mismatched response - no request with such ID:", message);
                        }
                        else if (message.Name != ":" + request.MessageName.Substring(1))
                        {
                            throw ProtocolError($"Mismatched response - message name does not match request '{request.MessageName}':", message);
                        }

                        request.Handle(this, message);
                        continue;
                    }

                    try {
                        switch (message.Name)
                        {
                        case "!End":
                            message.ExpectArguments(1);
                            await _callbacks.Shutdown(message.GetBoolean(0, "rdataSaved"));

                            break;

                        case "!CanceledAll":
                            CancelAll();
                            break;

                        case "?YesNoCancel":
                            ShowDialog(message, MessageButtons.YesNoCancel, ct)
                            .SilenceException <MessageTransportException>()
                            .DoNotWait();
                            break;

                        case "?YesNo":
                            ShowDialog(message, MessageButtons.YesNo, ct)
                            .SilenceException <MessageTransportException>()
                            .DoNotWait();
                            break;

                        case "?OkCancel":
                            ShowDialog(message, MessageButtons.OKCancel, ct)
                            .SilenceException <MessageTransportException>()
                            .DoNotWait();
                            break;

                        case "?LocYesNoCancel":
                            ShowLocalizedDialogFormat(message, MessageButtons.YesNoCancel, ct)
                            .SilenceException <MessageTransportException>()
                            .DoNotWait();
                            break;

                        case "?LocYesNo":
                            ShowLocalizedDialogFormat(message, MessageButtons.YesNo, ct)
                            .SilenceException <MessageTransportException>()
                            .DoNotWait();
                            break;

                        case "?LocOkCancel":
                            ShowLocalizedDialogFormat(message, MessageButtons.OKCancel, ct)
                            .SilenceException <MessageTransportException>()
                            .DoNotWait();
                            break;

                        case "?>":
                            ReadConsole(message, ct)
                            .SilenceException <MessageTransportException>()
                            .DoNotWait();
                            break;

                        case "!":
                        case "!!":
                            message.ExpectArguments(1);
                            await _callbacks.WriteConsoleEx(
                                message.GetString(0, "buf", allowNull: true),
                                message.Name.Length == 1?OutputType.Output : OutputType.Error,
                                ct);

                            break;

                        case "!ShowMessage":
                            message.ExpectArguments(1);
                            await _callbacks.ShowMessage(message.GetString(0, "s", allowNull: true), ct);

                            break;

                        case "!+":
                            await _callbacks.Busy(true, ct);

                            break;

                        case "!-":
                            await _callbacks.Busy(false, ct);

                            break;

                        case "!SetWD":
                            _callbacks.DirectoryChanged();
                            break;

                        case "!Library":
                            await _callbacks.ViewLibrary(ct);

                            break;

                        case "!ShowFile":
                            message.ExpectArguments(3);
                            // Do not await since it blocks callback from calling the host again
                            _callbacks.ShowFile(
                                message.GetString(0, "file"),
                                message.GetString(1, "tabName"),
                                message.GetBoolean(2, "delete.file"),
                                ct).DoNotWait();
                            break;

                        case "?EditFile":
                            message.ExpectArguments(2);
                            // Opens file in editor and blocks until file is closed.
                            var content = await _callbacks.EditFileAsync(message.GetString(0, "name", allowNull: true), message.GetString(1, "file", allowNull: true), ct);

                            ct.ThrowIfCancellationRequested();
                            await RespondAsync(message, ct, content);

                            break;

                        case "!View":
                            message.ExpectArguments(2);
                            _callbacks.ViewObject(message.GetString(0, "x"), message.GetString(1, "title"), ct)
                            .SilenceException <MessageTransportException>()
                            .DoNotWait();
                            break;

                        case "!Plot":
                            await _callbacks.Plot(
                                new PlotMessage(
                                    Guid.Parse(message.GetString(0, "device_id")),
                                    Guid.Parse(message.GetString(1, "plot_id")),
                                    message.GetString(2, "file_path"),
                                    message.GetInt32(3, "device_num"),
                                    message.GetInt32(4, "active_plot_index"),
                                    message.GetInt32(5, "plot_count"),
                                    message.Blob),
                                ct);

                            break;

                        case "?Locator":
                            var locatorResult = await _callbacks.Locator(Guid.Parse(message.GetString(0, "device_id")), ct);

                            ct.ThrowIfCancellationRequested();
                            await RespondAsync(message, ct, locatorResult.Clicked, locatorResult.X, locatorResult.Y);

                            break;

                        case "?PlotDeviceCreate":
                            var plotDeviceResult = await _callbacks.PlotDeviceCreate(Guid.Parse(message.GetString(0, "device_id")), ct);

                            ct.ThrowIfCancellationRequested();
                            await RespondAsync(message, ct, plotDeviceResult.Width, plotDeviceResult.Height, plotDeviceResult.Resolution);

                            break;

                        case "!PlotDeviceDestroy":
                            await _callbacks.PlotDeviceDestroy(Guid.Parse(message.GetString(0, "device_id")), ct);

                            break;

                        case "!WebBrowser":
                            _callbacks.WebBrowser(message.GetString(0, "url"), ct)
                            .DoNotWait();
                            break;

                        case "?BeforePackagesInstalled":
                            await _callbacks.BeforePackagesInstalledAsync(ct);

                            ct.ThrowIfCancellationRequested();
                            await RespondAsync(message, ct, true);

                            break;

                        case "?AfterPackagesInstalled":
                            await _callbacks.AfterPackagesInstalledAsync(ct);

                            ct.ThrowIfCancellationRequested();
                            await RespondAsync(message, ct, true);

                            break;

                        case "!PackagesRemoved":
                            _callbacks.PackagesRemoved();
                            break;

                        case "!FetchFile":
                            var remoteFileName = message.GetString(0, "file_remote_name");
                            var remoteBlobId   = message.GetUInt64(1, "blob_id");
                            var localPath      = message.GetString(2, "file_local_path");
                            Task.Run(async() => {
                                var destPath = await _callbacks.FetchFileAsync(remoteFileName, remoteBlobId, localPath, ct);
                                if (!message.GetBoolean(3, "silent"))
                                {
                                    await _callbacks.WriteConsoleEx(destPath, OutputType.Error, ct);
                                }
                            }).DoNotWait();
                            break;

                        case "!LocMessage":
                            _callbacks.WriteConsoleEx(GetLocalizedString(message) + Environment.NewLine, OutputType.Output, ct).DoNotWait();
                            break;

                        case "!LocWarning":
                            _callbacks.WriteConsoleEx(GetLocalizedString(message) + Environment.NewLine, OutputType.Error, ct).DoNotWait();
                            break;

                        default:
                            throw ProtocolError($"Unrecognized host message name:", message);
                        }

                        if (_cancelAllCts.IsCancellationRequested)
                        {
                            ct = UpdateCancelAllCtsLink(ref cancelAllCtsLink, loopCt);
                        }
                    } catch (OperationCanceledException) when(_cancelAllCts.IsCancellationRequested)
                    {
                        // Canceled via _cancelAllCts - update cancelAllCtsLink and move on
                        ct = UpdateCancelAllCtsLink(ref cancelAllCtsLink, loopCt);
                    }
                }
            } finally {
                // asyncronously-running handlers like ReadConsole and ShowDialog that were started in the loop should be canceled
                cancelAllCtsLink.Cancel();
                cancelAllCtsLink.Dispose();
                Log.ExitRLoop(--_rLoopDepth);
            }

            return(null);
        }
Example #2
0
        private async Task <Message> RunLoop(CancellationToken ct)
        {
            TaskUtilities.AssertIsOnBackgroundThread();

            try {
                _log.EnterRLoop(_rLoopDepth++);
                while (!ct.IsCancellationRequested)
                {
                    var message = await ReceiveMessageAsync(ct);

                    if (message.IsResponse)
                    {
                        Request request;
                        if (!_requests.TryRemove(message.RequestId, out request))
                        {
                            throw ProtocolError($"Mismatched response - no request with such ID:", message);
                        }
                        else if (message.Name != ":" + request.MessageName.Substring(1))
                        {
                            throw ProtocolError($"Mismatched response - message name does not match request '{request.MessageName}':", message);
                        }

                        request.Handle(this, message);
                        continue;
                    }

                    try {
                        switch (message.Name)
                        {
                        case "!End":
                            return(null);

                        case "!CanceledAll":
                            CancelAll();
                            break;

                        case "?YesNoCancel":
                            ShowDialog(message, MessageButtons.YesNoCancel, CancellationTokenSource.CreateLinkedTokenSource(ct, _cancelAllCts.Token).Token)
                            .SilenceException <MessageTransportException>()
                            .DoNotWait();
                            break;

                        case "?YesNo":
                            ShowDialog(message, MessageButtons.YesNo, CancellationTokenSource.CreateLinkedTokenSource(ct, _cancelAllCts.Token).Token)
                            .SilenceException <MessageTransportException>()
                            .DoNotWait();
                            break;

                        case "?OkCancel":
                            ShowDialog(message, MessageButtons.OKCancel, CancellationTokenSource.CreateLinkedTokenSource(ct, _cancelAllCts.Token).Token)
                            .SilenceException <MessageTransportException>()
                            .DoNotWait();
                            break;

                        case "?>":
                            ReadConsole(message, CancellationTokenSource.CreateLinkedTokenSource(ct, _cancelAllCts.Token).Token)
                            .SilenceException <MessageTransportException>()
                            .DoNotWait();
                            break;

                        case "!":
                        case "!!":
                            message.ExpectArguments(1);
                            await _callbacks.WriteConsoleEx(
                                message.GetString(0, "buf", allowNull: true),
                                message.Name.Length == 1?OutputType.Output : OutputType.Error,
                                ct);

                            break;

                        case "!ShowMessage":
                            message.ExpectArguments(1);
                            await _callbacks.ShowMessage(message.GetString(0, "s", allowNull: true), ct);

                            break;

                        case "!+":
                            await _callbacks.Busy(true, ct);

                            break;

                        case "!-":
                            await _callbacks.Busy(false, ct);

                            break;

                        case "!SetWD":
                            _callbacks.DirectoryChanged();
                            break;

                        case "!Library":
                            await _callbacks.ViewLibrary();

                            break;

                        case "!ShowFile":
                            message.ExpectArguments(3);
                            await _callbacks.ShowFile(
                                message.GetString(0, "file"),
                                message.GetString(1, "tabName"),
                                message.GetBoolean(2, "delete.file"));

                            break;

                        case "!View":
                            message.ExpectArguments(2);
                            _callbacks.ViewObject(message.GetString(0, "x"), message.GetString(1, "title"));
                            break;

                        case "!Plot":
                            await _callbacks.Plot(
                                new PlotMessage(
                                    message.GetString(0, "xaml_file_path"),
                                    message.GetInt32(1, "active_plot_index"),
                                    message.GetInt32(2, "plot_count"),
                                    message.Blob),
                                ct);

                            break;

                        case "?Locator":
                            var locatorResult = await _callbacks.Locator(ct);

                            ct.ThrowIfCancellationRequested();
                            await RespondAsync(message, ct, locatorResult.Clicked, locatorResult.X, locatorResult.Y);

                            break;

                        case "!WebBrowser":
                            await _callbacks.WebBrowser(message.GetString(0, "url"));

                            break;

                        case "!PackagesInstalled":
                            _callbacks.PackagesInstalled();
                            break;

                        case "!PackagesRemoved":
                            _callbacks.PackagesRemoved();
                            break;

                        case "!FetchFile":
                            var destPath = await _callbacks.SaveFileAsync(message.GetString(0, "file_path"), message.Blob);

                            await _callbacks.WriteConsoleEx(destPath, OutputType.Error, ct);

                            break;

                        default:
                            throw ProtocolError($"Unrecognized host message name:", message);
                        }
                    } catch (OperationCanceledException) when(!ct.IsCancellationRequested)
                    {
                        // Canceled via _cancelAllCts - just move onto the next message.
                    }
                }
            } finally {
                _log.ExitRLoop(--_rLoopDepth);
            }

            return(null);
        }