private void OnPluginStopped(PluginInstance pluginInstance,
                                     bool crashed = false)
        {
            if (IsDisposed || pluginInstance.Status == PluginStatus.Stopped)
            {
                return;
            }

            if (crashed)
            {
                // Notify user about crash
                LogTo.Information($"{pluginInstance.Denomination.CapitalizeFirst()} {pluginInstance.Metadata.PackageName} has crashed");
            }
            else
            {
                LogTo.Information($"{pluginInstance.Denomination.CapitalizeFirst()} {pluginInstance.Metadata.PackageName} has stopped.");
            }

            foreach (var interfaceType in pluginInstance.InterfaceChannelMap.Keys)
            {
                UnregisterChannelType(interfaceType, pluginInstance.Guid);
            }

            _runningPluginMap.TryRemove(pluginInstance.Guid, out _);

            pluginInstance.OnStopped();
        }
        private void OnPluginStarting(PluginInstance pluginInstance)
        {
            LogTo.Information(
                $"Starting {pluginInstance.Denomination} {pluginInstance.Package.Id}.");

            _runningPluginMap[pluginInstance.OnStarting()] = pluginInstance;
        }
        private void OnPluginStopping(PluginInstance pluginInstance)
        {
            LogTo.Information(
                $"Stopping {pluginInstance.Denomination} {pluginInstance.Package.Id}.");

            pluginInstance.OnStopping();
        }
        private void OnPluginStopped(PluginInstance pluginInstance)
        {
            if (IsDisposed || pluginInstance.Status == PluginStatus.Stopped)
            {
                return;
            }

            bool crashed = false;

            try
            {
                if (pluginInstance.Process?.HasExited ?? false)
                {
                    crashed = pluginInstance.Process.ExitCode != 0;
                }
            }
            catch
            {
                /* ignored */
            }

            LogTo.Information($"{pluginInstance.Denomination.CapitalizeFirst()} {pluginInstance.Metadata.PackageName} "
                              + $"has {(crashed ? "crashed" : "stopped")}");

            foreach (var interfaceType in pluginInstance.InterfaceChannelMap.Keys)
            {
                UnregisterChannelType(interfaceType, pluginInstance.Guid, false);
            }

            _runningPluginMap.TryRemove(pluginInstance.Guid, out _);

            pluginInstance.OnStopped();
        }
        private void OnPluginConnected(PluginInstance pluginInstance,
                                       ISMAPlugin plugin)
        {
            LogTo.Information($"Connected {pluginInstance.Denomination} {pluginInstance.Package.Id}.");

            pluginInstance.OnConnected(plugin);
        }
        public async Task StopPlugin(PluginInstance pluginInstance)
        {
            try
            {
                using (await pluginInstance.Lock.LockAsync())
                {
                    if (pluginInstance.Status == PluginStatus.Stopping)
                    {
                        return;
                    }

                    if (pluginInstance.Status == PluginStatus.Stopped)
                    {
                        return;
                    }

                    OnPluginStopping(pluginInstance);

                    try
                    {
                        pluginInstance.Plugin.Dispose();
                    }
                    catch (Exception ex)
                    {
                        LogTo.Error(
                            ex, $"An exception occured while gracefully stopping {pluginInstance.Denomination} {pluginInstance.Metadata.PackageName}.");
                    }
                }

                try
                {
                    if (await Task.Run(() => pluginInstance.Process.WaitForExit(PluginStopTimeout)))
                    {
                        return;
                    }

                    pluginInstance.Process.Refresh();

                    if (pluginInstance.Process.HasExited)
                    {
                        return;
                    }

                    LogTo.Warning(
                        $"{pluginInstance.Denomination.CapitalizeFirst()} {pluginInstance.Metadata.PackageName} didn't shut down gracefully after {PluginStopTimeout}ms. Attempting to kill process");

                    pluginInstance.Process.Kill();
                }
                catch (Exception ex)
                {
                    LogTo.Error(ex, $"An exception occured while killing {pluginInstance.Denomination} {pluginInstance.Metadata.PackageName}");
                }
            }
            finally
            {
                OnPluginStopped(pluginInstance);
            }
        }
Exemple #7
0
        /// <inheritdoc />
        protected override void OnPluginStartFailed(
            PluginInstance pluginInstance,
            PluginStartFailure reason,
            string errMsg)
        {
            base.OnPluginStartFailed(pluginInstance, reason, errMsg);

            errMsg.ShowDesktopNotification();
        }
