use of org.activiti.cloud.services.notifications.graphql.ws.api.GraphQLMessage in project activiti-cloud by Activiti.
the class GraphQLBrokerMessageHandlerTest method testHandleStartMessageBrokerAvailableSendsData.
@Test
public void testHandleStartMessageBrokerAvailableSendsData() throws InterruptedException {
// given
Message<GraphQLMessage> message = startMessage("operationId", "sess1");
CountDownLatch completeLatch = new CountDownLatch(1);
// Simulate stomp relay subscription stream
Flux<ExecutionResult> mockStompRelayObservable = Flux.interval(Duration.ZERO, Duration.ofMillis(20)).take(100).map(i -> {
Map<String, Object> data = new HashMap<>();
data.put("key", i);
return new ExecutionResultImpl(data, Collections.emptyList());
});
StepVerifier observable = StepVerifier.create(mockStompRelayObservable).expectNextCount(100).expectComplete();
ExecutionResult executionResult = stubExecutionResult(mockStompRelayObservable, completeLatch);
when(graphQLExecutor.execute(anyString(), any())).thenReturn(executionResult);
// when
this.messageHandler.handleMessage(message);
observable.verify(Duration.ofMinutes(2));
assertThat(completeLatch.await(2000, TimeUnit.MILLISECONDS)).isTrue();
// then get last message
verify(this.clientOutboundChannel, atLeast(99)).send(this.messageCaptor.capture());
GraphQLMessage completeMessage = messageCaptor.getValue().getPayload();
assertThat(completeMessage.getType()).isEqualTo(GraphQLMessageType.COMPLETE);
}
use of org.activiti.cloud.services.notifications.graphql.ws.api.GraphQLMessage in project activiti-cloud by Activiti.
the class GraphQLBrokerChannelSubscriber method onError.
@Override
public void onError(Throwable t) {
log.error("Subscription {} threw an exception {}", subscriptionRef.get(), t);
Map<String, Object> payload = Collections.singletonMap("errors", Collections.singletonList(t.getMessage()));
GraphQLMessage operationMessage = new GraphQLMessage(operationMessageId, GraphQLMessageType.ERROR, payload);
Message<GraphQLMessage> responseMessage = MessageBuilder.createMessage(operationMessage, getMessageHeaders());
outboundChannel.send(responseMessage);
}
use of org.activiti.cloud.services.notifications.graphql.ws.api.GraphQLMessage in project activiti-cloud by Activiti.
the class GraphQLBrokerChannelSubscriber method sendDataToClient.
protected void sendDataToClient(Object data) {
Map<String, Object> payload = Collections.singletonMap("data", data);
GraphQLMessage operationData = new GraphQLMessage(operationMessageId, GraphQLMessageType.DATA, payload);
Message<?> responseMessage = MessageBuilder.createMessage(operationData, getMessageHeaders());
// Send message directly to user
outboundChannel.send(responseMessage);
}
use of org.activiti.cloud.services.notifications.graphql.ws.api.GraphQLMessage in project activiti-cloud by Activiti.
the class GraphQLBrokerSubProtocolHandler method afterSessionEnded.
@Override
public void afterSessionEnded(WebSocketSession session, CloseStatus closeStatus, MessageChannel outputChannel) throws Exception {
this.stats.incrementDisconnectCount();
/*
* To cleanup we send an internal messages to the handlers. It might be possible
* that this is an unexpected session end and the client did not unsubscribe his
* subscriptions.
*/
Message<GraphQLMessage> message = createDisconnectMessage(session);
try {
SimpAttributesContextHolder.setAttributesFromMessage(message);
if (this.eventPublisher != null) {
Principal user = getUser(session);
publishEvent(new GraphQLSessionDisconnectEvent(this, message, session.getId(), closeStatus, user));
}
outputChannel.send(message);
} finally {
this.graphqlAuthentications.remove(session.getId());
SimpAttributesContextHolder.resetAttributes();
}
}
use of org.activiti.cloud.services.notifications.graphql.ws.api.GraphQLMessage in project activiti-cloud by Activiti.
the class GraphQLBrokerSubProtocolHandler method handleMessageFromClient.
@Override
public void handleMessageFromClient(WebSocketSession session, WebSocketMessage<?> message, MessageChannel outputChannel) throws Exception {
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
GraphQLMessage sourceMessage = objectMapper.reader().forType(GraphQLMessage.class).readValue(textMessage.getPayload());
try {
SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE);
headerAccessor.setDestination(destination);
headerAccessor.setSessionId(session.getId());
headerAccessor.setSessionAttributes(session.getAttributes());
headerAccessor.setUser(getUser(session));
headerAccessor.setLeaveMutable(true);
Message<GraphQLMessage> decodedMessage = MessageBuilder.createMessage(sourceMessage, headerAccessor.getMessageHeaders());
headerAccessor.setHeader(GRAPHQL_MESSAGE_TYPE, sourceMessage.getType().toString());
if (logger.isTraceEnabled()) {
logger.trace("From client: " + headerAccessor.getShortLogMessage(message.getPayload()));
}
boolean isConnect = GraphQLMessageType.CONNECTION_INIT.equals(sourceMessage.getType());
if (isConnect) {
this.stats.incrementConnectCount();
// Let's inject connectionParams into headers
Optional.ofNullable(sourceMessage.getPayload()).ifPresent(map -> {
map.entrySet().forEach(e -> {
headerAccessor.setHeader(e.getKey(), e.getValue());
});
});
// inject client KA interval
Integer kaInterval = Optional.ofNullable(headerAccessor.getHeader(KA_INTERVAL_HEADER)).map(v -> Integer.parseInt(v.toString())).orElse(DEFAULT_KA_INTERVAL);
headerAccessor.setHeader(StompHeaderAccessor.HEART_BEAT_HEADER, new long[] { 0, kaInterval });
} else if (GraphQLMessageType.CONNECTION_TERMINATE.equals(sourceMessage.getType())) {
this.stats.incrementDisconnectCount();
} else if (GraphQLMessageType.START.equals(sourceMessage.getType())) {
this.stats.incrementStartCount();
} else if (GraphQLMessageType.STOP.equals(sourceMessage.getType())) {
this.stats.incrementStopCount();
}
try {
SimpAttributesContextHolder.setAttributesFromMessage(decodedMessage);
boolean sent = outputChannel.send(decodedMessage);
if (sent) {
if (isConnect) {
Principal user = headerAccessor.getUser();
if (user != null && user != session.getPrincipal()) {
this.graphqlAuthentications.put(session.getId(), user);
}
}
if (this.eventPublisher != null) {
if (isConnect) {
publishEvent(new GraphQLSessionConnectEvent(this, decodedMessage, getUser(session)));
} else if (GraphQLMessageType.START.equals(sourceMessage.getType())) {
publishEvent(new GraphQLSessionSubscribeEvent(this, decodedMessage, getUser(session)));
} else if (GraphQLMessageType.STOP.equals(sourceMessage.getType())) {
publishEvent(new GraphQLSessionUnsubscribeEvent(this, decodedMessage, getUser(session)));
}
}
}
} finally {
SimpAttributesContextHolder.resetAttributes();
}
} catch (Throwable ex) {
if (logger.isErrorEnabled()) {
logger.error("Failed to send client message to application via MessageChannel" + " in session " + session.getId() + ". Sending CONNECTION_ERROR to client.", ex);
}
sendErrorMessage(session, ex, sourceMessage);
}
}
return;
}
Aggregations