1、添加websocket插件包
parent
6c99d57905
commit
f631bbfd8a
1
pom.xml
1
pom.xml
|
@ -11,6 +11,7 @@
|
|||
<module>DLT645-plugin</module>
|
||||
<module>hydrovalve-plugin</module>
|
||||
<module>emqx-plugin</module>
|
||||
<module>websocket-plugin</module>
|
||||
</modules>
|
||||
|
||||
<parent>
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>iot-iita-plugins</artifactId>
|
||||
<groupId>cc.iotkit.plugins</groupId>
|
||||
<version>1.0.1</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>websocket-plugin</artifactId>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-core</artifactId>
|
||||
<version>${vertx.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>dev</id>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<properties>
|
||||
<plugin.build.mode>dev</plugin.build.mode>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>prod</id>
|
||||
<properties>
|
||||
<plugin.build.mode>prod</plugin.build.mode>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.gitee.starblues</groupId>
|
||||
<artifactId>spring-brick-maven-packager</artifactId>
|
||||
<version>${spring-brick.version}</version>
|
||||
<configuration>
|
||||
<mode>${plugin.build.mode}</mode>
|
||||
<pluginInfo>
|
||||
<id>websocket-plugin</id>
|
||||
<bootstrapClass>cc.iotkit.plugins.websocket.Application</bootstrapClass>
|
||||
<version>${project.version}</version>
|
||||
<provider>iita</provider>
|
||||
<description>websocket示例插件</description>
|
||||
<configFileName>application.yml</configFileName>
|
||||
</pluginInfo>
|
||||
<prodConfig>
|
||||
<packageType>jar</packageType>
|
||||
</prodConfig>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,19 @@
|
|||
package cc.iotkit.plugins.websocket;
|
||||
|
||||
import com.gitee.starblues.bootstrap.SpringPluginBootstrap;
|
||||
import com.gitee.starblues.bootstrap.annotation.OneselfConfig;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
|
||||
/**
|
||||
* @author tfd
|
||||
*/
|
||||
@SpringBootApplication(scanBasePackages = "cc.iotkit.plugins.websocket")
|
||||
@OneselfConfig(mainConfigFileName = {"application.yml"})
|
||||
@EnableConfigurationProperties
|
||||
public class Application extends SpringPluginBootstrap {
|
||||
|
||||
public static void main(String[] args) {
|
||||
new Application().run(Application.class, args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package cc.iotkit.plugins.websocket.conf;
|
||||
|
||||
import cc.iotkit.plugin.core.IPluginConfig;
|
||||
import cc.iotkit.plugin.core.LocalPluginConfig;
|
||||
import cc.iotkit.plugin.core.thing.IThingService;
|
||||
import cc.iotkit.plugins.websocket.service.FakeThingService;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author tfd
|
||||
*/
|
||||
@Component
|
||||
public class BeanConfig {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(name = "plugin.runMode", havingValue = "dev")
|
||||
IThingService getThingService() {
|
||||
return new FakeThingService();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(name = "plugin.runMode", havingValue = "dev")
|
||||
IPluginConfig getPluginConfig(){
|
||||
return new LocalPluginConfig();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* +----------------------------------------------------------------------
|
||||
* | Copyright (c) 奇特物联 2021-2022 All rights reserved.
|
||||
* +----------------------------------------------------------------------
|
||||
* | Licensed 未经许可不能去掉「奇特物联」相关版权
|
||||
* +----------------------------------------------------------------------
|
||||
* | Author: xw2sy@163.com
|
||||
* +----------------------------------------------------------------------
|
||||
*/
|
||||
package cc.iotkit.plugins.websocket.conf;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "websocket")
|
||||
public class WebsocketConfig {
|
||||
|
||||
private int port;
|
||||
|
||||
private String sslKey;
|
||||
|
||||
private String sslCert;
|
||||
|
||||
private boolean ssl;
|
||||
|
||||
private List<AccessToken> accessTokens;
|
||||
|
||||
@Data
|
||||
public static class AccessToken{
|
||||
private String tokenName;
|
||||
private String tokenStr;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package cc.iotkit.plugins.websocket.service;
|
||||
|
||||
import cc.iotkit.plugin.core.thing.IThingService;
|
||||
import cc.iotkit.plugin.core.thing.actions.ActionResult;
|
||||
import cc.iotkit.plugin.core.thing.actions.IDeviceAction;
|
||||
import cc.iotkit.plugin.core.thing.model.ThingDevice;
|
||||
import cc.iotkit.plugin.core.thing.model.ThingProduct;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 测试服务
|
||||
*
|
||||
* @author tfd
|
||||
*/
|
||||
@Slf4j
|
||||
public class FakeThingService implements IThingService {
|
||||
|
||||
|
||||
/**
|
||||
* 添加测试设备
|
||||
*/
|
||||
private static final Map<String, String> DEVICES = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public ActionResult post(String pluginId, IDeviceAction action) {
|
||||
log.info("post action:{}", action);
|
||||
return ActionResult.builder().code(0).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThingProduct getProduct(String pk) {
|
||||
return ThingProduct.builder()
|
||||
.productKey(pk)
|
||||
.productSecret("")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThingDevice getDevice(String dn) {
|
||||
return ThingDevice.builder()
|
||||
.productKey(DEVICES.get(dn))
|
||||
.deviceName(dn)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ?> getProperty(String dn) {
|
||||
return new HashMap<>(0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package cc.iotkit.plugins.websocket.service;
|
||||
|
||||
import cc.iotkit.common.enums.ErrCode;
|
||||
import cc.iotkit.common.exception.BizException;
|
||||
import cc.iotkit.plugin.core.thing.IDevice;
|
||||
import cc.iotkit.plugin.core.thing.actions.ActionResult;
|
||||
import cc.iotkit.plugin.core.thing.actions.down.DeviceConfig;
|
||||
import cc.iotkit.plugin.core.thing.actions.down.PropertyGet;
|
||||
import cc.iotkit.plugin.core.thing.actions.down.PropertySet;
|
||||
import cc.iotkit.plugin.core.thing.actions.down.ServiceInvoke;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* websocket设备服务
|
||||
*
|
||||
* @author tfd
|
||||
*/
|
||||
@Service
|
||||
public class WebsocketDevice implements IDevice {
|
||||
|
||||
@Autowired
|
||||
private WebsocketVerticle websocketVerticle;
|
||||
|
||||
@Override
|
||||
public ActionResult config(DeviceConfig action) {
|
||||
return ActionResult.builder().code(0).reason("").build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult propertyGet(PropertyGet action) {
|
||||
return send(
|
||||
action.getDeviceName(),
|
||||
new JsonObject()
|
||||
.put("id", action.getId())
|
||||
.put("method", "thing.service.property.get")
|
||||
.put("params", action.getKeys())
|
||||
.toString()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult propertySet(PropertySet action) {
|
||||
return send(
|
||||
action.getDeviceName(),
|
||||
new JsonObject()
|
||||
.put("id", action.getId())
|
||||
.put("method", "thing.service.property.set")
|
||||
.put("params", action.getParams())
|
||||
.toString()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult serviceInvoke(ServiceInvoke action) {
|
||||
return send(
|
||||
action.getDeviceName(),
|
||||
new JsonObject()
|
||||
.put("id", action.getId())
|
||||
.put("method", "thing.service." + action.getName())
|
||||
.put("params", action.getParams())
|
||||
.toString()
|
||||
);
|
||||
}
|
||||
|
||||
private ActionResult send(String deviceName, String payload) {
|
||||
try {
|
||||
websocketVerticle.send(
|
||||
deviceName,
|
||||
payload
|
||||
);
|
||||
return ActionResult.builder().code(0).reason("").build();
|
||||
} catch (BizException e) {
|
||||
return ActionResult.builder().code(e.getCode()).reason(e.getMessage()).build();
|
||||
} catch (Exception e) {
|
||||
return ActionResult.builder().code(ErrCode.UNKNOWN_EXCEPTION.getKey()).reason(e.getMessage()).build();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package cc.iotkit.plugins.websocket.service;
|
||||
|
||||
import cc.iotkit.plugin.core.IPluginConfig;
|
||||
import cc.iotkit.plugins.websocket.conf.WebsocketConfig;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.bean.copier.CopyOptions;
|
||||
import com.gitee.starblues.bootstrap.annotation.AutowiredType;
|
||||
import com.gitee.starblues.bootstrap.realize.PluginCloseListener;
|
||||
import com.gitee.starblues.core.PluginCloseType;
|
||||
import com.gitee.starblues.core.PluginInfo;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.Vertx;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author tfd
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class WebsocketPlugin implements PluginCloseListener {
|
||||
|
||||
@Autowired
|
||||
private PluginInfo pluginInfo;
|
||||
@Autowired
|
||||
private WebsocketVerticle websocketVerticle;
|
||||
@Autowired
|
||||
private WebsocketConfig websocketConfig;
|
||||
|
||||
@Autowired
|
||||
@AutowiredType(AutowiredType.Type.MAIN_PLUGIN)
|
||||
private IPluginConfig pluginConfig;
|
||||
|
||||
private Vertx vertx;
|
||||
private String deployedId;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
vertx = Vertx.vertx();
|
||||
try {
|
||||
//获取插件最新配置替换当前配置
|
||||
Map<String, Object> config = pluginConfig.getConfig(pluginInfo.getPluginId());
|
||||
BeanUtil.copyProperties(config, websocketConfig, CopyOptions.create().ignoreNullValue());
|
||||
websocketVerticle.setConfig(websocketConfig);
|
||||
|
||||
Future<String> future = vertx.deployVerticle(websocketVerticle);
|
||||
future.onSuccess((s -> {
|
||||
deployedId = s;
|
||||
log.info("websocket plugin started success");
|
||||
}));
|
||||
future.onFailure((e) -> {
|
||||
log.error("websocket plugin startup failed", e);
|
||||
});
|
||||
} catch (Throwable e) {
|
||||
log.error("websocket plugin startup error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(GenericApplicationContext applicationContext, PluginInfo pluginInfo, PluginCloseType closeType) {
|
||||
try {
|
||||
log.info("plugin close,type:{},pluginId:{}", closeType, pluginInfo.getPluginId());
|
||||
if (deployedId != null) {
|
||||
CountDownLatch wait = new CountDownLatch(1);
|
||||
Future<Void> future = vertx.undeploy(deployedId);
|
||||
future.onSuccess(unused -> {
|
||||
log.info("websocket plugin stopped success");
|
||||
wait.countDown();
|
||||
});
|
||||
future.onFailure(h -> {
|
||||
log.info("websocket plugin stopped failed");
|
||||
h.printStackTrace();
|
||||
wait.countDown();
|
||||
});
|
||||
wait.await(5, TimeUnit.SECONDS);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
log.error("websocket plugin stop error", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
* +----------------------------------------------------------------------
|
||||
* | Copyright (c) 奇特物联 2021-2022 All rights reserved.
|
||||
* +----------------------------------------------------------------------
|
||||
* | Licensed 未经许可不能去掉「奇特物联」相关版权
|
||||
* +----------------------------------------------------------------------
|
||||
* | Author: xw2sy@163.com
|
||||
* +----------------------------------------------------------------------
|
||||
*/
|
||||
package cc.iotkit.plugins.websocket.service;
|
||||
|
||||
import cc.iotkit.common.utils.JsonUtils;
|
||||
import cc.iotkit.common.utils.StringUtils;
|
||||
import cc.iotkit.plugin.core.thing.IThingService;
|
||||
import cc.iotkit.plugin.core.thing.actions.ActionResult;
|
||||
import cc.iotkit.plugin.core.thing.actions.DeviceState;
|
||||
import cc.iotkit.plugin.core.thing.actions.up.DeviceRegister;
|
||||
import cc.iotkit.plugin.core.thing.actions.up.DeviceStateChange;
|
||||
import cc.iotkit.plugins.websocket.conf.WebsocketConfig;
|
||||
import com.gitee.starblues.bootstrap.annotation.AutowiredType;
|
||||
import com.gitee.starblues.core.PluginInfo;
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.http.HttpServer;
|
||||
import io.vertx.core.http.HttpServerOptions;
|
||||
import io.vertx.core.http.ServerWebSocket;
|
||||
import io.vertx.core.net.PemKeyCertOptions;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author tfd
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@Data
|
||||
public class WebsocketVerticle extends AbstractVerticle {
|
||||
|
||||
private HttpServer httpServer;
|
||||
private final Map<String, ServerWebSocket> wsClients = new ConcurrentHashMap<>();
|
||||
|
||||
private static final Map<String, Boolean> CONNECT_POOL = new ConcurrentHashMap<>();
|
||||
private static final Map<String, Boolean> DEVICE_ONLINE = new ConcurrentHashMap<>();
|
||||
|
||||
private Map<String, String> tokens=new HashMap<>();
|
||||
|
||||
private WebsocketConfig config;
|
||||
|
||||
@Autowired
|
||||
@AutowiredType(AutowiredType.Type.MAIN_PLUGIN)
|
||||
private IThingService thingService;
|
||||
|
||||
@Autowired
|
||||
private PluginInfo pluginInfo;
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
Executors.newSingleThreadScheduledExecutor().schedule(this::initMqttServer, 3, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void initMqttServer() {
|
||||
HttpServerOptions options = new HttpServerOptions()
|
||||
.setPort(config.getPort());
|
||||
if (config.isSsl()) {
|
||||
options = options.setSsl(true)
|
||||
.setKeyCertOptions(new PemKeyCertOptions()
|
||||
.setKeyPath(config.getSslKey())
|
||||
.setCertPath(config.getSslCert()));
|
||||
}
|
||||
|
||||
httpServer = vertx.createHttpServer(options).webSocketHandler(wsClient -> {
|
||||
log.info("webSocket client connect sessionId:{},path={}", wsClient.textHandlerID(), wsClient.path());
|
||||
String deviceKey = wsClient.path().replace("/","");
|
||||
String[] strArr=deviceKey.split("_");
|
||||
if(StringUtils.isBlank(deviceKey)||strArr.length!=2){
|
||||
log.warn("陌生连接,拒绝");
|
||||
wsClient.reject();
|
||||
return;
|
||||
}
|
||||
wsClient.writeTextMessage("connect succes! please auth!");
|
||||
wsClient.textMessageHandler(message -> {
|
||||
HashMap<String,String> msg;
|
||||
try{
|
||||
msg=JsonUtils.parseObject(message,HashMap.class);
|
||||
}catch (Exception e){
|
||||
log.warn("数据格式异常");
|
||||
wsClient.writeTextMessage("data err");
|
||||
return;
|
||||
}
|
||||
if(wsClients.containsKey(deviceKey)){
|
||||
if("ping".equals(msg.get("type"))){
|
||||
msg.put("type","pong");
|
||||
wsClient.writeTextMessage(JsonUtils.toJsonString(msg));
|
||||
return;
|
||||
}
|
||||
if("register".equals(msg.get("type"))){
|
||||
//设备注册
|
||||
ActionResult result = thingService.post(
|
||||
pluginInfo.getPluginId(),
|
||||
DeviceRegister.builder()
|
||||
.productKey(strArr[1])
|
||||
.deviceName(deviceKey)
|
||||
.model("")
|
||||
.version("1.0")
|
||||
.build()
|
||||
);
|
||||
if(result.getCode()==0){
|
||||
thingService.post(
|
||||
pluginInfo.getPluginId(),
|
||||
DeviceStateChange.builder()
|
||||
.productKey(strArr[1])
|
||||
.deviceName(deviceKey)
|
||||
.state(DeviceState.ONLINE)
|
||||
.build()
|
||||
);
|
||||
}else{
|
||||
//注册失败
|
||||
Map<String,String> ret=new HashMap<>();
|
||||
ret.put("id",msg.get("id"));
|
||||
ret.put("type",msg.get("type"));
|
||||
ret.put("result","fail");
|
||||
wsClient.writeTextMessage(JsonUtils.toJsonString(ret));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}else if(msg!=null&&"auth".equals(msg.get("type"))){
|
||||
Set<String> tokenKey=tokens.keySet();
|
||||
for(String key:tokenKey){
|
||||
if(StringUtils.isNotBlank(msg.get(key))&&tokens.get(key).equals(msg.get(key))){
|
||||
//保存设备与连接关系
|
||||
log.info("认证通过");
|
||||
wsClients.put(deviceKey, wsClient);
|
||||
wsClient.writeTextMessage("auth succes");
|
||||
return;
|
||||
}
|
||||
}
|
||||
log.warn("认证失败,拒绝");
|
||||
wsClient.writeTextMessage("auth fail");
|
||||
return;
|
||||
}else{
|
||||
log.warn("认证失败,拒绝");
|
||||
wsClient.writeTextMessage("auth fail");
|
||||
return;
|
||||
}
|
||||
|
||||
});
|
||||
wsClient.closeHandler(c -> {
|
||||
log.warn("client connection closed,deviceKey:{}", deviceKey);
|
||||
if(wsClients.containsKey(deviceKey)){
|
||||
wsClients.remove(deviceKey);
|
||||
thingService.post(
|
||||
pluginInfo.getPluginId(),
|
||||
DeviceStateChange.builder()
|
||||
.productKey(strArr[1])
|
||||
.deviceName(deviceKey)
|
||||
.state(DeviceState.OFFLINE)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
});
|
||||
wsClient.exceptionHandler(ex -> {
|
||||
log.warn("webSocket client connection exception,deviceKey:{}", deviceKey);
|
||||
if(wsClients.containsKey(deviceKey)){
|
||||
wsClients.remove(deviceKey);
|
||||
thingService.post(
|
||||
pluginInfo.getPluginId(),
|
||||
DeviceStateChange.builder()
|
||||
.productKey(strArr[1])
|
||||
.deviceName(deviceKey)
|
||||
.state(DeviceState.OFFLINE)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
});
|
||||
}).listen(config.getPort(), server -> {
|
||||
if (server.succeeded()) {
|
||||
log.info("webSocket server is listening on port " + config.getPort());
|
||||
if(config.getAccessTokens()!=null){
|
||||
List<WebsocketConfig.AccessToken> tokenConfig= config.getAccessTokens();
|
||||
for (WebsocketConfig.AccessToken obj:tokenConfig) {
|
||||
tokens.put(obj.getTokenName(),obj.getTokenStr());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.error("webSocket server on starting the server", server.cause());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
for (String deviceKey : wsClients.keySet()) {
|
||||
thingService.post(
|
||||
pluginInfo.getPluginId(),
|
||||
DeviceStateChange.builder()
|
||||
.productKey(deviceKey.split("_")[1])
|
||||
.deviceName(deviceKey)
|
||||
.state(DeviceState.OFFLINE)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
tokens.clear();
|
||||
httpServer.close(voidAsyncResult -> log.info("close webocket server..."));
|
||||
}
|
||||
|
||||
private String getDeviceKey(String productKey, String deviceName) {
|
||||
return String.format("%s_%s", productKey, deviceName);
|
||||
}
|
||||
|
||||
public void send(String deviceName,String msg) {
|
||||
ServerWebSocket wsClient = wsClients.get(deviceName);
|
||||
String msgStr = JsonUtils.toJsonString(msg);
|
||||
log.info("send msg payload:{}", msgStr);
|
||||
Future<Void> result = wsClient.writeTextMessage(msgStr);
|
||||
result.onFailure(e -> log.error("webSocket server send msg failed", e));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
plugin:
|
||||
runMode: prod
|
||||
mainPackage: cc.iotkit.plugin
|
||||
|
||||
websocket:
|
||||
port: 1662
|
||||
accessTokens: [{"tokenName":"test_token","tokenStr":"123456789"}]
|
|
@ -0,0 +1,16 @@
|
|||
[
|
||||
{
|
||||
"id": "port",
|
||||
"name": "端口",
|
||||
"type": "number",
|
||||
"value": 1662,
|
||||
"desc": "websocket端口,默认为1662"
|
||||
},
|
||||
{
|
||||
"id": "accessTokens",
|
||||
"name": "token表",
|
||||
"type": "json",
|
||||
"value": "[{'tokenName':'test_token','tokenStr':'123456789'}]",
|
||||
"desc": "token表,可多个"
|
||||
}
|
||||
]
|
Loading…
Reference in New Issue