Exemple #8
0
        /// <inheritdoc />
        protected override void OnPluginCrashed(PluginInstance pluginInstance)
        {
            ToastContent toastContent = new ToastContent
            {
                Visual = new ToastVisual
                {
                    BindingGeneric = new ToastBindingGeneric
                    {
                        Children =
                        {
                            new AdaptiveText
                            {
                                Text = $"{pluginInstance.ToString().CapitalizeFirst()} has crashed."
                            }
                        }
                    }
                },
                Actions = new ToastActionsCustom
                {
                    Buttons =
                    {
                        // Restart action
                        new ToastButton("Restart",
                                        new QueryString
                        {
                            { "action",                        ToastActionRestartAfterCrash},
                            { ToastActionParameterPluginId,    pluginInstance.Package.Id  }
                        }.ToString())
                        {
                            ActivationType = ToastActivationType.Background
                        },

                        // Open logs folder action
                        new ToastButton("Open the logs folder",SMAFileSystem.LogDir.FullPathWin)
                        {
                            ActivationType = ToastActivationType.Protocol
                        }
                    }
                }
            };

            var doc = new XmlDocument();

            doc.LoadXml(toastContent.GetContent());

            // And create the toast notification
            var toast = new ToastNotification(doc);

            // And then show it
            DesktopNotificationManager.CreateToastNotifier().Show(toast);
        }
Exemple #9
0
        public bool CanPluginStartOrPause(PluginInstance pluginInstance)
        {
            if (pluginInstance.Metadata.Enabled == false)
            {
                return(false);
            }

            switch (pluginInstance.Status)
            {
            case PluginStatus.Connected:
                return(true);

            case PluginStatus.Stopped:
                return(_runningPluginMap.Values.Any(p => p.Package.Id == pluginInstance.Package.Id) == false);

            default:
                return(false);
            }
        }
        public async Task UninstallPlugin(PluginInstance pluginInstance)
        {
            if (pluginInstance.Metadata.IsDevelopment)
            {
                throw new ArgumentException($"Cannot uninstall a development plugin");
            }

            await StopPlugin(pluginInstance);

            using (await pluginInstance.Lock.LockAsync())
            {
                var pm      = PackageManager;
                var success = await pm.UninstallPluginAsync(pluginInstance.Package.Id);

                if (success)
                {
                    _allPlugins.Remove(pluginInstance);
                }
            }
        }
Exemple #11
0
        /// <inheritdoc />
        protected override void OnPluginCrashed(PluginInstance pluginInstance)
        {
            $"{pluginInstance.ToString().CapitalizeFirst()} has crashed.".ShowDesktopNotification(
                // Restart action
                new ToastButton("Restart",
                                new QueryString
            {
                { "action", ToastActionRestartAfterCrash },
                { ToastActionParameterPluginId, pluginInstance.Package.Id }
            }.ToString())
            {
                ActivationType = ToastActivationType.Background
            },

                // Open logs folder action
                new ToastButton("Open the logs folder", SMAFileSystem.LogDir.FullPathWin)
            {
                ActivationType = ToastActivationType.Protocol
            }
                );
        }
Exemple #12
0
        public async Task StartPlugin(PluginInstance pluginInstance)
        {
            var pluginPackage = pluginInstance.Package;
            var packageName   = pluginPackage.Id;

            try
            {
                using (await pluginInstance.Lock.LockAsync())
                {
                    if (pluginInstance.Status != PluginStatus.Stopped)
                    {
                        return;
                    }

                    if (CanPluginStartOrPause(pluginInstance) == false)
                    {
                        throw new InvalidOperationException("A plugin with the same Package name is already running");
                    }

                    OnPluginStarting(pluginInstance);
                }

                var cmdLineParams = new PluginHostParameters
                {
                    PackageName    = packageName,
                    HomePath       = pluginPackage.GetHomeDir().FullPath,
                    SessionString  = pluginInstance.Guid.ToString(),
                    SMAChannelName = IpcServerChannelName,
                    SMAProcessId   = System.Diagnostics.Process.GetCurrentProcess().Id,
                    IsDeveloment   = pluginInstance.Metadata.IsDevelopment,
                };

                var processArgs = Parser.Default.FormatCommandLine(cmdLineParams);

                var pluginStartInfo = new ProcessStartInfo(
                    SMAFileSystem.PluginHostExeFile.FullPath,
                    processArgs)
                {
                    UseShellExecute = false,
                };

                pluginInstance.Process = System.Diagnostics.Process.Start(pluginStartInfo);

                if (pluginInstance.Process == null)
                {
                    LogTo.Warning($"Failed to start process for {pluginInstance.Denomination} {packageName}");
                    return;
                }

                pluginInstance.Process.EnableRaisingEvents = true;
                pluginInstance.Process.Exited += async(o, e) =>
                {
                    using (await pluginInstance.Lock.LockAsync())
                        OnPluginStopped(pluginInstance);
                };

                if (await pluginInstance.ConnectedEvent.WaitAsync(PluginConnectTimeout))
                {
                    return;
                }

                if (pluginInstance.Status == PluginStatus.Stopped)
                {
                    LogTo.Error($"{pluginInstance.Denomination.CapitalizeFirst()} {packageName} stopped unexpectedly.");
                    pluginInstance.ConnectedEvent.Set();
                    return;
                }
            }
            catch (Exception ex)
            {
                LogTo.Error(ex, $"An error occured while starting {pluginInstance.Denomination} {packageName}");
                return;
            }

            try
            {
                LogTo.Warning(
                    $"{pluginInstance.Denomination.CapitalizeFirst()} {packageName} failed to connect under {PluginConnectTimeout}ms. Attempting to kill process");

                pluginInstance.Process.Refresh();

                if (pluginInstance.Process.HasExited)
                {
                    LogTo.Warning($"{pluginInstance.Denomination.CapitalizeFirst()} {packageName} has already exited");
                    return;
                }

                pluginInstance.Process.Kill();
            }
            catch (RemotingException ex)
            {
                LogTo.Warning(ex, $"StartPlugin '{pluginInstance.Denomination}' {packageName} failed.");
            }
            catch (Exception ex)
            {
                LogTo.Error(ex, $"An error occured while starting {pluginInstance.Denomination} {packageName}");
            }
            finally
            {
                using (await pluginInstance.Lock.LockAsync())
                    OnPluginStopped(pluginInstance);
            }
        }
