Search in sources :

Example 11 with GraphQLMessage

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);
}
Also used : HashMap(java.util.HashMap) ExecutionResultImpl(graphql.ExecutionResultImpl) ExecutionResult(graphql.ExecutionResult) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) CountDownLatch(java.util.concurrent.CountDownLatch) StepVerifier(reactor.test.StepVerifier) GraphQLMessage(org.activiti.cloud.services.notifications.graphql.ws.api.GraphQLMessage) Test(org.junit.jupiter.api.Test)

Example 12 with GraphQLMessage

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);
}
Also used : GraphQLMessage(org.activiti.cloud.services.notifications.graphql.ws.api.GraphQLMessage)

Example 13 with GraphQLMessage

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);
}
Also used : GraphQLMessage(org.activiti.cloud.services.notifications.graphql.ws.api.GraphQLMessage)

Example 14 with GraphQLMessage

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();
    }
}
Also used : GraphQLMessage(org.activiti.cloud.services.notifications.graphql.ws.api.GraphQLMessage) Principal(java.security.Principal)

Example 15 with GraphQLMessage

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;
}
Also used : AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ScheduledFuture(java.util.concurrent.ScheduledFuture) SessionLimitExceededException(org.springframework.web.socket.handler.SessionLimitExceededException) LoggerFactory(org.slf4j.LoggerFactory) SimpAttributesContextHolder(org.springframework.messaging.simp.SimpAttributesContextHolder) StompHeaderAccessor(org.springframework.messaging.simp.stomp.StompHeaderAccessor) SubProtocolHandler(org.springframework.web.socket.messaging.SubProtocolHandler) SimpMessageHeaderAccessor(org.springframework.messaging.simp.SimpMessageHeaderAccessor) WebSocketSession(org.springframework.web.socket.WebSocketSession) CloseStatus(org.springframework.web.socket.CloseStatus) GraphQLMessage(org.activiti.cloud.services.notifications.graphql.ws.api.GraphQLMessage) TextMessage(org.springframework.web.socket.TextMessage) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Map(java.util.Map) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) ApplicationEventPublisher(org.springframework.context.ApplicationEventPublisher) Nullable(org.springframework.lang.Nullable) Message(org.springframework.messaging.Message) ApplicationEventPublisherAware(org.springframework.context.ApplicationEventPublisherAware) Logger(org.slf4j.Logger) WebSocketMessage(org.springframework.web.socket.WebSocketMessage) ObjectWriter(com.fasterxml.jackson.databind.ObjectWriter) SimpMessageType(org.springframework.messaging.simp.SimpMessageType) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper) IOException(java.io.IOException) MessageChannel(org.springframework.messaging.MessageChannel) Executors(java.util.concurrent.Executors) TimeUnit(java.util.concurrent.TimeUnit) ApplicationEvent(org.springframework.context.ApplicationEvent) List(java.util.List) Principal(java.security.Principal) GraphQLMessageType(org.activiti.cloud.services.notifications.graphql.ws.api.GraphQLMessageType) Gauge(com.codahale.metrics.annotation.Gauge) Optional(java.util.Optional) Collections(java.util.Collections) MessageBuilder(org.springframework.messaging.support.MessageBuilder) GraphQLMessage(org.activiti.cloud.services.notifications.graphql.ws.api.GraphQLMessage) TextMessage(org.springframework.web.socket.TextMessage) Principal(java.security.Principal) SimpMessageHeaderAccessor(org.springframework.messaging.simp.SimpMessageHeaderAccessor)

Aggregations

GraphQLMessage (org.activiti.cloud.services.notifications.graphql.ws.api.GraphQLMessage)35 Test (org.junit.jupiter.api.Test)14 SimpMessageHeaderAccessor (org.springframework.messaging.simp.SimpMessageHeaderAccessor)13 SpringBootTest (org.springframework.boot.test.context.SpringBootTest)6 WebsocketSender (reactor.netty.http.client.HttpClient.WebsocketSender)6 Date (java.util.Date)5 TextMessage (org.springframework.web.socket.TextMessage)5 ExecutionResult (graphql.ExecutionResult)4 Principal (java.security.Principal)4 MessageHeaderAccessor (org.springframework.messaging.support.MessageHeaderAccessor)4 WebSocketSession (org.springframework.web.socket.WebSocketSession)4 Timed (com.codahale.metrics.annotation.Timed)3 HashMap (java.util.HashMap)3 GraphQLMessageType (org.activiti.cloud.services.notifications.graphql.ws.api.GraphQLMessageType)3 Message (org.springframework.messaging.Message)3 MessageHeaders (org.springframework.messaging.MessageHeaders)3 SimpMessageType (org.springframework.messaging.simp.SimpMessageType)3 ObjectWriter (com.fasterxml.jackson.databind.ObjectWriter)2 IOException (java.io.IOException)2 Collections (java.util.Collections)2