From ee20020d9c576a48173c13b68b03d349c0ec3e47 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Thu, 2 Nov 2017 16:02:17 +0300 Subject: server-web: base websocket component with autoreconnect --- .../server/component/JuickServerComponent.java | 56 ++++++++++++++++++++++ .../component/JuickServerReconnectManager.java | 22 +++++++++ .../com/juick/server/component/MessageEvent.java | 21 ++++++++ .../JuickServerComponentConfiguration.java | 30 ++++++++++++ 4 files changed, 129 insertions(+) create mode 100644 juick-server-web/src/main/java/com/juick/server/component/JuickServerComponent.java create mode 100644 juick-server-web/src/main/java/com/juick/server/component/JuickServerReconnectManager.java create mode 100644 juick-server-web/src/main/java/com/juick/server/component/MessageEvent.java create mode 100644 juick-server-web/src/main/java/com/juick/server/configuration/JuickServerComponentConfiguration.java (limited to 'juick-server-web/src/main/java/com') diff --git a/juick-server-web/src/main/java/com/juick/server/component/JuickServerComponent.java b/juick-server-web/src/main/java/com/juick/server/component/JuickServerComponent.java new file mode 100644 index 00000000..96b8c398 --- /dev/null +++ b/juick-server-web/src/main/java/com/juick/server/component/JuickServerComponent.java @@ -0,0 +1,56 @@ +package com.juick.server.component; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.web.socket.CloseStatus; +import org.springframework.web.socket.PingMessage; +import org.springframework.web.socket.TextMessage; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.handler.TextWebSocketHandler; + +import javax.inject.Inject; +import java.io.IOException; + +public class JuickServerComponent extends TextWebSocketHandler { + private static Logger logger = LoggerFactory.getLogger(JuickServerComponent.class); + @Inject + private ApplicationEventPublisher applicationEventPublisher; + @Inject + private ObjectMapper jsonMapper; + + private WebSocketSession session; + + @Override + public void afterConnectionEstablished(WebSocketSession session) throws Exception { + logger.info("WebSocket connected"); + this.session = session; + } + + @Override + public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { + logger.info("WebSocket disconnected with code {}: {}", status.getCode(), status.getReason()); + applicationEventPublisher.publishEvent(new DisconnectedEvent(this)); + } + + @Override + protected void handleTextMessage(WebSocketSession session, TextMessage text) throws Exception { + com.juick.Message jmsg = jsonMapper.readValue(text.asBytes(), com.juick.Message.class); + + if (logger.isInfoEnabled()) // prevent writeValueAsString execution if logger disabled + logger.info("got jmsg: {}", jsonMapper.writeValueAsString(jmsg)); + applicationEventPublisher.publishEvent(new MessageEvent(this, jmsg)); + } + + @Scheduled(fixedRate = 30000, initialDelay = 30000) + public void ping() throws IOException { + if (session != null && session.isOpen()) { + logger.debug("Sending WebSocket ping"); + session.sendMessage(new PingMessage()); + } else { + applicationEventPublisher.publishEvent(new DisconnectedEvent(this)); + } + } +} diff --git a/juick-server-web/src/main/java/com/juick/server/component/JuickServerReconnectManager.java b/juick-server-web/src/main/java/com/juick/server/component/JuickServerReconnectManager.java new file mode 100644 index 00000000..a662e4fb --- /dev/null +++ b/juick-server-web/src/main/java/com/juick/server/component/JuickServerReconnectManager.java @@ -0,0 +1,22 @@ +package com.juick.server.component; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.client.WebSocketConnectionManager; + +import javax.inject.Inject; + +@Component +public class JuickServerReconnectManager implements ApplicationListener { + private static Logger logger = LoggerFactory.getLogger(JuickServerReconnectManager.class); + @Inject + private WebSocketConnectionManager webSocketConnectionManager; + @Override + public void onApplicationEvent(DisconnectedEvent event) { + logger.info("retrying..."); + webSocketConnectionManager.stop(); + webSocketConnectionManager.start(); + } +} diff --git a/juick-server-web/src/main/java/com/juick/server/component/MessageEvent.java b/juick-server-web/src/main/java/com/juick/server/component/MessageEvent.java new file mode 100644 index 00000000..59537a79 --- /dev/null +++ b/juick-server-web/src/main/java/com/juick/server/component/MessageEvent.java @@ -0,0 +1,21 @@ +package com.juick.server.component; + +import com.juick.Message; +import org.springframework.context.ApplicationEvent; + +public class MessageEvent extends ApplicationEvent { + private Message message; + /** + * Create a new ApplicationEvent. + * + * @param source the object on which the event initially occurred (never {@code null}) + */ + public MessageEvent(Object source, Message message) { + super(source); + this.message = message; + } + + public Message getMessage() { + return message; + } +} diff --git a/juick-server-web/src/main/java/com/juick/server/configuration/JuickServerComponentConfiguration.java b/juick-server-web/src/main/java/com/juick/server/configuration/JuickServerComponentConfiguration.java new file mode 100644 index 00000000..7ddda36e --- /dev/null +++ b/juick-server-web/src/main/java/com/juick/server/configuration/JuickServerComponentConfiguration.java @@ -0,0 +1,30 @@ +package com.juick.server.configuration; + +import com.juick.server.component.JuickServerComponent; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.web.socket.client.WebSocketConnectionManager; +import org.springframework.web.socket.client.standard.StandardWebSocketClient; + +import javax.inject.Inject; + +@Configuration +@EnableScheduling +public class JuickServerComponentConfiguration { + @Value("${websocket_url:ws://localhost:8080/ws/}") + private String WS_URI; + @Inject + private JuickServerComponent juickServerComponent; + @Bean + public WebSocketConnectionManager connectionManager() { + WebSocketConnectionManager manager = new WebSocketConnectionManager(client(), juickServerComponent, WS_URI); + manager.setAutoStartup(true); + return manager; + } + @Bean + public StandardWebSocketClient client() { + return new StandardWebSocketClient(); + } +} -- cgit v1.2.3