Exemple #13
0
        public async Task StopPlugin(PluginInstance pluginInstance)
        {
            try
            {
                using (await pluginInstance.Lock.LockAsync())
                {
                    switch (pluginInstance.Status)
                    {
                    case PluginStatus.Stopping:
                    case PluginStatus.Stopped:
                        return;

                    default:
                        OnPluginStopping(pluginInstance);

                        try
                        {
                            pluginInstance.Plugin.Dispose();
                        }
                        catch (RemotingException ex)
                        {
                            LogTo.Warning(ex, $"Failed to gracefully stop {pluginInstance.Denomination} '{pluginInstance.Metadata.PackageName}' failed.");
                        }
                        catch (Exception ex)
                        {
                            LogTo.Error(
                                ex, $"An exception occured while gracefully stopping {pluginInstance.Denomination} {pluginInstance.Metadata.PackageName}.");
                        }

                        break;
                    }
                }

                try
                {
                    if (pluginInstance.Process is null)
                    {
                        LogTo.Warning($"pluginInstance.Process is null. Unable to kill {pluginInstance.Denomination} {pluginInstance.Metadata.PackageName}.");
                        return;
                    }

                    if (await Task.Run(() => pluginInstance.Process.WaitForExit(PluginStopTimeout)))
                    {
                        return;
                    }

                    pluginInstance.Process.Refresh();

                    if (pluginInstance.Process.HasExited)
                    {
                        return;
                    }

                    LogTo.Warning(
                        $"{pluginInstance.Denomination.CapitalizeFirst()} {pluginInstance.Metadata.PackageName} didn't shut down gracefully after {PluginStopTimeout}ms. Attempting to kill process");

                    pluginInstance.Process.Kill();
                }
                catch (Exception ex)
                {
                    LogTo.Error(ex, $"An exception occured while killing {pluginInstance.Denomination} {pluginInstance.Metadata.PackageName}");
                }
            }
            catch (RemotingException ex)
            {
                LogTo.Warning(ex, $"StopPlugin {pluginInstance?.Denomination} '{pluginInstance?.Metadata?.PackageName}' failed.");
            }
            finally
            {
                using (await pluginInstance.Lock.LockAsync())
                    OnPluginStopped(pluginInstance);
            }
        }
Exemple #14
0
 /// <inheritdoc />
 public override string GetPluginHostTypeQualifiedName(PluginInstance pluginInstance)
 {
     return("SuperMemoAssistant.Interop.Plugins.PluginHost");
 }
Exemple #15
0
 /// <inheritdoc />
 public override NuGetVersion GetPluginHostTypeAssemblyMinimumVersion(PluginInstance pluginInstance)
 {
     return(NuGetVersion.Parse(MinInteropVersion)); // NuGetVersion.Parse(typeof(SMAConst).GetAssemblyVersion());
 }
Exemple #16
0
 /// <inheritdoc />
 public override string GetPluginHostTypeAssemblyName(PluginInstance pluginInstance)
 {
     return("SuperMemoAssistant.Interop");
 }