/// <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); } }
public PluginInstance this[Guid sessionGuid] => RunningPluginMap.SafeGet(sessionGuid);