通讯组件修改

V0.5.x
xiwa 2022-04-01 07:32:56 +08:00
parent a0d7d73a74
commit 983e857275
11 changed files with 186 additions and 102 deletions

View File

@ -4,6 +4,11 @@ import cc.iotkit.model.protocol.ProtocolComponent;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface ProtocolComponentRepository extends MongoRepository<ProtocolComponent, String> {
List<ProtocolComponent> findByState(String state);
}

View File

View File

@ -6,6 +6,7 @@ import cc.iotkit.common.utils.ReflectUtil;
import cc.iotkit.comp.CompConfig;
import cc.iotkit.comp.mqtt.MqttComponent;
import cc.iotkit.comps.ComponentManager;
import cc.iotkit.comps.config.ComponentConfig;
import cc.iotkit.converter.ScriptConverter;
import cc.iotkit.dao.ProtocolComponentRepository;
import cc.iotkit.dao.ProtocolConverterRepository;
@ -37,11 +38,8 @@ import java.util.UUID;
@RequestMapping("/protocol")
public class ProtocolController {
@Value("${component.dir:./data/components}")
private String componentDir;
@Value("${converter.dir:./data/converters}")
private String converterDir;
@Autowired
private ComponentConfig componentConfig;
@Autowired
private ProtocolComponentRepository protocolComponentRepository;
@ -58,16 +56,6 @@ public class ProtocolController {
@Autowired
private ComponentManager componentManager;
private Path getComponentFilePath(String comId) {
return Paths.get(String.format("%s/%s", componentDir, comId))
.toAbsolutePath().normalize();
}
private Path getConverterFilePath(String conId) {
return Paths.get(String.format("%s/%s", converterDir, conId))
.toAbsolutePath().normalize();
}
@PostMapping("/uploadJar")
public String uploadJar(@RequestParam("file") MultipartFile file, String id) {
if (file == null) {
@ -77,15 +65,11 @@ public class ProtocolController {
String fileName = StringUtils.cleanPath(file.getOriginalFilename());
try {
if (StringUtils.hasLength(id)) {
Optional<ProtocolComponent> optComponent = protocolComponentRepository.findById(id);
if (!optComponent.isPresent()) {
throw new BizException("the protocol component does not exists");
}
dataOwnerService.checkOwner(optComponent.get());
getAndCheckComponent(id);
} else {
id = UUID.randomUUID().toString();
}
Path jarFilePath = getComponentFilePath(id);
Path jarFilePath = componentConfig.getComponentFilePath(id);
Files.createDirectories(jarFilePath);
Path targetLocation = jarFilePath.resolve(fileName);
Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);
@ -101,7 +85,7 @@ public class ProtocolController {
if (!StringUtils.hasLength(id)) {
throw new BizException("component id is blank");
}
Path jarPath = getComponentFilePath(id);
Path jarPath = componentConfig.getComponentFilePath(id);
if (!jarPath.resolve(component.getJarFile()).toFile().exists()) {
throw new BizException("component jar file does not exist");
}
@ -125,20 +109,15 @@ public class ProtocolController {
if (!StringUtils.hasLength(id)) {
throw new BizException("component id is blank");
}
Path jarPath = getComponentFilePath(id);
Path jarPath = componentConfig.getComponentFilePath(id);
if (!jarPath.resolve(component.getJarFile()).toFile().exists()) {
throw new BizException("component jar file does not exist");
}
Optional<ProtocolComponent> optComponent = protocolComponentRepository.findById(component.getId());
if (!optComponent.isPresent()) {
throw new BizException("the protocol component does not exists");
}
ProtocolComponent oldComponent = optComponent.get();
ProtocolComponent oldComponent = getAndCheckComponent(id);
component = ReflectUtil.copyNoNulls(component, oldComponent);
dataOwnerService.checkOwner(component);
try {
componentManager.deRegister(id);
protocolComponentRepository.save(component);
} catch (Throwable e) {
throw new BizException("add protocol component error", e);
@ -147,14 +126,9 @@ public class ProtocolController {
@GetMapping("/getComponentScript/{id}")
public String getComponentScript(@PathVariable("id") String id) {
Optional<ProtocolComponent> optComponent = protocolComponentRepository.findById(id);
if (!optComponent.isPresent()) {
throw new BizException("the component does not exists");
}
ProtocolComponent component = optComponent.get();
dataOwnerService.checkOwner(component);
getAndCheckComponent(id);
try {
Path path = getComponentFilePath(id);
Path path = componentConfig.getComponentFilePath(id);
File file = path.resolve(ProtocolComponent.SCRIPT_FILE_NAME).toFile();
return FileUtils.readFileToString(file, "UTF-8");
} catch (Throwable e) {
@ -167,28 +141,37 @@ public class ProtocolController {
public void saveComponentScript(
@PathVariable("id") String id,
@RequestBody String script) {
Optional<ProtocolComponent> optComponent = protocolComponentRepository.findById(id);
if (!optComponent.isPresent()) {
throw new BizException("the component does not exists");
}
ProtocolComponent oldComponent = optComponent.get();
dataOwnerService.checkOwner(oldComponent);
ProtocolComponent oldComponent = getAndCheckComponent(id);
try {
Path path = getComponentFilePath(id);
Path path = componentConfig.getComponentFilePath(id);
File file = path.resolve(ProtocolComponent.SCRIPT_FILE_NAME).toFile();
script = JsonUtil.parse(script, String.class);
FileUtils.writeStringToFile(file, script, "UTF-8", false);
componentManager.deRegister(id);
protocolComponentRepository.save(oldComponent);
} catch (Throwable e) {
throw new BizException("save protocol component script error", e);
}
}
private ProtocolComponent getAndCheckComponent(@PathVariable("id") String id) {
Optional<ProtocolComponent> optComponent = protocolComponentRepository.findById(id);
if (!optComponent.isPresent()) {
throw new BizException("the component does not exists");
}
ProtocolComponent oldComponent = optComponent.get();
dataOwnerService.checkOwner(oldComponent);
return oldComponent;
}
@PostMapping("/deleteComponent/{id}")
public void deleteComponent(@PathVariable("id") String id) {
dataOwnerService.checkOwner(protocolComponentRepository, id);
ProtocolComponent component = getAndCheckComponent(id);
try {
Path path = Paths.get(String.format("%s/%s", componentDir, id))
componentManager.deRegister(id);
Path path = Paths.get(String.format("%s/%s", componentConfig.getComponentDir(), id))
.toAbsolutePath().normalize();
File file = path.toFile();
try {
@ -200,7 +183,7 @@ public class ProtocolController {
} catch (NoSuchFileException e) {
log.warn("delete component script error", e);
}
protocolComponentRepository.deleteById(id);
protocolComponentRepository.deleteById(component.getId());
} catch (Throwable e) {
throw new BizException("delete protocol component error", e);
}
@ -212,6 +195,8 @@ public class ProtocolController {
@PathVariable("page") int page) {
Page<ProtocolComponent> components = protocolComponentRepository.findAll(
PageRequest.of(page - 1, size, Sort.by(Sort.Order.desc("createAt"))));
components.getContent().forEach(c -> c.setState(componentManager.isRunning(c.getId()) ?
ProtocolComponent.STATE_RUNNING : ProtocolComponent.STATE_STOPPED));
return new Paging<>(components.getTotalElements(), components.getContent());
}
@ -240,14 +225,8 @@ public class ProtocolController {
@PostMapping("/saveConverter")
public void saveConverter(ProtocolConverter converter) {
Optional<ProtocolConverter> optConverter = protocolConverterRepository.findById(converter.getId());
if (!optConverter.isPresent()) {
throw new BizException("the protocol converter does not exists");
}
ProtocolConverter oldConverter = optConverter.get();
ProtocolConverter oldConverter = getAndCheckConverter(converter.getId());
converter = ReflectUtil.copyNoNulls(converter, oldConverter);
dataOwnerService.checkOwner(converter);
try {
protocolConverterRepository.save(converter);
} catch (Throwable e) {
@ -255,16 +234,22 @@ public class ProtocolController {
}
}
@GetMapping("/getConverterScript/{id}")
public String getConverterScript(@PathVariable("id") String id) {
private ProtocolConverter getAndCheckConverter(String id) {
Optional<ProtocolConverter> optConverter = protocolConverterRepository.findById(id);
if (!optConverter.isPresent()) {
throw new BizException("the converter does not exists");
throw new BizException("the protocol converter does not exists");
}
ProtocolConverter converter = optConverter.get();
dataOwnerService.checkOwner(converter);
return converter;
}
@GetMapping("/getConverterScript/{id}")
public String getConverterScript(@PathVariable("id") String id) {
getAndCheckConverter(id);
try {
Path path = getConverterFilePath(id);
Path path = componentConfig.getConverterFilePath(id);
File file = path.resolve(ProtocolConverter.SCRIPT_FILE_NAME).toFile();
return FileUtils.readFileToString(file, "UTF-8");
} catch (Throwable e) {
@ -277,14 +262,9 @@ public class ProtocolController {
public void saveConverterScript(
@PathVariable("id") String id,
@RequestBody String script) {
Optional<ProtocolConverter> optConverter = protocolConverterRepository.findById(id);
if (!optConverter.isPresent()) {
throw new BizException("the converter does not exists");
}
ProtocolConverter oldConverter = optConverter.get();
dataOwnerService.checkOwner(oldConverter);
getAndCheckConverter(id);
try {
Path path = getConverterFilePath(id);
Path path = componentConfig.getConverterFilePath(id);
File file = path.resolve(ProtocolConverter.SCRIPT_FILE_NAME).toFile();
script = JsonUtil.parse(script, String.class);
FileUtils.writeStringToFile(file, script, "UTF-8", false);
@ -295,9 +275,9 @@ public class ProtocolController {
@PostMapping("/deleteConverter/{id}")
public void deleteConverter(@PathVariable("id") String id) {
dataOwnerService.checkOwner(protocolConverterRepository, id);
getAndCheckConverter(id);
try {
Path path = Paths.get(String.format("%s/%s", componentDir, id))
Path path = Paths.get(String.format("%s/%s", componentConfig.getConverterDir(), id))
.toAbsolutePath().normalize();
File file = path.toFile();
try {
@ -315,28 +295,21 @@ public class ProtocolController {
}
}
@PostMapping("/component/{id}/{state}")
public void startComponent(@PathVariable("id") String id,
@PathVariable("state") String state) {
}
@GetMapping("/registerMqtt")
public void registerMqtt() throws IOException {
MqttComponent component = new MqttComponent();
component.create(new CompConfig(300, "{\"port\":2883,\"ssl\":false}"));
ScriptConverter converter = new ScriptConverter();
converter.setScript(FileUtils.readFileToString(new File("/Users/sjg/home/gitee/open-source/converter.js"), "UTF-8"));
component.setConverter(converter);
componentManager.register("123", component);
componentManager.start("123", FileUtils.readFileToString(new File("/Users/sjg/home/gitee/open-source/component.js"), "UTF-8"));
}
@GetMapping("/deregisterMqtt")
public void deregisterMqtt() {
componentManager.stop("123");
componentManager.deRegister("123");
@PostMapping("/component/{id}/state/{state}")
public void changeComponentState(@PathVariable("id") String id,
@PathVariable("state") String state) {
ProtocolComponent component = getAndCheckComponent(id);
String converterId = component.getConverter();
getAndCheckConverter(converterId);
if (ProtocolComponent.STATE_RUNNING.equals(state)) {
componentManager.register(component);
componentManager.start(component.getId());
component.setState(ProtocolComponent.STATE_RUNNING);
} else {
componentManager.deRegister(id);
component.setState(ProtocolComponent.STATE_STOPPED);
}
protocolComponentRepository.save(component);
}
}

View File

View File

@ -16,12 +16,12 @@ import java.nio.charset.Charset;
@Slf4j
public class ComponentClassLoader {
protected Class<IComponent> findClass(String name) throws ClassNotFoundException {
protected static Class<IComponent> findClass(String name) throws ClassNotFoundException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
return (Class<IComponent>) classLoader.loadClass(name);
}
private String addUrl(File jarPath) throws NoSuchMethodException, InvocationTargetException,
private static String addUrl(File jarPath) throws NoSuchMethodException, InvocationTargetException,
IllegalAccessException, IOException {
URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
@ -35,9 +35,9 @@ public class ComponentClassLoader {
return StreamUtils.copyToString(is, Charset.forName("UTF-8"));
}
public IComponent getComponent(File jarPath) {
public static IComponent getComponent(File jarFile) {
try {
String className = addUrl(jarPath);
String className = addUrl(jarFile);
Class<IComponent> componentClass = findClass(className);
return componentClass.newInstance();
} catch (Throwable e) {

View File

@ -3,18 +3,30 @@ package cc.iotkit.comps;
import cc.iotkit.common.exception.BizException;
import cc.iotkit.common.utils.JsonUtil;
import cc.iotkit.comp.CompConfig;
import cc.iotkit.comp.IComponent;
import cc.iotkit.comps.config.CacheKey;
import cc.iotkit.comps.config.ComponentConfig;
import cc.iotkit.comps.service.DeviceBehaviourService;
import cc.iotkit.converter.DeviceMessage;
import cc.iotkit.converter.ScriptConverter;
import cc.iotkit.converter.ThingService;
import cc.iotkit.dao.ProtocolComponentRepository;
import cc.iotkit.model.device.message.ThingModelMessage;
import cc.iotkit.model.protocol.ProtocolComponent;
import cc.iotkit.model.protocol.ProtocolConverter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@ -23,31 +35,84 @@ import java.util.concurrent.TimeUnit;
public class ComponentManager {
private final Map<String, IComponent> components = new HashMap<>();
private final Map<String, String> scripts = new HashMap<>();
private final Map<String, Boolean> states = new HashMap<>();
@Autowired
private DeviceBehaviourService deviceBehaviourService;
@Autowired
private StringRedisTemplate redisTemplate;
@Autowired
private ComponentConfig componentConfig;
@Autowired
private ProtocolComponentRepository componentRepository;
public void register(String id, IComponent component) {
@PostConstruct
public void init() {
List<ProtocolComponent> componentList = componentRepository.findByState(ProtocolComponent.STATE_RUNNING);
for (ProtocolComponent component : componentList) {
register(component);
start(component.getId());
}
}
public void register(ProtocolComponent component) {
String id = component.getId();
if (components.containsKey(id)) {
return;
}
Path path = componentConfig.getComponentFilePath(id);
File file = path.resolve(component.getJarFile()).toAbsolutePath().toFile();
IComponent componentInstance = ComponentClassLoader.getComponent(file);
if (componentInstance == null) {
throw new BizException("instance component failed");
}
componentInstance.create(new CompConfig(300, component.getConfig()));
try {
ScriptConverter scriptConverter = new ScriptConverter();
Path converterPath = componentConfig.getConverterFilePath(component.getConverter());
String converterScript = FileUtils.readFileToString(converterPath.
resolve(ProtocolConverter.SCRIPT_FILE_NAME).toFile(), "UTF-8");
scriptConverter.setScript(converterScript);
componentInstance.setConverter(scriptConverter);
String componentScript = FileUtils.readFileToString(path.
resolve(ProtocolComponent.SCRIPT_FILE_NAME).toFile(), "UTF-8");
register(id, componentInstance, componentScript);
} catch (IOException e) {
throw new BizException("get component script error", e);
}
}
public void register(String id, IComponent component, String script) {
components.put(id, component);
scripts.put(id, script);
states.put(id, false);
}
public void deRegister(String id) {
IComponent component = components.remove(id);
scripts.remove(id);
states.remove(id);
component.stop();
component.destroy();
}
public void start(String id, String script) {
public void start(String id) {
IComponent component = components.get(id);
if (component == null) {
return;
}
String script = scripts.get(id);
component.setHandler(
new MessageHandler(this, component,
script, component.getConverter(),
deviceBehaviourService));
component.start();
states.put(id, true);
}
public void stop(String id) {
@ -56,6 +121,11 @@ public class ComponentManager {
return;
}
component.stop();
states.put(id, false);
}
public boolean isRunning(String id) {
return states.containsKey(id) && states.get(id);
}
public void send(ThingService<?> service) {

View File

@ -48,12 +48,12 @@ public class MessageHandler implements IMessageHandler {
this.component = component;
this.converter = converter;
this.deviceBehaviourService = deviceBehaviourService;
scriptObj = engine.eval(script);
scriptObj = engine.eval(String.format("new (function () {\n%s})()", script));
}
public ReceiveResult onReceive(Map<String, Object> head, String type, String msg) {
try {
ScriptObjectMirror result = (ScriptObjectMirror) engine.invokeMethod(scriptObj, "onReceive", head, type, msg);
ScriptObjectMirror result = (ScriptObjectMirror) invokeMethod("onReceive", head, type, msg);
log.info("onReceive script result:{}", JsonUtil.toJsonString(result));
Object rstType = result.get("type");
if (rstType == null) {
@ -107,10 +107,10 @@ public class MessageHandler implements IMessageHandler {
private void doRegister(RegisterInfo reg) throws ScriptException, NoSuchMethodException {
try {
deviceBehaviourService.register(reg);
engine.invokeMethod(scriptObj, "onRegistered", reg, "true");
} catch (Throwable e) {
log.error("register error", e);
engine.invokeMethod(scriptObj, "onRegistered", reg, "false");
} finally {
invokeMethod("onRegistered", reg, "false");
}
}
@ -120,13 +120,20 @@ public class MessageHandler implements IMessageHandler {
auth.getDeviceName(),
auth.getProductSecret(),
auth.getDeviceSecret());
engine.invokeMethod(scriptObj, "onAuthed", auth, true);
} catch (Throwable e) {
log.error("device auth error", e);
engine.invokeMethod(scriptObj, "onAuthed", auth, false);
} finally {
invokeMethod("onAuthed", auth, "false");
}
}
private Object invokeMethod(String name, Object... args) throws ScriptException, NoSuchMethodException {
if (((ScriptObjectMirror) scriptObj).get(name) != null) {
return engine.invokeMethod(scriptObj, name, args);
}
return null;
}
private void doStateChange(DeviceState state) {
try {
component.onDeviceStateChange(state);

View File

@ -0,0 +1,29 @@
package cc.iotkit.comps.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import java.nio.file.Path;
import java.nio.file.Paths;
@Configuration
@Data
public class ComponentConfig {
@Value("${component.dir:./data/components}")
private String componentDir;
@Value("${converter.dir:./data/converters}")
private String converterDir;
public Path getComponentFilePath(String comId) {
return Paths.get(componentDir, comId)
.toAbsolutePath().normalize();
}
public Path getConverterFilePath(String conId) {
return Paths.get(converterDir, conId)
.toAbsolutePath().normalize();
}
}

View File

@ -21,7 +21,7 @@ public class ScriptConverter implements IConverter {
public void setScript(String script) {
try {
scriptObj = engine.eval(script);
scriptObj = engine.eval(String.format("new (function () {\n%s})()", script));
} catch (ScriptException e) {
log.error("eval converter script error", e);
}

View File

View File