cn.xishan.oftenporter.bridge.http.websocket.WSClientHandle Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of Porter-Bridge-Http Show documentation
Show all versions of Porter-Bridge-Http Show documentation
转接远程的http接口,服务器响应正确的数据格式必须是JResponse定义的格式。
客户端websocket使用"org.java-websocket:Java-WebSocket:1.5.2",项目地址https://github.com/TooTallNate/Java-WebSocket;
对Java-WebSocket做了适当修改。
package cn.xishan.oftenporter.bridge.http.websocket;
import cn.xishan.oftenporter.porter.core.advanced.IConfigData;
import cn.xishan.oftenporter.porter.core.annotation.AspectOperationOfPortIn;
import cn.xishan.oftenporter.porter.core.annotation.PortInited;
import cn.xishan.oftenporter.porter.core.annotation.sth.PorterOfFun;
import cn.xishan.oftenporter.porter.core.base.OutType;
import cn.xishan.oftenporter.porter.core.base.SyncOption;
import cn.xishan.oftenporter.porter.core.base.OftenObject;
import cn.xishan.oftenporter.porter.core.util.OftenTool;
import org.java_websocket.WebSocket;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.framing.Framedata;
import org.java_websocket.handshake.ServerHandshake;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author Created by https://github.com/CLovinr on 2017/11/20.
*/
class WSClientHandle extends AspectOperationOfPortIn.HandleAdapter
{
private static final Logger LOGGER = LoggerFactory.getLogger(WSClientHandle.class);
private static AtomicInteger count = new AtomicInteger();
class Handle implements SessionImpl.OnClose
{
private WSClient wsClient = new WSClient();
private WSClientConfig wsClientConfig;
private boolean isDestroyed = false;
private ScheduledExecutorService scheduledExecutorService;
private OftenObject oftenObject;
private long lastRetryTime;
private int retriedCount;
private ScheduledFuture firstStartCheckFuture;
public Handle()
{
}
private Object invoke(OftenObject oftenObject) throws Throwable
{
try
{
return porterOfFun.invokeByHandleArgs(oftenObject, wsClient);
} finally
{
if (oftenObject != null)
{
oftenObject.release();
}
}
}
void start(OftenObject oftenObject)
{
try
{
this.oftenObject = oftenObject;
this.wsClient.set(ClientWebSocket.Type.ON_CONFIG, null);
WSClientConfig wsClientConfig = (WSClientConfig) invoke(oftenObject);
this.wsClientConfig = wsClientConfig;
scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(r -> {
Thread thread = new Thread(r);
thread.setName("porter-bridge-http-thread-" + count.getAndIncrement());
thread.setDaemon(true);
return thread;
});
Runnable firstStartCheckRunnable = () -> {
if (isDestroyed)
{
return;
}
if (wsClient.session == null || wsClient.session.isClosed())
{
doConnect();
}
};
firstStartCheckFuture = scheduledExecutorService
.scheduleAtFixedRate(firstStartCheckRunnable, wsClientConfig.initDelay,
wsClientConfig.retryDelay, TimeUnit.MILLISECONDS);
} catch (Throwable e)
{
throw new RuntimeException(e);
}
}
@Override
public void onClosed()
{
}
void destroy()
{
if (isDestroyed)
{
return;
}
isDestroyed = true;
if (wsClient.session != null)
{
wsClient.session.close();
}
if (scheduledExecutorService != null)
{
scheduledExecutorService.shutdownNow();
scheduledExecutorService = null;
}
}
void doConnect()
{
if (wsClient.session == null)
{
connect();
} else
{
if (!wsClient.session.webSocketClient.isConnecting())
{
//重试
if (wsClientConfig.retryTimes < 0 || hasRetryTimes())
{
lastRetryTime = System.currentTimeMillis();
scheduledExecutorService
.schedule(this::connect, wsClientConfig.retryDelay, TimeUnit.MILLISECONDS);
} else
{
LOGGER.warn("stop retry!");
handleSet.remove(this);
wsClient.session = null;
destroy();
}
}
}
}
private boolean hasRetryTimes()
{
if (wsClientConfig.retryTimes < 0)
{
return true;
}
if (System.currentTimeMillis() - lastRetryTime > wsClientConfig.retryDelay * 10)
{
retriedCount = 0;
}
if (retriedCount++ < wsClientConfig.retryTimes)
{
return true;
} else
{
return true;
}
}
void connect()
{
try
{
_connect();
} catch (Throwable e)
{
e = OftenTool.getCause(e);
LOGGER.error(e.getMessage(), e);
}
}
private void _connect() throws Throwable
{
if (wsClient.session != null && wsClient.session.webSocketClient.isOpen())
{
return;
}
if (wsClient.session != null)
{
wsClient.session.close();
}
String wsUrl = wsClientConfig.getWSUrl();
WebSocketClient webSocketClient = new WebSocketClient(URI.create(wsUrl),
new Draft_6455(),
wsClientConfig.getConnectHeaders(), wsClientConfig.connectTimeout)
{
private void maySend(Object obj)
{
if (obj == null)
{
return;
}
if (obj instanceof byte[])
{
byte[] bs = (byte[]) obj;
wsClient.session.send(bs);
} else if (obj instanceof ByteBuffer)
{
ByteBuffer byteBuffer = (ByteBuffer) obj;
wsClient.session.send(byteBuffer);
} else
{
wsClient.session.send(String.valueOf(obj));
}
}
@Override
public void onOpen(ServerHandshake handshakedata)
{
try
{
wsClient.set(ClientWebSocket.Type.ON_OPEN, null);
Object obj = invoke(oftenObject);
maySend(obj);
} catch (Throwable e)
{
throw new RuntimeException(e);
}
}
@Override
public void onMessage(String message)
{
try
{
wsClient.set(ClientWebSocket.Type.ON_MESSAGE, message);
Object obj = invoke(oftenObject);
maySend(obj);
} catch (Throwable e)
{
throw new RuntimeException(e);
}
}
@Override
public void onMessage(ByteBuffer bytes)
{
try
{
wsClient.set(ClientWebSocket.Type.ON_BINARY_BYTE_BUFFER, bytes);
Object obj = invoke(oftenObject);
maySend(obj);
} catch (Throwable e)
{
throw new RuntimeException(e);
}
}
@Override
public void onWebsocketPong(WebSocket conn, Framedata f)
{
try
{
ByteBuffer byteBuffer = f.getPayloadData();
wsClient.set(ClientWebSocket.Type.ON_PONG, byteBuffer);
Object obj = invoke(oftenObject);
maySend(obj);
} catch (Throwable e)
{
throw new RuntimeException(e);
}
}
@Override
public void onClose(int code, String reason, boolean remote)
{
try
{
wsClient.set(ClientWebSocket.Type.ON_CLOSE, new ClientCloseReason(code, reason));
invoke(oftenObject);
} catch (Throwable e)
{
LOGGER.debug(e.getMessage(), e);
} finally
{
doConnect();
}
}
@Override
public void onError(Exception ex)
{
try
{
wsClient.set(ClientWebSocket.Type.ON_ERROR, ex);
porterOfFun.invokeByHandleArgs(oftenObject, wsClient);
} catch (Throwable e)
{
throw new RuntimeException(e);
}
}
};
wsClient.setSession(new SessionImpl(webSocketClient, this, String.valueOf(count.getAndIncrement())));
if (wsClientConfig.pingTimeSecond != null)
{
webSocketClient.setPingTime(wsClientConfig.pingTimeSecond);
}
if (wsClientConfig.connectionLostTimeoutSecond != null)
{
webSocketClient.setConnectionLostTimeout(wsClientConfig.connectionLostTimeoutSecond);
}
webSocketClient.setEnablePing(wsClientConfig.enablePing);
LOGGER.debug("connect to WebSocket server...:{}", wsUrl);
webSocketClient.connectBlocking();
if (firstStartCheckFuture != null)
{
firstStartCheckFuture.cancel(false);
firstStartCheckFuture = null;
}
}
}
private PorterOfFun porterOfFun;
private Set handleSet = ConcurrentHashMap.newKeySet();
private ClientWebSocket clientWebSocket;
@Override
public boolean init(ClientWebSocket current, IConfigData configData, PorterOfFun porterOfFun)
{
this.porterOfFun = porterOfFun;
this.clientWebSocket = current;
return true;
}
@PortInited
public void onInited(OftenObject oftenObject)
{
if (clientWebSocket.autoStart())
{
for (int i = 0; i < clientWebSocket.startCount(); i++)
{
SyncOption syncOption = new SyncOption(porterOfFun.getMethodPortIn().getMethods()[0],
porterOfFun.getMethodPortIn().getTiedNames()[0]);
oftenObject.newSyncPorter(syncOption).invokeWithNameValues(oftenObject);
}
}
}
@Override
public void onDestroy()
{
Iterator iterator = handleSet.iterator();
while (iterator.hasNext())
{
try
{
iterator.next().destroy();
} catch (Exception e)
{
LOGGER.debug(e.getMessage(), e);
}
iterator.remove();
}
}
@Override
public boolean needInvoke(OftenObject oftenObject, PorterOfFun porterOfFun, Object lastReturn)
{
return true;
}
@Override
public Object invoke(OftenObject oftenObject, PorterOfFun porterOfFun, Object lastReturn) throws Exception
{
Handle handle = new Handle();
handle.start(oftenObject);
handleSet.add(handle);
return null;
}
@Override
public OutType getOutType()
{
return OutType.NO_RESPONSE;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy