合dev、数据流转修改
commit
782eba22de
|
@ -26,3 +26,5 @@ target
|
|||
*.iml
|
||||
*.yml
|
||||
log
|
||||
components
|
||||
data
|
||||
|
|
|
@ -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";
|
||||
|
||||
/**
|
||||
* 管理系统用户角色
|
||||
*/
|
||||
|
@ -58,4 +63,14 @@ public interface Constants {
|
|||
*/
|
||||
String PWD_SYSTEM_USER = "s123456";
|
||||
|
||||
/**
|
||||
* 设备原始上报消息的topic
|
||||
*/
|
||||
String DEVICE_RAW_MESSAGE_TOPIC = "device_raw";
|
||||
|
||||
/**
|
||||
* 设备物模型消息的topic
|
||||
*/
|
||||
String THING_MODEL_MESSAGE_TOPIC = "device_thing";
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class PkDn {
|
||||
private String productKey;
|
||||
private String deviceName;
|
||||
String len = StringUtils.leftPad(deviceNae.length() + "", 2, '0');
|
||||
String rnd = Integer.toHexString(RandomUtils.nextInt(0, 16));
|
||||
return (System.currentTimeMillis() + "0" + dn + len + rnd).toLowerCase();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<Object> list = new ArrayList<>();
|
||||
for (Map.Entry<String, Object> entry : mirror.entrySet()) {
|
||||
Object result = entry.getValue();
|
||||
if (result instanceof ScriptObjectMirror) {
|
||||
list.add(toObject((ScriptObjectMirror) result));
|
||||
} else {
|
||||
list.add(result);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
for (Map.Entry<String, Object> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -15,4 +15,6 @@ public interface AligenieDeviceRepository extends MongoRepository<AligenieDevice
|
|||
|
||||
AligenieDevice findByUidAndDeviceId(String uid, String deviceId);
|
||||
|
||||
List<AligenieDevice> findByDeviceId(String deviceId);
|
||||
|
||||
}
|
||||
|
|
|
@ -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<AligenieProduct> {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -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<T> {
|
||||
|
||||
protected MongoTemplate mongoTemplate;
|
||||
|
||||
private Class<T> cls;
|
||||
|
||||
public BaseDao(MongoTemplate mongoTemplate, Class<T> cls) {
|
||||
this.mongoTemplate = mongoTemplate;
|
||||
this.cls = cls;
|
||||
}
|
||||
|
||||
public List<T> find(Criteria condition) {
|
||||
Query query = new Query();
|
||||
query.addCriteria(condition);
|
||||
return mongoTemplate.find(query, cls);
|
||||
}
|
||||
|
||||
public List<T> 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> 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> T save(T entity) {
|
||||
return mongoTemplate.save(entity);
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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<DeviceInfo> {
|
||||
public class DeviceDao {
|
||||
|
||||
@Autowired
|
||||
private DeviceRepository deviceRepository;
|
||||
private MongoTemplate mongoTemplate;
|
||||
|
||||
@Autowired
|
||||
public DeviceDao(MongoTemplate mongoTemplate) {
|
||||
super(mongoTemplate, DeviceInfo.class);
|
||||
public Paging<DeviceInfo> 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<String, Object> properties) {
|
||||
if (properties == null) {
|
||||
return;
|
||||
}
|
||||
mongoTemplate.updateFirst(query(where("deviceId").is(device.getDeviceId())),
|
||||
DaoTool.update(device), DeviceInfo.class);
|
||||
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, update, 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);
|
||||
/**
|
||||
* 更新设备标签
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
@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 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);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<DeviceEvent> {
|
||||
|
||||
@Autowired
|
||||
public DeviceEventDao(MongoTemplate mongoTemplate) {
|
||||
super(mongoTemplate, DeviceEvent.class);
|
||||
}
|
||||
}
|
|
@ -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<DeviceProperty> 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<DeviceProperty> result = template.search(query, DeviceProperty.class);
|
||||
return result.getSearchHits().stream()
|
||||
.map(SearchHit::getContent).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
|
@ -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<DeviceProperty, String> {
|
||||
|
||||
|
||||
}
|
|
@ -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, String> {
|
||||
|
||||
DeviceInfo findByProductKeyAndDeviceName(String productKey, String deviceName);
|
||||
|
||||
DeviceInfo findByDeviceId(String deviceId);
|
||||
|
||||
List<DeviceInfo> findByParentId(String parentId);
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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<ProtocolComponent, String> {
|
||||
|
||||
List<ProtocolComponent> findByState(String state);
|
||||
|
||||
}
|
|
@ -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<SceneInfo, String> {
|
||||
public interface ProtocolConverterRepository extends MongoRepository<ProtocolConverter, String> {
|
||||
}
|
|
@ -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<SceneLog, String> {
|
||||
public interface ProtocolGatewayRepository extends MongoRepository<ProtocolComponent, String> {
|
||||
|
||||
|
||||
}
|
|
@ -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<RuleInfo, String> {
|
||||
|
||||
List<RuleInfo> findByUidAndType(String uid, String type);
|
||||
|
||||
}
|
|
@ -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<RuleLog, String> {
|
||||
|
||||
void deleteByRuleId(String ruleId);
|
||||
|
||||
Page<RuleLog> findByRuleId(String ruleId, Pageable pageable);
|
||||
|
||||
}
|
|
@ -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<SceneLog> {
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
|
@ -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<TaskLog> {
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
|
@ -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<TaskLog, String> {
|
||||
public interface TaskLogRepository extends ElasticsearchRepository<TaskLog, String> {
|
||||
|
||||
void deleteByTaskId(String taskId);
|
||||
|
||||
Page<TaskLog> findByTaskId(String taskId, Pageable pageable);
|
||||
|
||||
}
|
||||
|
|
|
@ -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<ThingModelMessage> 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<ThingModelMessage> result = template.search(query, ThingModelMessage.class);
|
||||
return new Paging<>(result.getTotalHits(), result.getSearchHits().stream()
|
||||
.map(SearchHit::getContent).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
}
|
|
@ -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<ThingModelMessage, String> {
|
||||
|
||||
Page<ThingModelMessage> findByTypeAndIdentifier(String type, String identifier, Pageable pageable);
|
||||
|
||||
}
|
|
@ -6,4 +6,7 @@ import org.springframework.stereotype.Repository;
|
|||
|
||||
@Repository
|
||||
public interface ThingModelRepository extends MongoRepository<ThingModel, String> {
|
||||
|
||||
ThingModel findByProductKey(String productKey);
|
||||
|
||||
}
|
||||
|
|
|
@ -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<UserInfo> {
|
||||
|
||||
@Autowired
|
||||
public UserInfoDao(MongoTemplate mongoTemplate) {
|
||||
super(mongoTemplate, UserInfo.class);
|
||||
}
|
||||
}
|
|
@ -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<UserInfo, String> {
|
||||
|
||||
List<UserInfo> findByType(int type);
|
||||
|
||||
List<UserInfo> findByTypeAndOwnerId(int type, String ownerId);
|
||||
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<String, Object> properties);
|
||||
|
||||
/**
|
||||
* 调用服务
|
||||
*/
|
||||
@PostMapping("/{deviceId}/{identifier}/invoke")
|
||||
String invokeService(@PathVariable("deviceId") String deviceId,
|
||||
@PathVariable("identifier") String identifier,
|
||||
@RequestBody Map<String, Object> properties);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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<Parameter> inputData;
|
||||
|
||||
public Map<String, Object> parseInputData() {
|
||||
Map<String, Object> 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;
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>device-server</artifactId>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>mqtt-auth</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-mongodb</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-beanutils</groupId>
|
||||
<artifactId>commons-beanutils</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15on</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<artifactId>model</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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<Prop> props) {
|
||||
for (Prop pro : props) {
|
||||
update.set(pro.getName(), pro.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Prop> getProp(String key, Object value) {
|
||||
List<Prop> props = new ArrayList<>();
|
||||
if (value instanceof Map) {
|
||||
Set<Map.Entry<String, Object>> entrySet = ((Map) value).entrySet();
|
||||
for (Map.Entry<String, Object> 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 <T> Update update(T obj) {
|
||||
Map<Object, Object> pros = new BeanMap(obj);
|
||||
Update update = new Update();
|
||||
for (Map.Entry<Object, Object> 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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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.");
|
||||
// }
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
spring:
|
||||
data:
|
||||
mongodb:
|
||||
uri: mongodb://填写mongodb地址/admin
|
||||
database: iotkit
|
|
@ -1,5 +0,0 @@
|
|||
spring:
|
||||
data:
|
||||
mongodb:
|
||||
uri: mongodb://填写mongodb地址/admin
|
||||
database: iotkit
|
|
@ -1,81 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<jmxConfigurator/>
|
||||
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
|
||||
<!-- Example for logging into the build folder of your project -->
|
||||
<property name="LOG_FILE" value="log"/>
|
||||
|
||||
<!-- You can override this to have a custom pattern -->
|
||||
<property name="CONSOLE_LOG_PATTERN"
|
||||
value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
|
||||
|
||||
<!-- Appender to log to console -->
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<!-- Minimum logging level to be presented in the console logs-->
|
||||
<level>DEBUG</level>
|
||||
</filter>
|
||||
<encoder>
|
||||
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
|
||||
<charset>utf8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- Appender to log to file -->
|
||||
<appender name="info" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_FILE}/info.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_FILE}/info.%d{yyyy-MM-dd}.%i.gz</fileNamePattern>
|
||||
<!-- 如果按天来回滚,则最大保存时间为5天,5天之前的都将被清理掉 -->
|
||||
<maxHistory>5</maxHistory>
|
||||
<!-- 日志总保存量为20GB -->
|
||||
<totalSizeCap>20GB</totalSizeCap>
|
||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<!--文件达到 最大1GB时会被压缩和切割 -->
|
||||
<maxFileSize>1GB</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
|
||||
<charset>utf8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- Appender to log to file only error level log -->
|
||||
<appender name="error" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_FILE}/error.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_FILE}/error.%d{yyyy-MM-dd}.%i.gz</fileNamePattern>
|
||||
<!-- 如果按天来回滚,则最大保存时间为5天,5天之前的都将被清理掉 -->
|
||||
<maxHistory>5</maxHistory>
|
||||
<!-- 日志总保存量为5GB -->
|
||||
<totalSizeCap>5GB</totalSizeCap>
|
||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<!--文件达到 最大1GB时会被压缩和切割 -->
|
||||
<maxFileSize>1GB</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
|
||||
<charset>utf8</charset>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter"><!-- 只打印错误日志 -->
|
||||
<level>ERROR</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<logger name="cc.iotkit" level="debug" additivity="false">
|
||||
<appender-ref ref="info"/>
|
||||
<appender-ref ref="error"/>
|
||||
<appender-ref ref="console"/>
|
||||
</logger>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="info"/>
|
||||
<appender-ref ref="error"/>
|
||||
<appender-ref ref="console"/>
|
||||
</root>
|
||||
|
||||
</configuration>
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,123 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>device-server</artifactId>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>mqtt-server</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-mongodb</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-integration</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-mqtt</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-cache</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-beanutils</groupId>
|
||||
<artifactId>commons-beanutils</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15on</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<artifactId>model</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<artifactId>device-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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<T> {
|
||||
|
||||
protected MongoTemplate mongoTemplate;
|
||||
|
||||
private Class<T> cls;
|
||||
|
||||
public BaseDao(MongoTemplate mongoTemplate, Class<T> cls) {
|
||||
this.mongoTemplate = mongoTemplate;
|
||||
this.cls = cls;
|
||||
}
|
||||
|
||||
public List<T> find(Criteria condition) {
|
||||
Query query = new Query();
|
||||
query.addCriteria(condition);
|
||||
return mongoTemplate.find(query, cls);
|
||||
}
|
||||
|
||||
public List<T> 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> 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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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<Prop> props) {
|
||||
for (Prop pro : props) {
|
||||
update.set(pro.getName(), pro.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Prop> getProp(String key, Object value) {
|
||||
List<Prop> props = new ArrayList<>();
|
||||
if (value instanceof Map) {
|
||||
Set<Map.Entry<String, Object>> entrySet = ((Map) value).entrySet();
|
||||
for (Map.Entry<String, Object> 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 <T> Update update(T obj) {
|
||||
Map<Object, Object> pros = new BeanMap(obj);
|
||||
Update update = new Update();
|
||||
for (Map.Entry<Object, Object> 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;
|
||||
}
|
||||
}
|
|
@ -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<DeviceInfo> {
|
||||
|
||||
@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());
|
||||
}
|
||||
}
|
|
@ -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<DeviceEvent, String> {
|
||||
|
||||
Page<DeviceEvent> findByDeviceId(String deviceId, Pageable pageable);
|
||||
}
|
|
@ -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<DeviceInfo, String> {
|
||||
}
|
|
@ -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<ThingModel, String> {
|
||||
}
|
|
@ -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<Disconnected>() {
|
||||
});
|
||||
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<DeviceInfo> 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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<Map<String, Object>, 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<Request>() {
|
||||
});
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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<MqttHandler> 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<Unsubscribed>() {
|
||||
});
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
package cc.iotkit.server.handler;
|
||||
|
||||
import cc.iotkit.model.device.DeviceInfo;
|
||||
import cc.iotkit.model.mq.Request;
|
||||
|
||||
public interface MqttHandler<T, R> {
|
||||
|
||||
boolean compliant(String topic);
|
||||
|
||||
Request<T> parse(String msg);
|
||||
|
||||
R handler(String topic, DeviceInfo device, Request<T> request);
|
||||
|
||||
}
|
|
@ -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<Map<String, Object>, Response.Empty> {
|
||||
|
||||
@Autowired
|
||||
DeviceRepository deviceRepository;
|
||||
@Autowired
|
||||
DeviceEventRepository deviceEventRepository;
|
||||
|
||||
@Override
|
||||
public boolean compliant(String topic) {
|
||||
return topic.endsWith("/event/property/post");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request<Map<String, Object>> parse(String msg) {
|
||||
return JsonUtil.parse(msg, new TypeReference<Request<Map<String, Object>>>() {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response.Empty handler(String topic, DeviceInfo device, Request<Map<String, Object>> request) {
|
||||
device.setId(device.getDeviceId());
|
||||
if (device.getProperty() == null) {
|
||||
device.setProperty(new HashMap<>());
|
||||
}
|
||||
Map<String, Object> 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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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<Map<String, Object>, Response.Empty> {
|
||||
|
||||
@Autowired
|
||||
DeviceEventRepository deviceEventRepository;
|
||||
|
||||
@Override
|
||||
public boolean compliant(String topic) {
|
||||
return topic.endsWith("/service/property/set_reply");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request<Map<String, Object>> parse(String msg) {
|
||||
return JsonUtil.parse(msg, new TypeReference<Request<Map<String, Object>>>() {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response.Empty handler(String topic, DeviceInfo device, Request<Map<String, Object>> 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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<DeviceRegister, DeviceRegister> {
|
||||
|
||||
@Autowired
|
||||
private DeviceService deviceService;
|
||||
|
||||
@Override
|
||||
public boolean compliant(String topic) {
|
||||
return topic.endsWith("/register");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request<DeviceRegister> parse(String msg) {
|
||||
return JsonUtil.parse(msg, new TypeReference<Request<DeviceRegister>>() {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceRegister handler(String topic, DeviceInfo device, Request<DeviceRegister> request) {
|
||||
DeviceRegister regInfo = request.getParams();
|
||||
deviceService.register(device.getDeviceId(), regInfo.getProductKey(),
|
||||
regInfo.getDeviceName(), regInfo.getModel());
|
||||
return regInfo;
|
||||
}
|
||||
}
|
|
@ -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<Map<String, Object>, 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<Map<String, Object>> parse(String msg) {
|
||||
return JsonUtil.parse(msg, new TypeReference<Request<Map<String, Object>>>() {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response.Empty handler(String topic, DeviceInfo device, Request<Map<String, Object>> 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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<String, Object> 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<String, Object> properties) {
|
||||
return sendMsg(deviceId, identifier_set, properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String invokeService(String deviceId, String identifier, Map<String, Object> 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<String, Object> 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<String, Object> 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;
|
||||
}
|
||||
}
|
|
@ -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 对消息处理的几种机制。<br> 0 表示的是订阅者没收到消息不会再次发送,消息会丢失。<br>
|
||||
* 1 表示的是会尝试重试,一直到接收到消息,但这种情况可能导致订阅者收到多次重复消息。<br>
|
||||
* 2 多了一次去重的动作,确保订阅者收到的消息有一次。
|
||||
* @param payload 消息主体
|
||||
*/
|
||||
void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic,
|
||||
@Header(MqttHeaders.QOS) int qos,
|
||||
String payload);
|
||||
}
|
|
@ -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<String, Object> paramsParse(ThingModel thingModel, String identifier, Map<?, ?> params) {
|
||||
Map<String, Object> parsedParams = new HashMap<>();
|
||||
ThingModel.Model model = thingModel.getModel();
|
||||
|
||||
//属性设置
|
||||
if ("property/set".equals(identifier)) {
|
||||
List<ThingModel.Property> properties = model.getProperties();
|
||||
if (properties == null) {
|
||||
return parsedParams;
|
||||
}
|
||||
return parseProperties(properties, params);
|
||||
} else {
|
||||
//服务调用
|
||||
Map<String, ThingModel.Service> services = model.serviceMap();
|
||||
ThingModel.Service service = services.get(identifier);
|
||||
if (service == null) {
|
||||
return parsedParams;
|
||||
}
|
||||
List<ThingModel.Parameter> parameters = service.getInputData();
|
||||
return parseParams(parameters, params);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Object> parseParams(List<ThingModel.Parameter> parameters, Map<?, ?> params) {
|
||||
Map<String, Object> parsed = new HashMap<>();
|
||||
parameters.forEach((p -> parseField(p.getIdentifier(), p.getDataType(), params, parsed)));
|
||||
return parsed;
|
||||
}
|
||||
|
||||
private Map<String, Object> parseProperties(List<ThingModel.Property> properties, Map<?, ?> params) {
|
||||
Map<String, Object> 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<String, Object> parsed) {
|
||||
Object val = params.get(identifier);
|
||||
if (val == null) {
|
||||
return;
|
||||
}
|
||||
Object result = dataType.parse(val);
|
||||
if (result == null) {
|
||||
return;
|
||||
}
|
||||
parsed.put(identifier, result);
|
||||
}
|
||||
|
||||
}
|
|
@ -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连接地址
|
||||
|
|
@ -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连接地址
|
|
@ -1,87 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<jmxConfigurator/>
|
||||
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
|
||||
<!-- Example for logging into the build folder of your project -->
|
||||
<property name="LOG_FILE" value="log"/>
|
||||
|
||||
<!-- You can override this to have a custom pattern -->
|
||||
<property name="CONSOLE_LOG_PATTERN"
|
||||
value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
|
||||
|
||||
<!-- Appender to log to console -->
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<!-- Minimum logging level to be presented in the console logs-->
|
||||
<level>DEBUG</level>
|
||||
</filter>
|
||||
<encoder>
|
||||
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
|
||||
<charset>utf8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- Appender to log to file -->
|
||||
<appender name="info" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_FILE}/info.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_FILE}/info.%d{yyyy-MM-dd}.%i.gz</fileNamePattern>
|
||||
<!-- 如果按天来回滚,则最大保存时间为5天,5天之前的都将被清理掉 -->
|
||||
<maxHistory>5</maxHistory>
|
||||
<!-- 日志总保存量为20GB -->
|
||||
<totalSizeCap>20GB</totalSizeCap>
|
||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<!--文件达到 最大1GB时会被压缩和切割 -->
|
||||
<maxFileSize>1GB</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
|
||||
<charset>utf8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- Appender to log to file only error level log -->
|
||||
<appender name="error" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_FILE}/error.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_FILE}/error.%d{yyyy-MM-dd}.%i.gz</fileNamePattern>
|
||||
<!-- 如果按天来回滚,则最大保存时间为5天,5天之前的都将被清理掉 -->
|
||||
<maxHistory>5</maxHistory>
|
||||
<!-- 日志总保存量为5GB -->
|
||||
<totalSizeCap>5GB</totalSizeCap>
|
||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<!--文件达到 最大1GB时会被压缩和切割 -->
|
||||
<maxFileSize>1GB</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
|
||||
<charset>utf8</charset>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter"><!-- 只打印错误日志 -->
|
||||
<level>ERROR</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<logger name="cc.iotkit" level="debug" additivity="false">
|
||||
<appender-ref ref="info"/>
|
||||
<appender-ref ref="error"/>
|
||||
<appender-ref ref="console"/>
|
||||
</logger>
|
||||
|
||||
<!-- <logger name="org.springframework" level="debug" additivity="false">-->
|
||||
<!-- <appender-ref ref="info"/>-->
|
||||
<!-- <appender-ref ref="error"/>-->
|
||||
<!-- <appender-ref ref="console"/>-->
|
||||
<!-- </logger>-->
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="info"/>
|
||||
<appender-ref ref="error"/>
|
||||
<appender-ref ref="console"/>
|
||||
</root>
|
||||
|
||||
</configuration>
|
Binary file not shown.
|
@ -12,6 +12,7 @@
|
|||
<artifactId>manager</artifactId>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-mongodb</artifactId>
|
||||
|
@ -32,11 +33,6 @@
|
|||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
|
@ -128,11 +124,6 @@
|
|||
<artifactId>common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<artifactId>device-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<artifactId>rule-engine</artifactId>
|
||||
|
@ -143,23 +134,79 @@
|
|||
<artifactId>dao</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<artifactId>component-server</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<artifactId>converter</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<!-- <build>-->
|
||||
<!-- <plugins>-->
|
||||
<!-- <plugin>-->
|
||||
<!-- <groupId>org.springframework.boot</groupId>-->
|
||||
<!-- <artifactId>spring-boot-maven-plugin</artifactId>-->
|
||||
<!-- <configuration>-->
|
||||
<!-- <excludes>-->
|
||||
<!-- <exclude>-->
|
||||
<!-- <groupId>org.projectlombok</groupId>-->
|
||||
<!-- <artifactId>lombok</artifactId>-->
|
||||
<!-- </exclude>-->
|
||||
<!-- </excludes>-->
|
||||
<!-- </configuration>-->
|
||||
<!-- </plugin>-->
|
||||
<!-- </plugins>-->
|
||||
<!-- </build>-->
|
||||
|
||||
|
||||
<build>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.0</version>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<artifactId>standalone-package</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<configuration>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>standalone-package</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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<GrantType> 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<AuthorizationScope> 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<SecurityScheme> securitySchemes = Lists.newArrayList(oAuth);
|
||||
List<SecurityContext> 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();
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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<AppDesignVo> getDesigns() {
|
||||
public Paging<AppDesignVo> getDesigns() {
|
||||
|
||||
List<AppDesignVo> appDesignVos = new ArrayList<>();
|
||||
List<Product> products = productRepository.findAll(Example
|
||||
|
@ -64,7 +64,7 @@ public class AppController {
|
|||
}
|
||||
});
|
||||
|
||||
return new PagingData<>(appDesignRepository.count(),
|
||||
return new Paging<>(appDesignRepository.count(),
|
||||
appDesignVos);
|
||||
}
|
||||
|
||||
|
|
|
@ -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<R extends MongoRepository<T, String>, T> {
|
||||
|
||||
protected final R repository;
|
||||
|
||||
public DbBaseController(R r) {
|
||||
this.repository = r;
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
public List<T> list() {
|
||||
return repository.findAll();
|
||||
}
|
||||
|
||||
@PostMapping("/save")
|
||||
public void save(T t) {
|
||||
repository.save(t);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
public void delete(T t) {
|
||||
repository.delete(t);
|
||||
}
|
||||
}
|
|
@ -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,18 +55,19 @@ 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<String, Object> args) {
|
||||
dataOwnerService.checkWriteRole();
|
||||
return deviceService.setProperty(deviceId, args);
|
||||
}
|
||||
|
||||
@PostMapping("/list")
|
||||
public PagingData<DeviceInfo> getDevices(int page,
|
||||
public Paging<DeviceInfo> getDevices(int page,
|
||||
int size,
|
||||
String pk,
|
||||
Boolean online,
|
||||
|
@ -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<Product> 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<DeviceEvent> 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<ThingModelMessage> 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<DeviceProperty> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Product> getProducts(Product form) {
|
||||
public Paging<Product> 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("."));
|
||||
|
|
|
@ -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<ProtocolComponent> 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<ProtocolComponent> optComponent = protocolComponentRepository.findById(id);
|
||||
if (!optComponent.isPresent()) {
|
||||
throw new BizException("the component does not exists");
|
||||
}
|
||||
ProtocolComponent oldComponent = optComponent.get();
|
||||
dataOwnerService.checkOwner(oldComponent);
|
||||
return oldComponent;
|
||||
}
|
||||
|
||||
@PostMapping("/deleteComponent/{id}")
|
||||
public void deleteComponent(@PathVariable("id") String id) {
|
||||
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<ProtocolComponent> getComponents(
|
||||
@PathVariable("size") int size,
|
||||
@PathVariable("page") int page) {
|
||||
Page<ProtocolComponent> components = protocolComponentRepository.findAll(
|
||||
PageRequest.of(page - 1, size, Sort.by(Sort.Order.desc("createAt"))));
|
||||
components.getContent().forEach(c -> c.setState(componentManager.isRunning(c.getId()) ?
|
||||
ProtocolComponent.STATE_RUNNING : ProtocolComponent.STATE_STOPPED));
|
||||
return new Paging<>(components.getTotalElements(), components.getContent());
|
||||
}
|
||||
|
||||
@PostMapping("/converters/{size}/{page}")
|
||||
public Paging<ProtocolConverter> getConverters(
|
||||
@PathVariable("size") int size,
|
||||
@PathVariable("page") int page) {
|
||||
protocolConverterRepository.deleteById("");
|
||||
protocolConverterRepository.deleteById("null");
|
||||
Page<ProtocolConverter> 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<ProtocolConverter> 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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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<SceneInfo> 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<SceneInfo> 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<SceneInfo> 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<SceneInfo> 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<SceneInfo> 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<SceneLog> getSceneLogs(
|
||||
@PathVariable("sceneId") String sceneId,
|
||||
@PostMapping("/rules/{type}/{size}/{page}")
|
||||
public Paging<RuleInfo> rules(
|
||||
@PathVariable("type") String type,
|
||||
@PathVariable("size") int size,
|
||||
@PathVariable("page") int page
|
||||
) {
|
||||
SceneLog sceneLog=new SceneLog();
|
||||
sceneLog.setSceneId(sceneId);
|
||||
Page<SceneLog> 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<RuleInfo> 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<RuleInfo> 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<RuleInfo> 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<RuleInfo> 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<RuleInfo> 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<RuleLog> getRuleLogs(
|
||||
@PathVariable("ruleId") String ruleId,
|
||||
@PathVariable("size") int size,
|
||||
@PathVariable("page") int page
|
||||
) {
|
||||
RuleLog ruleLog = new RuleLog();
|
||||
ruleLog.setRuleId(ruleId);
|
||||
Page<RuleLog> 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<TaskLog> taskLogs = taskLogRepository.findAll(Example.of(taskLog),
|
||||
Page<TaskLog> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<SpaceInfo> getDevices(int page,
|
||||
int limit,
|
||||
String address) {
|
||||
Criteria condition = new Criteria();
|
||||
if (StringUtils.isNotBlank(address)) {
|
||||
condition.and("address").regex(".*" + address + ".*");
|
||||
}
|
||||
List<UserInfo> userInfoList = userInfoDao.find(condition, (page - 1) * limit,
|
||||
limit, Sort.Order.desc("createAt"));
|
||||
|
||||
List<SpaceInfo> 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<SpaceInfo> getDevices(int page,
|
||||
// int limit,
|
||||
// String address) {
|
||||
// Criteria condition = new Criteria();
|
||||
// if (StringUtils.isNotBlank(address)) {
|
||||
// condition.and("address").regex(".*" + address + ".*");
|
||||
// }
|
||||
// List<UserInfo> userInfoList = userInfoDao.find(condition, (page - 1) * limit,
|
||||
// limit, Sort.Order.desc("createAt"));
|
||||
//
|
||||
// List<SpaceInfo> 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<SpaceDeviceVo> getDevices(@PathVariable("userId") String userId) {
|
||||
List<SpaceDeviceVo> deviceVos = new ArrayList<>();
|
||||
List<SpaceDevice> 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());
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue