Add bulk MXAccess subscription commands

This commit is contained in:
Joseph Doherty
2026-04-26 22:29:27 -04:00
parent daff16cfd2
commit 3d11ac3316
31 changed files with 14346 additions and 969 deletions
@@ -2,9 +2,12 @@ package com.dohertylan.mxgateway.client;
import java.security.SecureRandom;
import java.util.HexFormat;
import java.util.List;
import java.util.Objects;
import mxaccess_gateway.v1.MxaccessGateway.AddItem2Command;
import mxaccess_gateway.v1.MxaccessGateway.AddItemBulkCommand;
import mxaccess_gateway.v1.MxaccessGateway.AddItemCommand;
import mxaccess_gateway.v1.MxaccessGateway.AdviseItemBulkCommand;
import mxaccess_gateway.v1.MxaccessGateway.AdviseCommand;
import mxaccess_gateway.v1.MxaccessGateway.CloseSessionReply;
import mxaccess_gateway.v1.MxaccessGateway.CloseSessionRequest;
@@ -15,7 +18,14 @@ import mxaccess_gateway.v1.MxaccessGateway.MxCommandRequest;
import mxaccess_gateway.v1.MxaccessGateway.MxValue;
import mxaccess_gateway.v1.MxaccessGateway.OpenSessionReply;
import mxaccess_gateway.v1.MxaccessGateway.RegisterCommand;
import mxaccess_gateway.v1.MxaccessGateway.RemoveItemBulkCommand;
import mxaccess_gateway.v1.MxaccessGateway.RemoveItemCommand;
import mxaccess_gateway.v1.MxaccessGateway.StreamEventsRequest;
import mxaccess_gateway.v1.MxaccessGateway.SubscribeBulkCommand;
import mxaccess_gateway.v1.MxaccessGateway.SubscribeResult;
import mxaccess_gateway.v1.MxaccessGateway.UnAdviseCommand;
import mxaccess_gateway.v1.MxaccessGateway.UnAdviseItemBulkCommand;
import mxaccess_gateway.v1.MxaccessGateway.UnsubscribeBulkCommand;
import mxaccess_gateway.v1.MxaccessGateway.UnregisterCommand;
import mxaccess_gateway.v1.MxaccessGateway.Write2Command;
import mxaccess_gateway.v1.MxaccessGateway.WriteCommand;
@@ -117,6 +127,19 @@ public final class MxGatewaySession implements AutoCloseable {
.build());
}
public void removeItem(int serverHandle, int itemHandle) {
removeItemRaw(serverHandle, itemHandle);
}
public MxCommandReply removeItemRaw(int serverHandle, int itemHandle) {
return invokeCommand(MxCommand.newBuilder()
.setKind(MxCommandKind.MX_COMMAND_KIND_REMOVE_ITEM)
.setRemoveItem(RemoveItemCommand.newBuilder()
.setServerHandle(serverHandle)
.setItemHandle(itemHandle))
.build());
}
public void advise(int serverHandle, int itemHandle) {
adviseRaw(serverHandle, itemHandle);
}
@@ -130,6 +153,85 @@ public final class MxGatewaySession implements AutoCloseable {
.build());
}
public void unAdvise(int serverHandle, int itemHandle) {
unAdviseRaw(serverHandle, itemHandle);
}
public MxCommandReply unAdviseRaw(int serverHandle, int itemHandle) {
return invokeCommand(MxCommand.newBuilder()
.setKind(MxCommandKind.MX_COMMAND_KIND_UN_ADVISE)
.setUnAdvise(UnAdviseCommand.newBuilder()
.setServerHandle(serverHandle)
.setItemHandle(itemHandle))
.build());
}
public List<SubscribeResult> addItemBulk(int serverHandle, List<String> tagAddresses) {
Objects.requireNonNull(tagAddresses, "tagAddresses");
MxCommandReply reply = invokeCommand(MxCommand.newBuilder()
.setKind(MxCommandKind.MX_COMMAND_KIND_ADD_ITEM_BULK)
.setAddItemBulk(AddItemBulkCommand.newBuilder()
.setServerHandle(serverHandle)
.addAllTagAddresses(tagAddresses))
.build());
return reply.getAddItemBulk().getResultsList();
}
public List<SubscribeResult> adviseItemBulk(int serverHandle, List<Integer> itemHandles) {
Objects.requireNonNull(itemHandles, "itemHandles");
MxCommandReply reply = invokeCommand(MxCommand.newBuilder()
.setKind(MxCommandKind.MX_COMMAND_KIND_ADVISE_ITEM_BULK)
.setAdviseItemBulk(AdviseItemBulkCommand.newBuilder()
.setServerHandle(serverHandle)
.addAllItemHandles(itemHandles))
.build());
return reply.getAdviseItemBulk().getResultsList();
}
public List<SubscribeResult> removeItemBulk(int serverHandle, List<Integer> itemHandles) {
Objects.requireNonNull(itemHandles, "itemHandles");
MxCommandReply reply = invokeCommand(MxCommand.newBuilder()
.setKind(MxCommandKind.MX_COMMAND_KIND_REMOVE_ITEM_BULK)
.setRemoveItemBulk(RemoveItemBulkCommand.newBuilder()
.setServerHandle(serverHandle)
.addAllItemHandles(itemHandles))
.build());
return reply.getRemoveItemBulk().getResultsList();
}
public List<SubscribeResult> unAdviseItemBulk(int serverHandle, List<Integer> itemHandles) {
Objects.requireNonNull(itemHandles, "itemHandles");
MxCommandReply reply = invokeCommand(MxCommand.newBuilder()
.setKind(MxCommandKind.MX_COMMAND_KIND_UN_ADVISE_ITEM_BULK)
.setUnAdviseItemBulk(UnAdviseItemBulkCommand.newBuilder()
.setServerHandle(serverHandle)
.addAllItemHandles(itemHandles))
.build());
return reply.getUnAdviseItemBulk().getResultsList();
}
public List<SubscribeResult> subscribeBulk(int serverHandle, List<String> tagAddresses) {
Objects.requireNonNull(tagAddresses, "tagAddresses");
MxCommandReply reply = invokeCommand(MxCommand.newBuilder()
.setKind(MxCommandKind.MX_COMMAND_KIND_SUBSCRIBE_BULK)
.setSubscribeBulk(SubscribeBulkCommand.newBuilder()
.setServerHandle(serverHandle)
.addAllTagAddresses(tagAddresses))
.build());
return reply.getSubscribeBulk().getResultsList();
}
public List<SubscribeResult> unsubscribeBulk(int serverHandle, List<Integer> itemHandles) {
Objects.requireNonNull(itemHandles, "itemHandles");
MxCommandReply reply = invokeCommand(MxCommand.newBuilder()
.setKind(MxCommandKind.MX_COMMAND_KIND_UNSUBSCRIBE_BULK)
.setUnsubscribeBulk(UnsubscribeBulkCommand.newBuilder()
.setServerHandle(serverHandle)
.addAllItemHandles(itemHandles))
.build());
return reply.getUnsubscribeBulk().getResultsList();
}
public void write(int serverHandle, int itemHandle, MxValue value, int userId) {
writeRaw(serverHandle, itemHandle, value, userId);
}
@@ -17,12 +17,14 @@ import io.grpc.inprocess.InProcessServerBuilder;
import io.grpc.stub.ServerCallStreamObserver;
import io.grpc.stub.StreamObserver;
import java.time.Duration;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import mxaccess_gateway.v1.MxAccessGatewayGrpc;
import mxaccess_gateway.v1.MxaccessGateway.AddItemReply;
import mxaccess_gateway.v1.MxaccessGateway.BulkSubscribeReply;
import mxaccess_gateway.v1.MxaccessGateway.CloseSessionReply;
import mxaccess_gateway.v1.MxaccessGateway.CloseSessionRequest;
import mxaccess_gateway.v1.MxaccessGateway.MxCommandKind;
@@ -36,6 +38,7 @@ import mxaccess_gateway.v1.MxaccessGateway.ProtocolStatusCode;
import mxaccess_gateway.v1.MxaccessGateway.RegisterReply;
import mxaccess_gateway.v1.MxaccessGateway.SessionState;
import mxaccess_gateway.v1.MxaccessGateway.StreamEventsRequest;
import mxaccess_gateway.v1.MxaccessGateway.SubscribeResult;
import org.junit.jupiter.api.Test;
final class MxGatewayClientSessionTests {
@@ -112,6 +115,42 @@ final class MxGatewayClientSessionTests {
}
}
@Test
void subscribeBulkBuildsOneBulkCommandAndReturnsResults() throws Exception {
AtomicReference<MxCommandRequest> commandRequest = new AtomicReference<>();
TestGatewayService service = new TestGatewayService() {
@Override
public void invoke(MxCommandRequest request, StreamObserver<MxCommandReply> responseObserver) {
commandRequest.set(request);
responseObserver.onNext(MxCommandReply.newBuilder()
.setSessionId(request.getSessionId())
.setKind(request.getCommand().getKind())
.setProtocolStatus(ok())
.setSubscribeBulk(BulkSubscribeReply.newBuilder()
.addResults(SubscribeResult.newBuilder()
.setServerHandle(12)
.setTagAddress("Area001.Pump001.Speed")
.setItemHandle(34)
.setWasSuccessful(true)))
.build());
responseObserver.onCompleted();
}
};
try (InProcessGateway gateway = InProcessGateway.start(service, new AtomicReference<>());
MxGatewayClient client = gateway.client("", Duration.ofSeconds(5))) {
MxGatewaySession session = MxGatewaySession.forSessionId(client, "existing-session");
List<SubscribeResult> results = session.subscribeBulk(12, List.of("Area001.Pump001.Speed"));
assertEquals(34, results.get(0).getItemHandle());
assertEquals(MxCommandKind.MX_COMMAND_KIND_SUBSCRIBE_BULK, commandRequest.get().getCommand().getKind());
assertEquals(
List.of("Area001.Pump001.Speed"),
commandRequest.get().getCommand().getSubscribeBulk().getTagAddressesList());
}
}
@Test
void streamCancellationCancelsServerCall() throws Exception {
CountDownLatch cancelled = new CountDownLatch(1);
File diff suppressed because it is too large Load Diff