组件脚本-添加脚本类型js,graaljs

V0.5.x
jay 2023-03-02 15:37:51 +08:00
parent 26f8570ea7
commit b84d4789c8
13 changed files with 291 additions and 37 deletions

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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());

View File

@ -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);
}

View File

@ -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();
}
}

View File

@ -33,6 +33,10 @@
<artifactId>js-scriptengine</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -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();
}
}

View File

@ -0,0 +1,6 @@
package cc.iotkit.engine;
public interface IScriptEngineFactory {
IScriptEngine getScriptEngine(String name);
}

View File

@ -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
})
}
}
};

View File

@ -45,4 +45,8 @@ public class ProtocolComponent implements Owned<String> {
private Long createAt;
private String scriptTyp;
private String script;
}

View File

@ -36,4 +36,10 @@ public class TbProtocolComponent {
private String state;
private Long createAt;
private String scriptTyp;
@Column(columnDefinition = "text")//设置映射为text类型
private String script;
}

View File

@ -40,6 +40,7 @@ public class TbProtocolConverter {
private String typ;
// 脚本内容
@Column(columnDefinition = "text")//设置映射为text类型
private String script;
}

View File

@ -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();