using System.Collections.Concurrent;
using System.Collections.Generic;
using Dalamud.Logging.Internal;
using Dalamud.Networking.Pipes.Rpc;
using Dalamud.Utility;
namespace Dalamud.Networking.Pipes.Internal;
///
/// A service responsible for handling Dalamud URIs and dispatching them accordingly.
///
[ServiceManager.EarlyLoadedService]
internal class LinkHandlerService : IInternalDisposableService
{
private readonly ModuleLog log = new("LinkHandler");
// key: namespace (e.g. "plugin" or "PluginInstaller") -> list of handlers
private readonly ConcurrentDictionary>> handlers
= new(StringComparer.OrdinalIgnoreCase);
///
/// Initializes a new instance of the class.
///
/// The injected RPC host service.
[ServiceManager.ServiceConstructor]
public LinkHandlerService(RpcHostService rpcHostService)
{
rpcHostService.AddMethod("handleLink", this.HandleLinkCall);
}
///
public void DisposeService()
{
}
///
/// Register a handler for a namespace. All URIs with this namespace will be dispatched to the handler.
///
/// The namespace to use for this subscription.
/// The command handler.
public void Register(string ns, Action handler)
{
if (string.IsNullOrWhiteSpace(ns))
throw new ArgumentNullException(nameof(ns));
var list = this.handlers.GetOrAdd(ns, _ => []);
lock (list)
{
list.Add(handler);
}
this.log.Verbose("Registered handler for {Namespace}", ns);
}
///
/// Unregister a handler.
///
/// The namespace to use for this subscription.
/// The command handler.
public void Unregister(string ns, Action handler)
{
if (string.IsNullOrWhiteSpace(ns))
return;
if (!this.handlers.TryGetValue(ns, out var list))
return;
list.RemoveAll(x => x == handler);
if (list.Count == 0)
this.handlers.TryRemove(ns, out _);
this.log.Verbose("Unregistered handler for {Namespace}", ns);
}
///
/// Dispatch a URI to matching handlers.
///
/// The URI to parse and dispatch.
public void Dispatch(DalamudUri uri)
{
this.log.Information("Received URI: {Uri}", uri.ToString());
var ns = uri.Namespace;
if (!this.handlers.TryGetValue(ns, out var actions))
return;
foreach (var h in actions)
{
h.InvokeSafely(uri);
}
}
///
/// The RPC-invokable link handler.
///
/// A plain-text URI to parse.
public void HandleLinkCall(string uri)
{
if (string.IsNullOrWhiteSpace(uri))
return;
var du = DalamudUri.FromUri(uri);
this.Dispatch(du);
}
}