Implement worker advise commands

This commit is contained in:
Joseph Doherty
2026-04-26 18:41:10 -04:00
parent 0fd954d94c
commit a871f2f2e5
11 changed files with 734 additions and 1 deletions
@@ -18,4 +18,16 @@ public interface IMxAccessServer
void RemoveItem(
int serverHandle,
int itemHandle);
void Advise(
int serverHandle,
int itemHandle);
void UnAdvise(
int serverHandle,
int itemHandle);
void AdviseSupervisory(
int serverHandle,
int itemHandle);
}
@@ -0,0 +1,7 @@
namespace MxGateway.Worker.MxAccess;
public enum MxAccessAdviceKind
{
Plain = 1,
Supervisory = 2,
}
@@ -73,6 +73,45 @@ public sealed class MxAccessComServer : IMxAccessServer
Invoke(nameof(RemoveItem), serverHandle, itemHandle);
}
public void Advise(
int serverHandle,
int itemHandle)
{
if (mxAccessComObject is ILMXProxyServer mxAccessServer)
{
mxAccessServer.Advise(serverHandle, itemHandle);
return;
}
Invoke(nameof(Advise), serverHandle, itemHandle);
}
public void UnAdvise(
int serverHandle,
int itemHandle)
{
if (mxAccessComObject is ILMXProxyServer mxAccessServer)
{
mxAccessServer.UnAdvise(serverHandle, itemHandle);
return;
}
Invoke(nameof(UnAdvise), serverHandle, itemHandle);
}
public void AdviseSupervisory(
int serverHandle,
int itemHandle)
{
if (mxAccessComObject is ILMXProxyServer4 mxAccessServer)
{
mxAccessServer.AdviseSupervisory(serverHandle, itemHandle);
return;
}
Invoke(nameof(AdviseSupervisory), serverHandle, itemHandle);
}
private object Invoke(
string methodName,
params object[] arguments)
@@ -37,6 +37,9 @@ public sealed class MxAccessCommandExecutor : IStaCommandExecutor
MxCommandKind.AddItem => ExecuteAddItem(command),
MxCommandKind.AddItem2 => ExecuteAddItem2(command),
MxCommandKind.RemoveItem => ExecuteRemoveItem(command),
MxCommandKind.Advise => ExecuteAdvise(command),
MxCommandKind.UnAdvise => ExecuteUnAdvise(command),
MxCommandKind.AdviseSupervisory => ExecuteAdviseSupervisory(command),
_ => CreateInvalidRequestReply(command, $"Unsupported MXAccess command kind {command.Kind}."),
};
}
@@ -130,6 +133,51 @@ public sealed class MxAccessCommandExecutor : IStaCommandExecutor
return CreateOkReply(command);
}
private MxCommandReply ExecuteAdvise(StaCommand command)
{
if (command.Command.PayloadCase != MxCommand.PayloadOneofCase.Advise)
{
return CreateInvalidRequestReply(command, "Advise command payload is required.");
}
AdviseCommand adviseCommand = command.Command.Advise;
session.Advise(
adviseCommand.ServerHandle,
adviseCommand.ItemHandle);
return CreateOkReply(command);
}
private MxCommandReply ExecuteUnAdvise(StaCommand command)
{
if (command.Command.PayloadCase != MxCommand.PayloadOneofCase.UnAdvise)
{
return CreateInvalidRequestReply(command, "UnAdvise command payload is required.");
}
UnAdviseCommand unAdviseCommand = command.Command.UnAdvise;
session.UnAdvise(
unAdviseCommand.ServerHandle,
unAdviseCommand.ItemHandle);
return CreateOkReply(command);
}
private MxCommandReply ExecuteAdviseSupervisory(StaCommand command)
{
if (command.Command.PayloadCase != MxCommand.PayloadOneofCase.AdviseSupervisory)
{
return CreateInvalidRequestReply(command, "AdviseSupervisory command payload is required.");
}
AdviseSupervisoryCommand adviseSupervisoryCommand = command.Command.AdviseSupervisory;
session.AdviseSupervisory(
adviseSupervisoryCommand.ServerHandle,
adviseSupervisoryCommand.ItemHandle);
return CreateOkReply(command);
}
private static MxCommandReply CreateOkReply(StaCommand command)
{
return new MxCommandReply
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
@@ -7,6 +8,7 @@ public sealed class MxAccessHandleRegistry
{
private readonly Dictionary<int, RegisteredServerHandle> serverHandles = new();
private readonly Dictionary<long, RegisteredItemHandle> itemHandles = new();
private readonly Dictionary<AdviceHandleKey, RegisteredAdviceHandle> adviceHandles = new();
public IReadOnlyList<RegisteredServerHandle> ServerHandles => serverHandles
.Values
@@ -19,6 +21,13 @@ public sealed class MxAccessHandleRegistry
.ThenBy(handle => handle.ItemHandle)
.ToArray();
public IReadOnlyList<RegisteredAdviceHandle> AdviceHandles => adviceHandles
.Values
.OrderBy(handle => handle.ServerHandle)
.ThenBy(handle => handle.ItemHandle)
.ThenBy(handle => handle.AdviceKind)
.ToArray();
public void RegisterServerHandle(
int serverHandle,
string clientName)
@@ -37,6 +46,14 @@ public sealed class MxAccessHandleRegistry
{
itemHandles.Remove(key);
}
foreach (AdviceHandleKey key in adviceHandles
.Where(pair => pair.Value.ServerHandle == serverHandle)
.Select(pair => pair.Key)
.ToArray())
{
adviceHandles.Remove(key);
}
}
public bool ContainsServerHandle(int serverHandle)
@@ -64,6 +81,7 @@ public sealed class MxAccessHandleRegistry
int itemHandle)
{
itemHandles.Remove(CreateItemKey(serverHandle, itemHandle));
RemoveAdviceHandles(serverHandle, itemHandle);
}
public bool ContainsItemHandle(
@@ -73,10 +91,84 @@ public sealed class MxAccessHandleRegistry
return itemHandles.ContainsKey(CreateItemKey(serverHandle, itemHandle));
}
public void RegisterAdviceHandle(
int serverHandle,
int itemHandle,
MxAccessAdviceKind adviceKind)
{
AdviceHandleKey key = new(serverHandle, itemHandle, adviceKind);
adviceHandles[key] = new RegisteredAdviceHandle(
serverHandle,
itemHandle,
adviceKind);
}
public void RemoveAdviceHandles(
int serverHandle,
int itemHandle)
{
foreach (AdviceHandleKey key in adviceHandles
.Where(pair => pair.Value.ServerHandle == serverHandle && pair.Value.ItemHandle == itemHandle)
.Select(pair => pair.Key)
.ToArray())
{
adviceHandles.Remove(key);
}
}
public bool ContainsAdviceHandle(
int serverHandle,
int itemHandle,
MxAccessAdviceKind adviceKind)
{
return adviceHandles.ContainsKey(new AdviceHandleKey(serverHandle, itemHandle, adviceKind));
}
private static long CreateItemKey(
int serverHandle,
int itemHandle)
{
return ((long)serverHandle << 32) | (uint)itemHandle;
}
private readonly struct AdviceHandleKey : IEquatable<AdviceHandleKey>
{
private readonly int serverHandle;
private readonly int itemHandle;
private readonly MxAccessAdviceKind adviceKind;
public AdviceHandleKey(
int serverHandle,
int itemHandle,
MxAccessAdviceKind adviceKind)
{
this.serverHandle = serverHandle;
this.itemHandle = itemHandle;
this.adviceKind = adviceKind;
}
public bool Equals(AdviceHandleKey other)
{
return serverHandle == other.serverHandle
&& itemHandle == other.itemHandle
&& adviceKind == other.adviceKind;
}
public override bool Equals(object? obj)
{
return obj is AdviceHandleKey other && Equals(other);
}
public override int GetHashCode()
{
unchecked
{
int hashCode = serverHandle;
hashCode = (hashCode * 397) ^ itemHandle;
hashCode = (hashCode * 397) ^ (int)adviceKind;
return hashCode;
}
}
}
}
@@ -151,6 +151,42 @@ public sealed class MxAccessSession : IDisposable
handleRegistry.RemoveItemHandle(serverHandle, itemHandle);
}
public void Advise(
int serverHandle,
int itemHandle)
{
ThrowIfDisposed();
mxAccessServer.Advise(serverHandle, itemHandle);
handleRegistry.RegisterAdviceHandle(
serverHandle,
itemHandle,
MxAccessAdviceKind.Plain);
}
public void UnAdvise(
int serverHandle,
int itemHandle)
{
ThrowIfDisposed();
mxAccessServer.UnAdvise(serverHandle, itemHandle);
handleRegistry.RemoveAdviceHandles(serverHandle, itemHandle);
}
public void AdviseSupervisory(
int serverHandle,
int itemHandle)
{
ThrowIfDisposed();
mxAccessServer.AdviseSupervisory(serverHandle, itemHandle);
handleRegistry.RegisterAdviceHandle(
serverHandle,
itemHandle,
MxAccessAdviceKind.Supervisory);
}
public void Dispose()
{
if (disposed)
@@ -94,6 +94,19 @@ public sealed class MxAccessStaSession : IDisposable
cancellationToken);
}
public Task<IReadOnlyList<RegisteredAdviceHandle>> GetRegisteredAdviceHandlesAsync(
CancellationToken cancellationToken = default)
{
if (session is null)
{
throw new InvalidOperationException("MXAccess COM session has not been started.");
}
return staRuntime.InvokeAsync(
() => session.HandleRegistry.AdviceHandles,
cancellationToken);
}
public void Dispose()
{
if (disposed)
@@ -0,0 +1,20 @@
namespace MxGateway.Worker.MxAccess;
public sealed class RegisteredAdviceHandle
{
public RegisteredAdviceHandle(
int serverHandle,
int itemHandle,
MxAccessAdviceKind adviceKind)
{
ServerHandle = serverHandle;
ItemHandle = itemHandle;
AdviceKind = adviceKind;
}
public int ServerHandle { get; }
public int ItemHandle { get; }
public MxAccessAdviceKind AdviceKind { get; }
}