6 changed files with 221 additions and 17 deletions
-
5src/pom.xml
-
16src/src/main/java/com/my/graphiteDigesterBg/diframe/DiDevice.java
-
144src/src/main/java/com/my/graphiteDigesterBg/diframe/connection/DiConWebsocket.java
-
49src/src/main/java/com/my/graphiteDigesterBg/diframe/connection/DiConWebsocketClient.java
-
8src/src/main/resources/application.yml
-
16src/src/main/resources/device.yml
@ -0,0 +1,144 @@ |
|||||
|
package com.my.graphiteDigesterBg.diframe.connection; |
||||
|
import com.my.graphiteDigesterBg.diframe.DiCommandRequest; |
||||
|
import com.my.graphiteDigesterBg.diframe.DiDevice; |
||||
|
import com.my.graphiteDigesterBg.diframe.DiDeviceConnection; |
||||
|
import com.my.graphiteDigesterBg.diframe.util.DiByteBuffer; |
||||
|
import org.slf4j.Logger; |
||||
|
import org.slf4j.LoggerFactory; |
||||
|
import java.net.URI; |
||||
|
import java.net.URISyntaxException; |
||||
|
import java.nio.ByteBuffer; |
||||
|
import java.nio.ByteOrder; |
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
import java.util.Timer; |
||||
|
import java.util.TimerTask; |
||||
|
public class DiConWebsocket implements DiDeviceConnection { |
||||
|
// logger |
||||
|
public static final Logger LOG = LoggerFactory.getLogger(DiConWebsocket.class); |
||||
|
// device |
||||
|
private DiDevice device; |
||||
|
// client |
||||
|
private DiConWebsocketClient client; |
||||
|
// requests |
||||
|
private final List<DiCommandRequest> requests; |
||||
|
|
||||
|
// constructor |
||||
|
public DiConWebsocket() { |
||||
|
this.requests = new ArrayList<>(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void setDevice(DiDevice device) { |
||||
|
this.device = device; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void connect() { |
||||
|
String wsUri = this.device.getConfig("connection.uri"); |
||||
|
if ( null == wsUri ) { |
||||
|
throw new RuntimeException("device option 'device.connection.uri' is required."); |
||||
|
} |
||||
|
URI uri = null; |
||||
|
try { |
||||
|
uri = new URI(wsUri); |
||||
|
} catch (URISyntaxException e) { |
||||
|
throw new RuntimeException(e); |
||||
|
} |
||||
|
this.client = new DiConWebsocketClient(uri); |
||||
|
this.client.connect(); |
||||
|
this.client.setHolder(this); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void call(DiCommandRequest request) { |
||||
|
this.requests.add(request); |
||||
|
String cmd = DiByteBuffer.toHex(request.parameter); |
||||
|
LOG.info("Command => {} : [{}]", request.parameterText, cmd); |
||||
|
cmd = cmd.replace(" ",""); |
||||
|
this.client.send(cmd); |
||||
|
this.setupRequestTimeoutTimer(request); |
||||
|
synchronized ( request ) { |
||||
|
try { |
||||
|
request.wait(); |
||||
|
} catch (InterruptedException e) { |
||||
|
throw new RuntimeException(e); |
||||
|
} |
||||
|
} |
||||
|
LOG.info("Command <= {}", DiByteBuffer.toHex(request.response)); |
||||
|
} |
||||
|
|
||||
|
// setup request timeout timer |
||||
|
private void setupRequestTimeoutTimer(DiCommandRequest request) { |
||||
|
TimerTask callTimeoutTimerTask = new TimerTask() { |
||||
|
@Override |
||||
|
public void run() { |
||||
|
DiConWebsocket.this.handleCallTimeout(request); |
||||
|
} |
||||
|
}; |
||||
|
request.timeoutTimer = new Timer(); |
||||
|
Integer callTimeout = this.device.getConfig("connection.callTimeout", Integer.class); |
||||
|
request.timeoutTimer.schedule(callTimeoutTimerTask, callTimeout); |
||||
|
} |
||||
|
|
||||
|
// handle call timeout |
||||
|
private void handleCallTimeout(DiCommandRequest request) { |
||||
|
if ( request.isResponseReceived ) { |
||||
|
return ; |
||||
|
} |
||||
|
|
||||
|
request.timeoutCount ++; |
||||
|
if ( request.timeoutCount > 3 ) { |
||||
|
synchronized ( request ) { |
||||
|
request.timeoutTimer = null; |
||||
|
request.errorCode = 8000; |
||||
|
request.notify(); |
||||
|
} |
||||
|
return ; |
||||
|
} |
||||
|
|
||||
|
String cmd = DiByteBuffer.toHex(request.parameter); |
||||
|
LOG.info("Command (Retry:{}) => {} : [{}]", request.timeoutCount, request.parameterText, cmd); |
||||
|
cmd = cmd.replace(" ",""); |
||||
|
this.client.send(cmd); |
||||
|
this.setupRequestTimeoutTimer(request); |
||||
|
} |
||||
|
|
||||
|
// handle on data |
||||
|
public void handleOnText(String text) { |
||||
|
ByteBuffer message = DiByteBuffer.fromHex(text); |
||||
|
message.order(ByteOrder.LITTLE_ENDIAN); |
||||
|
byte messageType = message.get(5); |
||||
|
if ( 0x01 == messageType ) { // ack message |
||||
|
this.handleOnTextAckMessage(message); |
||||
|
} else if ( 0x02 == messageType ) { // error message |
||||
|
throw new RuntimeException("error message received: " + text); |
||||
|
} else { |
||||
|
throw new RuntimeException("unknown message type : " + messageType + " <= " + text); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// handle on data timeout for binary mode ack message |
||||
|
private void handleOnTextAckMessage(ByteBuffer message) { |
||||
|
short messageId = message.getShort(0); |
||||
|
DiCommandRequest request = null; |
||||
|
for ( DiCommandRequest requestItem : this.requests ) { |
||||
|
if ( requestItem.id == messageId ) { |
||||
|
request = requestItem; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
if ( null == request ) { |
||||
|
return ; // 可能是超时了, 已经被处理掉了 ~~~ |
||||
|
} |
||||
|
request.response = message; |
||||
|
request.isResponseReceived = true; |
||||
|
if ( null != request.timeoutTimer ) { |
||||
|
request.timeoutTimer.cancel(); |
||||
|
request.timeoutTimer = null; |
||||
|
} |
||||
|
synchronized ( request ) { |
||||
|
request.notify(); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,49 @@ |
|||||
|
package com.my.graphiteDigesterBg.diframe.connection; |
||||
|
import org.java_websocket.client.WebSocketClient; |
||||
|
import org.java_websocket.handshake.ServerHandshake; |
||||
|
import org.slf4j.Logger; |
||||
|
import org.slf4j.LoggerFactory; |
||||
|
import java.net.URI; |
||||
|
public class DiConWebsocketClient extends WebSocketClient { |
||||
|
// logger |
||||
|
public static final Logger LOG = LoggerFactory.getLogger(DiConWebsocketClient.class); |
||||
|
|
||||
|
// holder |
||||
|
private DiConWebsocket holder; |
||||
|
|
||||
|
// constructor |
||||
|
public DiConWebsocketClient(URI uri) { |
||||
|
super(uri); |
||||
|
} |
||||
|
|
||||
|
// set holder |
||||
|
public void setHolder(DiConWebsocket holder) { |
||||
|
this.holder = holder; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* event handler for receiving text message from device |
||||
|
* @param text message from device |
||||
|
*/ |
||||
|
@Override |
||||
|
public void onMessage(String text) { |
||||
|
this.holder.handleOnText(text); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onOpen(ServerHandshake serverHandshake) { |
||||
|
LOG.info("device connected : {}", this.uri); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onClose(int i, String s, boolean b) { |
||||
|
LOG.info("close"); |
||||
|
throw new RuntimeException("device connection closed"); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onError(Exception e) { |
||||
|
LOG.error("error", e); |
||||
|
throw new RuntimeException(e); |
||||
|
} |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue