From d1bf50392cf16f364b027384fbb72d8fefe98af5 Mon Sep 17 00:00:00 2001 From: Kaz Wolfe Date: Sun, 15 Sep 2024 11:09:50 -0700 Subject: [PATCH] feat: Add new IPC methods, and docs - New methods `HasAction`, `HasFunction`, and `SubscriptionCount` to allow making better decisions about IPC logic. - Some better documentation for the call gates. --- Dalamud/Plugin/Ipc/ICallGateProvider.cs | 106 ++++++------------ Dalamud/Plugin/Ipc/ICallGateSubscriber.cs | 31 +++-- .../Plugin/Ipc/Internal/CallGatePubSubBase.cs | 67 +++++++++-- 3 files changed, 113 insertions(+), 91 deletions(-) diff --git a/Dalamud/Plugin/Ipc/ICallGateProvider.cs b/Dalamud/Plugin/Ipc/ICallGateProvider.cs index cf4c59b2e9..1d160d9cbb 100644 --- a/Dalamud/Plugin/Ipc/ICallGateProvider.cs +++ b/Dalamud/Plugin/Ipc/ICallGateProvider.cs @@ -4,27 +4,37 @@ namespace Dalamud.Plugin.Ipc; -/// -public interface ICallGateProvider +/// +/// The backing interface for the provider ("server") half of an IPC channel. This interface is used to expose methods +/// to other plugins via RPC, as well as to allow other plugins to subscribe to notifications from this plugin. +/// +public interface ICallGateProvider { - /// - public void RegisterAction(Action action); - - /// - public void RegisterFunc(Func func); - + /// + public int SubscriptionCount { get; } + /// public void UnregisterAction(); /// public void UnregisterFunc(); +} + +/// +public interface ICallGateProvider : ICallGateProvider +{ + /// + public void RegisterAction(Action action); + + /// + public void RegisterFunc(Func func); /// public void SendMessage(); } -/// -public interface ICallGateProvider +/// +public interface ICallGateProvider : ICallGateProvider { /// public void RegisterAction(Action action); @@ -32,18 +42,12 @@ public interface ICallGateProvider /// public void RegisterFunc(Func func); - /// - public void UnregisterAction(); - - /// - public void UnregisterFunc(); - /// public void SendMessage(T1 arg1); } -/// -public interface ICallGateProvider +/// +public interface ICallGateProvider : ICallGateProvider { /// public void RegisterAction(Action action); @@ -51,18 +55,12 @@ public interface ICallGateProvider /// public void RegisterFunc(Func func); - /// - public void UnregisterAction(); - - /// - public void UnregisterFunc(); - /// public void SendMessage(T1 arg1, T2 arg2); } -/// -public interface ICallGateProvider +/// +public interface ICallGateProvider : ICallGateProvider { /// public void RegisterAction(Action action); @@ -70,18 +68,12 @@ public interface ICallGateProvider /// public void RegisterFunc(Func func); - /// - public void UnregisterAction(); - - /// - public void UnregisterFunc(); - /// public void SendMessage(T1 arg1, T2 arg2, T3 arg3); } -/// -public interface ICallGateProvider +/// +public interface ICallGateProvider : ICallGateProvider { /// public void RegisterAction(Action action); @@ -89,18 +81,12 @@ public interface ICallGateProvider /// public void RegisterFunc(Func func); - /// - public void UnregisterAction(); - - /// - public void UnregisterFunc(); - /// public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4); } -/// -public interface ICallGateProvider +/// +public interface ICallGateProvider : ICallGateProvider { /// public void RegisterAction(Action action); @@ -108,18 +94,12 @@ public interface ICallGateProvider /// public void RegisterFunc(Func func); - /// - public void UnregisterAction(); - - /// - public void UnregisterFunc(); - /// public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); } -/// -public interface ICallGateProvider +/// +public interface ICallGateProvider : ICallGateProvider { /// public void RegisterAction(Action action); @@ -127,18 +107,12 @@ public interface ICallGateProvider /// public void RegisterFunc(Func func); - /// - public void UnregisterAction(); - - /// - public void UnregisterFunc(); - /// public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); } -/// -public interface ICallGateProvider +/// +public interface ICallGateProvider : ICallGateProvider { /// public void RegisterAction(Action action); @@ -146,18 +120,12 @@ public interface ICallGateProvider /// public void RegisterFunc(Func func); - /// - public void UnregisterAction(); - - /// - public void UnregisterFunc(); - /// public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); } -/// -public interface ICallGateProvider +/// +public interface ICallGateProvider : ICallGateProvider { /// public void RegisterAction(Action action); @@ -165,12 +133,6 @@ public interface ICallGateProvider /// public void RegisterFunc(Func func); - /// - public void UnregisterAction(); - - /// - public void UnregisterFunc(); - /// public void SendMessage(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8); } diff --git a/Dalamud/Plugin/Ipc/ICallGateSubscriber.cs b/Dalamud/Plugin/Ipc/ICallGateSubscriber.cs index 40d642a612..fd67ec7db6 100644 --- a/Dalamud/Plugin/Ipc/ICallGateSubscriber.cs +++ b/Dalamud/Plugin/Ipc/ICallGateSubscriber.cs @@ -4,8 +4,21 @@ namespace Dalamud.Plugin.Ipc; +/// +/// An interface for all IPC subscribers. +/// +public interface ICallGateSubscriber +{ + + /// + public bool HasAction { get; } + + /// + public bool HasFunction { get; } +} + /// -public interface ICallGateSubscriber +public interface ICallGateSubscriber : ICallGateSubscriber { /// public void Subscribe(Action action); @@ -21,7 +34,7 @@ public interface ICallGateSubscriber } /// -public interface ICallGateSubscriber +public interface ICallGateSubscriber : ICallGateSubscriber { /// public void Subscribe(Action action); @@ -37,7 +50,7 @@ public interface ICallGateSubscriber } /// -public interface ICallGateSubscriber +public interface ICallGateSubscriber : ICallGateSubscriber { /// public void Subscribe(Action action); @@ -53,7 +66,7 @@ public interface ICallGateSubscriber } /// -public interface ICallGateSubscriber +public interface ICallGateSubscriber : ICallGateSubscriber { /// public void Subscribe(Action action); @@ -69,7 +82,7 @@ public interface ICallGateSubscriber } /// -public interface ICallGateSubscriber +public interface ICallGateSubscriber : ICallGateSubscriber { /// public void Subscribe(Action action); @@ -84,7 +97,7 @@ public interface ICallGateSubscriber public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4); } -/// +/// : ICallGateSubscriber public interface ICallGateSubscriber { /// @@ -100,7 +113,7 @@ public interface ICallGateSubscriber public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); } -/// +/// : ICallGateSubscriber public interface ICallGateSubscriber { /// @@ -116,7 +129,7 @@ public interface ICallGateSubscriber public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); } -/// +/// : ICallGateSubscriber public interface ICallGateSubscriber { /// @@ -132,7 +145,7 @@ public interface ICallGateSubscriber public TRet InvokeFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); } -/// +/// : ICallGateSubscriber public interface ICallGateSubscriber { /// diff --git a/Dalamud/Plugin/Ipc/Internal/CallGatePubSubBase.cs b/Dalamud/Plugin/Ipc/Internal/CallGatePubSubBase.cs index b6a4e8a61b..3084573733 100644 --- a/Dalamud/Plugin/Ipc/Internal/CallGatePubSubBase.cs +++ b/Dalamud/Plugin/Ipc/Internal/CallGatePubSubBase.cs @@ -16,71 +16,118 @@ protected CallGatePubSubBase(string name) this.Channel = Service.Get().GetOrCreateChannel(name); } + /// + /// Gets a value indicating whether this IPC call gate has an associated Action. Only exposed to + /// s. + /// + public bool HasAction => this.Channel.Action != null; + + /// + /// Gets a value indicating whether this IPC call gate has an associated Function. Only exposed to + /// s. + /// + public bool HasFunction => this.Channel.Func != null; + + /// + /// Gets the count of subscribers listening for messages through this call gate. Only exposed to + /// s, and can be used to determine if messages should be sent through the gate. + /// + public int SubscriptionCount => this.Channel.Subscriptions.Count; + /// /// Gets the underlying channel implementation. /// protected CallGateChannel Channel { get; init; } - + /// - /// Removes a registered Action from inter-plugin communication. + /// Removes the associated Action from this call gate, effectively disabling RPC calls. /// + /// public void UnregisterAction() => this.Channel.Action = null; /// - /// Removes a registered Func from inter-plugin communication. + /// Removes the associated Function from this call gate. /// + /// public void UnregisterFunc() => this.Channel.Func = null; /// - /// Registers an Action for inter-plugin communication. + /// Registers a for use by other plugins via RPC. This Delegate must satisfy the constraints + /// of an type as defined by the interface, meaning they may not return a value and must have + /// the proper number of parameters. /// /// Action to register. + /// + /// private protected void RegisterAction(Delegate action) => this.Channel.Action = action; /// - /// Registers a Func for inter-plugin communication. + /// Registers a for use by other plugins via RPC. This Delegate must satisfy the constraints + /// of a type as defined by the interface, meaning its return type and parameters must + /// match accordingly. /// /// Func to register. + /// + /// private protected void RegisterFunc(Delegate func) => this.Channel.Func = func; /// - /// Subscribe an expression to this registration. + /// Registers a (of type ) that will be called when the providing + /// plugin calls . This method can be used to receive notifications + /// of events or data updates from a specific plugin. /// /// Action to subscribe. + /// private protected void Subscribe(Delegate action) => this.Channel.Subscribe(action); /// - /// Unsubscribe an expression from this registration. + /// Removes a subscription created through . Note that the to be + /// unsubscribed must be the same instance as the one passed in. /// /// Action to unsubscribe. + /// private protected void Unsubscribe(Delegate action) => this.Channel.Unsubscribe(action); /// - /// Invoke an action registered for inter-plugin communication. + /// Executes the Action registered for this IPC call gate via . This method is intended + /// to be called by plugins wishing to access another plugin via RPC. The parameters passed to this method will be + /// passed to the owning plugin, with appropriate serialization for complex data types. Primitive data types will + /// be passed as-is. The target Action will be called on the same thread as the caller. /// /// 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.Channel.InvokeAction(args); /// - /// Invoke a function registered for inter-plugin communication. + /// Executes the Function registered for this IPC call gate via . This method is intended + /// to be called by plugins wishing to access another plugin via RPC. The parameters passed to this method will be + /// passed to the owning plugin, with appropriate serialization for complex data types. Primitive data types will + /// be passed as-is. The target Action will be called on the same thread as the caller. /// /// Parameter args. /// The return value. /// The return type. /// This is thrown when the IPC publisher has not registered a func for calling yet. + /// + /// private protected TRet InvokeFunc(params object?[]? args) => this.Channel.InvokeFunc(args); /// - /// Invoke all actions that have subscribed to this IPC. + /// Send the given arguments to all subscribers (through ) of this IPC call gate. This method + /// is intended to be used by the provider plugin to notify all subscribers of an event or data update. The + /// parameters passed to this method will be passed to all subscribers, with appropriate serialization for complex + /// data types. Primitive data types will be passed as-is. The subscription actions will be called sequentially in + /// order of registration on the same thread as the caller. /// /// Delegate arguments. private protected void SendMessage(params object?[]? args)