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()));
+ }
+}