Implement worker AddItem commands

This commit is contained in:
Joseph Doherty
2026-04-26 18:26:44 -04:00
parent 653f17c669
commit 59c710d789
11 changed files with 803 additions and 2 deletions
@@ -5,4 +5,17 @@ public interface IMxAccessServer
int Register(string clientName);
void Unregister(int serverHandle);
int AddItem(
int serverHandle,
string itemDefinition);
int AddItem2(
int serverHandle,
string itemDefinition,
string itemContext);
void RemoveItem(
int serverHandle,
int itemHandle);
}
@@ -35,6 +35,44 @@ public sealed class MxAccessComServer : IMxAccessServer
Invoke(nameof(Unregister), serverHandle);
}
public int AddItem(
int serverHandle,
string itemDefinition)
{
if (mxAccessComObject is ILMXProxyServer mxAccessServer)
{
return mxAccessServer.AddItem(serverHandle, itemDefinition);
}
return (int)Invoke(nameof(AddItem), serverHandle, itemDefinition);
}
public int AddItem2(
int serverHandle,
string itemDefinition,
string itemContext)
{
if (mxAccessComObject is ILMXProxyServer3 mxAccessServer)
{
return mxAccessServer.AddItem2(serverHandle, itemDefinition, itemContext);
}
return (int)Invoke(nameof(AddItem2), serverHandle, itemDefinition, itemContext);
}
public void RemoveItem(
int serverHandle,
int itemHandle)
{
if (mxAccessComObject is ILMXProxyServer mxAccessServer)
{
mxAccessServer.RemoveItem(serverHandle, itemHandle);
return;
}
Invoke(nameof(RemoveItem), serverHandle, itemHandle);
}
private object Invoke(
string methodName,
params object[] arguments)
@@ -34,6 +34,9 @@ public sealed class MxAccessCommandExecutor : IStaCommandExecutor
{
MxCommandKind.Register => ExecuteRegister(command),
MxCommandKind.Unregister => ExecuteUnregister(command),
MxCommandKind.AddItem => ExecuteAddItem(command),
MxCommandKind.AddItem2 => ExecuteAddItem2(command),
MxCommandKind.RemoveItem => ExecuteRemoveItem(command),
_ => CreateInvalidRequestReply(command, $"Unsupported MXAccess command kind {command.Kind}."),
};
}
@@ -67,6 +70,66 @@ public sealed class MxAccessCommandExecutor : IStaCommandExecutor
return CreateOkReply(command);
}
private MxCommandReply ExecuteAddItem(StaCommand command)
{
if (command.Command.PayloadCase != MxCommand.PayloadOneofCase.AddItem)
{
return CreateInvalidRequestReply(command, "AddItem command payload is required.");
}
AddItemCommand addItemCommand = command.Command.AddItem;
int itemHandle = session.AddItem(
addItemCommand.ServerHandle,
addItemCommand.ItemDefinition);
MxCommandReply reply = CreateOkReply(command);
reply.ReturnValue = variantConverter.Convert(itemHandle);
reply.AddItem = new AddItemReply
{
ItemHandle = itemHandle,
};
return reply;
}
private MxCommandReply ExecuteAddItem2(StaCommand command)
{
if (command.Command.PayloadCase != MxCommand.PayloadOneofCase.AddItem2)
{
return CreateInvalidRequestReply(command, "AddItem2 command payload is required.");
}
AddItem2Command addItem2Command = command.Command.AddItem2;
int itemHandle = session.AddItem2(
addItem2Command.ServerHandle,
addItem2Command.ItemDefinition,
addItem2Command.ItemContext);
MxCommandReply reply = CreateOkReply(command);
reply.ReturnValue = variantConverter.Convert(itemHandle);
reply.AddItem2 = new AddItem2Reply
{
ItemHandle = itemHandle,
};
return reply;
}
private MxCommandReply ExecuteRemoveItem(StaCommand command)
{
if (command.Command.PayloadCase != MxCommand.PayloadOneofCase.RemoveItem)
{
return CreateInvalidRequestReply(command, "RemoveItem command payload is required.");
}
RemoveItemCommand removeItemCommand = command.Command.RemoveItem;
session.RemoveItem(
removeItemCommand.ServerHandle,
removeItemCommand.ItemHandle);
return CreateOkReply(command);
}
private static MxCommandReply CreateOkReply(StaCommand command)
{
return new MxCommandReply
@@ -6,12 +6,19 @@ namespace MxGateway.Worker.MxAccess;
public sealed class MxAccessHandleRegistry
{
private readonly Dictionary<int, RegisteredServerHandle> serverHandles = new();
private readonly Dictionary<long, RegisteredItemHandle> itemHandles = new();
public IReadOnlyList<RegisteredServerHandle> ServerHandles => serverHandles
.Values
.OrderBy(handle => handle.ServerHandle)
.ToArray();
public IReadOnlyList<RegisteredItemHandle> ItemHandles => itemHandles
.Values
.OrderBy(handle => handle.ServerHandle)
.ThenBy(handle => handle.ItemHandle)
.ToArray();
public void RegisterServerHandle(
int serverHandle,
string clientName)
@@ -22,10 +29,54 @@ public sealed class MxAccessHandleRegistry
public void UnregisterServerHandle(int serverHandle)
{
serverHandles.Remove(serverHandle);
foreach (long key in itemHandles
.Where(pair => pair.Value.ServerHandle == serverHandle)
.Select(pair => pair.Key)
.ToArray())
{
itemHandles.Remove(key);
}
}
public bool ContainsServerHandle(int serverHandle)
{
return serverHandles.ContainsKey(serverHandle);
}
public void RegisterItemHandle(
int serverHandle,
int itemHandle,
string itemDefinition,
string itemContext,
bool hasItemContext)
{
itemHandles[CreateItemKey(serverHandle, itemHandle)] = new RegisteredItemHandle(
serverHandle,
itemHandle,
itemDefinition,
itemContext,
hasItemContext);
}
public void RemoveItemHandle(
int serverHandle,
int itemHandle)
{
itemHandles.Remove(CreateItemKey(serverHandle, itemHandle));
}
public bool ContainsItemHandle(
int serverHandle,
int itemHandle)
{
return itemHandles.ContainsKey(CreateItemKey(serverHandle, itemHandle));
}
private static long CreateItemKey(
int serverHandle,
int itemHandle)
{
return ((long)serverHandle << 32) | (uint)itemHandle;
}
}
@@ -106,6 +106,51 @@ public sealed class MxAccessSession : IDisposable
handleRegistry.UnregisterServerHandle(serverHandle);
}
public int AddItem(
int serverHandle,
string itemDefinition)
{
ThrowIfDisposed();
int itemHandle = mxAccessServer.AddItem(serverHandle, itemDefinition);
handleRegistry.RegisterItemHandle(
serverHandle,
itemHandle,
itemDefinition,
string.Empty,
hasItemContext: false);
return itemHandle;
}
public int AddItem2(
int serverHandle,
string itemDefinition,
string itemContext)
{
ThrowIfDisposed();
int itemHandle = mxAccessServer.AddItem2(serverHandle, itemDefinition, itemContext);
handleRegistry.RegisterItemHandle(
serverHandle,
itemHandle,
itemDefinition,
itemContext,
hasItemContext: true);
return itemHandle;
}
public void RemoveItem(
int serverHandle,
int itemHandle)
{
ThrowIfDisposed();
mxAccessServer.RemoveItem(serverHandle, itemHandle);
handleRegistry.RemoveItemHandle(serverHandle, itemHandle);
}
public void Dispose()
{
if (disposed)
@@ -81,6 +81,19 @@ public sealed class MxAccessStaSession : IDisposable
cancellationToken);
}
public Task<IReadOnlyList<RegisteredItemHandle>> GetRegisteredItemHandlesAsync(
CancellationToken cancellationToken = default)
{
if (session is null)
{
throw new InvalidOperationException("MXAccess COM session has not been started.");
}
return staRuntime.InvokeAsync(
() => session.HandleRegistry.ItemHandles,
cancellationToken);
}
public void Dispose()
{
if (disposed)
@@ -0,0 +1,28 @@
namespace MxGateway.Worker.MxAccess;
public sealed class RegisteredItemHandle
{
public RegisteredItemHandle(
int serverHandle,
int itemHandle,
string itemDefinition,
string itemContext,
bool hasItemContext)
{
ServerHandle = serverHandle;
ItemHandle = itemHandle;
ItemDefinition = itemDefinition;
ItemContext = itemContext;
HasItemContext = hasItemContext;
}
public int ServerHandle { get; }
public int ItemHandle { get; }
public string ItemDefinition { get; }
public string ItemContext { get; }
public bool HasItemContext { get; }
}