diff --git a/iot-components/iot-component-converter/src/main/java/cc/iotkit/converter/DefaultScriptConvertFactory.java b/iot-components/iot-component-converter/src/main/java/cc/iotkit/converter/DefaultScriptConvertFactory.java new file mode 100644 index 00000000..8260b808 --- /dev/null +++ b/iot-components/iot-component-converter/src/main/java/cc/iotkit/converter/DefaultScriptConvertFactory.java @@ -0,0 +1,20 @@ +package cc.iotkit.converter; + +import org.apache.commons.lang3.StringUtils; + +public class DefaultScriptConvertFactory implements IScriptConvertFactory{ + + @Override + public IConverter getCovert(String name) { + if(StringUtils.isNotBlank(name)){ + if (name.endsWith("graaljs")){ + return new GraalJsScriptConverter(); + } + } + + // 默认是NashornScript js实现方式 + return new ScriptConverter(); + } + + +} diff --git a/iot-components/iot-component-converter/src/main/java/cc/iotkit/converter/ScriptConvertFactory.java b/iot-components/iot-component-converter/src/main/java/cc/iotkit/converter/ScriptConvertFactory.java deleted file mode 100644 index 491fbe1e..00000000 --- a/iot-components/iot-component-converter/src/main/java/cc/iotkit/converter/ScriptConvertFactory.java +++ /dev/null @@ -1,16 +0,0 @@ -package cc.iotkit.converter; - -public class ScriptConvertFactory implements IScriptConvertFactory{ - - @Override - public IConverter getCovert(String name) { - if (name.endsWith("graaljs")){ - return new GraalJsScriptConverter(); - } - - // 默认是NashornScript js实现方式 - return new ScriptConverter(); - } - - -} diff --git a/iot-components/iot-component-server/src/main/java/cc/iotkit/comps/DeviceComponentManager.java b/iot-components/iot-component-server/src/main/java/cc/iotkit/comps/DeviceComponentManager.java index 618e71b5..24fb51a5 100755 --- a/iot-components/iot-component-server/src/main/java/cc/iotkit/comps/DeviceComponentManager.java +++ b/iot-components/iot-component-server/src/main/java/cc/iotkit/comps/DeviceComponentManager.java @@ -25,6 +25,9 @@ import cc.iotkit.data.IDeviceInfoData; import cc.iotkit.data.IProductData; import cc.iotkit.data.IProtocolComponentData; import cc.iotkit.data.IProtocolConverterData; +import cc.iotkit.engine.IScriptEngine; +import cc.iotkit.engine.IScriptEngineFactory; +import cc.iotkit.engine.JsNashornScriptEngine; import cc.iotkit.model.device.DeviceInfo; import cc.iotkit.model.device.message.ThingModelMessage; import cc.iotkit.model.product.Product; @@ -75,8 +78,14 @@ public class DeviceComponentManager { private final IScriptConvertFactory scriptConverterFactory; - public DeviceComponentManager(IScriptConvertFactory scriptConverterFactory) { + private final IScriptEngineFactory scriptEngineFactory; + + private IScriptEngine scriptEngine; + + public DeviceComponentManager(IScriptConvertFactory scriptConverterFactory, + IScriptEngineFactory scriptEngineFactory ) { this.scriptConverterFactory = scriptConverterFactory; + this.scriptEngineFactory = scriptEngineFactory; } @PostConstruct @@ -112,10 +121,11 @@ public class DeviceComponentManager { try { setScriptConvert(component, componentInstance); + scriptEngine = scriptEngineFactory.getScriptEngine(component.getScriptTyp()); + String componentScript = FileUtils.readFileToString(path. resolve(ProtocolComponent.SCRIPT_FILE_NAME).toFile(), "UTF-8"); componentInstance.setScript(componentScript); - register(id, componentInstance); } catch (IOException e) { throw new BizException("get device component script error", e); @@ -126,12 +136,12 @@ public class DeviceComponentManager { ProtocolConverter protocolConvert = protocolConverterData.findById(component.getConverter()); IConverter scriptConverter = scriptConverterFactory.getCovert(protocolConvert.getTyp()); - + // 从文件方式内容 Path converterPath = componentConfig.getConverterFilePath(component.getConverter()); String converterScript = FileUtils.readFileToString(converterPath. resolve(ProtocolConverter.SCRIPT_FILE_NAME).toFile(), "UTF-8"); -// scriptConverter.setScript(protocolConvert.getScript()); +// scriptConverter.setScript(protocolConvert.getScript()); // 从数据库加载,以后可以加版本号 scriptConverter.setScript(converterScript); scriptConverter.putScriptEnv("component", componentInstance); componentInstance.setConverter(scriptConverter); @@ -157,8 +167,12 @@ public class DeviceComponentManager { if (component == null) { return; } + + + DeviceMessageHandler messageHandler = new DeviceMessageHandler( this, component, + scriptEngine, component.getScript(), component.getConverter(), deviceBehaviourService, deviceRouter); messageHandler.putScriptEnv("apiTool", new ApiTool()); diff --git a/iot-components/iot-component-server/src/main/java/cc/iotkit/comps/DeviceMessageHandler.java b/iot-components/iot-component-server/src/main/java/cc/iotkit/comps/DeviceMessageHandler.java index c4eed2ed..bc1402f7 100755 --- a/iot-components/iot-component-server/src/main/java/cc/iotkit/comps/DeviceMessageHandler.java +++ b/iot-components/iot-component-server/src/main/java/cc/iotkit/comps/DeviceMessageHandler.java @@ -60,6 +60,7 @@ public class DeviceMessageHandler implements IMessageHandler { @SneakyThrows public DeviceMessageHandler(DeviceComponentManager deviceComponentManager, IDeviceComponent component, + IScriptEngine scriptEngine, String script, IConverter converter, DeviceBehaviourService deviceBehaviourService, DeviceRouter deviceRouter @@ -69,7 +70,7 @@ public class DeviceMessageHandler implements IMessageHandler { this.converter = converter; this.deviceBehaviourService = deviceBehaviourService; this.deviceRouter = deviceRouter; - this.scriptEngine = new JsNashornScriptEngine(); + this.scriptEngine = scriptEngine; scriptEngine.putScriptEnv("component", component); scriptEngine.setScript(script); } diff --git a/iot-components/iot-component-server/src/main/java/cc/iotkit/comps/config/ComponentConfig.java b/iot-components/iot-component-server/src/main/java/cc/iotkit/comps/config/ComponentConfig.java index b67fbcf3..60da6e1a 100755 --- a/iot-components/iot-component-server/src/main/java/cc/iotkit/comps/config/ComponentConfig.java +++ b/iot-components/iot-component-server/src/main/java/cc/iotkit/comps/config/ComponentConfig.java @@ -1,9 +1,9 @@ package cc.iotkit.comps.config; -import cc.iotkit.converter.GraalJsScriptConverter; -import cc.iotkit.converter.IConverter; import cc.iotkit.converter.IScriptConvertFactory; -import cc.iotkit.converter.ScriptConvertFactory; +import cc.iotkit.converter.DefaultScriptConvertFactory; +import cc.iotkit.engine.DefaultScriptEngineFactory; +import cc.iotkit.engine.IScriptEngineFactory; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import lombok.Data; @@ -42,7 +42,11 @@ public class ComponentConfig { @Bean public IScriptConvertFactory scriptConverterFactory(){ - return new ScriptConvertFactory(); + return new DefaultScriptConvertFactory(); } + @Bean + public IScriptEngineFactory scriptEngineFactory(){ + return new DefaultScriptEngineFactory(); + } } diff --git a/iot-components/iot-components-engine/pom.xml b/iot-components/iot-components-engine/pom.xml index 11040c40..605ae0c9 100644 --- a/iot-components/iot-components-engine/pom.xml +++ b/iot-components/iot-components-engine/pom.xml @@ -33,6 +33,10 @@ js-scriptengine + + org.apache.commons + commons-lang3 + \ No newline at end of file diff --git a/iot-components/iot-components-engine/src/main/java/cc/iotkit/engine/DefaultScriptEngineFactory.java b/iot-components/iot-components-engine/src/main/java/cc/iotkit/engine/DefaultScriptEngineFactory.java new file mode 100644 index 00000000..270c09bf --- /dev/null +++ b/iot-components/iot-components-engine/src/main/java/cc/iotkit/engine/DefaultScriptEngineFactory.java @@ -0,0 +1,17 @@ +package cc.iotkit.engine; + +import org.apache.commons.lang3.StringUtils; + +public class DefaultScriptEngineFactory implements IScriptEngineFactory{ + @Override + public IScriptEngine getScriptEngine(String name) { + if(StringUtils.isNotBlank(name)){ + if (name.endsWith("graaljs")){ + return new JsGraalJsScriptEngine(); + } + } + + // 默认是NashornScript js实现方式 + return new JsNashornScriptEngine(); + } +} diff --git a/iot-components/iot-components-engine/src/main/java/cc/iotkit/engine/IScriptEngineFactory.java b/iot-components/iot-components-engine/src/main/java/cc/iotkit/engine/IScriptEngineFactory.java new file mode 100644 index 00000000..e16f3daf --- /dev/null +++ b/iot-components/iot-components-engine/src/main/java/cc/iotkit/engine/IScriptEngineFactory.java @@ -0,0 +1,6 @@ +package cc.iotkit.engine; + +public interface IScriptEngineFactory { + + IScriptEngine getScriptEngine(String name); +} diff --git a/iot-components/iot-mqtt-component/src/main/resources/graaljs-converter.js b/iot-components/iot-mqtt-component/src/main/resources/graaljs-converter.js new file mode 100644 index 00000000..ec816c8f --- /dev/null +++ b/iot-components/iot-mqtt-component/src/main/resources/graaljs-converter.js @@ -0,0 +1,178 @@ + +var mid=1; + +function getMid(){ + mid++; + if(mid>10000){ + mid=1; + } + return mid+""; +} + +this.decode = function (msg) { + + //对msg进行解析,并返回物模型数据 + console.log("msg", msg); + var content= msg.getContent(); + console.log("content",content); + var topic = content.topic; + console.log("topic",topic); + var payload = content.get("payload"); + console.log("payload",payload); + var identifier = topic.substring(topic.lastIndexOf("/") + 1); + + //透传上报 + if(topic.endsWith("/event/rawReport")){ + var rst= component.transparentDecode(payload.params); + if(!rst){ + return null; + } + rst.occured=new Date().getTime(); + rst.time=new Date().getTime(); + return rst; + } + + if (topic.endsWith("/property/post")) { + //属性上报 + return { + "mid": msg.getMid(), + "productKey": msg.getProductKey(), + "deviceName": msg.getDeviceName(), + "type":"property", + "identifier": "report", //属性上报 + "occured": new Date().getTime(), //时间戳,设备上的事件或数据产生的本地时间 + "time": new Date().getTime(), //时间戳,消息上报时间 + data: payload, + }; + } else if (topic.indexOf("/event/") > 0) { + //事件上报 + return { + mid: msg.getMid(), + productKey: msg.getProductKey(), + deviceName: msg.getDeviceName(), + type:"event", + identifier: identifier, + occured: new Date().getTime(), + time: new Date().getTime(), + data: payload.params, + }; + }else if(topic.endsWith("/service/property/set_reply")){ + //属性设置回复 + return { + mid: msg.getMid(), + productKey: msg.getProductKey(), + deviceName: msg.getDeviceName(), + type:"property", + identifier: identifier, + occured: new Date().getTime(), + time: new Date().getTime(), + code: payload.code + }; + }else if(topic.endsWith("/config/set_reply")){ + //设备配置设置回复 + return { + mid: msg.getMid(), + productKey: msg.getProductKey(), + deviceName: msg.getDeviceName(), + type:"config", + identifier: "set_reply", + occured: new Date().getTime(), + time: new Date().getTime(), + code: payload.code + }; + }else if(topic.endsWith("/config/get")){ + //设备配置获取 + return { + mid: msg.getMid(), + productKey: msg.getProductKey(), + deviceName: msg.getDeviceName(), + type:"config", + identifier: "get", + occured: new Date().getTime(), + time: new Date().getTime(), + data: {}, + }; + } else if (topic.endsWith("_reply")) { + //服务回复 + return { + mid: msg.getMid(), + productKey: msg.getProductKey(), + deviceName: msg.getDeviceName(), + type:"service", + identifier: identifier, + occured: new Date().getTime(), + time: new Date().getTime(), + code: payload.code, + data: payload.data, + }; + } + return null; +}; + +this.encode = function (service,device) { + var deviceMid=getMid(); + var method="thing.service."; + var topic="/sys/"+service.getProductKey()+"/"+service.getDeviceName()+"/c/service/"; + var params={}; + + //透传下发 + if(device.isTransparent()){ + var rst=component.transparentEncode(service,device); + topic="/sys/"+rst.productKey+"/"+rst.deviceName+"/c/service/rawSend"; + params.model=rst.content.model; + params.deviceName=rst.content.deviceName; + params.data=rst.content.data; + + return { + productKey:rst.productKey, + deviceName:rst.deviceName, + mid:rst.mid, + content:{ + topic:topic, + payload:JSON.stringify({ + id:rst.mid, + method:method+"rawSend", + params:params + }) + } + } + + } + + var type=service.getType(); + var identifier=service.getIdentifier(); + + if(type=="property"){ + method+="property."+identifier; + topic+="property/"+identifier; + }else if(type=="service"){ + method+=identifier; + topic+=identifier; + }else if(type=="config"){ + //设备配置下发 + method+=identifier; + topic="/sys/"+service.getProductKey()+"/"+service.getDeviceName()+"/c/config/"+identifier; + }else if(type="lifetime"){ + //子设备注销下发 + method+=identifier; + topic="/sys/"+service.getProductKey()+"/"+service.getDeviceName()+"/c/deregister"; + } + + for(var p in service.getParams()){ + params[p]=service.getParams()[p]; + } + + return { + productKey:service.getProductKey(), + deviceName:service.getDeviceName(), + mid:deviceMid, + content:{ + topic:topic, + payload:JSON.stringify({ + id:deviceMid, + method:method, + params:params + }) + } + } +}; \ No newline at end of file diff --git a/iot-data/iot-model/src/main/java/cc/iotkit/model/protocol/ProtocolComponent.java b/iot-data/iot-model/src/main/java/cc/iotkit/model/protocol/ProtocolComponent.java index bc5cefe0..9c8d5498 100755 --- a/iot-data/iot-model/src/main/java/cc/iotkit/model/protocol/ProtocolComponent.java +++ b/iot-data/iot-model/src/main/java/cc/iotkit/model/protocol/ProtocolComponent.java @@ -45,4 +45,8 @@ public class ProtocolComponent implements Owned { private Long createAt; + private String scriptTyp; + + private String script; + } diff --git a/iot-data/iot-rdb-data-service/src/main/java/cc/iotkit/data/model/TbProtocolComponent.java b/iot-data/iot-rdb-data-service/src/main/java/cc/iotkit/data/model/TbProtocolComponent.java index 7f1684bd..fc2437a9 100755 --- a/iot-data/iot-rdb-data-service/src/main/java/cc/iotkit/data/model/TbProtocolComponent.java +++ b/iot-data/iot-rdb-data-service/src/main/java/cc/iotkit/data/model/TbProtocolComponent.java @@ -36,4 +36,10 @@ public class TbProtocolComponent { private String state; private Long createAt; + + private String scriptTyp; + + @Column(columnDefinition = "text")//设置映射为text类型 + private String script; + } diff --git a/iot-data/iot-rdb-data-service/src/main/java/cc/iotkit/data/model/TbProtocolConverter.java b/iot-data/iot-rdb-data-service/src/main/java/cc/iotkit/data/model/TbProtocolConverter.java index 27f4ad3e..b7350138 100755 --- a/iot-data/iot-rdb-data-service/src/main/java/cc/iotkit/data/model/TbProtocolConverter.java +++ b/iot-data/iot-rdb-data-service/src/main/java/cc/iotkit/data/model/TbProtocolConverter.java @@ -40,6 +40,7 @@ public class TbProtocolConverter { private String typ; // 脚本内容 + @Column(columnDefinition = "text")//设置映射为text类型 private String script; } diff --git a/iot-standalone/src/main/java/cc/iotkit/manager/controller/ProtocolController.java b/iot-standalone/src/main/java/cc/iotkit/manager/controller/ProtocolController.java index 0e09f898..a5202102 100755 --- a/iot-standalone/src/main/java/cc/iotkit/manager/controller/ProtocolController.java +++ b/iot-standalone/src/main/java/cc/iotkit/manager/controller/ProtocolController.java @@ -131,26 +131,41 @@ public class ProtocolController { } @GetMapping("/getComponentScript/{id}") - public String getComponentScript(@PathVariable("id") String id) { - getAndCheckComponent(id); - try { - File file = getComponentScriptFile(id); - return FileUtils.readFileToString(file, "UTF-8"); - } catch (Throwable e) { - log.error("read component script file error", e); - return ""; + public ProtocolComponent getComponentScript(@PathVariable("id") String id) { + ProtocolComponent component = getAndCheckComponent(id); + + String script = component.getScript(); + // 如果数据库里不存在,则从文件中读取脚本 + if(!StringUtils.hasText(script)){ + try { + File file = getComponentScriptFile(id); + script = FileUtils.readFileToString(file, "UTF-8"); + } catch (Throwable e) { + log.error("read converter script file error", e); + script = ""; + } + component.setScript(script); } + return component; + } @PostMapping("/saveComponentScript/{id}") public void saveComponentScript( @PathVariable("id") String id, - @RequestBody String script) { - getAndCheckComponent(id); + @RequestBody ProtocolComponent upReq) { + ProtocolComponent old = getAndCheckComponent(id); try { + // 保存到文件 File file = getComponentScriptFile(id); - script = JsonUtil.parse(script, String.class); + String script = upReq.getScript(); FileUtils.writeStringToFile(file, script, "UTF-8", false); + + // 保存到数据库,后续加版本号 + old.setScript(upReq.getScript()); + old.setScriptTyp(upReq.getScriptTyp()); + protocolComponentData.save(old); + componentManager.deRegister(id); } catch (Throwable e) { throw new BizException("save protocol component script error", e); @@ -252,7 +267,7 @@ public class ProtocolController { ProtocolConverter converter = getAndCheckConverter(id); String script = converter.getScript(); // 如果数据库里不存在,则从文件中读取脚本 - if(StringUtils.hasText(script)){ + if(!StringUtils.hasText(script)){ try { Path path = componentConfig.getConverterFilePath(id); File file = path.resolve(ProtocolConverter.SCRIPT_FILE_NAME).toFile();