From d3ed5b4ade690b7d835f4fd2a177c4c22e434c07 Mon Sep 17 00:00:00 2001 From: Raymond Date: Mon, 23 Aug 2021 13:35:44 -0400 Subject: [PATCH] Shuffle files around --- .../Interface/Internal/Windows/DataWindow.cs | 5 +- Dalamud/Plugin/CallGate.cs | 770 ------------------ Dalamud/Plugin/DalamudPluginInterface.cs | 68 +- Dalamud/Plugin/ICallGateProvider.cs | 127 +++ Dalamud/Plugin/ICallGateSubscriber.cs | 154 ++++ Dalamud/Plugin/Internal/CallGate.cs | 92 +++ Dalamud/Plugin/Internal/CallGatePubSub.cs | 296 +++++++ Dalamud/Plugin/Internal/CallGatePubSubBase.cs | 116 +++ 8 files changed, 822 insertions(+), 806 deletions(-) delete mode 100644 Dalamud/Plugin/CallGate.cs create mode 100644 Dalamud/Plugin/ICallGateProvider.cs create mode 100644 Dalamud/Plugin/ICallGateSubscriber.cs create mode 100644 Dalamud/Plugin/Internal/CallGate.cs create mode 100644 Dalamud/Plugin/Internal/CallGatePubSub.cs create mode 100644 Dalamud/Plugin/Internal/CallGatePubSubBase.cs diff --git a/Dalamud/Interface/Internal/Windows/DataWindow.cs b/Dalamud/Interface/Internal/Windows/DataWindow.cs index f515773cb..253f9a4ac 100644 --- a/Dalamud/Interface/Internal/Windows/DataWindow.cs +++ b/Dalamud/Interface/Internal/Windows/DataWindow.cs @@ -25,6 +25,7 @@ using Dalamud.Game.Text; using Dalamud.Interface.Windowing; using Dalamud.Memory; using Dalamud.Plugin; +using Dalamud.Plugin.Internal; using Dalamud.Utility; using ImGuiNET; using ImGuiScene; @@ -61,8 +62,8 @@ namespace Dalamud.Interface.Internal.Windows private UIDebug addonInspector = null; // IPC - private ICallGatePub ipcPub; - private ICallGateSub ipcSub; + private ICallGateProvider ipcPub; + private ICallGateSubscriber ipcSub; private string callGateResponse = string.Empty; // Toast fields diff --git a/Dalamud/Plugin/CallGate.cs b/Dalamud/Plugin/CallGate.cs deleted file mode 100644 index 9a643308c..000000000 --- a/Dalamud/Plugin/CallGate.cs +++ /dev/null @@ -1,770 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -using Serilog; - -#pragma warning disable SA1201 // Elements should appear in the correct order -#pragma warning disable SA1402 // File may only contain a single type - -namespace Dalamud.Plugin -{ - /// - /// This class facilitates inter-plugin communication. - /// - internal class CallGate - { - private Dictionary gates = new(); - - #region GetIpcPubSub - - /// - internal CallGatePubSub GetIpcPubSub(string name) - => (CallGatePubSub)this.GetIpcPubSub(name, typeof(TRet)); - - /// - internal CallGatePubSub GetIpcPubSub(string name) - => (CallGatePubSub)this.GetIpcPubSub(name, typeof(T1), typeof(TRet)); - - /// - internal CallGatePubSub GetIpcPubSub(string name) - => (CallGatePubSub)this.GetIpcPubSub(name, typeof(T1), typeof(T2), typeof(TRet)); - - /// - internal CallGatePubSub GetIpcPubSub(string name) - => (CallGatePubSub)this.GetIpcPubSub(name, typeof(T1), typeof(T2), typeof(T3), typeof(TRet)); - - /// - internal CallGatePubSub GetIpcPubSub(string name) - => (CallGatePubSub)this.GetIpcPubSub(name, typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(TRet)); - - /// - internal CallGatePubSub GetIpcPubSub(string name) - => (CallGatePubSub)this.GetIpcPubSub(name, typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(TRet)); - - /// - internal CallGatePubSub GetIpcPubSub(string name) - => (CallGatePubSub)this.GetIpcPubSub(name, typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(TRet)); - - /// - internal CallGatePubSub GetIpcPubSub(string name) - => (CallGatePubSub)this.GetIpcPubSub(name, typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(TRet)); - - /// - internal CallGatePubSub GetIpcPubSub(string name) - => (CallGatePubSub)this.GetIpcPubSub(name, typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(TRet)); - - #endregion - - /// - /// Gets or sets an IPC pub/sub callgate. - /// - /// Name of the IPC registration. - /// The callgate parameter types. - /// The IPC pub/sub callgate. - private CallGateBase GetIpcPubSub(string name, params Type[] types) - { - if (!this.gates.TryGetValue(name, out var callGate)) - { - var generic = types.Length switch - { - 1 => typeof(CallGatePubSub<>), - 2 => typeof(CallGatePubSub<,>), - 3 => typeof(CallGatePubSub<,,>), - 4 => typeof(CallGatePubSub<,,,>), - 5 => typeof(CallGatePubSub<,,,,>), - 6 => typeof(CallGatePubSub<,,,,,>), - 7 => typeof(CallGatePubSub<,,,,,,>), - 8 => typeof(CallGatePubSub<,,,,,,,>), - 9 => typeof(CallGatePubSub<,,,,,,,,>), - _ => throw new Exception("Misconfigured number of type args"), - }; - - var type = generic.MakeGenericType(types); - callGate = (CallGateBase)Activator.CreateInstance(type); - callGate.Name = name; - - this.gates[name] = callGate; - } - - var requested = callGate.GetType().GenericTypeArguments; - if (!Enumerable.SequenceEqual(requested, types)) - throw new IpcTypeMismatchError(name, requested, types); - - return callGate; - } - } - - #region ICallGatePub - - /// - public interface ICallGatePub - { - /// - public void RegisterAction(Action action); - - /// - public void RegisterFunc(Func func); - - /// - public void SendMessage(); - } - - /// - public interface ICallGatePub - { - /// - public void RegisterAction(Action action); - - /// - public void RegisterFunc(Func func); - - /// - public void SendMessage(T1 arg1); - } - - /// - public interface ICallGatePub - { - /// - public void RegisterAction(Action action); - - /// - public void RegisterFunc(Func func); - - /// - public void SendMessage(T1 arg1, T2 arg2); - } - - /// - public interface ICallGatePub - { - /// - public void RegisterAction(Action action); - - /// - public void RegisterFunc(Func func); - - /// - public void SendMessage(T1 arg1, T2 arg2, T3 arg3); - } - - /// - public interface ICallGatePub - { - /// - public void RegisterAction(Action action); - - /// - public void RegisterFunc(Func func); - - /// - public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4); - } - - /// - public interface ICallGatePub - { - /// - public void RegisterAction(Action action); - - /// - public void RegisterFunc(Func func); - - /// - public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); - } - - /// - public interface ICallGatePub - { - /// - public void RegisterAction(Action action); - - /// - public void RegisterFunc(Func func); - - /// - public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); - } - - /// - public interface ICallGatePub - { - /// - public void RegisterAction(Action action); - - /// - public void RegisterFunc(Func func); - - /// - public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); - } - - /// - public interface ICallGatePub - { - /// - public void RegisterAction(Action action); - - /// - public void RegisterFunc(Func func); - - /// - public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8); - } - - #endregion - - #region ICallGateSub - - /// - public interface ICallGateSub - { - /// - public void Subscribe(Action action); - - /// - public void Unsubscribe(Action action); - - /// - public void InvokeAction(); - - /// - public TRet InvokeFunc(); - } - - /// - public interface ICallGateSub - { - /// - public void Subscribe(Action action); - - /// - public void Unsubscribe(Action action); - - /// - public void InvokeAction(T1 arg1); - - /// - public TRet InvokeFunc(T1 arg1); - } - - /// - public interface ICallGateSub - { - /// - public void Subscribe(Action action); - - /// - public void Unsubscribe(Action action); - - /// - public void InvokeAction(T1 arg1, T2 arg2); - - /// - public TRet InvokeFunc(T1 arg1, T2 arg2); - } - - /// - public interface ICallGateSub - { - /// - public void Subscribe(Action action); - - /// - public void Unsubscribe(Action action); - - /// - public void InvokeAction(T1 arg1, T2 arg2, T3 arg3); - - /// - public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3); - } - - /// - public interface ICallGateSub - { - /// - public void Subscribe(Action action); - - /// - public void Unsubscribe(Action action); - - /// - public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4); - - /// - public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4); - } - - /// - public interface ICallGateSub - { - /// - public void Subscribe(Action action); - - /// - public void Unsubscribe(Action action); - - /// - public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); - - /// - public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); - } - - /// - public interface ICallGateSub - { - /// - public void Subscribe(Action action); - - /// - public void Unsubscribe(Action action); - - /// - public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); - - /// - public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); - } - - /// - public interface ICallGateSub - { - /// - public void Subscribe(Action action); - - /// - public void Unsubscribe(Action action); - - /// - public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); - - /// - public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); - } - - /// - public interface ICallGateSub - { - /// - public void Subscribe(Action action); - - /// - public void Unsubscribe(Action action); - - /// - public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8); - - /// - public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8); - } - - #endregion - - #region CallGatePubSub - - /// - internal class CallGatePubSub : CallGateBase, ICallGatePub, ICallGateSub - { - /// - public void RegisterAction(Action action) - => base.RegisterAction(action); - - /// - public void RegisterFunc(Func func) - => base.RegisterFunc(func); - - /// - public void SendMessage() - => base.SendMessage(); - - /// - public void Subscribe(Action action) - => base.Subscribe(action); - - /// - public void Unsubscribe(Action action) - => base.Unsubscribe(action); - - /// - public void InvokeAction() - => base.InvokeAction(); - - /// - public TRet InvokeFunc() - => (TRet)base.InvokeFunc(); - } - - /// - internal class CallGatePubSub : CallGateBase, ICallGatePub, ICallGateSub - { - /// - public void RegisterAction(Action action) - => base.RegisterAction(action); - - /// - public void RegisterFunc(Func func) - => base.RegisterFunc(func); - - /// - public void SendMessage(T1 arg1) - => base.SendMessage(arg1); - - /// - public void Subscribe(Action action) - => base.Subscribe(action); - - /// - public void Unsubscribe(Action action) - => base.Unsubscribe(action); - - /// - public void InvokeAction(T1 arg1) - => base.InvokeAction(arg1); - - /// - public TRet InvokeFunc(T1 arg1) - => (TRet)base.InvokeFunc(arg1); - } - - /// - internal class CallGatePubSub : CallGateBase, ICallGatePub, ICallGateSub - { - /// - public void RegisterAction(Action action) - => base.RegisterAction(action); - - /// - public void RegisterFunc(Func func) - => base.RegisterFunc(func); - - /// - public void SendMessage(T1 arg1, T2 arg2) - => base.SendMessage(arg1, arg2); - - /// - public void Subscribe(Action action) - => base.Subscribe(action); - - /// - public void Unsubscribe(Action action) - => base.Unsubscribe(action); - - /// - public void InvokeAction(T1 arg1, T2 arg2) - => base.InvokeAction(arg1, arg2); - - /// - public TRet InvokeFunc(T1 arg1, T2 arg2) - => (TRet)base.InvokeFunc(arg1, arg2); - } - - /// - internal class CallGatePubSub : CallGateBase, ICallGatePub, ICallGateSub - { - /// - public void RegisterAction(Action action) - => base.RegisterAction(action); - - /// - public void RegisterFunc(Func func) - => base.RegisterFunc(func); - - /// - public void SendMessage(T1 arg1, T2 arg2, T3 arg3) - => base.SendMessage(arg1, arg2, arg3); - - /// - public void Subscribe(Action action) - => base.Subscribe(action); - - /// - public void Unsubscribe(Action action) - => base.Unsubscribe(action); - - /// - public void InvokeAction(T1 arg1, T2 arg2, T3 arg3) - => base.InvokeAction(arg1, arg2, arg3); - - /// - public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3) - => (TRet)base.InvokeFunc(arg1, arg2, arg3); - } - - /// - internal class CallGatePubSub : CallGateBase, ICallGatePub, ICallGateSub - { - /// - public void RegisterAction(Action action) - => base.RegisterAction(action); - - /// - public void RegisterFunc(Func func) - => base.RegisterFunc(func); - - /// - public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4) - => base.SendMessage(arg1, arg2, arg3, arg4); - - /// - public void Subscribe(Action action) - => base.Subscribe(action); - - /// - public void Unsubscribe(Action action) - => base.Unsubscribe(action); - - /// - public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4) - => base.InvokeAction(arg1, arg2, arg3, arg4); - - /// - public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4) - => (TRet)base.InvokeFunc(arg1, arg2, arg3, arg4); - } - - /// - internal class CallGatePubSub : CallGateBase, ICallGatePub, ICallGateSub - { - /// - public void RegisterAction(Action action) - => base.RegisterAction(action); - - /// - public void RegisterFunc(Func func) - => base.RegisterFunc(func); - - /// - public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) - => base.SendMessage(arg1, arg2, arg3, arg4, arg5); - - /// - public void Subscribe(Action action) - => base.Subscribe(action); - - /// - public void Unsubscribe(Action action) - => base.Unsubscribe(action); - - /// - public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) - => base.InvokeAction(arg1, arg2, arg3, arg4, arg5); - - /// - public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) - => (TRet)base.InvokeFunc(arg1, arg2, arg3, arg4, arg5); - } - - /// - internal class CallGatePubSub : CallGateBase, ICallGatePub, ICallGateSub - { - /// - public void RegisterAction(Action action) - => base.RegisterAction(action); - - /// - public void RegisterFunc(Func func) - => base.RegisterFunc(func); - - /// - public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) - => base.SendMessage(arg1, arg2, arg3, arg4, arg5, arg6); - - /// - public void Subscribe(Action action) - => base.Subscribe(action); - - /// - public void Unsubscribe(Action action) - => base.Unsubscribe(action); - - /// - public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) - => base.InvokeAction(arg1, arg2, arg3, arg4, arg5, arg6); - - /// - public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) - => (TRet)base.InvokeFunc(arg1, arg2, arg3, arg4, arg5, arg6); - } - - /// - internal class CallGatePubSub : CallGateBase, ICallGatePub, ICallGateSub - { - /// - public void RegisterAction(Action action) - => base.RegisterAction(action); - - /// - public void RegisterFunc(Func func) - => base.RegisterFunc(func); - - /// - public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) - => base.SendMessage(arg1, arg2, arg3, arg4, arg5, arg6, arg7); - - /// - public void Subscribe(Action action) - => base.Subscribe(action); - - /// - public void Unsubscribe(Action action) - => base.Unsubscribe(action); - - /// - public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) - => base.InvokeAction(arg1, arg2, arg3, arg4, arg5, arg6, arg7); - - /// - public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) - => (TRet)base.InvokeFunc(arg1, arg2, arg3, arg4, arg5, arg6, arg7); - } - - /// - internal class CallGatePubSub : CallGateBase, ICallGatePub, ICallGateSub - { - /// - public void RegisterAction(Action action) - => base.RegisterAction(action); - - /// - public void RegisterFunc(Func func) - => base.RegisterFunc(func); - - /// - public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) - => base.SendMessage(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); - - /// - public void Subscribe(Action action) - => base.Subscribe(action); - - /// - public void Unsubscribe(Action action) - => base.Unsubscribe(action); - - /// - public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) - => base.InvokeAction(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); - - /// - public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) - => (TRet)base.InvokeFunc(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); - } - - #endregion - - /// - /// This class facilitates inter-plugin communication. - /// - internal class CallGateBase - { - /// - /// Initializes a new instance of the class. - /// - internal CallGateBase() - { - } - - /// - /// Gets or sets the name of the IPC registration. - /// - public string Name { get; internal set; } - - /// - /// Gets or sets the Action. - /// - protected Delegate? Action { get; set; } - - /// - /// Gets or sets the Func. - /// - protected Delegate? Func { get; set; } - - /// - /// Gets the list of subscribed delegates. - /// - protected List Subs { get; } = new(); - - /// - /// Removes a registered Action from inter-plugin communication. - /// - public void UnregisterAction() - => this.Action = null; - - /// - /// Removes a registered Func from inter-plugin communication. - /// - public void UnregisterFunc() - => this.Func = null; - - /// - /// Removes a registered Action from inter-plugin communication. - /// - /// Action to register. - private protected void RegisterAction(Delegate action) - => this.Action = action; - - /// - /// Removes a registered Func from inter-plugin communication. - /// - /// Func to register. - private protected void RegisterFunc(Delegate func) - => this.Func = func; - - /// - /// Invoke all actions that have subscribed to this IPC. - /// - /// Delegate arguments. - private protected void SendMessage(params object?[]? args) - { - foreach (var sub in this.Subs) - { - try - { - sub.DynamicInvoke(args); - } - catch (Exception ex) - { - Log.Error(ex, $"Error invoking a subscription of {this.Name}"); - } - } - } - - /// - /// Subscribe an expression to this registration. - /// - /// Action to subscribe. - private protected void Subscribe(Delegate action) - => this.Subs.Add(action); - - /// - /// Unsubscribe an expression from this registration. - /// - /// Action to unsubscribe. - private protected void Unsubscribe(Delegate action) - => this.Subs.Remove(action); - - /// - /// Invoke an action registered for inter-plugin communication. - /// - /// Action arguments. - /// This is thrown when the IPC publisher has not registered an action for calling yet. - private protected void InvokeAction(params object?[]? args) - => (this.Action ?? throw new IpcNotReadyError(this.Name)).DynamicInvoke(args); - - /// - /// Invoke a function registered for inter-plugin communication. - /// - /// Parameter args. - /// The return value. - /// This is thrown when the IPC publisher has not registered a func for calling yet. - private protected object InvokeFunc(params object?[]? args) - => (this.Func ?? throw new IpcNotReadyError(this.Name)).DynamicInvoke(args); - } -} - -#pragma warning restore SA1402 // File may only contain a single type -#pragma warning restore SA1201 // Elements should appear in the correct order diff --git a/Dalamud/Plugin/DalamudPluginInterface.cs b/Dalamud/Plugin/DalamudPluginInterface.cs index d81b1a84c..0ee445637 100644 --- a/Dalamud/Plugin/DalamudPluginInterface.cs +++ b/Dalamud/Plugin/DalamudPluginInterface.cs @@ -143,39 +143,39 @@ namespace Dalamud.Plugin /// The name of the IPC registration. /// An IPC publisher. /// This is thrown when the requested types do not match the previously registered types are different. - public ICallGatePub GetIpcPub(string name) + public ICallGateProvider GetIpcProvider(string name) => Service.Get().GetIpcPubSub(name); - /// - public ICallGatePub GetIpcPub(string name) + /// + public ICallGateProvider GetIpcProvider(string name) => Service.Get().GetIpcPubSub(name); - /// - public ICallGatePub GetIpcPub(string name) + /// + public ICallGateProvider GetIpcProvider(string name) => Service.Get().GetIpcPubSub(name); - /// - public ICallGatePub GetIpcPub(string name) + /// + public ICallGateProvider GetIpcProvider(string name) => Service.Get().GetIpcPubSub(name); - /// - public ICallGatePub GetIpcPub(string name) + /// + public ICallGateProvider GetIpcProvider(string name) => Service.Get().GetIpcPubSub(name); - /// - public ICallGatePub GetIpcPub(string name) + /// + public ICallGateProvider GetIpcProvider(string name) => Service.Get().GetIpcPubSub(name); - /// - public ICallGatePub GetIpcPub(string name) + /// + public ICallGateProvider GetIpcProvider(string name) => Service.Get().GetIpcPubSub(name); - /// - public ICallGatePub GetIpcPub(string name) + /// + public ICallGateProvider GetIpcProvider(string name) => Service.Get().GetIpcPubSub(name); - /// - public ICallGatePub GetIpcPub(string name) + /// + public ICallGateProvider GetIpcProvider(string name) => Service.Get().GetIpcPubSub(name); /// @@ -184,39 +184,39 @@ namespace Dalamud.Plugin /// The return type for funcs. Use object if this is unused. /// The name of the IPC registration. /// An IPC publisher. - public ICallGateSub GetIpcSub(string name) + public ICallGateSubscriber GetIpcSubscriber(string name) => Service.Get().GetIpcPubSub(name); - /// - public ICallGateSub GetIpcSub(string name) + /// + public ICallGateSubscriber GetIpcSubscriber(string name) => Service.Get().GetIpcPubSub(name); - /// - public ICallGateSub GetIpcSub(string name) + /// + public ICallGateSubscriber GetIpcSubscriber(string name) => Service.Get().GetIpcPubSub(name); - /// - public ICallGateSub GetIpcSub(string name) + /// + public ICallGateSubscriber GetIpcSubscriber(string name) => Service.Get().GetIpcPubSub(name); - /// - public ICallGateSub GetIpcSub(string name) + /// + public ICallGateSubscriber GetIpcSubscriber(string name) => Service.Get().GetIpcPubSub(name); - /// - public ICallGateSub GetIpcSub(string name) + /// + public ICallGateSubscriber GetIpcSubscriber(string name) => Service.Get().GetIpcPubSub(name); - /// - public ICallGateSub GetIpcSub(string name) + /// + public ICallGateSubscriber GetIpcSubscriber(string name) => Service.Get().GetIpcPubSub(name); - /// - public ICallGateSub GetIpcSub(string name) + /// + public ICallGateSubscriber GetIpcSubscriber(string name) => Service.Get().GetIpcPubSub(name); - /// - public ICallGateSub GetIpcSub(string name) + /// + public ICallGateSubscriber GetIpcSubscriber(string name) => Service.Get().GetIpcPubSub(name); #endregion diff --git a/Dalamud/Plugin/ICallGateProvider.cs b/Dalamud/Plugin/ICallGateProvider.cs new file mode 100644 index 000000000..08387b298 --- /dev/null +++ b/Dalamud/Plugin/ICallGateProvider.cs @@ -0,0 +1,127 @@ +using System; + +using Dalamud.Plugin.Internal; + +#pragma warning disable SA1402 // File may only contain a single type + +namespace Dalamud.Plugin +{ + /// + public interface ICallGateProvider + { + /// + public void RegisterAction(Action action); + + /// + public void RegisterFunc(Func func); + + /// + public void SendMessage(); + } + + /// + public interface ICallGateProvider + { + /// + public void RegisterAction(Action action); + + /// + public void RegisterFunc(Func func); + + /// + public void SendMessage(T1 arg1); + } + + /// + public interface ICallGateProvider + { + /// + public void RegisterAction(Action action); + + /// + public void RegisterFunc(Func func); + + /// + public void SendMessage(T1 arg1, T2 arg2); + } + + /// + public interface ICallGateProvider + { + /// + public void RegisterAction(Action action); + + /// + public void RegisterFunc(Func func); + + /// + public void SendMessage(T1 arg1, T2 arg2, T3 arg3); + } + + /// + public interface ICallGateProvider + { + /// + public void RegisterAction(Action action); + + /// + public void RegisterFunc(Func func); + + /// + public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4); + } + + /// + public interface ICallGateProvider + { + /// + public void RegisterAction(Action action); + + /// + public void RegisterFunc(Func func); + + /// + public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); + } + + /// + public interface ICallGateProvider + { + /// + public void RegisterAction(Action action); + + /// + public void RegisterFunc(Func func); + + /// + public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); + } + + /// + public interface ICallGateProvider + { + /// + public void RegisterAction(Action action); + + /// + public void RegisterFunc(Func func); + + /// + public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); + } + + /// + public interface ICallGateProvider + { + /// + public void RegisterAction(Action action); + + /// + public void RegisterFunc(Func func); + + /// + public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8); + } +} + +#pragma warning restore SA1402 // File may only contain a single type diff --git a/Dalamud/Plugin/ICallGateSubscriber.cs b/Dalamud/Plugin/ICallGateSubscriber.cs new file mode 100644 index 000000000..f2d9ea5a4 --- /dev/null +++ b/Dalamud/Plugin/ICallGateSubscriber.cs @@ -0,0 +1,154 @@ +using System; + +using Dalamud.Plugin.Internal; + +#pragma warning disable SA1402 // File may only contain a single type + +namespace Dalamud.Plugin +{ + /// + public interface ICallGateSubscriber + { + /// + public void Subscribe(Action action); + + /// + public void Unsubscribe(Action action); + + /// + public void InvokeAction(); + + /// + public TRet InvokeFunc(); + } + + /// + public interface ICallGateSubscriber + { + /// + public void Subscribe(Action action); + + /// + public void Unsubscribe(Action action); + + /// + public void InvokeAction(T1 arg1); + + /// + public TRet InvokeFunc(T1 arg1); + } + + /// + public interface ICallGateSubscriber + { + /// + public void Subscribe(Action action); + + /// + public void Unsubscribe(Action action); + + /// + public void InvokeAction(T1 arg1, T2 arg2); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2); + } + + /// + public interface ICallGateSubscriber + { + /// + public void Subscribe(Action action); + + /// + public void Unsubscribe(Action action); + + /// + public void InvokeAction(T1 arg1, T2 arg2, T3 arg3); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3); + } + + /// + public interface ICallGateSubscriber + { + /// + public void Subscribe(Action action); + + /// + public void Unsubscribe(Action action); + + /// + public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4); + } + + /// + public interface ICallGateSubscriber + { + /// + public void Subscribe(Action action); + + /// + public void Unsubscribe(Action action); + + /// + public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); + } + + /// + public interface ICallGateSubscriber + { + /// + public void Subscribe(Action action); + + /// + public void Unsubscribe(Action action); + + /// + public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); + } + + /// + public interface ICallGateSubscriber + { + /// + public void Subscribe(Action action); + + /// + public void Unsubscribe(Action action); + + /// + public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); + } + + /// + public interface ICallGateSubscriber + { + /// + public void Subscribe(Action action); + + /// + public void Unsubscribe(Action action); + + /// + public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8); + } +} + +#pragma warning restore SA1402 // File may only contain a single type diff --git a/Dalamud/Plugin/Internal/CallGate.cs b/Dalamud/Plugin/Internal/CallGate.cs new file mode 100644 index 000000000..7ec4d9dc7 --- /dev/null +++ b/Dalamud/Plugin/Internal/CallGate.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Dalamud.Plugin.Internal +{ + /// + /// This class facilitates inter-plugin communication. + /// + internal class CallGate + { + private Dictionary gates = new(); + + #region GetIpcPubSub + + /// + internal CallGatePubSub GetIpcPubSub(string name) + => (CallGatePubSub)this.GetIpcPubSub(name, typeof(TRet)); + + /// + internal CallGatePubSub GetIpcPubSub(string name) + => (CallGatePubSub)this.GetIpcPubSub(name, typeof(T1), typeof(TRet)); + + /// + internal CallGatePubSub GetIpcPubSub(string name) + => (CallGatePubSub)this.GetIpcPubSub(name, typeof(T1), typeof(T2), typeof(TRet)); + + /// + internal CallGatePubSub GetIpcPubSub(string name) + => (CallGatePubSub)this.GetIpcPubSub(name, typeof(T1), typeof(T2), typeof(T3), typeof(TRet)); + + /// + internal CallGatePubSub GetIpcPubSub(string name) + => (CallGatePubSub)this.GetIpcPubSub(name, typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(TRet)); + + /// + internal CallGatePubSub GetIpcPubSub(string name) + => (CallGatePubSub)this.GetIpcPubSub(name, typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(TRet)); + + /// + internal CallGatePubSub GetIpcPubSub(string name) + => (CallGatePubSub)this.GetIpcPubSub(name, typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(TRet)); + + /// + internal CallGatePubSub GetIpcPubSub(string name) + => (CallGatePubSub)this.GetIpcPubSub(name, typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(TRet)); + + /// + internal CallGatePubSub GetIpcPubSub(string name) + => (CallGatePubSub)this.GetIpcPubSub(name, typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(TRet)); + + #endregion + + /// + /// Gets or sets an IPC pub/sub callgate. + /// + /// Name of the IPC registration. + /// The callgate parameter types. + /// The IPC pub/sub callgate. + private CallGatePubSubBase GetIpcPubSub(string name, params Type[] types) + { + if (!this.gates.TryGetValue(name, out var callGate)) + { + var generic = types.Length switch + { + 1 => typeof(CallGatePubSub<>), + 2 => typeof(CallGatePubSub<,>), + 3 => typeof(CallGatePubSub<,,>), + 4 => typeof(CallGatePubSub<,,,>), + 5 => typeof(CallGatePubSub<,,,,>), + 6 => typeof(CallGatePubSub<,,,,,>), + 7 => typeof(CallGatePubSub<,,,,,,>), + 8 => typeof(CallGatePubSub<,,,,,,,>), + 9 => typeof(CallGatePubSub<,,,,,,,,>), + _ => throw new Exception("Misconfigured number of type args"), + }; + + var type = generic.MakeGenericType(types); + callGate = (CallGatePubSubBase)Activator.CreateInstance(type); + callGate.Name = name; + + this.gates[name] = callGate; + } + + var requested = callGate.GetType().GenericTypeArguments; + if (!Enumerable.SequenceEqual(requested, types)) + throw new IpcTypeMismatchError(name, requested, types); + + return callGate; + } + } +} diff --git a/Dalamud/Plugin/Internal/CallGatePubSub.cs b/Dalamud/Plugin/Internal/CallGatePubSub.cs new file mode 100644 index 000000000..76ba0b885 --- /dev/null +++ b/Dalamud/Plugin/Internal/CallGatePubSub.cs @@ -0,0 +1,296 @@ +using System; + +#pragma warning disable SA1402 // File may only contain a single type + +namespace Dalamud.Plugin.Internal +{ + /// + internal class CallGatePubSub : CallGatePubSubBase, ICallGateProvider, ICallGateSubscriber + { + /// + public void RegisterAction(Action action) + => base.RegisterAction(action); + + /// + public void RegisterFunc(Func func) + => base.RegisterFunc(func); + + /// + public void SendMessage() + => base.SendMessage(); + + /// + public void Subscribe(Action action) + => base.Subscribe(action); + + /// + public void Unsubscribe(Action action) + => base.Unsubscribe(action); + + /// + public void InvokeAction() + => base.InvokeAction(); + + /// + public TRet InvokeFunc() + => (TRet)base.InvokeFunc(); + } + + /// + internal class CallGatePubSub : CallGatePubSubBase, ICallGateProvider, ICallGateSubscriber + { + /// + public void RegisterAction(Action action) + => base.RegisterAction(action); + + /// + public void RegisterFunc(Func func) + => base.RegisterFunc(func); + + /// + public void SendMessage(T1 arg1) + => base.SendMessage(arg1); + + /// + public void Subscribe(Action action) + => base.Subscribe(action); + + /// + public void Unsubscribe(Action action) + => base.Unsubscribe(action); + + /// + public void InvokeAction(T1 arg1) + => base.InvokeAction(arg1); + + /// + public TRet InvokeFunc(T1 arg1) + => (TRet)base.InvokeFunc(arg1); + } + + /// + internal class CallGatePubSub : CallGatePubSubBase, ICallGateProvider, ICallGateSubscriber + { + /// + public void RegisterAction(Action action) + => base.RegisterAction(action); + + /// + public void RegisterFunc(Func func) + => base.RegisterFunc(func); + + /// + public void SendMessage(T1 arg1, T2 arg2) + => base.SendMessage(arg1, arg2); + + /// + public void Subscribe(Action action) + => base.Subscribe(action); + + /// + public void Unsubscribe(Action action) + => base.Unsubscribe(action); + + /// + public void InvokeAction(T1 arg1, T2 arg2) + => base.InvokeAction(arg1, arg2); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2) + => (TRet)base.InvokeFunc(arg1, arg2); + } + + /// + internal class CallGatePubSub : CallGatePubSubBase, ICallGateProvider, ICallGateSubscriber + { + /// + public void RegisterAction(Action action) + => base.RegisterAction(action); + + /// + public void RegisterFunc(Func func) + => base.RegisterFunc(func); + + /// + public void SendMessage(T1 arg1, T2 arg2, T3 arg3) + => base.SendMessage(arg1, arg2, arg3); + + /// + public void Subscribe(Action action) + => base.Subscribe(action); + + /// + public void Unsubscribe(Action action) + => base.Unsubscribe(action); + + /// + public void InvokeAction(T1 arg1, T2 arg2, T3 arg3) + => base.InvokeAction(arg1, arg2, arg3); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3) + => (TRet)base.InvokeFunc(arg1, arg2, arg3); + } + + /// + internal class CallGatePubSub : CallGatePubSubBase, ICallGateProvider, ICallGateSubscriber + { + /// + public void RegisterAction(Action action) + => base.RegisterAction(action); + + /// + public void RegisterFunc(Func func) + => base.RegisterFunc(func); + + /// + public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4) + => base.SendMessage(arg1, arg2, arg3, arg4); + + /// + public void Subscribe(Action action) + => base.Subscribe(action); + + /// + public void Unsubscribe(Action action) + => base.Unsubscribe(action); + + /// + public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4) + => base.InvokeAction(arg1, arg2, arg3, arg4); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4) + => (TRet)base.InvokeFunc(arg1, arg2, arg3, arg4); + } + + /// + internal class CallGatePubSub : CallGatePubSubBase, ICallGateProvider, ICallGateSubscriber + { + /// + public void RegisterAction(Action action) + => base.RegisterAction(action); + + /// + public void RegisterFunc(Func func) + => base.RegisterFunc(func); + + /// + public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) + => base.SendMessage(arg1, arg2, arg3, arg4, arg5); + + /// + public void Subscribe(Action action) + => base.Subscribe(action); + + /// + public void Unsubscribe(Action action) + => base.Unsubscribe(action); + + /// + public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) + => base.InvokeAction(arg1, arg2, arg3, arg4, arg5); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) + => (TRet)base.InvokeFunc(arg1, arg2, arg3, arg4, arg5); + } + + /// + internal class CallGatePubSub : CallGatePubSubBase, ICallGateProvider, ICallGateSubscriber + { + /// + public void RegisterAction(Action action) + => base.RegisterAction(action); + + /// + public void RegisterFunc(Func func) + => base.RegisterFunc(func); + + /// + public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) + => base.SendMessage(arg1, arg2, arg3, arg4, arg5, arg6); + + /// + public void Subscribe(Action action) + => base.Subscribe(action); + + /// + public void Unsubscribe(Action action) + => base.Unsubscribe(action); + + /// + public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) + => base.InvokeAction(arg1, arg2, arg3, arg4, arg5, arg6); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) + => (TRet)base.InvokeFunc(arg1, arg2, arg3, arg4, arg5, arg6); + } + + /// + internal class CallGatePubSub : CallGatePubSubBase, ICallGateProvider, ICallGateSubscriber + { + /// + public void RegisterAction(Action action) + => base.RegisterAction(action); + + /// + public void RegisterFunc(Func func) + => base.RegisterFunc(func); + + /// + public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) + => base.SendMessage(arg1, arg2, arg3, arg4, arg5, arg6, arg7); + + /// + public void Subscribe(Action action) + => base.Subscribe(action); + + /// + public void Unsubscribe(Action action) + => base.Unsubscribe(action); + + /// + public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) + => base.InvokeAction(arg1, arg2, arg3, arg4, arg5, arg6, arg7); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) + => (TRet)base.InvokeFunc(arg1, arg2, arg3, arg4, arg5, arg6, arg7); + } + + /// + internal class CallGatePubSub : CallGatePubSubBase, ICallGateProvider, ICallGateSubscriber + { + /// + public void RegisterAction(Action action) + => base.RegisterAction(action); + + /// + public void RegisterFunc(Func func) + => base.RegisterFunc(func); + + /// + public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) + => base.SendMessage(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + + /// + public void Subscribe(Action action) + => base.Subscribe(action); + + /// + public void Unsubscribe(Action action) + => base.Unsubscribe(action); + + /// + public void InvokeAction(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) + => base.InvokeAction(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + + /// + public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) + => (TRet)base.InvokeFunc(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + } +} + +#pragma warning restore SA1402 // File may only contain a single type diff --git a/Dalamud/Plugin/Internal/CallGatePubSubBase.cs b/Dalamud/Plugin/Internal/CallGatePubSubBase.cs new file mode 100644 index 000000000..a523b48af --- /dev/null +++ b/Dalamud/Plugin/Internal/CallGatePubSubBase.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; + +using Serilog; + +namespace Dalamud.Plugin.Internal +{ + /// + /// This class facilitates inter-plugin communication. + /// + internal abstract class CallGatePubSubBase + { + /// + /// Initializes a new instance of the class. + /// + internal CallGatePubSubBase() + { + } + + /// + /// Gets or sets the name of the IPC registration. + /// + public string Name { get; internal set; } + + /// + /// Gets or sets the Action. + /// + protected Delegate? Action { get; set; } + + /// + /// Gets or sets the Func. + /// + protected Delegate? Func { get; set; } + + /// + /// Gets the list of subscribed delegates. + /// + protected List Subs { get; } = new(); + + /// + /// Removes a registered Action from inter-plugin communication. + /// + public void UnregisterAction() + => this.Action = null; + + /// + /// Removes a registered Func from inter-plugin communication. + /// + public void UnregisterFunc() + => this.Func = null; + + /// + /// Removes a registered Action from inter-plugin communication. + /// + /// Action to register. + private protected void RegisterAction(Delegate action) + => this.Action = action; + + /// + /// Removes a registered Func from inter-plugin communication. + /// + /// Func to register. + private protected void RegisterFunc(Delegate func) + => this.Func = func; + + /// + /// Invoke all actions that have subscribed to this IPC. + /// + /// Delegate arguments. + private protected void SendMessage(params object?[]? args) + { + foreach (var sub in this.Subs) + { + try + { + sub.DynamicInvoke(args); + } + catch (Exception ex) + { + Log.Error(ex, $"Error invoking a subscription of {this.Name}"); + } + } + } + + /// + /// Subscribe an expression to this registration. + /// + /// Action to subscribe. + private protected void Subscribe(Delegate action) + => this.Subs.Add(action); + + /// + /// Unsubscribe an expression from this registration. + /// + /// Action to unsubscribe. + private protected void Unsubscribe(Delegate action) + => this.Subs.Remove(action); + + /// + /// Invoke an action registered for inter-plugin communication. + /// + /// Action arguments. + /// This is thrown when the IPC publisher has not registered an action for calling yet. + private protected void InvokeAction(params object?[]? args) + => (this.Action ?? throw new IpcNotReadyError(this.Name)).DynamicInvoke(args); + + /// + /// Invoke a function registered for inter-plugin communication. + /// + /// Parameter args. + /// The return value. + /// This is thrown when the IPC publisher has not registered a func for calling yet. + private protected object InvokeFunc(params object?[]? args) + => (this.Func ?? throw new IpcNotReadyError(this.Name)).DynamicInvoke(args); + } +}