@ -5,29 +5,39 @@ 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.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 +47,14 @@ import java.util.TimerTask;
public class DesignerSocketIO {
static {
EventDispatcher . listen ( WorkspaceEvent . LostConnect , new Listener < Workspace > ( ) {
@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 +63,8 @@ public class DesignerSocketIO {
private static String [ ] uri ;
//维护一个关于uri列表的计数器
private static int count ;
// 当前webSocket选择的协议
private static String currentProtocol ;
public static void close ( ) {
@ -95,7 +95,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 +112,54 @@ 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 {
String currentName = DesignerEnvManager . getEnvManager ( ) . getCurEnvName ( ) ;
DesignerWorkspaceInfo info = DesignerEnvManager . getEnvManager ( ) . getWorkspaceInfo ( currentName ) ;
WorkspaceConnectionInfo connection = info . getConnection ( ) ;
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 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 ;
if ( WebSocketConfig . getInstance ( ) . isUsingProxy ( ) ) {
// 如果配置了代理服务器跟随服务器协议
currentProtocol = url . getProtocol ( ) ;
}
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 +168,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 +176,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 +223,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 ( ) ;
}
@ -226,4 +266,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 . getMessage ( ) , throwable ) ;
} else {
printEventLog . print ( prefix , object ) ;
}
}
}
interface PrintEventLog {
void printThrowable ( String s , Throwable throwable ) ;
void print ( String s , Object . . . object ) ;
}
enum PrintEventLogImpl implements PrintEventLog {
ERROR {
@Override
public void printThrowable ( String s , Throwable throwable ) {
FineLoggerFactory . getLogger ( ) . error ( s , throwable ) ;
}
@Override
public void print ( String s , Object . . . object ) {
FineLoggerFactory . getLogger ( ) . error ( s , object ) ;
}
} ,
WARN {
@Override
public void printThrowable ( String s , Throwable throwable ) {
FineLoggerFactory . getLogger ( ) . warn ( s , throwable ) ;
}
@Override
public void print ( String s , Object . . . object ) {
FineLoggerFactory . getLogger ( ) . warn ( s , object ) ;
}
} ;
}
}