/// <summary>
        ///   Called when a plugin failed to start. Use this to add custom handling of errors.
        /// Make sure to call base method.
        /// </summary>
        /// <param name="pluginInstance">The plugin that failed to start</param>
        /// <param name="reason">The reason why the plugin failed to start</param>
        /// <param name="errMsg">The error message</param>
        protected virtual void OnPluginStartFailed(TPluginInstance pluginInstance, PluginStartFailure reason, string errMsg)
        {
            switch (reason)
            {
            case PluginStartFailure.InteropAssemblyNotFound:
            case PluginStartFailure.InteropAssemblyInvalidVersionString:
            case PluginStartFailure.InteropAssemblyOutdated:
            case PluginStartFailure.ProcessDidNotStart:
            case PluginStartFailure.ProcessDidNotConnect:
            case PluginStartFailure.Unknown:
                LogTo.Warning("OnPluginStartFailed: " + errMsg);
                break;
            }

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

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

                pluginInstance.OnStopped(false);
            }
        }
        public void UnregisterChannelType(string remoteServiceType,
                                          Guid sessionGuid,
                                          bool requireLock)
        {
            IDisposable @lock = null;

            try
            {
                var pluginInst = RunningPluginMap.SafeGet(sessionGuid);

                if (pluginInst == null)
                {
                    throw new ArgumentException($"Plugin not found for service {remoteServiceType}");
                }

                if (requireLock)
                {
                    @lock = pluginInst.Lock.Lock();
                }

                pluginInst.InterfaceChannelMap.TryRemove(remoteServiceType, out _);
                InterfaceChannelMap.TryRemove(remoteServiceType, out _);

                Task.Run(() => NotifyServiceRevoked(remoteServiceType));
            }
            finally
            {
                @lock?.Dispose();
            }
        }
        /// <inheritdoc />
        public IDisposable RegisterService(Guid sessionGuid,
                                           string remoteServiceType,
                                           string channelName)
        {
            if (sessionGuid == null)
            {
                throw new ArgumentNullException(nameof(sessionGuid));
            }

            if (remoteServiceType == null)
            {
                throw new ArgumentNullException(nameof(remoteServiceType));
            }

            if (channelName == null)
            {
                throw new ArgumentNullException(nameof(channelName));
            }

            var pluginInst = RunningPluginMap.SafeGet(sessionGuid);

            if (pluginInst == null)
            {
                throw new ArgumentException($"No plugin matching session guid {sessionGuid} could be found");
            }

            pluginInst.InterfaceChannelMap[remoteServiceType] = channelName;
            InterfaceChannelMap[remoteServiceType]            = channelName;

            Task.Run(() => NotifyServicePublished(remoteServiceType));

            return(new PluginChannelDisposer <TParent, TPluginInstance, TMeta, ICustomPluginManager, ICore, IPlugin>(
                       this, remoteServiceType, sessionGuid));
        }
        /// <inheritdoc />
        public ICore ConnectPlugin(string channel,
                                   Guid sessionGuid)
        {
            if (channel == null)
            {
                throw new ArgumentNullException(nameof(channel));
            }

            if (sessionGuid == null)
            {
                throw new ArgumentNullException(nameof(sessionGuid));
            }

            string pluginAssemblyName = "N/A";

            try
            {
                var plugin = RemotingServicesEx.ConnectToIpcServer <IPlugin>(channel);
                pluginAssemblyName = plugin.AssemblyName;

                var pluginInstance = RunningPluginMap.SafeGet(sessionGuid);

                if (pluginInstance == null)
                {
                    LogTo.Warning($"Plugin {pluginAssemblyName} unexpected for connection. Aborting");
                    return(null);
                }

                using (pluginInstance.Lock.Lock())
                    OnPluginConnected(pluginInstance, plugin);

                return(GetCoreInstance());
            }
            catch (RemotingException ex)
            {
                LogTo.Warning(ex, $"Connection to plugin {pluginAssemblyName} failed.");

                return(null);
            }
            catch (Exception ex)
            {
                LogTo.Error(ex, $"An exception occured while connecting plugin {pluginAssemblyName}");

                return(null);
            }
        }
        /// <summary>
        ///   Called after the plugin has been stopped or killed. Its
        ///   <see cref="IPluginInstance{TParent, TMeta, IPlugin}.Process" /> is still available. Always
        ///   call this base method if it is inherited.
        /// </summary>
        /// <param name="pluginInstance">The plugin that stopped</param>
        protected virtual void OnPluginStopped(TPluginInstance pluginInstance)
        {
            if (IsDisposed || pluginInstance.Status == PluginStatus.Stopped)
            {
                return;
            }

            bool crashed  = false;
            var  exitCode = pluginInstance.Process.ExitCode;

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

            LogTo.Information($"{pluginInstance.Denomination.CapitalizeFirst()} {pluginInstance.Package.Id} "
                              + $"has {(crashed ? $"crashed with code {exitCode}" : "stopped")}");

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

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

            pluginInstance.OnStopped(crashed);

            if (crashed)
            {
                OnPluginCrashed(pluginInstance);
            }
        }
Esempio n. 6
0
 public PluginInstance this[Guid sessionGuid] => RunningPluginMap.SafeGet(sessionGuid);