diff --git a/.DS_Store b/.DS_Store index 7722cb09..112b470e 100755 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index 8da0c3c1..d9c4d48c 100755 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,5 @@ target *.iml *.yml log +components +data diff --git a/common/src/main/java/cc/iotkit/common/Constants.java b/common/src/main/java/cc/iotkit/common/Constants.java index f4a1987d..e5563376 100755 --- a/common/src/main/java/cc/iotkit/common/Constants.java +++ b/common/src/main/java/cc/iotkit/common/Constants.java @@ -2,7 +2,7 @@ package cc.iotkit.common; public interface Constants { - String MQTT_SECRET = "xdkKUymrEGSCYWswqCvSPyRSFvH5j7CU"; + String PRODUCT_SECRET = "xdkKUymrEGSCYWswqCvSPyRSFvH5j7CU"; String ACCOUNT_SECRET = "3n1z33kzvpgz1foijpkepyd3e8tw84us"; @@ -38,6 +38,11 @@ public interface Constants { */ String ROLE_ADMIN = "iot_admin"; + /** + * 可写角色 + */ + String ROLE_WRITE = "iot_write"; + /** * 管理系统用户角色 */ @@ -46,16 +51,26 @@ public interface Constants { /** * C端用户角色 */ - String ROLE_CLIENT= "iot_client_user"; + String ROLE_CLIENT = "iot_client_user"; /** * C端用户默认密码 */ - String PWD_CLIENT_USER="c123456"; + String PWD_CLIENT_USER = "c123456"; /** * 系统用户默认密码 */ - String PWD_SYSTEM_USER="s123456"; + String PWD_SYSTEM_USER = "s123456"; + + /** + * 设备原始上报消息的topic + */ + String DEVICE_RAW_MESSAGE_TOPIC = "device_raw"; + + /** + * 设备物模型消息的topic + */ + String THING_MODEL_MESSAGE_TOPIC = "device_thing"; } diff --git a/common/src/main/java/cc/iotkit/common/utils/DeviceUtil.java b/common/src/main/java/cc/iotkit/common/utils/DeviceUtil.java index 340e1233..747b5ecc 100755 --- a/common/src/main/java/cc/iotkit/common/utils/DeviceUtil.java +++ b/common/src/main/java/cc/iotkit/common/utils/DeviceUtil.java @@ -1,22 +1,26 @@ package cc.iotkit.common.utils; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; +import org.apache.commons.lang3.RandomUtils; +import org.apache.commons.lang3.StringUtils; public class DeviceUtil { - public static PkDn getPkDn(String pkDn) { - String[] arr = pkDn.split("/"); - return new PkDn(arr[0], arr[1]); + /** + * 1-13位 时间戳 + * 14-29位 deviceNae,去除非字母和数字,不足16位补0,超过16位的mac取后16位,共16位 + * 30-31位 mac长度,共2位 + * 32位 随机一个0-f字符 + */ + public static String newDeviceId(String deviceNae) { + int maxDnLen = 16; + String dn = deviceNae.replaceAll("[^0-9A-Za-z]", ""); + if (dn.length() > maxDnLen) { + dn = dn.substring(dn.length() - maxDnLen); + } else { + dn = (dn + "00000000000000000000").substring(0, maxDnLen); + } + String len = StringUtils.leftPad(deviceNae.length() + "", 2, '0'); + String rnd = Integer.toHexString(RandomUtils.nextInt(0, 16)); + return (System.currentTimeMillis() + "0" + dn + len + rnd).toLowerCase(); } - - @Data - @NoArgsConstructor - @AllArgsConstructor - public static class PkDn { - private String productKey; - private String deviceName; - } - } diff --git a/common/src/main/java/cc/iotkit/common/utils/JsonUtil.java b/common/src/main/java/cc/iotkit/common/utils/JsonUtil.java index c3b3365d..8bd2b5e2 100755 --- a/common/src/main/java/cc/iotkit/common/utils/JsonUtil.java +++ b/common/src/main/java/cc/iotkit/common/utils/JsonUtil.java @@ -5,8 +5,14 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import jdk.nashorn.api.scripting.ScriptObjectMirror; import lombok.SneakyThrows; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + public final class JsonUtil { private final static ObjectMapper MAPPER = new ObjectMapper() @@ -32,4 +38,33 @@ public final class JsonUtil { public static JsonNode parse(String json) { return MAPPER.readTree(json); } + + public static Object toObject(ScriptObjectMirror mirror) { + if (mirror.isEmpty()) { + return null; + } + if (mirror.isArray()) { + List list = new ArrayList<>(); + for (Map.Entry entry : mirror.entrySet()) { + Object result = entry.getValue(); + if (result instanceof ScriptObjectMirror) { + list.add(toObject((ScriptObjectMirror) result)); + } else { + list.add(result); + } + } + return list; + } + + Map map = new HashMap<>(); + for (Map.Entry entry : mirror.entrySet()) { + Object result = entry.getValue(); + if (result instanceof ScriptObjectMirror) { + map.put(entry.getKey(), toObject((ScriptObjectMirror) result)); + } else { + map.put(entry.getKey(), result); + } + } + return map; + } } diff --git a/common/src/main/java/cc/iotkit/common/utils/ThreadUtil.java b/common/src/main/java/cc/iotkit/common/utils/ThreadUtil.java new file mode 100755 index 00000000..bbe481d5 --- /dev/null +++ b/common/src/main/java/cc/iotkit/common/utils/ThreadUtil.java @@ -0,0 +1,25 @@ +package cc.iotkit.common.utils; + +import java.util.concurrent.ScheduledThreadPoolExecutor; + +public class ThreadUtil { + + public static ScheduledThreadPoolExecutor newScheduled(int poolSize, String threadName) { + return new ScheduledThreadPoolExecutor(poolSize, (Runnable r) -> { + SecurityManager s = System.getSecurityManager(); + ThreadGroup group = (s != null) ? s.getThreadGroup() : + Thread.currentThread().getThreadGroup(); + Thread t = new Thread(group, r, + threadName, + 0); + if (t.isDaemon()) { + t.setDaemon(false); + } + if (t.getPriority() != Thread.NORM_PRIORITY) { + t.setPriority(Thread.NORM_PRIORITY); + } + return t; + }); + } + +} diff --git a/dao/src/main/java/cc/iotkit/dao/AligenieDeviceRepository.java b/dao/src/main/java/cc/iotkit/dao/AligenieDeviceRepository.java index fa821f80..44e2f25b 100755 --- a/dao/src/main/java/cc/iotkit/dao/AligenieDeviceRepository.java +++ b/dao/src/main/java/cc/iotkit/dao/AligenieDeviceRepository.java @@ -15,4 +15,6 @@ public interface AligenieDeviceRepository extends MongoRepository findByDeviceId(String deviceId); + } diff --git a/dao/src/main/java/cc/iotkit/dao/AligenieProductDao.java b/dao/src/main/java/cc/iotkit/dao/AligenieProductDao.java deleted file mode 100755 index 2a1d648e..00000000 --- a/dao/src/main/java/cc/iotkit/dao/AligenieProductDao.java +++ /dev/null @@ -1,28 +0,0 @@ -package cc.iotkit.dao; - -import cc.iotkit.model.aligenie.AligenieProduct; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.data.domain.Example; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.stereotype.Repository; - -@Repository -public class AligenieProductDao extends BaseDao { - - private final AligenieProductRepository aligenieProductRepository; - - @Autowired - public AligenieProductDao(MongoTemplate mongoTemplate, - AligenieProductRepository aligenieProductRepository) { - super(mongoTemplate, AligenieProduct.class); - this.aligenieProductRepository = aligenieProductRepository; - } - - @Cacheable(value = "cache_getAligenieProduct", key = "'getAligenieProduct'+#pk", unless = "#result == null") - public AligenieProduct getAligenieProduct(String pk) { - return aligenieProductRepository.findOne(Example.of( - AligenieProduct.builder().productKey(pk).build() - )).orElse(null); - } -} diff --git a/dao/src/main/java/cc/iotkit/dao/BaseDao.java b/dao/src/main/java/cc/iotkit/dao/BaseDao.java deleted file mode 100755 index 96773013..00000000 --- a/dao/src/main/java/cc/iotkit/dao/BaseDao.java +++ /dev/null @@ -1,59 +0,0 @@ -package cc.iotkit.dao; - -import org.springframework.data.domain.Sort; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.query.Criteria; -import org.springframework.data.mongodb.core.query.Query; - -import java.util.List; - -import static org.springframework.data.mongodb.core.query.Criteria.where; -import static org.springframework.data.mongodb.core.query.Query.query; - -public class BaseDao { - - protected MongoTemplate mongoTemplate; - - private Class cls; - - public BaseDao(MongoTemplate mongoTemplate, Class cls) { - this.mongoTemplate = mongoTemplate; - this.cls = cls; - } - - public List find(Criteria condition) { - Query query = new Query(); - query.addCriteria(condition); - return mongoTemplate.find(query, cls); - } - - public List find(Criteria condition, long skip, int count, Sort.Order order) { - Query query = new Query(); - query.addCriteria(condition) - .with(Sort.by(order)) - .skip(skip) - .limit(count); - return mongoTemplate.find(query, cls); - } - - public long count(Criteria condition) { - Query query = new Query(); - query.addCriteria(condition); - return mongoTemplate.count(query, cls); - } - - public T save(String id, T entity) { - if (id == null) { - return mongoTemplate.save(entity); - } else { - mongoTemplate.updateFirst(query(where("_id").is(id)), - DaoTool.update(entity), entity.getClass()); - return (T) mongoTemplate.findById(id, entity.getClass()); - } - } - - public T save(T entity) { - return mongoTemplate.save(entity); - } - -} diff --git a/dao/src/main/java/cc/iotkit/dao/DeviceCache.java b/dao/src/main/java/cc/iotkit/dao/DeviceCache.java new file mode 100755 index 00000000..7464b4fb --- /dev/null +++ b/dao/src/main/java/cc/iotkit/dao/DeviceCache.java @@ -0,0 +1,29 @@ +package cc.iotkit.dao; + +import cc.iotkit.common.Constants; +import cc.iotkit.model.device.DeviceInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Repository; + +@Repository +public class DeviceCache { + + @Autowired + private DeviceRepository deviceRepository; + + @Cacheable(value = Constants.DEVICE_CACHE, key = "#pk+'_'+#dn") + public DeviceInfo findByProductKeyAndDeviceName(String pk, String dn) { + return deviceRepository.findByProductKeyAndDeviceName(pk, dn); + } + + @Cacheable(value = Constants.DEVICE_CACHE, key = "#deviceId") + public DeviceInfo findByDeviceId(String deviceId) { + return deviceRepository.findByDeviceId(deviceId); + } + + @Cacheable(value = Constants.DEVICE_CACHE, key = "#deviceId") + public DeviceInfo get(String deviceId) { + return deviceRepository.findById(deviceId).orElse(new DeviceInfo()); + } +} diff --git a/dao/src/main/java/cc/iotkit/dao/DeviceDao.java b/dao/src/main/java/cc/iotkit/dao/DeviceDao.java index 1d34e2b9..831fa9aa 100755 --- a/dao/src/main/java/cc/iotkit/dao/DeviceDao.java +++ b/dao/src/main/java/cc/iotkit/dao/DeviceDao.java @@ -1,62 +1,67 @@ package cc.iotkit.dao; -import cc.iotkit.common.Constants; +import cc.iotkit.model.Paging; import cc.iotkit.model.device.DeviceInfo; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; +import org.springframework.data.mongodb.core.query.Update; import org.springframework.stereotype.Repository; -import static org.springframework.data.mongodb.core.query.Criteria.where; -import static org.springframework.data.mongodb.core.query.Query.query; +import java.util.Map; @Repository -public class DeviceDao extends BaseDao { +public class DeviceDao { @Autowired - private DeviceRepository deviceRepository; + private MongoTemplate mongoTemplate; - @Autowired - public DeviceDao(MongoTemplate mongoTemplate) { - super(mongoTemplate, DeviceInfo.class); + public Paging find(Criteria condition, int size, int page) { + Query query = Query.query(condition); + return new Paging<>( + mongoTemplate.count(query, DeviceInfo.class), + mongoTemplate.find( + query.with(PageRequest.of(page - 1, size, Sort.by(Sort.Order.desc("createAt")))) + , DeviceInfo.class) + ); } - public void addDevice(DeviceInfo device) { - device.setCreateAt(System.currentTimeMillis()); - mongoTemplate.insert(device); - } - - public void updateDevice(DeviceInfo device) { - if (device.getDeviceId() == null) { + /** + * 更新设备属性 + */ + public void updateProperties(String deviceId, Map properties) { + if (properties == null) { return; } - mongoTemplate.updateFirst(query(where("deviceId").is(device.getDeviceId())), - DaoTool.update(device), DeviceInfo.class); - } - - public void updateDeviceByPkAndDn(DeviceInfo device) { - if (device.getProductKey() == null || device.getDeviceName() == null) { - return; + Query query = Query.query(new Criteria().and("deviceId").is(deviceId)); + Update update = new Update(); + for (String key : properties.keySet()) { + update.set("property." + key, properties.get(key)); } - mongoTemplate.updateFirst(query(where("productKey").is(device.getProductKey()). - and("deviceName").is(device.getDeviceName())), - DaoTool.update(device), DeviceInfo.class); + mongoTemplate.updateFirst(query, update, DeviceInfo.class); } - @Cacheable(value = "deviceInfoCache", key = "#pk+'_'+#dn") - public DeviceInfo getByPkAndDn(String pk, String dn) { - Query query = query(where("productKey").is(pk).and("deviceName").is(dn)); - return mongoTemplate.findOne(query, DeviceInfo.class); + /** + * 更新设备标签 + */ + public void updateTag(String deviceId, DeviceInfo.Tag tag) { + Query query = Query.query(new Criteria().and("deviceId").is(deviceId)); + Update update = new Update(); + update.set("tag." + tag.getId(), tag); + mongoTemplate.updateFirst(query, update, DeviceInfo.class); } - public DeviceInfo getByDeviceId(String deviceId) { - Query query = query(where("deviceId").is(deviceId)); - return mongoTemplate.findOne(query, DeviceInfo.class); + /** + * 设置设备标签值为空 + */ + public void setTagNull(String deviceId, String tagId) { + Query query = Query.query(new Criteria().and("deviceId").is(deviceId)); + Update update = new Update(); + update.set("tag." + tagId, null); + mongoTemplate.updateFirst(query, update, DeviceInfo.class); } - @Cacheable(value = Constants.DEVICE_CACHE, key = "#deviceId") - public DeviceInfo get(String deviceId) { - return deviceRepository.findById(deviceId).orElse(new DeviceInfo()); - } } diff --git a/dao/src/main/java/cc/iotkit/dao/DeviceEventDao.java b/dao/src/main/java/cc/iotkit/dao/DeviceEventDao.java deleted file mode 100755 index 15e9e56f..00000000 --- a/dao/src/main/java/cc/iotkit/dao/DeviceEventDao.java +++ /dev/null @@ -1,15 +0,0 @@ -package cc.iotkit.dao; - -import cc.iotkit.model.device.message.DeviceEvent; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.stereotype.Repository; - -@Repository -public class DeviceEventDao extends BaseDao { - - @Autowired - public DeviceEventDao(MongoTemplate mongoTemplate) { - super(mongoTemplate, DeviceEvent.class); - } -} diff --git a/dao/src/main/java/cc/iotkit/dao/DevicePropertyDao.java b/dao/src/main/java/cc/iotkit/dao/DevicePropertyDao.java new file mode 100755 index 00000000..7db9cc80 --- /dev/null +++ b/dao/src/main/java/cc/iotkit/dao/DevicePropertyDao.java @@ -0,0 +1,40 @@ +package cc.iotkit.dao; + +import cc.iotkit.model.device.message.DeviceProperty; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.search.sort.FieldSortBuilder; +import org.elasticsearch.search.sort.SortOrder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; +import org.springframework.data.elasticsearch.core.SearchHit; +import org.springframework.data.elasticsearch.core.SearchHits; +import org.springframework.data.elasticsearch.core.query.NativeSearchQuery; +import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.stream.Collectors; + +@Repository +public class DevicePropertyDao { + + @Autowired + private ElasticsearchRestTemplate template; + + public List findDevicePropertyHistory(String deviceId, String name, long start, long end) { + NativeSearchQuery query = new NativeSearchQueryBuilder() + .withQuery( + QueryBuilders.boolQuery() + .must(QueryBuilders.termQuery("deviceId", deviceId)) + .must(QueryBuilders.termQuery("name", name.toLowerCase())) + .must(QueryBuilders.rangeQuery("time") + .from(start, true).to(end, true)) + ) + .withSorts(new FieldSortBuilder("time").order(SortOrder.ASC)) + .build(); + SearchHits result = template.search(query, DeviceProperty.class); + return result.getSearchHits().stream() + .map(SearchHit::getContent).collect(Collectors.toList()); + } + +} diff --git a/dao/src/main/java/cc/iotkit/dao/DevicePropertyRepository.java b/dao/src/main/java/cc/iotkit/dao/DevicePropertyRepository.java new file mode 100755 index 00000000..3300b370 --- /dev/null +++ b/dao/src/main/java/cc/iotkit/dao/DevicePropertyRepository.java @@ -0,0 +1,11 @@ +package cc.iotkit.dao; + +import cc.iotkit.model.device.message.DeviceProperty; +import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface DevicePropertyRepository extends ElasticsearchRepository { + + +} diff --git a/dao/src/main/java/cc/iotkit/dao/DeviceRepository.java b/dao/src/main/java/cc/iotkit/dao/DeviceRepository.java index d19b3170..14a98cd2 100755 --- a/dao/src/main/java/cc/iotkit/dao/DeviceRepository.java +++ b/dao/src/main/java/cc/iotkit/dao/DeviceRepository.java @@ -4,6 +4,15 @@ import cc.iotkit.model.device.DeviceInfo; import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface DeviceRepository extends MongoRepository { + + DeviceInfo findByProductKeyAndDeviceName(String productKey, String deviceName); + + DeviceInfo findByDeviceId(String deviceId); + + List findByParentId(String parentId); + } diff --git a/dao/src/main/java/cc/iotkit/dao/ProductDao.java b/dao/src/main/java/cc/iotkit/dao/ProductCache.java similarity index 55% rename from dao/src/main/java/cc/iotkit/dao/ProductDao.java rename to dao/src/main/java/cc/iotkit/dao/ProductCache.java index 18bd810f..db78ee01 100755 --- a/dao/src/main/java/cc/iotkit/dao/ProductDao.java +++ b/dao/src/main/java/cc/iotkit/dao/ProductCache.java @@ -5,25 +5,23 @@ import cc.iotkit.model.product.Product; import cc.iotkit.model.product.ThingModel; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.Cacheable; -import org.springframework.data.domain.Example; import org.springframework.stereotype.Repository; @Repository -public class ProductDao { +public class ProductCache { @Autowired private ProductRepository productRepository; @Autowired private ThingModelRepository thingModelRepository; - @Cacheable(value = Constants.PRODUCT_CACHE, key = "'getProductById'+#pk", unless = "#result == null") - public Product get(String pk) { + @Cacheable(value = Constants.PRODUCT_CACHE, key = "'pk'+#pk", unless = "#result == null") + public Product findById(String pk) { return productRepository.findById(pk).orElse(new Product()); } - @Cacheable(value = Constants.THING_MODEL_CACHE, key = "'getThingModel'+#pk", unless = "#result == null") + @Cacheable(value = Constants.THING_MODEL_CACHE, key = "'pk'+#pk", unless = "#result == null") public ThingModel getThingModel(String pk) { - return thingModelRepository.findOne(Example.of(ThingModel.builder() - .productKey(pk).build())).orElse(new ThingModel()); + return thingModelRepository.findByProductKey(pk); } } diff --git a/dao/src/main/java/cc/iotkit/dao/ProtocolComponentRepository.java b/dao/src/main/java/cc/iotkit/dao/ProtocolComponentRepository.java new file mode 100755 index 00000000..2da53005 --- /dev/null +++ b/dao/src/main/java/cc/iotkit/dao/ProtocolComponentRepository.java @@ -0,0 +1,14 @@ +package cc.iotkit.dao; + +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 { + + List findByState(String state); + +} diff --git a/dao/src/main/java/cc/iotkit/dao/SceneInfoRepository.java b/dao/src/main/java/cc/iotkit/dao/ProtocolConverterRepository.java similarity index 51% rename from dao/src/main/java/cc/iotkit/dao/SceneInfoRepository.java rename to dao/src/main/java/cc/iotkit/dao/ProtocolConverterRepository.java index 0670944f..336d2aaf 100755 --- a/dao/src/main/java/cc/iotkit/dao/SceneInfoRepository.java +++ b/dao/src/main/java/cc/iotkit/dao/ProtocolConverterRepository.java @@ -1,9 +1,9 @@ package cc.iotkit.dao; -import cc.iotkit.model.rule.SceneInfo; +import cc.iotkit.model.protocol.ProtocolConverter; import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.stereotype.Repository; @Repository -public interface SceneInfoRepository extends MongoRepository { +public interface ProtocolConverterRepository extends MongoRepository { } diff --git a/dao/src/main/java/cc/iotkit/dao/SceneLogRepository.java b/dao/src/main/java/cc/iotkit/dao/ProtocolGatewayRepository.java similarity index 51% rename from dao/src/main/java/cc/iotkit/dao/SceneLogRepository.java rename to dao/src/main/java/cc/iotkit/dao/ProtocolGatewayRepository.java index eee529e8..8248a283 100755 --- a/dao/src/main/java/cc/iotkit/dao/SceneLogRepository.java +++ b/dao/src/main/java/cc/iotkit/dao/ProtocolGatewayRepository.java @@ -1,9 +1,11 @@ package cc.iotkit.dao; -import cc.iotkit.model.rule.SceneLog; +import cc.iotkit.model.protocol.ProtocolComponent; import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.stereotype.Repository; @Repository -public interface SceneLogRepository extends MongoRepository { +public interface ProtocolGatewayRepository extends MongoRepository { + + } diff --git a/dao/src/main/java/cc/iotkit/dao/RuleInfoRepository.java b/dao/src/main/java/cc/iotkit/dao/RuleInfoRepository.java new file mode 100755 index 00000000..de4e6020 --- /dev/null +++ b/dao/src/main/java/cc/iotkit/dao/RuleInfoRepository.java @@ -0,0 +1,14 @@ +package cc.iotkit.dao; + +import cc.iotkit.model.rule.RuleInfo; +import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface RuleInfoRepository extends MongoRepository { + + List findByUidAndType(String uid, String type); + +} diff --git a/dao/src/main/java/cc/iotkit/dao/RuleLogRepository.java b/dao/src/main/java/cc/iotkit/dao/RuleLogRepository.java new file mode 100755 index 00000000..2ada4aaa --- /dev/null +++ b/dao/src/main/java/cc/iotkit/dao/RuleLogRepository.java @@ -0,0 +1,16 @@ +package cc.iotkit.dao; + +import cc.iotkit.model.rule.RuleLog; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface RuleLogRepository extends ElasticsearchRepository { + + void deleteByRuleId(String ruleId); + + Page findByRuleId(String ruleId, Pageable pageable); + +} diff --git a/dao/src/main/java/cc/iotkit/dao/SceneLogDao.java b/dao/src/main/java/cc/iotkit/dao/SceneLogDao.java deleted file mode 100755 index c53d722b..00000000 --- a/dao/src/main/java/cc/iotkit/dao/SceneLogDao.java +++ /dev/null @@ -1,22 +0,0 @@ -package cc.iotkit.dao; - -import cc.iotkit.model.rule.SceneLog; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.query.Query; -import org.springframework.stereotype.Repository; - -import static org.springframework.data.mongodb.core.query.Criteria.where; - -@Repository -public class SceneLogDao extends BaseDao { - - @Autowired - public SceneLogDao(MongoTemplate mongoTemplate) { - super(mongoTemplate, SceneLog.class); - } - - public void deleteLogs(String sceneId) { - this.mongoTemplate.remove(Query.query(where("sceneId").is(sceneId)), SceneLog.class); - } -} diff --git a/dao/src/main/java/cc/iotkit/dao/TaskLogDao.java b/dao/src/main/java/cc/iotkit/dao/TaskLogDao.java deleted file mode 100755 index ee780dbc..00000000 --- a/dao/src/main/java/cc/iotkit/dao/TaskLogDao.java +++ /dev/null @@ -1,22 +0,0 @@ -package cc.iotkit.dao; - -import cc.iotkit.model.rule.TaskLog; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.query.Query; -import org.springframework.stereotype.Repository; - -import static org.springframework.data.mongodb.core.query.Criteria.where; - -@Repository -public class TaskLogDao extends BaseDao { - - @Autowired - public TaskLogDao(MongoTemplate mongoTemplate) { - super(mongoTemplate, TaskLog.class); - } - - public void deleteLogs(String taskId) { - this.mongoTemplate.remove(Query.query(where("taskId").is(taskId)), TaskLog.class); - } -} diff --git a/dao/src/main/java/cc/iotkit/dao/TaskLogRepository.java b/dao/src/main/java/cc/iotkit/dao/TaskLogRepository.java index c197c13f..ddf2bbab 100755 --- a/dao/src/main/java/cc/iotkit/dao/TaskLogRepository.java +++ b/dao/src/main/java/cc/iotkit/dao/TaskLogRepository.java @@ -1,9 +1,16 @@ package cc.iotkit.dao; import cc.iotkit.model.rule.TaskLog; -import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; import org.springframework.stereotype.Repository; @Repository -public interface TaskLogRepository extends MongoRepository { +public interface TaskLogRepository extends ElasticsearchRepository { + + void deleteByTaskId(String taskId); + + Page findByTaskId(String taskId, Pageable pageable); + } diff --git a/dao/src/main/java/cc/iotkit/dao/ThingModelMessageDao.java b/dao/src/main/java/cc/iotkit/dao/ThingModelMessageDao.java new file mode 100755 index 00000000..2b06157f --- /dev/null +++ b/dao/src/main/java/cc/iotkit/dao/ThingModelMessageDao.java @@ -0,0 +1,45 @@ +package cc.iotkit.dao; + +import cc.iotkit.model.Paging; +import cc.iotkit.model.device.message.ThingModelMessage; +import org.apache.commons.lang3.StringUtils; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; +import org.springframework.data.elasticsearch.core.SearchHit; +import org.springframework.data.elasticsearch.core.SearchHits; +import org.springframework.data.elasticsearch.core.query.NativeSearchQuery; +import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; +import org.springframework.stereotype.Repository; + +import java.util.stream.Collectors; + +@Repository +public class ThingModelMessageDao { + + @Autowired + private ElasticsearchRestTemplate template; + + public Paging findByTypeAndIdentifier(String deviceId, String type, + String identifier, + int page, int size) { + BoolQueryBuilder builder = QueryBuilders.boolQuery(); + builder.must(QueryBuilders.termQuery("deviceId", deviceId)); + if (StringUtils.isNotBlank(type)) { + builder.must(QueryBuilders.termQuery("type", type)); + } + if (StringUtils.isNotBlank(identifier)) { + builder.must(QueryBuilders.matchPhraseQuery("identifier", identifier)); + } + NativeSearchQuery query = new NativeSearchQueryBuilder().withQuery(builder) + .withPageable(PageRequest.of(page, size, Sort.by(Sort.Order.desc("time")))) + .build(); + SearchHits result = template.search(query, ThingModelMessage.class); + return new Paging<>(result.getTotalHits(), result.getSearchHits().stream() + .map(SearchHit::getContent).collect(Collectors.toList())); + } + +} diff --git a/dao/src/main/java/cc/iotkit/dao/ThingModelMessageRepository.java b/dao/src/main/java/cc/iotkit/dao/ThingModelMessageRepository.java new file mode 100755 index 00000000..5e95e53d --- /dev/null +++ b/dao/src/main/java/cc/iotkit/dao/ThingModelMessageRepository.java @@ -0,0 +1,14 @@ +package cc.iotkit.dao; + +import cc.iotkit.model.device.message.ThingModelMessage; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ThingModelMessageRepository extends ElasticsearchRepository { + + Page findByTypeAndIdentifier(String type, String identifier, Pageable pageable); + +} diff --git a/dao/src/main/java/cc/iotkit/dao/ThingModelRepository.java b/dao/src/main/java/cc/iotkit/dao/ThingModelRepository.java index 16612cb5..880adb47 100755 --- a/dao/src/main/java/cc/iotkit/dao/ThingModelRepository.java +++ b/dao/src/main/java/cc/iotkit/dao/ThingModelRepository.java @@ -6,4 +6,7 @@ import org.springframework.stereotype.Repository; @Repository public interface ThingModelRepository extends MongoRepository { + + ThingModel findByProductKey(String productKey); + } diff --git a/dao/src/main/java/cc/iotkit/dao/UserInfoDao.java b/dao/src/main/java/cc/iotkit/dao/UserInfoDao.java deleted file mode 100755 index 0b9b2151..00000000 --- a/dao/src/main/java/cc/iotkit/dao/UserInfoDao.java +++ /dev/null @@ -1,15 +0,0 @@ -package cc.iotkit.dao; - -import cc.iotkit.model.UserInfo; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.stereotype.Repository; - -@Repository -public class UserInfoDao extends BaseDao { - - @Autowired - public UserInfoDao(MongoTemplate mongoTemplate) { - super(mongoTemplate, UserInfo.class); - } -} diff --git a/dao/src/main/java/cc/iotkit/dao/UserInfoRepository.java b/dao/src/main/java/cc/iotkit/dao/UserInfoRepository.java index e58f2c5c..afeece71 100755 --- a/dao/src/main/java/cc/iotkit/dao/UserInfoRepository.java +++ b/dao/src/main/java/cc/iotkit/dao/UserInfoRepository.java @@ -4,6 +4,13 @@ import cc.iotkit.model.UserInfo; import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface UserInfoRepository extends MongoRepository { + + List findByType(int type); + + List findByTypeAndOwnerId(int type, String ownerId); + } diff --git a/dao/src/main/java/cc/iotkit/dao/config/ElasticsearchConfiguration.java b/dao/src/main/java/cc/iotkit/dao/config/ElasticsearchConfiguration.java new file mode 100644 index 00000000..3c87b0b7 --- /dev/null +++ b/dao/src/main/java/cc/iotkit/dao/config/ElasticsearchConfiguration.java @@ -0,0 +1,15 @@ +package cc.iotkit.dao.config; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.context.annotation.Lazy; +import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; +import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories; + +@Lazy +@Configuration +@EnableElasticsearchRepositories(basePackages = "cc.iotkit.dao", includeFilters = +@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = ElasticsearchRepository.class)) +public class ElasticsearchConfiguration { +} diff --git a/dao/src/main/java/cc/iotkit/dao/config/RepositoryConfig.java b/dao/src/main/java/cc/iotkit/dao/config/RepositoryConfig.java index 9d5dc24e..c7a636be 100755 --- a/dao/src/main/java/cc/iotkit/dao/config/RepositoryConfig.java +++ b/dao/src/main/java/cc/iotkit/dao/config/RepositoryConfig.java @@ -1,19 +1,24 @@ package cc.iotkit.dao.config; import org.springframework.beans.factory.BeanFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; +import org.springframework.context.annotation.*; import org.springframework.data.convert.CustomConversions; import org.springframework.data.mongodb.MongoDatabaseFactory; -import org.springframework.data.mongodb.core.convert.DbRefResolver; -import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver; -import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper; -import org.springframework.data.mongodb.core.convert.MappingMongoConverter; +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.convert.*; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; +import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; +import java.util.Collections; + @Configuration -@EnableMongoRepositories(basePackages = "cc.iotkit.dao") +@Import(value = MongoAutoConfiguration.class) +@EnableMongoRepositories(basePackages = "cc.iotkit.dao", includeFilters = @ComponentScan.Filter( + type = FilterType.ASSIGNABLE_TYPE, value = MongoRepository.class)) public class RepositoryConfig { @Bean @@ -28,4 +33,16 @@ public class RepositoryConfig { return mappingMongoConverter; } + @Bean + @ConditionalOnMissingBean({MongoOperations.class}) + MongoTemplate mongoTemplate(MongoDatabaseFactory factory, MongoConverter converter) { + return new MongoTemplate(factory, converter); + } + + @Bean + @Primary + MongoCustomConversions mongoCustomConversions() { + return new MongoCustomConversions(Collections.emptyList()); + } + } diff --git a/device-server/device-api/src/main/java/cc/iotkit/deviceapi/IDeviceManager.java b/device-server/device-api/src/main/java/cc/iotkit/deviceapi/IDeviceManager.java deleted file mode 100755 index 8e8087c7..00000000 --- a/device-server/device-api/src/main/java/cc/iotkit/deviceapi/IDeviceManager.java +++ /dev/null @@ -1,44 +0,0 @@ -package cc.iotkit.deviceapi; - -import cc.iotkit.model.device.DeviceInfo; -import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.stereotype.Component; -import org.springframework.web.bind.annotation.*; - -import java.util.Map; - -@Component -@FeignClient(value = "iot-device-manager",url = "localhost:8091") -public interface IDeviceManager { - - /** - * 设备注册 - */ - @PostMapping("/register") - @ResponseBody - DeviceInfo register(@RequestParam("parentId") String parentId, - @RequestParam("productKey") String productKey, - @RequestParam("deviceName") String deviceName, - @RequestParam("model") String model); - - /** - * 解绑子设备 - */ - @PostMapping("/{deviceId}/unbind") - void unbind(@PathVariable("deviceId") String deviceId); - - /** - * 设置属性 - */ - @PostMapping("/{deviceId}/property/set") - String setProperty(@PathVariable("deviceId") String deviceId, - @RequestBody Map properties); - - /** - * 调用服务 - */ - @PostMapping("/{deviceId}/{identifier}/invoke") - String invokeService(@PathVariable("deviceId") String deviceId, - @PathVariable("identifier") String identifier, - @RequestBody Map properties); -} diff --git a/device-server/device-api/src/main/java/cc/iotkit/deviceapi/IDeviceService.java b/device-server/device-api/src/main/java/cc/iotkit/deviceapi/IDeviceService.java deleted file mode 100755 index d98a44b3..00000000 --- a/device-server/device-api/src/main/java/cc/iotkit/deviceapi/IDeviceService.java +++ /dev/null @@ -1,16 +0,0 @@ -package cc.iotkit.deviceapi; - -import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.stereotype.Component; -import org.springframework.web.bind.annotation.*; - -@Component -@FeignClient(value = "iot-device-service", url = "localhost:8091") -public interface IDeviceService { - - /** - * 调用服务 - */ - @PostMapping("/invoke") - String invoke(@RequestBody Service service); -} diff --git a/device-server/device-api/src/main/java/cc/iotkit/deviceapi/Service.java b/device-server/device-api/src/main/java/cc/iotkit/deviceapi/Service.java deleted file mode 100755 index 7501e1b8..00000000 --- a/device-server/device-api/src/main/java/cc/iotkit/deviceapi/Service.java +++ /dev/null @@ -1,31 +0,0 @@ -package cc.iotkit.deviceapi; - -import lombok.Data; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@Data -public class Service { - - private String device; - - private String identifier; - - private List inputData; - - public Map parseInputData() { - Map data = new HashMap<>(); - for (Parameter p : inputData) { - data.put(p.getIdentifier(), p.getValue()); - } - return data; - } - - @Data - public static class Parameter { - private String identifier; - private Object value; - } -} diff --git a/device-server/mqtt-auth/pom.xml b/device-server/mqtt-auth/pom.xml deleted file mode 100755 index 4b942648..00000000 --- a/device-server/mqtt-auth/pom.xml +++ /dev/null @@ -1,95 +0,0 @@ - - - - device-server - cc.iotkit - 0.0.1-SNAPSHOT - - 4.0.0 - - mqtt-auth - - - - org.springframework.boot - spring-boot-starter-data-mongodb - - - - org.springframework.boot - spring-boot-starter-web - - - - com.github.ben-manes.caffeine - caffeine - - - - org.projectlombok - lombok - true - - - - org.apache.commons - commons-lang3 - - - - commons-codec - commons-codec - - - - commons-beanutils - commons-beanutils - - - - org.bouncycastle - bcprov-jdk15on - - - - joda-time - joda-time - - - - cc.iotkit - common - - - - cc.iotkit - model - - - junit - junit - test - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - - - - - - \ No newline at end of file diff --git a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/Application.java b/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/Application.java deleted file mode 100755 index 5ab5413a..00000000 --- a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/Application.java +++ /dev/null @@ -1,12 +0,0 @@ -package cc.iotkit.mqttauth; - -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); - } -} diff --git a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/controller/MqttAuthController.java b/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/controller/MqttAuthController.java deleted file mode 100755 index 3806f20e..00000000 --- a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/controller/MqttAuthController.java +++ /dev/null @@ -1,84 +0,0 @@ -package cc.iotkit.mqttauth.controller; - - -import cc.iotkit.common.Constants; -import cc.iotkit.common.utils.CodecUtil; -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.mqttauth.model.EmqAcl; -import cc.iotkit.mqttauth.model.EmqAuthInfo; -import cc.iotkit.mqttauth.service.DeviceMqttAuth; -import cc.iotkit.mqttauth.service.MqttAuth; -import cc.iotkit.mqttauth.service.SysMqttAuth; -import cc.iotkit.mqttauth.service.WxMqttAuth; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; - -import javax.servlet.http.HttpServletResponse; - -@Slf4j -@RestController -public class MqttAuthController { - - @Autowired - private DeviceMqttAuth deviceMqttAuth; - @Autowired - private WxMqttAuth wxMqttAuth; - @Autowired - private SysMqttAuth sysMqttAuth; - - @PostMapping("/mqtt/auth") - public void auth(@RequestBody EmqAuthInfo auth) { - log.info("mqtt auth:" + JsonUtil.toJsonString(auth)); - String clientId = auth.getClientid(); - if (isSupperUser(clientId)) { - return; - } - MqttAuth mqttAuth = getMqttAuth(clientId); - mqttAuth.auth(auth); - } - - @PostMapping("/mqtt/acl") - public void acl(@RequestBody EmqAcl acl) { - log.info("mqtt acl:" + JsonUtil.toJsonString(acl)); - if (isSupperUser(acl.getClientid())) { - return; - } - MqttAuth mqttAuth = getMqttAuth(acl.getClientid()); - mqttAuth.acl(acl); - } - - @PostMapping("/mqtt/superuser") - public void superuser(@RequestBody EmqAcl acl, HttpServletResponse response) { - response.setStatus(HttpServletResponse.SC_BAD_GATEWAY); -// log.info("mqtt superuser:" + JsonUtil.toJsonString(acl)); -// if (!isSupperUser(acl.getClientid())) { -// throw new RuntimeException("superuser check false."); -// } - } - - public boolean isSupperUser(String clientId) { - try { - if (!clientId.startsWith("su_")) { - return false; - } - clientId = clientId.replaceFirst("su_", ""); - return CodecUtil.aesDecrypt(clientId, Constants.MQTT_SECRET).startsWith("admin_"); - } catch (Throwable e) { - log.error("aesDecrypt error.", e); - return false; - } - } - - private MqttAuth getMqttAuth(String clientId) { - if (clientId.startsWith("wx_")) { - return wxMqttAuth; - } else if (clientId.startsWith("sy_")) { - return sysMqttAuth; - } - return deviceMqttAuth; - } - -} diff --git a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/dao/DaoTool.java b/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/dao/DaoTool.java deleted file mode 100755 index 74f8b660..00000000 --- a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/dao/DaoTool.java +++ /dev/null @@ -1,53 +0,0 @@ -package cc.iotkit.mqttauth.dao; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.SneakyThrows; -import org.apache.commons.beanutils.BeanMap; -import org.springframework.data.mongodb.core.query.Update; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -public class DaoTool { - - public static void update(Update update, List props) { - for (Prop pro : props) { - update.set(pro.getName(), pro.getValue()); - } - } - - public static List getProp(String key, Object value) { - List props = new ArrayList<>(); - if (value instanceof Map) { - Set> entrySet = ((Map) value).entrySet(); - for (Map.Entry entry : entrySet) { - props.addAll(getProp(key + "." + entry.getKey(), entry.getValue())); - } - } else if (value != null && !(value instanceof Class)) { - props.add(new Prop(key, value)); - } - return props; - } - - @SneakyThrows - public static Update update(T obj) { - Map pros = new BeanMap(obj); - Update update = new Update(); - for (Map.Entry entry : pros.entrySet()) { - update(update, DaoTool.getProp(entry.getKey().toString(), entry.getValue())); - } - return update; - } - - @Data - @AllArgsConstructor - @NoArgsConstructor - static class Prop { - private String name; - private Object value; - } -} diff --git a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/dao/DeviceDao.java b/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/dao/DeviceDao.java deleted file mode 100755 index c3fbfd5e..00000000 --- a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/dao/DeviceDao.java +++ /dev/null @@ -1,53 +0,0 @@ -package cc.iotkit.mqttauth.dao; - -import cc.iotkit.model.device.DeviceInfo; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.query.Query; -import org.springframework.stereotype.Repository; - -import javax.annotation.Resource; - -import static org.springframework.data.mongodb.core.query.Criteria.where; -import static org.springframework.data.mongodb.core.query.Query.query; - -@Repository -public class DeviceDao { - - @Resource - private MongoTemplate mongoTemplate; - - public void addDevice(DeviceInfo device) { - device.setId(device.getDeviceId()); - device.setCreateAt(System.currentTimeMillis()); - mongoTemplate.insert(device); - } - - public void updateDevice(DeviceInfo device) { - if (device.getDeviceId() == null) { - return; - } - mongoTemplate.updateFirst(query(where("deviceId").is(device.getDeviceId())), - DaoTool.update(device), DeviceInfo.class); - } - - public void updateDeviceByPkAndDn(DeviceInfo device) { - if (device.getProductKey() == null || device.getDeviceName() == null) { - return; - } - mongoTemplate.updateFirst(query(where("productKey").is(device.getProductKey()). - and("deviceName").is(device.getDeviceName())), - DaoTool.update(device), DeviceInfo.class); - } - - @Cacheable(value = "deviceInfoCache", key = "#pk+'_'+#dn") - public DeviceInfo getByPkAndDn(String pk, String dn) { - Query query = query(where("productKey").is(pk).and("deviceName").is(dn)); - return mongoTemplate.findOne(query, DeviceInfo.class); - } - - public DeviceInfo getByDeviceId(String deviceId) { - Query query = query(where("deviceId").is(deviceId)); - return mongoTemplate.findOne(query, DeviceInfo.class); - } -} diff --git a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/dao/ProductDao.java b/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/dao/ProductDao.java deleted file mode 100755 index f1782be6..00000000 --- a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/dao/ProductDao.java +++ /dev/null @@ -1,23 +0,0 @@ -package cc.iotkit.mqttauth.dao; - -import cc.iotkit.model.product.Product; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.query.Query; -import org.springframework.stereotype.Repository; - -import javax.annotation.Resource; - -import static org.springframework.data.mongodb.core.query.Criteria.where; -import static org.springframework.data.mongodb.core.query.Query.query; - -@Repository -public class ProductDao { - - @Resource - private MongoTemplate mongoTemplate; - - public Product getProduct(String pk) { - Query query = query(where("code").is(pk)); - return mongoTemplate.findOne(query, Product.class); - } -} diff --git a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/model/EmqAcl.java b/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/model/EmqAcl.java deleted file mode 100755 index 8fd1138f..00000000 --- a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/model/EmqAcl.java +++ /dev/null @@ -1,19 +0,0 @@ -package cc.iotkit.mqttauth.model; - -import lombok.Data; - -@Data -public class EmqAcl { - - private String access; - - private String username; - - private String clientid; - - private String ipaddr; - - private String protocol; - - private String topic; -} diff --git a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/model/EmqAuthInfo.java b/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/model/EmqAuthInfo.java deleted file mode 100755 index 2673f1e1..00000000 --- a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/model/EmqAuthInfo.java +++ /dev/null @@ -1,18 +0,0 @@ -package cc.iotkit.mqttauth.model; - -import lombok.Data; - -@Data -public class EmqAuthInfo { - - private String clientid; - - private String password; - - private String username; - - private String ipaddress; - - private String protocol; - -} diff --git a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/DeviceMqttAuth.java b/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/DeviceMqttAuth.java deleted file mode 100755 index cfffe3ff..00000000 --- a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/DeviceMqttAuth.java +++ /dev/null @@ -1,75 +0,0 @@ -package cc.iotkit.mqttauth.service; - -import cc.iotkit.common.Constants; -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.mqttauth.model.EmqAcl; -import cc.iotkit.mqttauth.model.EmqAuthInfo; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.codec.digest.DigestUtils; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Slf4j -@Component("DeviceMqttAuth") -public class DeviceMqttAuth implements MqttAuth { - @Autowired - private DeviceService deviceService; - - @Override - public void auth(EmqAuthInfo auth) { - - String clientId = auth.getClientid(); - String[] pkDnAndModel = getPkDnAndModel(clientId); - - String hmac = DigestUtils.md5Hex(Constants.MQTT_SECRET + clientId); - if (!hmac.equalsIgnoreCase(auth.getPassword())) { - throw new RuntimeException("password is illegal."); - } - - DeviceInfo device = new DeviceInfo(); - device.setProductKey(pkDnAndModel[0]); - device.setDeviceName(pkDnAndModel[1]); - device.setModel(pkDnAndModel[2]); - deviceService.register(device); - } - - @Override - public void acl(EmqAcl acl) { - String[] pkDn = getPkDnFromTopic(acl.getTopic()); - String pk = pkDn[2]; - String dn = pkDn[3]; - DeviceInfo device = deviceService.getByPkAndDn(pk, dn); - if (device == null) { - log.error("the device is not registered,pk:{},dn:{}", pk, dn); - return; - } - - deviceService.online(pk, dn); - } - - private String[] getPkDnAndModel(String clientId) { - if (StringUtils.isBlank(clientId)) { - throw new RuntimeException("clientId is blank."); - } - clientId += "_"; - - String[] pkDnAndModel = clientId.split("_", -1); - if (pkDnAndModel.length < 3) { - throw new RuntimeException("clientId is illegal."); - } - return pkDnAndModel; - } - - private String[] getPkDnFromTopic(String topic) { - if (StringUtils.isBlank(topic)) { - throw new RuntimeException("topic is blank."); - } - - String[] pkDn = topic.split("/", -1); - if (pkDn.length < 4) { - throw new RuntimeException("topic is illegal."); - } - return pkDn; - } -} diff --git a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/DeviceService.java b/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/DeviceService.java deleted file mode 100755 index fdb563ef..00000000 --- a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/DeviceService.java +++ /dev/null @@ -1,82 +0,0 @@ -package cc.iotkit.mqttauth.service; - -import cc.iotkit.common.exception.BizException; -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.model.product.Product; -import cc.iotkit.mqttauth.dao.DeviceDao; -import cc.iotkit.mqttauth.dao.ProductDao; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.RandomUtils; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -@Slf4j -@Service -public class DeviceService { - - @Autowired - private DeviceDao deviceDao; - @Autowired - private ProductDao productDao; - - public DeviceInfo register(DeviceInfo device) { - - String pk = device.getProductKey(); - Product product = productDao.getProduct(pk); - if (product == null) { - throw new BizException("Product does not exist"); - } - String uid = product.getUid(); - - DeviceInfo deviceInfo = deviceDao.getByPkAndDn(pk, device.getDeviceName()); - if (deviceInfo != null) { - device.setDeviceId(deviceInfo.getDeviceId()); - device.setUid(uid); - deviceDao.updateDevice(device); - log.info("device register update:{}", JsonUtil.toJsonString(device)); - return device; - } - - device.setUid(uid); - device.setDeviceId(newDeviceId(device.getDeviceName())); - deviceDao.addDevice(device); - log.info("device registered:{}", JsonUtil.toJsonString(device)); - return device; - } - - public DeviceInfo getByPkAndDn(String pk, String dn) { - return deviceDao.getByPkAndDn(pk, dn); - } - - public void online(String pk, String dn) { - DeviceInfo device = new DeviceInfo(); - device.setProductKey(pk); - device.setDeviceName(dn); - - device.getState().setOnline(true); - device.getState().setOnlineTime(System.currentTimeMillis()); - deviceDao.updateDeviceByPkAndDn(device); - } - - /** - * 1-13位 时间戳 - * 14-29位 deviceNae,去除非字母和数字,不足16位补0,超过16位的mac取后16位,共16位 - * 30-31位 mac长度,共2位 - * 32位 随机一个0-f字符 - */ - public static String newDeviceId(String deviceNae) { - int maxDnLen = 16; - String dn = deviceNae.replaceAll("[^0-9A-Za-z]", ""); - if (dn.length() > maxDnLen) { - dn = dn.substring(dn.length() - maxDnLen); - } else { - dn = (dn + "00000000000000000000").substring(0, maxDnLen); - } - String len = StringUtils.leftPad(deviceNae.length() + "", 2, '0'); - String rnd = Integer.toHexString(RandomUtils.nextInt(0, 16)); - return (System.currentTimeMillis() + "0" + dn + len + rnd).toLowerCase(); - } - -} diff --git a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/MqttAuth.java b/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/MqttAuth.java deleted file mode 100755 index 708dddca..00000000 --- a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/MqttAuth.java +++ /dev/null @@ -1,12 +0,0 @@ -package cc.iotkit.mqttauth.service; - -import cc.iotkit.mqttauth.model.EmqAcl; -import cc.iotkit.mqttauth.model.EmqAuthInfo; - -public interface MqttAuth { - - void auth(EmqAuthInfo auth); - - void acl(EmqAcl acl); - -} diff --git a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/SysMqttAuth.java b/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/SysMqttAuth.java deleted file mode 100755 index 450eadf8..00000000 --- a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/SysMqttAuth.java +++ /dev/null @@ -1,42 +0,0 @@ -package cc.iotkit.mqttauth.service; - -import cc.iotkit.common.Constants; -import cc.iotkit.common.utils.CodecUtil; -import cc.iotkit.mqttauth.model.EmqAcl; -import cc.iotkit.mqttauth.model.EmqAuthInfo; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Component; - -@Slf4j -@Component("SysMqttAuth") -public class SysMqttAuth implements MqttAuth { - @Override - public void auth(EmqAuthInfo auth) { - try { - //password= aes(sy_username,ACCOUNT_SECRET) - String uid = auth.getUsername(); - String codes = CodecUtil.aesDecryptHex(auth.getPassword(), Constants.ACCOUNT_SECRET); - if (StringUtils.isBlank(codes)) { - throw new RuntimeException("mqtt auth failed,pwd error."); - } - //解出来的用户id与username是否一致 - String[] parts = codes.split("_"); - if (parts.length < 2 || !uid.equals(parts[1])) { - throw new RuntimeException("mqtt auth failed,pw validate error."); - } - } catch (Throwable e) { - log.error("sys user mqtt failed.", e); - throw new RuntimeException("mqtt auth failed:" + e.getMessage()); - } - } - - @Override - public void acl(EmqAcl acl) { - //平台用户可订阅以所有设备 -// String topic = acl.getTopic(); -// if (!topic.startsWith("/app/")) { -// throw new RuntimeException("acl failed."); -// } - } -} diff --git a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/WxMqttAuth.java b/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/WxMqttAuth.java deleted file mode 100755 index 63e5ecad..00000000 --- a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/WxMqttAuth.java +++ /dev/null @@ -1,18 +0,0 @@ -package cc.iotkit.mqttauth.service; - -import cc.iotkit.mqttauth.model.EmqAcl; -import cc.iotkit.mqttauth.model.EmqAuthInfo; -import org.springframework.stereotype.Component; - -@Component("WxMqttAuth") -public class WxMqttAuth implements MqttAuth { - @Override - public void auth(EmqAuthInfo auth) { - - } - - @Override - public void acl(EmqAcl acl) { - - } -} diff --git a/device-server/mqtt-auth/src/main/resources/application-dev.yml b/device-server/mqtt-auth/src/main/resources/application-dev.yml deleted file mode 100755 index c7d60c0a..00000000 --- a/device-server/mqtt-auth/src/main/resources/application-dev.yml +++ /dev/null @@ -1,5 +0,0 @@ -spring: - data: - mongodb: - uri: mongodb://填写mongodb地址/admin - database: iotkit diff --git a/device-server/mqtt-auth/src/main/resources/application.yml b/device-server/mqtt-auth/src/main/resources/application.yml deleted file mode 100755 index c7d60c0a..00000000 --- a/device-server/mqtt-auth/src/main/resources/application.yml +++ /dev/null @@ -1,5 +0,0 @@ -spring: - data: - mongodb: - uri: mongodb://填写mongodb地址/admin - database: iotkit diff --git a/device-server/mqtt-auth/src/main/resources/logback-spring.xml b/device-server/mqtt-auth/src/main/resources/logback-spring.xml deleted file mode 100755 index 40a98cf0..00000000 --- a/device-server/mqtt-auth/src/main/resources/logback-spring.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - - - - - DEBUG - - - ${CONSOLE_LOG_PATTERN} - utf8 - - - - - - ${LOG_FILE}/info.log - - ${LOG_FILE}/info.%d{yyyy-MM-dd}.%i.gz - - 5 - - 20GB - - - 1GB - - - - ${CONSOLE_LOG_PATTERN} - utf8 - - - - - - ${LOG_FILE}/error.log - - ${LOG_FILE}/error.%d{yyyy-MM-dd}.%i.gz - - 5 - - 5GB - - - 1GB - - - - ${CONSOLE_LOG_PATTERN} - utf8 - - - ERROR - ACCEPT - DENY - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/device-server/mqtt-auth/src/test/java/SupperUser.java b/device-server/mqtt-auth/src/test/java/SupperUser.java deleted file mode 100755 index 83f16234..00000000 --- a/device-server/mqtt-auth/src/test/java/SupperUser.java +++ /dev/null @@ -1,23 +0,0 @@ -import cc.iotkit.common.Constants; -import cc.iotkit.common.utils.CodecUtil; -import cc.iotkit.mqttauth.controller.MqttAuthController; -import org.junit.Assert; -import org.junit.Test; - -public class SupperUser { - - @Test - public void createSuperuser() throws Exception { - //mqtt生成超级用户,作为mqtt-server连接mqtt的clientId - String clientId = "mqtt-server-producer-dev"; - System.out.println("clientId:su_" + CodecUtil.aesEncrypt("admin_" + clientId, Constants.MQTT_SECRET)); - } - - @Test - public void isSupperUser() { - String clientId = "su_344A6E61654F567A30536E59646A306659664A75625A374D35484756776D457977374653684B306B414E513D"; -// String clientId = "su_tng1t408QrZDEoM7CxiDueP++4FmXIxS7x35YbpuNf8="; - MqttAuthController authController = new MqttAuthController(); - Assert.assertTrue(authController.isSupperUser(clientId)); - } -} diff --git a/device-server/mqtt-auth/src/test/java/SysMqttAuth.java b/device-server/mqtt-auth/src/test/java/SysMqttAuth.java deleted file mode 100755 index 9f0a73fe..00000000 --- a/device-server/mqtt-auth/src/test/java/SysMqttAuth.java +++ /dev/null @@ -1,13 +0,0 @@ -import cc.iotkit.common.Constants; -import cc.iotkit.common.utils.CodecUtil; -import org.junit.Test; - -public class SysMqttAuth { - - @Test - public void createSyPwd() throws Exception { - System.out.println(CodecUtil.aesEncrypt("sy_gateway_dev", Constants.ACCOUNT_SECRET)); - System.out.println(CodecUtil.aesDecryptHex("4B6272544E59324C596562686173494A696E764E69673D3D", Constants.ACCOUNT_SECRET)); - } - -} diff --git a/device-server/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/Application.java b/device-server/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/Application.java deleted file mode 100755 index e6bcb418..00000000 --- a/device-server/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/Application.java +++ /dev/null @@ -1,19 +0,0 @@ -package cc.iotkit.simulator; - -import cc.iotkit.simulator.config.Mqtt; -import cc.iotkit.simulator.service.Gateway; - -public class Application { - - public static void main(String[] args) { - - Mqtt.broker = args[0]; - - Gateway gateway = new Gateway("hbtgIA0SuVw9lxjB", "AA:BB:CC:DD:22"); - gateway.addSubDevice("Rf4QSjbm65X45753", "ABC12300002", "S01"); - gateway.addSubDevice("Rf4QSjbm65X45753", "ABC12300003", "S01"); - gateway.addSubDevice("hdX3PCMcFrCYpesJ", "ABD12300001", "F01"); - gateway.addSubDevice("hdX3PCMcFrCYpesJ", "ABD12300002", "F01"); - gateway.start(); - } -} diff --git a/device-server/mqtt-server/.DS_Store b/device-server/mqtt-server/.DS_Store deleted file mode 100755 index a3c148ab..00000000 Binary files a/device-server/mqtt-server/.DS_Store and /dev/null differ diff --git a/device-server/mqtt-server/log/error.2022-01-10.0.gz b/device-server/mqtt-server/log/error.2022-01-10.0.gz deleted file mode 100755 index 33d7414a..00000000 Binary files a/device-server/mqtt-server/log/error.2022-01-10.0.gz and /dev/null differ diff --git a/device-server/mqtt-server/log/error.2022-01-11.0.gz b/device-server/mqtt-server/log/error.2022-01-11.0.gz deleted file mode 100755 index 365f8c7c..00000000 Binary files a/device-server/mqtt-server/log/error.2022-01-11.0.gz and /dev/null differ diff --git a/device-server/mqtt-server/log/error.2022-01-12.0.gz b/device-server/mqtt-server/log/error.2022-01-12.0.gz deleted file mode 100755 index 312d3325..00000000 Binary files a/device-server/mqtt-server/log/error.2022-01-12.0.gz and /dev/null differ diff --git a/device-server/mqtt-server/log/error.2022-01-13.0.gz b/device-server/mqtt-server/log/error.2022-01-13.0.gz deleted file mode 100755 index 56466d0b..00000000 Binary files a/device-server/mqtt-server/log/error.2022-01-13.0.gz and /dev/null differ diff --git a/device-server/mqtt-server/log/info.2022-01-10.0.gz b/device-server/mqtt-server/log/info.2022-01-10.0.gz deleted file mode 100755 index 38fc3fce..00000000 Binary files a/device-server/mqtt-server/log/info.2022-01-10.0.gz and /dev/null differ diff --git a/device-server/mqtt-server/log/info.2022-01-11.0.gz b/device-server/mqtt-server/log/info.2022-01-11.0.gz deleted file mode 100755 index 1518b11c..00000000 Binary files a/device-server/mqtt-server/log/info.2022-01-11.0.gz and /dev/null differ diff --git a/device-server/mqtt-server/log/info.2022-01-12.0.gz b/device-server/mqtt-server/log/info.2022-01-12.0.gz deleted file mode 100755 index 1dea45f4..00000000 Binary files a/device-server/mqtt-server/log/info.2022-01-12.0.gz and /dev/null differ diff --git a/device-server/mqtt-server/log/info.2022-01-13.0.gz b/device-server/mqtt-server/log/info.2022-01-13.0.gz deleted file mode 100755 index f9f2a098..00000000 Binary files a/device-server/mqtt-server/log/info.2022-01-13.0.gz and /dev/null differ diff --git a/device-server/mqtt-server/pom.xml b/device-server/mqtt-server/pom.xml deleted file mode 100755 index ed3482c9..00000000 --- a/device-server/mqtt-server/pom.xml +++ /dev/null @@ -1,123 +0,0 @@ - - - - device-server - cc.iotkit - 0.0.1-SNAPSHOT - - 4.0.0 - - mqtt-server - - - - org.springframework.boot - spring-boot-starter-data-mongodb - - - - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.boot - spring-boot-starter-integration - - - org.springframework.integration - spring-integration-mqtt - - - - org.springframework.boot - spring-boot-starter-cache - - - - org.springframework.cloud - spring-cloud-commons - - - - com.github.ben-manes.caffeine - caffeine - - - - org.projectlombok - lombok - true - - - - commons-beanutils - commons-beanutils - - - - org.apache.commons - commons-lang3 - - - - commons-codec - commons-codec - - - - commons-io - commons-io - - - - com.google.guava - guava - - - - org.bouncycastle - bcprov-jdk15on - - - - joda-time - joda-time - - - - cc.iotkit - model - - - - cc.iotkit - common - - - cc.iotkit - device-api - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - - - - - - \ No newline at end of file diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/Application.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/Application.java deleted file mode 100755 index c774fd20..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/Application.java +++ /dev/null @@ -1,14 +0,0 @@ -package cc.iotkit.server; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.client.discovery.EnableDiscoveryClient; - -@EnableDiscoveryClient -@SpringBootApplication -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/config/CacheConfig.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/config/CacheConfig.java deleted file mode 100755 index 137ebb51..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/config/CacheConfig.java +++ /dev/null @@ -1,43 +0,0 @@ -package cc.iotkit.server.config; - -import com.github.benmanes.caffeine.cache.Caffeine; -import com.google.common.collect.Lists; -import org.springframework.cache.CacheManager; -import org.springframework.cache.caffeine.CaffeineCache; -import org.springframework.cache.support.SimpleCacheManager; -import org.springframework.context.annotation.Bean; - -import java.util.concurrent.TimeUnit; - -//@Configuration -//@EnableCaching -public class CacheConfig { - - /** - * 配置本地缓存 - */ - @Bean - public CacheManager cacheManager() { - SimpleCacheManager manager = new SimpleCacheManager(); - manager.setCaches(Lists.newArrayList(new CaffeineCache( - "device_cache", - Caffeine.newBuilder() - .expireAfterWrite(5, TimeUnit.MINUTES) - .build() - ), - new CaffeineCache( - "product_cache", - Caffeine.newBuilder() - .expireAfterWrite(5, TimeUnit.MINUTES) - .build() - ), - new CaffeineCache( - "app_design_cache", - Caffeine.newBuilder() - .expireAfterWrite(5, TimeUnit.MINUTES) - .build() - ))); - return manager; - } - -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/config/GlobalExceptionHandler.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/config/GlobalExceptionHandler.java deleted file mode 100755 index 1c603d32..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/config/GlobalExceptionHandler.java +++ /dev/null @@ -1,42 +0,0 @@ -package cc.iotkit.server.config; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.ResponseBody; - -import javax.servlet.http.HttpServletResponse; - -@Slf4j -@ControllerAdvice -public class GlobalExceptionHandler { - - @ExceptionHandler(Exception.class) - @ResponseBody - public RequestResult handleException(Exception e, HttpServletResponse response) { - log.error("handler exception", e); - if(e.getMessage().contains("Unauthorized")){ - response.setStatus(403); - return new RequestResult("403", "没有权限"); - } - response.setStatus(500); - return new RequestResult("500", e.getMessage()); - } - - @NoArgsConstructor - @AllArgsConstructor - @Data - public static class RequestResult { - - private String code; - - private String message; - - } - -} - - diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/config/MqttConfig.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/config/MqttConfig.java deleted file mode 100755 index c984a60c..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/config/MqttConfig.java +++ /dev/null @@ -1,147 +0,0 @@ -package cc.iotkit.server.config; - -import cc.iotkit.common.Constants; -import cc.iotkit.common.utils.CodecUtil; -import cc.iotkit.server.handler.MqttConsumerHandler; -import lombok.SneakyThrows; -import org.apache.commons.lang3.StringUtils; -import org.eclipse.paho.client.mqttv3.MqttConnectOptions; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.integration.annotation.ServiceActivator; -import org.springframework.integration.channel.DirectChannel; -import org.springframework.integration.core.MessageProducer; -import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory; -import org.springframework.integration.mqtt.core.MqttPahoClientFactory; -import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter; -import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler; -import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.MessageHandler; - -@Configuration -public class MqttConfig { - - /** - * 订阅的bean名称 - */ - public static final String CHANNEL_NAME_IN = "mqttInboundChannel"; - /** - * 发布的bean名称 - */ - public static final String CHANNEL_NAME_OUT = "mqttOutboundChannel"; - - @Value("${mqtt.url}") - private String url; - - @Value(("${spring.profiles.active:}")) - private String env; - - /** - * MQTT连接器选项 - * - * @return {@link MqttConnectOptions} - */ - @Bean - public MqttConnectOptions getMqttConnectOptions() { - MqttConnectOptions options = new MqttConnectOptions(); - // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录, - // 这里设置为true表示每次连接到服务器都以新的身份连接 - options.setCleanSession(true); - // 设置连接的用户名 - options.setUserName("admin"); - // 设置连接的密码 - options.setPassword("password".toCharArray()); - options.setServerURIs(StringUtils.split(url, ",")); - // 设置超时时间 单位为秒 - options.setConnectionTimeout(10); - // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送心跳判断客户端是否在线,但这个方法并没有重连的机制 - options.setKeepAliveInterval(20); - return options; - } - - /** - * MQTT客户端 - * - * @return {@link MqttPahoClientFactory} - */ - @Bean - public MqttPahoClientFactory mqttClientFactory() { - DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory(); - factory.setConnectionOptions(getMqttConnectOptions()); - return factory; - } - - /** - * MQTT信息通道(生产者) - * - * @return {@link MessageChannel} - */ - @Bean(name = CHANNEL_NAME_OUT) - public MessageChannel mqttOutboundChannel() { - return new DirectChannel(); - } - - /** - * MQTT消息处理器(生产者) - * - * @return {@link MessageHandler} - */ - @SneakyThrows - @Bean - @ServiceActivator(inputChannel = CHANNEL_NAME_OUT) - public MessageHandler mqttOutbound() { - String clientId = "mqtt-server-producer-" + env; - clientId = "su_" + CodecUtil.aesEncrypt("admin_" + clientId, Constants.MQTT_SECRET); - MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler( - clientId, - mqttClientFactory()); - messageHandler.setAsync(true); - return messageHandler; - } - - /** - * MQTT消息订阅绑定(消费者) - * - * @return {@link MessageProducer} - */ - @SneakyThrows - @Bean - public MessageProducer inbound() { - // 可以同时消费(订阅)多个Topic - String clientId = "mqtt-server-consumer-" + env; - clientId = "su_" + CodecUtil.aesEncrypt("admin_" + clientId, Constants.MQTT_SECRET); - MqttPahoMessageDrivenChannelAdapter adapter = - new MqttPahoMessageDrivenChannelAdapter( - clientId, mqttClientFactory(), - "/sys/#"); - adapter.setCompletionTimeout(5000); - adapter.setConverter(new DefaultPahoMessageConverter()); - adapter.setQos(1); - // 设置订阅通道 - adapter.setOutputChannel(mqttInboundChannel()); - return adapter; - } - - /** - * MQTT信息通道(消费者) - * - * @return {@link MessageChannel} - */ - @Bean(name = CHANNEL_NAME_IN) - public MessageChannel mqttInboundChannel() { - return new DirectChannel(); - } - - /** - * MQTT消息处理器(消费者) - * - * @return {@link MessageHandler} - */ - @Bean - @ServiceActivator(inputChannel = CHANNEL_NAME_IN) - public MessageHandler handler() { - return new MqttConsumerHandler(); - } -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/BaseDao.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/BaseDao.java deleted file mode 100755 index 53218ee0..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/BaseDao.java +++ /dev/null @@ -1,55 +0,0 @@ -package cc.iotkit.server.dao; - -import org.springframework.data.domain.Sort; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.query.Criteria; -import org.springframework.data.mongodb.core.query.Query; - -import java.util.List; - -import static org.springframework.data.mongodb.core.query.Criteria.where; -import static org.springframework.data.mongodb.core.query.Query.query; - -public class BaseDao { - - protected MongoTemplate mongoTemplate; - - private Class cls; - - public BaseDao(MongoTemplate mongoTemplate, Class cls) { - this.mongoTemplate = mongoTemplate; - this.cls = cls; - } - - public List find(Criteria condition) { - Query query = new Query(); - query.addCriteria(condition); - return mongoTemplate.find(query, cls); - } - - public List find(Criteria condition, long skip, int count, Sort.Order order) { - Query query = new Query(); - query.addCriteria(condition) - .with(Sort.by(order)) - .skip(skip) - .limit(count); - return mongoTemplate.find(query, cls); - } - - public long count(Criteria condition) { - Query query = new Query(); - query.addCriteria(condition); - return mongoTemplate.count(query, cls); - } - - public T save(String id, T entity) { - if (id == null) { - return mongoTemplate.save(entity); - } else { - mongoTemplate.updateFirst(query(where("_id").is(id)), - DaoTool.update(entity), entity.getClass()); - return (T) mongoTemplate.findById(id, entity.getClass()); - } - } - -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DaoTool.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DaoTool.java deleted file mode 100755 index 03fc448e..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DaoTool.java +++ /dev/null @@ -1,53 +0,0 @@ -package cc.iotkit.server.dao; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.SneakyThrows; -import org.apache.commons.beanutils.BeanMap; -import org.springframework.data.mongodb.core.query.Update; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -public class DaoTool { - - public static void update(Update update, List props) { - for (Prop pro : props) { - update.set(pro.getName(), pro.getValue()); - } - } - - public static List getProp(String key, Object value) { - List props = new ArrayList<>(); - if (value instanceof Map) { - Set> entrySet = ((Map) value).entrySet(); - for (Map.Entry entry : entrySet) { - props.addAll(getProp(key + "." + entry.getKey(), entry.getValue())); - } - } else if (value != null && !(value instanceof Class)) { - props.add(new Prop(key, value)); - } - return props; - } - - @SneakyThrows - public static Update update(T obj) { - Map pros = new BeanMap(obj); - Update update = new Update(); - for (Map.Entry entry : pros.entrySet()) { - update(update, DaoTool.getProp(entry.getKey().toString(), entry.getValue())); - } - return update; - } - - @Data - @AllArgsConstructor - @NoArgsConstructor - static class Prop { - private String name; - private Object value; - } -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DeviceDao.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DeviceDao.java deleted file mode 100755 index e553f4d2..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DeviceDao.java +++ /dev/null @@ -1,62 +0,0 @@ -package cc.iotkit.server.dao; - -import cc.iotkit.common.Constants; -import cc.iotkit.model.device.DeviceInfo; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.query.Query; -import org.springframework.stereotype.Repository; - -import static org.springframework.data.mongodb.core.query.Criteria.where; -import static org.springframework.data.mongodb.core.query.Query.query; - -@Repository -public class DeviceDao extends BaseDao { - - @Autowired - private DeviceRepository deviceRepository; - - @Autowired - public DeviceDao(MongoTemplate mongoTemplate) { - super(mongoTemplate, DeviceInfo.class); - } - - public void addDevice(DeviceInfo device) { - device.setCreateAt(System.currentTimeMillis()); - mongoTemplate.insert(device); - } - - public void updateDevice(DeviceInfo device) { - if (device.getDeviceId() == null) { - return; - } - mongoTemplate.updateFirst(query(where("deviceId").is(device.getDeviceId())), - DaoTool.update(device), DeviceInfo.class); - } - - public void updateDeviceByPkAndDn(DeviceInfo device) { - if (device.getProductKey() == null || device.getDeviceName() == null) { - return; - } - mongoTemplate.updateFirst(query(where("productKey").is(device.getProductKey()). - and("deviceName").is(device.getDeviceName())), - DaoTool.update(device), DeviceInfo.class); - } - - @Cacheable(value = "deviceInfoCache", key = "#pk+'_'+#dn") - public DeviceInfo getByPkAndDn(String pk, String dn) { - Query query = query(where("productKey").is(pk).and("deviceName").is(dn)); - return mongoTemplate.findOne(query, DeviceInfo.class); - } - - public DeviceInfo getByDeviceId(String deviceId) { - Query query = query(where("deviceId").is(deviceId)); - return mongoTemplate.findOne(query, DeviceInfo.class); - } - - @Cacheable(value = Constants.DEVICE_CACHE, key = "#deviceId") - public DeviceInfo get(String deviceId) { - return deviceRepository.findById(deviceId).orElse(new DeviceInfo()); - } -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DeviceEventRepository.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DeviceEventRepository.java deleted file mode 100755 index 7b8b9e01..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DeviceEventRepository.java +++ /dev/null @@ -1,13 +0,0 @@ -package cc.iotkit.server.dao; - -import cc.iotkit.model.device.message.DeviceEvent; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.mongodb.repository.MongoRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface DeviceEventRepository extends MongoRepository { - - Page findByDeviceId(String deviceId, Pageable pageable); -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DeviceRepository.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DeviceRepository.java deleted file mode 100755 index 2ee7e611..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DeviceRepository.java +++ /dev/null @@ -1,9 +0,0 @@ -package cc.iotkit.server.dao; - -import cc.iotkit.model.device.DeviceInfo; -import org.springframework.data.mongodb.repository.MongoRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface DeviceRepository extends MongoRepository { -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/ThingModelRepository.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/ThingModelRepository.java deleted file mode 100755 index a306169e..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/ThingModelRepository.java +++ /dev/null @@ -1,9 +0,0 @@ -package cc.iotkit.server.dao; - -import cc.iotkit.model.product.ThingModel; -import org.springframework.data.mongodb.repository.MongoRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface ThingModelRepository extends MongoRepository { -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/DisconnectedHandler.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/DisconnectedHandler.java deleted file mode 100755 index 31517224..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/DisconnectedHandler.java +++ /dev/null @@ -1,63 +0,0 @@ -package cc.iotkit.server.handler; - -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.server.dao.DeviceRepository; -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.server.service.DeviceService; -import com.fasterxml.jackson.core.type.TypeReference; -import lombok.Data; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Example; -import org.springframework.stereotype.Component; - -import java.util.List; - -@Slf4j -@Component -public class DisconnectedHandler { - - @Autowired - private DeviceService deviceService; - @Autowired - private DeviceRepository deviceRepository; - - public void handler(String msg) { - Disconnected disconnected = JsonUtil.parse(msg, new TypeReference() { - }); - String clientId = disconnected.getClientid(); - String[] parts = clientId.split("_"); - if (parts.length < 2) { - return; - } - String pk = parts[0]; - String dn = parts[1]; - log.info("gateway disconnected, offline,pk:{},dn:{}", pk, dn); - - DeviceInfo example = new DeviceInfo(); - example.setProductKey(pk); - example.setDeviceName(dn); - DeviceInfo device = deviceRepository.findOne(Example.of(example)).orElse(new DeviceInfo()); - if (device.getDeviceId() == null) { - log.error("no device found by pk:{} and dn:{}", pk, dn); - return; - } - deviceService.offline(pk, dn); - - example = new DeviceInfo(); - example.setParentId(device.getDeviceId()); - //子设备下线 - List children = deviceRepository.findAll(Example.of(example)); - children.forEach(c -> deviceService.offline(c.getProductKey(), c.getDeviceName())); - } - - @Data - private static class Disconnected { - private String reason; - private String clientid; - private String username; - private String peername; - private String sockname; - } - -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/EventReportHandler.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/EventReportHandler.java deleted file mode 100755 index fec33d09..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/EventReportHandler.java +++ /dev/null @@ -1,49 +0,0 @@ -package cc.iotkit.server.handler; - -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.server.dao.DeviceEventRepository; -import cc.iotkit.model.device.message.DeviceEvent; -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.model.mq.Request; -import cc.iotkit.model.mq.Response; -import com.fasterxml.jackson.core.type.TypeReference; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.util.Map; -import java.util.regex.Pattern; - -@Component -public class EventReportHandler implements MqttHandler, Response.Empty> { - - private static final Pattern MATCH_REG = Pattern.compile("^/sys/\\w+/\\w+/s/event/[^_/]+$"); - - @Autowired - DeviceEventRepository deviceEventRepository; - - @Override - public boolean compliant(String topic) { - return MATCH_REG.matcher(topic).matches(); - } - - @Override - public Request parse(String msg) { - return JsonUtil.parse(msg, new TypeReference() { - }); - } - - @Override - public Response.Empty handler(String topic, DeviceInfo device, Request request) { - String identifier = topic.substring(topic.indexOf("/event/") + 7); - DeviceEvent event = DeviceEvent.builder() - .deviceId(device.getDeviceId()) - .identifier(identifier) - .request(request) - .type(topic.endsWith("_reply") ? "ack" : "event") - .createAt(System.currentTimeMillis()) - .build(); - deviceEventRepository.save(event); - return Response.empty(); - } - -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/MqttConsumerHandler.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/MqttConsumerHandler.java deleted file mode 100755 index 49a45cc3..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/MqttConsumerHandler.java +++ /dev/null @@ -1,162 +0,0 @@ -package cc.iotkit.server.handler; - -import cc.iotkit.common.Constants; -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.server.dao.DeviceDao; -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.model.mq.Request; -import cc.iotkit.model.mq.Response; -import cc.iotkit.server.service.DeviceService; -import cc.iotkit.server.service.IMqttSender; -import com.fasterxml.jackson.core.type.TypeReference; -import lombok.Data; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageHandler; -import org.springframework.messaging.MessageHeaders; -import org.springframework.messaging.MessagingException; - -import java.util.ArrayList; -import java.util.List; - -@Slf4j -public class MqttConsumerHandler implements MessageHandler, ApplicationContextAware { - - private List mqttHandlers = new ArrayList<>(); - - @Autowired - private DeviceDao deviceDao; - @Autowired - private IMqttSender mqttSender; - @Autowired - private DeviceService deviceService; - @Autowired - private DisconnectedHandler disconnectedHandler; - - @Override - public void handleMessage(Message msg) throws MessagingException { - log.info(JsonUtil.toJsonString(msg)); - MessageHeaders headers = msg.getHeaders(); - String topic = headers.get("mqtt_receivedTopic", String.class); - if (topic == null) { - log.error("message topic is null."); - return; - } - - if (topic.equals("/sys/session/topic/unsubscribed")) { - topicUnsubscribed(msg.getPayload().toString()); - return; - } - - if (topic.equals("/sys/client/disconnected")) { - disconnectedHandler.handler(msg.getPayload().toString()); - return; - } - - String[] parts = topic.split("/"); - if (parts.length < 5) { - log.error("message topic is illegal."); - return; - } - - String pk = parts[2]; - String dn = parts[3]; - DeviceInfo device = deviceDao.getByPkAndDn(pk, dn); - if (device == null) { - log.warn("device not found by pk and dn."); - return; - } - String payload = msg.getPayload().toString(); - - //转发到deviceId对应的topic中给客户端消费 - sendToAppClientTopic(device.getDeviceId(), topic, payload); - - Object result = null; - Request request = new Request<>(); - try { - for (MqttHandler handler : mqttHandlers) { - if (!handler.compliant(topic)) { - continue; - } - request = handler.parse(payload); - result = handler.handler(topic, device, request); - } - } catch (Throwable e) { - log.error("handler mqtt msg error.", e); - reply(device.getDeviceId(), topic, request.getId(), 1, ""); - return; - } - - if (result == null) { - return; - } - - reply(device.getDeviceId(), topic, request.getId(), 0, result); - } - - private void reply(String deviceId, String topic, String id, int code, Object result) { - topic = topic.replace("/s/", "/c/") + "_reply"; - String msg = JsonUtil.toJsonString(new Response<>(id, code, result)); - mqttSender.sendToMqtt(topic, msg); - sendToAppClientTopic(deviceId, topic, msg); - } - - private void topicUnsubscribed(String msg) { - Unsubscribed unsubscribed = JsonUtil.parse(msg, new TypeReference() { - }); - String topic = unsubscribed.getTopic(); - String[] parts = topic.split("/"); - if (parts.length < 4) { - return; - } - - log.info("device offline,pk:{},dn:{}", parts[2], parts[3]); - deviceService.offline(parts[2], parts[3]); - } - - private void sendToAppClientTopic(String deviceId, String topic, String msg) { - //排除服务调用和属性设置消息 - if (topic.contains("/c/service/") || topic.endsWith("/post_reply")) { - return; - } - - //发给app端订阅消息 - distributeMsg(Constants.TOPIC_PREFIX_APP, topic, deviceId, msg); - //发送给第三方接入gateway - distributeMsg(Constants.TOPIC_PREFIX_GATEWAY, topic, deviceId, msg); - } - - /** - * 分发消息 - */ - void distributeMsg(String topicNamePrefix, String topic, String deviceId, String msg) { - /* - /app/xxxdeviceId/event/事件名 - /app/xxxdeviceId/event/property/post - /app/xxxdeviceId/service/服务名_reply - */ - String distTopic = "/" + topicNamePrefix + "/" + deviceId + "/" + - (topic.replaceAll("/sys/.*/s/", "") - .replaceAll("/sys/.*/c/", "")); - log.info("send msg:{},to topic:{}", JsonUtil.toJsonString(msg), distTopic); - //转发到deviceId对应的topic中给客户端消费 - mqttSender.sendToMqtt(distTopic, msg); - } - - @Override - public void setApplicationContext(ApplicationContext context) throws BeansException { - mqttHandlers.addAll(context.getBeansOfType(MqttHandler.class).values()); - } - - @Data - private static class Unsubscribed { - private String clientid; - private String username; - private String topic; - private String peerhost; - } -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/MqttHandler.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/MqttHandler.java deleted file mode 100755 index ff6fc23b..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/MqttHandler.java +++ /dev/null @@ -1,14 +0,0 @@ -package cc.iotkit.server.handler; - -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.model.mq.Request; - -public interface MqttHandler { - - boolean compliant(String topic); - - Request parse(String msg); - - R handler(String topic, DeviceInfo device, Request request); - -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/PropertyPostHandler.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/PropertyPostHandler.java deleted file mode 100755 index 3a1be075..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/PropertyPostHandler.java +++ /dev/null @@ -1,62 +0,0 @@ -package cc.iotkit.server.handler; - -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.server.dao.DeviceEventRepository; -import cc.iotkit.server.dao.DeviceRepository; -import cc.iotkit.model.device.message.DeviceEvent; -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.model.mq.Request; -import cc.iotkit.model.mq.Response; -import com.fasterxml.jackson.core.type.TypeReference; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.util.HashMap; -import java.util.Map; - -@Slf4j -@Component -public class PropertyPostHandler implements MqttHandler, Response.Empty> { - - @Autowired - DeviceRepository deviceRepository; - @Autowired - DeviceEventRepository deviceEventRepository; - - @Override - public boolean compliant(String topic) { - return topic.endsWith("/event/property/post"); - } - - @Override - public Request> parse(String msg) { - return JsonUtil.parse(msg, new TypeReference>>() { - }); - } - - @Override - public Response.Empty handler(String topic, DeviceInfo device, Request> request) { - device.setId(device.getDeviceId()); - if (device.getProperty() == null) { - device.setProperty(new HashMap<>()); - } - Map newProps = request.getParams(); - if (newProps != null && newProps.size() > 0) { - request.getParams().forEach(device.getProperty()::put); - } - - deviceRepository.save(device); - - DeviceEvent event = DeviceEvent.builder() - .deviceId(device.getDeviceId()) - .identifier("propertyPost") - .request(request) - .type("property") - .createAt(System.currentTimeMillis()) - .build(); - deviceEventRepository.save(event); - return Response.empty(); - } - -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/PropertyReplyHandler.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/PropertyReplyHandler.java deleted file mode 100755 index b4cfc4ab..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/PropertyReplyHandler.java +++ /dev/null @@ -1,47 +0,0 @@ -package cc.iotkit.server.handler; - -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.server.dao.DeviceEventRepository; -import cc.iotkit.model.device.message.DeviceEvent; -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.model.mq.Request; -import cc.iotkit.model.mq.Response; -import com.fasterxml.jackson.core.type.TypeReference; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.util.Map; - -@Component -public class PropertyReplyHandler implements MqttHandler, Response.Empty> { - - @Autowired - DeviceEventRepository deviceEventRepository; - - @Override - public boolean compliant(String topic) { - return topic.endsWith("/service/property/set_reply"); - } - - @Override - public Request> parse(String msg) { - return JsonUtil.parse(msg, new TypeReference>>() { - }); - } - - @Override - public Response.Empty handler(String topic, DeviceInfo device, Request> request) { - String identifier = "propertySetReply"; - DeviceEvent event = - DeviceEvent.builder() - .deviceId(device.getDeviceId()) - .identifier(identifier) - .request(request) - .type("ack") - .createAt(System.currentTimeMillis()) - .build(); - deviceEventRepository.save(event); - return null; - } - -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/RegisterHandler.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/RegisterHandler.java deleted file mode 100755 index 22f79da4..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/RegisterHandler.java +++ /dev/null @@ -1,36 +0,0 @@ -package cc.iotkit.server.handler; - -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.model.device.message.DeviceRegister; -import cc.iotkit.model.mq.Request; -import cc.iotkit.server.service.DeviceService; -import com.fasterxml.jackson.core.type.TypeReference; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class RegisterHandler implements MqttHandler { - - @Autowired - private DeviceService deviceService; - - @Override - public boolean compliant(String topic) { - return topic.endsWith("/register"); - } - - @Override - public Request parse(String msg) { - return JsonUtil.parse(msg, new TypeReference>() { - }); - } - - @Override - public DeviceRegister handler(String topic, DeviceInfo device, Request request) { - DeviceRegister regInfo = request.getParams(); - deviceService.register(device.getDeviceId(), regInfo.getProductKey(), - regInfo.getDeviceName(), regInfo.getModel()); - return regInfo; - } -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/ServiceReplyHandler.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/ServiceReplyHandler.java deleted file mode 100755 index 4e3c7c86..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/ServiceReplyHandler.java +++ /dev/null @@ -1,49 +0,0 @@ -package cc.iotkit.server.handler; - -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.server.dao.DeviceEventRepository; -import cc.iotkit.model.device.message.DeviceEvent; -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.model.mq.Request; -import cc.iotkit.model.mq.Response; -import com.fasterxml.jackson.core.type.TypeReference; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.util.Map; -import java.util.regex.Pattern; - -@Component -public class ServiceReplyHandler implements MqttHandler, Response.Empty> { - - private static final Pattern MATCH_REG = Pattern.compile("^/sys/\\w+/\\w+/s/service/[^_/]+_reply$"); - - @Autowired - DeviceEventRepository deviceEventRepository; - - @Override - public boolean compliant(String topic) { - return MATCH_REG.matcher(topic).matches(); - } - - @Override - public Request> parse(String msg) { - return JsonUtil.parse(msg, new TypeReference>>() { - }); - } - - @Override - public Response.Empty handler(String topic, DeviceInfo device, Request> request) { - String identifier = topic.substring(topic.indexOf("/service/") + 9); - DeviceEvent event = DeviceEvent.builder() - .deviceId(device.getDeviceId()) - .identifier(identifier) - .request(request) - .type("ack") - .createAt(System.currentTimeMillis()) - .build(); - deviceEventRepository.save(event); - return null; - } - -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/service/DeviceService.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/service/DeviceService.java deleted file mode 100755 index 67922629..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/service/DeviceService.java +++ /dev/null @@ -1,225 +0,0 @@ -package cc.iotkit.server.service; - -import cc.iotkit.common.exception.BizException; -import cc.iotkit.common.exception.NotFoundException; -import cc.iotkit.common.exception.OfflineException; -import cc.iotkit.common.utils.DeviceUtil; -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.common.utils.UniqueIdUtil; -import cc.iotkit.deviceapi.IDeviceManager; -import cc.iotkit.deviceapi.IDeviceService; -import cc.iotkit.deviceapi.Service; -import cc.iotkit.model.device.message.DeviceEvent; -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.model.product.ThingModel; -import cc.iotkit.model.mq.Request; -import cc.iotkit.server.dao.DeviceDao; -import cc.iotkit.server.dao.DeviceEventRepository; -import cc.iotkit.server.dao.DeviceRepository; -import cc.iotkit.server.dao.ThingModelRepository; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.RandomUtils; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; - -import java.util.HashMap; -import java.util.Map; - -@Slf4j -@RestController -public class DeviceService implements IDeviceManager, IDeviceService { - - @Autowired - private DeviceDao deviceDao; - @Autowired - private DeviceRepository deviceRepository; - @Autowired - private ThingModelRepository thingModelRepository; - @Autowired - private ThingModelService thingModelService; - @Autowired - private DeviceEventRepository deviceEventRepository; - - @Autowired - private IMqttSender mqttSender; - - private static final String identifier_set = "property/set"; - - @Override - public DeviceInfo register(String parentId, String productKey, String deviceName, String model) { - DeviceInfo device = new DeviceInfo(); - device.setParentId(parentId); - device.setProductKey(productKey); - device.setDeviceName(deviceName); - device.setModel(model); - - DeviceInfo parentDevice = deviceDao.getByDeviceId(parentId); - if (parentDevice == null) { - throw new BizException("Parent device does not exist"); - } - String uid = parentDevice.getUid(); - - DeviceInfo deviceInfo = deviceDao.getByPkAndDn(productKey, deviceName); - if (deviceInfo != null) { - device.setId(deviceInfo.getId()); - device.setDeviceId(deviceInfo.getDeviceId()); - device.setUid(uid); - deviceDao.updateDevice(device); - log.info("device register update:{}", JsonUtil.toJsonString(device)); - return deviceInfo; - } - - String deviceId = newDeviceId(deviceName); - - device.setId(deviceId); - device.setDeviceId(deviceId); - device.setUid(uid); - deviceDao.addDevice(device); - log.info("device registered:{}", JsonUtil.toJsonString(device)); - return device; - } - - @Override - public void unbind(String deviceId) { - log.info("start unbind device,deviceId:{}", deviceId); - - DeviceInfo device = deviceRepository.findById(deviceId) - .orElseThrow(() -> new RuntimeException("no device found by deviceId:" + deviceId)); - - String gatewayId = device.getParentId(); - DeviceInfo gateway = deviceRepository.findById(gatewayId) - .orElseThrow(() -> new RuntimeException("no device found by deviceId:" + deviceId)); - - //数据库解绑 - device.setParentId(""); - deviceRepository.save(device); - - //网关注销 - String topic = "/sys/" + gateway.getProductKey() + "/" + gateway.getDeviceName() + "/c/service/deregister"; - String requestId = UniqueIdUtil.newRequestId(); - Map params = new HashMap<>(); - params.put("productKey", device.getProductKey()); - params.put("deviceName", device.getDeviceName()); - CmdRequest request = new CmdRequest(requestId, "thing.lifetime.deregister", params); - String msg = JsonUtil.toJsonString(request); - log.info("start send mqtt msg,topic:{},payload:{}", topic, msg); - mqttSender.sendToMqtt(topic, msg); - } - - @Override - public String invoke(Service service) { - return sendMsg(service); - } - - @Override - public String setProperty(String deviceId, @RequestBody Map properties) { - return sendMsg(deviceId, identifier_set, properties); - } - - @Override - public String invokeService(String deviceId, String identifier, Map properties) { - return sendMsg(deviceId, identifier, properties); - } - - public void offline(String pk, String dn) { - DeviceInfo device = new DeviceInfo(); - device.setProductKey(pk); - device.setDeviceName(dn); - - device.getState().setOnline(false); - device.getState().setOfflineTime(System.currentTimeMillis()); - deviceDao.updateDeviceByPkAndDn(device); - log.info("device offline,pk:{},dn:{}", pk, dn); - } - - public String sendMsg(String deviceId, String service, Map args) { - DeviceInfo device = deviceRepository.findById(deviceId) - .orElseThrow(() -> new NotFoundException("device not found by deviceId")); - - return this.sendMsg(device, service, args); - } - - public String sendMsg(DeviceInfo device, String service, Map args) { - if (device.getState() == null || device.getState().getOnline() != Boolean.TRUE) { - throw new OfflineException("device is offline"); - } - - String pk = device.getProductKey(); - String dn = device.getDeviceName(); - - ThingModel thingModel = thingModelRepository.findById(pk) - .orElseThrow(() -> new NotFoundException("device thingModel not found")); - - String topic = "/sys/" + pk + "/" + dn + "/c/service/" + service; - String requestId = UniqueIdUtil.newRequestId(); - - //参数类型转换 - args = thingModelService.paramsParse(thingModel, service, args); - - String method = "thing.service." + service; - if (service.equals(identifier_set)) { - method = "thing.service.property.set"; - } - - CmdRequest request = new CmdRequest(requestId, method, args); - String msg = JsonUtil.toJsonString(request); - log.info("start send mqtt msg,topic:{},payload:{}", topic, msg); - mqttSender.sendToMqtt(topic, msg); - - //记录下行日志 - DeviceEvent deviceEvent = DeviceEvent.builder() - .deviceId(device.getDeviceId()) - .identifier(service.replace("property/set", "propertySet")) - .type("service") - .request(new Request<>(requestId, args)) - .createAt(System.currentTimeMillis()) - .build(); - deviceEventRepository.save(deviceEvent); - - return requestId; - } - - public String sendMsg(Service service) { - DeviceUtil.PkDn pkDn = DeviceUtil.getPkDn(service.getDevice()); - DeviceInfo deviceInfo = deviceDao.getByPkAndDn(pkDn.getProductKey(), pkDn.getDeviceName()); - if ("set".equals(service.getIdentifier())) { - return sendMsg(deviceInfo.getDeviceId(), identifier_set, service.parseInputData()); - } else { - return sendMsg(deviceInfo.getDeviceId(), service.getIdentifier(), service.parseInputData()); - } - } - - /** - * 1-13位 时间戳 - * 14-29位 deviceNae,去除非字母和数字,不足16位补0,超过16位的mac取后16位,共16位 - * 30-31位 mac长度,共2位 - * 32位 随机一个0-f字符 - */ - private static String newDeviceId(String deviceNae) { - int maxDnLen = 16; - String dn = deviceNae.replaceAll("[^0-9A-Za-z]", ""); - if (dn.length() > maxDnLen) { - dn = dn.substring(dn.length() - maxDnLen); - } else { - dn = (dn + "00000000000000000000").substring(0, maxDnLen); - } - String len = StringUtils.leftPad(deviceNae.length() + "", 2, '0'); - String rnd = Integer.toHexString(RandomUtils.nextInt(0, 16)); - return (System.currentTimeMillis() + "0" + dn + len + rnd).toLowerCase(); - } - - - @Data - @NoArgsConstructor - @AllArgsConstructor - private static class CmdRequest { - private String id; - private String method; - private Object params; - } -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/service/IMqttSender.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/service/IMqttSender.java deleted file mode 100755 index 9831e409..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/service/IMqttSender.java +++ /dev/null @@ -1,40 +0,0 @@ -package cc.iotkit.server.service; -import cc.iotkit.server.config.MqttConfig; -import org.springframework.integration.annotation.MessagingGateway; -import org.springframework.integration.mqtt.support.MqttHeaders; -import org.springframework.messaging.handler.annotation.Header; -import org.springframework.stereotype.Component; - -@Component -@MessagingGateway(defaultRequestChannel = MqttConfig.CHANNEL_NAME_OUT) -public interface IMqttSender { - - /** - * 发送信息到MQTT服务器 - * - * @param data 发送的文本 - */ - void sendToMqtt(String data); - - /** - * 发送信息到MQTT服务器 - * - * @param topic 主题 - * @param payload 消息主体 - */ - void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, - String payload); - - /** - * 发送信息到MQTT服务器 - * - * @param topic 主题 - * @param qos 对消息处理的几种机制。
0 表示的是订阅者没收到消息不会再次发送,消息会丢失。
- * 1 表示的是会尝试重试,一直到接收到消息,但这种情况可能导致订阅者收到多次重复消息。
- * 2 多了一次去重的动作,确保订阅者收到的消息有一次。 - * @param payload 消息主体 - */ - void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, - @Header(MqttHeaders.QOS) int qos, - String payload); -} \ No newline at end of file diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/service/ThingModelService.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/service/ThingModelService.java deleted file mode 100755 index c0e47c53..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/service/ThingModelService.java +++ /dev/null @@ -1,60 +0,0 @@ -package cc.iotkit.server.service; - -import cc.iotkit.model.product.ThingModel; -import org.springframework.stereotype.Component; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@Component -public class ThingModelService { - - public Map paramsParse(ThingModel thingModel, String identifier, Map params) { - Map parsedParams = new HashMap<>(); - ThingModel.Model model = thingModel.getModel(); - - //属性设置 - if ("property/set".equals(identifier)) { - List properties = model.getProperties(); - if (properties == null) { - return parsedParams; - } - return parseProperties(properties, params); - } else { - //服务调用 - Map services = model.serviceMap(); - ThingModel.Service service = services.get(identifier); - if (service == null) { - return parsedParams; - } - List parameters = service.getInputData(); - return parseParams(parameters, params); - } - } - - private Map parseParams(List parameters, Map params) { - Map parsed = new HashMap<>(); - parameters.forEach((p -> parseField(p.getIdentifier(), p.getDataType(), params, parsed))); - return parsed; - } - - private Map parseProperties(List properties, Map params) { - Map parsed = new HashMap<>(); - properties.forEach((p -> parseField(p.getIdentifier(), p.getDataType(), params, parsed))); - return parsed; - } - - private void parseField(String identifier, ThingModel.DataType dataType, Map params, Map parsed) { - Object val = params.get(identifier); - if (val == null) { - return; - } - Object result = dataType.parse(val); - if (result == null) { - return; - } - parsed.put(identifier, result); - } - -} diff --git a/device-server/mqtt-server/src/main/resources/application-dev.yml b/device-server/mqtt-server/src/main/resources/application-dev.yml deleted file mode 100755 index 63e3cdec..00000000 --- a/device-server/mqtt-server/src/main/resources/application-dev.yml +++ /dev/null @@ -1,17 +0,0 @@ -server: - port: 8091 - -spring: - data: - mongodb: - uri: mongodb://填写mongodb地址/admin - database: iotkit - - cache: - cache-names: foo,bar - caffeine: - spec: maximumSize=5000,expireAfterAccess=120s - -mqtt: - url: tcp://填写mqtt连接地址 - diff --git a/device-server/mqtt-server/src/main/resources/application.yml b/device-server/mqtt-server/src/main/resources/application.yml deleted file mode 100755 index 5b877471..00000000 --- a/device-server/mqtt-server/src/main/resources/application.yml +++ /dev/null @@ -1,16 +0,0 @@ -server: - port: 8091 - -spring: - data: - mongodb: - uri: mongodb://填写mongodb地址/admin - database: iotkit - - cache: - cache-names: foo,bar - caffeine: - spec: maximumSize=5000,expireAfterAccess=120s - -mqtt: - url: tcp://填写mqtt连接地址 diff --git a/device-server/mqtt-server/src/main/resources/logback-spring.xml b/device-server/mqtt-server/src/main/resources/logback-spring.xml deleted file mode 100755 index 6322c4b5..00000000 --- a/device-server/mqtt-server/src/main/resources/logback-spring.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - DEBUG - - - ${CONSOLE_LOG_PATTERN} - utf8 - - - - - - ${LOG_FILE}/info.log - - ${LOG_FILE}/info.%d{yyyy-MM-dd}.%i.gz - - 5 - - 20GB - - - 1GB - - - - ${CONSOLE_LOG_PATTERN} - utf8 - - - - - - ${LOG_FILE}/error.log - - ${LOG_FILE}/error.%d{yyyy-MM-dd}.%i.gz - - 5 - - 5GB - - - 1GB - - - - ${CONSOLE_LOG_PATTERN} - utf8 - - - ERROR - ACCEPT - DENY - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/manager/.DS_Store b/manager/.DS_Store index aa005d05..f4c5579e 100755 Binary files a/manager/.DS_Store and b/manager/.DS_Store differ diff --git a/manager/pom.xml b/manager/pom.xml index 3e7e3530..8ce80576 100755 --- a/manager/pom.xml +++ b/manager/pom.xml @@ -12,6 +12,7 @@ manager + org.springframework.boot spring-boot-starter-data-mongodb @@ -32,11 +33,6 @@ spring-cloud-starter-openfeign - - com.github.xiaoymin - knife4j-spring-boot-starter - - org.springframework.boot spring-boot-starter-security @@ -128,11 +124,6 @@ common - - cc.iotkit - device-api - - cc.iotkit rule-engine @@ -143,23 +134,79 @@ dao + + cc.iotkit + component-server + + + + cc.iotkit + converter + + - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - - - - + + + + + + + + + + + + + + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.0 + + 1.8 + 1.8 + UTF-8 + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + cc.iotkit + standalone-package + ${project.version} + + + + false + + standalone-package + + + + + make-assembly + package + + single + + + + + + + + \ No newline at end of file diff --git a/manager/src/main/java/cc/iotkit/manager/Application.java b/manager/src/main/java/cc/iotkit/manager/Application.java index 15b2122f..f296ebd0 100755 --- a/manager/src/main/java/cc/iotkit/manager/Application.java +++ b/manager/src/main/java/cc/iotkit/manager/Application.java @@ -1,14 +1,17 @@ package cc.iotkit.manager; +import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; +@Slf4j @EnableFeignClients(basePackages = {"cc.iotkit.deviceapi"}) -@SpringBootApplication(scanBasePackages = {"cc.iotkit.manager", "cc.iotkit.dao", "cc.iotkit.ruleengine"}) +@SpringBootApplication(scanBasePackages = {"cc.iotkit"}) public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } + } diff --git a/manager/src/main/java/cc/iotkit/manager/config/ElasticSearchConfig.java b/manager/src/main/java/cc/iotkit/manager/config/ElasticSearchConfig.java new file mode 100755 index 00000000..c1a9c370 --- /dev/null +++ b/manager/src/main/java/cc/iotkit/manager/config/ElasticSearchConfig.java @@ -0,0 +1,75 @@ +package cc.iotkit.manager.config; + +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.node.InternalSettingsPreparer; +import org.elasticsearch.node.Node; +import org.elasticsearch.transport.Netty4Plugin; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +import java.util.Collections; + +@Slf4j +@Configuration +public class ElasticSearchConfig { + + static { + System.setProperty("es.set.netty.runtime.available.processors", "false"); + } + + @SneakyThrows + @Bean + public EmbeddedElasticSearch getEmbeddedElasticSearch(ConfigProperty configProperty) { + if (configProperty.enabled) { + EmbeddedElasticSearch embeddedElasticSearch = new EmbeddedElasticSearch(configProperty); + embeddedElasticSearch.start(); + return embeddedElasticSearch; + } + return null; + } + + @Component + @ConfigurationProperties(prefix = "elasticsearch.embedded") + public static class ConfigProperty { + + private boolean enabled; + + private String dataPath = "./data/elasticsearch"; + + private String homePath = "./"; + + private int port = 9200; + + private String host = "0.0.0.0"; + + public Settings.Builder applySetting(Settings.Builder settings) { + return settings.put("network.host", host) + .put("http.port", port) + .put("path.data", dataPath) + .put("path.home", homePath); + } + + } + + public static class EmbeddedElasticSearch extends Node { + + @SneakyThrows + public EmbeddedElasticSearch(ConfigProperty properties) { + super(InternalSettingsPreparer.prepareEnvironment( + properties.applySetting( + Settings.builder() + .put("node.name", "test") + .put("discovery.type", "single-node") + .put("transport.type", Netty4Plugin.NETTY_TRANSPORT_NAME) + .put("http.type", Netty4Plugin.NETTY_HTTP_TRANSPORT_NAME) + .put("network.host", "0.0.0.0") + .put("http.port", 9200) + ).build(), Collections.emptyMap(), null, () -> "default"), + Collections.singleton(Netty4Plugin.class), false); + } + } +} diff --git a/manager/src/main/java/cc/iotkit/manager/config/KeycloakSecurityConfig.java b/manager/src/main/java/cc/iotkit/manager/config/KeycloakSecurityConfig.java index ce806f61..19ad984c 100755 --- a/manager/src/main/java/cc/iotkit/manager/config/KeycloakSecurityConfig.java +++ b/manager/src/main/java/cc/iotkit/manager/config/KeycloakSecurityConfig.java @@ -54,12 +54,13 @@ public class KeycloakSecurityConfig extends KeycloakWebSecurityConfigurerAdapter http .authorizeRequests() .antMatchers("/*.html", "/favicon.ico","/v2/api-docs", "/webjars/**", "/swagger-resources/**", "/*.js").permitAll() - .antMatchers("/api/**").hasAnyRole("iot_client_user") - .antMatchers("/aligenieDevice/invoke/**").hasAnyRole("iot_client_user") + .antMatchers("/api/**").hasRole("iot_client_user") + .antMatchers("/aligenieDevice/invoke/**").hasRole("iot_client_user") .antMatchers("/**/save*").hasRole("iot_write") .antMatchers("/**/del*").hasRole("iot_write") .antMatchers("/**/add*").hasRole("iot_write") .antMatchers("/**/clear*").hasRole("iot_write") + .antMatchers("/**/set*").hasRole("iot_write") .antMatchers("/**").hasAnyRole(systemRole) .and().csrf().disable(); } diff --git a/manager/src/main/java/cc/iotkit/manager/config/SwaggerConfig.java b/manager/src/main/java/cc/iotkit/manager/config/SwaggerConfig.java deleted file mode 100755 index 17292179..00000000 --- a/manager/src/main/java/cc/iotkit/manager/config/SwaggerConfig.java +++ /dev/null @@ -1,78 +0,0 @@ -package cc.iotkit.manager.config; - -import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j; -import com.google.common.collect.Lists; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import springfox.documentation.builders.ApiInfoBuilder; -import springfox.documentation.builders.OAuthBuilder; -import springfox.documentation.builders.PathSelectors; -import springfox.documentation.builders.RequestHandlerSelectors; -import springfox.documentation.service.*; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spi.service.contexts.SecurityContext; -import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger2.annotations.EnableSwagger2; - -import java.util.ArrayList; -import java.util.List; - - -@Configuration -@EnableSwagger2 -@EnableKnife4j -public class SwaggerConfig { - - @Value("${keycloak.auth-server-url}") - private String authServerUrl; - - @Value("${keycloak.realm}") - private String realm; - - @Bean - public Docket productApi() { - //schema - List grantTypes = new ArrayList<>(); - //密码模式 - String passwordTokenUrl = String.format("%s/realms/%s/protocol/openid-connect/token", authServerUrl, realm); - ResourceOwnerPasswordCredentialsGrant resourceOwnerPasswordCredentialsGrant = new ResourceOwnerPasswordCredentialsGrant(passwordTokenUrl); - grantTypes.add(resourceOwnerPasswordCredentialsGrant); - OAuth oAuth = new OAuthBuilder().name("oauth2") - .grantTypes(grantTypes).build(); - - //context - //scope方位 - List scopes = new ArrayList<>(); - scopes.add(new AuthorizationScope("read", "read resources")); - scopes.add(new AuthorizationScope("write", "write resources")); - - SecurityReference securityReference = new SecurityReference("oauth2", scopes.toArray(new AuthorizationScope[]{})); - SecurityContext securityContext = new SecurityContext(Lists.newArrayList(securityReference), - PathSelectors.ant("/**"), - method -> true, - null - ); - - //schemas - List securitySchemes = Lists.newArrayList(oAuth); - List securityContexts = Lists.newArrayList(securityContext); - return new Docket(DocumentationType.SWAGGER_2) - .select() - .apis(RequestHandlerSelectors.basePackage("cc.iotkit.manager")) - .paths(PathSelectors.any()) - .build() - .securityContexts(securityContexts) - .securitySchemes(securitySchemes) - .apiInfo(apiInfo()); - } - - private ApiInfo apiInfo() { - return new ApiInfoBuilder().title("iot管理后台").description("") - .license("Open Source") - .version("1.0.0") - .build(); - - } - -} \ No newline at end of file diff --git a/manager/src/main/java/cc/iotkit/manager/controller/AppController.java b/manager/src/main/java/cc/iotkit/manager/controller/AppController.java index b9a16536..c54d5d98 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/AppController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/AppController.java @@ -5,9 +5,9 @@ import cc.iotkit.dao.CategoryRepository; import cc.iotkit.dao.ProductRepository; import cc.iotkit.manager.model.vo.AppDesignVo; import cc.iotkit.manager.service.DataOwnerService; +import cc.iotkit.model.Paging; import cc.iotkit.model.product.AppDesign; import cc.iotkit.model.product.Category; -import cc.iotkit.model.PagingData; import cc.iotkit.model.product.Product; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -37,7 +37,7 @@ public class AppController { private DataOwnerService dataOwnerService; @PostMapping("/designs") - public PagingData getDesigns() { + public Paging getDesigns() { List appDesignVos = new ArrayList<>(); List products = productRepository.findAll(Example @@ -64,7 +64,7 @@ public class AppController { } }); - return new PagingData<>(appDesignRepository.count(), + return new Paging<>(appDesignRepository.count(), appDesignVos); } diff --git a/manager/src/main/java/cc/iotkit/manager/controller/DbBaseController.java b/manager/src/main/java/cc/iotkit/manager/controller/DbBaseController.java deleted file mode 100755 index fdebab1d..00000000 --- a/manager/src/main/java/cc/iotkit/manager/controller/DbBaseController.java +++ /dev/null @@ -1,32 +0,0 @@ -package cc.iotkit.manager.controller; - -import org.springframework.data.mongodb.repository.MongoRepository; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; - -import java.util.List; - -public class DbBaseController, T> { - - protected final R repository; - - public DbBaseController(R r) { - this.repository = r; - } - - @GetMapping("/list") - public List list() { - return repository.findAll(); - } - - @PostMapping("/save") - public void save(T t) { - repository.save(t); - } - - @DeleteMapping("/delete") - public void delete(T t) { - repository.delete(t); - } -} diff --git a/manager/src/main/java/cc/iotkit/manager/controller/DeviceController.java b/manager/src/main/java/cc/iotkit/manager/controller/DeviceController.java index 751c3792..ce0cf258 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/DeviceController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/DeviceController.java @@ -1,26 +1,28 @@ package cc.iotkit.manager.controller; -import cc.iotkit.dao.DeviceDao; -import cc.iotkit.dao.DeviceEventDao; -import cc.iotkit.dao.DeviceEventRepository; -import cc.iotkit.dao.DeviceRepository; +import cc.iotkit.common.exception.BizException; +import cc.iotkit.common.utils.DeviceUtil; +import cc.iotkit.dao.*; import cc.iotkit.manager.service.DataOwnerService; import cc.iotkit.manager.service.DeviceService; import cc.iotkit.manager.utils.AuthUtil; -import cc.iotkit.model.device.message.DeviceEvent; +import cc.iotkit.model.Paging; import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.model.PagingData; +import cc.iotkit.model.device.message.DeviceProperty; +import cc.iotkit.model.device.message.ThingModelMessage; +import cc.iotkit.model.product.Product; import cc.iotkit.model.product.ThingModel; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; import org.springframework.data.domain.Example; -import org.springframework.data.domain.Sort; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.Map; +import java.util.Optional; @Slf4j @RestController @@ -32,15 +34,19 @@ public class DeviceController { @Autowired private DeviceRepository deviceRepository; @Autowired - private DeviceEventRepository deviceEventRepository; - @Autowired - private DeviceEventDao deviceEventDao; + private ProductRepository productRepository; @Autowired private DeviceDao deviceDao; @Autowired private DataOwnerService dataOwnerService; @Autowired private ProductController productController; + @Lazy + @Autowired + private ThingModelMessageDao thingModelMessageDao; + @Lazy + @Autowired + private DevicePropertyDao devicePropertyDao; @PostMapping("/{deviceId}/service/{service}") public String invokeService(@PathVariable("deviceId") String deviceId, @@ -49,22 +55,23 @@ public class DeviceController { if (StringUtils.isBlank(deviceId) || StringUtils.isBlank(service)) { throw new RuntimeException("deviceId/service is blank."); } - + dataOwnerService.checkWriteRole(); return deviceService.invokeService(deviceId, service, args); } @PostMapping("/{deviceId}/service/property/set") public String setProperty(@PathVariable("deviceId") String deviceId, @RequestBody Map args) { + dataOwnerService.checkWriteRole(); return deviceService.setProperty(deviceId, args); } @PostMapping("/list") - public PagingData getDevices(int page, - int size, - String pk, - Boolean online, - String dn) { + public Paging getDevices(int page, + int size, + String pk, + Boolean online, + String dn) { Criteria condition = new Criteria(); if (!AuthUtil.isAdmin()) { condition.and("uid").is(AuthUtil.getUserId()); @@ -78,8 +85,27 @@ public class DeviceController { if (online != null) { condition.and("state.online").is(online); } - return new PagingData<>(deviceDao.count(condition), - deviceDao.find(condition, (page - 1) * size, size, Sort.Order.desc("createAt"))); + + return deviceDao.find(condition, size, page); + } + + @PostMapping("/create") + public void createDevice(String productKey, String deviceName) { + Optional productOpt = productRepository.findById(productKey); + if (!productOpt.isPresent()) { + throw new BizException("the product does not exist"); + } + + DeviceInfo device = new DeviceInfo(); + device.setId(DeviceUtil.newDeviceId(deviceName)); + device.setUid(productOpt.get().getUid()); + device.setDeviceId(device.getId()); + device.setProductKey(productKey); + device.setDeviceName(deviceName); + device.setState(new DeviceInfo.State(false, null, null)); + device.setCreateAt(System.currentTimeMillis()); + + deviceRepository.save(device); } @GetMapping("/{deviceId}/children") @@ -112,29 +138,28 @@ public class DeviceController { deviceRepository.deleteById(deviceId); } - @PostMapping("/{deviceId}/events") - public PagingData events(@PathVariable("deviceId") String deviceId, - int page, - int limit, - String type, - String identifier) { - Criteria condition = Criteria.where("deviceId").is(deviceId); - if (StringUtils.isNotBlank(type)) { - condition.and("type").is(type); - } - if (StringUtils.isNotBlank(identifier)) { - condition.and("identifier").regex(".*" + identifier + ".*"); - } + @PostMapping("/{deviceId}/logs/{size}/{page}") + public Paging logs( + @PathVariable("deviceId") String deviceId, + @PathVariable("size") int size, + @PathVariable("page") int page, + String type, String identifier) { + return thingModelMessageDao.findByTypeAndIdentifier(deviceId, type, identifier, page, size); + } - return new PagingData<>(deviceEventDao.count(condition), - deviceEventDao.find(condition, - (page - 1) * limit, limit, Sort.Order.desc("createAt"))); + @GetMapping("/{deviceId}/property/{name}/{start}/{end}") + public List getPropertyHistory( + @PathVariable("deviceId") String deviceId, + @PathVariable("name") String name, + @PathVariable("start") long start, + @PathVariable("end") long end) { + return devicePropertyDao.findDevicePropertyHistory(deviceId, name, start, end); } @PostMapping("/{deviceId}/unbind") public void unbindDevice(@PathVariable("deviceId") String deviceId) { deviceId = getDetail(deviceId).getDeviceId(); - deviceService.unbindDevice(deviceId); +// deviceService.unbindDevice(deviceId); } @GetMapping("/{deviceId}/thingModel") @@ -142,4 +167,12 @@ public class DeviceController { DeviceInfo deviceInfo = getDetail(deviceId); return productController.getThingModel(deviceInfo.getProductKey()); } + + @PostMapping("/{deviceId}/tag/add") + public void addTag(@PathVariable("deviceId") String deviceId, + DeviceInfo.Tag tag) { + DeviceInfo device = deviceRepository.findByDeviceId(deviceId); + dataOwnerService.checkOwner(device); + deviceDao.updateTag(deviceId, tag); + } } diff --git a/manager/src/main/java/cc/iotkit/manager/controller/ProductController.java b/manager/src/main/java/cc/iotkit/manager/controller/ProductController.java index b0ea953b..1d7e28f5 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/ProductController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/ProductController.java @@ -6,8 +6,8 @@ import cc.iotkit.dao.ProductRepository; import cc.iotkit.dao.ThingModelRepository; import cc.iotkit.manager.config.AliyunConfig; import cc.iotkit.manager.service.DataOwnerService; +import cc.iotkit.model.Paging; import cc.iotkit.model.product.Category; -import cc.iotkit.model.PagingData; import cc.iotkit.model.product.Product; import cc.iotkit.model.product.ThingModel; import com.aliyun.oss.OSS; @@ -42,15 +42,14 @@ public class ProductController { private OSS ossClient; @PostMapping("/list") - public PagingData getProducts(Product form) { + public Paging getProducts(Product form) { form = dataOwnerService.wrapExample(form); - return new PagingData<>(productRepository.count(Example.of(form)), + return new Paging<>(productRepository.count(Example.of(form)), productRepository.findAll(Example.of(form))); } @PostMapping("/save") public void save(Product product) { - product.setId(product.getCode()); dataOwnerService.checkOwnerSave(productRepository, product); if (product.getCreateAt() == null) { @@ -66,19 +65,19 @@ public class ProductController { @GetMapping("/thingModel/{productKey}") public ThingModel getThingModel(@PathVariable("productKey") String productKey) { - productKey = getProduct(productKey).getCode(); + productKey = getProduct(productKey).getId(); return thingModelRepository.findById(productKey).orElse(new ThingModel(productKey)); } @PostMapping("/thingModel/save") public void saveThingModel(String productKey, String model) { - productKey = getProduct(productKey).getCode(); + productKey = getProduct(productKey).getId(); thingModelRepository.save(new ThingModel(productKey, productKey, JsonUtil.parse(model, ThingModel.Model.class))); } @DeleteMapping("/thingModel/{productKey}") public void deleteThingModel(String productKey) { - productKey = getProduct(productKey).getCode(); + productKey = getProduct(productKey).getId(); thingModelRepository.deleteById(productKey); } @@ -104,7 +103,7 @@ public class ProductController { @PostMapping("/uploadImg/{productKey}") public String uploadImg(@PathVariable("productKey") String productKey, @RequestParam("file") MultipartFile file) { - productKey = getProduct(productKey).getCode(); + productKey = getProduct(productKey).getId(); String fileName = file.getOriginalFilename(); String end = fileName.substring(fileName.lastIndexOf(".")); diff --git a/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java b/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java new file mode 100755 index 00000000..8af55f6c --- /dev/null +++ b/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java @@ -0,0 +1,311 @@ +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.config.ComponentConfig; +import cc.iotkit.dao.ProtocolComponentRepository; +import cc.iotkit.dao.ProtocolConverterRepository; +import cc.iotkit.dao.UserInfoRepository; +import cc.iotkit.manager.service.DataOwnerService; +import cc.iotkit.manager.utils.AuthUtil; +import cc.iotkit.model.Paging; +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.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.nio.file.*; +import java.util.Optional; +import java.util.UUID; + +@Slf4j +@RestController +@RequestMapping("/protocol") +public class ProtocolController { + + @Autowired + private ComponentConfig componentConfig; + + @Autowired + private ProtocolComponentRepository protocolComponentRepository; + + @Autowired + private ProtocolConverterRepository protocolConverterRepository; + + @Autowired + private DataOwnerService dataOwnerService; + + @Autowired + private UserInfoRepository userInfoRepository; + + @Autowired + private ComponentManager componentManager; + + @PostMapping("/uploadJar") + public String uploadJar(@RequestParam("file") MultipartFile file, String id) { + if (file == null) { + throw new BizException("file is null"); + } + log.info("saving upload jar file:{}", file.getName()); + String fileName = StringUtils.cleanPath(file.getOriginalFilename()); + try { + if (StringUtils.hasLength(id)) { + getAndCheckComponent(id); + } else { + id = UUID.randomUUID().toString(); + } + Path jarFilePath = componentConfig.getComponentFilePath(id); + Files.createDirectories(jarFilePath); + Path targetLocation = jarFilePath.resolve(fileName); + Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING); + return id; + } catch (IOException ex) { + throw new BizException("upload jar error", ex); + } + } + + @PostMapping("/addComponent") + public void addComponent(ProtocolComponent component) { + String id = component.getId(); + if (!StringUtils.hasLength(id)) { + throw new BizException("component id is blank"); + } + Path jarPath = componentConfig.getComponentFilePath(id); + if (!jarPath.resolve(component.getJarFile()).toFile().exists()) { + throw new BizException("component jar file does not exist"); + } + + Optional optComponent = protocolComponentRepository.findById(id); + if (optComponent.isPresent()) { + throw new BizException("component already exists"); + } + try { + component.setCreateAt(System.currentTimeMillis()); + component.setUid(AuthUtil.getUserId()); + protocolComponentRepository.save(component); + } catch (Throwable e) { + throw new BizException("add protocol component error", e); + } + } + + @PostMapping("/saveComponent") + public void saveComponent(ProtocolComponent component) { + String id = component.getId(); + if (!StringUtils.hasLength(id)) { + throw new BizException("component id is blank"); + } + Path jarPath = componentConfig.getComponentFilePath(id); + if (!jarPath.resolve(component.getJarFile()).toFile().exists()) { + throw new BizException("component jar file does not exist"); + } + + ProtocolComponent oldComponent = getAndCheckComponent(id); + component = ReflectUtil.copyNoNulls(component, oldComponent); + try { + componentManager.deRegister(id); + protocolComponentRepository.save(component); + } catch (Throwable e) { + throw new BizException("add protocol component error", e); + } + } + + @GetMapping("/getComponentScript/{id}") + public String getComponentScript(@PathVariable("id") String id) { + getAndCheckComponent(id); + try { + Path path = componentConfig.getComponentFilePath(id); + File file = path.resolve(ProtocolComponent.SCRIPT_FILE_NAME).toFile(); + return FileUtils.readFileToString(file, "UTF-8"); + } catch (Throwable e) { + log.error("read component script file error", e); + return ""; + } + } + + @PostMapping("/saveComponentScript/{id}") + public void saveComponentScript( + @PathVariable("id") String id, + @RequestBody String script) { + ProtocolComponent oldComponent = getAndCheckComponent(id); + try { + 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 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) { + ProtocolComponent component = getAndCheckComponent(id); + try { + componentManager.deRegister(id); + + Path path = Paths.get(String.format("%s/%s", componentConfig.getComponentDir(), id)) + .toAbsolutePath().normalize(); + File file = path.toFile(); + try { + if (file.isDirectory()) { + FileUtils.deleteDirectory(file); + } else { + FileUtils.delete(file); + } + } catch (NoSuchFileException e) { + log.warn("delete component script error", e); + } + protocolComponentRepository.deleteById(component.getId()); + } catch (Throwable e) { + throw new BizException("delete protocol component error", e); + } + } + + @PostMapping("/components/{size}/{page}") + public Paging getComponents( + @PathVariable("size") int size, + @PathVariable("page") int page) { + Page 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()); + } + + @PostMapping("/converters/{size}/{page}") + public Paging getConverters( + @PathVariable("size") int size, + @PathVariable("page") int page) { + protocolConverterRepository.deleteById(""); + protocolConverterRepository.deleteById("null"); + Page converters = protocolConverterRepository.findAll( + PageRequest.of(page - 1, size, Sort.by(Sort.Order.desc("createAt")))); + return new Paging<>(converters.getTotalElements(), converters.getContent()); + } + + @PostMapping("/addConverter") + public void addConverter(ProtocolConverter converter) { + try { + converter.setId(null); + converter.setCreateAt(System.currentTimeMillis()); + converter.setUid(AuthUtil.getUserId()); + protocolConverterRepository.save(converter); + } catch (Throwable e) { + throw new BizException("add protocol converter error", e); + } + } + + @PostMapping("/saveConverter") + public void saveConverter(ProtocolConverter converter) { + ProtocolConverter oldConverter = getAndCheckConverter(converter.getId()); + converter = ReflectUtil.copyNoNulls(converter, oldConverter); + try { + protocolConverterRepository.save(converter); + } catch (Throwable e) { + throw new BizException("add protocol converter error", e); + } + } + + private ProtocolConverter getAndCheckConverter(String id) { + Optional optConverter = protocolConverterRepository.findById(id); + if (!optConverter.isPresent()) { + 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 = componentConfig.getConverterFilePath(id); + File file = path.resolve(ProtocolConverter.SCRIPT_FILE_NAME).toFile(); + return FileUtils.readFileToString(file, "UTF-8"); + } catch (Throwable e) { + log.error("read converter script file error", e); + return ""; + } + } + + @PostMapping("/saveConverterScript/{id}") + public void saveConverterScript( + @PathVariable("id") String id, + @RequestBody String script) { + getAndCheckConverter(id); + try { + 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); + } catch (Throwable e) { + throw new BizException("save protocol converter script error", e); + } + } + + @PostMapping("/deleteConverter/{id}") + public void deleteConverter(@PathVariable("id") String id) { + getAndCheckConverter(id); + try { + Path path = Paths.get(String.format("%s/%s", componentConfig.getConverterDir(), id)) + .toAbsolutePath().normalize(); + File file = path.toFile(); + try { + if (file.isDirectory()) { + FileUtils.deleteDirectory(file); + } else { + FileUtils.delete(file); + } + } catch (NoSuchFileException e) { + log.warn("delete converter script error", e); + } + protocolConverterRepository.deleteById(id); + } catch (Throwable e) { + throw new BizException("delete protocol converter error", e); + } + } + + @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); + } + +} diff --git a/manager/src/main/java/cc/iotkit/manager/controller/RuleEngineController.java b/manager/src/main/java/cc/iotkit/manager/controller/RuleEngineController.java index e855629b..9f317c1d 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/RuleEngineController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/RuleEngineController.java @@ -6,20 +6,18 @@ import cc.iotkit.dao.*; import cc.iotkit.manager.service.DataOwnerService; import cc.iotkit.manager.utils.AuthUtil; import cc.iotkit.model.Paging; -import cc.iotkit.model.rule.SceneInfo; -import cc.iotkit.model.rule.SceneLog; +import cc.iotkit.model.rule.RuleInfo; +import cc.iotkit.model.rule.RuleLog; import cc.iotkit.model.rule.TaskInfo; import cc.iotkit.model.rule.TaskLog; -import cc.iotkit.ruleengine.scene.SceneManager; +import cc.iotkit.ruleengine.rule.RuleManager; import cc.iotkit.ruleengine.task.TaskManager; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.quartz.SchedulerException; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Example; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Sort; +import org.springframework.context.annotation.Lazy; +import org.springframework.data.domain.*; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -35,13 +33,11 @@ public class RuleEngineController { private TaskInfoRepository taskInfoRepository; @Autowired - private SceneInfoRepository sceneInfoRepository; + private RuleInfoRepository ruleInfoRepository; + @Lazy @Autowired - private SceneLogRepository sceneLogRepository; - - @Autowired - private SceneLogDao sceneLogDao; + private RuleLogRepository ruleLogRepository; @Autowired private DataOwnerService dataOwnerService; @@ -50,107 +46,111 @@ public class RuleEngineController { private TaskManager taskManager; @Autowired - private SceneManager sceneManager; - - @Autowired - private TaskLogDao taskLogDao; + private RuleManager ruleManager; + @Lazy @Autowired private TaskLogRepository taskLogRepository; - @PostMapping("/scenes") - public List scenes() { - return sceneInfoRepository.findAll(Example.of(dataOwnerService - .wrapExample(new SceneInfo())) - ); - } - - @PostMapping("/saveScene") - public void saveScene(@RequestBody SceneInfo scene) { - if (StringUtils.isBlank(scene.getId())) { - scene.setId(UUID.randomUUID().toString()); - scene.setState(SceneInfo.STATE_STOPPED); - scene.setCreateAt(System.currentTimeMillis()); - scene.setUid(AuthUtil.getUserId()); - sceneInfoRepository.save(scene); - sceneManager.add(scene); - } else { - Optional oldScene = sceneInfoRepository.findById(scene.getId()); - if (!oldScene.isPresent()) { - throw new BizException("Scene does not exist"); - } - SceneInfo sceneInfo = oldScene.get(); - if (SceneInfo.STATE_RUNNING.equals(sceneInfo.getState())) { - throw new BizException("Scene is running"); - } - - dataOwnerService.checkOwner(sceneInfo); - - sceneInfo.setListeners(scene.getListeners()); - sceneInfo.setFilters(scene.getFilters()); - sceneInfo.setActions(scene.getActions()); - sceneInfo.setName(scene.getName()); - sceneInfo.setDesc(scene.getDesc()); - - sceneInfoRepository.save(sceneInfo); - } - } - - @PostMapping("/scene/{sceneId}/pause") - public void pauseScene(@PathVariable("sceneId") String sceneId) { - Optional sceneOpt = sceneInfoRepository.findById(sceneId); - if (!sceneOpt.isPresent()) { - throw new BizException("Scene does not exist"); - } - SceneInfo sceneInfo = sceneOpt.get(); - dataOwnerService.checkOwner(sceneInfo); - sceneInfo.setState(SceneInfo.STATE_STOPPED); - sceneInfoRepository.save(sceneInfo); - sceneManager.pause(sceneInfo.getId()); - } - - @PostMapping("/scene/{sceneId}/resume") - public void resumeScene(@PathVariable("sceneId") String sceneId) { - Optional sceneOpt = sceneInfoRepository.findById(sceneId); - if (!sceneOpt.isPresent()) { - throw new BizException("Scene does not exist"); - } - SceneInfo sceneInfo = sceneOpt.get(); - dataOwnerService.checkOwner(sceneInfo); - sceneInfo.setState(SceneInfo.STATE_RUNNING); - sceneInfoRepository.save(sceneInfo); - sceneManager.resume(sceneInfo); - } - - @DeleteMapping("/scene/{sceneId}/delete") - public void deleteScene(@PathVariable("sceneId") String sceneId) { - Optional sceneOpt = sceneInfoRepository.findById(sceneId); - if (!sceneOpt.isPresent()) { - throw new BizException("Scene does not exist"); - } - SceneInfo sceneInfo = sceneOpt.get(); - dataOwnerService.checkOwner(sceneInfo); - sceneInfoRepository.delete(sceneInfo); - sceneManager.remove(sceneInfo.getId()); - sceneLogDao.deleteLogs(sceneId); - } - - @PostMapping("/scene/{sceneId}/logs/{size}/{page}") - public Paging getSceneLogs( - @PathVariable("sceneId") String sceneId, + @PostMapping("/rules/{type}/{size}/{page}") + public Paging rules( + @PathVariable("type") String type, @PathVariable("size") int size, @PathVariable("page") int page ) { - SceneLog sceneLog=new SceneLog(); - sceneLog.setSceneId(sceneId); - Page sceneLogs = sceneLogRepository.findAll(Example.of(sceneLog), - PageRequest.of(page - 1, size, Sort.by(Sort.Order.desc("logAt")))); - return new Paging<>(sceneLogs.getTotalElements(), sceneLogs.getContent()); + RuleInfo ruleInfo = new RuleInfo(); + ruleInfo.setType(type); + Page rules = ruleInfoRepository.findAll(Example.of(dataOwnerService + .wrapExample(ruleInfo)), Pageable.ofSize(size).withPage(page - 1)); + return new Paging<>(rules.getTotalElements(), rules.getContent()); } - @DeleteMapping("/scene/{sceneId}/logs/clear") - public void clearSceneLogs(@PathVariable("sceneId") String sceneId) { - sceneLogDao.deleteLogs(sceneId); + @PostMapping("/rule/save") + public void saveRule(@RequestBody RuleInfo rule) { + if (StringUtils.isBlank(rule.getId())) { + rule.setId(UUID.randomUUID().toString()); + rule.setState(RuleInfo.STATE_STOPPED); + rule.setCreateAt(System.currentTimeMillis()); + rule.setUid(AuthUtil.getUserId()); + ruleInfoRepository.save(rule); + ruleManager.add(rule); + } else { + Optional oldRule = ruleInfoRepository.findById(rule.getId()); + if (!oldRule.isPresent()) { + throw new BizException("Rule does not exist"); + } + RuleInfo ruleInfo = oldRule.get(); + if (RuleInfo.STATE_RUNNING.equals(ruleInfo.getState())) { + throw new BizException("Rule is running"); + } + + dataOwnerService.checkOwner(ruleInfo); + + ruleInfo.setListeners(rule.getListeners()); + ruleInfo.setFilters(rule.getFilters()); + ruleInfo.setActions(rule.getActions()); + ruleInfo.setName(rule.getName()); + ruleInfo.setDesc(rule.getDesc()); + + ruleInfoRepository.save(ruleInfo); + } + } + + @PostMapping("/rule/{ruleId}/pause") + public void pauseRule(@PathVariable("ruleId") String ruleId) { + Optional ruleOpt = ruleInfoRepository.findById(ruleId); + if (!ruleOpt.isPresent()) { + throw new BizException("Rule does not exist"); + } + RuleInfo ruleInfo = ruleOpt.get(); + dataOwnerService.checkOwner(ruleInfo); + ruleInfo.setState(RuleInfo.STATE_STOPPED); + ruleInfoRepository.save(ruleInfo); + ruleManager.pause(ruleInfo.getId()); + } + + @PostMapping("/rule/{ruleId}/resume") + public void resumeRule(@PathVariable("ruleId") String ruleId) { + Optional ruleOpt = ruleInfoRepository.findById(ruleId); + if (!ruleOpt.isPresent()) { + throw new BizException("Rule does not exist"); + } + RuleInfo ruleInfo = ruleOpt.get(); + dataOwnerService.checkOwner(ruleInfo); + ruleInfo.setState(RuleInfo.STATE_RUNNING); + ruleInfoRepository.save(ruleInfo); + ruleManager.resume(ruleInfo); + } + + @DeleteMapping("/rule/{ruleId}/delete") + public void deleteRule(@PathVariable("ruleId") String ruleId) { + Optional ruleOpt = ruleInfoRepository.findById(ruleId); + if (!ruleOpt.isPresent()) { + throw new BizException("Rule does not exist"); + } + RuleInfo ruleInfo = ruleOpt.get(); + dataOwnerService.checkOwner(ruleInfo); + ruleInfoRepository.delete(ruleInfo); + ruleManager.remove(ruleInfo.getId()); + ruleLogRepository.deleteByRuleId(ruleId); + } + + @PostMapping("/rule/{ruleId}/logs/{size}/{page}") + public Paging getRuleLogs( + @PathVariable("ruleId") String ruleId, + @PathVariable("size") int size, + @PathVariable("page") int page + ) { + RuleLog ruleLog = new RuleLog(); + ruleLog.setRuleId(ruleId); + Page ruleLogs = ruleLogRepository.findByRuleId(ruleId, + PageRequest.of(page - 1, size, Sort.by(Sort.Order.desc("logAt")))); + return new Paging<>(ruleLogs.getTotalElements(), ruleLogs.getContent()); + } + + @DeleteMapping("/rule/{ruleId}/logs/clear") + public void clearRuleLogs(@PathVariable("ruleId") String ruleId) { + ruleLogRepository.deleteByRuleId(ruleId); } @PostMapping("/tasks") @@ -230,7 +230,7 @@ public class RuleEngineController { dataOwnerService.checkOwner(taskInfo); taskManager.deleteTask(taskId, "delete by " + AuthUtil.getUserId()); taskInfoRepository.deleteById(taskId); - taskLogDao.deleteLogs(taskId); + taskLogRepository.deleteByTaskId(taskId); } @PostMapping("/task/{taskId}/logs/{size}/{page}") @@ -241,14 +241,14 @@ public class RuleEngineController { ) { TaskLog taskLog = new TaskLog(); taskLog.setTaskId(taskId); - Page taskLogs = taskLogRepository.findAll(Example.of(taskLog), + Page taskLogs = taskLogRepository.findByTaskId(taskId, PageRequest.of(page - 1, size, Sort.by(Sort.Order.desc("logAt")))); return new Paging<>(taskLogs.getTotalElements(), taskLogs.getContent()); } @DeleteMapping("/task/{taskId}/logs/clear") public void clearTaskLogs(@PathVariable("taskId") String taskId) { - taskLogDao.deleteLogs(taskId); + taskLogRepository.deleteByTaskId(taskId); } } diff --git a/manager/src/main/java/cc/iotkit/manager/controller/SpaceController.java b/manager/src/main/java/cc/iotkit/manager/controller/SpaceController.java index 46e9608a..fc63f838 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/SpaceController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/SpaceController.java @@ -23,49 +23,47 @@ import java.util.stream.Collectors; @RequestMapping("/space") public class SpaceController { - @Autowired - private UserInfoDao userInfoDao; @Autowired private SpaceDeviceRepository spaceDeviceRepository; @Autowired private DeviceRepository deviceRepository; @Autowired - private DeviceDao deviceDao; + private DeviceCache deviceCache; @Autowired - private ProductDao productDao; + private ProductCache productCache; - @PostMapping("/list") - public PagingData getDevices(int page, - int limit, - String address) { - Criteria condition = new Criteria(); - if (StringUtils.isNotBlank(address)) { - condition.and("address").regex(".*" + address + ".*"); - } - List userInfoList = userInfoDao.find(condition, (page - 1) * limit, - limit, Sort.Order.desc("createAt")); - - List spaces = userInfoList.stream().map((u -> - new SpaceInfo(u.getAddress(), u.getUid()))) - .collect(Collectors.toList()); - - return new PagingData<>(userInfoDao.count(condition), - spaces); - } +// @PostMapping("/list") +// public Paging getDevices(int page, +// int limit, +// String address) { +// Criteria condition = new Criteria(); +// if (StringUtils.isNotBlank(address)) { +// condition.and("address").regex(".*" + address + ".*"); +// } +// List userInfoList = userInfoDao.find(condition, (page - 1) * limit, +// limit, Sort.Order.desc("createAt")); +// +// List spaces = userInfoList.stream().map((u -> +// new SpaceInfo(u.getAddress(), u.getUid()))) +// .collect(Collectors.toList()); +// +// return new Paging<>(userInfoDao.count(condition), +// spaces); +// } @GetMapping("/{userId}/devices") public List getDevices(@PathVariable("userId") String userId) { List deviceVos = new ArrayList<>(); List devices = spaceDeviceRepository.findAll(Example.of(SpaceDevice.builder().uid(userId).build())); devices.forEach(sd -> { - DeviceInfo deviceInfo = deviceDao.get(sd.getDeviceId()); - Product product = productDao.get(deviceInfo.getProductKey()); + DeviceInfo deviceInfo = deviceCache.findByDeviceId(sd.getDeviceId()); + Product product = productCache.findById(deviceInfo.getProductKey()); deviceVos.add(SpaceDeviceVo.builder() .deviceId(sd.getDeviceId()) .name(sd.getName()) .picUrl(product.getImg()) .spaceName(sd.getSpaceName()) - .online(deviceInfo.getState().getOnline()) + .online(deviceInfo.getState().isOnline()) .property(deviceInfo.getProperty()) .productKey(deviceInfo.getProductKey()) .build()); diff --git a/manager/src/main/java/cc/iotkit/manager/controller/UserInfoController.java b/manager/src/main/java/cc/iotkit/manager/controller/UserInfoController.java index 93ad1e33..6b7d6737 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/UserInfoController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/UserInfoController.java @@ -7,11 +7,11 @@ import cc.iotkit.dao.AligenieDeviceRepository; import cc.iotkit.dao.UserInfoRepository; import cc.iotkit.manager.service.DataOwnerService; import cc.iotkit.manager.service.KeycloakAdminService; +import cc.iotkit.manager.service.PulsarAdminService; import cc.iotkit.manager.utils.AuthUtil; import cc.iotkit.model.UserInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.data.domain.Example; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; @@ -29,18 +29,20 @@ public class UserInfoController { @Autowired private UserInfoRepository userInfoRepository; @Autowired + private PulsarAdminService pulsarAdminService; + @Autowired private AligenieDeviceRepository aligenieDeviceRepository; @Autowired private DataOwnerService ownerService; + /** * 平台用户列表 */ @PreAuthorize("hasRole('iot_admin')") @GetMapping("/platform/users") public List getPlatformUsers() { - return userInfoRepository.findAll(Example.of(UserInfo.builder() - .type(UserInfo.USER_TYPE_PLATFORM).build())); + return userInfoRepository.findByType(UserInfo.USER_TYPE_PLATFORM); } /** @@ -48,13 +50,26 @@ public class UserInfoController { */ @PostMapping("/platform/user/add") public void addPlatformUser(@RequestBody UserInfo user) { - user.setType(UserInfo.USER_TYPE_PLATFORM); - user.setOwnerId(AuthUtil.getUserId()); - user.setRoles(Collections.singletonList(Constants.ROLE_SYSTEM)); - user.setCreateAt(System.currentTimeMillis()); - String uid = keycloakAdminService.createUser(user, Constants.PWD_SYSTEM_USER); - user.setId(uid); - userInfoRepository.save(user); + try { + user.setId(UUID.randomUUID().toString()); + user.setType(UserInfo.USER_TYPE_PLATFORM); + user.setOwnerId(AuthUtil.getUserId()); + user.setRoles(Arrays.asList(Constants.ROLE_SYSTEM)); + user.setCreateAt(System.currentTimeMillis()); + UserInfo keycloakUser = keycloakAdminService.getUser(user.getUid()); + if (keycloakUser != null) { + user.setId(keycloakUser.getId()); + keycloakAdminService.updateUser(user); + } else { + keycloakAdminService.createUser(user, Constants.PWD_SYSTEM_USER); + } + if (!pulsarAdminService.tenantExists(user.getUid())) { + pulsarAdminService.createTenant(user.getUid()); + } + userInfoRepository.save(user); + } catch (Throwable e) { + throw new BizException("add platform user error", e); + } } /** @@ -62,11 +77,7 @@ public class UserInfoController { */ @GetMapping("/client/users") public List clientUsers() { - return userInfoRepository.findAll(Example.of( - UserInfo.builder() - .type(UserInfo.USER_TYPE_CLIENT) - .ownerId(AuthUtil.getUserId()) - .build())); + return userInfoRepository.findByTypeAndOwnerId(UserInfo.USER_TYPE_CLIENT, AuthUtil.getUserId()); } /** diff --git a/manager/src/main/java/cc/iotkit/manager/controller/aligenie/AligenieDeviceController.java b/manager/src/main/java/cc/iotkit/manager/controller/aligenie/AligenieDeviceController.java index bcec8ec7..f6b9717b 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/aligenie/AligenieDeviceController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/aligenie/AligenieDeviceController.java @@ -3,25 +3,31 @@ package cc.iotkit.manager.controller.aligenie; import cc.iotkit.common.exception.BizException; import cc.iotkit.common.exception.OfflineException; import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.dao.AligenieDeviceRepository; -import cc.iotkit.dao.AligenieProductRepository; -import cc.iotkit.dao.DeviceRepository; -import cc.iotkit.dao.UserInfoRepository; -import cc.iotkit.deviceapi.IDeviceManager; +import cc.iotkit.common.utils.UniqueIdUtil; +import cc.iotkit.dao.*; import cc.iotkit.manager.service.DataOwnerService; +import cc.iotkit.manager.service.DeviceService; import cc.iotkit.manager.utils.AuthUtil; import cc.iotkit.model.InvokeResult; import cc.iotkit.model.UserInfo; import cc.iotkit.model.aligenie.AligenieDevice; import cc.iotkit.model.aligenie.AligenieProduct; import cc.iotkit.model.device.DeviceInfo; +import cc.iotkit.model.device.message.ThingModelMessage; import io.swagger.annotations.ApiOperation; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.apache.pulsar.client.api.Producer; +import org.apache.pulsar.client.api.PulsarClient; +import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.pulsar.client.impl.schema.JSONSchema; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.*; +import javax.annotation.PostConstruct; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -42,7 +48,26 @@ public class AligenieDeviceController { @Autowired private AligenieProductRepository aligenieProductRepository; @Autowired - private IDeviceManager deviceManager; + private DeviceService deviceService; + @Autowired + private DeviceDao deviceDao; + @Value("${app.aligenie.push.device}") + private String pushDevice; + @Value("${pulsar.broker}") + private String pulsarBrokerUrl; + + private Producer deviceMessageProducer; + + @PostConstruct + public void init() throws PulsarClientException { + //初始化pulsar客户端 + PulsarClient client = PulsarClient.builder() + .serviceUrl(pulsarBrokerUrl) + .build(); + deviceMessageProducer = client.newProducer(JSONSchema.of(ThingModelMessage.class)) + .topic("persistent://iotkit/default/device_thing") + .create(); + } @GetMapping("/list/{uid}") public List getDevices(@PathVariable("uid") String uid) { @@ -53,27 +78,56 @@ public class AligenieDeviceController { @PostMapping("/bind/{uid}") public void bind(@PathVariable("uid") String uid, - @RequestBody List devices) { + @RequestBody List devices) throws PulsarClientException { Optional optUser = userInfoRepository.findById(uid); if (!optUser.isPresent()) { throw new BizException("user does not exist"); } UserInfo user = optUser.get(); ownerService.checkOwner(user); - + String token = ""; + List aligenieDevices = aligenieDeviceRepository.findByUid(uid); + //先清除待删除的标签 + for (AligenieDevice alDevice : aligenieDevices) { + deviceDao.setTagNull(alDevice.getDeviceId(), "aligenie"); + token = alDevice.getToken(); + } + //删除原有的设备 aligenieDeviceRepository.deleteByUid(uid); + for (Device device : devices) { DeviceInfo deviceInfo = deviceRepository.findById(device.getDeviceId()).get(); AligenieProduct product = aligenieProductRepository.findByProductKey(deviceInfo.getProductKey()); aligenieDeviceRepository.save(AligenieDevice.builder() .uid(user.getId()) + .token(token) .deviceId(device.getDeviceId()) .productId(product.getProductId()) .spaceName("客厅") .name(device.getName()) .build()); + + //设置天猫精灵接入标签 + deviceDao.updateTag(device.getDeviceId(), + new DeviceInfo.Tag("aligenie", "天猫精灵接入", "是")); } + DeviceInfo deviceInfo = deviceRepository.findByDeviceId(pushDevice); + if (deviceInfo == null) { + return; + } + + Map uidData = new HashMap<>(); + uidData.put("uid", uid); + deviceMessageProducer.send(ThingModelMessage.builder() + .deviceId(pushDevice) + .productKey(deviceInfo.getProductKey()) + .deviceName(deviceInfo.getDeviceName()) + .type(ThingModelMessage.TYPE_EVENT) + .identifier("userDevicesChange") + .mid(UniqueIdUtil.newRequestId()) + .data(uidData) + .build()); } @ApiOperation("设备服务调用") @@ -98,11 +152,11 @@ public class AligenieDeviceController { try { String requestId; if ("set".equals(service)) { - requestId = deviceManager.setProperty(deviceId, - JsonUtil.parse(args, Map.class)); + requestId = deviceService.setProperty(deviceId, + JsonUtil.parse(args, Map.class), false); } else { - requestId = deviceManager.invokeService(deviceId, service, - JsonUtil.parse(args, Map.class)); + requestId = deviceService.invokeService(deviceId, + service, JsonUtil.parse(args, Map.class), false); } result.setRequestId(requestId); result.setCode(InvokeResult.SUCCESS); diff --git a/manager/src/main/java/cc/iotkit/manager/controller/api/MessageController.java b/manager/src/main/java/cc/iotkit/manager/controller/api/MessageController.java index 89b0e2b4..b0401ac1 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/api/MessageController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/api/MessageController.java @@ -1,7 +1,7 @@ package cc.iotkit.manager.controller.api; -import cc.iotkit.dao.DeviceDao; -import cc.iotkit.dao.ProductDao; +import cc.iotkit.dao.DeviceCache; +import cc.iotkit.dao.ProductCache; import cc.iotkit.dao.UserActionLogRepository; import cc.iotkit.manager.model.vo.MessageVo; import cc.iotkit.manager.utils.AuthUtil; @@ -31,9 +31,9 @@ public class MessageController { @Autowired private UserActionLogRepository userActionLogRepository; @Autowired - private ProductDao productDao; + private ProductCache productCache; @Autowired - private DeviceDao deviceDao; + private DeviceCache deviceCache; @ApiOperation("取系统消息") @PostMapping("/getSysMessages") @@ -67,9 +67,12 @@ public class MessageController { StringBuffer logMsg = new StringBuffer(); if (log instanceof DeviceEvent) { DeviceEvent de = (DeviceEvent) log; - DeviceInfo device = deviceDao.getByDeviceId(de.getDeviceId()); - ThingModel.Model model = productDao.getThingModel(device.getProductKey()) - .getModel(); + DeviceInfo device = deviceCache.findByDeviceId(de.getDeviceId()); + ThingModel thingModel = productCache.getThingModel(device.getProductKey()); + if (thingModel == null) { + return logMsg.toString(); + } + ThingModel.Model model = thingModel.getModel(); logMsg.append("将【").append(target).append("】"); String identifier = de.getIdentifier(); diff --git a/manager/src/main/java/cc/iotkit/manager/controller/api/SpaceController.java b/manager/src/main/java/cc/iotkit/manager/controller/api/SpaceController.java index 1975c110..457c5809 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/api/SpaceController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/api/SpaceController.java @@ -39,9 +39,9 @@ public class SpaceController { @Autowired private ProductRepository productRepository; @Autowired - private ProductDao productDao; + private ProductCache productCache; @Autowired - private DeviceDao deviceDao; + private DeviceCache deviceCache; @Autowired private SpaceDeviceService spaceDeviceService; @@ -170,8 +170,8 @@ public class SpaceController { } private SpaceDeviceVo buildSpaceDeviceVo(String id, String deviceId, String uid, String name, String spaceName) { - DeviceInfo deviceInfo = deviceDao.get(deviceId); - Product product = productDao.get(deviceInfo.getProductKey()); + DeviceInfo deviceInfo = deviceCache.findByDeviceId(deviceId); + Product product = productCache.findById(deviceInfo.getProductKey()); return SpaceDeviceVo.builder() .id(id) .uid(uid) @@ -180,7 +180,7 @@ public class SpaceController { .deviceName(deviceInfo.getDeviceName()) .picUrl(product.getImg()) .spaceName(spaceName) - .online(deviceInfo.getState().getOnline()) + .online(deviceInfo.getState().isOnline()) .property(deviceInfo.getProperty() == null ? new HashMap<>() : deviceInfo.getProperty()) .productKey(deviceInfo.getProductKey()) .build(); diff --git a/manager/src/main/java/cc/iotkit/manager/model/vo/DeviceLog.java b/manager/src/main/java/cc/iotkit/manager/model/vo/DeviceLog.java new file mode 100755 index 00000000..82a0b7cf --- /dev/null +++ b/manager/src/main/java/cc/iotkit/manager/model/vo/DeviceLog.java @@ -0,0 +1,9 @@ +package cc.iotkit.manager.model.vo; + +import lombok.Data; + +@Data +public class DeviceLog { + + +} diff --git a/manager/src/main/java/cc/iotkit/manager/service/AligenieService.java b/manager/src/main/java/cc/iotkit/manager/service/AligenieService.java deleted file mode 100755 index 07bda95b..00000000 --- a/manager/src/main/java/cc/iotkit/manager/service/AligenieService.java +++ /dev/null @@ -1,90 +0,0 @@ -package cc.iotkit.manager.service; - -import cc.iotkit.dao.AligenieDeviceRepository; -import cc.iotkit.dao.AligenieProductDao; -import cc.iotkit.dao.DeviceDao; -import cc.iotkit.dao.SpaceDeviceRepository; -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.model.space.SpaceDevice; -import cc.iotkit.model.UserInfo; -import cc.iotkit.model.aligenie.AligenieDevice; -import cc.iotkit.model.aligenie.AligenieProduct; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Example; -import org.springframework.stereotype.Service; - -import java.util.List; - -@Service -public class AligenieService { - - @Autowired - private SpaceDeviceRepository spaceDeviceRepository; - - @Autowired - private AligenieDeviceRepository aligenieDeviceRepository; - - @Autowired - private AligenieProductDao aligenieProductDao; - - @Autowired - private DeviceDao deviceDao; - - public void syncDevice(UserInfo user) { - if (!user.getUsePlatforms().isAligenie()) { - //清空 - List aligenieDevices = aligenieDeviceRepository.findAll(Example.of( - AligenieDevice.builder() - .uid(user.getId()) - .build())); - for (AligenieDevice aligenieDevice : aligenieDevices) { - aligenieDeviceRepository.delete(aligenieDevice); - } - return; - } - - //找出用户空间下所有设备 - List spaceDeviceList = spaceDeviceRepository.findAll(Example.of( - SpaceDevice.builder().uid(user.getId()).build() - )); - - for (SpaceDevice spaceDevice : spaceDeviceList) { - AligenieDevice aligenieDevice = aligenieDeviceRepository.findOne(Example.of( - AligenieDevice.builder() - .deviceId(spaceDevice.getDeviceId()) - .uid(user.getId()) - .build() - )).orElse(null); - - //不存在设备,新增 - if (aligenieDevice == null) { - DeviceInfo deviceInfo = deviceDao.get(spaceDevice.getDeviceId()); - AligenieProduct aligenieProduct = aligenieProductDao.getAligenieProduct(deviceInfo.getProductKey()); - if(aligenieProduct==null){ - continue; - } - - aligenieDeviceRepository.save( - AligenieDevice.builder() - .uid(user.getId()) - .deviceId(spaceDevice.getDeviceId()) - .name(spaceDevice.getName()) - .spaceName(spaceDevice.getSpaceName()) - .productId(aligenieProduct.getProductId()) - .build() - ); - } else { - //存在,更新设备信息 - aligenieDeviceRepository.save( - AligenieDevice.builder() - .id(aligenieDevice.getId()) - .name(spaceDevice.getName()) - .spaceName(spaceDevice.getSpaceName()) - .build() - ); - } - - } - } - -} diff --git a/manager/src/main/java/cc/iotkit/manager/service/DataOwnerService.java b/manager/src/main/java/cc/iotkit/manager/service/DataOwnerService.java index 922f9d87..8a83e01c 100755 --- a/manager/src/main/java/cc/iotkit/manager/service/DataOwnerService.java +++ b/manager/src/main/java/cc/iotkit/manager/service/DataOwnerService.java @@ -18,6 +18,9 @@ public class DataOwnerService { return data; } + /** + * 检查数据中的uid与当前登录用户是否一致 + */ public T checkOwner(T data) { //管理员不限制 if (AuthUtil.isAdmin()) { @@ -37,19 +40,21 @@ public class DataOwnerService { throw new BizException("无权限操作"); } - public void checkOwner(MongoRepository repository, T data) { + /** + * 从库中取对应数据Id的数据中的uid是否与当前登录用户一致 + */ + public void checkOwner(MongoRepository repository, String id) { //管理员不限制 if (AuthUtil.isAdmin()) { return; } - String dataId = data.getId(); - //没有数据id为新数据 - if (StringUtils.isBlank(dataId)) { + //数据id为空的新数据 + if (StringUtils.isBlank(id)) { return; } - T old = repository.findById(dataId).orElse(null); + T old = repository.findById(id).orElse(null); //新数据 if (old == null) { return; @@ -63,9 +68,21 @@ public class DataOwnerService { throw new BizException("无权限操作"); } + /** + * 从库中取对应数据Id的数据中的uid是否与当前登录用户一致,并把当前用户id设置到数据中 + */ public void checkOwnerSave(MongoRepository repository, T data) { - checkOwner(repository, data); + checkOwner(repository, data.getId()); data.setUid(AuthUtil.getUserId()); } + public void checkWriteRole() { + if (AuthUtil.isAdmin()) { + return; + } + + if (!AuthUtil.hasWriteRole()) { + throw new BizException("无权操作"); + } + } } diff --git a/manager/src/main/java/cc/iotkit/manager/service/DeviceService.java b/manager/src/main/java/cc/iotkit/manager/service/DeviceService.java index fdfca40f..efa6eccc 100755 --- a/manager/src/main/java/cc/iotkit/manager/service/DeviceService.java +++ b/manager/src/main/java/cc/iotkit/manager/service/DeviceService.java @@ -1,75 +1,91 @@ package cc.iotkit.manager.service; +import cc.iotkit.common.exception.BizException; import cc.iotkit.common.exception.NotFoundException; -import cc.iotkit.dao.DeviceDao; -import cc.iotkit.dao.DeviceEventRepository; +import cc.iotkit.common.utils.UniqueIdUtil; +import cc.iotkit.comps.ComponentManager; +import cc.iotkit.converter.ThingService; import cc.iotkit.dao.DeviceRepository; -import cc.iotkit.dao.ThingModelRepository; -import cc.iotkit.deviceapi.IDeviceManager; import cc.iotkit.model.device.DeviceInfo; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; +import cc.iotkit.model.device.message.ThingModelMessage; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Example; import org.springframework.stereotype.Service; -import java.util.List; import java.util.Map; @Slf4j @Service public class DeviceService { - @Autowired - private DeviceDao deviceDao; @Autowired private DeviceRepository deviceRepository; @Autowired - private ThingModelRepository thingModelRepository; - @Autowired - private ThingModelService thingModelService; - @Autowired - private DeviceEventRepository deviceEventRepository; - @Autowired private DataOwnerService dataOwnerService; @Autowired - private IDeviceManager deviceManager; + private ComponentManager componentManager; + @Autowired + private ThingModelService thingModelService; - public String invokeService(String deviceId, String service, Map args) { + public String invokeService(String deviceId, String service, + Map args) { + return invokeService(deviceId, service, args, true); + } + + public String invokeService(String deviceId, String service, + Map args, boolean checkOwner) { DeviceInfo device = deviceRepository.findById(deviceId) .orElseThrow(() -> new NotFoundException("device not found by deviceId")); - dataOwnerService.checkOwner(device); - return this.deviceManager.invokeService(deviceId, service, args); + if (checkOwner) { + dataOwnerService.checkOwner(device); + } + if (!device.getState().isOnline()) { + throw new BizException("device is offline"); + } + + ThingService thingService = ThingService.builder() + .mid(UniqueIdUtil.newRequestId()) + .productKey(device.getProductKey()) + .deviceName(device.getDeviceName()) + .type(ThingModelMessage.TYPE_SERVICE) + .identifier(service) + .params(args) + .build(); + thingModelService.parseParams(thingService); + + componentManager.send(thingService); + return thingService.getMid(); } public String setProperty(String deviceId, Map properties) { + return setProperty(deviceId, properties, true); + } + + public String setProperty(String deviceId, Map properties, + boolean checkOwner) { DeviceInfo device = deviceRepository.findById(deviceId) .orElseThrow(() -> new NotFoundException("device not found by deviceId")); - dataOwnerService.checkOwner(device); - return deviceManager.setProperty(deviceId, properties); + if (checkOwner) { + dataOwnerService.checkOwner(device); + } + if (!device.getState().isOnline()) { + throw new BizException("device is offline"); + } + + ThingService thingService = ThingService.builder() + .mid(UniqueIdUtil.newRequestId()) + .productKey(device.getProductKey()) + .deviceName(device.getDeviceName()) + .type(ThingModelMessage.TYPE_PROPERTY) + .identifier("set") + .params(properties) + .build(); + thingModelService.parseParams(thingService); + + componentManager.send(thingService); + return thingService.getMid(); } - public void unbindDevice(String deviceId) { - deviceManager.unbind(deviceId); - } - - public List findDevices(DeviceInfo form) { - return deviceRepository.findAll(Example.of(form)); - } - - public long count(DeviceInfo form) { - return deviceRepository.count(Example.of(form)); - } - - @Data - @NoArgsConstructor - @AllArgsConstructor - private static class CmdRequest { - private String id; - private Object params; - } } diff --git a/manager/src/main/java/cc/iotkit/manager/service/KeycloakAdminService.java b/manager/src/main/java/cc/iotkit/manager/service/KeycloakAdminService.java index 30af8479..9e12f639 100755 --- a/manager/src/main/java/cc/iotkit/manager/service/KeycloakAdminService.java +++ b/manager/src/main/java/cc/iotkit/manager/service/KeycloakAdminService.java @@ -15,6 +15,7 @@ import org.springframework.stereotype.Service; import java.util.Arrays; import java.util.Collections; +import java.util.List; @Slf4j @Service @@ -101,6 +102,21 @@ public class KeycloakAdminService { userResource.update(userRepresentation); } + public UserInfo getUser(String uid) { + Keycloak keycloak = getKeycloak(); + List users = keycloak.realm(realm) + .users().search(uid); + if (users.size() == 0) { + return null; + } + UserRepresentation user = users.get(0); + + return UserInfo.builder() + .id(user.getId()) + .uid(uid) + .build(); + } + public void resetUserPwd(String id, String pwd) { Keycloak keycloak = getKeycloak(); UserResource userResource = keycloak.realm(realm) diff --git a/manager/src/main/java/cc/iotkit/manager/service/PulsarAdminService.java b/manager/src/main/java/cc/iotkit/manager/service/PulsarAdminService.java new file mode 100755 index 00000000..0854e6b7 --- /dev/null +++ b/manager/src/main/java/cc/iotkit/manager/service/PulsarAdminService.java @@ -0,0 +1,50 @@ +package cc.iotkit.manager.service; + +import com.google.common.collect.Sets; +import org.apache.pulsar.client.admin.PulsarAdmin; +import org.apache.pulsar.client.admin.PulsarAdminException; +import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.pulsar.common.policies.data.TenantInfo; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.util.HashSet; + +@Service +public class PulsarAdminService { + + @Value("${pulsar.service}") + private String pulsarServiceUrl; + + private PulsarAdmin pulsarAdmin; + + private PulsarAdmin getPulsarAdmin() throws PulsarClientException { + if (pulsarAdmin == null) { + pulsarAdmin = PulsarAdmin.builder() + .serviceHttpUrl(pulsarServiceUrl) + .build(); + } + return pulsarAdmin; + } + + public boolean tenantExists(String uid) throws PulsarAdminException, PulsarClientException { + PulsarAdmin pulsarAdmin = getPulsarAdmin(); + return pulsarAdmin.tenants().getTenants().contains(uid); + } + + public void createTenant(String uid) throws PulsarClientException, PulsarAdminException { + PulsarAdmin pulsarAdmin = getPulsarAdmin(); + pulsarAdmin.tenants().createTenant(uid, TenantInfo.builder() + .adminRoles(new HashSet<>()) + .allowedClusters(Sets.newHashSet("standalone")) + .build()); + + pulsarAdmin.namespaces().createNamespace(uid + "/default"); + } + + public void deleteTenant(String uid) throws PulsarClientException, PulsarAdminException { + PulsarAdmin pulsarAdmin = getPulsarAdmin(); + pulsarAdmin.tenants().deleteTenant(uid); + } + +} diff --git a/manager/src/main/java/cc/iotkit/manager/service/SpaceDeviceService.java b/manager/src/main/java/cc/iotkit/manager/service/SpaceDeviceService.java index d60e9639..4bec68b2 100755 --- a/manager/src/main/java/cc/iotkit/manager/service/SpaceDeviceService.java +++ b/manager/src/main/java/cc/iotkit/manager/service/SpaceDeviceService.java @@ -1,7 +1,7 @@ package cc.iotkit.manager.service; -import cc.iotkit.dao.DeviceDao; -import cc.iotkit.dao.ProductDao; +import cc.iotkit.dao.DeviceCache; +import cc.iotkit.dao.ProductCache; import cc.iotkit.dao.SpaceDeviceRepository; import cc.iotkit.manager.model.vo.SpaceDeviceVo; import cc.iotkit.model.device.DeviceInfo; @@ -20,9 +20,9 @@ public class SpaceDeviceService { @Autowired private SpaceDeviceRepository spaceDeviceRepository; @Autowired - private DeviceDao deviceDao; + private DeviceCache deviceCache; @Autowired - private ProductDao productDao; + private ProductCache productCache; public List getUserDevices(String uid, String spaceId) { SpaceDevice device = new SpaceDevice(); @@ -33,15 +33,15 @@ public class SpaceDeviceService { List spaceDevices = spaceDeviceRepository.findAll(Example.of(device)); List spaceDeviceVos = new ArrayList<>(); spaceDevices.forEach(sd -> { - DeviceInfo deviceInfo = deviceDao.get(sd.getDeviceId()); - Product product = productDao.get(deviceInfo.getProductKey()); + DeviceInfo deviceInfo = deviceCache.findByDeviceId(sd.getDeviceId()); + Product product = productCache.findById(deviceInfo.getProductKey()); spaceDeviceVos.add(SpaceDeviceVo.builder() .uid(sd.getUid()) .deviceId(sd.getDeviceId()) .name(sd.getName()) .picUrl(product.getImg()) .spaceName(sd.getSpaceName()) - .online(deviceInfo.getState().getOnline()) + .online(deviceInfo.getState().isOnline()) .property(deviceInfo.getProperty()) .productKey(deviceInfo.getProductKey()) .build()); diff --git a/manager/src/main/java/cc/iotkit/manager/service/ThingModelService.java b/manager/src/main/java/cc/iotkit/manager/service/ThingModelService.java index b719ceec..2383038d 100755 --- a/manager/src/main/java/cc/iotkit/manager/service/ThingModelService.java +++ b/manager/src/main/java/cc/iotkit/manager/service/ThingModelService.java @@ -1,6 +1,9 @@ package cc.iotkit.manager.service; +import cc.iotkit.converter.ThingService; +import cc.iotkit.dao.ThingModelRepository; import cc.iotkit.model.product.ThingModel; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.HashMap; @@ -9,28 +12,34 @@ import java.util.Map; @Component public class ThingModelService { + @Autowired + private ThingModelRepository thingModelRepository; - public Map paramsParse(ThingModel thingModel, String identifier, Map params) { - Map parsedParams = new HashMap<>(); + public void parseParams(ThingService service) { + ThingModel thingModel = thingModelRepository.findByProductKey(service.getProductKey()); + thingModel.getModel(); ThingModel.Model model = thingModel.getModel(); + String type = service.getType(); + String identifier = service.getIdentifier(); + Object params = null; //属性设置 - if ("property/set".equals(identifier)) { + if (ThingService.TYPE_PROPERTY.equals(type)) { List properties = model.getProperties(); if (properties == null) { - return parsedParams; + return; } - return parseProperties(properties, params); - } else { + params = parseProperties(properties, (Map) service.getParams()); + } else if (ThingService.TYPE_SERVICE.equals(type)) { //服务调用 Map services = model.serviceMap(); - ThingModel.Service service = services.get(identifier); - if (service == null) { - return parsedParams; + ThingModel.Service s = services.get(identifier); + if (s == null) { + return; } - List parameters = service.getInputData(); - return parseParams(parameters, params); + params = parseParams(s.getInputData(), (Map) service.getParams()); } + service.setParams(params); } private Map parseParams(List parameters, Map params) { diff --git a/manager/src/main/java/cc/iotkit/manager/utils/AuthUtil.java b/manager/src/main/java/cc/iotkit/manager/utils/AuthUtil.java index 0a1d889d..0f604108 100755 --- a/manager/src/main/java/cc/iotkit/manager/utils/AuthUtil.java +++ b/manager/src/main/java/cc/iotkit/manager/utils/AuthUtil.java @@ -34,4 +34,8 @@ public class AuthUtil { return AuthUtil.getUserRoles().contains(Constants.ROLE_ADMIN); } + public static boolean hasWriteRole(){ + return AuthUtil.getUserRoles().contains(Constants.ROLE_WRITE); + } + } diff --git a/manager/src/main/resources/application-dev.yml b/manager/src/main/resources/application-dev.yml index c2aa6d16..4b5a94ae 100755 --- a/manager/src/main/resources/application-dev.yml +++ b/manager/src/main/resources/application-dev.yml @@ -1,14 +1,32 @@ spring: + servlet: + multipart: + enabled: true + max-file-size: 10MB + max-request-size: 12MB + data: mongodb: uri: mongodb://填写mongodb地址/admin database: iotkit + elasticsearch: + rest: + uris: http://elasticsearch 连接地址 + username: elasticsearch 用户名 + password: 密码 + connection-timeout: 10s + + redis: + host: redis地址 + port: 6379 + database: 0 + password: redis密码 + cache: cache-names: foo,bar caffeine: spec: maximumSize=5000,expireAfterAccess=120s - mvc: pathmatch: matching-strategy: ant_path_matcher @@ -41,6 +59,10 @@ keycloak-admin-clientid : 填写keycloak中定义的clientId keycloak-admin-user : 填写keycloak中添加的管理员用户名 keycloak-admin-password : 填写keycloak中添加的管理员密码 +pulsar: + broker: pulsar://pulsar broker地址:6650 + service: http://pulsar 服务地址:8080 + app: systemRole: iot_system_user diff --git a/manager/src/main/resources/application.yml b/manager/src/main/resources/application.yml index c2aa6d16..363f3651 100755 --- a/manager/src/main/resources/application.yml +++ b/manager/src/main/resources/application.yml @@ -1,14 +1,30 @@ spring: + servlet: + multipart: + enabled: true + max-file-size: 10MB + max-request-size: 12MB + data: mongodb: uri: mongodb://填写mongodb地址/admin database: iotkit + elasticsearch: + rest: + uris: http://elasticsearch 连接地址 + connection-timeout: 10s + + redis: + host: redis地址 + port: 6379 + database: 0 + password: + cache: cache-names: foo,bar caffeine: spec: maximumSize=5000,expireAfterAccess=120s - mvc: pathmatch: matching-strategy: ant_path_matcher @@ -41,6 +57,10 @@ keycloak-admin-clientid : 填写keycloak中定义的clientId keycloak-admin-user : 填写keycloak中添加的管理员用户名 keycloak-admin-password : 填写keycloak中添加的管理员密码 +pulsar: + broker: pulsar://pulsar broker地址:6650 + service: http://pulsar 服务地址:8080 + app: systemRole: iot_system_user diff --git a/model/pom.xml b/model/pom.xml index b2bc841b..1e7c5d40 100755 --- a/model/pom.xml +++ b/model/pom.xml @@ -19,10 +19,17 @@ lombok provided + org.springframework.data spring-data-mongodb + + + org.springframework.data + spring-data-elasticsearch + + com.fasterxml.jackson.core jackson-annotations diff --git a/model/src/main/java/cc/iotkit/model/aligenie/AligenieDevice.java b/model/src/main/java/cc/iotkit/model/aligenie/AligenieDevice.java index 4913c974..4a9c0963 100755 --- a/model/src/main/java/cc/iotkit/model/aligenie/AligenieDevice.java +++ b/model/src/main/java/cc/iotkit/model/aligenie/AligenieDevice.java @@ -23,6 +23,11 @@ public class AligenieDevice { */ private String uid; + /** + * 用户token + */ + private String token; + /** * 空间中的设备id */ diff --git a/model/src/main/java/cc/iotkit/model/device/DeviceInfo.java b/model/src/main/java/cc/iotkit/model/device/DeviceInfo.java index b709e6e5..b42f799d 100755 --- a/model/src/main/java/cc/iotkit/model/device/DeviceInfo.java +++ b/model/src/main/java/cc/iotkit/model/device/DeviceInfo.java @@ -37,17 +37,35 @@ public class DeviceInfo implements Owned { private State state = new State(); - private Map property; + private Map property; + + /** + * 设备标签 + */ + private Map tag; private Long createAt; @Data + @NoArgsConstructor + @AllArgsConstructor public static class State { - private Boolean online; + private boolean online; private Long onlineTime; private Long offlineTime; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class Tag { + private String id; + private String name; + private Object value; + } + } diff --git a/model/src/main/java/cc/iotkit/model/device/message/DeviceProperty.java b/model/src/main/java/cc/iotkit/model/device/message/DeviceProperty.java new file mode 100755 index 00000000..53acacf8 --- /dev/null +++ b/model/src/main/java/cc/iotkit/model/device/message/DeviceProperty.java @@ -0,0 +1,29 @@ +package cc.iotkit.model.device.message; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.Id; +import org.springframework.data.elasticsearch.annotations.Document; +import org.springframework.data.elasticsearch.annotations.Field; +import org.springframework.data.elasticsearch.annotations.FieldType; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Document(indexName = "device_property") +public class DeviceProperty { + + @Id + private String mid; + + private String deviceId; + + private String name; + + private Object value; + + @Field(type = FieldType.Date) + private Long time; + +} diff --git a/model/src/main/java/cc/iotkit/model/device/message/ThingModelMessage.java b/model/src/main/java/cc/iotkit/model/device/message/ThingModelMessage.java new file mode 100755 index 00000000..a493ff94 --- /dev/null +++ b/model/src/main/java/cc/iotkit/model/device/message/ThingModelMessage.java @@ -0,0 +1,81 @@ +package cc.iotkit.model.device.message; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.Id; +import org.springframework.data.elasticsearch.annotations.Document; +import org.springframework.data.elasticsearch.annotations.Field; +import org.springframework.data.elasticsearch.annotations.FieldType; + +import java.util.HashMap; +import java.util.Map; + +/** + * 物模型消息 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Document(indexName = "thing_model_messages") +public class ThingModelMessage { + + public static final String TYPE_LIFETIME = "lifetime"; + public static final String TYPE_STATE = "state"; + public static final String TYPE_PROPERTY = "property"; + public static final String TYPE_EVENT = "event"; + public static final String TYPE_SERVICE = "service"; + + public static final String ID_PROPERTY_GET = "get"; + public static final String ID_PROPERTY_SET = "set"; + + @Id + private String mid; + + private String deviceId; + + private String productKey; + + private String deviceName; + + /** + * 消息类型 + * lifetime:生命周期 + * state:状态 + * property:属性 + * event:事件 + * service:服务 + */ + private String type; + + private String identifier; + + /** + * 消息状态码 + */ + private int code; + + private Object data; + + /** + * 时间戳,设备上的事件或数据产生的本地时间 + */ + @Field(type = FieldType.Date) + private Long occurred; + + /** + * 消息上报时间 + */ + @Field(type = FieldType.Date) + private Long time; + + public Map dataToMap() { + Map mapData = new HashMap<>(); + if (data instanceof Map) { + ((Map) data).forEach((key, value) -> mapData.put(key.toString(), value)); + } + return mapData; + } +} diff --git a/model/src/main/java/cc/iotkit/model/product/Product.java b/model/src/main/java/cc/iotkit/model/product/Product.java index d4bd8c54..1dc2691e 100755 --- a/model/src/main/java/cc/iotkit/model/product/Product.java +++ b/model/src/main/java/cc/iotkit/model/product/Product.java @@ -18,8 +18,6 @@ public class Product implements Owned { @Id private String id; - private String code; - private String name; private String category; diff --git a/model/src/main/java/cc/iotkit/model/protocol/ProtocolComponent.java b/model/src/main/java/cc/iotkit/model/protocol/ProtocolComponent.java new file mode 100755 index 00000000..3d9ab585 --- /dev/null +++ b/model/src/main/java/cc/iotkit/model/protocol/ProtocolComponent.java @@ -0,0 +1,39 @@ +package cc.iotkit.model.protocol; + +import cc.iotkit.model.Owned; +import lombok.Data; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +@Data +@Document +public class ProtocolComponent implements Owned { + + public static final String STATE_STOPPED = "stopped"; + public static final String STATE_RUNNING = "running"; + + public static final String SCRIPT_FILE_NAME = "component.js"; + + @Id + private String id; + + /** + * 所属性用户id + */ + private String uid; + + private String name; + + private String protocol; + + private String jarFile; + + private String config; + + private String converter; + + private String state; + + private Long createAt; + +} diff --git a/model/src/main/java/cc/iotkit/model/protocol/ProtocolConverter.java b/model/src/main/java/cc/iotkit/model/protocol/ProtocolConverter.java new file mode 100755 index 00000000..8aaec0f0 --- /dev/null +++ b/model/src/main/java/cc/iotkit/model/protocol/ProtocolConverter.java @@ -0,0 +1,27 @@ +package cc.iotkit.model.protocol; + +import cc.iotkit.model.Owned; +import lombok.Data; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +@Document +@Data +public class ProtocolConverter implements Owned { + + public static final String SCRIPT_FILE_NAME = "converter.js"; + + @Id + private String id; + + /** + * 所属性用户id + */ + private String uid; + + private String name; + + private String desc; + + private Long createAt; +} diff --git a/model/src/main/java/cc/iotkit/model/rule/SceneInfo.java b/model/src/main/java/cc/iotkit/model/rule/RuleInfo.java similarity index 84% rename from model/src/main/java/cc/iotkit/model/rule/SceneInfo.java rename to model/src/main/java/cc/iotkit/model/rule/RuleInfo.java index 49a32b50..841bd6e0 100755 --- a/model/src/main/java/cc/iotkit/model/rule/SceneInfo.java +++ b/model/src/main/java/cc/iotkit/model/rule/RuleInfo.java @@ -13,16 +13,21 @@ import java.util.List; @NoArgsConstructor @AllArgsConstructor @Document -public class SceneInfo implements Owned { +public class RuleInfo implements Owned { public static final String STATE_STOPPED = "stopped"; public static final String STATE_RUNNING = "running"; + public static final String TYPE_SCENE = "scene"; + public static final String TYPE_FLOW = "flow"; + @Id private String id; private String name; + private String type; + private List listeners; private List filters; diff --git a/model/src/main/java/cc/iotkit/model/rule/SceneLog.java b/model/src/main/java/cc/iotkit/model/rule/RuleLog.java similarity index 67% rename from model/src/main/java/cc/iotkit/model/rule/SceneLog.java rename to model/src/main/java/cc/iotkit/model/rule/RuleLog.java index fe9c1588..f7c948dc 100755 --- a/model/src/main/java/cc/iotkit/model/rule/SceneLog.java +++ b/model/src/main/java/cc/iotkit/model/rule/RuleLog.java @@ -4,13 +4,15 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.data.annotation.Id; -import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.elasticsearch.annotations.Document; +import org.springframework.data.elasticsearch.annotations.Field; +import org.springframework.data.elasticsearch.annotations.FieldType; @Data @NoArgsConstructor @AllArgsConstructor -@Document -public class SceneLog { +@Document(indexName = "rule_log") +public class RuleLog { public static final String STATE_MATCHED_LISTENER = "matched_listener"; public static final String STATE_MATCHED_FILTER = "matched_filter"; @@ -20,7 +22,7 @@ public class SceneLog { @Id private String id; - private String sceneId; + private String ruleId; private String state; @@ -28,5 +30,6 @@ public class SceneLog { private Boolean success; + @Field(type = FieldType.Date) private Long logAt; } diff --git a/model/src/main/java/cc/iotkit/model/rule/TaskLog.java b/model/src/main/java/cc/iotkit/model/rule/TaskLog.java index cbcf8ecc..317d6aef 100755 --- a/model/src/main/java/cc/iotkit/model/rule/TaskLog.java +++ b/model/src/main/java/cc/iotkit/model/rule/TaskLog.java @@ -5,13 +5,15 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.data.annotation.Id; -import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.elasticsearch.annotations.Document; +import org.springframework.data.elasticsearch.annotations.Field; +import org.springframework.data.elasticsearch.annotations.FieldType; @Data @NoArgsConstructor @AllArgsConstructor @Builder -@Document +@Document(indexName = "task_log") public class TaskLog { @Id @@ -23,5 +25,6 @@ public class TaskLog { private Boolean success; + @Field(type = FieldType.Date) private Long logAt; } diff --git a/pom.xml b/pom.xml index f653e772..da37389d 100755 --- a/pom.xml +++ b/pom.xml @@ -4,13 +4,14 @@ 4.0.0 pom - device-server model rule-engine common manager dao tppa-server + protocol-gateway + standalone-package org.springframework.boot @@ -88,12 +89,6 @@ 1.57 - - com.github.xiaoymin - knife4j-spring-boot-starter - 3.0.3 - - org.keycloak keycloak-spring-boot-starter @@ -136,16 +131,65 @@ 3.10.2 + + co.elastic.clients + elasticsearch-java + 7.15.2 + + joda-time joda-time 2.10.10 + + org.apache.pulsar + pulsar-client + 2.9.1 + + + + org.apache.pulsar + pulsar-client-api + 2.9.1 + + + + org.apache.pulsar + pulsar-client-original + 2.9.1 + + + org.eclipse.paho org.eclipse.paho.client.mqttv3 - 1.2.2 + 1.2.5 + + + + org.apache.pulsar + pulsar-functions-api + 2.6.0 + + + + io.vertx + vertx-core + 4.2.6 + + + + io.vertx + vertx-mqtt + 4.2.6 + + + + io.vertx + vertx-web-proxy + 4.2.6 @@ -168,13 +212,37 @@ cc.iotkit - device-api + rule-engine ${project.version} cc.iotkit - rule-engine + component + ${project.version} + + + + cc.iotkit + converter + ${project.version} + + + + cc.iotkit + component-server + ${project.version} + + + + cc.iotkit + mqtt-component + ${project.version} + + + + cc.iotkit + standalone-package ${project.version} diff --git a/device-server/mqtt-auth/.DS_Store b/protocol-gateway/.DS_Store similarity index 91% rename from device-server/mqtt-auth/.DS_Store rename to protocol-gateway/.DS_Store index ee771938..5008ddfc 100755 Binary files a/device-server/mqtt-auth/.DS_Store and b/protocol-gateway/.DS_Store differ diff --git a/protocol-gateway/component-server/pom.xml b/protocol-gateway/component-server/pom.xml new file mode 100755 index 00000000..2af23c5b --- /dev/null +++ b/protocol-gateway/component-server/pom.xml @@ -0,0 +1,92 @@ + + + + protocol-gateway + cc.iotkit + 0.0.1-SNAPSHOT + + 4.0.0 + + component-server + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-data-elasticsearch + + + + org.springframework + spring-context + + + + org.springframework.data + spring-data-redis + + + redis.clients + jedis + + + + org.slf4j + slf4j-api + + + + commons-io + commons-io + + + + org.apache.pulsar + pulsar-client-api + + + + org.apache.pulsar + pulsar-client-original + + + + org.projectlombok + lombok + + + + cc.iotkit + common + + + + cc.iotkit + converter + + + + cc.iotkit + model + + + + cc.iotkit + dao + + + + cc.iotkit + component + + + + + \ No newline at end of file diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentClassLoader.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentClassLoader.java new file mode 100755 index 00000000..bd205160 --- /dev/null +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentClassLoader.java @@ -0,0 +1,49 @@ +package cc.iotkit.comps; + +import cc.iotkit.comp.IComponent; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.StreamUtils; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.charset.Charset; + +@Slf4j +public class ComponentClassLoader { + + protected static Class findClass(String name) throws ClassNotFoundException { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + return (Class) classLoader.loadClass(name); + } + + private static String addUrl(File jarPath) throws NoSuchMethodException, InvocationTargetException, + IllegalAccessException, IOException { + URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); + Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); + if (!method.isAccessible()) { + method.setAccessible(true); + } + URL url = jarPath.toURI().toURL(); + method.invoke(classLoader, url); + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + InputStream is = loader.getResourceAsStream("component.spi"); + return StreamUtils.copyToString(is, Charset.forName("UTF-8")); + } + + public static IComponent getComponent(File jarFile) { + try { + String className = addUrl(jarFile); + Class componentClass = findClass(className); + return componentClass.newInstance(); + } catch (Throwable e) { + log.error("instance component from jar error", e); + return null; + } + } + +} diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentManager.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentManager.java new file mode 100755 index 00000000..95f954fd --- /dev/null +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentManager.java @@ -0,0 +1,177 @@ +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; + +@Slf4j +@Component +public class ComponentManager { + + private final Map components = new HashMap<>(); + private final Map scripts = new HashMap<>(); + private final Map states = new HashMap<>(); + + @Autowired + private DeviceBehaviourService deviceBehaviourService; + @Autowired + private StringRedisTemplate redisTemplate; + @Autowired + private ComponentConfig componentConfig; + @Autowired + private ProtocolComponentRepository componentRepository; + + @PostConstruct + public void init() { + try { + List componentList = componentRepository.findByState(ProtocolComponent.STATE_RUNNING); + 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 = 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); + if (component == null) { + return; + } + component.stop(); + component.destroy(); + } + + 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) { + 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); + } + + public void send(ThingService service) { + log.info("start exec device service:{}", JsonUtil.toJsonString(service)); + if (components.size() == 0) { + throw new BizException("there is no components"); + } + + for (IComponent com : components.values()) { + if (com.exist(service.getProductKey(), service.getDeviceName())) { + //对下发消息进行编码转换 + DeviceMessage message = com.getConverter().encode(service, null); + if (message == null) { + throw new BizException("encode send message failed"); + } + //保存设备端mid与平台mid对应关系 + redisTemplate.opsForValue().set( + CacheKey.getKeyCmdMid(service.getDeviceName(), message.getMid()), + service.getMid(), com.getConfig().getCmdTimeout(), TimeUnit.SECONDS); + com.send(message); + + ThingModelMessage thingModelMessage = ThingModelMessage.builder() + .mid(service.getMid()) + .productKey(service.getProductKey()) + .deviceName(service.getDeviceName()) + .identifier(service.getIdentifier()) + .type(service.getType()) + .data(service.getParams()) + .build(); + deviceBehaviourService.reportMessage(thingModelMessage); + + return; + } + } + throw new BizException("send destination not found"); + } + + public String getPlatformMid(String deviceName, String mid) { + return redisTemplate.opsForValue().get(CacheKey.getKeyCmdMid(deviceName, mid)); + } + +} diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/MessageHandler.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/MessageHandler.java new file mode 100755 index 00000000..07cfd54e --- /dev/null +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/MessageHandler.java @@ -0,0 +1,208 @@ +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.IMessageHandler; +import cc.iotkit.comp.model.AuthInfo; +import cc.iotkit.comp.model.ReceiveResult; +import cc.iotkit.comp.model.RegisterInfo; +import cc.iotkit.converter.DeviceMessage; +import cc.iotkit.comp.model.DeviceState; +import cc.iotkit.comps.service.DeviceBehaviourService; +import cc.iotkit.converter.IConverter; +import cc.iotkit.model.device.message.ThingModelMessage; +import jdk.nashorn.api.scripting.NashornScriptEngine; +import jdk.nashorn.api.scripting.ScriptObjectMirror; +import lombok.Data; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +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 { + private final NashornScriptEngine engine = (NashornScriptEngine) (new ScriptEngineManager()).getEngineByName("nashorn"); + + private final Object scriptObj; + + private final IConverter converter; + + private final DeviceBehaviourService deviceBehaviourService; + + private final ComponentManager componentManager; + + private final IComponent component; + + @SneakyThrows + public MessageHandler(ComponentManager componentManager, + IComponent component, + String script, IConverter converter, + DeviceBehaviourService deviceBehaviourService) { + this.componentManager = componentManager; + this.component = component; + this.converter = converter; + this.deviceBehaviourService = deviceBehaviourService; + scriptObj = engine.eval(String.format("new (function () {\n%s})()", script)); + } + + public ReceiveResult onReceive(Map head, String type, String msg) { + try { + ScriptObjectMirror result = (ScriptObjectMirror) invokeMethod("onReceive", head, type, msg); + log.info("onReceive script result:{}", JsonUtil.toJsonString(result)); + Object rstType = result.get("type"); + if (rstType == null) { + return null; + } + //取脚本执行后返回的数据 + Object data = JsonUtil.toObject((ScriptObjectMirror) result.get("data")); + if (!(data instanceof Map)) { + throw new BizException("script result data is incorrect"); + } + Map dataMap = (Map) data; + //获取动作数据 + Action action = getAction(result.get("action")); + + if ("register".equals(rstType)) { + //注册数据 + RegisterInfo regInfo = RegisterInfo.from(dataMap); + if (regInfo == null) { + return null; + } + doRegister(regInfo); + doAction(action); + return new ReceiveResult(regInfo.getProductKey(), regInfo.getDeviceName(), regInfo); + } else if ("auth".equals(rstType)) { + //设备认证 + AuthInfo authInfo = new AuthInfo(); + BeanUtils.populate(authInfo, dataMap); + doAuth(authInfo); + doAction(action); + return new ReceiveResult(authInfo.getProductKey(), authInfo.getDeviceName(), authInfo); + } else if ("state".equals(rstType)) { + //设备状态变更 + DeviceState state = DeviceState.from(dataMap); + if (state == null) { + return null; + } + doStateChange(state); + doAction(action); + return new ReceiveResult(state.getProductKey(), state.getDeviceName(), state); + } else if ("report".equals(rstType)) { + //上报数据 + DeviceMessage message = new DeviceMessage(); + BeanUtils.populate(message, dataMap); + doReport(message); + doAction(action); + return new ReceiveResult(message.getProductKey(), message.getDeviceName(), message); + } + + } catch (BizException e) { + throw e; + } catch (Throwable e) { + throw new BizException("receive component message error", e); + } + return null; + } + + private void doRegister(RegisterInfo reg) throws ScriptException, NoSuchMethodException { + try { + deviceBehaviourService.register(reg); + } catch (Throwable e) { + log.error("register error", e); + } finally { + invokeMethod("onRegistered", reg, "false"); + } + } + + private void doAuth(AuthInfo auth) throws ScriptException, NoSuchMethodException { + try { + deviceBehaviourService.deviceAuth(auth.getProductKey(), + auth.getDeviceName(), + auth.getProductSecret(), + auth.getDeviceSecret()); + } catch (Throwable e) { + log.error("device auth error", e); + } 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); + deviceBehaviourService.deviceStateChange(state.getProductKey(), + state.getDeviceName(), + DeviceState.STATE_ONLINE.equals(state.getState())); + } catch (Throwable e) { + log.error("device state change error", e); + } + } + + private void doReport(DeviceMessage message) { + ThingModelMessage thingModelMessage = converter.decode(message); + + //服务回复需要重新对应mid + if (thingModelMessage.getIdentifier().endsWith("_reply")) { + String platformMid = componentManager.getPlatformMid(message.getDeviceName(), message.getMid()); + if (platformMid == null) { + platformMid = UniqueIdUtil.newRequestId(); + } + thingModelMessage.setMid(platformMid); + } else { + //其它消息重新生成唯一MID + thingModelMessage.setMid(UniqueIdUtil.newRequestId()); + } + + deviceBehaviourService.reportMessage(thingModelMessage); + } + + private Action getAction(Object objAction) { + if (!(objAction instanceof Map)) { + return null; + } + Action action = new Action(); + try { + BeanUtils.populate(action, (Map) objAction); + } catch (Throwable e) { + log.error("parse action error", e); + } + return action; + } + + private void doAction(Action action) { + if (action == null) { + return; + } + try { + if (Action.TYPE_ACK.equals(action.getType())) { + DeviceMessage deviceMessage = JsonUtil.parse(action.getContent(), DeviceMessage.class); + this.getComponent().send(deviceMessage); + } + } catch (Throwable e) { + log.error("do action error", e); + } + } + + @Data + public static class Action { + public static final String TYPE_ACK = "ack"; + + private String type; + private String content; + } + +} diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/CacheKey.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/CacheKey.java new file mode 100755 index 00000000..115cfe82 --- /dev/null +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/CacheKey.java @@ -0,0 +1,11 @@ +package cc.iotkit.comps.config; + +public class CacheKey { + + private static final String KEY_CMD_MID = "str:cmd:mid:%s:%s"; + + public static String getKeyCmdMid(String deviceName, String downMid) { + return String.format(KEY_CMD_MID, deviceName, downMid); + } + +} diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/ComponentConfig.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/ComponentConfig.java new file mode 100755 index 00000000..bb8d5db4 --- /dev/null +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/ComponentConfig.java @@ -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(); + } +} diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/ServerConfig.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/ServerConfig.java new file mode 100755 index 00000000..7238b060 --- /dev/null +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/ServerConfig.java @@ -0,0 +1,17 @@ +package cc.iotkit.comps.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +@Data +public class ServerConfig { + + @Value("${pulsar.broker}") + private String pulsarBrokerUrl; + + @Value("${pulsar.service}") + private String pulsarServiceUrl; + +} diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceBehaviourService.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceBehaviourService.java new file mode 100755 index 00000000..803bdde2 --- /dev/null +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceBehaviourService.java @@ -0,0 +1,209 @@ +package cc.iotkit.comps.service; + +import cc.iotkit.common.Constants; +import cc.iotkit.common.exception.BizException; +import cc.iotkit.common.utils.DeviceUtil; +import cc.iotkit.common.utils.JsonUtil; +import cc.iotkit.common.utils.UniqueIdUtil; +import cc.iotkit.comp.model.DeviceState; +import cc.iotkit.comp.model.RegisterInfo; +import cc.iotkit.comps.config.ServerConfig; +import cc.iotkit.dao.DeviceCache; +import cc.iotkit.dao.DeviceRepository; +import cc.iotkit.dao.ProductRepository; +import cc.iotkit.model.device.DeviceInfo; +import cc.iotkit.model.device.message.ThingModelMessage; +import cc.iotkit.model.product.Product; +import lombok.extern.slf4j.Slf4j; +import org.apache.pulsar.client.api.Producer; +import org.apache.pulsar.client.api.PulsarClient; +import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.pulsar.client.impl.schema.JSONSchema; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.util.HashMap; +import java.util.List; +import java.util.Optional; + +@Slf4j +@Service +public class DeviceBehaviourService { + + @Autowired + private ProductRepository productRepository; + @Autowired + private DeviceRepository deviceRepository; + @Autowired + private ServerConfig serverConfig; + @Autowired + private DeviceCache deviceCache; + @Autowired + private DeviceStateHolder deviceStateHolder; + + private Producer deviceMessageProducer; + + @PostConstruct + public void init() throws PulsarClientException { + //初始化pulsar客户端 + PulsarClient client = PulsarClient.builder() + .serviceUrl(serverConfig.getPulsarBrokerUrl()) + .build(); + deviceMessageProducer = client.newProducer(JSONSchema.of(ThingModelMessage.class)) + .topic("persistent://iotkit/default/device_thing") + .create(); + } + + public void register(RegisterInfo info) { + try { + DeviceInfo deviceInfo = register(null, info); + //子设备注册 + List subDevices = info.getSubDevices(); + if (subDevices != null && subDevices.size() != 0) { + for (RegisterInfo.SubDevice subDevice : subDevices) { + register(deviceInfo.getDeviceId(), + new RegisterInfo(subDevice.getProductKey(), + subDevice.getDeviceName(), + subDevice.getModel(), + subDevice.getTag(), null)); + } + } + + //设备注册消息 + ThingModelMessage modelMessage = new ThingModelMessage( + UniqueIdUtil.newRequestId(), "", + info.getProductKey(), info.getDeviceName(), + ThingModelMessage.TYPE_LIFETIME, "register", + 0, new HashMap<>(), System.currentTimeMillis(), + System.currentTimeMillis() + ); + + reportMessage(modelMessage); + } catch (BizException e) { + log.error("register device error", e); + throw e; + } catch (Throwable e) { + log.error("register device error", e); + throw new BizException("register device error", e); + } + } + + public DeviceInfo register(String parentId, RegisterInfo info) { + String pk = info.getProductKey(); + Optional optProduct = productRepository.findById(pk); + if (!optProduct.isPresent()) { + throw new BizException("Product does not exist"); + } + String uid = optProduct.get().getUid(); + DeviceInfo device = deviceRepository.findByProductKeyAndDeviceName(pk, info.getDeviceName()); + + if (device != null) { + log.info("device already registered."); + return device; + } + //不存在,注册新设备 + device = new DeviceInfo(); + device.setId(DeviceUtil.newDeviceId(info.getDeviceName())); + device.setParentId(parentId); + device.setUid(uid); + device.setDeviceId(device.getId()); + device.setProductKey(pk); + device.setDeviceName(info.getDeviceName()); + device.setState(new DeviceInfo.State(false, null, null)); + device.setCreateAt(System.currentTimeMillis()); + + deviceRepository.save(device); + log.info("device registered:{}", JsonUtil.toJsonString(device)); + + return device; + } + + public void deviceAuth(String productKey, + String deviceName, + String productSecret, + String deviceSecret) { + DeviceInfo deviceInfo = deviceRepository.findByProductKeyAndDeviceName(productKey, deviceName); + if (deviceInfo == null) { + throw new BizException("device does not exist"); + } + if (!Constants.PRODUCT_SECRET.equals(productSecret)) { + throw new BizException("incorrect productSecret"); + } + + //todo 按产品ProductSecret认证,子设备需要父设备认证后可通过验证 +// Optional optProduct = productRepository.findById(productKey); +// if (!optProduct.isPresent()) { +// throw new BizException("product does not exist"); +// } +// Product product = optProduct.get(); +// if (product.getNodeType()) { +// +// } + + } + + public void deviceStateChange(String productKey, + String deviceName, + boolean online) { + DeviceInfo device = deviceRepository.findByProductKeyAndDeviceName(productKey, deviceName); + if (device == null) { + throw new BizException("device does not exist"); + } + deviceStateChange(device, online); + + //可能是父设备,父设备离线,子设备也要离线 + if (!online && device.getParentId() == null) { + List subDevices = deviceRepository.findByParentId(device.getDeviceId()); + for (DeviceInfo subDevice : subDevices) { + deviceStateChange(subDevice, false); + } + } + } + + private void deviceStateChange(DeviceInfo device, boolean online) { + if (online) { + device.getState().setOnline(true); + device.getState().setOnlineTime(System.currentTimeMillis()); + deviceStateHolder.online(device.getDeviceId()); + } else { + device.getState().setOnline(false); + device.getState().setOfflineTime(System.currentTimeMillis()); + deviceStateHolder.offline(device.getDeviceId()); + } + deviceRepository.save(device); + + //设备状态变更消息 + ThingModelMessage modelMessage = new ThingModelMessage( + UniqueIdUtil.newRequestId(), "", + device.getProductKey(), device.getDeviceName(), + ThingModelMessage.TYPE_STATE, + online ? DeviceState.STATE_ONLINE : DeviceState.STATE_OFFLINE, + 0, + new HashMap<>(), System.currentTimeMillis(), + System.currentTimeMillis() + ); + + reportMessage(modelMessage); + } + + public void reportMessage(ThingModelMessage message) { + try { + DeviceInfo device = deviceCache.findByProductKeyAndDeviceName(message.getProductKey(), + message.getDeviceName()); + if (device == null) { + return; + } + if (message.getOccurred() == null) { + message.setOccurred(System.currentTimeMillis()); + } + if (message.getTime() == null) { + message.setTime(System.currentTimeMillis()); + } + message.setDeviceId(device.getDeviceId()); + deviceMessageProducer.send(message); + } catch (PulsarClientException e) { + log.error("send thing model message error", e); + } + } +} diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceMessageConsumer.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceMessageConsumer.java new file mode 100755 index 00000000..d26ff35b --- /dev/null +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceMessageConsumer.java @@ -0,0 +1,105 @@ +package cc.iotkit.comps.service; + +import cc.iotkit.common.Constants; +import cc.iotkit.common.utils.JsonUtil; +import cc.iotkit.comps.config.ServerConfig; +import cc.iotkit.dao.DeviceDao; +import cc.iotkit.dao.DevicePropertyRepository; +import cc.iotkit.dao.ThingModelMessageRepository; +import cc.iotkit.model.device.message.DeviceProperty; +import cc.iotkit.model.device.message.ThingModelMessage; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.pulsar.client.api.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.util.Map; + +@Slf4j +@Service +public class DeviceMessageConsumer implements MessageListener { + + @Autowired + private ServerConfig serverConfig; + @Lazy + @Autowired + private ThingModelMessageRepository messageRepository; + @Lazy + @Autowired + private DevicePropertyRepository propertyRepository; + @Autowired + private DeviceDao deviceDao; + + @PostConstruct + public void init() throws PulsarClientException { + PulsarClient client = PulsarClient.builder() + .serviceUrl(this.serverConfig.getPulsarBrokerUrl()) + .build(); + + client.newConsumer(Schema.JSON(ThingModelMessage.class)) + .topic("persistent://iotkit/default/" + Constants.THING_MODEL_MESSAGE_TOPIC) + .subscriptionName("thing-model-message") + .consumerName("thing-model-message-consumer") + .messageListener(this).subscribe(); + } + + @SneakyThrows + @Override + public void received(Consumer consumer, Message msg) { + try { + ThingModelMessage modelMessage = msg.getValue(); + String deviceId = modelMessage.getDeviceId(); + log.info("save message to es:{}", JsonUtil.toJsonString(modelMessage)); + //属性入库 + if (ThingModelMessage.TYPE_PROPERTY.equals(modelMessage.getType()) + && "report".equals(modelMessage.getIdentifier())) { + log.info("update device property,deviceId:{},property:{}", + deviceId, JsonUtil.toJsonString(modelMessage.getData())); + deviceDao.updateProperties(deviceId, (Map) modelMessage.getData()); + + //设备属性历史数据存储 + if (modelMessage.getData() instanceof Map) { + Map map = (Map) modelMessage.getData(); + int index = 0; + for (Object key : map.keySet()) { + index++; + try { + propertyRepository.save( + new DeviceProperty( + //防止重复id被覆盖 + modelMessage.getMid() + "_" + index, + deviceId, + key.toString(), + map.get(key), + modelMessage.getOccurred() + ) + ); + } catch (Throwable e) { + log.warn("save property data to es error", e); + } + } + } + } + + try { + //设备消息日志入库 + messageRepository.save(modelMessage); + } catch (Throwable e) { + log.warn("save device message to es error", e); + } + } catch (Throwable e) { + //不能重复消费 + log.error("device message consumer error", e); + } + consumer.acknowledge(msg); + } + + @Override + public void reachedEndOfTopic(Consumer consumer) { + + } + +} diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceStateHolder.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceStateHolder.java new file mode 100755 index 00000000..95811205 --- /dev/null +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceStateHolder.java @@ -0,0 +1,122 @@ +package cc.iotkit.comps.service; + +import cc.iotkit.common.utils.ThreadUtil; +import cc.iotkit.comps.config.ServerConfig; +import cc.iotkit.dao.DeviceRepository; +import cc.iotkit.model.device.DeviceInfo; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.pulsar.client.api.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * 设备状态维持,每1分钟更新一次心跳 + */ +@Slf4j +@Service +public class DeviceStateHolder implements MessageListener { + + private ScheduledThreadPoolExecutor stateHolderTask; + + private Set devices = new TreeSet<>(); + + @Autowired + private StringRedisTemplate redisTemplate; + @Autowired + private ServerConfig serverConfig; + @Autowired + private DeviceRepository deviceRepository; + + private Producer offlineMessageProducer; + + @PostConstruct + public void init() throws PulsarClientException { + stateHolderTask = ThreadUtil.newScheduled(4, "thread-device-state-holder"); + stateHolderTask.scheduleAtFixedRate(this::hold, 0, 1, TimeUnit.MINUTES); + + PulsarClient client = PulsarClient.builder() + .serviceUrl(this.serverConfig.getPulsarBrokerUrl()) + .build(); + + offlineMessageProducer = client.newProducer(Schema.JSON(OfflineMessage.class)) + .topic("persistent://iotkit/default/holder_offline") + .create(); + + client.newConsumer(Schema.JSON(OfflineMessage.class)) + .topic("persistent://iotkit/default/holder_offline") + .subscriptionName("holder_offline") + .consumerName("device-state-holder-consumer") + .messageListener(this).subscribe(); + } + + public void online(String deviceId) { + try { + devices.add(deviceId); + hold(deviceId); + //上线后先产生离线消息 + offlineMessageProducer.send(new OfflineMessage(deviceId)); + } catch (Throwable e) { + log.error("state holder online error", e); + } + } + + public void offline(String deviceId) { + devices.remove(deviceId); + } + + private void hold() { + //标识在线 + for (String deviceId : devices) { + hold(deviceId); + } + } + + private void hold(String deviceId) { + redisTemplate.opsForValue().set("str:device:state:holder:" + deviceId, + "1", 5, TimeUnit.SECONDS); + } + + @SneakyThrows + @Override + public void received(Consumer consumer, Message msg) { + String deviceId = msg.getValue().getDeviceId(); + //如果设备在线,不处理离线消息 + String hold = redisTemplate.opsForValue().get("str:device:state:holder:" + deviceId); + if (hold != null) { + return; + } + //如果设备不在线,则将设备更新为离线 + DeviceInfo device = deviceRepository.findByDeviceId(deviceId); + DeviceInfo.State state = device.getState(); + state.setOnline(false); + state.setOfflineTime(System.currentTimeMillis()); + deviceRepository.save(device); + log.info("device offline,deviceId:{}", deviceId); + + consumer.acknowledge(msg); + } + + @Override + public void reachedEndOfTopic(Consumer consumer) { + + } + + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class OfflineMessage { + private String deviceId; + } +} diff --git a/protocol-gateway/component/pom.xml b/protocol-gateway/component/pom.xml new file mode 100755 index 00000000..4086ecf6 --- /dev/null +++ b/protocol-gateway/component/pom.xml @@ -0,0 +1,33 @@ + + + + protocol-gateway + cc.iotkit + 0.0.1-SNAPSHOT + + 4.0.0 + + component + + + 8 + 8 + + + + + + cc.iotkit + converter + + + + org.projectlombok + lombok + + + + + \ No newline at end of file diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java new file mode 100755 index 00000000..7fd6ebbb --- /dev/null +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java @@ -0,0 +1,39 @@ +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.IConverter; +import lombok.Data; + +@Data +public abstract class AbstractComponent implements IComponent { + + protected IMessageHandler handler; + + protected IConverter converter; + + protected CompConfig config; + + @Override + public void create(CompConfig config) { + this.config=config; + } + + @Override + public void onDeviceRegister(RegisterInfo info) { + } + + @Override + public void onDeviceAuth(AuthInfo authInfo) { + } + + @Override + public void onDeviceStateChange(DeviceState state) { + } + + @Override + public CompConfig getConfig() { + return config; + } +} diff --git a/model/src/main/java/cc/iotkit/model/PagingData.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/CompConfig.java similarity index 52% rename from model/src/main/java/cc/iotkit/model/PagingData.java rename to protocol-gateway/component/src/main/java/cc/iotkit/comp/CompConfig.java index 30637bf9..724c7a85 100755 --- a/model/src/main/java/cc/iotkit/model/PagingData.java +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/CompConfig.java @@ -1,18 +1,16 @@ -package cc.iotkit.model; +package cc.iotkit.comp; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import java.util.List; - @Data @NoArgsConstructor @AllArgsConstructor -public class PagingData { +public class CompConfig { - private long count; + private long cmdTimeout; - private List data; + private String other; } diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/IComponent.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/IComponent.java new file mode 100755 index 00000000..7f42d4fe --- /dev/null +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/IComponent.java @@ -0,0 +1,36 @@ +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); + + void start(); + + void stop(); + + 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(); +} diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/IMessageHandler.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/IMessageHandler.java new file mode 100755 index 00000000..e3eed223 --- /dev/null +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/IMessageHandler.java @@ -0,0 +1,10 @@ +package cc.iotkit.comp; + +import cc.iotkit.comp.model.ReceiveResult; + +import java.util.Map; + +public interface IMessageHandler { + + ReceiveResult onReceive(Map head, String type, String msg); +} diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/AuthInfo.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/AuthInfo.java new file mode 100755 index 00000000..29a61d53 --- /dev/null +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/AuthInfo.java @@ -0,0 +1,16 @@ +package cc.iotkit.comp.model; + +import lombok.Data; + +@Data +public class AuthInfo { + + private String productKey; + + private String deviceName; + + private String productSecret; + + private String deviceSecret; + +} diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/DeviceState.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/DeviceState.java new file mode 100755 index 00000000..bff86846 --- /dev/null +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/DeviceState.java @@ -0,0 +1,33 @@ +package cc.iotkit.comp.model; + +import cc.iotkit.common.utils.JsonUtil; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +import java.util.Map; + +@Data +@Slf4j +public class DeviceState { + + public static final String STATE_ONLINE = "online"; + public static final String STATE_OFFLINE = "offline"; + + private String productKey; + + private String deviceName; + + private String state; + + private Parent parent; + + public static DeviceState from(Map map) { + return JsonUtil.parse(JsonUtil.toJsonString(map), DeviceState.class); + } + + @Data + public static class Parent { + private String productKey; + private String deviceName; + } +} diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/ReceiveResult.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/ReceiveResult.java new file mode 100755 index 00000000..3119ff7c --- /dev/null +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/ReceiveResult.java @@ -0,0 +1,18 @@ +package cc.iotkit.comp.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ReceiveResult { + + private String productKey; + + private String deviceName; + + private Object data; + +} diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/RegisterInfo.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/RegisterInfo.java new file mode 100755 index 00000000..4decb820 --- /dev/null +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/RegisterInfo.java @@ -0,0 +1,85 @@ +package cc.iotkit.comp.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.beanutils.BeanUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 注册信息 + */ +@Slf4j +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class RegisterInfo { + + private String productKey; + + private String deviceName; + + private String model; + + private Map tag; + + private List subDevices; + + public RegisterInfo(String productKey, String deviceName, String model) { + this.productKey = productKey; + this.deviceName = deviceName; + this.model = model; + } + + public RegisterInfo(String productKey, String deviceName, String subProductKey, String subDeviceName) { + this.productKey = productKey; + this.deviceName = deviceName; + if (subProductKey != null && subDeviceName != null) { + SubDevice subDevice = new SubDevice(subProductKey, subDeviceName, null, null); + subDevices = new ArrayList<>(); + subDevices.add(subDevice); + } + } + + public static RegisterInfo from(Map map) { + RegisterInfo bean = new RegisterInfo(); + try { + BeanUtils.populate(bean, map); + List subDevices = new ArrayList<>(); + List sourceSubDevices = (List) map.get("subDevices"); + if (sourceSubDevices == null) { + return bean; + } + for (Object sourceSubDevice : sourceSubDevices) { + SubDevice subDevice = new SubDevice(); + BeanUtils.populate(subDevice, (Map) sourceSubDevice); + subDevices.add(subDevice); + } + bean.setSubDevices(subDevices); + } catch (Throwable e) { + log.error("parse bean from map error", e); + return null; + } + return bean; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class SubDevice { + + private String productKey; + + private String deviceName; + + private String model; + + private Map tag; + } +} \ No newline at end of file diff --git a/device-server/device-api/pom.xml b/protocol-gateway/converter/pom.xml similarity index 64% rename from device-server/device-api/pom.xml rename to protocol-gateway/converter/pom.xml index d10955a6..0dc29b76 100755 --- a/device-server/device-api/pom.xml +++ b/protocol-gateway/converter/pom.xml @@ -3,33 +3,41 @@ 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"> - device-server + protocol-gateway cc.iotkit 0.0.1-SNAPSHOT 4.0.0 - device-api + converter + + 8 + 8 + + - org.springframework.cloud - spring-cloud-openfeign-core + org.slf4j + slf4j-api + - org.springframework - spring-web - - - org.projectlombok - lombok - compile + commons-beanutils + commons-beanutils + cc.iotkit model + + + org.projectlombok + lombok + + \ No newline at end of file diff --git a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/Device.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/Device.java new file mode 100755 index 00000000..20379d03 --- /dev/null +++ b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/Device.java @@ -0,0 +1,9 @@ +package cc.iotkit.converter; + +import lombok.Data; + +@Data +public class Device { + + +} diff --git a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/DeviceMessage.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/DeviceMessage.java new file mode 100755 index 00000000..a5f3ce66 --- /dev/null +++ b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/DeviceMessage.java @@ -0,0 +1,15 @@ +package cc.iotkit.converter; + +import lombok.Data; + +@Data +public class DeviceMessage { + + private String productKey; + + private String deviceName; + + private String mid; + + private Object content; +} diff --git a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/IConverter.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/IConverter.java new file mode 100755 index 00000000..d5c208da --- /dev/null +++ b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/IConverter.java @@ -0,0 +1,13 @@ +package cc.iotkit.converter; + +import cc.iotkit.model.device.message.ThingModelMessage; + +public interface IConverter { + + void setScript(String script); + + ThingModelMessage decode(DeviceMessage msg); + + DeviceMessage encode(ThingService service, Device device); + +} diff --git a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java new file mode 100755 index 00000000..0c56ba70 --- /dev/null +++ b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java @@ -0,0 +1,56 @@ +package cc.iotkit.converter; + +import cc.iotkit.common.utils.JsonUtil; +import cc.iotkit.model.device.message.ThingModelMessage; +import jdk.nashorn.api.scripting.NashornScriptEngine; +import jdk.nashorn.api.scripting.ScriptObjectMirror; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.beanutils.BeanUtils; + +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; +import java.util.Map; + +@Slf4j +@Data +public class ScriptConverter implements IConverter { + private final NashornScriptEngine engine = (NashornScriptEngine) (new ScriptEngineManager()).getEngineByName("nashorn"); + + private Object scriptObj; + + public void setScript(String script) { + try { + scriptObj = engine.eval(String.format("new (function () {\n%s})()", script)); + } catch (ScriptException e) { + log.error("eval converter script error", e); + } + } + + public ThingModelMessage decode(DeviceMessage msg) { + try { + ScriptObjectMirror result = (ScriptObjectMirror) engine.invokeMethod(scriptObj, "decode", msg); + ThingModelMessage modelMessage = new ThingModelMessage(); + BeanUtils.populate(modelMessage, result); + return modelMessage; + } catch (Throwable e) { + log.error("execute decode script error", e); + } + return null; + } + + @Override + public DeviceMessage encode(ThingService service, Device device) { + try { + ScriptObjectMirror result = (ScriptObjectMirror) engine.invokeMethod(scriptObj, "encode", service, device); + Map map = (Map) JsonUtil.toObject(result); + DeviceMessage message = new DeviceMessage(); + BeanUtils.populate(message, map); + return message; + } catch (Throwable e) { + log.error("execute encode script error", e); + } + return null; + } + +} diff --git a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ThingService.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ThingService.java new file mode 100755 index 00000000..633856d3 --- /dev/null +++ b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ThingService.java @@ -0,0 +1,29 @@ +package cc.iotkit.converter; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ThingService { + + public static final String TYPE_PROPERTY = "property"; + public static final String TYPE_SERVICE = "service"; + + private String mid; + + private String productKey; + + private String deviceName; + + private String type; + + private String identifier; + + private T params; + +} diff --git a/protocol-gateway/emqx-component/dependency-reduced-pom.xml b/protocol-gateway/emqx-component/dependency-reduced-pom.xml new file mode 100644 index 00000000..7a20b0f0 --- /dev/null +++ b/protocol-gateway/emqx-component/dependency-reduced-pom.xml @@ -0,0 +1,80 @@ + + + + protocol-gateway + cc.iotkit + 0.0.1-SNAPSHOT + + 4.0.0 + emqx-component + + + + maven-shade-plugin + 3.2.4 + + + package + + shade + + + + + + + io.vertx:vertx-core + io.vertx:vertx-web-proxy + io.vertx:vertx-mqtt + + + + + + maven-compiler-plugin + + 8 + 8 + + + + + + + io.vertx + vertx-core + 4.2.6 + provided + + + io.vertx + vertx-web-proxy + 4.2.6 + provided + + + io.vertx + vertx-mqtt + 4.2.6 + provided + + + cc.iotkit + model + 0.0.1-SNAPSHOT + compile + + + cc.iotkit + common + 0.0.1-SNAPSHOT + compile + + + cc.iotkit + component + 0.0.1-SNAPSHOT + compile + + + diff --git a/protocol-gateway/emqx-component/pom.xml b/protocol-gateway/emqx-component/pom.xml new file mode 100755 index 00000000..3e9788b0 --- /dev/null +++ b/protocol-gateway/emqx-component/pom.xml @@ -0,0 +1,83 @@ + + + + protocol-gateway + cc.iotkit + 0.0.1-SNAPSHOT + + 4.0.0 + + emqx-component + + + + + io.vertx + vertx-core + + + + io.vertx + vertx-web-proxy + + + + io.vertx + vertx-mqtt + + + + cc.iotkit + model + + + + cc.iotkit + common + + + + cc.iotkit + component + + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.4 + + + package + + shade + + + + + + + io.vertx:vertx-core + io.vertx:vertx-web-proxy + io.vertx:vertx-mqtt + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + + \ No newline at end of file diff --git a/protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/AuthVerticle.java b/protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/AuthVerticle.java new file mode 100755 index 00000000..9a89df27 --- /dev/null +++ b/protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/AuthVerticle.java @@ -0,0 +1,70 @@ +package cc.iotkit.comp.emqx; + +import cc.iotkit.comp.IMessageHandler; +import io.vertx.core.AbstractVerticle; +import io.vertx.core.http.HttpMethod; +import io.vertx.core.http.HttpServer; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.web.Router; +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; +import java.util.Map; + +@Slf4j +public class AuthVerticle extends AbstractVerticle { + + private HttpServer backendServer; + + private IMessageHandler executor; + + private EmqxConfig config; + + public void setExecutor(IMessageHandler executor) { + this.executor = executor; + } + + public AuthVerticle(EmqxConfig config) { + this.config = config; + } + + @Override + public void start() throws Exception { + backendServer = vertx.createHttpServer(); + Router backendRouter = Router.router(vertx); + + backendRouter.route(HttpMethod.POST, "/mqtt/auth").handler(rc -> { + JsonObject json = rc.getBodyAsJson(); + try { + executor.onReceive(new HashMap<>(), "auth", json.toString()); + rc.response().setStatusCode(200) + .end(); + } catch (Throwable e) { + rc.response().setStatusCode(500) + .end(); + log.error("mqtt auth failed", e); + } + }); + backendRouter.route(HttpMethod.POST, "/mqtt/acl").handler(rc -> { + JsonObject json = rc.getBodyAsJson(); + try { + Map head = new HashMap<>(); + head.put("topic", json.getString("topic")); + executor.onReceive(head, "subscribe", json.toString()); + rc.response().setStatusCode(200) + .end(); + } catch (Throwable e) { + rc.response().setStatusCode(500) + .end(); + log.error("mqtt acl failed", e); + } + }); + + backendServer.requestHandler(backendRouter).listen(config.getAuthPort()); + } + + @Override + public void stop() throws Exception { + backendServer.close(voidAsyncResult -> log.info("close emqx auth server...")); + } +} diff --git a/protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/EmqxComponent.java b/protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/EmqxComponent.java new file mode 100755 index 00000000..b698e745 --- /dev/null +++ b/protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/EmqxComponent.java @@ -0,0 +1,147 @@ +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.CompConfig; +import cc.iotkit.comp.model.DeviceState; +import cc.iotkit.converter.DeviceMessage; +import io.vertx.core.Future; +import io.vertx.core.Vertx; +import io.vertx.mqtt.MqttClient; +import io.vertx.mqtt.MqttClientOptions; +import io.vertx.mqtt.messages.MqttConnAckMessage; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; + +@Slf4j +public class EmqxComponent extends AbstractComponent { + + private Vertx vertx; + private AuthVerticle authVerticle; + private CountDownLatch countDownLatch; + private String deployedId; + private EmqxConfig mqttConfig; + + public void create(CompConfig config) { + super.create(config); + vertx = Vertx.vertx(); + mqttConfig = JsonUtil.parse(config.getOther(), EmqxConfig.class); + authVerticle = new AuthVerticle(mqttConfig); + } + + @Override + public void start() { + try { + authVerticle.setExecutor(getHandler()); + countDownLatch = new CountDownLatch(1); + Future future = vertx.deployVerticle(authVerticle); + future.onSuccess((s -> { + deployedId = s; + countDownLatch.countDown(); + })); + future.onFailure((e) -> { + countDownLatch.countDown(); + log.error("start emqx auth component failed", e); + }); + countDownLatch.await(); + + MqttClientOptions options = new MqttClientOptions() + .setClientId(mqttConfig.getClientId()) + .setUsername(mqttConfig.getUsername()) + .setPassword(mqttConfig.getPassword()) + .setCleanSession(true) + .setKeepAliveInterval(60); + + if (mqttConfig.isSsl()) { + options.setSsl(true) + .setTrustAll(true); + } + MqttClient client = MqttClient.create(vertx, options); + + Future connFuture = + client.connect(mqttConfig.getPort(), mqttConfig.getBroker()); + connFuture.onSuccess(ack -> log.info("connect emqx broker success")) + .onFailure(e -> log.error("connect emqx broker failed", e)); + + List topics = mqttConfig.getSubscribeTopics(); + Map subscribes = new HashMap<>(); + for (String topic : topics) { + subscribes.put(topic, 1); + } + + client.publishHandler(s -> { + String topic = s.topicName(); + String payload = s.payload().toString(); + log.info("receive message,topic:{},payload:{}", topic, payload); + +// +// //取消订阅 +// if (topic.equals("/sys/session/topic/unsubscribed")) { +// topicUnsubscribed(payload); +// return; +// } +// +// //连接断开 +// if (topic.equals("/sys/client/disconnected")) { +// disconnectedHandler.handler(payload); +// return; +// } +// +// String[] parts = topic.split("/"); +// if (parts.length < 5) { +// log.error("message topic is illegal."); +// return; +// } +// String productKey = parts[2]; +// String deviceName = parts[3]; +// +// //子设备注册 +// if (topic.endsWith("/register")) { + + + Map head = new HashMap<>(); + head.put("topic", topic); + getHandler().onReceive(head, "", payload); + }).subscribe(subscribes).onSuccess(a -> log.info("subscribe topic success")) + .onFailure(e -> log.error("subscribe topic failed", e)); + + } catch (Throwable e) { + throw new BizException("start emqx auth component error", e); + } + } + + @SneakyThrows + @Override + public void stop() { + authVerticle.stop(); + Future future = vertx.undeploy(deployedId); + future.onSuccess(unused -> log.info("stop emqx auth component success")); + } + + @Override + public void destroy() { + + } + + @Override + public void onDeviceStateChange(DeviceState state) { + + } + + @Override + public void send(DeviceMessage message) { + + } + + @Override + public boolean exist(String productKey, String deviceName) { + return false; + } + +} diff --git a/protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/EmqxConfig.java b/protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/EmqxConfig.java new file mode 100755 index 00000000..4c3cf453 --- /dev/null +++ b/protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/EmqxConfig.java @@ -0,0 +1,25 @@ +package cc.iotkit.comp.emqx; + +import lombok.Data; + +import java.util.List; + +@Data +public class EmqxConfig { + + private int authPort; + + private String broker; + + private int port; + + private boolean ssl; + + private String clientId; + + private String username; + + private String password; + + private List subscribeTopics; +} diff --git a/protocol-gateway/emqx-component/src/main/resources/component.spi b/protocol-gateway/emqx-component/src/main/resources/component.spi new file mode 100755 index 00000000..672ee448 --- /dev/null +++ b/protocol-gateway/emqx-component/src/main/resources/component.spi @@ -0,0 +1 @@ +cc.iotkit.comp.emqx.EmqxComponent \ No newline at end of file diff --git a/device-server/mqtt-client-simulator/.DS_Store b/protocol-gateway/mqtt-client-simulator/.DS_Store similarity index 100% rename from device-server/mqtt-client-simulator/.DS_Store rename to protocol-gateway/mqtt-client-simulator/.DS_Store diff --git a/device-server/mqtt-client-simulator/pom.xml b/protocol-gateway/mqtt-client-simulator/pom.xml similarity index 97% rename from device-server/mqtt-client-simulator/pom.xml rename to protocol-gateway/mqtt-client-simulator/pom.xml index 989e1f3b..72a6fe2b 100755 --- a/device-server/mqtt-client-simulator/pom.xml +++ b/protocol-gateway/mqtt-client-simulator/pom.xml @@ -3,7 +3,7 @@ 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"> - device-server + protocol-gateway cc.iotkit 0.0.1-SNAPSHOT diff --git a/protocol-gateway/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/Application.java b/protocol-gateway/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/Application.java new file mode 100755 index 00000000..603f9dd6 --- /dev/null +++ b/protocol-gateway/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/Application.java @@ -0,0 +1,37 @@ +package cc.iotkit.simulator; + +import cc.iotkit.simulator.config.Mqtt; +import cc.iotkit.simulator.service.Gateway; +import org.apache.commons.lang3.StringUtils; + +import java.io.IOException; + +public class Application { + + public static void main(String[] args) throws IOException { + + if (args.length == 0) { + Mqtt.broker = "tcp://127.0.0.1:1883"; +// Mqtt.broker = "tcp://120.76.96.206:1883"; + } else { + Mqtt.broker = args[0]; + } + new Thread(() -> { + Gateway gateway = new Gateway("hbtgIA0SuVw9lxjB", "AA:BB:CC:DD:22"); + gateway.addSubDevice("Rf4QSjbm65X45753", "ABC12300002", "S01"); + gateway.addSubDevice("Rf4QSjbm65X45753", "ABC12300003", "S01"); + gateway.addSubDevice("hdX3PCMcFrCYpesJ", "ABD12300001", "F01"); + gateway.addSubDevice("hdX3PCMcFrCYpesJ", "ABD12300002", "F01"); + gateway.addSubDevice("hdX3PCMcFrCYpesJ", "ABD12300002", "F01"); + gateway.start(); + + Gateway gateway2 = new Gateway("N523nWsCiG3CAn6X", "AA:BB:CC:EE:01"); + //插座 + gateway2.addSubDevice("cGCrkK7Ex4FESAwe", "ABE12300001", "S1"); + gateway2.addSubDevice("cGCrkK7Ex4FESAwe", "ABE12300002", "S1"); + gateway2.start(); + }).start(); + + System.in.read(); + } +} diff --git a/device-server/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/config/Mqtt.java b/protocol-gateway/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/config/Mqtt.java similarity index 100% rename from device-server/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/config/Mqtt.java rename to protocol-gateway/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/config/Mqtt.java diff --git a/device-server/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/service/Device.java b/protocol-gateway/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/service/Device.java similarity index 100% rename from device-server/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/service/Device.java rename to protocol-gateway/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/service/Device.java diff --git a/device-server/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/service/Gateway.java b/protocol-gateway/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/service/Gateway.java similarity index 55% rename from device-server/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/service/Gateway.java rename to protocol-gateway/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/service/Gateway.java index bded1d2c..0f232147 100755 --- a/device-server/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/service/Gateway.java +++ b/protocol-gateway/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/service/Gateway.java @@ -9,6 +9,7 @@ import org.apache.commons.codec.digest.DigestUtils; import org.eclipse.paho.client.mqttv3.*; import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; +import java.net.ConnectException; import java.util.*; @Slf4j @@ -24,10 +25,11 @@ public class Gateway extends Device { super(productKey, deviceName, "GW01"); } + @SneakyThrows public void start() { String broker = Mqtt.broker; - String clientId = String.format("%s_%s", productKey, deviceName); + String clientId = String.format("%s_%s_%s", productKey, deviceName, getModel()); MemoryPersistence persistence = new MemoryPersistence(); try { @@ -36,21 +38,32 @@ public class Gateway extends Device { // MQTT 连接选项 MqttConnectOptions connOpts = new MqttConnectOptions(); connOpts.setUserName(this.deviceName); - connOpts.setPassword(DigestUtils.md5Hex(Constants.MQTT_SECRET + clientId).toCharArray()); + connOpts.setPassword(DigestUtils.md5Hex(Constants.PRODUCT_SECRET + clientId).toCharArray()); // 保留会话 connOpts.setCleanSession(true); // 设置回调 - client.setCallback(new OnMessageCallback(client)); + client.setCallback(new OnMessageCallback(client, this)); // 建立连接 log.info("Connecting to broker:{} ", broker); - client.connect(connOpts); + try { + IMqttToken result = client.connectWithResult(connOpts); + result.waitForCompletion(); + } catch (Throwable e) { + log.error("connect failed,reconnect..."); + Thread.sleep(3000); + this.start(); + } log.info("Connected"); // 订阅 String topic = String.format("/sys/%s/%s/c/#", productKey, deviceName); log.info("subscribe topic:{}", topic); + while (!client.isConnected()) { + Thread.sleep(100); + } + IMqttToken mqttToken = client.subscribeWithResponse(topic); if (mqttToken.isComplete()) { //注册子设备 @@ -76,50 +89,60 @@ public class Gateway extends Device { public static class OnMessageCallback implements MqttCallback { private MqttClient client; + private Gateway gateway; - public OnMessageCallback(MqttClient client) { + public OnMessageCallback(MqttClient client, Gateway gateway) { this.client = client; + this.gateway = gateway; } + @SneakyThrows public void connectionLost(Throwable cause) { - log.info("连接断开"); + log.info("连接断开,重连..."); + Thread.sleep(3000); + client.close(); + gateway.start(); } @SneakyThrows public void messageArrived(String topic, MqttMessage message) { - log.info("接收消息,topic:{},payload:{}", topic, - new String(message.getPayload())); + try { + log.info("接收消息,topic:{},payload:{}", topic, + new String(message.getPayload())); - if (topic.endsWith("register_reply")) { - String payload = new String(message.getPayload()); - Response response = JsonUtil.parse(payload, Response.class); - //子设备注册成功 - if (response.code == 0) { - Map data = response.getData(); - //订阅子设备消息 - String subTopic = String.format("/sys/%s/%s/c/#", - data.get("productKey"), data.get("deviceName")); - log.info("subscribe topic:{}", subTopic); - client.subscribe(subTopic); + if (topic.endsWith("register_reply")) { + String payload = new String(message.getPayload()); + Response response = JsonUtil.parse(payload, Response.class); + //子设备注册成功 + if (response.code == 0) { + Map data = response.getData(); + //订阅子设备消息 + String subTopic = String.format("/sys/%s/%s/c/#", + data.get("productKey"), data.get("deviceName")); + log.info("subscribe topic:{}", subTopic); + client.subscribe(subTopic); + } } - } - if (topic.endsWith("_reply")) { - return; - } - String payload = new String(message.getPayload()); - Request request = JsonUtil.parse(payload, Request.class); + if (topic.endsWith("_reply")) { + return; + } + String payload = new String(message.getPayload()); + Request request = JsonUtil.parse(payload, Request.class); - Response response = new Response(request.getId(), 0, new HashMap<>()); - client.publish(topic.replace("/c/", "/s/") + "_reply", - new MqttMessage(JsonUtil.toJsonString(response).getBytes())); + Response response = new Response(request.getId(), 0, new HashMap<>()); + client.publish(topic.replace("/c/", "/s/") + "_reply", + new MqttMessage(JsonUtil.toJsonString(response).getBytes())); - //属性设置后上报属性 - String setTopic = "/c/service/property/set"; - if (topic.endsWith(setTopic)) { - request.setId(UUID.randomUUID().toString()); - client.publish(topic.replace(setTopic, "/s/event/property/post"), - new MqttMessage(JsonUtil.toJsonString(request).getBytes())); + //属性设置后上报属性 + String setTopic = "/c/service/property/set"; + if (topic.endsWith(setTopic)) { + request.setId(UUID.randomUUID().toString()); + client.publish(topic.replace(setTopic, "/s/event/property/post"), + new MqttMessage(JsonUtil.toJsonString(request).getBytes())); + } + } catch (Throwable e) { + log.info("receive msg error", e); } } diff --git a/device-server/.DS_Store b/protocol-gateway/mqtt-component/.DS_Store similarity index 67% rename from device-server/.DS_Store rename to protocol-gateway/mqtt-component/.DS_Store index b021504d..827186b4 100755 Binary files a/device-server/.DS_Store and b/protocol-gateway/mqtt-component/.DS_Store differ diff --git a/protocol-gateway/mqtt-component/dependency-reduced-pom.xml b/protocol-gateway/mqtt-component/dependency-reduced-pom.xml new file mode 100644 index 00000000..71213bd4 --- /dev/null +++ b/protocol-gateway/mqtt-component/dependency-reduced-pom.xml @@ -0,0 +1,86 @@ + + + + protocol-gateway + cc.iotkit + 0.0.1-SNAPSHOT + + 4.0.0 + mqtt-component + + + + maven-shade-plugin + 3.2.4 + + + package + + shade + + + + + + + io.vertx:vertx-core + io.vertx:vertx-mqtt + io.netty:netty-codec-mqtt + + + + + + maven-compiler-plugin + + 8 + 8 + + + + + + + io.vertx + vertx-core + 4.2.6 + provided + + + io.vertx + vertx-mqtt + 4.2.6 + provided + + + io.netty + netty-codec-mqtt + 4.1.72.Final + provided + + + org.projectlombok + lombok + 1.18.22 + compile + + + org.slf4j + slf4j-api + 1.7.32 + compile + + + cc.iotkit + common + 0.0.1-SNAPSHOT + compile + + + cc.iotkit + component + 0.0.1-SNAPSHOT + compile + + + diff --git a/protocol-gateway/mqtt-component/pom.xml b/protocol-gateway/mqtt-component/pom.xml new file mode 100755 index 00000000..52a9c79d --- /dev/null +++ b/protocol-gateway/mqtt-component/pom.xml @@ -0,0 +1,88 @@ + + + + protocol-gateway + cc.iotkit + 0.0.1-SNAPSHOT + + 4.0.0 + + mqtt-component + + + + + io.vertx + vertx-core + + + + io.vertx + vertx-mqtt + + + + io.netty + netty-codec-mqtt + + + + org.projectlombok + lombok + + + + org.slf4j + slf4j-api + + + + cc.iotkit + common + + + + cc.iotkit + component + + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.4 + + + package + + shade + + + + + + + io.vertx:vertx-core + io.vertx:vertx-mqtt + io.netty:netty-codec-mqtt + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + + \ No newline at end of file diff --git a/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttComponent.java b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttComponent.java new file mode 100755 index 00000000..ee1b2100 --- /dev/null +++ b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttComponent.java @@ -0,0 +1,140 @@ +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.CompConfig; +import cc.iotkit.comp.model.DeviceState; +import cc.iotkit.converter.DeviceMessage; +import io.vertx.core.Future; +import io.vertx.core.Vertx; +import lombok.*; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.beanutils.BeanUtils; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CountDownLatch; + +@Slf4j +public class MqttComponent extends AbstractComponent { + + private Vertx vertx; + private CountDownLatch countDownLatch; + private String deployedId; + private MqttVerticle mqttVerticle; + private Map deviceChildToParent = new HashMap<>(); + + public void create(CompConfig config) { + super.create(config); + vertx = Vertx.vertx(); + MqttConfig mqttConfig = JsonUtil.parse(config.getOther(), MqttConfig.class); + mqttVerticle = new MqttVerticle(mqttConfig); + } + + public void start() { + try { + mqttVerticle.setExecutor(getHandler()); + countDownLatch = new CountDownLatch(1); + Future future = vertx.deployVerticle(mqttVerticle); + future.onSuccess((s -> { + deployedId = s; + countDownLatch.countDown(); + })); + future.onFailure((e) -> { + countDownLatch.countDown(); + log.error("start mqtt component failed", e); + }); + countDownLatch.await(); + future.succeeded(); + } catch (Throwable e) { + throw new BizException("start mqtt component error", e); + } + } + + @SneakyThrows + public void stop() { + mqttVerticle.stop(); + Future future = vertx.undeploy(deployedId); + future.onSuccess(unused -> log.info("stop mqtt component success")); + } + + public void destroy() { + } + + @Override + public void onDeviceStateChange(DeviceState state) { + DeviceState.Parent parent = state.getParent(); + if (parent == null) { + return; + } + Device device = new Device(state.getProductKey(), state.getDeviceName()); + + if (DeviceState.STATE_ONLINE.equals(state.getState())) { + //保存子设备所属父设备 + deviceChildToParent.put(device.toString(), + new Device(parent.getProductKey(), parent.getDeviceName()) + ); + } else { + //删除关系 + deviceChildToParent.remove(device.toString()); + } + + } + + @Override + public void send(DeviceMessage message) { + Device child = new Device(message.getProductKey(), message.getDeviceName()); + //作为子设备查找父设备 + Device parent = deviceChildToParent.get(child.toString()); + if (parent == null) { + parent = child; + } + + Object obj = message.getContent(); + if (!(obj instanceof Map)) { + throw new BizException("message content is not Map"); + } + Message msg = new Message(); + try { + BeanUtils.populate(msg, (Map) obj); + } catch (Throwable e) { + throw new BizException("message content is incorrect"); + } + log.info("publish topic:{},payload:{}", msg.getTopic(), msg.getPayload()); + mqttVerticle.publish(parent.getProductKey(), parent.getDeviceName(), + msg.getTopic(), msg.getPayload()); + } + + @Override + public boolean exist(String productKey, String deviceName) { + //先作为子设备查找是否存在父设备 + Device device = deviceChildToParent.get(new Device(productKey, deviceName).toString()); + if (device != null) { + return true; + } + + return mqttVerticle.exist(productKey, deviceName); + } + + @Override + public CompConfig getConfig() { + return config; + } + + @Data + public static class Message { + private String topic; + private String payload; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + @ToString + public static class Device { + private String productKey; + private String deviceName; + } + +} diff --git a/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttConfig.java b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttConfig.java new file mode 100755 index 00000000..84edb733 --- /dev/null +++ b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttConfig.java @@ -0,0 +1,16 @@ +package cc.iotkit.comp.mqtt; + +import lombok.Data; + +@Data +public class MqttConfig { + + private int port; + + private String sslKey; + + private String sslCert; + + private boolean ssl; + +} diff --git a/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttVerticle.java b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttVerticle.java new file mode 100755 index 00000000..50d05621 --- /dev/null +++ b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttVerticle.java @@ -0,0 +1,175 @@ +package cc.iotkit.comp.mqtt; + +import cc.iotkit.common.exception.BizException; +import cc.iotkit.comp.IMessageHandler; +import cc.iotkit.comp.model.ReceiveResult; +import io.netty.handler.codec.mqtt.MqttConnectReturnCode; +import io.netty.handler.codec.mqtt.MqttProperties; +import io.netty.handler.codec.mqtt.MqttQoS; +import io.vertx.core.AbstractVerticle; +import io.vertx.core.Future; +import io.vertx.core.Handler; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.net.PemKeyCertOptions; +import io.vertx.mqtt.*; +import io.vertx.mqtt.messages.codes.MqttSubAckReasonCode; +import lombok.extern.slf4j.Slf4j; + +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Slf4j +public class MqttVerticle extends AbstractVerticle { + + private MqttServer mqttServer; + + private final MqttConfig config; + + private IMessageHandler executor; + + private Map endpointMap = new HashMap<>(); + + public MqttVerticle(MqttConfig config) { + this.config = config; + } + + public void setExecutor(IMessageHandler executor) { + this.executor = executor; + } + + @Override + public void start() throws Exception { + MqttServerOptions options = new MqttServerOptions() + .setPort(config.getPort()); + if (config.isSsl()) { + options = options.setSsl(true) + .setKeyCertOptions(new PemKeyCertOptions() + .setKeyPath(config.getSslKey()) + .setCertPath(config.getSslCert())); + } + + mqttServer = MqttServer.create(vertx, options); + mqttServer.endpointHandler(endpoint -> { + log.info("MQTT client:{} request to connect, clean session = {}", endpoint.clientIdentifier(), endpoint.isCleanSession()); + + MqttAuth auth = endpoint.auth(); + if (auth == null) { + return; + } + + String clientId = endpoint.clientIdentifier(); + String authJson = auth.toJson() + .put("clientid", clientId).toString(); + + log.info("MQTT client auth,clientId:{},username:{},password:{}", + clientId, auth.getUsername(), auth.getPassword()); + try { + ReceiveResult result = executor.onReceive(new HashMap<>(), "auth", authJson); + //保存设备与连接关系 + endpointMap.put(getEndpointKey(result), endpoint); + } catch (Throwable e) { + log.error("auth failed", e); + endpoint.reject(MqttConnectReturnCode.CONNECTION_REFUSED_NOT_AUTHORIZED); + return; + } + + log.info("MQTT client keep alive timeout = {} ", endpoint.keepAliveTimeSeconds()); + + endpoint.accept(false); + endpoint.disconnectMessageHandler(disconnectMessage -> { + log.info("Received disconnect from client, reason code = {}", disconnectMessage.code()); + ReceiveResult result = executor.onReceive(new HashMap<>(), "disconnect", clientId); + //删除设备与连接关系 + endpointMap.remove(getEndpointKey(result)); + }).subscribeHandler(subscribe -> { + List reasonCodes = new ArrayList<>(); + for (MqttTopicSubscription s : subscribe.topicSubscriptions()) { + log.info("Subscription for {},with QoS {}", s.topicName(), s.qualityOfService()); + try { + Map head = new HashMap<>(); + head.put("topic", s.topicName()); + executor.onReceive(head, "subscribe", clientId); + reasonCodes.add(MqttSubAckReasonCode.qosGranted(s.qualityOfService())); + } catch (Throwable e) { + log.error("subscribe failed,topic:" + s.topicName(), e); + reasonCodes.add(MqttSubAckReasonCode.NOT_AUTHORIZED); + } + } + // ack the subscriptions request + endpoint.subscribeAcknowledge(subscribe.messageId(), reasonCodes, MqttProperties.NO_PROPERTIES); + + }).unsubscribeHandler(unsubscribe -> { + for (String t : unsubscribe.topics()) { + log.info("Unsubscription for {}", t); + try { + Map head = new HashMap<>(); + head.put("topic", t); + executor.onReceive(head, "unsubscribe", clientId); + } catch (Throwable e) { + log.error("unsubscribe failed,topic:" + t, e); + } + } + // ack the subscriptions request + endpoint.unsubscribeAcknowledge(unsubscribe.messageId()); + }).publishHandler(message -> { + String payload = message.payload().toString(Charset.defaultCharset()); + log.info("Received message:{}, with QoS {}", payload, + message.qosLevel()); + try { + Map head = new HashMap<>(); + head.put("topic", message.topicName()); + executor.onReceive(head, "", payload); + if (message.qosLevel() == MqttQoS.AT_LEAST_ONCE) { + endpoint.publishAcknowledge(message.messageId()); + } else if (message.qosLevel() == MqttQoS.EXACTLY_ONCE) { + endpoint.publishReceived(message.messageId()); + } + } catch (Throwable e) { + log.error("handler message failed,topic:" + message.topicName(), e); + } + }).publishReleaseHandler(endpoint::publishComplete); + }).listen(ar -> { + if (ar.succeeded()) { + log.info("MQTT server is listening on port " + ar.result().actualPort()); + } else { + log.error("Error on starting the server", ar.cause()); + } + }); + } + + @Override + public void stop() throws Exception { + for (MqttEndpoint endpoint : endpointMap.values()) { + executor.onReceive(new HashMap<>(), "disconnect", endpoint.clientIdentifier()); + } + mqttServer.close(voidAsyncResult -> log.info("close mqtt server...")); + } + + private String getEndpointKey(ReceiveResult result) { + return getEndpointKey(result.getProductKey(), result.getDeviceName()); + } + + private String getEndpointKey(String productKey, String deviceName) { + return String.format("%s_%s", productKey, deviceName); + } + + public boolean exist(String productKey, String deviceName) { + return endpointMap.containsKey(getEndpointKey(productKey, deviceName)); + } + + public void publish(String productKey, String deviceName, String topic, String msg) { + MqttEndpoint endpoint = endpointMap.get(getEndpointKey(productKey, deviceName)); + if (endpoint == null) { + throw new BizException("endpoint does not exist"); + } + Future result = endpoint.publish(topic, Buffer.buffer(msg), + MqttQoS.AT_LEAST_ONCE, false, false); + result.onFailure(e -> log.error("public topic failed", e)); + result.onSuccess(integer -> { + log.info("publish success,topic:{},payload:{}", topic, msg); + }); + } +} diff --git a/protocol-gateway/mqtt-component/src/main/resources/component.js b/protocol-gateway/mqtt-component/src/main/resources/component.js new file mode 100755 index 00000000..cd505874 --- /dev/null +++ b/protocol-gateway/mqtt-component/src/main/resources/component.js @@ -0,0 +1,77 @@ +!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)))<>>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<>>9<<4)]=t;for(var c=1732584193,f=-271733879,i=-1732584194,a=271733878,h=0;h>5]>>>e%32&255);return t}function a(n){var t=[];for(t[(n.length>>2)-1]=void 0,e=0;e>5]|=(255&n.charCodeAt(e/8))<>>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 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, + }; + } 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 null; +}; diff --git a/device-server/pom.xml b/protocol-gateway/pom.xml similarity index 69% rename from device-server/pom.xml rename to protocol-gateway/pom.xml index e5077655..81409a9e 100755 --- a/device-server/pom.xml +++ b/protocol-gateway/pom.xml @@ -9,14 +9,15 @@ 4.0.0 - device-server + protocol-gateway pom - mqtt-auth - mqtt-server - device-api + component-server + converter + mqtt-component + emqx-component + component mqtt-client-simulator - \ No newline at end of file diff --git a/rule-engine/pom.xml b/rule-engine/pom.xml index d911db84..435630b7 100755 --- a/rule-engine/pom.xml +++ b/rule-engine/pom.xml @@ -41,6 +41,11 @@ spring-integration-mqtt + + com.squareup.okhttp3 + okhttp + + org.projectlombok lombok @@ -58,12 +63,12 @@ cc.iotkit - device-api + dao cc.iotkit - dao + component-server diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/action/Action.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/action/Action.java index 67f1273b..3089e56a 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/action/Action.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/action/Action.java @@ -1,5 +1,7 @@ package cc.iotkit.ruleengine.action; +import cc.iotkit.model.device.message.ThingModelMessage; + import java.util.List; public interface Action { @@ -8,5 +10,5 @@ public interface Action { List getServices(); - void execute(); + void execute(ThingModelMessage msg); } diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceAction.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceAction.java index f0c020ac..7d9139be 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceAction.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceAction.java @@ -1,7 +1,6 @@ package cc.iotkit.ruleengine.action; -import cc.iotkit.deviceapi.IDeviceService; -import cc.iotkit.deviceapi.Service; +import cc.iotkit.model.device.message.ThingModelMessage; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -11,15 +10,15 @@ import java.util.List; @NoArgsConstructor @AllArgsConstructor @Data -public class DeviceAction implements Action { +public class DeviceAction implements Action { public static final String TYPE = "device"; private String type; - private List services; + private List services; - private IDeviceService deviceService; + private DeviceActionService deviceActionService; @Override public String getType() { @@ -27,9 +26,9 @@ public class DeviceAction implements Action { } @Override - public void execute() { - for (Service service : services) { - deviceService.invoke(service); + public void execute(ThingModelMessage msg) { + for (DeviceActionService.Service service : services) { + deviceActionService.invoke(service); } } diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceActionService.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceActionService.java new file mode 100755 index 00000000..c06f9283 --- /dev/null +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceActionService.java @@ -0,0 +1,56 @@ +package cc.iotkit.ruleengine.action; + +import cc.iotkit.common.utils.UniqueIdUtil; +import cc.iotkit.comps.ComponentManager; +import cc.iotkit.converter.ThingService; +import lombok.Data; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +public class DeviceActionService { + + @Autowired + private ComponentManager componentManager; + + public String invoke(Service service) { + String[] pkDn = service.getDevice().split("/"); + ThingService> thingService = new ThingService<>(); + thingService.setMid(UniqueIdUtil.newRequestId()); + thingService.setProductKey(pkDn[0]); + thingService.setDeviceName(pkDn[1]); + thingService.setIdentifier(service.getIdentifier()); + thingService.setParams(service.parseInputData()); + componentManager.send(thingService); + return thingService.getMid(); + } + + @Data + public static class Service { + + private String device; + + private String identifier; + + private List inputData; + + public Map parseInputData() { + Map data = new HashMap<>(); + for (Parameter p : inputData) { + data.put(p.getIdentifier(), p.getValue()); + } + return data; + } + + @Data + public static class Parameter { + private String identifier; + private Object value; + } + } + +} diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/action/HttpAction.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/action/HttpAction.java new file mode 100755 index 00000000..5188a07b --- /dev/null +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/action/HttpAction.java @@ -0,0 +1,33 @@ +package cc.iotkit.ruleengine.action; + +import cc.iotkit.model.device.message.ThingModelMessage; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@NoArgsConstructor +@AllArgsConstructor +@Data +public class HttpAction implements Action { + + public static final String TYPE = "http"; + + private String type; + + private List services; + + @Override + public String getType() { + return TYPE; + } + + @Override + public void execute(ThingModelMessage msg) { + for (HttpService service : services) { + service.execute(msg); + } + } + +} diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/action/HttpService.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/action/HttpService.java new file mode 100644 index 00000000..7a28e766 --- /dev/null +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/action/HttpService.java @@ -0,0 +1,88 @@ +package cc.iotkit.ruleengine.action; + +import cc.iotkit.common.utils.JsonUtil; +import cc.iotkit.model.device.message.ThingModelMessage; +import jdk.nashorn.api.scripting.NashornScriptEngine; +import jdk.nashorn.api.scripting.ScriptObjectMirror; +import lombok.Data; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import okhttp3.*; +import org.apache.commons.beanutils.BeanUtils; + +import javax.script.ScriptEngineManager; +import java.io.IOException; +import java.util.Map; + +@Slf4j +@Data +public class HttpService { + private final NashornScriptEngine engine = (NashornScriptEngine) (new ScriptEngineManager()) + .getEngineByName("nashorn"); + + private String script; + + private String url; + + private ScriptObjectMirror scriptObject; + + private OkHttpClient httpClient = new OkHttpClient(); + + @SneakyThrows + public void execute(ThingModelMessage msg) { + if (scriptObject == null) { + scriptObject = (ScriptObjectMirror) engine.eval("new (function(){" + script + "})()"); + } + //执行转换脚本 + ScriptObjectMirror result = (ScriptObjectMirror) engine.invokeMethod(scriptObject, "translate", msg); + Object objResult = JsonUtil.toObject(result); + if (!(objResult instanceof Map)) { + return; + } + + HttpData httpData = new HttpData(); + BeanUtils.populate(httpData, (Map) objResult); + + //组装http请求 + String url = this.url + httpData.getPath(); + Request.Builder builder = new Request.Builder(); + Map headers = httpData.getHeader(); + if (headers != null) { + headers.forEach((key, val) -> builder.header(key, val.toString())); + } + HttpHeader httpHeader = new HttpHeader(); + BeanUtils.populate(httpHeader, headers); + + builder.url(url); + RequestBody requestBody; + requestBody = RequestBody.create(MediaType.get(httpHeader.getContentType()), + httpData.getBody().toString()); + + Request request = builder.method(httpData.getMethod().toUpperCase(), requestBody).build(); + log.info("send http request:{} ,{}", url, JsonUtil.toJsonString(objResult)); + + //发送请求 + try (Response response = httpClient.newCall(request).execute()) { + ResponseBody body = response.body(); + String content = body == null ? "" : body.string(); + log.info("send result,code:{},response:{}", response.code(), content); + } catch (IOException e) { + throw new RuntimeException("send request failed", e); + } + + } + + @Data + public static class HttpData { + private String path; + private String method; + private Map header; + private Object body; + } + + @Data + public static class HttpHeader { + private String contentType; + } + +} diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/config/JobFactory.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/config/JobFactory.java index 7e1530de..dd502de3 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/config/JobFactory.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/config/JobFactory.java @@ -1,7 +1,7 @@ package cc.iotkit.ruleengine.config; import cc.iotkit.model.rule.TaskInfo; -import cc.iotkit.ruleengine.action.ActionExecutorManager; +import cc.iotkit.ruleengine.task.ActionExecutorManager; import cc.iotkit.ruleengine.task.CommonJob; import cc.iotkit.ruleengine.task.TaskManager; import org.quartz.JobDetail; diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/config/MqttConsumerHandler.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/config/MqttConsumerHandler.java deleted file mode 100755 index 96d53baf..00000000 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/config/MqttConsumerHandler.java +++ /dev/null @@ -1,32 +0,0 @@ -package cc.iotkit.ruleengine.config; - -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.ruleengine.scene.SceneMessageHandler; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageHandler; -import org.springframework.messaging.MessagingException; - -@Slf4j -public class MqttConsumerHandler implements MessageHandler { - - @Autowired - private SceneMessageHandler sceneMessageHandler; - - @Override - public void handleMessage(Message msg) throws MessagingException { - String topic = (String) msg.getHeaders().get("mqtt_receivedTopic"); - if (topic == null) { - log.warn("topic is null"); - return; - } - Object payload = msg.getPayload(); - if (!(payload instanceof String)) { - payload = JsonUtil.toJsonString(payload); - } - log.info("receive message,topic:{},payload:{}", topic, payload); - sceneMessageHandler.handler(topic, payload.toString()); - } - -} diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/config/QuartzConfiguration.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/config/QuartzConfiguration.java index d4ad0871..4aa75579 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/config/QuartzConfiguration.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/config/QuartzConfiguration.java @@ -3,15 +3,10 @@ package cc.iotkit.ruleengine.config; import org.quartz.Scheduler; import org.quartz.spi.JobFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.config.PropertiesFactoryBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.io.ClassPathResource; import org.springframework.scheduling.quartz.SchedulerFactoryBean; -import java.io.IOException; -import java.util.Properties; - @Configuration public class QuartzConfiguration { @@ -23,7 +18,6 @@ public class QuartzConfiguration { SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); try { schedulerFactoryBean.setOverwriteExistingJobs(true); -// schedulerFactoryBean.setQuartzProperties(quartzProperties()); schedulerFactoryBean.setJobFactory(jobFactory); } catch (Exception e) { e.printStackTrace(); @@ -31,16 +25,6 @@ public class QuartzConfiguration { return schedulerFactoryBean; } - // 指定quartz.properties,可在配置文件中配置相关属性 -// @Bean - public Properties quartzProperties() throws IOException { - PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean(); - propertiesFactoryBean.setLocation(new ClassPathResource("/config/quartz.properties")); - propertiesFactoryBean.afterPropertiesSet(); - return propertiesFactoryBean.getObject(); - } - - // 创建schedule @Bean(name = "scheduler") public Scheduler scheduler() { return schedulerFactoryBean().getScheduler(); diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/config/RuleConfiguration.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/config/RuleConfiguration.java index 8c2048a2..45186c6a 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/config/RuleConfiguration.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/config/RuleConfiguration.java @@ -1,130 +1,27 @@ package cc.iotkit.ruleengine.config; -import cc.iotkit.common.Constants; -import cc.iotkit.common.utils.CodecUtil; +import cc.iotkit.ruleengine.handler.RuleDeviceConsumer; +import cc.iotkit.ruleengine.rule.RuleMessageHandler; import cc.iotkit.ruleengine.task.TaskManager; -import lombok.SneakyThrows; -import org.apache.commons.lang3.StringUtils; -import org.eclipse.paho.client.mqttv3.MqttConnectOptions; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.integration.annotation.ServiceActivator; -import org.springframework.integration.channel.DirectChannel; -import org.springframework.integration.core.MessageProducer; -import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory; -import org.springframework.integration.mqtt.core.MqttPahoClientFactory; -import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter; -import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.MessageHandler; + +import java.util.Collections; @Configuration public class RuleConfiguration { - /** - * 订阅的bean名称 - */ - public static final String CHANNEL_NAME_IN = "mqttInboundChannel"; + @Value("${pulsar.broker}") + public String pulsarBroker; - @Value("${mqtt.url}") - private String url; - - @Value(("${spring.profiles.active:}")) - private String env; - - private MqttPahoMessageDrivenChannelAdapter adapter; - - /** - * MQTT连接器选项 - * - * @return {@link MqttConnectOptions} - */ @Bean - public MqttConnectOptions getMqttConnectOptions() { - MqttConnectOptions options = new MqttConnectOptions(); - // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录, - // 这里设置为true表示每次连接到服务器都以新的身份连接 - options.setCleanSession(true); - // 设置连接的用户名 - options.setUserName("username"); - // 设置连接的密码 - options.setPassword("password".toCharArray()); - options.setServerURIs(StringUtils.split(url, ",")); - // 设置超时时间 单位为秒 - options.setConnectionTimeout(10); - // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送心跳判断客户端是否在线,但这个方法并没有重连的机制 - options.setKeepAliveInterval(20); - return options; - } - - /** - * MQTT客户端 - * - * @return {@link MqttPahoClientFactory} - */ - @Bean - public MqttPahoClientFactory mqttClientFactory() { - DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory(); - factory.setConnectionOptions(getMqttConnectOptions()); - return factory; - } - - /** - * MQTT消息订阅绑定(消费者) - * - * @return {@link MessageProducer} - */ - @SneakyThrows - @Bean - public MessageProducer inbound() { - String clientId = "rule-consumer-" + env; - clientId = "su_" + CodecUtil.aesEncrypt("admin_" + clientId, Constants.MQTT_SECRET); - adapter = new MqttPahoMessageDrivenChannelAdapter( - clientId, mqttClientFactory()); - adapter.setCompletionTimeout(5000); - adapter.setConverter(new DefaultPahoMessageConverter()); - adapter.setQos(1); - // 设置订阅通道 - adapter.setOutputChannel(mqttInboundChannel()); - return adapter; - } - - /** - * MQTT信息通道(消费者) - * - * @return {@link MessageChannel} - */ - @Bean(name = CHANNEL_NAME_IN) - public MessageChannel mqttInboundChannel() { - return new DirectChannel(); - } - - /** - * MQTT消息处理器(消费者) - * - * @return {@link MessageHandler} - */ - @Bean - @ServiceActivator(inputChannel = CHANNEL_NAME_IN) - public MessageHandler handler() { - return new MqttConsumerHandler(); - } - - public void subscribeTopic(String topic) { - adapter.addTopic(topic); - } - - public void unsubscribeTopic(String topic) { - adapter.removeTopic(topic); + public RuleDeviceConsumer getConsumer(RuleMessageHandler ruleMessageHandler) { + return new RuleDeviceConsumer(pulsarBroker, Collections.singletonList(ruleMessageHandler)); } @Bean public TaskManager getTaskManager() { return new TaskManager(); } - - public boolean isReady() { - return adapter != null; - } } diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/filter/DeviceCondition.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/filter/DeviceCondition.java index b802f6f8..e15ffbe9 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/filter/DeviceCondition.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/filter/DeviceCondition.java @@ -1,6 +1,6 @@ package cc.iotkit.ruleengine.filter; -import cc.iotkit.dao.DeviceDao; +import cc.iotkit.dao.DeviceCache; import cc.iotkit.model.device.DeviceInfo; import cc.iotkit.ruleengine.expression.Expression; import lombok.Data; @@ -20,18 +20,50 @@ public class DeviceCondition { private String comparator; - private DeviceDao deviceDao; + private DeviceCache deviceCache; + + public DeviceCondition clone() { + DeviceCondition con = new DeviceCondition(); + con.setDevice(device); + con.setType(type); + con.setIdentifier(identifier); + con.setValue(value); + con.setComparator(comparator); + con.setDeviceCache(deviceCache); + return con; + } public boolean matches() { + DeviceInfo deviceInfo; String[] pkDn = device.split("/"); - DeviceInfo deviceInfo = deviceDao.getByPkAndDn(pkDn[0], pkDn[1]); + if (pkDn.length < 2) { + //用deviceId取 + deviceInfo = deviceCache.findByDeviceId(device); + } else { + //用pk/dn取 + deviceInfo = deviceCache.findByProductKeyAndDeviceName(pkDn[0], pkDn[1]); + } Object left = null; if ("property".equals(type)) { Map properties = deviceInfo.getProperty(); left = properties.get(identifier); } else if ("state".equals(type)) { DeviceInfo.State state = deviceInfo.getState(); - left = state != null && state.getOnline(); + left = state != null && state.isOnline(); + } else if ("tag".equals(type)) { + //取设备标签判断 + Map tags = deviceInfo.getTag(); + if (tags == null) { + left = null; + } else { + DeviceInfo.Tag tag = tags.get(identifier); + if (tag == null) { + left = null; + } else { + //设备标签值 + left = tag.getValue(); + } + } } return Expression.eval(comparator, left, value); } diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/filter/DeviceFilter.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/filter/DeviceFilter.java index b1973126..db3d446b 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/filter/DeviceFilter.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/filter/DeviceFilter.java @@ -1,7 +1,9 @@ package cc.iotkit.ruleengine.filter; -import cc.iotkit.dao.DeviceDao; +import cc.iotkit.dao.DeviceCache; +import cc.iotkit.model.device.message.ThingModelMessage; import lombok.Data; +import org.apache.commons.lang3.StringUtils; import java.util.List; @@ -14,7 +16,7 @@ public class DeviceFilter implements Filter { private List conditions; - private DeviceDao deviceDao; + private DeviceCache deviceCache; @Override public String getType() { @@ -22,10 +24,20 @@ public class DeviceFilter implements Filter { } @Override - public boolean execute() { + public void init() { + } + + @Override + public boolean execute(ThingModelMessage msg) { for (DeviceCondition condition : getConditions()) { - condition.setDeviceDao(deviceDao); - if (!condition.matches()) { + DeviceCondition con = condition.clone(); + //未指定device,使用消息中的deviceId + if (StringUtils.isBlank(con.getDevice())) { + con.setDevice(msg.getDeviceId()); + } + + con.setDeviceCache(deviceCache); + if (!con.matches()) { return false; } } diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/filter/Filter.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/filter/Filter.java index 3c812879..d9440106 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/filter/Filter.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/filter/Filter.java @@ -1,5 +1,7 @@ package cc.iotkit.ruleengine.filter; +import cc.iotkit.model.device.message.ThingModelMessage; + import java.util.List; /** @@ -11,5 +13,7 @@ public interface Filter { List getConditions(); - boolean execute(); + void init(); + + boolean execute(ThingModelMessage msg); } diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/handler/DeviceMessageHandler.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/handler/DeviceMessageHandler.java new file mode 100644 index 00000000..1390566a --- /dev/null +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/handler/DeviceMessageHandler.java @@ -0,0 +1,9 @@ +package cc.iotkit.ruleengine.handler; + +import cc.iotkit.model.device.message.ThingModelMessage; + +public interface DeviceMessageHandler { + + void handle(ThingModelMessage message); + +} diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/handler/RuleDeviceConsumer.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/handler/RuleDeviceConsumer.java new file mode 100755 index 00000000..1fd63bc7 --- /dev/null +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/handler/RuleDeviceConsumer.java @@ -0,0 +1,53 @@ +package cc.iotkit.ruleengine.handler; + +import cc.iotkit.common.Constants; +import cc.iotkit.common.utils.JsonUtil; +import cc.iotkit.model.device.message.ThingModelMessage; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.pulsar.client.api.*; + +import java.util.ArrayList; +import java.util.List; + +@Slf4j +public class RuleDeviceConsumer implements MessageListener { + + private final List handlers = new ArrayList<>(); + + @SneakyThrows + public RuleDeviceConsumer(String broker, List handlers) { + this.handlers.addAll(handlers); + + PulsarClient client = PulsarClient.builder() + .serviceUrl(broker) + .build(); + + client.newConsumer(Schema.JSON(ThingModelMessage.class)) + .topic("persistent://iotkit/default/" + Constants.THING_MODEL_MESSAGE_TOPIC) + .subscriptionName("rule-engine-device") + .consumerName("rule-engine-device-consumer") + .messageListener(this).subscribe(); + } + + @SneakyThrows + @Override + public void received(Consumer consumer, Message msg) { + log.info("received thing model message:{}", JsonUtil.toJsonString(msg.getValue())); + try { + ThingModelMessage modelMessage = msg.getValue(); + for (DeviceMessageHandler handler : this.handlers) { + handler.handle(modelMessage); + } + } catch (Throwable e) { + log.error("rule device message process error", e); + } + consumer.acknowledge(msg); + } + + @Override + public void reachedEndOfTopic(Consumer consumer) { + + } + +} diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/listener/DeviceCondition.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/listener/DeviceCondition.java index 3ab59a2b..190ea53a 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/listener/DeviceCondition.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/listener/DeviceCondition.java @@ -11,6 +11,8 @@ public class DeviceCondition { private String type; + private String device; + private String identifier; private List parameters; @@ -41,10 +43,18 @@ public class DeviceCondition { private String comparator; public boolean matches(Map parameter) { + //任意匹配 + if ("*".equals(identifier)) { + return true; + } Object left = parameter.get(identifier); if (left == null) { return false; } + //任意匹配 + if ("*".equals(comparator)) { + return true; + } return Expression.eval(comparator, left, value); } } diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/listener/DeviceListener.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/listener/DeviceListener.java index 25f44094..e4e8e064 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/listener/DeviceListener.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/listener/DeviceListener.java @@ -1,5 +1,6 @@ package cc.iotkit.ruleengine.listener; +import cc.iotkit.model.device.message.ThingModelMessage; import lombok.Data; import lombok.extern.slf4j.Slf4j; @@ -14,8 +15,6 @@ public class DeviceListener implements Listener { private String type; - private String topic; - private List conditions; @Override @@ -24,21 +23,16 @@ public class DeviceListener implements Listener { } @Override - public boolean execute(String topic, Map params) { - String[] parts = topic.split("/"); - if (parts.length < 2) { - log.error("topic:{} is not Satisfiable", topic); - return false; - } - - String identifier = parts[parts.length - 1]; + public boolean execute(ThingModelMessage message) { + String identifier = message.getIdentifier(); + Map mapData = message.dataToMap(); for (DeviceCondition condition : this.conditions) { - if (!condition.matches(condition.getType(), identifier, params)) { - return false; + if (condition.matches(message.getType(), identifier, mapData)) { + return true; } } - return true; + return false; } } diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/listener/Listener.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/listener/Listener.java index 811cf19a..67208f30 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/listener/Listener.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/listener/Listener.java @@ -1,5 +1,7 @@ package cc.iotkit.ruleengine.listener; +import cc.iotkit.model.device.message.ThingModelMessage; + import java.util.List; import java.util.Map; @@ -7,9 +9,7 @@ public interface Listener { String getType(); - String getTopic(); - List getConditions(); - boolean execute(String topic, Map params); + boolean execute(ThingModelMessage msg); } diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/scene/Scene.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/rule/Rule.java similarity index 89% rename from rule-engine/src/main/java/cc/iotkit/ruleengine/scene/Scene.java rename to rule-engine/src/main/java/cc/iotkit/ruleengine/rule/Rule.java index fb94d7aa..1b213c39 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/scene/Scene.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/rule/Rule.java @@ -1,4 +1,4 @@ -package cc.iotkit.ruleengine.scene; +package cc.iotkit.ruleengine.rule; import cc.iotkit.ruleengine.action.Action; import cc.iotkit.ruleengine.filter.Filter; @@ -12,7 +12,7 @@ import java.util.List; @Data @NoArgsConstructor @AllArgsConstructor -public class Scene { +public class Rule { private String id; diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/rule/RuleExecutor.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/rule/RuleExecutor.java new file mode 100755 index 00000000..a9fc20ed --- /dev/null +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/rule/RuleExecutor.java @@ -0,0 +1,90 @@ +package cc.iotkit.ruleengine.rule; + +import cc.iotkit.dao.RuleLogRepository; +import cc.iotkit.model.device.message.ThingModelMessage; +import cc.iotkit.model.rule.RuleLog; +import cc.iotkit.ruleengine.action.Action; +import cc.iotkit.ruleengine.filter.Filter; +import cc.iotkit.ruleengine.listener.Listener; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.UUID; + +/** + * 规则执行器 + */ +@Component +@Slf4j +public class RuleExecutor { + + @Lazy + @Autowired + private RuleLogRepository ruleLogRepository; + + public void execute(ThingModelMessage message, Rule rule) { + if (!doListeners(message, rule)) { + log.info("The listener did not match the appropriate content,rule:{},{}", rule.getId(), rule.getName()); + return; + } + log.info("Start execute rule {},id:{}", rule.getName(), rule.getId()); + + RuleLog ruleLog = new RuleLog(); + ruleLog.setId(UUID.randomUUID().toString()); + ruleLog.setRuleId(rule.getId()); + ruleLog.setState(RuleLog.STATE_MATCHED_LISTENER); + + try { + if (!doFilters(rule, message)) { + ruleLog.setState(RuleLog.STATE_UNMATCHED_FILTER); + log.info("The filter did not match the appropriate content,rule:{},{}", rule.getId(), rule.getName()); + return; + } + ruleLog.setState(RuleLog.STATE_MATCHED_FILTER); + + doActions(rule, message); + ruleLog.setState(RuleLog.STATE_EXECUTED_ACTION); + ruleLog.setSuccess(true); + log.info("rule execution completed,id:{}", rule.getId()); + } catch (Throwable e) { + log.error("rule execution error,id:" + rule.getId(), e); + ruleLog.setSuccess(false); + ruleLog.setContent(e.toString()); + } finally { + ruleLog.setLogAt(System.currentTimeMillis()); + ruleLogRepository.save(ruleLog); + } + } + + private boolean doListeners(ThingModelMessage message, Rule rule) { + List> listeners = rule.getListeners(); + for (Listener listener : listeners) { + if (listener.execute(message)) { + //只要有一个监听器匹配到数据即可 + return true; + } + } + return false; + } + + private boolean doFilters(Rule rule, ThingModelMessage msg) { + List> filters = rule.getFilters(); + for (Filter filter : filters) { + //只要有一个过滤器未通过都不算通过 + if (!filter.execute(msg)) { + return false; + } + } + return true; + } + + private void doActions(Rule rule, ThingModelMessage msg) { + for (Action action : rule.getActions()) { + action.execute(msg); + } + } + +} diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/rule/RuleManager.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/rule/RuleManager.java new file mode 100755 index 00000000..0e56cb64 --- /dev/null +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/rule/RuleManager.java @@ -0,0 +1,140 @@ +package cc.iotkit.ruleengine.rule; + +import cc.iotkit.common.utils.JsonUtil; +import cc.iotkit.dao.DeviceCache; +import cc.iotkit.dao.RuleInfoRepository; +import cc.iotkit.model.rule.RuleAction; +import cc.iotkit.model.rule.RuleInfo; +import cc.iotkit.ruleengine.action.Action; +import cc.iotkit.ruleengine.action.DeviceAction; +import cc.iotkit.ruleengine.action.DeviceActionService; +import cc.iotkit.ruleengine.action.HttpAction; +import cc.iotkit.ruleengine.config.RuleConfiguration; +import cc.iotkit.ruleengine.filter.DeviceFilter; +import cc.iotkit.ruleengine.filter.Filter; +import cc.iotkit.ruleengine.listener.DeviceListener; +import cc.iotkit.ruleengine.listener.Listener; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +@Component +@Slf4j +public class RuleManager { + + @Autowired + private RuleConfiguration ruleConfiguration; + + @Autowired + private RuleMessageHandler ruleMessageHandler; + + @Autowired + private RuleInfoRepository ruleInfoRepository; + + @Autowired + private DeviceCache deviceCache; + + @Autowired + private DeviceActionService deviceActionService; + + public RuleManager() { + ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); + executorService.schedule(this::initRules, 1, TimeUnit.SECONDS); + } + + @SneakyThrows + public void initRules() { + int idx = 0; + while (true) { + Page rules = ruleInfoRepository.findAll(PageRequest.of(idx, + 1000, Sort.by(Sort.Order.desc("createAt")))); + rules.get().forEach(rule -> { + try { + log.info("got rule {} to init", rule.getId()); + add(rule); + } catch (Throwable e) { + log.error("add rule error", e); + } + }); + idx++; + if (rules.getContent().size() == 0) { + break; + } + } + } + + public void add(RuleInfo ruleInfo) { + Rule rule = parseRule(ruleInfo); + ruleMessageHandler.putRule(rule); + } + + public void remove(String ruleId) { + ruleMessageHandler.removeRule(ruleId); + } + + public void pause(String ruleId) { + remove(ruleId); + } + + public void resume(RuleInfo ruleInfo) { + add(ruleInfo); + } + + private Rule parseRule(RuleInfo ruleInfo) { + List> listeners = new ArrayList<>(); + for (RuleInfo.Listener listener : ruleInfo.getListeners()) { + listeners.add(parseListener(listener.getType(), listener.getConfig())); + } + List> filters = new ArrayList<>(); + for (RuleInfo.Filter filter : ruleInfo.getFilters()) { + filters.add(parseFilter(filter.getType(), filter.getConfig())); + } + List> actions = new ArrayList<>(); + for (RuleAction action : ruleInfo.getActions()) { + actions.add(parseAction(action.getType(), action.getConfig())); + } + + return new Rule(ruleInfo.getId(), ruleInfo.getName(), listeners, filters, actions); + } + + private Listener parseListener(String type, String config) { + if (DeviceListener.TYPE.equals(type)) { + return parse(config, DeviceListener.class); + } + return null; + } + + private Filter parseFilter(String type, String config) { + if (DeviceFilter.TYPE.equals(type)) { + DeviceFilter filter = parse(config, DeviceFilter.class); + filter.setDeviceCache(deviceCache); + return filter; + } + return null; + } + + private Action parseAction(String type, String config) { + if (DeviceAction.TYPE.equals(type)) { + DeviceAction action = parse(config, DeviceAction.class); + action.setDeviceActionService(deviceActionService); + return action; + } else if (HttpAction.TYPE.equals(type)) { + return parse(config, HttpAction.class); + } + return null; + } + + private T parse(String config, Class cls) { + return JsonUtil.parse(config, cls); + } + +} diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/rule/RuleMessageHandler.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/rule/RuleMessageHandler.java new file mode 100755 index 00000000..1608bb50 --- /dev/null +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/rule/RuleMessageHandler.java @@ -0,0 +1,74 @@ +package cc.iotkit.ruleengine.rule; + +import cc.iotkit.model.device.message.ThingModelMessage; +import cc.iotkit.ruleengine.handler.DeviceMessageHandler; +import cc.iotkit.ruleengine.listener.DeviceCondition; +import cc.iotkit.ruleengine.listener.Listener; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.*; + +@Component +public class RuleMessageHandler implements DeviceMessageHandler { + + private Map> deviceRuleMap = new HashMap<>(); + + @Autowired + private RuleExecutor ruleExecutor; + + public synchronized void putRule(Rule rule) { + //先删除已经存在的规则 + removeRule(rule.getId()); + + //将同一个规则中不同device拆开存储 + for (Listener listener : rule.getListeners()) { + for (Object condition : listener.getConditions()) { + if (!(condition instanceof DeviceCondition)) { + continue; + } + String device = ((DeviceCondition) condition).getDevice(); + deviceRuleMap.putIfAbsent(device, new ArrayList<>()); + List rules = deviceRuleMap.get(device); + rules.add(rule); + } + } + } + + public synchronized void removeRule(String ruleId) { + Iterator>> iterator = deviceRuleMap.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry> entry = iterator.next(); + String device = entry.getKey(); + //找出相同场景ID的规则删除 + entry.getValue().removeIf(s -> s != null && s.getId().equals(ruleId)); + //删除空的规则列表 + if (entry.getValue().size() == 0) { + iterator.remove(); + deviceRuleMap.remove(device); + } + } + } + + @Override + public void handle(ThingModelMessage message) { + String pk = message.getProductKey(); + String dn = message.getDeviceName(); + List rules = new ArrayList<>(); + //仅用PK匹配 + List foundRules = deviceRuleMap.get(pk + "/#"); + if (foundRules != null) { + rules.addAll(foundRules); + } + //用PK和DN匹配 + foundRules = deviceRuleMap.get(pk + "/" + dn); + if (foundRules != null) { + rules.addAll(foundRules); + } + //执行规则 + for (Rule rule : rules) { + ruleExecutor.execute(message, rule); + } + } + +} diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/scene/SceneExecutor.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/scene/SceneExecutor.java deleted file mode 100755 index 46e69630..00000000 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/scene/SceneExecutor.java +++ /dev/null @@ -1,88 +0,0 @@ -package cc.iotkit.ruleengine.scene; - -import cc.iotkit.dao.SceneLogRepository; -import cc.iotkit.model.rule.SceneLog; -import cc.iotkit.ruleengine.action.Action; -import cc.iotkit.ruleengine.filter.Filter; -import cc.iotkit.ruleengine.listener.Listener; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.util.List; -import java.util.Map; -import java.util.UUID; - -/** - * 场景执行器 - */ -@Component -@Slf4j -public class SceneExecutor { - - @Autowired - private SceneLogRepository sceneLogRepository; - - public void execute(String topic, Map params, Scene scene) { - if (!doListeners(topic, params, scene)) { - log.info("The listener did not match the appropriate content,scene:{},{}", scene.getId(), scene.getName()); - return; - } - log.info("Start execute scene {},id:{}", scene.getName(), scene.getId()); - - SceneLog sceneLog = new SceneLog(); - sceneLog.setId(UUID.randomUUID().toString()); - sceneLog.setSceneId(scene.getId()); - sceneLog.setState(SceneLog.STATE_MATCHED_LISTENER); - - try { - if (!doFilters(scene)) { - sceneLog.setState(SceneLog.STATE_UNMATCHED_FILTER); - log.info("The filter did not match the appropriate content,scene:{},{}", scene.getId(), scene.getName()); - return; - } - sceneLog.setState(SceneLog.STATE_MATCHED_FILTER); - - doActions(scene); - sceneLog.setState(SceneLog.STATE_EXECUTED_ACTION); - sceneLog.setSuccess(true); - log.info("Scene execution completed,id:{}", scene.getId()); - } catch (Throwable e) { - log.error("Scene execution error,id:" + scene.getId(), e); - sceneLog.setSuccess(false); - sceneLog.setContent(e.getMessage()); - } finally { - sceneLog.setLogAt(System.currentTimeMillis()); - sceneLogRepository.save(sceneLog); - } - } - - private boolean doListeners(String topic, Map params, Scene scene) { - List> listeners = scene.getListeners(); - for (Listener listener : listeners) { - if (listener.execute(topic, params)) { - //只要有一个监听器匹配到数据即可 - return true; - } - } - return false; - } - - private boolean doFilters(Scene scene) { - List> filters = scene.getFilters(); - for (Filter filter : filters) { - //只要有一个过滤器未通过都不算通过 - if (!filter.execute()) { - return false; - } - } - return true; - } - - private void doActions(Scene scene) { - for (Action action : scene.getActions()) { - action.execute(); - } - } - -} diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/scene/SceneManager.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/scene/SceneManager.java deleted file mode 100755 index 3ae04242..00000000 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/scene/SceneManager.java +++ /dev/null @@ -1,178 +0,0 @@ -package cc.iotkit.ruleengine.scene; - -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.dao.DeviceDao; -import cc.iotkit.dao.SceneInfoRepository; -import cc.iotkit.deviceapi.IDeviceService; -import cc.iotkit.model.rule.RuleAction; -import cc.iotkit.model.rule.SceneInfo; -import cc.iotkit.ruleengine.action.Action; -import cc.iotkit.ruleengine.action.DeviceAction; -import cc.iotkit.ruleengine.config.RuleConfiguration; -import cc.iotkit.ruleengine.filter.DeviceFilter; -import cc.iotkit.ruleengine.filter.Filter; -import cc.iotkit.ruleengine.listener.DeviceListener; -import cc.iotkit.ruleengine.listener.Listener; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Sort; -import org.springframework.stereotype.Component; - -import java.util.*; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -@Component -@Slf4j -public class SceneManager { - - private Map sceneMap = new HashMap<>(); - private Map> topicSceneMap = new HashMap<>(); - - @Autowired - private RuleConfiguration ruleConfiguration; - - @Autowired - private SceneMessageHandler sceneMessageHandler; - - @Autowired - private SceneInfoRepository sceneInfoRepository; - - @Autowired - private DeviceDao deviceDao; - - @Autowired - private IDeviceService deviceService; - - public SceneManager() { - ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); - executorService.schedule(this::initScenes, 1, TimeUnit.SECONDS); - } - - @SneakyThrows - public void initScenes() { - while (!ruleConfiguration.isReady()) { - Thread.sleep(100); - } - - int idx = 0; - while (true) { - Page scenes = sceneInfoRepository.findAll(PageRequest.of(idx, - 1000, Sort.by(Sort.Order.desc("createAt")))); - scenes.get().forEach(scene -> { - try { - log.info("got scene {} to init", scene.getId()); - add(scene); - } catch (Throwable e) { - log.error("add scene error", e); - } - }); - idx++; - if (scenes.getSize() == 0) { - break; - } - } - } - - public void add(SceneInfo sceneInfo) { - Scene scene = parseScene(sceneInfo); - sceneMap.put(scene.getId(), scene); - sceneMessageHandler.putScene(scene); - //订阅消息 - subscribe(scene); - } - - public void remove(String sceneId) { - Scene scene = sceneMap.get(sceneId); - for (Listener listener : scene.getListeners()) { - String topic = listener.getTopic(); - Set sceneIds = topicSceneMap.get(topic); - sceneIds.remove(sceneId); - - if (sceneIds.size() == 0) { - //topic没有场景关联,取消订阅 - ruleConfiguration.unsubscribeTopic(topic); - } - } - - sceneMap.remove(sceneId); - sceneMessageHandler.removeScene(sceneId); - } - - public void pause(String sceneId) { - remove(sceneId); - } - - public void resume(SceneInfo sceneInfo) { - add(sceneInfo); - } - - private void subscribe(Scene scene) { - for (Listener listener : scene.getListeners()) { - if (listener == null) { - return; - } - String topic = listener.getTopic(); - //已经订阅了,不重复订阅 - if (topicSceneMap.containsKey(topic)) { - topicSceneMap.get(topic).add(scene.getId()); - continue; - } - ruleConfiguration.subscribeTopic(topic); - Set sceneIds = new HashSet<>(); - sceneIds.add(scene.getId()); - topicSceneMap.put(topic, sceneIds); - } - } - - private Scene parseScene(SceneInfo sceneInfo) { - List> listeners = new ArrayList<>(); - for (SceneInfo.Listener listener : sceneInfo.getListeners()) { - listeners.add(parseListener(listener.getType(), listener.getConfig())); - } - List> filters = new ArrayList<>(); - for (SceneInfo.Filter filter : sceneInfo.getFilters()) { - filters.add(parseFilter(filter.getType(), filter.getConfig())); - } - List> actions = new ArrayList<>(); - for (RuleAction action : sceneInfo.getActions()) { - actions.add(parseAction(action.getType(), action.getConfig())); - } - - return new Scene(sceneInfo.getId(), sceneInfo.getName(), listeners, filters, actions); - } - - private Listener parseListener(String type, String config) { - if (DeviceListener.TYPE.equals(type)) { - return parse(config, DeviceListener.class); - } - return null; - } - - private Filter parseFilter(String type, String config) { - if (DeviceFilter.TYPE.equals(type)) { - DeviceFilter filter = parse(config, DeviceFilter.class); - filter.setDeviceDao(deviceDao); - return filter; - } - return null; - } - - private Action parseAction(String type, String config) { - if (DeviceAction.TYPE.equals(type)) { - DeviceAction action = parse(config, DeviceAction.class); - action.setDeviceService(deviceService); - return action; - } - return null; - } - - private T parse(String config, Class cls) { - return JsonUtil.parse(config, cls); - } - -} diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/scene/SceneMessageHandler.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/scene/SceneMessageHandler.java deleted file mode 100755 index fb7edb5a..00000000 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/scene/SceneMessageHandler.java +++ /dev/null @@ -1,84 +0,0 @@ -package cc.iotkit.ruleengine.scene; - -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.model.mq.Request; -import cc.iotkit.model.mq.Response; -import cc.iotkit.ruleengine.listener.Listener; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.util.*; -import java.util.regex.Pattern; - -@Component -public class SceneMessageHandler { - - private Map> topicSceneMap = new HashMap<>(); - private Map topicPatternMap = new HashMap<>(); - - @Autowired - private SceneExecutor sceneExecutor; - - public synchronized void putScene(Scene scene) { - //先删除已经存在的场景 - removeScene(scene.getId()); - - //将同一个场景中不同topic拆开存储 - for (Listener listener : scene.getListeners()) { - String topic = listener.getTopic(); - topicPatternMap.put(topic, Pattern.compile("")); - topicSceneMap.putIfAbsent(topic, new ArrayList<>()); - List scenes = topicSceneMap.get(topic); - scenes.add(scene); - } - } - - public synchronized void removeScene(String sceneId) { - Iterator>> iterator = topicSceneMap.entrySet().iterator(); - while (iterator.hasNext()) { - Map.Entry> entry = iterator.next(); - String topic = entry.getKey(); - //找出相同场景ID的场景删除 - entry.getValue().removeIf(s -> s != null && s.getId().equals(sceneId)); - //删除空的场景列表 - if (entry.getValue().size() == 0) { - iterator.remove(); - topicPatternMap.remove(topic); - } - } - } - - public void handler(String topic, String message) { - topicSceneMap.forEach((t, scenes) -> { - Pattern pattern = topicPatternMap.get(t); - if (pattern == null) { - return; - } - if (!pattern.matcher(topic).find()) { - return; - } - - Map params; - //匹配到topic,取消息内容 - if (topic.endsWith("_reply")) { - ResponseMsg response = JsonUtil.parse(message, ResponseMsg.class); - params = response.getData(); - } else { - RequestMsg request = JsonUtil.parse(message, RequestMsg.class); - params = request.getParams(); - } - - //执行场景 - for (Scene scene : scenes) { - sceneExecutor.execute(topic, params, scene); - } - }); - } - - private static class ResponseMsg extends Response> { - } - - private static class RequestMsg extends Request> { - - } -} diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/action/ActionExecutor.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/task/ActionExecutor.java similarity index 84% rename from rule-engine/src/main/java/cc/iotkit/ruleengine/action/ActionExecutor.java rename to rule-engine/src/main/java/cc/iotkit/ruleengine/task/ActionExecutor.java index 8650a0eb..fc235ca1 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/action/ActionExecutor.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/task/ActionExecutor.java @@ -1,4 +1,4 @@ -package cc.iotkit.ruleengine.action; +package cc.iotkit.ruleengine.task; /** * 动作执行器接口 diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/action/ActionExecutorManager.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/task/ActionExecutorManager.java similarity index 96% rename from rule-engine/src/main/java/cc/iotkit/ruleengine/action/ActionExecutorManager.java rename to rule-engine/src/main/java/cc/iotkit/ruleengine/task/ActionExecutorManager.java index 3bfe2283..a5cc98b2 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/action/ActionExecutorManager.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/task/ActionExecutorManager.java @@ -1,4 +1,4 @@ -package cc.iotkit.ruleengine.action; +package cc.iotkit.ruleengine.task; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeansException; diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/task/CommonJob.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/task/CommonJob.java index df8d8e9b..21e8a3f9 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/task/CommonJob.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/task/CommonJob.java @@ -2,7 +2,6 @@ package cc.iotkit.ruleengine.task; import cc.iotkit.model.rule.RuleAction; import cc.iotkit.model.rule.TaskInfo; -import cc.iotkit.ruleengine.action.ActionExecutorManager; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceActionExecutor.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/task/DeviceActionExecutor.java similarity index 52% rename from rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceActionExecutor.java rename to rule-engine/src/main/java/cc/iotkit/ruleengine/task/DeviceActionExecutor.java index 65d29758..80cc7478 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceActionExecutor.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/task/DeviceActionExecutor.java @@ -1,14 +1,17 @@ -package cc.iotkit.ruleengine.action; +package cc.iotkit.ruleengine.task; import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.dao.DeviceDao; -import cc.iotkit.deviceapi.IDeviceService; -import cc.iotkit.deviceapi.Service; +import cc.iotkit.dao.DeviceCache; +import cc.iotkit.ruleengine.action.DeviceAction; +import cc.iotkit.ruleengine.action.DeviceActionService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + /** * 设备输出器 */ @@ -17,10 +20,11 @@ import org.springframework.stereotype.Component; public class DeviceActionExecutor implements ActionExecutor { @Autowired - private IDeviceService deviceService; - + private DeviceCache deviceCache; @Autowired - private DeviceDao deviceDao; + private DeviceActionService deviceActionService; + + private Map actionMap = new ConcurrentHashMap<>(); @Override public String getName() { @@ -34,10 +38,14 @@ public class DeviceActionExecutor implements ActionExecutor { return; } //将执行的数据转换为动作配置 - DeviceAction action = JsonUtil.parse(config, DeviceAction.class); + DeviceAction action = actionMap.putIfAbsent(config.hashCode(), JsonUtil.parse(config, DeviceAction.class)); + if (action == null) { + return; + } + log.info("start device service invoke,{}", JsonUtil.toJsonString(action)); - for (Service service : action.getServices()) { - deviceService.invoke(service); + for (DeviceActionService.Service service : action.getServices()) { + deviceActionService.invoke(service); } } } diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/task/TaskManager.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/task/TaskManager.java index 910b30bf..3d339ffa 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/task/TaskManager.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/task/TaskManager.java @@ -2,7 +2,7 @@ package cc.iotkit.ruleengine.task; import cc.iotkit.common.exception.BizException; import cc.iotkit.dao.TaskInfoRepository; -import cc.iotkit.dao.TaskLogDao; +import cc.iotkit.dao.TaskLogRepository; import cc.iotkit.model.rule.TaskInfo; import cc.iotkit.model.rule.TaskLog; import lombok.SneakyThrows; @@ -12,6 +12,7 @@ import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; +import org.springframework.context.annotation.Lazy; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; @@ -31,8 +32,9 @@ public class TaskManager implements ApplicationContextAware { @Autowired private TaskInfoRepository taskInfoRepository; + @Lazy @Autowired - private TaskLogDao taskLogDao; + private TaskLogRepository taskLogRepository; public TaskManager() { ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); @@ -205,7 +207,7 @@ public class TaskManager implements ApplicationContextAware { } public void addLog(String taskId, boolean success, String content) { - taskLogDao.save(TaskLog.builder() + taskLogRepository.save(TaskLog.builder() .id(UUID.randomUUID().toString()) .taskId(taskId) .success(success) diff --git a/rule-engine/src/main/resources/spring.factories b/rule-engine/src/main/resources/spring.factories index 557a2014..f80a18ec 100755 --- a/rule-engine/src/main/resources/spring.factories +++ b/rule-engine/src/main/resources/spring.factories @@ -1 +1 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.danbay.iot.commons.logger.config.LoggerAutoConfiguration \ No newline at end of file +org.springframework.boot.autoconfigure.EnableAutoConfiguration=cc.iotkit.ruleengine.config.RuleConfiguration diff --git a/standalone-package/pom.xml b/standalone-package/pom.xml new file mode 100644 index 00000000..ca4e4c82 --- /dev/null +++ b/standalone-package/pom.xml @@ -0,0 +1,34 @@ + + + + iotkit-parent + cc.iotkit + 0.0.1-SNAPSHOT + + 4.0.0 + + standalone-package + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.0 + + 1.8 + 1.8 + UTF-8 + + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + + + + \ No newline at end of file diff --git a/standalone-package/src/main/resources/assemblies/standalone-package.xml b/standalone-package/src/main/resources/assemblies/standalone-package.xml new file mode 100644 index 00000000..6860e112 --- /dev/null +++ b/standalone-package/src/main/resources/assemblies/standalone-package.xml @@ -0,0 +1,17 @@ + + standalone-package + + zip + + false + + + lib + + runtime + false + + + \ No newline at end of file