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做了适当修改。
The newest version!
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.OftenObject;
import cn.xishan.oftenporter.porter.core.base.OutType;
import cn.xishan.oftenporter.porter.core.base.SyncOption;
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.enums.ReadyState;
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.getReadyState() != ReadyState.NOT_YET_CONNECTED) {
//重试
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 - 2024 Weber Informatics LLC | Privacy Policy