组件调整、增加httpbiz组件、删除第三方接入模块

V0.5.x
xiwa 2022-04-22 18:43:42 +08:00
parent 447e481111
commit b9d6054198
55 changed files with 940 additions and 581 deletions

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>iotkit-parent</artifactId>
<groupId>cc.iotkit</groupId>
<version>0.0.1-SNAPSHOT</version>
<version>0.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -23,6 +23,11 @@
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>

View File

@ -1,8 +1,4 @@
package cc.iotkit.comps;
import cc.iotkit.comp.IComponent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StreamUtils;
package cc.iotkit.common;
import java.io.File;
import java.io.IOException;
@ -15,13 +11,14 @@ import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
@Slf4j
import org.apache.commons.io.IOUtils;
public class ComponentClassLoader {
private static final Map<String, URLClassLoader> classLoaders = new HashMap<>();
protected static Class<IComponent> findClass(String name, String clsName) throws ClassNotFoundException {
protected static <T> Class<T> findClass(String name, String clsName) throws ClassNotFoundException {
ClassLoader classLoader = classLoaders.get(name);
return (Class<IComponent>) classLoader.loadClass(clsName);
return (Class<T>) classLoader.loadClass(clsName);
}
private static String addUrl(String name, File jarPath) throws NoSuchMethodException, InvocationTargetException,
@ -42,18 +39,17 @@ public class ComponentClassLoader {
URL url = jarPath.toURI().toURL();
method.invoke(classLoader, url);
InputStream is = classLoader.getResourceAsStream("component.spi");
return StreamUtils.copyToString(is, StandardCharsets.UTF_8);
}
public static IComponent getComponent(String name, File jarFile) {
try {
String className = addUrl(name, jarFile);
Class<IComponent> componentClass = findClass(name, className);
return componentClass.newInstance();
} catch (Throwable e) {
log.error("instance component from jar error", e);
if (is == null) {
return null;
}
return IOUtils.toString(is, StandardCharsets.UTF_8);
}
public static <T> T getComponent(String name, File jarFile) throws Exception {
String className = addUrl(name, jarFile);
Class<T> componentClass = findClass(name, className);
return componentClass.newInstance();
}
}

View File

@ -73,4 +73,34 @@ public interface Constants {
*/
String THING_MODEL_MESSAGE_TOPIC = "device_thing";
interface API {
/**
* -
*/
String DEVICE_BASE = "/device";
/**
* -
*/
String DEVICE_LIST = "/list/{size}/{page}";
/**
* -
*/
String DEVICE_DETAIL = "/{deviceId}/detail";
/**
* -
*/
String DEVICE_SET_PROPERTIES = "/{deviceId}/service/property/set";
/**
* -
*/
String DEVICE_INVOKE_SERVICE = "/{deviceId}/service/{service}/invoke";
}
}

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>iotkit-parent</artifactId>
<groupId>cc.iotkit</groupId>
<version>0.0.1-SNAPSHOT</version>
<version>0.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -11,4 +11,6 @@ public interface ProtocolComponentRepository extends MongoRepository<ProtocolCom
List<ProtocolComponent> findByState(String state);
List<ProtocolComponent> findByStateAndType(String state, String type);
}

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>iotkit-parent</artifactId>
<groupId>cc.iotkit</groupId>
<version>0.0.1-SNAPSHOT</version>
<version>0.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -1,10 +1,12 @@
package cc.iotkit.manager.controller;
import cc.iotkit.common.Constants;
import cc.iotkit.common.exception.BizException;
import cc.iotkit.common.utils.DeviceUtil;
import cc.iotkit.common.utils.UniqueIdUtil;
import cc.iotkit.comps.service.DeviceBehaviourService;
import cc.iotkit.dao.*;
import cc.iotkit.manager.model.query.DeviceQuery;
import cc.iotkit.manager.service.DataOwnerService;
import cc.iotkit.manager.service.DeviceService;
import cc.iotkit.manager.utils.AuthUtil;
@ -52,7 +54,7 @@ public class DeviceController {
@Autowired
private DeviceBehaviourService behaviourService;
@PostMapping("/{deviceId}/service/{service}")
@PostMapping(Constants.API.DEVICE_INVOKE_SERVICE)
public String invokeService(@PathVariable("deviceId") String deviceId,
@PathVariable("service") String service,
@RequestBody Map<String, Object> args) {
@ -63,7 +65,7 @@ public class DeviceController {
return deviceService.invokeService(deviceId, service, args);
}
@PostMapping("/{deviceId}/service/property/set")
@PostMapping(Constants.API.DEVICE_SET_PROPERTIES)
public String setProperty(@PathVariable("deviceId") String deviceId,
@RequestBody Map<String, Object> args) {
dataOwnerService.checkWriteRole();
@ -93,6 +95,39 @@ public class DeviceController {
return deviceDao.find(condition, size, page);
}
@PostMapping("/list/{size}/{page}")
public Paging<DeviceInfo> getDevices(
@PathVariable("size") int size,
@PathVariable("page") int page,
@RequestBody DeviceQuery query) {
Criteria condition = new Criteria();
String uid = AuthUtil.getUserId();
if (!AuthUtil.isAdmin()) {
//客户端用户使用绑定子用户查询
if (AuthUtil.isClientUser()) {
condition.and("subUid").elemMatch(new Criteria().is(uid));
} else {
condition.and("uid").is(uid);
}
}
String pk = query.getProductKey();
if (StringUtils.isNotBlank(pk)) {
condition.and("productKey").is(pk);
}
String dn = query.getDeviceName();
if (StringUtils.isNotBlank(dn)) {
condition.and("deviceName").regex(".*" + dn + ".*");
}
String state = query.getState();
if (state != null) {
condition.and("state.online").is(state);
}
return deviceDao.find(condition, size, page);
}
@PostMapping("/create")
public void createDevice(String productKey, String deviceName) {
Optional<Product> productOpt = productRepository.findById(productKey);
@ -121,7 +156,7 @@ public class DeviceController {
.build())));
}
@GetMapping("/{deviceId}")
@GetMapping(Constants.API.DEVICE_DETAIL)
public DeviceInfo getDetail(@PathVariable("deviceId") String deviceId) {
return dataOwnerService.checkOwner(deviceRepository.findById(deviceId).orElse(new DeviceInfo()));
}

View File

@ -3,7 +3,7 @@ package cc.iotkit.manager.controller;
import cc.iotkit.common.exception.BizException;
import cc.iotkit.common.utils.JsonUtil;
import cc.iotkit.common.utils.ReflectUtil;
import cc.iotkit.comps.ComponentManager;
import cc.iotkit.comps.DeviceComponentManager;
import cc.iotkit.comps.config.ComponentConfig;
import cc.iotkit.dao.ProtocolComponentRepository;
import cc.iotkit.dao.ProtocolConverterRepository;
@ -50,7 +50,7 @@ public class ProtocolController {
private UserInfoRepository userInfoRepository;
@Autowired
private ComponentManager componentManager;
private DeviceComponentManager deviceComponentManager;
@PostMapping("/uploadJar")
public String uploadJar(@RequestParam("file") MultipartFile file, String id) {
@ -113,7 +113,7 @@ public class ProtocolController {
ProtocolComponent oldComponent = getAndCheckComponent(id);
component = ReflectUtil.copyNoNulls(component, oldComponent);
try {
componentManager.deRegister(id);
deviceComponentManager.deRegister(id);
protocolComponentRepository.save(component);
} catch (Throwable e) {
throw new BizException("add protocol component error", e);
@ -144,7 +144,7 @@ public class ProtocolController {
script = JsonUtil.parse(script, String.class);
FileUtils.writeStringToFile(file, script, "UTF-8", false);
componentManager.deRegister(id);
deviceComponentManager.deRegister(id);
} catch (Throwable e) {
throw new BizException("save protocol component script error", e);
}
@ -164,7 +164,7 @@ public class ProtocolController {
public void deleteComponent(@PathVariable("id") String id) {
ProtocolComponent component = getAndCheckComponent(id);
try {
componentManager.deRegister(id);
deviceComponentManager.deRegister(id);
Path path = Paths.get(String.format("%s/%s", componentConfig.getComponentDir(), id))
.toAbsolutePath().normalize();
@ -190,7 +190,7 @@ 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()) ?
components.getContent().forEach(c -> c.setState(deviceComponentManager.isRunning(c.getId()) ?
ProtocolComponent.STATE_RUNNING : ProtocolComponent.STATE_STOPPED));
return new Paging<>(components.getTotalElements(), components.getContent());
}
@ -297,11 +297,11 @@ public class ProtocolController {
String converterId = component.getConverter();
getAndCheckConverter(converterId);
if (ProtocolComponent.STATE_RUNNING.equals(state)) {
componentManager.register(component);
componentManager.start(component.getId());
deviceComponentManager.register(component);
deviceComponentManager.start(component.getId());
component.setState(ProtocolComponent.STATE_RUNNING);
} else {
componentManager.deRegister(id);
deviceComponentManager.deRegister(id);
component.setState(ProtocolComponent.STATE_STOPPED);
}
protocolComponentRepository.save(component);

View File

@ -0,0 +1,14 @@
package cc.iotkit.manager.model.query;
import lombok.Data;
@Data
public class DeviceQuery {
private String productKey;
private String deviceName;
private String state;
}

View File

@ -3,10 +3,13 @@ package cc.iotkit.manager.service;
import cc.iotkit.common.exception.BizException;
import cc.iotkit.manager.utils.AuthUtil;
import cc.iotkit.model.Owned;
import cc.iotkit.model.device.DeviceInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class DataOwnerService {
@ -33,10 +36,21 @@ public class DataOwnerService {
if (StringUtils.isBlank(data.getUid())) {
return data;
}
if (AuthUtil.getUserId().equals(data.getUid())) {
String uid = AuthUtil.getUserId();
if (uid.equals(data.getUid())) {
return data;
}
if (data instanceof DeviceInfo) {
DeviceInfo device = (DeviceInfo) data;
//设备子用户验证
List<String> subUid = device.getSubUid();
if (subUid != null && subUid.contains(uid)) {
return data;
}
}
throw new BizException("无权限操作");
}

View File

@ -3,7 +3,7 @@ package cc.iotkit.manager.service;
import cc.iotkit.common.exception.NotFoundException;
import cc.iotkit.common.exception.OfflineException;
import cc.iotkit.common.utils.UniqueIdUtil;
import cc.iotkit.comps.ComponentManager;
import cc.iotkit.comps.DeviceComponentManager;
import cc.iotkit.converter.ThingService;
import cc.iotkit.dao.DeviceRepository;
import cc.iotkit.dao.ThingModelMessageRepository;
@ -24,7 +24,7 @@ public class DeviceService {
@Autowired
private DataOwnerService dataOwnerService;
@Autowired
private ComponentManager componentManager;
private DeviceComponentManager deviceComponentManager;
@Autowired
private ThingModelService thingModelService;
@Autowired
@ -57,7 +57,7 @@ public class DeviceService {
.build();
thingModelService.parseParams(thingService);
componentManager.send(thingService);
deviceComponentManager.send(thingService);
String mid = thingService.getMid();
//保存设备日志
@ -103,7 +103,7 @@ public class DeviceService {
.build();
thingModelService.parseParams(thingService);
componentManager.send(thingService);
deviceComponentManager.send(thingService);
String mid = thingService.getMid();
//保存设备日志

View File

@ -34,7 +34,11 @@ public class AuthUtil {
return AuthUtil.getUserRoles().contains(Constants.ROLE_ADMIN);
}
public static boolean hasWriteRole(){
public static boolean isClientUser() {
return AuthUtil.getUserRoles().contains(Constants.ROLE_CLIENT);
}
public static boolean hasWriteRole() {
return AuthUtil.getUserRoles().contains(Constants.ROLE_WRITE);
}

View File

@ -5,9 +5,9 @@
<parent>
<artifactId>iotkit-parent</artifactId>
<groupId>cc.iotkit</groupId>
<version>0.0.1-SNAPSHOT</version>
<version>0.1.0-SNAPSHOT</version>
</parent>
<version>0.0.1-SNAPSHOT</version>
<version>0.1.0-SNAPSHOT</version>
<modelVersion>4.0.0</modelVersion>
<artifactId>model</artifactId>

View File

@ -8,6 +8,7 @@ import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.List;
import java.util.Map;
@Data
@ -35,6 +36,11 @@ public class DeviceInfo implements Owned {
*/
private String uid;
/**
* ID
*/
private List<String> subUid;
private State state = new State();
private Map<String, Object> property;

View File

@ -11,6 +11,8 @@ public class ProtocolComponent implements Owned {
public static final String STATE_STOPPED = "stopped";
public static final String STATE_RUNNING = "running";
public static final String TYPE_DEVICE = "device";
public static final String TYPE_BIZ = "biz";
public static final String SCRIPT_FILE_NAME = "component.js";
@ -24,6 +26,8 @@ public class ProtocolComponent implements Owned {
private String name;
private String type = TYPE_DEVICE;
private String protocol;
private String jarFile;

22
pom.xml
View File

@ -9,7 +9,6 @@
<module>common</module>
<module>manager</module>
<module>dao</module>
<module>tppa-server</module>
<module>protocol-gateway</module>
<module>standalone-package</module>
</modules>
@ -22,7 +21,7 @@
<groupId>cc.iotkit</groupId>
<artifactId>iotkit-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<version>0.1.0-SNAPSHOT</version>
<name>iotkit-parent</name>
<description>iotkit parent</description>
<properties>
@ -71,6 +70,12 @@
<version>1.14</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
@ -161,19 +166,12 @@
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.pulsar</groupId>
<artifactId>pulsar-functions-api</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-core</artifactId>
@ -192,6 +190,12 @@
<version>4.2.6</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web-client</artifactId>
<version>4.2.6</version>
</dependency>
<dependency>
<groupId>cc.iotkit</groupId>
<artifactId>model</artifactId>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>protocol-gateway</artifactId>
<groupId>cc.iotkit</groupId>
<version>0.0.1-SNAPSHOT</version>
<version>0.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -0,0 +1,113 @@
package cc.iotkit.comps;
import cc.iotkit.common.ComponentClassLoader;
import cc.iotkit.common.exception.BizException;
import cc.iotkit.comp.CompConfig;
import cc.iotkit.comp.IComponent;
import cc.iotkit.comps.config.ComponentConfig;
import cc.iotkit.dao.ProtocolComponentRepository;
import cc.iotkit.model.protocol.ProtocolComponent;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
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;
@Slf4j
@Component
public class BizComponentManager {
private final Map<String, IComponent> components = new HashMap<>();
private final Map<String, Boolean> states = new HashMap<>();
@Autowired
private ComponentConfig componentConfig;
@Autowired
private ProtocolComponentRepository componentRepository;
@PostConstruct
public void init() {
try {
List<ProtocolComponent> componentList = componentRepository
.findByStateAndType(ProtocolComponent.STATE_RUNNING, ProtocolComponent.TYPE_BIZ);
for (ProtocolComponent component : componentList) {
register(component);
start(component.getId());
}
} catch (Throwable e) {
log.error("init protocol components error", e);
}
}
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;
try {
componentInstance = ComponentClassLoader.getComponent(component.getId(), file);
} catch (Throwable e) {
throw new BizException("get component instance error");
}
componentInstance.create(new CompConfig(300, component.getConfig()));
try {
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 component script error", e);
}
}
public void register(String id, IComponent component) {
components.put(id, component);
states.put(id, false);
}
public void deRegister(String id) {
IComponent component = components.remove(id);
states.remove(id);
if (component == null) {
return;
}
component.stop();
component.destroy();
}
public void start(String id) {
IComponent component = components.get(id);
if (component == null) {
return;
}
component.start();
states.put(id, true);
}
public void stop(String id) {
IComponent component = components.get(id);
if (component == null) {
return;
}
component.stop();
states.put(id, false);
}
public boolean isRunning(String id) {
return states.containsKey(id) && states.get(id);
}
}

View File

@ -1,10 +1,11 @@
package cc.iotkit.comps;
import cc.iotkit.common.ComponentClassLoader;
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.comp.IDeviceComponent;
import cc.iotkit.comps.config.CacheKey;
import cc.iotkit.comps.config.ComponentConfig;
import cc.iotkit.comps.service.DeviceBehaviourService;
@ -32,10 +33,9 @@ import java.util.concurrent.TimeUnit;
@Slf4j
@Component
public class ComponentManager {
public class DeviceComponentManager {
private final Map<String, IComponent> components = new HashMap<>();
private final Map<String, String> scripts = new HashMap<>();
private final Map<String, IDeviceComponent> components = new HashMap<>();
private final Map<String, Boolean> states = new HashMap<>();
@Autowired
@ -68,9 +68,11 @@ public class ComponentManager {
Path path = componentConfig.getComponentFilePath(id);
File file = path.resolve(component.getJarFile()).toAbsolutePath().toFile();
IComponent componentInstance = ComponentClassLoader.getComponent(component.getId(), file);
if (componentInstance == null) {
throw new BizException("instance component failed");
IDeviceComponent componentInstance;
try {
componentInstance = ComponentClassLoader.getComponent(component.getId(), file);
} catch (Throwable e) {
throw new BizException("get device component instance error");
}
componentInstance.create(new CompConfig(300, component.getConfig()));
@ -85,21 +87,21 @@ public class ComponentManager {
String componentScript = FileUtils.readFileToString(path.
resolve(ProtocolComponent.SCRIPT_FILE_NAME).toFile(), "UTF-8");
register(id, componentInstance, componentScript);
componentInstance.setScript(componentScript);
register(id, componentInstance);
} catch (IOException e) {
throw new BizException("get component script error", e);
throw new BizException("get device component script error", e);
}
}
public void register(String id, IComponent component, String script) {
public void register(String id, IDeviceComponent component) {
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);
IDeviceComponent component = components.remove(id);
states.remove(id);
if (component == null) {
return;
@ -109,21 +111,20 @@ public class ComponentManager {
}
public void start(String id) {
IComponent component = components.get(id);
IDeviceComponent component = components.get(id);
if (component == null) {
return;
}
String script = scripts.get(id);
component.setHandler(
new MessageHandler(this, component,
script, component.getConverter(),
new DeviceMessageHandler(this, component,
component.getScript(), component.getConverter(),
deviceBehaviourService));
component.start();
states.put(id, true);
}
public void stop(String id) {
IComponent component = components.get(id);
IDeviceComponent component = components.get(id);
if (component == null) {
return;
}
@ -141,7 +142,7 @@ public class ComponentManager {
throw new BizException("there is no components");
}
for (IComponent com : components.values()) {
for (IDeviceComponent com : components.values()) {
if (com.exist(service.getProductKey(), service.getDeviceName())) {
//对下发消息进行编码转换
DeviceMessage message = com.getConverter().encode(service, null);

View File

@ -3,7 +3,7 @@ package cc.iotkit.comps;
import cc.iotkit.common.exception.BizException;
import cc.iotkit.common.utils.JsonUtil;
import cc.iotkit.common.utils.UniqueIdUtil;
import cc.iotkit.comp.IComponent;
import cc.iotkit.comp.IDeviceComponent;
import cc.iotkit.comp.IMessageHandler;
import cc.iotkit.comp.model.AuthInfo;
import cc.iotkit.comp.model.ReceiveResult;
@ -22,12 +22,11 @@ import org.apache.commons.beanutils.BeanUtils;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
@Slf4j
@Data
public class MessageHandler implements IMessageHandler {
public class DeviceMessageHandler implements IMessageHandler {
private final NashornScriptEngine engine = (NashornScriptEngine) (new ScriptEngineManager()).getEngineByName("nashorn");
private final Object scriptObj;
@ -36,16 +35,16 @@ public class MessageHandler implements IMessageHandler {
private final DeviceBehaviourService deviceBehaviourService;
private final ComponentManager componentManager;
private final DeviceComponentManager deviceComponentManager;
private final IComponent component;
private final IDeviceComponent component;
@SneakyThrows
public MessageHandler(ComponentManager componentManager,
IComponent component,
String script, IConverter converter,
DeviceBehaviourService deviceBehaviourService) {
this.componentManager = componentManager;
public DeviceMessageHandler(DeviceComponentManager deviceComponentManager,
IDeviceComponent component,
String script, IConverter converter,
DeviceBehaviourService deviceBehaviourService) {
this.deviceComponentManager = deviceComponentManager;
this.component = component;
this.converter = converter;
this.deviceBehaviourService = deviceBehaviourService;
@ -157,7 +156,7 @@ public class MessageHandler implements IMessageHandler {
//服务回复需要重新对应mid
if (thingModelMessage.getIdentifier().endsWith("_reply")) {
String platformMid = componentManager.getPlatformMid(message.getDeviceName(), message.getMid());
String platformMid = deviceComponentManager.getPlatformMid(message.getDeviceName(), message.getMid());
if (platformMid == null) {
platformMid = UniqueIdUtil.newRequestId();
}

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>protocol-gateway</artifactId>
<groupId>cc.iotkit</groupId>
<version>0.0.1-SNAPSHOT</version>
<version>0.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -7,7 +7,7 @@ import cc.iotkit.converter.IConverter;
import lombok.Data;
@Data
public abstract class AbstractComponent implements IComponent {
public abstract class AbstractDeviceComponent implements IDeviceComponent {
protected IMessageHandler handler;
@ -15,9 +15,11 @@ public abstract class AbstractComponent implements IComponent {
protected CompConfig config;
protected String script;
@Override
public void create(CompConfig config) {
this.config=config;
this.config = config;
}
@Override

View File

@ -1,11 +1,5 @@
package cc.iotkit.comp;
import cc.iotkit.comp.model.AuthInfo;
import cc.iotkit.comp.model.DeviceState;
import cc.iotkit.comp.model.RegisterInfo;
import cc.iotkit.converter.DeviceMessage;
import cc.iotkit.converter.IConverter;
public interface IComponent {
void create(CompConfig config);
@ -16,21 +10,9 @@ public interface IComponent {
void destroy();
void onDeviceAuth(AuthInfo authInfo);
void onDeviceRegister(RegisterInfo info);
void onDeviceStateChange(DeviceState state);
void send(DeviceMessage message);
boolean exist(String productKey, String deviceName);
void setHandler(IMessageHandler handler);
void setConverter(IConverter converter);
IConverter getConverter();
CompConfig getConfig();
void setScript(String script);
String getScript();
}

View File

@ -0,0 +1,27 @@
package cc.iotkit.comp;
import cc.iotkit.comp.model.AuthInfo;
import cc.iotkit.comp.model.DeviceState;
import cc.iotkit.comp.model.RegisterInfo;
import cc.iotkit.converter.DeviceMessage;
import cc.iotkit.converter.IConverter;
public interface IDeviceComponent extends IComponent {
void onDeviceAuth(AuthInfo authInfo);
void onDeviceRegister(RegisterInfo info);
void onDeviceStateChange(DeviceState state);
void send(DeviceMessage message);
boolean exist(String productKey, String deviceName);
void setHandler(IMessageHandler handler);
void setConverter(IConverter converter);
IConverter getConverter();
}

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>protocol-gateway</artifactId>
<groupId>cc.iotkit</groupId>
<version>0.0.1-SNAPSHOT</version>
<version>0.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -3,7 +3,7 @@
<parent>
<artifactId>protocol-gateway</artifactId>
<groupId>cc.iotkit</groupId>
<version>0.0.1-SNAPSHOT</version>
<version>0.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>emqx-component</artifactId>
@ -61,19 +61,19 @@
<dependency>
<groupId>cc.iotkit</groupId>
<artifactId>model</artifactId>
<version>0.0.1-SNAPSHOT</version>
<version>0.1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cc.iotkit</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<version>0.1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cc.iotkit</groupId>
<artifactId>component</artifactId>
<version>0.0.1-SNAPSHOT</version>
<version>0.1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>protocol-gateway</artifactId>
<groupId>cc.iotkit</groupId>
<version>0.0.1-SNAPSHOT</version>
<version>0.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -2,7 +2,7 @@ package cc.iotkit.comp.emqx;
import cc.iotkit.common.exception.BizException;
import cc.iotkit.common.utils.JsonUtil;
import cc.iotkit.comp.AbstractComponent;
import cc.iotkit.comp.AbstractDeviceComponent;
import cc.iotkit.comp.CompConfig;
import cc.iotkit.comp.model.DeviceState;
import cc.iotkit.converter.DeviceMessage;
@ -20,7 +20,7 @@ import java.util.Map;
import java.util.concurrent.CountDownLatch;
@Slf4j
public class EmqxComponent extends AbstractComponent {
public class EmqxDeviceComponent extends AbstractDeviceComponent {
private Vertx vertx;
private AuthVerticle authVerticle;

View File

@ -1 +1 @@
cc.iotkit.comp.emqx.EmqxComponent
cc.iotkit.comp.emqx.EmqxDeviceComponent

View File

@ -3,13 +3,13 @@
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>iotkit-parent</artifactId>
<artifactId>protocol-gateway</artifactId>
<groupId>cc.iotkit</groupId>
<version>0.0.1-SNAPSHOT</version>
<version>0.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>tppa-server</artifactId>
<artifactId>http-biz-component</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
@ -18,21 +18,27 @@
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>cc.iotkit</groupId>
<artifactId>common</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web-proxy</artifactId>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web-client</artifactId>
</dependency>
<dependency>
<groupId>cc.iotkit</groupId>
<artifactId>component</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,137 @@
package cc.iotkit.comp.biz;
import cc.iotkit.common.Constants;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.ext.web.client.HttpRequest;
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.client.WebClientOptions;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
/**
* API
*/
public class ApiTool {
private static final Vertx vertx;
private static final WebClient client;
static {
if (Vertx.currentContext() == null) {
vertx = Vertx.vertx();
} else {
vertx = Vertx.currentContext().owner();
}
WebClientOptions options = new WebClientOptions()
.setUserAgent("component-api-tool");
options.setKeepAlive(false);
client = WebClient.create(vertx, options);
}
private static String host;
private static int port;
private static int timeout;
public static void config(String host, int port, int timeout) {
ApiTool.host = host;
ApiTool.port = port;
ApiTool.timeout = timeout;
}
/**
*
*/
public static ApiResponse getDevices(String token) {
HttpRequest<Buffer> request = client
.post(port, host, Paths.get(Constants.API.DEVICE_BASE, Constants.API.DEVICE_LIST
.replace("size", "1000")
.replace("page", "1")).toString())
.timeout(timeout)
.putHeader("authorization", "Bearer " + token);
return sendJson(request, new HashMap<>());
}
/**
*
*/
public static ApiResponse getDeviceDetail(String token, String deviceId) {
HttpRequest<Buffer> request = client
.post(port, host, Paths.get(Constants.API.DEVICE_BASE, Constants.API.DEVICE_DETAIL
.replace("deviceId", deviceId)).toString())
.timeout(timeout)
.putHeader("authorization", "Bearer " + token);
return sendJson(request, new HashMap<>());
}
/**
*
*/
public static ApiResponse setProperties(String token, String deviceId, Map<String, Object> properties) {
HttpRequest<Buffer> request = client
.post(port, host, Paths.get(Constants.API.DEVICE_BASE, Constants.API.DEVICE_SET_PROPERTIES
.replace("deviceId", deviceId)).toString())
.timeout(timeout)
.putHeader("authorization", "Bearer " + token);
return sendJson(request, properties);
}
/**
*
*/
public static ApiResponse invokeService(String token, String deviceId, String service, Map<String, Object> params) {
HttpRequest<Buffer> request = client
.post(port, host, Paths.get(Constants.API.DEVICE_BASE, Constants.API.DEVICE_INVOKE_SERVICE
.replace("deviceId", deviceId)
.replace("service", service)).toString())
.timeout(timeout)
.putHeader("authorization", "Bearer " + token);
return sendJson(request, params);
}
private static ApiResponse sendJson(HttpRequest<Buffer> request, Map<String, Object> params) {
AtomicReference<ApiResponse> apiResponse = new AtomicReference<>(new ApiResponse(500, "", null));
try {
//转为同步模式便于提供给js调用
CountDownLatch wait = new CountDownLatch(1);
request.sendJson(params)
.onSuccess((response) -> {
System.out.println(response.bodyAsString());
apiResponse.set(response.bodyAsJson(ApiResponse.class));
wait.countDown();
})
.onFailure((err) -> {
err.printStackTrace();
wait.countDown();
});
if (wait.await(timeout, TimeUnit.MILLISECONDS)) {
return apiResponse.get();
} else {
apiResponse.get().setCode(500);
apiResponse.get().setMessage("request timeout");
}
} catch (Throwable e) {
apiResponse.get().setCode(500);
apiResponse.get().setMessage(e.getMessage());
}
return apiResponse.get();
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class ApiResponse {
private int code;
private String message;
private Object data;
}
}

View File

@ -0,0 +1,134 @@
package cc.iotkit.comp.biz;
import cc.iotkit.common.utils.JsonUtil;
import cc.iotkit.comp.CompConfig;
import cc.iotkit.comp.IComponent;
import io.vertx.core.MultiMap;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.BodyHandler;
import jdk.nashorn.api.scripting.NashornScriptEngine;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@Data
public class HttpBizComponent implements IComponent {
private final Vertx vertx = Vertx.vertx();
private final NashornScriptEngine engine = (NashornScriptEngine) (new ScriptEngineManager()).getEngineByName("nashorn");
private Object scriptObj;
private HttpConfig config;
private String script;
private HttpServer backendServer;
@Override
public void create(CompConfig config) {
this.config = JsonUtil.parse(config.getOther(), HttpConfig.class);
try {
scriptObj = engine.eval(String.format("new (function () {\n%s})()", script));
} catch (ScriptException e) {
log.error("init script error", e);
}
}
@Override
public void start() {
backendServer = vertx.createHttpServer();
Router backendRouter = Router.router(vertx);
backendRouter.route().handler(BodyHandler.create())
.handler(rc -> {
Map<String, Object> httpHeader = getData(rc.request().headers());
log.info("request header:{}", JsonUtil.toJsonString(httpHeader));
Map<String, List<Object>> httpParams = getListData(rc.request().params());
log.info("request params:{}", JsonUtil.toJsonString(httpParams));
String contentType = rc.request().headers().get("Content-Type");
JsonObject responseHeader = new JsonObject();
if ("application/json".equals(contentType)) {
String bodyStr = rc.toString();
Map body = JsonUtil.parse(bodyStr, Map.class);
log.info("request body:{}", bodyStr);
String response = "unknown error";
String name = "onReceive";
if (((ScriptObjectMirror) scriptObj).get(name) != null) {
try {
Object result = engine.invokeMethod(scriptObj, name, body);
Object resultObj = JsonUtil.toObject((ScriptObjectMirror) result);
if (resultObj instanceof Map) {
JsonObject data = JsonObject.mapFrom(resultObj);
responseHeader = data.getJsonObject("header");
response = data.getString("content");
}
} catch (Throwable e) {
log.error("invokeMethod onReceive error", e);
response = e.getMessage();
}
} else {
log.error("required [onReceive] method");
}
HttpServerResponse httpServerResponse = rc.response();
//设置响应头
responseHeader.getMap().forEach((key, value) -> {
//大写转换
key = key.replaceAll("([A-Z])", "-$1").toLowerCase();
httpServerResponse.putHeader(key, value.toString());
});
log.info("response,header:{},content:{}", responseHeader, response);
//设置响应内容
httpServerResponse
.end(response);
}
});
backendServer.requestHandler(backendRouter).listen(config.getPort());
}
@Override
public void stop() {
backendServer.close();
}
@Override
public void destroy() {
}
private static Map<String, List<Object>> getListData(MultiMap multiMap) {
Map<String, List<Object>> listData = new HashMap<>();
for (Map.Entry<String, String> entry : multiMap.entries()) {
String key = entry.getKey();
Object value = entry.getValue();
listData.putIfAbsent(key, new ArrayList<>());
listData.get(key).add(value);
}
return listData;
}
private static Map<String, Object> getData(MultiMap multiMap) {
Map<String, Object> data = new HashMap<>();
for (Map.Entry<String, String> entry : multiMap.entries()) {
data.put(entry.getKey(), entry.getValue());
}
return data;
}
}

View File

@ -0,0 +1,10 @@
package cc.iotkit.comp.biz;
import lombok.Data;
@Data
public class HttpConfig {
private int port;
}

View File

@ -0,0 +1 @@
cc.iotkit.comp.biz.HttpBizComponent

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>protocol-gateway</artifactId>
<groupId>cc.iotkit</groupId>
<version>0.0.1-SNAPSHOT</version>
<version>0.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<description>mqtt客户端模拟器</description>

View File

@ -3,7 +3,7 @@
<parent>
<artifactId>protocol-gateway</artifactId>
<groupId>cc.iotkit</groupId>
<version>0.0.1-SNAPSHOT</version>
<version>0.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mqtt-component</artifactId>
@ -73,13 +73,13 @@
<dependency>
<groupId>cc.iotkit</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<version>0.1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cc.iotkit</groupId>
<artifactId>component</artifactId>
<version>0.0.1-SNAPSHOT</version>
<version>0.1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>protocol-gateway</artifactId>
<groupId>cc.iotkit</groupId>
<version>0.0.1-SNAPSHOT</version>
<version>0.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -2,7 +2,7 @@ package cc.iotkit.comp.mqtt;
import cc.iotkit.common.exception.BizException;
import cc.iotkit.common.utils.JsonUtil;
import cc.iotkit.comp.AbstractComponent;
import cc.iotkit.comp.AbstractDeviceComponent;
import cc.iotkit.comp.CompConfig;
import cc.iotkit.comp.model.DeviceState;
import cc.iotkit.converter.DeviceMessage;
@ -17,13 +17,13 @@ import java.util.Map;
import java.util.concurrent.CountDownLatch;
@Slf4j
public class MqttComponent extends AbstractComponent {
public class MqttDeviceComponent extends AbstractDeviceComponent {
private Vertx vertx;
private CountDownLatch countDownLatch;
private String deployedId;
private MqttVerticle mqttVerticle;
private Map<String, Device> deviceChildToParent = new HashMap<>();
private final Map<String, Device> deviceChildToParent = new HashMap<>();
public void create(CompConfig config) {
super.create(config);
@ -34,7 +34,6 @@ public class MqttComponent extends AbstractComponent {
public void start() {
try {
System.out.println("start:======2222222222");
mqttVerticle.setExecutor(getHandler());
countDownLatch = new CountDownLatch(1);
Future<String> future = vertx.deployVerticle(mqttVerticle);

View File

@ -1,77 +1,191 @@
!function(n){"use strict";function d(n,t){var r=(65535&n)+(65535&t);return(n>>16)+(t>>16)+(r>>16)<<16|65535&r}function f(n,t,r,e,o,u){return d((u=d(d(t,n),d(e,u)))<<o|u>>>32-o,r)}function l(n,t,r,e,o,u,c){return f(t&r|~t&e,n,t,o,u,c)}function g(n,t,r,e,o,u,c){return f(t&e|r&~e,n,t,o,u,c)}function v(n,t,r,e,o,u,c){return f(t^r^e,n,t,o,u,c)}function m(n,t,r,e,o,u,c){return f(r^(t|~e),n,t,o,u,c)}function c(n,t){var r,e,o,u;n[t>>5]|=128<<t%32,n[14+(t+64>>>9<<4)]=t;for(var c=1732584193,f=-271733879,i=-1732584194,a=271733878,h=0;h<n.length;h+=16)c=l(r=c,e=f,o=i,u=a,n[h],7,-680876936),a=l(a,c,f,i,n[h+1],12,-389564586),i=l(i,a,c,f,n[h+2],17,606105819),f=l(f,i,a,c,n[h+3],22,-1044525330),c=l(c,f,i,a,n[h+4],7,-176418897),a=l(a,c,f,i,n[h+5],12,1200080426),i=l(i,a,c,f,n[h+6],17,-1473231341),f=l(f,i,a,c,n[h+7],22,-45705983),c=l(c,f,i,a,n[h+8],7,1770035416),a=l(a,c,f,i,n[h+9],12,-1958414417),i=l(i,a,c,f,n[h+10],17,-42063),f=l(f,i,a,c,n[h+11],22,-1990404162),c=l(c,f,i,a,n[h+12],7,1804603682),a=l(a,c,f,i,n[h+13],12,-40341101),i=l(i,a,c,f,n[h+14],17,-1502002290),c=g(c,f=l(f,i,a,c,n[h+15],22,1236535329),i,a,n[h+1],5,-165796510),a=g(a,c,f,i,n[h+6],9,-1069501632),i=g(i,a,c,f,n[h+11],14,643717713),f=g(f,i,a,c,n[h],20,-373897302),c=g(c,f,i,a,n[h+5],5,-701558691),a=g(a,c,f,i,n[h+10],9,38016083),i=g(i,a,c,f,n[h+15],14,-660478335),f=g(f,i,a,c,n[h+4],20,-405537848),c=g(c,f,i,a,n[h+9],5,568446438),a=g(a,c,f,i,n[h+14],9,-1019803690),i=g(i,a,c,f,n[h+3],14,-187363961),f=g(f,i,a,c,n[h+8],20,1163531501),c=g(c,f,i,a,n[h+13],5,-1444681467),a=g(a,c,f,i,n[h+2],9,-51403784),i=g(i,a,c,f,n[h+7],14,1735328473),c=v(c,f=g(f,i,a,c,n[h+12],20,-1926607734),i,a,n[h+5],4,-378558),a=v(a,c,f,i,n[h+8],11,-2022574463),i=v(i,a,c,f,n[h+11],16,1839030562),f=v(f,i,a,c,n[h+14],23,-35309556),c=v(c,f,i,a,n[h+1],4,-1530992060),a=v(a,c,f,i,n[h+4],11,1272893353),i=v(i,a,c,f,n[h+7],16,-155497632),f=v(f,i,a,c,n[h+10],23,-1094730640),c=v(c,f,i,a,n[h+13],4,681279174),a=v(a,c,f,i,n[h],11,-358537222),i=v(i,a,c,f,n[h+3],16,-722521979),f=v(f,i,a,c,n[h+6],23,76029189),c=v(c,f,i,a,n[h+9],4,-640364487),a=v(a,c,f,i,n[h+12],11,-421815835),i=v(i,a,c,f,n[h+15],16,530742520),c=m(c,f=v(f,i,a,c,n[h+2],23,-995338651),i,a,n[h],6,-198630844),a=m(a,c,f,i,n[h+7],10,1126891415),i=m(i,a,c,f,n[h+14],15,-1416354905),f=m(f,i,a,c,n[h+5],21,-57434055),c=m(c,f,i,a,n[h+12],6,1700485571),a=m(a,c,f,i,n[h+3],10,-1894986606),i=m(i,a,c,f,n[h+10],15,-1051523),f=m(f,i,a,c,n[h+1],21,-2054922799),c=m(c,f,i,a,n[h+8],6,1873313359),a=m(a,c,f,i,n[h+15],10,-30611744),i=m(i,a,c,f,n[h+6],15,-1560198380),f=m(f,i,a,c,n[h+13],21,1309151649),c=m(c,f,i,a,n[h+4],6,-145523070),a=m(a,c,f,i,n[h+11],10,-1120210379),i=m(i,a,c,f,n[h+2],15,718787259),f=m(f,i,a,c,n[h+9],21,-343485551),c=d(c,r),f=d(f,e),i=d(i,o),a=d(a,u);return[c,f,i,a]}function i(n){for(var t="",r=32*n.length,e=0;e<r;e+=8)t+=String.fromCharCode(n[e>>5]>>>e%32&255);return t}function a(n){var t=[];for(t[(n.length>>2)-1]=void 0,e=0;e<t.length;e+=1)t[e]=0;for(var r=8*n.length,e=0;e<r;e+=8)t[e>>5]|=(255&n.charCodeAt(e/8))<<e%32;return t}function e(n){for(var t,r="0123456789abcdef",e="",o=0;o<n.length;o+=1)t=n.charCodeAt(o),e+=r.charAt(t>>>4&15)+r.charAt(15&t);return e}function r(n){return unescape(encodeURIComponent(n))}function o(n){return i(c(a(n=r(n)),8*n.length))}function u(n,t){return function(n,t){var r,e=a(n),o=[],u=[];for(o[15]=u[15]=void 0,16<e.length&&(e=c(e,8*n.length)),r=0;r<16;r+=1)o[r]=909522486^e[r],u[r]=1549556828^e[r];return t=c(o.concat(a(t)),512+8*t.length),i(c(u.concat(t),640))}(r(n),r(t))}function t(n,t,r){return t?r?u(t,n):e(u(t,n)):r?o(n):e(o(n))}"function"==typeof define&&define.amd?define(function(){return t}):"object"==typeof module&&module.exports?module.exports=t:n.md5=t}(this);
var md5=this.md5;
/**
网关上线
订阅/sys/hbtgIA0SuVw9lxjB/AA:BB:CC:DD:10/c/#
function register(payload){
var auth= JSON.parse(payload);
var arr= auth.clientid.split("_");
if(arr.length<3){
throw new Error("incorrect clientid");
}
var pk=arr[0];
var dn=arr[1];
var model=arr[2];
var pwd=md5("xdkKUymrEGSCYWswqCvSPyRSFvH5j7CU"+auth.clientid);
if(pwd!=auth.password){
throw new Error("incorrect password");
}
return {
type:"register",
data:{
productKey:pk,
deviceName:dn,
model:model
子设备注册
/sys/hbtgIA0SuVw9lxjB/AA:BB:CC:DD:10/s/register
{
"id": "6",
"params":{
"productKey":"Rf4QSjbm65X45753",
"deviceName":"ABC12400001",
"model":"S1"
}
};
}
子设备上线
订阅/sys/Rf4QSjbm65X45753/ABC12400001/c/#
数据上报
/sys/Rf4QSjbm65X45753/ABC12400001/s/event/property/post
{
"id": "6",
"params":{
"powerstate": 1
}
}
*/
var registered={};
function getPkDn(clientId){
var arr=clientId.split("_");
return {
pk:arr[0],
dn:arr[1]
};
}
function online(topic){
var arr= topic.split('/');
if(arr.length<6){
throw new Error("incorrect topic")
}
function register(payload){
var auth= JSON.parse(payload);
var arr= auth.clientid.split("_");
if(arr.length<3){
throw new Error("incorrect clientid");
}
var pk=arr[2];
var dn=arr[3];
return {
type:"state",
data:{
productKey:pk,
deviceName:dn,
state:"online"
}
}
var pk=arr[0];
var dn=arr[1];
var model=arr[2];
var pwd=md5("xdkKUymrEGSCYWswqCvSPyRSFvH5j7CU"+auth.clientid);
if(pwd!=auth.password){
throw new Error("incorrect password");
}
return {
type:"register",
data:{
productKey:pk,
deviceName:dn,
model:model
}
};
}
function subRegister(topic,parent,payload){
var params= payload.params;
var reply=
{
productKey:parent.productKey,
deviceName:parent.deviceName,
mid:"0",
content:{
topic:topic.replace("/s/","/c/")+"_reply",
payload:JSON.stringify({
id:"0",
code:0,
data:{
"productKey":params.productKey,
"deviceName":params.deviceName
}
})
}
};
return {
type:"register",
data:{
productKey:parent.productKey,
deviceName:parent.deviceName,
subDevices:[{
productKey:params.productKey,
deviceName:params.deviceName,
model:params.model
}]
},
action:{
type:"ack",
content:JSON.stringify(reply)
}
};
}
function deviceStateChange(head,clientId,state){
var topic=head.topic;
var device=getPkDn(clientId);
var arr= topic.split('/');
if(arr.length<6){
throw new Error("incorrect topic")
}
var pk=arr[2];
var dn=arr[3];
return {
type:"state",
data:{
productKey:pk,
deviceName:dn,
state:state,
parent:{
productKey:device.pk,
deviceName:device.dn,
}
}
}
}
function disconnect(clientId){
var device=getPkDn(clientId);
return {
type:"state",
data:{
productKey:device.pk,
deviceName:device.dn,
state:"offline"
}
}
}
//必须提供onReceive方法
this.onReceive=function(head,type,payload){
if(type=='auth'){
return register(payload);
}
if(type=='auth'){
return register(payload);
}
if(type=='subscribe'){
return online(payload);
}
if(type=='subscribe'){
return deviceStateChange(head,payload,'online');
}
var topic=head['topic'];
if(!topic){
throw new Error("topic is blank")
}
if(type=='unsubscribe'){
return deviceStateChange(head,payload,'offline');
}
var arr= topic.split('/');
if(arr.length<6){
throw new Error("incorrect topic")
}
if(type=='disconnect'){
return disconnect(payload);
}
var pk=arr[2];
var dn=arr[3];
return {
type:"report",
data:{
productKey:pk,
deviceName:dn,
content:payload
}
}
var topic=head['topic'];
if(!topic){
throw new Error("topic is blank")
}
var arr= topic.split('/');
if(arr.length<6){
throw new Error("incorrect topic")
}
var pk=arr[2];
var dn=arr[3];
payload=JSON.parse(payload);
//子设备注册
if(topic.endsWith('/register')){
return subRegister(topic,{productKey:pk,deviceName:dn},payload);
}
//数据上报
return {
type:"report",
data:{
productKey:pk,
deviceName:dn,
mid:payload.id,
content:{
topic:topic,
payload:payload
}
}
}
}
this.onRegistered=function(regInfo,result){
}

View File

@ -1 +1 @@
cc.iotkit.comp.mqtt.MqttComponent
cc.iotkit.comp.mqtt.MqttDeviceComponent

View File

@ -1,48 +1,104 @@
var mid=1;
function getMid(){
mid++;
if(mid>10000){
mid=1;
}
return mid+"";
}
this.decode = function (msg) {
//对msg进行解析并返回物模型数据
var mqttMsg = JSON.parse(msg.content);
var topic = mqttMsg.topic;
var payload = mqttMsg.payload;
var content=msg.content;
var topic = content.topic;
var payload = content.payload;
var identifier = topic.substring(topic.lastIndexOf("/") + 1);
if (topic.endsWith("/property/post")) {
//属性上报
return {
mid: msg.mid,
productKey: msg.productKey, //可根据消息内容判断填写不同产品
deviceName: msg.deviceName,
type:"property",
identifier: "report", //属性上报
occur: new Date().getTime(), //时间戳,设备上的事件或数据产生的本地时间
time: new Date().getTime(), //时间戳,消息上报时间
data: payload.params,
};
//属性上报
return {
mid: msg.mid,
productKey: msg.productKey,
deviceName: msg.deviceName,
type:"property",
identifier: "report", //属性上报
occur: new Date().getTime(), //时间戳,设备上的事件或数据产生的本地时间
time: new Date().getTime(), //时间戳,消息上报时间
data: payload.params,
};
} else if (topic.indexOf("/event/") > 0) {
var identifier = topic.substring(topic.lastIndexOf("/") + 1);
//事件上报
return {
mid: msg.mid,
productKey: msg.productKey,
deviceName: msg.deviceName,
type:"event",
identifier: identifier,
occur: new Date().getTime(),
time: new Date().getTime(),
data: payload.params,
};
//事件上报
return {
mid: msg.mid,
productKey: msg.productKey,
deviceName: msg.deviceName,
type:"event",
identifier: identifier,
occur: new Date().getTime(),
time: new Date().getTime(),
data: payload.params,
};
}else if(topic.endsWith("/service/property/set_reply")){
//属性设置回复
return {
mid: msg.mid,
productKey: msg.productKey,
deviceName: msg.deviceName,
type:"property",
identifier: identifier,
occur: new Date().getTime(),
time: new Date().getTime(),
code: payload.code
};
} else if (topic.endsWith("_reply")) {
var identifier = topic.substring(topic.lastIndexOf("/") + 1);
//服务回复
return {
mid: msg.mid,
productKey: msg.productKey,
deviceName: msg.deviceName,
type:"service",
identifier: identifier.replace("_reply", "Reply"),
occur: new Date().getTime(),
time: new Date().getTime(),
code: payload.code,
data: payload.data,
};
//服务回复
return {
mid: msg.mid,
productKey: msg.productKey,
deviceName: msg.deviceName,
type:"service",
identifier: identifier,
occur: new Date().getTime(),
time: new Date().getTime(),
code: payload.code,
data: payload.data,
};
}
return null;
};
this.encode = function (service,device) {
var type=service.type;
var identifier=service.identifier;
var topic="/sys/"+service.productKey+"/"+service.deviceName+"/c/service/";
var method="thing.service.";
if(type=="property"){
method+="property."+identifier;
topic+="property/"+identifier;
}else if(type=="service"){
method+=identifier;
topic+=identifier;
}
var deviceMid=getMid();
var params={};
for(var p in service.params){
params[p]=service.params[p];
}
return {
productKey:service.productKey,
deviceName:service.deviceName,
mid:deviceMid,
content:{
topic:topic,
payload:JSON.stringify({
id:deviceMid,
method:method,
params:params
})
}
}
};

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>iotkit-parent</artifactId>
<groupId>cc.iotkit</groupId>
<version>0.0.1-SNAPSHOT</version>
<version>0.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -18,6 +18,7 @@
<module>emqx-component</module>
<module>component</module>
<module>mqtt-client-simulator</module>
<module>http-biz-component</module>
</modules>
</project>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>iotkit-parent</artifactId>
<groupId>cc.iotkit</groupId>
<version>0.0.1-SNAPSHOT</version>
<version>0.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -1,7 +1,7 @@
package cc.iotkit.ruleengine.action;
import cc.iotkit.common.utils.UniqueIdUtil;
import cc.iotkit.comps.ComponentManager;
import cc.iotkit.comps.DeviceComponentManager;
import cc.iotkit.converter.ThingService;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
@ -15,7 +15,7 @@ import java.util.Map;
public class DeviceActionService {
@Autowired
private ComponentManager componentManager;
private DeviceComponentManager deviceComponentManager;
public String invoke(Service service) {
String[] pkDn = service.getDevice().split("/");
@ -25,7 +25,7 @@ public class DeviceActionService {
thingService.setDeviceName(pkDn[1]);
thingService.setIdentifier(service.getIdentifier());
thingService.setParams(service.parseInputData());
componentManager.send(thingService);
deviceComponentManager.send(thingService);
return thingService.getMid();
}

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>iotkit-parent</artifactId>
<groupId>cc.iotkit</groupId>
<version>0.0.1-SNAPSHOT</version>
<version>0.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -1,8 +0,0 @@
tppa 即第三方平台接入
天猫精灵
小度
发现设备,输入: 小度小度,发现设备
小米

View File

@ -1,12 +0,0 @@
package cc.iotkit.tppa;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

View File

@ -1,53 +0,0 @@
package cc.iotkit.tppa.xiaodu;
import cc.iotkit.common.utils.JsonUtil;
import cc.iotkit.tppa.xiaodu.handler.IRequestHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
@RestController
@RequestMapping("/xiaodu")
public class MainController implements ApplicationContextAware {
private Pattern requestNamePattern = Pattern.compile(".*\"name\":\"(\\w+)\".*");
private Map<String, IRequestHandler> handlerMap = new HashMap<>();
@PostMapping("/receive")
public Object receive(@RequestBody String msg) {
log.info("receive msg:{}", msg);
Matcher matcher = requestNamePattern.matcher(msg);
if (!matcher.matches()) {
return null;
}
String name = matcher.group(1);
IRequestHandler handler = handlerMap.get(name);
if (handler == null) {
return null;
}
Object response = handler.handle(JsonUtil.parse(msg, handler.getRequestType()));
log.info("response data:{}", JsonUtil.toJsonString(response));
return response;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
applicationContext.getBeansOfType(IRequestHandler.class).forEach((name, handler) ->
handlerMap.put(handler.getName(), handler));
}
}

View File

@ -1,68 +0,0 @@
package cc.iotkit.tppa.xiaodu.handler;
import cc.iotkit.tppa.xiaodu.request.DiscoverAppliancesRequest;
import cc.iotkit.tppa.xiaodu.request.Header;
import cc.iotkit.tppa.xiaodu.response.DiscoverAppliancesResponse;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
@Component
public class DiscoverAppliancesRequestHandler implements IRequestHandler<DiscoverAppliancesRequest, DiscoverAppliancesResponse> {
@Override
public String getName() {
return "DiscoverAppliancesRequest";
}
@Override
public Class getRequestType() {
return DiscoverAppliancesRequest.class;
}
@Override
public DiscoverAppliancesResponse handle(DiscoverAppliancesRequest request) {
DiscoverAppliancesResponse response = new DiscoverAppliancesResponse();
response.setHeader(new Header("DuerOS.ConnectedHome.Discovery",
"DiscoverAppliancesResponse",
request.getHeader().getMessageId(),
"1"));
DiscoverAppliancesResponse.Payload payload = new DiscoverAppliancesResponse.Payload();
response.setPayload(payload);
List<DiscoverAppliancesResponse.DiscoveredAppliance> discoveredAppliances = new ArrayList<>();
discoveredAppliances.add(DiscoverAppliancesResponse.DiscoveredAppliance.builder()
.applianceId("11223344")
.applianceTypes("SWITCH")
.friendlyName("开关")
.isReachable(true)
.friendlyDescription("")
.manufacturerName("奇特")
.modelName("M01")
.version("1.0")
.actions(Arrays.asList("turnOn", "turnOff"))
.attributes(Arrays.asList(new DiscoverAppliancesResponse.Attribute(
"powerstate",
"1",
"",
System.currentTimeMillis() / 1000,
1000L
)))
.build());
payload.setDiscoveredAppliances(discoveredAppliances);
List<DiscoverAppliancesResponse.DiscoveredGroup> discoveredGroups = new ArrayList<>();
payload.setDiscoveredGroups(discoveredGroups);
discoveredGroups.add(new DiscoverAppliancesResponse.DiscoveredGroup("客厅",
Arrays.asList("11223344"),
"",
new ArrayList()
));
return response;
}
}

View File

@ -1,11 +0,0 @@
package cc.iotkit.tppa.xiaodu.handler;
public interface IRequestHandler<T, R> {
String getName();
Class getRequestType();
R handle(T request);
}

View File

@ -1,19 +0,0 @@
package cc.iotkit.tppa.xiaodu.request;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
public class DiscoverAppliancesRequest {
private Header header;
private Payload payload;
@EqualsAndHashCode(callSuper = true)
@Data
public static class Payload extends PayloadToken {
private String openUid;
}
}

View File

@ -1,17 +0,0 @@
package cc.iotkit.tppa.xiaodu.request;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Header {
private String namespace;
private String name;
private String messageId;
private String payloadVersion;
}

View File

@ -1,10 +0,0 @@
package cc.iotkit.tppa.xiaodu.request;
import lombok.Data;
@Data
public class PayloadToken {
protected String accessToken;
}

View File

@ -1,11 +0,0 @@
package cc.iotkit.tppa.xiaodu.request;
import lombok.Data;
@Data
public class TurnOnRequest {
private Header header;
}

View File

@ -1,128 +0,0 @@
package cc.iotkit.tppa.xiaodu.response;
import cc.iotkit.tppa.xiaodu.request.Header;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
@Data
public class DiscoverAppliancesResponse {
private Header header;
private Payload payload;
@Data
public static class Payload {
private List<DiscoveredAppliance> discoveredAppliances;
/**
* discoveredGroups
*
* []10
*/
private List<DiscoveredGroup> discoveredGroups;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class DiscoveredAppliance {
private List<String> actions;
/**
* discoveredAppliance.applianceTypes
*/
private String applianceTypes;
/**
*
*/
private String applianceId;
/**
* 使
*/
private String friendlyDescription;
/**
*
*/
private String friendlyName;
/**
* truefalse
*/
private boolean isReachable;
/**
*
*/
private String manufacturerName;
/**
* 128
*/
private String modelName;
/**
* 128
*/
private String version;
/**
* 10
*/
private List<Attribute> attributes;
/**
* 使DuerOS使
*/
private List additionalApplianceDetails=new ArrayList();
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Attribute {
/**
* 线128
*/
private String name;
/**
* json
*/
private String value;
/**
* 线128
*/
private String scale;
/**
*
*/
private Long timestampOfSample;
/**
* ms使uncertaintyInMilliseconds
* 11uncertaintyInMilliseconds1000
*/
private Long uncertaintyInMilliseconds;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class DiscoveredGroup{
/**
*
*/
private String groupName;
/**
* IDIDID
*/
private List<String> applianceIds;
/**
*
*/
private String groupNotes;
/**
* 使
*/
private List additionalGroupDetails;
}
}