diff --git a/.env b/.env index ca0428e1b..f95cf5d11 100644 --- a/.env +++ b/.env @@ -8,6 +8,8 @@ ################## SONIC_SERVER_HOST=192.168.1.1 SONIC_SERVER_PORT=3000 +SONIC_SERVER_HTTPS=false +SONIC_SERVER_HTTPS_PORT=443 SONIC_EUREKA_USERNAME=sonic SONIC_EUREKA_PASSWORD=sonic SONIC_EUREKA_PORT=8761 diff --git a/docker-compose.yml b/docker-compose.yml index 4a41c8bc6..42d7c6862 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -91,6 +91,9 @@ services: environment: - SONIC_SERVER_HOST - SONIC_SERVER_PORT + - SONIC_SERVER_HTTPS + volumes: + - ./certs:/etc/nginx/certs networks: - sonic-network depends_on: @@ -98,6 +101,7 @@ services: restart: on-failure ports: - "${SONIC_SERVER_PORT}:80" + - "${SONIC_SERVER_HTTPS_PORT}:443" networks: sonic-network: diff --git a/sonic-server-controller/pom.xml b/sonic-server-controller/pom.xml index ad282ff87..8d73785ec 100644 --- a/sonic-server-controller/pom.xml +++ b/sonic-server-controller/pom.xml @@ -64,6 +64,11 @@ + + org.java-websocket + Java-WebSocket + 1.5.3 + org.springframework.boot diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/BytesTool.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/BytesTool.java index 38806e4d8..b6dba0a48 100644 --- a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/BytesTool.java +++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/BytesTool.java @@ -21,6 +21,7 @@ import lombok.extern.slf4j.Slf4j; import java.io.IOException; +import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; @@ -40,4 +41,17 @@ public static void sendText(Session session, String message) { } } } + + public static void sendByte(Session session, ByteBuffer message) { + if (session == null || !session.isOpen()) { + return; + } + synchronized (session) { + try { + session.getBasicRemote().sendBinary(message); + } catch (IllegalStateException | IOException e) { + log.error("WebSocket send msg error...connection has been closed."); + } + } + } } diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/transport/HubAudioServer.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/transport/HubAudioServer.java new file mode 100644 index 000000000..74d06b3f9 --- /dev/null +++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/transport/HubAudioServer.java @@ -0,0 +1,99 @@ +package org.cloud.sonic.controller.transport; + + +import java.net.URI; +import java.util.HashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.io.StringWriter; +import java.io.PrintWriter; + +import org.cloud.sonic.controller.config.WsEndpointConfigure; +import org.springframework.stereotype.Component; +import org.java_websocket.enums.ReadyState; + +import jakarta.websocket.OnClose; +import jakarta.websocket.OnError; +import jakarta.websocket.OnMessage; +import jakarta.websocket.OnOpen; +import jakarta.websocket.Session; +import jakarta.websocket.server.PathParam; +import jakarta.websocket.server.ServerEndpoint; +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +@ServerEndpoint(value = "/hub/{host}/{port}/{service}/{key}/{udId}", configurator = WsEndpointConfigure.class) +public class HubAudioServer { + HashMap hubMap = new HashMap(); + ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); + + @OnOpen + public void onOpen(Session session, @PathParam("host") String host, @PathParam("port") String port, @PathParam("service") String service, @PathParam("key") String key, @PathParam("udId") String udId) { + String agentUri = String.format("ws://%s:%s/websockets/%s/%s/%s", host, port, service, key, udId); + + try { + URI uri = new URI(agentUri); + TransportClient agent = new TransportClient(session, uri); + agent.connect(); + hubMap.put(session, agent); + log.info(String.format("Hub Server: Connected to agent\nUrl=%s", agentUri)); + } + catch(Exception ex) + { + StringWriter sw = new StringWriter(); + ex.printStackTrace(new PrintWriter(sw)); + log.error(String.format("Hub Server: Failed to connect agent!\nUrl=%s\nError=%s", agentUri, sw.toString())); + } + } + + @OnMessage + public void onMessage(Session session, String message) { + if (hubMap.get(session).getReadyState() == ReadyState.NOT_YET_CONNECTED) + { + cachedThreadPool.execute(() -> { + boolean needRetry = true; + while (needRetry) { + try { + if (hubMap.get(session).getReadyState() == ReadyState.OPEN) { + log.info(String.format("Hub Server: Messages forwarded to agent\nUrl=%s", hubMap.get(session).getUrl())); + hubMap.get(session).send(message); + needRetry = false; + } else if (hubMap.get(session).getReadyState() == ReadyState.NOT_YET_CONNECTED) { + log.info(String.format("Hub Server: Wait agent in 1s\nStatus=%s\nUrl=%s", hubMap.get(session).getReadyState().toString(), hubMap.get(session).getUrl())); + Thread.sleep(1000); + } else { + log.info(String.format("Hub Server: Agent closed\nStatus=%s\nUrl=%s", hubMap.get(session).getReadyState().toString(), hubMap.get(session).getUrl())); + needRetry = false; + } + + } catch (Exception error) { + needRetry = false; + StringWriter sw = new StringWriter(); + error.printStackTrace(new PrintWriter(sw)); + log.error(String.format("Hub Server: Fail to forward\nStatus=%s\nUrl=%s\nMessages=%s\nError=%s", hubMap.get(session).getReadyState().toString(), hubMap.get(session).getUrl(), message, sw.toString())); + } + } + }); + } + else + { + log.info(String.format("Hub Server: Messages forwarded to agent\nUrl=%s", hubMap.get(session).getUrl())); + hubMap.get(session).send(message); + } + } + + @OnClose + public void onClose(Session session) { + log.info(String.format("Hub Server: Closed\nUrl=%s", hubMap.get(session).getUrl())); + hubMap.get(session).close(); + hubMap.remove(session); + } + + @OnError + public void onError(Session session, Throwable error) { + StringWriter sw = new StringWriter(); + error.printStackTrace(new PrintWriter(sw)); + log.error(String.format("Hub Server: Error caught!\nUrl=%s\nError=%s", hubMap.get(session).getUrl(), sw.toString())); + } +} diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/transport/HubServer.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/transport/HubServer.java new file mode 100644 index 000000000..dbfb4b604 --- /dev/null +++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/transport/HubServer.java @@ -0,0 +1,99 @@ +package org.cloud.sonic.controller.transport; + + +import java.net.URI; +import java.util.HashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.io.StringWriter; +import java.io.PrintWriter; + +import org.cloud.sonic.controller.config.WsEndpointConfigure; +import org.springframework.stereotype.Component; +import org.java_websocket.enums.ReadyState; + +import jakarta.websocket.OnClose; +import jakarta.websocket.OnError; +import jakarta.websocket.OnMessage; +import jakarta.websocket.OnOpen; +import jakarta.websocket.Session; +import jakarta.websocket.server.PathParam; +import jakarta.websocket.server.ServerEndpoint; +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +@ServerEndpoint(value = "/hub/{host}/{port}/{platform}/{key}/{udId}/{token}", configurator = WsEndpointConfigure.class) +public class HubServer { + HashMap hubMap = new HashMap(); + ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); + + @OnOpen + public void onOpen(Session session, @PathParam("host") String host, @PathParam("port") String port, @PathParam("platform") String platform, @PathParam("key") String key, @PathParam("udId") String udId, @PathParam("token") String token) { + String agentUri = String.format("ws://%s:%s/websockets/%s/%s/%s/%s", host, port, platform, key, udId, token); + + try { + URI uri = new URI(agentUri); + TransportClient agent = new TransportClient(session, uri); + agent.connect(); + hubMap.put(session, agent); + log.info(String.format("Hub Server: Connected to agent\nUrl=%s", agentUri)); + } + catch(Exception ex) + { + StringWriter sw = new StringWriter(); + ex.printStackTrace(new PrintWriter(sw)); + log.error(String.format("Hub Server: Failed to connect agent!\nUrl=%s\nError=%s", agentUri, sw.toString())); + } + } + + @OnMessage + public void onMessage(Session session, String message) { + if (hubMap.get(session).getReadyState() == ReadyState.NOT_YET_CONNECTED) + { + cachedThreadPool.execute(() -> { + boolean needRetry = true; + while (needRetry) { + try { + if (hubMap.get(session).getReadyState() == ReadyState.OPEN) { + log.info(String.format("Hub Server: Messages forwarded to agent\nUrl=%s", hubMap.get(session).getUrl())); + hubMap.get(session).send(message); + needRetry = false; + } else if (hubMap.get(session).getReadyState() == ReadyState.NOT_YET_CONNECTED) { + log.info(String.format("Hub Server: Wait agent in 1s\nStatus=%s\nUrl=%s", hubMap.get(session).getReadyState().toString(), hubMap.get(session).getUrl())); + Thread.sleep(1000); + } else { + log.info(String.format("Hub Server: Agent closed\nStatus=%s\nUrl=%s", hubMap.get(session).getReadyState().toString(), hubMap.get(session).getUrl())); + needRetry = false; + } + + } catch (Exception error) { + needRetry = false; + StringWriter sw = new StringWriter(); + error.printStackTrace(new PrintWriter(sw)); + log.error(String.format("Hub Server: Fail to forward\nStatus=%s\nUrl=%s\nMessages=%s\nError=%s", hubMap.get(session).getReadyState().toString(), hubMap.get(session).getUrl(), message, sw.toString())); + } + } + }); + } + else + { + log.info(String.format("Hub Server: Messages forwarded to agent\nUrl=%s", hubMap.get(session).getUrl())); + hubMap.get(session).send(message); + } + } + + @OnClose + public void onClose(Session session) { + log.info(String.format("Hub Server: Closed\nUrl=%s", hubMap.get(session).getUrl())); + hubMap.get(session).close(); + hubMap.remove(session); + } + + @OnError + public void onError(Session session, Throwable error) { + StringWriter sw = new StringWriter(); + error.printStackTrace(new PrintWriter(sw)); + log.error(String.format("Hub Server: Error caught!\nUrl=%s\nError=%s", hubMap.get(session).getUrl(), sw.toString())); + } +} diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/transport/HubServiceServer.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/transport/HubServiceServer.java new file mode 100644 index 000000000..a0a3e3c5b --- /dev/null +++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/transport/HubServiceServer.java @@ -0,0 +1,99 @@ +package org.cloud.sonic.controller.transport; + + +import java.net.URI; +import java.util.HashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.io.StringWriter; +import java.io.PrintWriter; + +import org.cloud.sonic.controller.config.WsEndpointConfigure; +import org.springframework.stereotype.Component; +import org.java_websocket.enums.ReadyState; + +import jakarta.websocket.OnClose; +import jakarta.websocket.OnError; +import jakarta.websocket.OnMessage; +import jakarta.websocket.OnOpen; +import jakarta.websocket.Session; +import jakarta.websocket.server.PathParam; +import jakarta.websocket.server.ServerEndpoint; +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +@ServerEndpoint(value = "/hub/{host}/{port}/{platform}/{service}/{key}/{udId}/{token}", configurator = WsEndpointConfigure.class) +public class HubServiceServer { + HashMap hubMap = new HashMap(); + ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); + + @OnOpen + public void onOpen(Session session, @PathParam("host") String host, @PathParam("port") String port, @PathParam("platform") String platform, @PathParam("service") String service, @PathParam("key") String key, @PathParam("udId") String udId, @PathParam("token") String token) { + String agentUri = String.format("ws://%s:%s/websockets/%s/%s/%s/%s/%s", host, port, platform, service, key, udId, token); + + try { + URI uri = new URI(agentUri); + TransportClient agent = new TransportClient(session, uri); + agent.connect(); + hubMap.put(session, agent); + log.info(String.format("Hub Server: Connected to agent\nUrl=%s", agentUri)); + } + catch(Exception ex) + { + StringWriter sw = new StringWriter(); + ex.printStackTrace(new PrintWriter(sw)); + log.error(String.format("Hub Server: Failed to connect agent!\nUrl=%s\nError=%s", agentUri, sw.toString())); + } + } + + @OnMessage + public void onMessage(Session session, String message) { + if (hubMap.get(session).getReadyState() == ReadyState.NOT_YET_CONNECTED) + { + cachedThreadPool.execute(() -> { + boolean needRetry = true; + while (needRetry) { + try { + if (hubMap.get(session).getReadyState() == ReadyState.OPEN) { + log.info(String.format("Hub Server: Messages forwarded to agent\nUrl=%s", hubMap.get(session).getUrl())); + hubMap.get(session).send(message); + needRetry = false; + } else if (hubMap.get(session).getReadyState() == ReadyState.NOT_YET_CONNECTED) { + log.info(String.format("Hub Server: Wait agent in 1s\nStatus=%s\nUrl=%s", hubMap.get(session).getReadyState().toString(), hubMap.get(session).getUrl())); + Thread.sleep(1000); + } else { + log.info(String.format("Hub Server: Agent closed\nStatus=%s\nUrl=%s", hubMap.get(session).getReadyState().toString(), hubMap.get(session).getUrl())); + needRetry = false; + } + + } catch (Exception error) { + needRetry = false; + StringWriter sw = new StringWriter(); + error.printStackTrace(new PrintWriter(sw)); + log.error(String.format("Hub Server: Fail to forward\nStatus=%s\nUrl=%s\nMessages=%s\nError=%s", hubMap.get(session).getReadyState().toString(), hubMap.get(session).getUrl(), message, sw.toString())); + } + } + }); + } + else + { + log.info(String.format("Hub Server: Messages forwarded to agent\nUrl=%s", hubMap.get(session).getUrl())); + hubMap.get(session).send(message); + } + } + + @OnClose + public void onClose(Session session) { + log.info(String.format("Hub Server: Closed\nUrl=%s", hubMap.get(session).getUrl())); + hubMap.get(session).close(); + hubMap.remove(session); + } + + @OnError + public void onError(Session session, Throwable error) { + StringWriter sw = new StringWriter(); + error.printStackTrace(new PrintWriter(sw)); + log.error(String.format("Hub Server: Error caught!\nUrl=%s\nError=%s", hubMap.get(session).getUrl(), sw.toString())); + } +} diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/transport/TransportClient.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/transport/TransportClient.java new file mode 100644 index 000000000..f5f60951a --- /dev/null +++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/transport/TransportClient.java @@ -0,0 +1,76 @@ +/* + * sonic-agent Agent of Sonic Cloud Real Machine Platform. + * Copyright (C) 2022 SonicCloudOrg + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.cloud.sonic.controller.transport; + +import jakarta.websocket.Session; +import lombok.extern.slf4j.Slf4j; + +import org.cloud.sonic.controller.tools.BytesTool; +import org.java_websocket.client.WebSocketClient; +import org.java_websocket.handshake.ServerHandshake; + +import java.net.URI; +import java.nio.ByteBuffer; +import java.io.StringWriter; +import java.io.PrintWriter; + +@Slf4j +public class TransportClient extends WebSocketClient { + Session hubSession; + String url; + + public TransportClient(Session session, URI serverUri) { + super(serverUri); + hubSession = session; + url = serverUri.toString(); + } + + public String getUrl() + { + return url; + } + + @Override + public void onOpen(ServerHandshake serverHandshake) { + log.info(String.format("Hub Client: Connected to '%s'", url)); + } + + @Override + public void onMessage(String s) { + log.info(String.format("Hub Client: Messages forwarded to server\nUrl=%s", url)); + BytesTool.sendText(hubSession, s); + } + + @Override + public void onMessage(ByteBuffer bytes) { + log.info(String.format("Hub Client: Bytes forwarded to server\nUrl=%s", url)); + BytesTool.sendByte(hubSession, bytes); + } + + @Override + public void onClose(int code, String reason, boolean remote) { + log.info(String.format("Hub Client: Disconnected\nUrl=%s\nReason=%s", url, reason)); + } + + @Override + public void onError(Exception ex) { + StringWriter sw = new StringWriter(); + ex.printStackTrace(new PrintWriter(sw)); + log.error(String.format("Hub Server: Error caught!\nUrl=%s\nError=%s", url, sw.toString())); + } +}