diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/PluginIpcWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/PluginIpcWidget.cs index 0ca754a91..1f1f82cdd 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/PluginIpcWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/PluginIpcWidget.cs @@ -48,12 +48,20 @@ internal class PluginIpcWidget : IDataWindowWidget this.ipcPub.RegisterAction(msg => { - Log.Information("Data action was called: {Msg}", msg); + Log.Information( + "Data action was called: {Msg}\n" + + " Context: {Context}", + msg, + this.ipcPub.GetContext()); }); this.ipcPub.RegisterFunc(msg => { - Log.Information("Data func was called: {Msg}", msg); + Log.Information( + "Data func was called: {Msg}\n" + + " Context: {Context}", + msg, + this.ipcPub.GetContext()); return Guid.NewGuid().ToString(); }); } @@ -61,14 +69,8 @@ internal class PluginIpcWidget : IDataWindowWidget if (this.ipcSub == null) { this.ipcSub = new CallGatePubSub("dataDemo1"); - this.ipcSub.Subscribe(_ => - { - Log.Information("PONG1"); - }); - this.ipcSub.Subscribe(_ => - { - Log.Information("PONG2"); - }); + this.ipcSub.Subscribe(_ => { Log.Information("PONG1"); }); + this.ipcSub.Subscribe(_ => { Log.Information("PONG2"); }); this.ipcSub.Subscribe(_ => throw new Exception("PONG3")); } @@ -78,12 +80,21 @@ internal class PluginIpcWidget : IDataWindowWidget this.ipcPubGo.RegisterAction(go => { - Log.Information("Data action was called: {Name}", go?.Name); + Log.Information( + "Data action was called: {Name}" + + "\n Context: {Context}", + go?.Name, + this.ipcPubGo.GetContext()); }); this.ipcPubGo.RegisterFunc(go => { - Log.Information("Data func was called: {Name}", go?.Name); + Log.Information( + "Data func was called: {Name}\n" + + " Context: {Context}", + go?.Name, + this.ipcPubGo.GetContext()); + return "test"; }); } diff --git a/Dalamud/Plugin/DalamudPluginInterface.cs b/Dalamud/Plugin/DalamudPluginInterface.cs index 6fd9064b6..aa7237358 100644 --- a/Dalamud/Plugin/DalamudPluginInterface.cs +++ b/Dalamud/Plugin/DalamudPluginInterface.cs @@ -248,75 +248,75 @@ internal sealed class DalamudPluginInterface : IDalamudPluginInterface, IDisposa /// public ICallGateProvider GetIpcProvider(string name) - => new CallGatePubSub(name); + => new CallGatePubSub(name, this.plugin); /// public ICallGateProvider GetIpcProvider(string name) - => new CallGatePubSub(name); + => new CallGatePubSub(name, this.plugin); /// public ICallGateProvider GetIpcProvider(string name) - => new CallGatePubSub(name); + => new CallGatePubSub(name, this.plugin); /// public ICallGateProvider GetIpcProvider(string name) - => new CallGatePubSub(name); + => new CallGatePubSub(name, this.plugin); /// public ICallGateProvider GetIpcProvider(string name) - => new CallGatePubSub(name); + => new CallGatePubSub(name, this.plugin); /// public ICallGateProvider GetIpcProvider(string name) - => new CallGatePubSub(name); + => new CallGatePubSub(name, this.plugin); /// public ICallGateProvider GetIpcProvider(string name) - => new CallGatePubSub(name); + => new CallGatePubSub(name, this.plugin); /// public ICallGateProvider GetIpcProvider(string name) - => new CallGatePubSub(name); + => new CallGatePubSub(name, this.plugin); /// public ICallGateProvider GetIpcProvider(string name) - => new CallGatePubSub(name); + => new CallGatePubSub(name, this.plugin); /// public ICallGateSubscriber GetIpcSubscriber(string name) - => new CallGatePubSub(name); + => new CallGatePubSub(name, this.plugin); /// public ICallGateSubscriber GetIpcSubscriber(string name) - => new CallGatePubSub(name); + => new CallGatePubSub(name, this.plugin); /// public ICallGateSubscriber GetIpcSubscriber(string name) - => new CallGatePubSub(name); + => new CallGatePubSub(name, this.plugin); /// public ICallGateSubscriber GetIpcSubscriber(string name) - => new CallGatePubSub(name); + => new CallGatePubSub(name, this.plugin); /// public ICallGateSubscriber GetIpcSubscriber(string name) - => new CallGatePubSub(name); + => new CallGatePubSub(name, this.plugin); /// public ICallGateSubscriber GetIpcSubscriber(string name) - => new CallGatePubSub(name); + => new CallGatePubSub(name, this.plugin); /// public ICallGateSubscriber GetIpcSubscriber(string name) - => new CallGatePubSub(name); + => new CallGatePubSub(name, this.plugin); /// public ICallGateSubscriber GetIpcSubscriber(string name) - => new CallGatePubSub(name); + => new CallGatePubSub(name, this.plugin); /// public ICallGateSubscriber GetIpcSubscriber(string name) - => new CallGatePubSub(name); + => new CallGatePubSub(name, this.plugin); #endregion diff --git a/Dalamud/Plugin/Ipc/ICallGateProvider.cs b/Dalamud/Plugin/Ipc/ICallGateProvider.cs index f4e5c76d7..387f0adf9 100644 --- a/Dalamud/Plugin/Ipc/ICallGateProvider.cs +++ b/Dalamud/Plugin/Ipc/ICallGateProvider.cs @@ -19,6 +19,9 @@ public interface ICallGateProvider /// public void UnregisterFunc(); + + /// + public IpcContext? GetContext(); } /// diff --git a/Dalamud/Plugin/Ipc/Internal/CallGateChannel.cs b/Dalamud/Plugin/Ipc/Internal/CallGateChannel.cs index ea94103f7..e177abab7 100644 --- a/Dalamud/Plugin/Ipc/Internal/CallGateChannel.cs +++ b/Dalamud/Plugin/Ipc/Internal/CallGateChannel.cs @@ -2,7 +2,9 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Reflection; +using System.Threading; +using Dalamud.Plugin.Internal.Types; using Dalamud.Plugin.Ipc.Exceptions; using Dalamud.Plugin.Ipc.Internal.Converters; @@ -16,6 +18,8 @@ namespace Dalamud.Plugin.Ipc.Internal; /// internal class CallGateChannel { + private readonly ThreadLocal ipcExecutionContext = new(); + /// /// The actual storage. /// @@ -145,6 +149,21 @@ internal class CallGateChannel return (TRet)result; } + internal void SetInvocationContext(IpcContext ipcContext) + { + this.ipcExecutionContext.Value = ipcContext; + } + + internal IpcContext? GetInvocationContext() + { + return this.ipcExecutionContext.IsValueCreated ? this.ipcExecutionContext.Value : null; + } + + internal void ClearInvocationContext() + { + this.ipcExecutionContext.Value = null; + } + private void CheckAndConvertArgs(object?[]? args, MethodInfo methodInfo) { var paramTypes = methodInfo.GetParameters() diff --git a/Dalamud/Plugin/Ipc/Internal/CallGatePubSub.cs b/Dalamud/Plugin/Ipc/Internal/CallGatePubSub.cs index cc54a563b..8725ef733 100644 --- a/Dalamud/Plugin/Ipc/Internal/CallGatePubSub.cs +++ b/Dalamud/Plugin/Ipc/Internal/CallGatePubSub.cs @@ -1,3 +1,5 @@ +using Dalamud.Plugin.Internal.Types; + #pragma warning disable SA1402 // File may only contain a single type namespace Dalamud.Plugin.Ipc.Internal; @@ -5,9 +7,9 @@ namespace Dalamud.Plugin.Ipc.Internal; /// internal class CallGatePubSub : CallGatePubSubBase, ICallGateProvider, ICallGateSubscriber { - /// - public CallGatePubSub(string name) - : base(name) + /// + public CallGatePubSub(string name, LocalPlugin? owningPlugin = null) + : base(name, owningPlugin) { } @@ -43,9 +45,9 @@ internal class CallGatePubSub : CallGatePubSubBase, ICallGateProvider internal class CallGatePubSub : CallGatePubSubBase, ICallGateProvider, ICallGateSubscriber { - /// - public CallGatePubSub(string name) - : base(name) + /// + public CallGatePubSub(string name, LocalPlugin? owningPlugin = null) + : base(name, owningPlugin) { } @@ -81,9 +83,9 @@ internal class CallGatePubSub : CallGatePubSubBase, ICallGateProvider< /// internal class CallGatePubSub : CallGatePubSubBase, ICallGateProvider, ICallGateSubscriber { - /// - public CallGatePubSub(string name) - : base(name) + /// + public CallGatePubSub(string name, LocalPlugin? owningPlugin = null) + : base(name, owningPlugin) { } @@ -119,9 +121,9 @@ internal class CallGatePubSub : CallGatePubSubBase, ICallGateProvi /// internal class CallGatePubSub : CallGatePubSubBase, ICallGateProvider, ICallGateSubscriber { - /// - public CallGatePubSub(string name) - : base(name) + /// + public CallGatePubSub(string name, LocalPlugin? owningPlugin = null) + : base(name, owningPlugin) { } @@ -157,9 +159,9 @@ internal class CallGatePubSub : CallGatePubSubBase, ICallGateP /// internal class CallGatePubSub : CallGatePubSubBase, ICallGateProvider, ICallGateSubscriber { - /// - public CallGatePubSub(string name) - : base(name) + /// + public CallGatePubSub(string name, LocalPlugin? owningPlugin = null) + : base(name, owningPlugin) { } @@ -195,9 +197,9 @@ internal class CallGatePubSub : CallGatePubSubBase, ICallG /// internal class CallGatePubSub : CallGatePubSubBase, ICallGateProvider, ICallGateSubscriber { - /// - public CallGatePubSub(string name) - : base(name) + /// + public CallGatePubSub(string name, LocalPlugin? owningPlugin = null) + : base(name, owningPlugin) { } @@ -233,9 +235,9 @@ internal class CallGatePubSub : CallGatePubSubBase, IC /// internal class CallGatePubSub : CallGatePubSubBase, ICallGateProvider, ICallGateSubscriber { - /// - public CallGatePubSub(string name) - : base(name) + /// + public CallGatePubSub(string name, LocalPlugin? owningPlugin = null) + : base(name, owningPlugin) { } @@ -271,9 +273,9 @@ internal class CallGatePubSub : CallGatePubSubBase /// internal class CallGatePubSub : CallGatePubSubBase, ICallGateProvider, ICallGateSubscriber { - /// - public CallGatePubSub(string name) - : base(name) + /// + public CallGatePubSub(string name, LocalPlugin? owningPlugin = null) + : base(name, owningPlugin) { } @@ -309,9 +311,9 @@ internal class CallGatePubSub : CallGatePubSub /// internal class CallGatePubSub : CallGatePubSubBase, ICallGateProvider, ICallGateSubscriber { - /// - public CallGatePubSub(string name) - : base(name) + /// + public CallGatePubSub(string name, LocalPlugin? owningPlugin = null) + : base(name, owningPlugin) { } diff --git a/Dalamud/Plugin/Ipc/Internal/CallGatePubSubBase.cs b/Dalamud/Plugin/Ipc/Internal/CallGatePubSubBase.cs index 308457373..521824b7b 100644 --- a/Dalamud/Plugin/Ipc/Internal/CallGatePubSubBase.cs +++ b/Dalamud/Plugin/Ipc/Internal/CallGatePubSubBase.cs @@ -1,4 +1,11 @@ +using System.Reactive.Disposables; +using System.Threading; + +using Dalamud.Plugin.Internal.Types; using Dalamud.Plugin.Ipc.Exceptions; +using Dalamud.Utility; + +using Serilog; namespace Dalamud.Plugin.Ipc.Internal; @@ -11,9 +18,11 @@ internal abstract class CallGatePubSubBase /// Initializes a new instance of the class. /// /// The name of the IPC registration. - protected CallGatePubSubBase(string name) + /// The plugin that owns this IPC pubsub. + protected CallGatePubSubBase(string name, LocalPlugin? owningPlugin) { this.Channel = Service.Get().GetOrCreateChannel(name); + this.OwningPlugin = owningPlugin; } /// @@ -21,7 +30,7 @@ internal abstract class CallGatePubSubBase /// 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. @@ -33,12 +42,17 @@ internal abstract class CallGatePubSubBase /// 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; } - + + /// + /// Gets the plugin that owns this pubsub instance. + /// + protected LocalPlugin? OwningPlugin { get; init; } + /// /// Removes the associated Action from this call gate, effectively disabling RPC calls. /// @@ -53,6 +67,16 @@ internal abstract class CallGatePubSubBase public void UnregisterFunc() => this.Channel.Func = null; + /// + /// Gets the current context for this IPC call. This will only be present when called from within an IPC action + /// or function handler, and will be null otherwise. + /// + /// Returns a potential IPC context. + public IpcContext? GetContext() + { + return this.Channel.GetInvocationContext(); + } + /// /// 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 @@ -105,7 +129,12 @@ internal abstract class CallGatePubSubBase /// /// private protected void InvokeAction(params object?[]? args) - => this.Channel.InvokeAction(args); + { + using (this.BuildContext()) + { + this.Channel.InvokeAction(args); + } + } /// /// Executes the Function registered for this IPC call gate via . This method is intended @@ -120,7 +149,12 @@ internal abstract class CallGatePubSubBase /// /// private protected TRet InvokeFunc(params object?[]? args) - => this.Channel.InvokeFunc(args); + { + using (this.BuildContext()) + { + return this.Channel.InvokeFunc(args); + } + } /// /// Send the given arguments to all subscribers (through ) of this IPC call gate. This method @@ -132,4 +166,14 @@ internal abstract class CallGatePubSubBase /// Delegate arguments. private protected void SendMessage(params object?[]? args) => this.Channel.SendMessage(args); + + private IDisposable BuildContext() + { + this.Channel.SetInvocationContext(new IpcContext + { + SourcePlugin = this.OwningPlugin != null ? new ExposedPlugin(this.OwningPlugin) : null, + }); + + return Disposable.Create(() => { this.Channel.ClearInvocationContext(); }); + } } diff --git a/Dalamud/Plugin/Ipc/IpcContext.cs b/Dalamud/Plugin/Ipc/IpcContext.cs new file mode 100644 index 000000000..25fde6a36 --- /dev/null +++ b/Dalamud/Plugin/Ipc/IpcContext.cs @@ -0,0 +1,15 @@ +namespace Dalamud.Plugin.Ipc; + +/// +/// The context associated for an IPC call. Reads from ThreadLocal. +/// +public class IpcContext +{ + /// + /// Gets the plugin that initiated this IPC call. + /// + public IExposedPlugin? SourcePlugin { get; init; } + + /// + public override string ToString() => $""; +}