合dev、数据流转修改

V0.5.x
xiwa 2022-04-11 08:58:53 +08:00
commit 782eba22de
208 changed files with 5019 additions and 3715 deletions

BIN
.DS_Store vendored

Binary file not shown.

2
.gitignore vendored
View File

@ -26,3 +26,5 @@ target
*.iml
*.yml
log
components
data

View File

@ -2,7 +2,7 @@ package cc.iotkit.common;
public interface Constants {
String MQTT_SECRET = "xdkKUymrEGSCYWswqCvSPyRSFvH5j7CU";
String PRODUCT_SECRET = "xdkKUymrEGSCYWswqCvSPyRSFvH5j7CU";
String ACCOUNT_SECRET = "3n1z33kzvpgz1foijpkepyd3e8tw84us";
@ -38,6 +38,11 @@ public interface Constants {
*/
String ROLE_ADMIN = "iot_admin";
/**
*
*/
String ROLE_WRITE = "iot_write";
/**
*
*/
@ -46,16 +51,26 @@ public interface Constants {
/**
* C
*/
String ROLE_CLIENT= "iot_client_user";
String ROLE_CLIENT = "iot_client_user";
/**
* C
*/
String PWD_CLIENT_USER="c123456";
String PWD_CLIENT_USER = "c123456";
/**
*
*/
String PWD_SYSTEM_USER="s123456";
String PWD_SYSTEM_USER = "s123456";
/**
* topic
*/
String DEVICE_RAW_MESSAGE_TOPIC = "device_raw";
/**
* topic
*/
String THING_MODEL_MESSAGE_TOPIC = "device_thing";
}

View File

@ -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 deviceNae16016mac1616
* 30-31 mac2
* 32 0-f
*/
public static String newDeviceId(String deviceNae) {
int maxDnLen = 16;
String dn = deviceNae.replaceAll("[^0-9A-Za-z]", "");
if (dn.length() > maxDnLen) {
dn = dn.substring(dn.length() - maxDnLen);
} else {
dn = (dn + "00000000000000000000").substring(0, maxDnLen);
}
String len = StringUtils.leftPad(deviceNae.length() + "", 2, '0');
String rnd = Integer.toHexString(RandomUtils.nextInt(0, 16));
return (System.currentTimeMillis() + "0" + dn + len + rnd).toLowerCase();
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class PkDn {
private String productKey;
private String deviceName;
}
}

View File

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

View File

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

View File

@ -15,4 +15,6 @@ public interface AligenieDeviceRepository extends MongoRepository<AligenieDevice
AligenieDevice findByUidAndDeviceId(String uid, String deviceId);
List<AligenieDevice> findByDeviceId(String deviceId);
}

View File

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

View File

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

View File

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

View File

@ -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);
}
public void updateDeviceByPkAndDn(DeviceInfo device) {
if (device.getProductKey() == null || device.getDeviceName() == null) {
return;
Query query = Query.query(new Criteria().and("deviceId").is(deviceId));
Update update = new Update();
for (String key : properties.keySet()) {
update.set("property." + key, properties.get(key));
}
mongoTemplate.updateFirst(query(where("productKey").is(device.getProductKey()).
and("deviceName").is(device.getDeviceName())),
DaoTool.update(device), DeviceInfo.class);
mongoTemplate.updateFirst(query, update, DeviceInfo.class);
}
@Cacheable(value = "deviceInfoCache", key = "#pk+'_'+#dn")
public DeviceInfo getByPkAndDn(String pk, String dn) {
Query query = query(where("productKey").is(pk).and("deviceName").is(dn));
return mongoTemplate.findOne(query, DeviceInfo.class);
/**
*
*/
public void updateTag(String deviceId, DeviceInfo.Tag tag) {
Query query = Query.query(new Criteria().and("deviceId").is(deviceId));
Update update = new Update();
update.set("tag." + tag.getId(), tag);
mongoTemplate.updateFirst(query, update, DeviceInfo.class);
}
public DeviceInfo getByDeviceId(String deviceId) {
Query query = query(where("deviceId").is(deviceId));
return mongoTemplate.findOne(query, DeviceInfo.class);
/**
*
*/
public void setTagNull(String deviceId, String tagId) {
Query query = Query.query(new Criteria().and("deviceId").is(deviceId));
Update update = new Update();
update.set("tag." + tagId, null);
mongoTemplate.updateFirst(query, update, DeviceInfo.class);
}
@Cacheable(value = Constants.DEVICE_CACHE, key = "#deviceId")
public DeviceInfo get(String deviceId) {
return deviceRepository.findById(deviceId).orElse(new DeviceInfo());
}
}

View File

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

View File

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

View File

@ -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> {
}

View File

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

View File

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

View File

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

View File

@ -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> {
}

View File

@ -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> {
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,4 +6,7 @@ import org.springframework.stereotype.Repository;
@Repository
public interface ThingModelRepository extends MongoRepository<ThingModel, String> {
ThingModel findByProductKey(String productKey);
}

View File

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

View File

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

View File

@ -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 {
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 deviceNae16016mac1616
* 30-31 mac2
* 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();
}
}

View File

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

View File

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

View File

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

View File

@ -1,5 +0,0 @@
spring:
data:
mongodb:
uri: mongodb://填写mongodb地址/admin
database: iotkit

View File

@ -1,5 +0,0 @@
spring:
data:
mongodb:
uri: mongodb://填写mongodb地址/admin
database: iotkit

View File

@ -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>

View File

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

View File

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

View File

@ -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.

View File

@ -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>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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> {
}

View File

@ -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> {
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 deviceNae16016mac1616
* 30-31 mac2
* 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;
}
}

View File

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

View File

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

View File

@ -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连接地址

View File

@ -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连接地址

View File

@ -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>

BIN
manager/.DS_Store vendored

Binary file not shown.

View File

@ -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>-->
<!-- <configuration>-->
<!-- <excludes>-->
<!-- <exclude>-->
<!-- <groupId>org.projectlombok</groupId>-->
<!-- <artifactId>lombok</artifactId>-->
<!-- </exclude>-->
<!-- </excludes>-->
<!-- </configuration>-->
<!-- </plugin>-->
<!-- </plugins>-->
<!-- </build>-->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<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>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,26 +1,28 @@
package cc.iotkit.manager.controller;
import cc.iotkit.dao.DeviceDao;
import cc.iotkit.dao.DeviceEventDao;
import cc.iotkit.dao.DeviceEventRepository;
import cc.iotkit.dao.DeviceRepository;
import cc.iotkit.common.exception.BizException;
import cc.iotkit.common.utils.DeviceUtil;
import cc.iotkit.dao.*;
import cc.iotkit.manager.service.DataOwnerService;
import cc.iotkit.manager.service.DeviceService;
import cc.iotkit.manager.utils.AuthUtil;
import cc.iotkit.model.device.message.DeviceEvent;
import cc.iotkit.model.Paging;
import cc.iotkit.model.device.DeviceInfo;
import cc.iotkit.model.PagingData;
import cc.iotkit.model.device.message.DeviceProperty;
import cc.iotkit.model.device.message.ThingModelMessage;
import cc.iotkit.model.product.Product;
import cc.iotkit.model.product.ThingModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@Slf4j
@RestController
@ -32,15 +34,19 @@ public class DeviceController {
@Autowired
private DeviceRepository deviceRepository;
@Autowired
private DeviceEventRepository deviceEventRepository;
@Autowired
private DeviceEventDao deviceEventDao;
private ProductRepository productRepository;
@Autowired
private DeviceDao deviceDao;
@Autowired
private DataOwnerService dataOwnerService;
@Autowired
private ProductController productController;
@Lazy
@Autowired
private ThingModelMessageDao thingModelMessageDao;
@Lazy
@Autowired
private DevicePropertyDao devicePropertyDao;
@PostMapping("/{deviceId}/service/{service}")
public String invokeService(@PathVariable("deviceId") String deviceId,
@ -49,22 +55,23 @@ public class DeviceController {
if (StringUtils.isBlank(deviceId) || StringUtils.isBlank(service)) {
throw new RuntimeException("deviceId/service is blank.");
}
dataOwnerService.checkWriteRole();
return deviceService.invokeService(deviceId, service, args);
}
@PostMapping("/{deviceId}/service/property/set")
public String setProperty(@PathVariable("deviceId") String deviceId,
@RequestBody Map<String, Object> args) {
dataOwnerService.checkWriteRole();
return deviceService.setProperty(deviceId, args);
}
@PostMapping("/list")
public PagingData<DeviceInfo> getDevices(int page,
int size,
String pk,
Boolean online,
String dn) {
public Paging<DeviceInfo> getDevices(int page,
int size,
String pk,
Boolean online,
String dn) {
Criteria condition = new Criteria();
if (!AuthUtil.isAdmin()) {
condition.and("uid").is(AuthUtil.getUserId());
@ -78,8 +85,27 @@ public class DeviceController {
if (online != null) {
condition.and("state.online").is(online);
}
return new PagingData<>(deviceDao.count(condition),
deviceDao.find(condition, (page - 1) * size, size, Sort.Order.desc("createAt")));
return deviceDao.find(condition, size, page);
}
@PostMapping("/create")
public void createDevice(String productKey, String deviceName) {
Optional<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);
}
}

View File

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

View File

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

View File

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

View File

@ -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