diff --git a/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java b/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java index 6881c8445..cd9c835f3 100644 --- a/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java +++ b/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java @@ -8,6 +8,7 @@ import com.fr.design.dialog.DialogActionAdapter; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.env.DesignerWorkspaceGenerator; import com.fr.design.env.DesignerWorkspaceInfo; +import com.fr.design.env.DesignerWorkspaceInfoContext; import com.fr.design.env.DesignerWorkspaceType; import com.fr.design.env.RemoteDesignerWorkspaceInfo; import com.fr.design.env.RemoteWorkspace; @@ -105,6 +106,7 @@ public class EnvChangeEntrance { private boolean switch2Env(final String envName, PopTipStrategy strategy) { DesignerEnvManager envManager = DesignerEnvManager.getEnvManager(); DesignerWorkspaceInfo selectedEnv = envManager.getWorkspaceInfo(envName); + DesignerWorkspaceInfoContext.setWorkspaceInfo(selectedEnv); WorkspaceConnectionInfo connectionInfo = selectedEnv.getConnection(); try { diff --git a/designer-base/src/main/java/com/fr/design/env/DesignerWorkspaceInfoContext.java b/designer-base/src/main/java/com/fr/design/env/DesignerWorkspaceInfoContext.java new file mode 100644 index 000000000..ba8a5b09f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/env/DesignerWorkspaceInfoContext.java @@ -0,0 +1,20 @@ +package com.fr.design.env; + +/** + * + * @author hades + * @version 10.0 + * Created by hades on 2021/8/24 + */ +public class DesignerWorkspaceInfoContext { + + private static DesignerWorkspaceInfo workspaceInfo; + + public static DesignerWorkspaceInfo getWorkspaceInfo() { + return workspaceInfo; + } + + public static void setWorkspaceInfo(DesignerWorkspaceInfo workspaceInfo) { + DesignerWorkspaceInfoContext.workspaceInfo = workspaceInfo; + } +} diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/socketio/DesignerSocketIO.java b/designer-realize/src/main/java/com/fr/design/mainframe/socketio/DesignerSocketIO.java index 157ce6f98..782c7f35d 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/socketio/DesignerSocketIO.java +++ b/designer-realize/src/main/java/com/fr/design/mainframe/socketio/DesignerSocketIO.java @@ -5,29 +5,40 @@ import com.fr.decision.webservice.utils.DecisionServiceConstants; import com.fr.design.DesignerEnvManager; import com.fr.design.EnvChangeEntrance; import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.env.DesignerWorkspaceInfo; +import com.fr.design.env.DesignerWorkspaceInfoContext; import com.fr.design.i18n.Toolkit; import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.loghandler.DesignerLogger; import com.fr.design.ui.util.UIUtil; -import com.fr.event.Event; import com.fr.event.EventDispatcher; -import com.fr.event.Listener; +import com.fr.general.ComparatorUtils; import com.fr.log.FineLoggerFactory; import com.fr.report.RemoteDesignConstants; import com.fr.serialization.SerializerHelper; import com.fr.stable.ArrayUtils; +import com.fr.stable.StringUtils; import com.fr.third.apache.log4j.spi.LoggingEvent; +import com.fr.third.org.apache.http.conn.ssl.NoopHostnameVerifier; +import com.fr.third.org.apache.http.conn.ssl.TrustSelfSignedStrategy; +import com.fr.third.org.apache.http.ssl.SSLContexts; +import com.fr.web.WebSocketConfig; +import com.fr.web.socketio.WebSocketProtocol; import com.fr.workspace.WorkContext; import com.fr.workspace.Workspace; -import com.fr.workspace.WorkspaceEvent; import com.fr.workspace.base.WorkspaceConstants; import com.fr.workspace.connect.WorkspaceConnection; +import com.fr.workspace.connect.WorkspaceConnectionInfo; import com.fr.workspace.server.socket.SocketInfoOperator; import io.socket.client.IO; import io.socket.client.Socket; import io.socket.emitter.Emitter; +import java.io.File; +import java.io.FileInputStream; +import java.security.KeyStore; import java.util.Arrays; +import javax.net.ssl.SSLContext; import javax.swing.*; import java.io.IOException; import java.net.URI; @@ -37,26 +48,14 @@ import java.util.TimerTask; public class DesignerSocketIO { - - static { - EventDispatcher.listen(WorkspaceEvent.LostConnect, new Listener() { - @Override - public void on(Event event, Workspace param) { - // 远程设计websocket不支持wss 所以断开无法提醒 - // 使用远程设计的心跳断开来提醒断开 - if (DesignerEnvManager.getEnvManager().isHttps()) { - showConnectionLostDialog(); - } - } - }); - } - enum Status { Connected, Disconnected, Disconnecting } + private static final String HTTPS = "https"; + private static final String HTTP = "http"; private static Socket socket = null; private static Status status = Status.Disconnected; private static Timer disConnectHintTimer = null; @@ -65,6 +64,8 @@ public class DesignerSocketIO { private static String[] uri; //维护一个关于uri列表的计数器 private static int count; + // 当前webSocket选择的协议 + private static String currentProtocol; public static void close() { @@ -95,7 +96,7 @@ public class DesignerSocketIO { //根据uri和计数器建立连接,并注册监听 try { if (count < uri.length) { - socket = IO.socket(new URI(uri[count])); + socket = IO.socket(new URI(uri[count]), createOptions()); socket.on(WorkspaceConstants.WS_LOGRECORD, printLog); socket.on(WorkspaceConstants.CONFIG_MODIFY, modifyConfig); socket.on(Socket.EVENT_CONNECT_ERROR, failRetry); @@ -112,15 +113,58 @@ public class DesignerSocketIO { } } + private static IO.Options createOptions() { + IO.Options options = new IO.Options(); + try { + if (ComparatorUtils.equals(currentProtocol, HTTPS)) { + options.sslContext = getSSLContext(); + options.hostnameVerifier = NoopHostnameVerifier.INSTANCE; + options.secure = true; + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + return options; + } + + private static SSLContext getSSLContext() throws Exception { + WorkspaceConnectionInfo connection = getConnectionInfo(); + String certPath = connection.getCertPath(); + String certSecretKey = connection.getCertSecretKey(); + if (StringUtils.isBlank(certPath) || StringUtils.isBlank(certSecretKey)) { + return SSLContexts.createDefault(); + } + KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); + try (FileInputStream keystore = new FileInputStream(new File(certPath))) { + trustStore.load(keystore, certSecretKey.toCharArray()); + } + return SSLContexts.custom() + .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()) + .build(); + } + + private static WorkspaceConnectionInfo getConnectionInfo() { + if (DesignerWorkspaceInfoContext.getWorkspaceInfo() == null) { + String currentName = DesignerEnvManager.getEnvManager().getCurEnvName(); + DesignerWorkspaceInfo info = DesignerEnvManager.getEnvManager().getWorkspaceInfo(currentName); + return info.getConnection(); + } else { + return DesignerWorkspaceInfoContext.getWorkspaceInfo().getConnection(); + } + } + private static String[] getSocketUri() throws IOException { Workspace current = WorkContext.getCurrent(); URL url = new URL(current.getPath()); Integer[] ports = current.get(SocketInfoOperator.class).getPort(); WorkspaceConnection connection = current.getConnection(); + // 服务器配置https webSocket可能是wss也可能是ws webSocket的协议可以单独配置 + WebSocketProtocol webSocketProtocol = WebSocketConfig.getInstance().getProtocol(); + currentProtocol = webSocketProtocol == WebSocketProtocol.PLAIN ? HTTP : HTTPS; String[] result = new String[ports.length]; for (int i = 0; i < ports.length; i++) { result[i] = String.format("%s://%s:%s%s?%s=%s&%s=%s", - url.getProtocol(), + currentProtocol, url.getHost(), ports[i], WorkspaceConstants.WS_NAMESPACE, @@ -129,6 +173,7 @@ public class DesignerSocketIO { RemoteDesignConstants.USER_LOCK_ID, connection.getId()); } + FineLoggerFactory.getLogger().error("Available ports: {}, current Protocol: {}", Arrays.toString(ports), currentProtocol); return result; } @@ -136,7 +181,7 @@ public class DesignerSocketIO { private static final Emitter.Listener failRetry = new Emitter.Listener() { @Override public void call(Object... args) { - FineLoggerFactory.getLogger().warn("failed args: {}", Arrays.toString(args)); + printLog(args, PrintEventLogImpl.WARN, "failed args: {}"); status = Status.Disconnecting; socket.close(); count++; @@ -183,7 +228,7 @@ public class DesignerSocketIO { * todo 远程心跳断开不一定 socket 断开 和远程紧密相关的业务都绑定在心跳上,切换成心跳断开之后进行提醒, * socket 只用推日志和通知配置变更 */ - FineLoggerFactory.getLogger().error("disConnected args: {}", Arrays.toString(objects)); + printLog(objects, PrintEventLogImpl.ERROR, "disConnected args: {}"); if (status != Status.Disconnecting) { showConnectionLostDialog(); } @@ -199,7 +244,7 @@ public class DesignerSocketIO { private static void showConnectionLostDialog() { try { - UIUtil.invokeAndWaitIfNeeded(new Runnable() { + UIUtil.invokeLaterIfNeeded(new Runnable() { @Override public void run() { FineJOptionPane.showMessageDialog( @@ -226,4 +271,46 @@ public class DesignerSocketIO { } }; + private static void printLog(Object[] objects, PrintEventLog printEventLog, String prefix) { + for (Object object : objects) { + if (object instanceof Throwable) { + Throwable throwable = (Throwable) object; + printEventLog.printThrowable(throwable); + } else { + printEventLog.print(prefix, object); + } + } + } + + interface PrintEventLog { + void printThrowable(Throwable throwable); + void print(String s, Object ...object); + } + + enum PrintEventLogImpl implements PrintEventLog { + ERROR { + @Override + public void printThrowable(Throwable throwable) { + FineLoggerFactory.getLogger().error(throwable.getMessage(), throwable); + } + + @Override + public void print(String s, Object... object) { + FineLoggerFactory.getLogger().error(s, object); + } + }, + + WARN { + @Override + public void printThrowable(Throwable throwable) { + FineLoggerFactory.getLogger().warn(throwable.getMessage(), throwable); + } + + @Override + public void print(String s, Object... object) { + FineLoggerFactory.getLogger().warn(s, object); + } + }; + } + }