Merge remote-tracking branch 'origin/dev' into dev
commit
e956fa4a6a
12
README.md
12
README.md
|
@ -4,12 +4,14 @@
|
|||
此仓库为奇特物联(iotkit)物联网平台开源项目。
|
||||
奇特物联是一个开源的物联网基础开发平台,提供了物联网及相关业务开发的常见基础功能, 能帮助你快速搭建自己的物联网相关业务平台。
|
||||
|
||||
系统包含了品类、物模型、消息转换、通讯组件、设备管理、规则引擎、数据流转、数据可视化、报警中心等模块。
|
||||
系统包含了品类、物模型、消息转换、通讯组件(mqtt通讯组件、小度音箱接入组件、onenet Studio接入组件)、云端低代码设备开发、设备管理、规则引擎、第三方平台接入、数据流转、数据可视化、报警中心等模块和智能家居APP(小程序)。
|
||||
|
||||
**前端项目见:** https://gitee.com/iotkit-open-source/iot-console-web
|
||||
|
||||
**演示地址:** [演示地址](http://120.76.96.206),账号:guest1,密码:guest123 (只读权限)
|
||||
|
||||
**智能家居小程序:** https://gitee.com/iotkit-open-source/iot-mp-home
|
||||
|
||||
|
||||
#### 软件架构
|
||||
软件架构说明
|
||||
|
@ -19,14 +21,13 @@
|
|||
#### 安装教程
|
||||
|
||||
见:https://ztktkv.yuque.com/docs/share/b32da919-0108-4112-9406-fe5c6672e0d7?# 《安装和配置》
|
||||
链接有效期至 2022-04-08 20:20:01
|
||||
|
||||
#### 使用说明
|
||||
|
||||
1. 技术文档
|
||||
邀你加入「iot平台技术文档」知识库: https://ztktkv.yuque.com/g/ztktkv/gb3v6g/collaborator/join?token=zz5PUmXzGQqc4h9t# (只读成员)
|
||||
邀你加入「iot平台技术文档」知识库: https://ztktkv.yuque.com/g/ztktkv/gb3v6g/collaborator/join?token=zz5PUmXzGQqc4h9t#
|
||||
|
||||
**这是我宝贵的技术文档分享,看完后请帮忙给本仓库点个star。 :sparkles:**
|
||||
**这是我宝贵的技术文档分享,请给本仓库点个star :sparkles: 支持一下,谢谢!**
|
||||
2. 系统操作文档
|
||||
|
||||
#### 待办事项
|
||||
|
@ -52,4 +53,5 @@
|
|||
|
||||
微信群:
|
||||
|
||||
![输入图片说明](doc/ma.png)
|
||||
![输入图片说明](doc/ma.png)
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package cc.iotkit.common;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
public interface Constants {
|
||||
|
||||
String PRODUCT_SECRET = "xdkKUymrEGSCYWswqCvSPyRSFvH5j7CU";
|
||||
|
@ -10,6 +12,10 @@ public interface Constants {
|
|||
|
||||
String DEVICE_CACHE = "device_cache";
|
||||
|
||||
String CATEGORY_CACHE = "category_cache";
|
||||
|
||||
String SPACE_CACHE = "space_cache";
|
||||
|
||||
String THING_MODEL_CACHE = "thing_model_cache";
|
||||
|
||||
String WECHAT_APP_ID = "wx791cb7bf75950e0c";
|
||||
|
@ -18,20 +24,7 @@ public interface Constants {
|
|||
|
||||
String APP_DESIGN_CACHE = "app_design_cache";
|
||||
|
||||
/**
|
||||
* 天猫精灵平台
|
||||
*/
|
||||
String PLATFORM_ALIGENIE = "aligenie";
|
||||
|
||||
/**
|
||||
* topic前缀第三方接入网关
|
||||
*/
|
||||
String TOPIC_PREFIX_GATEWAY = "gateway";
|
||||
|
||||
/**
|
||||
* topic前缀APP
|
||||
*/
|
||||
String TOPIC_PREFIX_APP = "app";
|
||||
String PRODUCT_SCRIPT_CACHE = "product_script_cache";
|
||||
|
||||
/**
|
||||
* 管理员角色
|
||||
|
@ -63,44 +56,101 @@ public interface Constants {
|
|||
*/
|
||||
String PWD_SYSTEM_USER = "s123456";
|
||||
|
||||
/**
|
||||
* 设备原始上报消息的topic
|
||||
*/
|
||||
String DEVICE_RAW_MESSAGE_TOPIC = "device_raw";
|
||||
|
||||
/**
|
||||
* 设备物模型消息的topic
|
||||
*/
|
||||
String THING_MODEL_MESSAGE_TOPIC = "device_thing";
|
||||
|
||||
/**
|
||||
* http消费设备信息的topic
|
||||
*/
|
||||
String HTTP_CONSUMER_DEVICE_INFO_TOPIC = "device_info:";
|
||||
|
||||
interface API {
|
||||
/**
|
||||
* 三方平台类型
|
||||
*/
|
||||
enum ThirdPlatform {
|
||||
dueros("小度"),
|
||||
aligenie("天猫精灵"),
|
||||
miiot("小爱");
|
||||
|
||||
public String desc;
|
||||
|
||||
ThirdPlatform(String desc) {
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface API_DEVICE {
|
||||
|
||||
/**
|
||||
* 设备-基路径
|
||||
*/
|
||||
String DEVICE_BASE = "/device";
|
||||
String BASE = "/device";
|
||||
|
||||
/**
|
||||
* 设备-设备列表
|
||||
*/
|
||||
String DEVICE_LIST = "/list/{size}/{page}";
|
||||
String LIST = "/list/{size}/{page}";
|
||||
|
||||
/**
|
||||
* 设备-设备详情
|
||||
*/
|
||||
String DEVICE_DETAIL = "/{deviceId}/detail";
|
||||
String DETAIL = "/{deviceId}/detail";
|
||||
|
||||
/**
|
||||
* 设备-属性设置
|
||||
*/
|
||||
String DEVICE_SET_PROPERTIES = "/{deviceId}/service/property/set";
|
||||
String SET_PROPERTIES = "/{deviceId}/service/property/set";
|
||||
|
||||
/**
|
||||
* 设备-服务调用
|
||||
*/
|
||||
String DEVICE_INVOKE_SERVICE = "/{deviceId}/service/{service}/invoke";
|
||||
String INVOKE_SERVICE = "/{deviceId}/service/{service}/invoke";
|
||||
|
||||
}
|
||||
|
||||
interface API_SPACE {
|
||||
|
||||
/**
|
||||
* 空间-基路径
|
||||
*/
|
||||
String BASE = "/space";
|
||||
|
||||
/**
|
||||
* 最近使用设备列表
|
||||
*/
|
||||
String RECENT_DEVICES = "/myRecentDevices";
|
||||
|
||||
/**
|
||||
* 我的空间设备列表
|
||||
*/
|
||||
String SPACE_DEVICES = "/myDevices/{spaceId}";
|
||||
|
||||
/**
|
||||
* 查找设备
|
||||
*/
|
||||
String FIND_DEVICE = "/findDevice";
|
||||
|
||||
/**
|
||||
* 空间添加设备
|
||||
*/
|
||||
String ADD_DEVICE = "/addDevice";
|
||||
|
||||
/**
|
||||
* 空间删除设备
|
||||
*/
|
||||
String REMOVE_DEVICE = "/removeDevice";
|
||||
|
||||
/**
|
||||
* 空间修改设备
|
||||
*/
|
||||
String SAVE_DEVICE = "/saveDevice";
|
||||
|
||||
/**
|
||||
* 获取空间设备信息
|
||||
*/
|
||||
String GET_DEVICE = "/device/{deviceId}";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package cc.iotkit.common.utils;
|
|||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import sun.misc.BASE64Decoder;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyGenerator;
|
||||
|
@ -30,7 +29,7 @@ public class CodecUtil {
|
|||
* @throws Exception 抛出异常
|
||||
*/
|
||||
private static byte[] base64Decode(String base64Code) throws Exception {
|
||||
return StringUtils.isEmpty(base64Code) ? null : new BASE64Decoder().decodeBuffer(base64Code);
|
||||
return StringUtils.isEmpty(base64Code) ? null : new Base64().decode(base64Code);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ public final class JsonUtil {
|
|||
|
||||
public static Object toObject(ScriptObjectMirror mirror) {
|
||||
if (mirror.isEmpty()) {
|
||||
return null;
|
||||
return new Object();
|
||||
}
|
||||
if (mirror.isArray()) {
|
||||
List<Object> list = new ArrayList<>();
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package cc.iotkit.dao;
|
||||
|
||||
import cc.iotkit.common.Constants;
|
||||
import cc.iotkit.model.product.Category;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
@Repository
|
||||
public class CategoryCache {
|
||||
|
||||
@Autowired
|
||||
private CategoryRepository categoryRepository;
|
||||
|
||||
private static CategoryCache INSTANCE;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
INSTANCE = this;
|
||||
}
|
||||
|
||||
public static CategoryCache getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Cacheable(value = Constants.CATEGORY_CACHE, key = "#id")
|
||||
public Category getById(String id) {
|
||||
return categoryRepository.findById(id).orElse(null);
|
||||
}
|
||||
}
|
|
@ -6,24 +6,33 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
@Repository
|
||||
public class DeviceCache {
|
||||
|
||||
@Autowired
|
||||
private DeviceRepository deviceRepository;
|
||||
|
||||
private static DeviceCache INSTANCE;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
INSTANCE = this;
|
||||
}
|
||||
|
||||
public static DeviceCache getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Cacheable(value = Constants.DEVICE_CACHE, key = "#pk+'_'+#dn")
|
||||
public DeviceInfo findByProductKeyAndDeviceName(String pk, String dn) {
|
||||
public DeviceInfo getDeviceInfo(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);
|
||||
public DeviceInfo get(String deviceId) {
|
||||
return deviceRepository.findById(deviceId).orElse(null);
|
||||
}
|
||||
|
||||
@Cacheable(value = Constants.DEVICE_CACHE, key = "#deviceId")
|
||||
public DeviceInfo get(String deviceId) {
|
||||
return deviceRepository.findById(deviceId).orElse(new DeviceInfo());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,4 +15,6 @@ public interface DeviceRepository extends MongoRepository<DeviceInfo, String> {
|
|||
|
||||
List<DeviceInfo> findByParentId(String parentId);
|
||||
|
||||
List<DeviceInfo> findByDeviceName(String deviceName);
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,12 @@ import cc.iotkit.model.space.Home;
|
|||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface HomeRepository extends MongoRepository<Home, String> {
|
||||
|
||||
List<Home> findByUid(String uid);
|
||||
|
||||
Home findByUidAndCurrent(String uid,boolean current);
|
||||
}
|
||||
|
|
|
@ -2,11 +2,14 @@ package cc.iotkit.dao;
|
|||
|
||||
import cc.iotkit.common.Constants;
|
||||
import cc.iotkit.model.product.Product;
|
||||
import cc.iotkit.model.product.ProductModel;
|
||||
import cc.iotkit.model.product.ThingModel;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
@Repository
|
||||
public class ProductCache {
|
||||
|
||||
|
@ -14,14 +17,34 @@ public class ProductCache {
|
|||
private ProductRepository productRepository;
|
||||
@Autowired
|
||||
private ThingModelRepository thingModelRepository;
|
||||
@Autowired
|
||||
private ProductModelRepository productModelRepository;
|
||||
|
||||
@Cacheable(value = Constants.PRODUCT_CACHE, key = "'pk'+#pk", unless = "#result == null")
|
||||
private static ProductCache INSTANCE;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
INSTANCE = this;
|
||||
}
|
||||
|
||||
public static ProductCache getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Cacheable(value = Constants.PRODUCT_CACHE, key = "'product'+#pk")
|
||||
public Product findById(String pk) {
|
||||
return productRepository.findById(pk).orElse(new Product());
|
||||
}
|
||||
|
||||
@Cacheable(value = Constants.THING_MODEL_CACHE, key = "'pk'+#pk", unless = "#result == null")
|
||||
@Cacheable(value = Constants.THING_MODEL_CACHE, key = "'thing_model'+#pk")
|
||||
public ThingModel getThingModel(String pk) {
|
||||
return thingModelRepository.findByProductKey(pk);
|
||||
}
|
||||
|
||||
@Cacheable(value = Constants.PRODUCT_SCRIPT_CACHE, key = "'product_script'+#model")
|
||||
public ProductModel getProductScriptByModel(String model) {
|
||||
return productModelRepository.findByModel(model);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package cc.iotkit.dao;
|
||||
|
||||
import cc.iotkit.model.product.ProductModel;
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface ProductModelRepository extends MongoRepository<ProductModel, String> {
|
||||
|
||||
ProductModel findByModel(String model);
|
||||
|
||||
List<ProductModel> findByProductKey(String productKey);
|
||||
|
||||
}
|
|
@ -6,4 +6,7 @@ import org.springframework.stereotype.Repository;
|
|||
|
||||
@Repository
|
||||
public interface ProductRepository extends MongoRepository<Product, String> {
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
package cc.iotkit.dao;
|
||||
|
||||
import cc.iotkit.common.Constants;
|
||||
import cc.iotkit.model.space.Space;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
@Repository
|
||||
public class SpaceCache {
|
||||
|
||||
@Autowired
|
||||
private SpaceRepository spaceRepository;
|
||||
|
||||
private static SpaceCache INSTANCE;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
INSTANCE = this;
|
||||
}
|
||||
|
||||
public static SpaceCache getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Cacheable(value = Constants.SPACE_CACHE, key = "#spaceId")
|
||||
public Space getSpace(String spaceId) {
|
||||
return spaceRepository.findById(spaceId).orElse(null);
|
||||
}
|
||||
|
||||
}
|
|
@ -4,6 +4,18 @@ import cc.iotkit.model.space.SpaceDevice;
|
|||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface SpaceDeviceRepository extends MongoRepository<SpaceDevice, String> {
|
||||
|
||||
List<SpaceDevice> findByUidOrderByUseAtDesc(String uid);
|
||||
|
||||
List<SpaceDevice> findByUidOrderByAddAtDesc(String uid);
|
||||
|
||||
List<SpaceDevice> findByUidAndSpaceIdOrderByAddAtDesc(String uid, String spaceId);
|
||||
|
||||
SpaceDevice findByDeviceId(String deviceId);
|
||||
|
||||
SpaceDevice findByDeviceIdAndUid(String deviceId, String uid);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,13 @@ import cc.iotkit.model.space.Space;
|
|||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface SpaceRepository extends MongoRepository<Space, String> {
|
||||
|
||||
List<Space> findByUidOrderByCreateAtDesc(String uid);
|
||||
|
||||
List<Space> findByUidAndHomeIdOrderByCreateAtDesc(String uid, String homeId);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package cc.iotkit.dao;
|
||||
|
||||
import cc.iotkit.model.UserAccount;
|
||||
import cc.iotkit.model.ThirdUserSession;
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface UserAccountRepository extends MongoRepository<UserAccount, String> {
|
||||
public interface ThirdUserSessionRepository extends MongoRepository<ThirdUserSession, String> {
|
||||
|
||||
|
||||
}
|
BIN
doc/ma.png
BIN
doc/ma.png
Binary file not shown.
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 73 KiB |
Binary file not shown.
|
@ -172,8 +172,8 @@
|
|||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.0</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<source>11</source>
|
||||
<target>11</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
package cc.iotkit.manager.config;
|
||||
|
||||
import cc.iotkit.common.Constants;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.cache.caffeine.CaffeineCache;
|
||||
import org.springframework.cache.support.SimpleCacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
//@Configuration
|
||||
//@EnableCaching
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
public class CacheConfig {
|
||||
|
||||
/**
|
||||
|
@ -20,23 +23,46 @@ public class CacheConfig {
|
|||
public CacheManager cacheManager() {
|
||||
SimpleCacheManager manager = new SimpleCacheManager();
|
||||
manager.setCaches(Lists.newArrayList(new CaffeineCache(
|
||||
"device_cache",
|
||||
Constants.DEVICE_CACHE,
|
||||
Caffeine.newBuilder()
|
||||
.expireAfterWrite(5, TimeUnit.MINUTES)
|
||||
.build()
|
||||
),
|
||||
new CaffeineCache(
|
||||
"product_cache",
|
||||
Constants.PRODUCT_CACHE,
|
||||
Caffeine.newBuilder()
|
||||
.expireAfterWrite(5, TimeUnit.MINUTES)
|
||||
.build()
|
||||
),
|
||||
new CaffeineCache(
|
||||
"app_design_cache",
|
||||
Constants.APP_DESIGN_CACHE,
|
||||
Caffeine.newBuilder()
|
||||
.expireAfterWrite(5, TimeUnit.MINUTES)
|
||||
.build()
|
||||
)));
|
||||
),
|
||||
new CaffeineCache(
|
||||
Constants.THING_MODEL_CACHE,
|
||||
Caffeine.newBuilder()
|
||||
.expireAfterWrite(5, TimeUnit.MINUTES)
|
||||
.build()
|
||||
),
|
||||
new CaffeineCache(
|
||||
Constants.PRODUCT_SCRIPT_CACHE,
|
||||
Caffeine.newBuilder()
|
||||
.expireAfterWrite(5, TimeUnit.MINUTES)
|
||||
.build()
|
||||
), new CaffeineCache(
|
||||
Constants.SPACE_CACHE,
|
||||
Caffeine.newBuilder()
|
||||
.expireAfterWrite(5, TimeUnit.MINUTES)
|
||||
.build()
|
||||
), new CaffeineCache(
|
||||
Constants.CATEGORY_CACHE,
|
||||
Caffeine.newBuilder()
|
||||
.expireAfterWrite(5, TimeUnit.MINUTES)
|
||||
.build()
|
||||
)
|
||||
));
|
||||
return manager;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
|
@ -53,14 +54,38 @@ public class KeycloakSecurityConfig extends KeycloakWebSecurityConfigurerAdapter
|
|||
super.configure(http);
|
||||
http
|
||||
.authorizeRequests()
|
||||
.antMatchers("/*.html", "/favicon.ico","/v2/api-docs", "/webjars/**", "/swagger-resources/**", "/*.js").permitAll()
|
||||
.antMatchers("/*.html", "/favicon.ico", "/v2/api-docs", "/webjars/**", "/swagger-resources/**", "/*.js").permitAll()
|
||||
.antMatchers("/api/**").hasRole("iot_client_user")
|
||||
.antMatchers("/aligenieDevice/invoke/**").hasRole("iot_client_user")
|
||||
//客户端用户写权限
|
||||
.antMatchers("/space/addSpace/**").hasAnyRole("iot_write","iot_client_user")
|
||||
.antMatchers("/space/saveSpace/**").hasAnyRole("iot_write","iot_client_user")
|
||||
.antMatchers("/space/delSpace/**").hasAnyRole("iot_write","iot_client_user")
|
||||
.antMatchers("/space/saveHome/**").hasAnyRole("iot_write","iot_client_user")
|
||||
.antMatchers("/space/currentHome/**").hasAnyRole("iot_write","iot_client_user")
|
||||
.antMatchers("/space/myRecentDevices/**").hasAnyRole("iot_write","iot_client_user")
|
||||
.antMatchers("/space/spaces/**").hasAnyRole("iot_write","iot_client_user")
|
||||
.antMatchers("/space/myDevices/**").hasAnyRole("iot_write","iot_client_user")
|
||||
.antMatchers("/space/findDevice/**").hasAnyRole("iot_write","iot_client_user")
|
||||
.antMatchers("/space/addDevice/**").hasAnyRole("iot_write","iot_client_user")
|
||||
.antMatchers("/space/saveDevice").hasAnyRole("iot_write","iot_client_user")
|
||||
.antMatchers("/space/removeDevice").hasAnyRole("iot_write","iot_client_user")
|
||||
.antMatchers("/space/device/*").hasAnyRole("iot_write","iot_client_user")
|
||||
.antMatchers("/device/*/consumer/*").hasAnyRole("iot_write","iot_client_user")
|
||||
.antMatchers("/device/*/service/property/set").hasAnyRole("iot_write","iot_client_user")
|
||||
.antMatchers("/device/*/service/*/invoke").hasAnyRole("iot_write","iot_client_user")
|
||||
|
||||
|
||||
.antMatchers(HttpMethod.DELETE).hasRole("iot_write")
|
||||
.antMatchers(HttpMethod.PUT).hasRole("iot_write")
|
||||
.antMatchers("/**/save*/**").hasRole("iot_write")
|
||||
.antMatchers("/**/remove*/**").hasRole("iot_write")
|
||||
.antMatchers("/**/del*/**").hasRole("iot_write")
|
||||
.antMatchers("/**/add*/**").hasRole("iot_write")
|
||||
.antMatchers("/**/clear*/**").hasRole("iot_write")
|
||||
.antMatchers("/**/set*/**").hasRole("iot_write")
|
||||
.antMatchers("/**/set").hasRole("iot_write")
|
||||
.antMatchers("/**/invoke").hasRole("iot_write")
|
||||
.antMatchers("/**").hasAnyRole(systemRole)
|
||||
.and().csrf().disable();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
package cc.iotkit.manager.config;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Map;
|
||||
|
||||
@ControllerAdvice
|
||||
public class ResponseResultHandler implements ResponseBodyAdvice<Object> {
|
||||
@Override
|
||||
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
|
||||
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
|
||||
String wrapResponse = request.getHeader("wrap-response");
|
||||
return "json".equals(wrapResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object beforeBodyWrite(Object body, MethodParameter returnType,
|
||||
MediaType selectedContentType,
|
||||
Class<? extends HttpMessageConverter<?>> selectedConverterType,
|
||||
ServerHttpRequest request, ServerHttpResponse response) {
|
||||
if (body instanceof GlobalExceptionHandler.RequestResult) {
|
||||
GlobalExceptionHandler.RequestResult requestResult = (GlobalExceptionHandler.RequestResult) body;
|
||||
return new ApiResponse(Integer.parseInt(requestResult.getCode()), requestResult.getMessage(),
|
||||
"", System.currentTimeMillis());
|
||||
} else if (body instanceof Map) {
|
||||
Map map = (Map) body;
|
||||
//spring mvc内部异常
|
||||
if (map.containsKey("timestamp") && map.containsKey("status") && map.containsKey("error")) {
|
||||
return new ApiResponse((Integer) map.get("status"), (String) map.get("error"),
|
||||
"", System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
|
||||
return new ApiResponse(200, "", body, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class ApiResponse {
|
||||
private int status;
|
||||
private String message;
|
||||
private Object data;
|
||||
private long timestamp;
|
||||
}
|
||||
}
|
|
@ -8,8 +8,10 @@ import cc.iotkit.comps.service.DeviceBehaviourService;
|
|||
import cc.iotkit.dao.*;
|
||||
import cc.iotkit.manager.model.query.DeviceQuery;
|
||||
import cc.iotkit.manager.service.DataOwnerService;
|
||||
import cc.iotkit.manager.service.DeferredDataConsumer;
|
||||
import cc.iotkit.manager.service.DeviceService;
|
||||
import cc.iotkit.manager.utils.AuthUtil;
|
||||
import cc.iotkit.model.InvokeResult;
|
||||
import cc.iotkit.model.Paging;
|
||||
import cc.iotkit.model.device.DeviceInfo;
|
||||
import cc.iotkit.model.device.message.DeviceProperty;
|
||||
|
@ -23,6 +25,7 @@ import org.springframework.context.annotation.Lazy;
|
|||
import org.springframework.data.domain.Example;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.context.request.async.DeferredResult;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -53,46 +56,23 @@ public class DeviceController {
|
|||
private DevicePropertyDao devicePropertyDao;
|
||||
@Autowired
|
||||
private DeviceBehaviourService behaviourService;
|
||||
@Autowired
|
||||
DeferredDataConsumer deferredDataConsumer;
|
||||
|
||||
@PostMapping(Constants.API.DEVICE_INVOKE_SERVICE)
|
||||
public String invokeService(@PathVariable("deviceId") String deviceId,
|
||||
@PathVariable("service") String service,
|
||||
@RequestBody Map<String, Object> args) {
|
||||
@PostMapping(Constants.API_DEVICE.INVOKE_SERVICE)
|
||||
public InvokeResult invokeService(@PathVariable("deviceId") String deviceId,
|
||||
@PathVariable("service") String service,
|
||||
@RequestBody Map<String, Object> args) {
|
||||
if (StringUtils.isBlank(deviceId) || StringUtils.isBlank(service)) {
|
||||
throw new RuntimeException("deviceId/service is blank.");
|
||||
}
|
||||
dataOwnerService.checkWriteRole();
|
||||
return deviceService.invokeService(deviceId, service, args);
|
||||
return new InvokeResult(deviceService.invokeService(deviceId, service, args));
|
||||
}
|
||||
|
||||
@PostMapping(Constants.API.DEVICE_SET_PROPERTIES)
|
||||
public String setProperty(@PathVariable("deviceId") String deviceId,
|
||||
@RequestBody Map<String, Object> args) {
|
||||
dataOwnerService.checkWriteRole();
|
||||
return deviceService.setProperty(deviceId, args);
|
||||
}
|
||||
|
||||
@PostMapping("/list")
|
||||
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());
|
||||
}
|
||||
if (StringUtils.isNotBlank(pk)) {
|
||||
condition.and("productKey").is(pk);
|
||||
}
|
||||
if (StringUtils.isNotBlank(dn)) {
|
||||
condition.and("deviceName").regex(".*" + dn + ".*");
|
||||
}
|
||||
if (online != null) {
|
||||
condition.and("state.online").is(online);
|
||||
}
|
||||
|
||||
return deviceDao.find(condition, size, page);
|
||||
@PostMapping(Constants.API_DEVICE.SET_PROPERTIES)
|
||||
public InvokeResult setProperty(@PathVariable("deviceId") String deviceId,
|
||||
@RequestBody Map<String, Object> args) {
|
||||
return new InvokeResult(deviceService.setProperty(deviceId, args));
|
||||
}
|
||||
|
||||
@PostMapping("/list/{size}/{page}")
|
||||
|
@ -121,8 +101,8 @@ public class DeviceController {
|
|||
condition.and("deviceName").regex(".*" + dn + ".*");
|
||||
}
|
||||
String state = query.getState();
|
||||
if (state != null) {
|
||||
condition.and("state.online").is(state);
|
||||
if (StringUtils.isNotBlank(state)) {
|
||||
condition.and("state.online").is(state.equals("online"));
|
||||
}
|
||||
|
||||
return deviceDao.find(condition, size, page);
|
||||
|
@ -156,7 +136,7 @@ public class DeviceController {
|
|||
.build())));
|
||||
}
|
||||
|
||||
@GetMapping(Constants.API.DEVICE_DETAIL)
|
||||
@GetMapping(Constants.API_DEVICE.DETAIL)
|
||||
public DeviceInfo getDetail(@PathVariable("deviceId") String deviceId) {
|
||||
return dataOwnerService.checkOwner(deviceRepository.findById(deviceId).orElse(new DeviceInfo()));
|
||||
}
|
||||
|
@ -227,4 +207,21 @@ public class DeviceController {
|
|||
message.setTime(System.currentTimeMillis());
|
||||
behaviourService.reportMessage(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 消费设备信息消息(实时推送设备信息)
|
||||
*/
|
||||
@GetMapping("/{deviceId}/consumer/{clientId}")
|
||||
public DeferredResult<ThingModelMessage> consumerDeviceInfo(
|
||||
@PathVariable("deviceId") String deviceId,
|
||||
@PathVariable("clientId") String clientId
|
||||
) {
|
||||
String uid = AuthUtil.getUserId();
|
||||
DeviceInfo deviceInfo = deviceRepository.findByDeviceId(deviceId);
|
||||
dataOwnerService.checkOwner(deviceInfo);
|
||||
|
||||
//按用户+客户端ID订阅
|
||||
return deferredDataConsumer.newConsumer(uid + clientId,
|
||||
Constants.HTTP_CONSUMER_DEVICE_INFO_TOPIC + deviceId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
package cc.iotkit.manager.controller;
|
||||
|
||||
import cc.iotkit.common.exception.BizException;
|
||||
import cc.iotkit.common.utils.JsonUtil;
|
||||
import cc.iotkit.dao.CategoryRepository;
|
||||
import cc.iotkit.dao.ProductRepository;
|
||||
import cc.iotkit.dao.ProductModelRepository;
|
||||
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.product.Product;
|
||||
import cc.iotkit.model.product.ProductModel;
|
||||
import cc.iotkit.model.product.ThingModel;
|
||||
import com.aliyun.oss.OSS;
|
||||
import com.aliyun.oss.OSSClientBuilder;
|
||||
|
@ -17,12 +20,16 @@ import lombok.SneakyThrows;
|
|||
import lombok.extern.slf4j.Slf4j;
|
||||
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.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
|
@ -39,13 +46,21 @@ public class ProductController {
|
|||
private DataOwnerService dataOwnerService;
|
||||
@Autowired
|
||||
private AliyunConfig aliyunConfig;
|
||||
@Autowired
|
||||
private ProductModelRepository productModelRepository;
|
||||
|
||||
private OSS ossClient;
|
||||
|
||||
@PostMapping("/list")
|
||||
public Paging<Product> getProducts(Product form) {
|
||||
@PostMapping("/list/{size}/{page}")
|
||||
public Paging<Product> getProducts(
|
||||
@PathVariable("size") int size,
|
||||
@PathVariable("page") int page,
|
||||
Product form) {
|
||||
form = dataOwnerService.wrapExample(form);
|
||||
return new Paging<>(productRepository.count(Example.of(form)),
|
||||
productRepository.findAll(Example.of(form)));
|
||||
Page<Product> products = productRepository.findAll(Example.of(form),
|
||||
PageRequest.of(page - 1, size, Sort.by(Sort.Order.desc("createAt")))
|
||||
);
|
||||
return new Paging<>(products.getTotalElements(), products.getContent());
|
||||
}
|
||||
|
||||
@PostMapping("/save")
|
||||
|
@ -121,4 +136,29 @@ public class ProductController {
|
|||
return ossClient.generatePresignedUrl(bucket, fileName,
|
||||
new Date(new Date().getTime() + 3600L * 1000 * 24 * 365 * 10)).toString();
|
||||
}
|
||||
|
||||
@GetMapping("/{productKey}/models")
|
||||
public List<ProductModel> getModels(@PathVariable("productKey") String productKey) {
|
||||
dataOwnerService.checkOwner(productRepository, productKey);
|
||||
return productModelRepository.findByProductKey(productKey);
|
||||
}
|
||||
|
||||
@PostMapping("/saveProductModel")
|
||||
public void saveProductModel(ProductModel productModel) {
|
||||
String model = productModel.getModel();
|
||||
String productKey = productModel.getProductKey();
|
||||
Optional<Product> optProduct = productRepository.findById(productKey);
|
||||
if (!optProduct.isPresent()) {
|
||||
throw new BizException("product does not exist");
|
||||
}
|
||||
dataOwnerService.checkOwner(optProduct.get());
|
||||
|
||||
ProductModel oldScript = productModelRepository.findByModel(model);
|
||||
if (oldScript != null && !oldScript.getProductKey().equals(productKey)) {
|
||||
throw new BizException("model already exists");
|
||||
}
|
||||
|
||||
productModel.setModifyAt(System.currentTimeMillis());
|
||||
productModelRepository.save(productModel);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package cc.iotkit.manager.controller;
|
|||
import cc.iotkit.common.exception.BizException;
|
||||
import cc.iotkit.common.utils.JsonUtil;
|
||||
import cc.iotkit.common.utils.ReflectUtil;
|
||||
import cc.iotkit.comps.DeviceComponentManager;
|
||||
import cc.iotkit.comps.ComponentManager;
|
||||
import cc.iotkit.comps.config.ComponentConfig;
|
||||
import cc.iotkit.dao.ProtocolComponentRepository;
|
||||
import cc.iotkit.dao.ProtocolConverterRepository;
|
||||
|
@ -50,7 +50,7 @@ public class ProtocolController {
|
|||
private UserInfoRepository userInfoRepository;
|
||||
|
||||
@Autowired
|
||||
private DeviceComponentManager deviceComponentManager;
|
||||
private ComponentManager componentManager;
|
||||
|
||||
@PostMapping("/uploadJar")
|
||||
public String uploadJar(@RequestParam("file") MultipartFile file, String id) {
|
||||
|
@ -112,8 +112,9 @@ public class ProtocolController {
|
|||
|
||||
ProtocolComponent oldComponent = getAndCheckComponent(id);
|
||||
component = ReflectUtil.copyNoNulls(component, oldComponent);
|
||||
|
||||
try {
|
||||
deviceComponentManager.deRegister(id);
|
||||
componentManager.deRegister(id);
|
||||
protocolComponentRepository.save(component);
|
||||
} catch (Throwable e) {
|
||||
throw new BizException("add protocol component error", e);
|
||||
|
@ -144,7 +145,7 @@ public class ProtocolController {
|
|||
script = JsonUtil.parse(script, String.class);
|
||||
FileUtils.writeStringToFile(file, script, "UTF-8", false);
|
||||
|
||||
deviceComponentManager.deRegister(id);
|
||||
componentManager.deRegister(id);
|
||||
} catch (Throwable e) {
|
||||
throw new BizException("save protocol component script error", e);
|
||||
}
|
||||
|
@ -164,7 +165,7 @@ public class ProtocolController {
|
|||
public void deleteComponent(@PathVariable("id") String id) {
|
||||
ProtocolComponent component = getAndCheckComponent(id);
|
||||
try {
|
||||
deviceComponentManager.deRegister(id);
|
||||
componentManager.deRegister(id);
|
||||
|
||||
Path path = Paths.get(String.format("%s/%s", componentConfig.getComponentDir(), id))
|
||||
.toAbsolutePath().normalize();
|
||||
|
@ -190,8 +191,10 @@ public class ProtocolController {
|
|||
@PathVariable("page") int page) {
|
||||
Page<ProtocolComponent> components = protocolComponentRepository.findAll(
|
||||
PageRequest.of(page - 1, size, Sort.by(Sort.Order.desc("createAt"))));
|
||||
components.getContent().forEach(c -> c.setState(deviceComponentManager.isRunning(c.getId()) ?
|
||||
ProtocolComponent.STATE_RUNNING : ProtocolComponent.STATE_STOPPED));
|
||||
components.getContent().forEach(c -> c.setState(
|
||||
componentManager.isRunning(c.getId()) ?
|
||||
ProtocolComponent.STATE_RUNNING : ProtocolComponent.STATE_STOPPED
|
||||
));
|
||||
return new Paging<>(components.getTotalElements(), components.getContent());
|
||||
}
|
||||
|
||||
|
@ -294,14 +297,17 @@ public class ProtocolController {
|
|||
public void changeComponentState(@PathVariable("id") String id,
|
||||
@PathVariable("state") String state) {
|
||||
ProtocolComponent component = getAndCheckComponent(id);
|
||||
String converterId = component.getConverter();
|
||||
getAndCheckConverter(converterId);
|
||||
if(ProtocolComponent.TYPE_DEVICE.equals(component.getType())){
|
||||
String converterId = component.getConverter();
|
||||
getAndCheckConverter(converterId);
|
||||
}
|
||||
|
||||
if (ProtocolComponent.STATE_RUNNING.equals(state)) {
|
||||
deviceComponentManager.register(component);
|
||||
deviceComponentManager.start(component.getId());
|
||||
componentManager.register(component);
|
||||
componentManager.start(component.getId());
|
||||
component.setState(ProtocolComponent.STATE_RUNNING);
|
||||
} else {
|
||||
deviceComponentManager.deRegister(id);
|
||||
componentManager.deRegister(id);
|
||||
component.setState(ProtocolComponent.STATE_STOPPED);
|
||||
}
|
||||
protocolComponentRepository.save(component);
|
||||
|
|
|
@ -1,22 +1,18 @@
|
|||
package cc.iotkit.manager.controller;
|
||||
|
||||
import cc.iotkit.dao.*;
|
||||
import cc.iotkit.manager.model.vo.SpaceDeviceVo;
|
||||
import cc.iotkit.manager.model.vo.SpaceInfo;
|
||||
import cc.iotkit.model.*;
|
||||
import cc.iotkit.model.device.DeviceInfo;
|
||||
import cc.iotkit.model.product.Product;
|
||||
import cc.iotkit.model.space.SpaceDevice;
|
||||
import cc.iotkit.common.exception.BizException;
|
||||
import cc.iotkit.dao.HomeRepository;
|
||||
import cc.iotkit.dao.SpaceRepository;
|
||||
import cc.iotkit.manager.service.DataOwnerService;
|
||||
import cc.iotkit.manager.utils.AuthUtil;
|
||||
import cc.iotkit.model.space.Home;
|
||||
import cc.iotkit.model.space.Space;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
@RestController
|
||||
|
@ -24,51 +20,87 @@ import java.util.stream.Collectors;
|
|||
public class SpaceController {
|
||||
|
||||
@Autowired
|
||||
private SpaceDeviceRepository spaceDeviceRepository;
|
||||
private SpaceRepository spaceRepository;
|
||||
@Autowired
|
||||
private DeviceRepository deviceRepository;
|
||||
private HomeRepository homeRepository;
|
||||
@Autowired
|
||||
private DeviceCache deviceCache;
|
||||
@Autowired
|
||||
private ProductCache productCache;
|
||||
private DataOwnerService dataOwnerService;
|
||||
|
||||
// @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("/currentHome")
|
||||
public Home getCurrentHome() {
|
||||
return homeRepository.findByUidAndCurrent(AuthUtil.getUserId(), true);
|
||||
}
|
||||
|
||||
@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 = 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().isOnline())
|
||||
.property(deviceInfo.getProperty())
|
||||
.productKey(deviceInfo.getProductKey())
|
||||
.build());
|
||||
});
|
||||
return deviceVos;
|
||||
/**
|
||||
* 保存家庭信息
|
||||
*/
|
||||
@PostMapping("/saveHome/{id}")
|
||||
public void saveHome(@PathVariable("id") String id, Home home) {
|
||||
Optional<Home> optHome = homeRepository.findById(id);
|
||||
if (!optHome.isPresent()) {
|
||||
throw new BizException("home does not exist");
|
||||
}
|
||||
Home oldHome = optHome.get();
|
||||
dataOwnerService.checkOwner(oldHome);
|
||||
if (StringUtils.isNotBlank(home.getName())) {
|
||||
oldHome.setName(home.getName());
|
||||
}
|
||||
if (StringUtils.isNotBlank(home.getAddress())) {
|
||||
oldHome.setName(home.getAddress());
|
||||
}
|
||||
homeRepository.save(oldHome);
|
||||
}
|
||||
|
||||
/**
|
||||
* 我的空间列表
|
||||
*/
|
||||
@GetMapping("/spaces/{homeId}")
|
||||
public List<Space> getSpaces(@PathVariable("homeId") String homeId) {
|
||||
return spaceRepository.findByUidAndHomeIdOrderByCreateAtDesc(AuthUtil.getUserId(), homeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在当前家庭中添加空间
|
||||
*/
|
||||
@PostMapping("/addSpace")
|
||||
public void addSpace(String name) {
|
||||
String uid = AuthUtil.getUserId();
|
||||
Home currHome = homeRepository.findByUidAndCurrent(uid, true);
|
||||
if (currHome == null) {
|
||||
throw new BizException("current home does not exist");
|
||||
}
|
||||
spaceRepository.save(Space.builder()
|
||||
.homeId(currHome.getId())
|
||||
.name(name)
|
||||
.uid(uid)
|
||||
.createAt(System.currentTimeMillis())
|
||||
.build());
|
||||
}
|
||||
|
||||
@DeleteMapping("/delSpace/{id}")
|
||||
public void delSpace(@PathVariable("id") String id) {
|
||||
checkExistAndOwner(id);
|
||||
spaceRepository.deleteById(id);
|
||||
}
|
||||
|
||||
@PostMapping("/saveSpace/{id}")
|
||||
public void saveSpace(@PathVariable("id") String id, String name) {
|
||||
Space oldSpace = checkExistAndOwner(id);
|
||||
oldSpace.setName(name);
|
||||
spaceRepository.save(oldSpace);
|
||||
}
|
||||
|
||||
private Space checkExistAndOwner(String id) {
|
||||
Optional<Space> optSpace = spaceRepository.findById(id);
|
||||
if (!optSpace.isPresent()) {
|
||||
throw new BizException("space does not exist");
|
||||
}
|
||||
|
||||
dataOwnerService.checkOwner(optSpace.get());
|
||||
return optSpace.get();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,267 @@
|
|||
package cc.iotkit.manager.controller;
|
||||
|
||||
import cc.iotkit.common.Constants;
|
||||
import cc.iotkit.common.exception.BizException;
|
||||
import cc.iotkit.dao.*;
|
||||
import cc.iotkit.manager.model.vo.FindDeviceVo;
|
||||
import cc.iotkit.manager.model.vo.SpaceDeviceVo;
|
||||
import cc.iotkit.manager.service.DataOwnerService;
|
||||
import cc.iotkit.manager.utils.AuthUtil;
|
||||
import cc.iotkit.model.UserInfo;
|
||||
import cc.iotkit.model.device.DeviceInfo;
|
||||
import cc.iotkit.model.product.Category;
|
||||
import cc.iotkit.model.product.Product;
|
||||
import cc.iotkit.model.space.Space;
|
||||
import cc.iotkit.model.space.SpaceDevice;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Example;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/space")
|
||||
public class SpaceDeviceController {
|
||||
|
||||
@Autowired
|
||||
private SpaceDeviceRepository spaceDeviceRepository;
|
||||
@Autowired
|
||||
private DeviceRepository deviceRepository;
|
||||
@Autowired
|
||||
private DeviceCache deviceCache;
|
||||
@Autowired
|
||||
private ProductCache productCache;
|
||||
@Autowired
|
||||
private CategoryCache categoryCache;
|
||||
@Autowired
|
||||
private SpaceCache spaceCache;
|
||||
@Autowired
|
||||
private SpaceRepository spaceRepository;
|
||||
@Autowired
|
||||
private DataOwnerService dataOwnerService;
|
||||
@Autowired
|
||||
private UserInfoRepository userInfoRepository;
|
||||
|
||||
/**
|
||||
* 我最近使用的设备列表
|
||||
*/
|
||||
@GetMapping(Constants.API_SPACE.RECENT_DEVICES)
|
||||
public List<SpaceDeviceVo> getMyRecentDevices() {
|
||||
List<SpaceDevice> spaceDevices = spaceDeviceRepository.findByUidOrderByUseAtDesc(AuthUtil.getUserId());
|
||||
return spaceDevices.stream().map((this::parseSpaceDevice)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 我的空间设备列表-按空间获取
|
||||
*
|
||||
* @param spaceId 空间id
|
||||
*/
|
||||
@GetMapping(Constants.API_SPACE.SPACE_DEVICES)
|
||||
public List<SpaceDeviceVo> getMyDevices(@PathVariable("spaceId") String spaceId) {
|
||||
String uid = AuthUtil.getUserId();
|
||||
List<SpaceDevice> spaceDevices;
|
||||
if ("all".equals(spaceId)) {
|
||||
//全部设备
|
||||
spaceDevices = spaceDeviceRepository.findByUidOrderByUseAtDesc(uid);
|
||||
} else {
|
||||
//按空间获取
|
||||
spaceDevices = spaceDeviceRepository.
|
||||
findByUidAndSpaceIdOrderByAddAtDesc(uid, spaceId);
|
||||
}
|
||||
return spaceDevices.stream().map((this::parseSpaceDevice)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private SpaceDeviceVo parseSpaceDevice(SpaceDevice sd) {
|
||||
DeviceInfo device = deviceRepository.findByDeviceId(sd.getDeviceId());
|
||||
Space space = spaceCache.getSpace(sd.getSpaceId());
|
||||
Product product = productCache.findById(device.getProductKey());
|
||||
Category category = categoryCache.getById(product.getCategory());
|
||||
DeviceInfo.State state = device.getState();
|
||||
|
||||
return SpaceDeviceVo.builder()
|
||||
.id(sd.getId())
|
||||
.deviceId(sd.getDeviceId())
|
||||
.deviceName(device.getDeviceName())
|
||||
.name(sd.getName())
|
||||
.spaceId(sd.getSpaceId())
|
||||
.spaceName(space.getName())
|
||||
.productKey(device.getProductKey())
|
||||
.productName(product.getName())
|
||||
.category(product.getCategory())
|
||||
.categoryName(category.getName())
|
||||
.picUrl(product.getImg())
|
||||
.online(state != null && state.isOnline())
|
||||
.property(device.getProperty())
|
||||
.uid(sd.getUid())
|
||||
.build();
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('iot_system_user')")
|
||||
@GetMapping("/{userId}/devices")
|
||||
public List<SpaceDeviceVo> getDevices(@PathVariable("userId") String userId) {
|
||||
List<SpaceDevice> spaceDevices = spaceDeviceRepository.findAll(Example.of(SpaceDevice.builder().uid(userId).build()));
|
||||
return spaceDevices.stream().map((this::parseSpaceDevice)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@GetMapping(Constants.API_SPACE.FIND_DEVICE)
|
||||
List<FindDeviceVo> findDevice(String mac) {
|
||||
if (StringUtils.isBlank(mac)) {
|
||||
throw new BizException("mac is blank");
|
||||
}
|
||||
|
||||
List<FindDeviceVo> findDeviceVos = new ArrayList<>();
|
||||
List<DeviceInfo> devices = deviceRepository.findByDeviceName(mac);
|
||||
if (devices == null) {
|
||||
return findDeviceVos;
|
||||
}
|
||||
|
||||
//查找网关下子设备
|
||||
List<DeviceInfo> subDevices = new ArrayList<>();
|
||||
for (DeviceInfo device : devices) {
|
||||
if (device.getParentId() == null) {
|
||||
subDevices = deviceRepository.findByParentId(device.getDeviceId());
|
||||
}
|
||||
}
|
||||
devices.addAll(subDevices);
|
||||
|
||||
//查找空间设备
|
||||
for (DeviceInfo device : devices) {
|
||||
SpaceDevice spaceDevice = spaceDeviceRepository.findByDeviceId(device.getDeviceId());
|
||||
if (spaceDevice == null) {
|
||||
//没有被其它人占用
|
||||
findDeviceVos.add(getFindDeviceVo(device));
|
||||
}
|
||||
}
|
||||
return findDeviceVos;
|
||||
}
|
||||
|
||||
private FindDeviceVo getFindDeviceVo(DeviceInfo device) {
|
||||
FindDeviceVo findDeviceVo = FindDeviceVo.builder()
|
||||
.deviceId(device.getDeviceId())
|
||||
.deviceName(device.getDeviceName())
|
||||
.productKey(device.getProductKey())
|
||||
.build();
|
||||
|
||||
Product product = productCache.findById(device.getProductKey());
|
||||
Category category = categoryCache.getById(product.getCategory());
|
||||
findDeviceVo.setProductName(product.getName());
|
||||
findDeviceVo.setProductImg(product.getImg());
|
||||
findDeviceVo.setCategoryName(category.getName());
|
||||
return findDeviceVo;
|
||||
}
|
||||
|
||||
@PostMapping(Constants.API_SPACE.ADD_DEVICE)
|
||||
public void addDevice(SpaceDevice device) {
|
||||
String deviceId = device.getDeviceId();
|
||||
DeviceInfo deviceInfo = deviceRepository.findByDeviceId(deviceId);
|
||||
if (deviceInfo == null) {
|
||||
throw new BizException("device does not exist");
|
||||
}
|
||||
String spaceId = device.getSpaceId();
|
||||
Optional<Space> optSpace = spaceRepository.findById(spaceId);
|
||||
if (!optSpace.isPresent()) {
|
||||
throw new BizException("space does not exist");
|
||||
}
|
||||
|
||||
SpaceDevice oldSpaceDevice = spaceDeviceRepository.findByDeviceId(deviceId);
|
||||
if (oldSpaceDevice != null) {
|
||||
throw new BizException("device has been added");
|
||||
}
|
||||
|
||||
Space space = optSpace.get();
|
||||
|
||||
SpaceDevice spaceDevice = SpaceDevice.builder()
|
||||
.deviceId(deviceId)
|
||||
.spaceId(spaceId)
|
||||
.deviceId(deviceId)
|
||||
.name(device.getName())
|
||||
.homeId(space.getHomeId())
|
||||
.uid(AuthUtil.getUserId())
|
||||
.addAt(System.currentTimeMillis())
|
||||
.build();
|
||||
spaceDeviceRepository.save(spaceDevice);
|
||||
|
||||
//更新设备子用户列表
|
||||
List<String> subUid = deviceInfo.getSubUid();
|
||||
if (subUid == null) {
|
||||
subUid = new ArrayList<>();
|
||||
deviceInfo.setSubUid(subUid);
|
||||
}
|
||||
|
||||
String uid = AuthUtil.getUserId();
|
||||
Optional<UserInfo> optUser = userInfoRepository.findById(uid);
|
||||
if (!optUser.isPresent()) {
|
||||
throw new BizException("user does not exist");
|
||||
}
|
||||
if (!subUid.contains(uid)) {
|
||||
subUid.add(uid);
|
||||
}
|
||||
|
||||
//更新设备标签
|
||||
List<String> platforms = optUser.get().getUsePlatforms();
|
||||
Map<String, DeviceInfo.Tag> tags = deviceInfo.getTag();
|
||||
for (String platform : platforms) {
|
||||
Constants.ThirdPlatform thirdPlatform = Constants.ThirdPlatform.valueOf(platform);
|
||||
tags.put(platform, new DeviceInfo.Tag(platform, thirdPlatform.desc, "是"));
|
||||
}
|
||||
|
||||
deviceRepository.save(deviceInfo);
|
||||
}
|
||||
|
||||
@DeleteMapping(Constants.API_SPACE.REMOVE_DEVICE)
|
||||
public void removeDevice(String deviceId) {
|
||||
String uid = AuthUtil.getUserId();
|
||||
SpaceDevice spaceDevice = spaceDeviceRepository.findByDeviceIdAndUid(deviceId, uid);
|
||||
if (spaceDevice == null) {
|
||||
throw new BizException("space device does not exist");
|
||||
}
|
||||
dataOwnerService.checkOwner(spaceDevice);
|
||||
|
||||
spaceDeviceRepository.deleteById(spaceDevice.getId());
|
||||
DeviceInfo deviceInfo = deviceRepository.findByDeviceId(deviceId);
|
||||
Optional<UserInfo> optUser = userInfoRepository.findById(uid);
|
||||
if (!optUser.isPresent()) {
|
||||
throw new BizException("user does not exist");
|
||||
}
|
||||
|
||||
List<String> platforms = optUser.get().getUsePlatforms();
|
||||
List<String> subUid = deviceInfo.getSubUid();
|
||||
subUid.remove(uid);
|
||||
//删除设备标签
|
||||
for (String platform : platforms) {
|
||||
deviceInfo.getTag().remove(platform);
|
||||
}
|
||||
|
||||
deviceRepository.save(deviceInfo);
|
||||
}
|
||||
|
||||
@PostMapping(Constants.API_SPACE.SAVE_DEVICE)
|
||||
public void saveDevice(SpaceDevice spaceDevice) {
|
||||
dataOwnerService.checkOwner(spaceDevice);
|
||||
Optional<SpaceDevice> optData = spaceDeviceRepository.findById(spaceDevice.getId());
|
||||
if (!optData.isPresent()) {
|
||||
throw new BizException("space device does not exist");
|
||||
}
|
||||
SpaceDevice oldData = optData.get();
|
||||
oldData.setName(spaceDevice.getName());
|
||||
oldData.setSpaceId(spaceDevice.getSpaceId());
|
||||
spaceDeviceRepository.save(oldData);
|
||||
}
|
||||
|
||||
@GetMapping(Constants.API_SPACE.GET_DEVICE)
|
||||
public SpaceDeviceVo getSpaceDevice(@PathVariable("deviceId") String deviceId) {
|
||||
String uid = AuthUtil.getUserId();
|
||||
SpaceDevice spaceDevice = spaceDeviceRepository.findByDeviceIdAndUid(deviceId, uid);
|
||||
//更新设备使用时间
|
||||
spaceDevice.setUseAt(System.currentTimeMillis());
|
||||
spaceDeviceRepository.save(spaceDevice);
|
||||
return parseSpaceDevice(spaceDevice);
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
package cc.iotkit.manager.controller;
|
||||
|
||||
import cc.iotkit.common.Constants;
|
||||
import cc.iotkit.common.utils.CodecUtil;
|
||||
import cc.iotkit.dao.UserAccountRepository;
|
||||
import cc.iotkit.model.UserAccount;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class SystemController {
|
||||
|
||||
@Autowired
|
||||
private UserAccountRepository userAccountRepository;
|
||||
|
||||
@PostMapping("/user/login")
|
||||
public String login(String uid, String pwd) throws Exception {
|
||||
UserAccount account = userAccountRepository.findById(uid).orElse(new UserAccount());
|
||||
String encodePwd = CodecUtil.aesEncrypt(uid + pwd, Constants.ACCOUNT_SECRET);
|
||||
if (encodePwd.equals(account.getPwd())) {
|
||||
return CodecUtil.aesEncrypt(System.currentTimeMillis() + "_" + uid, Constants.ACCOUNT_SECRET);
|
||||
}
|
||||
throw new RuntimeException("用户名或密码错误");
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println(CodecUtil.aesEncrypt("aaa123", Constants.ACCOUNT_SECRET));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
package cc.iotkit.manager.controller;
|
||||
|
||||
import cc.iotkit.common.utils.JsonUtil;
|
||||
import cc.iotkit.dao.ThirdUserSessionRepository;
|
||||
import cc.iotkit.model.ThirdUserSession;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Base64;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* 第三方接入认证
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/auth")
|
||||
public class ThirdAuthController {
|
||||
|
||||
private final OkHttpClient client = new OkHttpClient().newBuilder().build();
|
||||
|
||||
@Autowired
|
||||
private ThirdUserSessionRepository thirdUserSessionRepository;
|
||||
|
||||
@PostMapping("/token/{type}")
|
||||
public void getToken(
|
||||
@PathVariable("type") String type,
|
||||
HttpServletRequest servletRequest,
|
||||
HttpServletResponse servletResponse)
|
||||
throws UnsupportedEncodingException {
|
||||
|
||||
log.info("request:{}", JsonUtil.toJsonString(servletRequest.getParameterMap()));
|
||||
Enumeration<String> names = servletRequest.getParameterNames();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (names.hasMoreElements()) {
|
||||
String name = names.nextElement();
|
||||
sb.append(name).append("=")
|
||||
.append(URLEncoder.encode(servletRequest.getParameter(name), "UTF-8"))
|
||||
.append("&");
|
||||
}
|
||||
|
||||
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
|
||||
RequestBody body = RequestBody.create(mediaType, sb.toString());
|
||||
|
||||
Request.Builder builder = new Request.Builder();
|
||||
Request request = builder.url("https://auth.iotkit.cc/realms/iotkit/protocol/openid-connect/token")
|
||||
.method("POST", body)
|
||||
.build();
|
||||
log.info("send request body:{}", sb.toString());
|
||||
|
||||
Response response;
|
||||
try {
|
||||
response = client.newCall(request).execute();
|
||||
servletResponse.setStatus(response.code());
|
||||
Headers headers = response.headers();
|
||||
for (String name : headers.names()) {
|
||||
log.info("response header,name:{},value:{}", name, headers.get(name));
|
||||
servletResponse.setHeader(name, headers.get(name));
|
||||
}
|
||||
String bodyStr = response.body().string();
|
||||
log.info("response body:{}", bodyStr);
|
||||
TokenInfo tokenInfo = JsonUtil.parse(bodyStr, TokenInfo.class);
|
||||
String accessToken = tokenInfo.getAccess_token();
|
||||
String[] tokenParts = accessToken.split("\\.");
|
||||
Base64.Decoder decoder = Base64.getUrlDecoder();
|
||||
String payloadStr = new String(decoder.decode(tokenParts[1]));
|
||||
TokenPayload payload = JsonUtil.parse(payloadStr, TokenPayload.class);
|
||||
log.info("token payload:{}", payloadStr);
|
||||
|
||||
//保存用户授权token
|
||||
String uid = payload.getSub();
|
||||
thirdUserSessionRepository.save(ThirdUserSession.builder()
|
||||
.uid(uid)
|
||||
.token(accessToken)
|
||||
.type(type)
|
||||
.authAt(System.currentTimeMillis())
|
||||
.build());
|
||||
|
||||
servletResponse.setContentType("application/json");
|
||||
servletResponse.getWriter().write(bodyStr);
|
||||
} catch (IOException e) {
|
||||
log.error("request error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class TokenInfo {
|
||||
private String access_token;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class TokenPayload {
|
||||
private String sub;
|
||||
}
|
||||
}
|
|
@ -2,23 +2,17 @@ package cc.iotkit.manager.controller.aligenie;
|
|||
|
||||
import cc.iotkit.common.Constants;
|
||||
import cc.iotkit.common.exception.BizException;
|
||||
import cc.iotkit.common.exception.OfflineException;
|
||||
import cc.iotkit.common.utils.JsonUtil;
|
||||
import cc.iotkit.common.utils.UniqueIdUtil;
|
||||
import cc.iotkit.dao.*;
|
||||
import cc.iotkit.manager.service.DataOwnerService;
|
||||
import cc.iotkit.manager.service.DeviceService;
|
||||
import cc.iotkit.manager.utils.AuthUtil;
|
||||
import cc.iotkit.model.InvokeResult;
|
||||
import cc.iotkit.model.UserInfo;
|
||||
import cc.iotkit.model.aligenie.AligenieDevice;
|
||||
import cc.iotkit.model.aligenie.AligenieProduct;
|
||||
import cc.iotkit.model.device.DeviceInfo;
|
||||
import cc.iotkit.model.device.message.ThingModelMessage;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.pulsar.client.api.Producer;
|
||||
import org.apache.pulsar.client.api.PulsarClient;
|
||||
import org.apache.pulsar.client.api.PulsarClientException;
|
||||
|
@ -131,44 +125,6 @@ public class AligenieDeviceController {
|
|||
.build());
|
||||
}
|
||||
|
||||
@ApiOperation("设备服务调用")
|
||||
@PostMapping("/invoke/{deviceId}/{service}")
|
||||
public InvokeResult invokeService(@PathVariable("deviceId") String deviceId,
|
||||
@PathVariable("service") String service,
|
||||
String args) {
|
||||
InvokeResult result = new InvokeResult("", InvokeResult.FAILED_UNKNOWN);
|
||||
AligenieDevice device = aligenieDeviceRepository.findByUidAndDeviceId(AuthUtil.getUserId(), deviceId);
|
||||
|
||||
if (device == null) {
|
||||
result.setCode(InvokeResult.FAILED_NO_AUTH);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(deviceId) || StringUtils.isBlank(service)) {
|
||||
log.error("deviceId/service is blank");
|
||||
result.setCode(InvokeResult.FAILED_PARAM_ERROR);
|
||||
return result;
|
||||
}
|
||||
|
||||
try {
|
||||
String requestId;
|
||||
if ("set".equals(service)) {
|
||||
requestId = deviceService.setProperty(deviceId,
|
||||
JsonUtil.parse(args, Map.class), false);
|
||||
} else {
|
||||
requestId = deviceService.invokeService(deviceId,
|
||||
service, JsonUtil.parse(args, Map.class), false);
|
||||
}
|
||||
result.setRequestId(requestId);
|
||||
result.setCode(InvokeResult.SUCCESS);
|
||||
} catch (OfflineException e) {
|
||||
log.error("sendMsg failed", e);
|
||||
result.setCode(InvokeResult.FAILED_OFFLINE);
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Device {
|
||||
private String deviceId;
|
||||
|
|
|
@ -3,8 +3,6 @@ package cc.iotkit.manager.controller.api;
|
|||
import cc.iotkit.dao.AppInfoRepository;
|
||||
import cc.iotkit.dao.HomeRepository;
|
||||
import cc.iotkit.dao.UserInfoRepository;
|
||||
import cc.iotkit.manager.model.vo.LoginResult;
|
||||
import cc.iotkit.manager.service.AccountService;
|
||||
import cc.iotkit.manager.utils.AuthUtil;
|
||||
import cc.iotkit.model.AppInfo;
|
||||
import cc.iotkit.model.space.Home;
|
||||
|
@ -22,8 +20,6 @@ import org.springframework.web.bind.annotation.RestController;
|
|||
@RequestMapping("/api/account")
|
||||
public class AccountController {
|
||||
|
||||
@Autowired
|
||||
private AccountService accountService;
|
||||
@Autowired
|
||||
private HomeRepository homeRepository;
|
||||
@Autowired
|
||||
|
@ -31,18 +27,6 @@ public class AccountController {
|
|||
@Autowired
|
||||
private AppInfoRepository appInfoRepository;
|
||||
|
||||
@ApiOperation("用户注册")
|
||||
@PostMapping("/register")
|
||||
public void register(String uid, String pwd) {
|
||||
accountService.register(uid, pwd);
|
||||
}
|
||||
|
||||
@ApiOperation("用户登录")
|
||||
@PostMapping("/login")
|
||||
public LoginResult login(String uid, String pwd) {
|
||||
return new LoginResult(accountService.login(uid, pwd));
|
||||
}
|
||||
|
||||
@ApiOperation("设置当前家庭")
|
||||
@PostMapping("/setHomeId")
|
||||
public void setHomeId(String homeId) {
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
package cc.iotkit.manager.controller.api;
|
||||
|
||||
import cc.iotkit.common.exception.OfflineException;
|
||||
import cc.iotkit.common.utils.JsonUtil;
|
||||
import cc.iotkit.dao.AppDesignRepository;
|
||||
import cc.iotkit.dao.DeviceRepository;
|
||||
import cc.iotkit.dao.SpaceDeviceRepository;
|
||||
import cc.iotkit.dao.UserActionLogRepository;
|
||||
import cc.iotkit.manager.model.vo.AppPageNode;
|
||||
import cc.iotkit.manager.service.AppDesignService;
|
||||
import cc.iotkit.manager.service.DeviceService;
|
||||
import cc.iotkit.manager.utils.AuthUtil;
|
||||
import cc.iotkit.model.InvokeResult;
|
||||
import cc.iotkit.model.device.DeviceInfo;
|
||||
import cc.iotkit.model.space.SpaceDevice;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
|
@ -20,10 +16,12 @@ import lombok.extern.slf4j.Slf4j;
|
|||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Example;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
|
@ -40,8 +38,6 @@ public class DeviceController {
|
|||
@Autowired
|
||||
private AppDesignRepository appDesignRepository;
|
||||
@Autowired
|
||||
private UserActionLogRepository userActionLogRepository;
|
||||
@Autowired
|
||||
private AppDesignService appDesignService;
|
||||
|
||||
@ApiOperation("设备列表")
|
||||
|
@ -72,74 +68,6 @@ public class DeviceController {
|
|||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@ApiOperation("设备服务调用")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(value = "设备ID", name = "deviceId", required = true, dataType = "String"),
|
||||
@ApiImplicitParam(value = "服务名", name = "service", required = true, dataType = "String"),
|
||||
@ApiImplicitParam(value = "参数", name = "args", required = true, dataType = "String"),
|
||||
})
|
||||
@PostMapping("/{deviceId}/service/{service}")
|
||||
public InvokeResult invokeService(@PathVariable("deviceId") String deviceId,
|
||||
@PathVariable("service") String service,
|
||||
String args) {
|
||||
InvokeResult result = new InvokeResult("", InvokeResult.FAILED_UNKNOWN);
|
||||
SpaceDevice device = checkOwner(deviceId);
|
||||
|
||||
if (device == null) {
|
||||
result.setCode(InvokeResult.FAILED_NO_AUTH);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(deviceId) || StringUtils.isBlank(service)) {
|
||||
log.error("deviceId/service is blank");
|
||||
result.setCode(InvokeResult.FAILED_PARAM_ERROR);
|
||||
return result;
|
||||
}
|
||||
|
||||
try {
|
||||
String requestId;
|
||||
if ("property/set".equals(service)) {
|
||||
requestId = deviceService.setProperty(deviceId,
|
||||
JsonUtil.parse(args, Map.class));
|
||||
} else {
|
||||
requestId = deviceService.invokeService(deviceId, service,
|
||||
JsonUtil.parse(args, Map.class));
|
||||
}
|
||||
result.setRequestId(requestId);
|
||||
result.setCode(InvokeResult.SUCCESS);
|
||||
} catch (OfflineException e) {
|
||||
log.error("sendMsg failed", e);
|
||||
result.setCode(InvokeResult.FAILED_OFFLINE);
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ApiOperation("设备属性调用")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(value = "设备ID", name = "deviceId", required = true, dataType = "String"),
|
||||
@ApiImplicitParam(value = "参数", name = "args", required = true, dataType = "String"),
|
||||
})
|
||||
@PostMapping("/{deviceId}/service/property/set")
|
||||
public InvokeResult setProperty(@PathVariable("deviceId") String deviceId,
|
||||
String args) {
|
||||
checkOwner(deviceId);
|
||||
if (StringUtils.isBlank(deviceId) || StringUtils.isBlank(args)) {
|
||||
throw new RuntimeException("deviceId/args is blank.");
|
||||
}
|
||||
return invokeService(deviceId, "property/set", args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查设备是否属于该用户
|
||||
*/
|
||||
private SpaceDevice checkOwner(String deviceId) {
|
||||
return spaceDeviceRepository.findOne(Example.of(SpaceDevice.builder()
|
||||
.uid(AuthUtil.getUserId()).deviceId(deviceId).build()))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@GetMapping("/detailPage/{deviceId}")
|
||||
public List<AppPageNode> deviceDetailPage(@PathVariable("deviceId") String deviceId) {
|
||||
DeviceInfo device = deviceRepository.findById(deviceId).orElseThrow(() -> new RuntimeException("device not found"));
|
||||
|
|
|
@ -134,7 +134,7 @@ public class SpaceController {
|
|||
List<SpaceDeviceVo> spaceDeviceVos = new ArrayList<>();
|
||||
spaceDevices.forEach(sd -> spaceDeviceVos.add(buildSpaceDeviceVo(
|
||||
sd.getId(), sd.getDeviceId(),
|
||||
sd.getUid(), sd.getName(), sd.getSpaceName())));
|
||||
sd.getUid(), sd.getName(), "")));
|
||||
return spaceDeviceVos;
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,7 @@ public class SpaceController {
|
|||
|
||||
return buildSpaceDeviceVo(device.getId(), device.getDeviceId(),
|
||||
AuthUtil.getUserId(), device.getName(),
|
||||
device.getSpaceName());
|
||||
"");
|
||||
}
|
||||
|
||||
@ApiOperation("使用mac获取设备信息")
|
||||
|
@ -170,7 +170,7 @@ public class SpaceController {
|
|||
}
|
||||
|
||||
private SpaceDeviceVo buildSpaceDeviceVo(String id, String deviceId, String uid, String name, String spaceName) {
|
||||
DeviceInfo deviceInfo = deviceCache.findByDeviceId(deviceId);
|
||||
DeviceInfo deviceInfo = deviceCache.get(deviceId);
|
||||
Product product = productCache.findById(deviceInfo.getProductKey());
|
||||
return SpaceDeviceVo.builder()
|
||||
.id(id)
|
||||
|
@ -211,7 +211,6 @@ public class SpaceController {
|
|||
.name(name == null ? product.getName() : name)
|
||||
.homeId(space.getHomeId())
|
||||
.spaceId(space.getId())
|
||||
.spaceName(space.getName())
|
||||
.build());
|
||||
}
|
||||
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
package cc.iotkit.manager.controller.mp;
|
||||
|
||||
import cc.iotkit.dao.UserInfoRepository;
|
||||
import cc.iotkit.manager.model.vo.LoginResult;
|
||||
import cc.iotkit.manager.service.WeChatService;
|
||||
import cc.iotkit.manager.utils.AuthUtil;
|
||||
import cc.iotkit.model.UserInfo;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiImplicitParams;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController("mp-sys")
|
||||
@RequestMapping("/mp/sys")
|
||||
public class SystemController {
|
||||
|
||||
@Autowired
|
||||
private WeChatService weChatService;
|
||||
@Autowired
|
||||
private UserInfoRepository userInfoRepository;
|
||||
|
||||
@ApiOperation("用户登录")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(value = "加密的用户信息", name = "userInfo", required = true, dataType = "String"),
|
||||
@ApiImplicitParam(value = "加密向量", name = "iv", required = true, dataType = "String"),
|
||||
@ApiImplicitParam(value = "登录码", name = "loginCode", required = true, dataType = "String"),
|
||||
})
|
||||
@PostMapping("/login")
|
||||
public LoginResult login(String userInfo, String iv, String loginCode) {
|
||||
return new LoginResult(weChatService.login(userInfo, iv, loginCode));
|
||||
}
|
||||
|
||||
@ApiOperation("用户设置")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(value = "地址", name = "address", required = true, dataType = "String"),
|
||||
})
|
||||
@PostMapping("/settings")
|
||||
public void settings(String address) {
|
||||
UserInfo userInfo = userInfoRepository.findById(AuthUtil.getUserId()).get();
|
||||
userInfo.setAddress(address);
|
||||
userInfoRepository.save(userInfo);
|
||||
}
|
||||
|
||||
}
|
0
manager/src/main/java/cc/iotkit/manager/model/query/DeviceQuery.java
Normal file → Executable file
0
manager/src/main/java/cc/iotkit/manager/model/query/DeviceQuery.java
Normal file → Executable file
|
@ -0,0 +1,26 @@
|
|||
package cc.iotkit.manager.model.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class FindDeviceVo {
|
||||
|
||||
private String deviceId;
|
||||
|
||||
private String productKey;
|
||||
|
||||
private String deviceName;
|
||||
|
||||
private String productName;
|
||||
|
||||
private String categoryName;
|
||||
|
||||
private String productImg;
|
||||
|
||||
}
|
|
@ -43,6 +43,11 @@ public class SpaceDeviceVo {
|
|||
*/
|
||||
private String picUrl;
|
||||
|
||||
/**
|
||||
* 空间ID
|
||||
*/
|
||||
private String spaceId;
|
||||
|
||||
/**
|
||||
* 空间名称
|
||||
*/
|
||||
|
@ -63,4 +68,18 @@ public class SpaceDeviceVo {
|
|||
*/
|
||||
private String productKey;
|
||||
|
||||
/**
|
||||
* 产品名
|
||||
*/
|
||||
private String productName;
|
||||
|
||||
/**
|
||||
* 品类
|
||||
*/
|
||||
private String category;
|
||||
|
||||
/**
|
||||
* 品类名
|
||||
*/
|
||||
private String categoryName;
|
||||
}
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
package cc.iotkit.manager.service;
|
||||
|
||||
import cc.iotkit.common.Constants;
|
||||
import cc.iotkit.common.utils.CodecUtil;
|
||||
import cc.iotkit.dao.UserAccountRepository;
|
||||
import cc.iotkit.dao.UserInfoRepository;
|
||||
import cc.iotkit.model.UserAccount;
|
||||
import cc.iotkit.model.UserInfo;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Example;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class AccountService {
|
||||
@Autowired
|
||||
private UserAccountRepository accountRepository;
|
||||
@Autowired
|
||||
private UserInfoRepository userInfoRepository;
|
||||
|
||||
@SneakyThrows
|
||||
public String login(String uid, String pwd) {
|
||||
UserAccount account = accountRepository.findOne(Example.of(UserAccount.builder().uid(uid).build()))
|
||||
.orElseThrow(() -> new RuntimeException("用户名或密码错误"));
|
||||
String encodePwd = CodecUtil.aesEncrypt(uid + pwd, Constants.ACCOUNT_SECRET);
|
||||
if (!account.getPwd().equals(encodePwd)) {
|
||||
throw new RuntimeException("用户名或密码错误");
|
||||
}
|
||||
return CodecUtil.aesEncrypt(System.currentTimeMillis() + "_" + uid, Constants.ACCOUNT_SECRET);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public void register(String uid, String pwd) {
|
||||
if (accountRepository.exists(Example.of(UserAccount.builder().uid(uid).build()))) {
|
||||
throw new RuntimeException("用户名已存在");
|
||||
}
|
||||
accountRepository.save(UserAccount.builder().uid(uid)
|
||||
.pwd(CodecUtil.aesEncrypt(uid + pwd, Constants.ACCOUNT_SECRET))
|
||||
.build());
|
||||
userInfoRepository.save(UserInfo.builder().uid(uid).build());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
package cc.iotkit.manager.service;
|
||||
|
||||
import cc.iotkit.common.Constants;
|
||||
import cc.iotkit.common.utils.JsonUtil;
|
||||
import cc.iotkit.comps.config.ServerConfig;
|
||||
import cc.iotkit.model.device.DeviceInfo;
|
||||
import cc.iotkit.model.device.message.ThingModelMessage;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.pulsar.client.api.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.request.async.DeferredResult;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class DeferredDataConsumer implements MessageListener<ThingModelMessage>, Runnable {
|
||||
|
||||
private final Map<String, Set<String>> topicConsumers = new ConcurrentHashMap<>();
|
||||
private final Map<String, DeferredResultInfo> consumerDeferred = new ConcurrentHashMap<>();
|
||||
private final DelayQueue<DelayedPush> delayedPushes = new DelayQueue<>();
|
||||
|
||||
@Autowired
|
||||
private ServerConfig serverConfig;
|
||||
|
||||
@PostConstruct
|
||||
public void init() throws PulsarClientException {
|
||||
PulsarClient client = PulsarClient.builder()
|
||||
.serviceUrl(this.serverConfig.getPulsarBrokerUrl())
|
||||
.build();
|
||||
|
||||
client.newConsumer(Schema.JSON(ThingModelMessage.class))
|
||||
.topic("persistent://iotkit/default/" + Constants.THING_MODEL_MESSAGE_TOPIC)
|
||||
.subscriptionName("device-info-push")
|
||||
.consumerName("device-info-push-consumer")
|
||||
.messageListener(this).subscribe();
|
||||
|
||||
Executors.newCachedThreadPool().submit(this);
|
||||
}
|
||||
|
||||
public <T> DeferredResult<T> newConsumer(String consumerId, String topic) {
|
||||
topicConsumers.putIfAbsent(topic, new HashSet<>());
|
||||
Set<String> consumers = topicConsumers.get(topic);
|
||||
consumers.add(consumerId);
|
||||
|
||||
String consumerKey = getConsumerKey(consumerId, topic);
|
||||
DeferredResult<T> result = new DeferredResult<>(10000L, new DeviceInfo());
|
||||
DeferredResultInfo resultInfo = new DeferredResultInfo(result, false);
|
||||
result.onCompletion(() -> resultInfo.setCompleted(true));
|
||||
result.onTimeout(() -> resultInfo.setCompleted(true));
|
||||
|
||||
consumerDeferred.put(consumerKey, resultInfo);
|
||||
return result;
|
||||
}
|
||||
|
||||
public <T> void publish(String topic, T msg, boolean republish) {
|
||||
Set<String> consumers = topicConsumers.get(topic);
|
||||
if (consumers == null) {
|
||||
return;
|
||||
}
|
||||
for (String consumer : consumers) {
|
||||
String consumerKey = getConsumerKey(consumer, topic);
|
||||
DeferredResultInfo result = consumerDeferred.get(consumerKey);
|
||||
if (result == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//如果已经推送完成了,等待1秒再尝试发送,让客户端有时间重连
|
||||
if (!republish && result.isCompleted() && !result.isExpired()) {
|
||||
delayedPushes.offer(new DelayedPush<>(topic, System.currentTimeMillis(), msg),
|
||||
3, TimeUnit.SECONDS);
|
||||
} else {
|
||||
log.info("push {} to {},msg:{}", topic, consumer, JsonUtil.toJsonString(msg));
|
||||
result.getDeferredResult().setResult(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public <T> void publish(String topic, T msg) {
|
||||
publish(topic, msg, false);
|
||||
}
|
||||
|
||||
private String getConsumerKey(String consumerId, String topic) {
|
||||
return consumerId + topic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void received(Consumer<ThingModelMessage> consumer, Message<ThingModelMessage> msg) {
|
||||
ThingModelMessage thingModelMessage = msg.getValue();
|
||||
String type = thingModelMessage.getType();
|
||||
String identifier = thingModelMessage.getIdentifier();
|
||||
//属性上报和上下线消息
|
||||
if ((ThingModelMessage.TYPE_PROPERTY.equals(type) && "report".equals(identifier)) ||
|
||||
ThingModelMessage.TYPE_STATE.equals(type)) {
|
||||
publish(Constants.HTTP_CONSUMER_DEVICE_INFO_TOPIC + thingModelMessage.getDeviceId(),
|
||||
thingModelMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reachedEndOfTopic(Consumer<ThingModelMessage> consumer) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
try {
|
||||
DelayedPush<ThingModelMessage> delayedPush = delayedPushes.take();
|
||||
ThingModelMessage modelMessage = delayedPush.getMsg();
|
||||
publish(delayedPush.getTopic(), modelMessage, true);
|
||||
} catch (Throwable e) {
|
||||
log.error("delayed push error", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class DeferredResultInfo {
|
||||
private DeferredResult deferredResult;
|
||||
private boolean completed;
|
||||
private long completedTime;
|
||||
|
||||
public DeferredResultInfo(DeferredResult deferredResult, boolean completed) {
|
||||
this.deferredResult = deferredResult;
|
||||
this.completed = completed;
|
||||
this.completedTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void setCompleted(boolean completed) {
|
||||
this.completed = completed;
|
||||
this.completedTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public boolean isExpired() {
|
||||
//完成超过3后视为过期,客户端可能已断开
|
||||
return completed && System.currentTimeMillis() - completedTime > 3 * 1000L;
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class DelayedPush<T> implements Delayed {
|
||||
|
||||
private String topic;
|
||||
|
||||
private T msg;
|
||||
|
||||
private long addTime;
|
||||
|
||||
public DelayedPush(String topic, long addTime, T message) {
|
||||
this.topic = topic;
|
||||
this.addTime = addTime;
|
||||
this.msg = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDelay(TimeUnit unit) {
|
||||
return unit.convert(addTime - System.nanoTime(), TimeUnit.NANOSECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Delayed o) {
|
||||
long diff = o.getDelay(TimeUnit.NANOSECONDS) - getDelay(TimeUnit.NANOSECONDS);
|
||||
return diff == 0 ? 0 : (diff > 0 ? 1 : -1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -33,14 +33,13 @@ public class SpaceDeviceService {
|
|||
List<SpaceDevice> spaceDevices = spaceDeviceRepository.findAll(Example.of(device));
|
||||
List<SpaceDeviceVo> spaceDeviceVos = new ArrayList<>();
|
||||
spaceDevices.forEach(sd -> {
|
||||
DeviceInfo deviceInfo = deviceCache.findByDeviceId(sd.getDeviceId());
|
||||
DeviceInfo deviceInfo = deviceCache.get(sd.getDeviceId());
|
||||
Product product = productCache.findById(deviceInfo.getProductKey());
|
||||
spaceDeviceVos.add(SpaceDeviceVo.builder()
|
||||
.uid(sd.getUid())
|
||||
.deviceId(sd.getDeviceId())
|
||||
.name(sd.getName())
|
||||
.picUrl(product.getImg())
|
||||
.spaceName(sd.getSpaceName())
|
||||
.online(deviceInfo.getState().isOnline())
|
||||
.property(deviceInfo.getProperty())
|
||||
.productKey(deviceInfo.getProductKey())
|
||||
|
|
|
@ -24,7 +24,7 @@ spring:
|
|||
cache:
|
||||
cache-names: foo,bar
|
||||
caffeine:
|
||||
spec: maximumSize=5000,expireAfterAccess=120s
|
||||
spec: maximumSize=5000,expireAfterAccess=300s
|
||||
mvc:
|
||||
pathmatch:
|
||||
matching-strategy: ant_path_matcher
|
||||
|
|
|
@ -9,13 +9,12 @@ import lombok.NoArgsConstructor;
|
|||
@AllArgsConstructor
|
||||
public class InvokeResult {
|
||||
|
||||
public static final String SUCCESS = "success";
|
||||
public static final String FAILED_UNKNOWN = "unknown";
|
||||
public static final String FAILED_OFFLINE = "offline";
|
||||
public static final String FAILED_PARAM_ERROR = "param_error";
|
||||
public static final String FAILED_NO_AUTH = "no_auth";
|
||||
|
||||
private String requestId;
|
||||
|
||||
private String code;
|
||||
private long time;
|
||||
|
||||
public InvokeResult(String requestId) {
|
||||
this.requestId = requestId;
|
||||
this.time = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package cc.iotkit.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
/**
|
||||
* 第三方接入用户会话
|
||||
*/
|
||||
@Data
|
||||
@Document
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ThirdUserSession {
|
||||
|
||||
/**
|
||||
* 账号id
|
||||
*/
|
||||
@Id
|
||||
private String uid;
|
||||
|
||||
/**
|
||||
* 账号类型
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 登录授权后的token
|
||||
*/
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* 授权时间
|
||||
*/
|
||||
private Long authAt;
|
||||
}
|
|
@ -8,6 +8,7 @@ import lombok.NoArgsConstructor;
|
|||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
|
@ -72,16 +73,10 @@ public class UserInfo implements Owned {
|
|||
|
||||
/**
|
||||
* 用户使用的平台
|
||||
* 见:Constants.THIRD_PLATFORM
|
||||
*/
|
||||
private Platforms usePlatforms = new Platforms();
|
||||
private List<String> usePlatforms = new ArrayList<>();
|
||||
|
||||
private Long createAt;
|
||||
|
||||
@Data
|
||||
public static class Platforms {
|
||||
/**
|
||||
* 天猫精灵
|
||||
*/
|
||||
private boolean aligenie;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ import lombok.NoArgsConstructor;
|
|||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -39,16 +41,16 @@ public class DeviceInfo implements Owned {
|
|||
/**
|
||||
* 关联子用户ID列表
|
||||
*/
|
||||
private List<String> subUid;
|
||||
private List<String> subUid = new ArrayList<>();
|
||||
|
||||
private State state = new State();
|
||||
|
||||
private Map<String, Object> property;
|
||||
private Map<String, Object> property = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 设备标签
|
||||
*/
|
||||
private Map<String, Tag> tag;
|
||||
private Map<String, Tag> tag = new HashMap<>();
|
||||
|
||||
private Long createAt;
|
||||
|
||||
|
|
|
@ -31,5 +31,14 @@ public class Product implements Owned {
|
|||
|
||||
private String img;
|
||||
|
||||
/**
|
||||
* 是否透传
|
||||
*/
|
||||
private Boolean transparent;
|
||||
|
||||
private Long createAt;
|
||||
|
||||
public boolean isTransparent() {
|
||||
return transparent != null && transparent;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package cc.iotkit.model.product;
|
||||
|
||||
import cc.iotkit.model.Owned;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Document
|
||||
public class ProductModel {
|
||||
|
||||
public static final String TYPE_JS = "JavaScript";
|
||||
public static final String TYPE_LUA = "LuaScript";
|
||||
|
||||
public static final String STATE_DEV = "dev";
|
||||
public static final String STATE_PUBLISH = "publish";
|
||||
|
||||
/**
|
||||
* 型号在所有产品中唯一
|
||||
*/
|
||||
@Id
|
||||
private String model;
|
||||
|
||||
private String name;
|
||||
|
||||
private String productKey;
|
||||
|
||||
private String type;
|
||||
|
||||
private String script;
|
||||
|
||||
/**
|
||||
* 脚本状态,只有发布状态才生效
|
||||
*/
|
||||
private String state;
|
||||
|
||||
private Long modifyAt;
|
||||
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package cc.iotkit.model.space;
|
||||
|
||||
import cc.iotkit.model.Owned;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
@ -12,7 +13,7 @@ import org.springframework.data.mongodb.core.mapping.Document;
|
|||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Document
|
||||
public class Home {
|
||||
public class Home implements Owned {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
@ -41,4 +42,9 @@ public class Home {
|
|||
* 设备数量
|
||||
*/
|
||||
private Integer deviceNum;
|
||||
|
||||
/**
|
||||
* 是否为用户当前使用的家庭
|
||||
*/
|
||||
private Boolean current;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package cc.iotkit.model.space;
|
||||
|
||||
import cc.iotkit.model.Owned;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
@ -12,7 +13,7 @@ import org.springframework.data.mongodb.core.mapping.Document;
|
|||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Document
|
||||
public class Space {
|
||||
public class Space implements Owned {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
@ -36,4 +37,6 @@ public class Space {
|
|||
* 设备数量
|
||||
*/
|
||||
private Integer deviceNum;
|
||||
|
||||
private Long createAt;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package cc.iotkit.model.space;
|
||||
|
||||
import cc.iotkit.model.Owned;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
@ -12,7 +13,7 @@ import org.springframework.data.mongodb.core.mapping.Document;
|
|||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Document
|
||||
public class SpaceDevice {
|
||||
public class SpaceDevice implements Owned {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
@ -48,7 +49,13 @@ public class SpaceDevice {
|
|||
private String spaceId;
|
||||
|
||||
/**
|
||||
* 空间名称
|
||||
* 添加时间
|
||||
*/
|
||||
private String spaceName;
|
||||
private Long addAt;
|
||||
|
||||
/**
|
||||
* 使用时间
|
||||
*/
|
||||
private Long useAt;
|
||||
|
||||
}
|
||||
|
|
17
pom.xml
17
pom.xml
|
@ -25,8 +25,9 @@
|
|||
<name>iotkit-parent</name>
|
||||
<description>iotkit parent</description>
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<java.version>11</java.version>
|
||||
<keycloak-spring.version>17.0.0</keycloak-spring.version>
|
||||
<vertx.version>4.2.2</vertx.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
@ -172,28 +173,34 @@
|
|||
<version>1.2.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.luaj</groupId>
|
||||
<artifactId>luaj-jse</artifactId>
|
||||
<version>3.0.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-core</artifactId>
|
||||
<version>4.2.6</version>
|
||||
<version>${vertx.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-mqtt</artifactId>
|
||||
<version>4.2.6</version>
|
||||
<version>${vertx.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-web-proxy</artifactId>
|
||||
<version>4.2.6</version>
|
||||
<version>${vertx.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-web-client</artifactId>
|
||||
<version>4.2.6</version>
|
||||
<version>${vertx.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
|
Binary file not shown.
|
@ -42,6 +42,11 @@
|
|||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-web-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
|
@ -57,6 +62,11 @@
|
|||
<artifactId>pulsar-client-original</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.luaj</groupId>
|
||||
<artifactId>luaj-jse</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
|
|
|
@ -0,0 +1,186 @@
|
|||
package cc.iotkit.comps;
|
||||
|
||||
import cc.iotkit.common.Constants;
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.core.buffer.Buffer;
|
||||
import io.vertx.core.http.HttpMethod;
|
||||
import io.vertx.ext.web.client.HttpRequest;
|
||||
import io.vertx.ext.web.client.WebClient;
|
||||
import io.vertx.ext.web.client.WebClientOptions;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* 平台API调用工具类
|
||||
*/
|
||||
@Slf4j
|
||||
public class ApiTool {
|
||||
|
||||
private final Vertx vertx;
|
||||
private final WebClient client;
|
||||
|
||||
private String host;
|
||||
private int port;
|
||||
private int timeout;
|
||||
|
||||
public ApiTool() {
|
||||
if (Vertx.currentContext() == null) {
|
||||
vertx = Vertx.vertx();
|
||||
} else {
|
||||
vertx = Vertx.currentContext().owner();
|
||||
}
|
||||
|
||||
WebClientOptions options = new WebClientOptions()
|
||||
.setUserAgent("component-api-tool");
|
||||
options.setKeepAlive(false);
|
||||
client = WebClient.create(vertx, options);
|
||||
}
|
||||
|
||||
public void config(String host, int port, int timeout) {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
private String getDevicePath(String path) {
|
||||
return Paths.get(Constants.API_DEVICE.BASE, path).toString();
|
||||
}
|
||||
|
||||
private String getSpacePath(String path) {
|
||||
return Paths.get(Constants.API_SPACE.BASE, path).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户空间中设备列表
|
||||
*/
|
||||
public ApiResponse getSpaceDevices(String token) {
|
||||
HttpRequest<Buffer> request = client
|
||||
.get(port, host, getSpacePath(Constants.API_SPACE.SPACE_DEVICES
|
||||
.replace("{spaceId}", "all")));
|
||||
return send(token, HttpMethod.GET, request, new HashMap<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取空间设备详情
|
||||
*/
|
||||
public ApiResponse getSpaceDeviceDetail(String token, String deviceId) {
|
||||
HttpRequest<Buffer> request = client
|
||||
.get(port, host, getSpacePath(Constants.API_SPACE.GET_DEVICE
|
||||
.replace("{deviceId}", deviceId)));
|
||||
return send(token, HttpMethod.GET, request, new HashMap<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户的设备列表
|
||||
*/
|
||||
public ApiResponse getDevices(String token) {
|
||||
HttpRequest<Buffer> request = client
|
||||
.post(port, host, getDevicePath(Constants.API_DEVICE.LIST
|
||||
.replace("{size}", "1000")
|
||||
.replace("{page}", "1")));
|
||||
return send(token, HttpMethod.POST, request, new HashMap<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备详情
|
||||
*/
|
||||
public ApiResponse getDeviceDetail(String token, String deviceId) {
|
||||
HttpRequest<Buffer> request = client
|
||||
.get(port, host, getDevicePath(Constants.API_DEVICE.DETAIL
|
||||
.replace("{deviceId}", deviceId)));
|
||||
return send(token, HttpMethod.GET, request, new HashMap<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置属性
|
||||
*/
|
||||
public ApiResponse setProperties(String token, String deviceId, Map<String, Object> properties) {
|
||||
HttpRequest<Buffer> request = client
|
||||
.post(port, host, getDevicePath(Constants.API_DEVICE.SET_PROPERTIES
|
||||
.replace("{deviceId}", deviceId)));
|
||||
return send(token, HttpMethod.POST, request, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用服务
|
||||
*/
|
||||
public ApiResponse invokeService(String token, String deviceId, String service, Map<String, Object> params) {
|
||||
HttpRequest<Buffer> request = client
|
||||
.post(port, host, getDevicePath(Constants.API_DEVICE.INVOKE_SERVICE
|
||||
.replace("{deviceId}", deviceId)
|
||||
.replace("{service}", service)));
|
||||
return send(token, HttpMethod.POST, request, params);
|
||||
}
|
||||
|
||||
private ApiResponse send(String token, HttpMethod method, HttpRequest<Buffer> request, Map<String, Object> params) {
|
||||
request = request
|
||||
.timeout(timeout)
|
||||
.putHeader("wrap-response", "json")
|
||||
.putHeader("authorization", "Bearer " + token);
|
||||
|
||||
AtomicReference<ApiResponse> apiResponse = new AtomicReference<>(
|
||||
new ApiResponse(500, "", null, System.currentTimeMillis()));
|
||||
try {
|
||||
//转为同步模式便于提供给js调用
|
||||
CountDownLatch wait = new CountDownLatch(1);
|
||||
|
||||
if (method == HttpMethod.POST) {
|
||||
request.sendJson(params)
|
||||
.onSuccess((response) -> {
|
||||
log.info("send succeed,response:{}", response.bodyAsString());
|
||||
apiResponse.set(response.bodyAsJson(ApiResponse.class));
|
||||
wait.countDown();
|
||||
})
|
||||
.onFailure((err) -> {
|
||||
log.error("send failed", err);
|
||||
wait.countDown();
|
||||
});
|
||||
} else if (method == HttpMethod.GET) {
|
||||
request.send()
|
||||
.onSuccess((response) -> {
|
||||
log.info("send succeed,response:{}", response.bodyAsString());
|
||||
apiResponse.set(response.bodyAsJson(ApiResponse.class));
|
||||
wait.countDown();
|
||||
})
|
||||
.onFailure((err) -> {
|
||||
log.error("send failed", err);
|
||||
wait.countDown();
|
||||
});
|
||||
}
|
||||
if (wait.await(timeout, TimeUnit.MILLISECONDS)) {
|
||||
return apiResponse.get();
|
||||
} else {
|
||||
apiResponse.get().setStatus(500);
|
||||
apiResponse.get().setMessage("request timeout");
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
apiResponse.get().setStatus(500);
|
||||
apiResponse.get().setMessage(e.getMessage());
|
||||
log.error("send error", e);
|
||||
}
|
||||
return apiResponse.get();
|
||||
}
|
||||
|
||||
public void log(String msg) {
|
||||
log.info(msg);
|
||||
}
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class ApiResponse {
|
||||
private int status;
|
||||
private String message;
|
||||
private Object data;
|
||||
private long timestamp;
|
||||
}
|
||||
}
|
11
protocol-gateway/component-server/src/main/java/cc/iotkit/comps/BizComponentManager.java
Normal file → Executable file
11
protocol-gateway/component-server/src/main/java/cc/iotkit/comps/BizComponentManager.java
Normal file → Executable file
|
@ -6,6 +6,7 @@ import cc.iotkit.common.exception.BizException;
|
|||
import cc.iotkit.comp.CompConfig;
|
||||
import cc.iotkit.comp.IComponent;
|
||||
import cc.iotkit.comps.config.ComponentConfig;
|
||||
import cc.iotkit.comps.service.DeviceBehaviourService;
|
||||
import cc.iotkit.dao.ProtocolComponentRepository;
|
||||
import cc.iotkit.model.protocol.ProtocolComponent;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
@ -32,6 +33,8 @@ public class BizComponentManager {
|
|||
private ComponentConfig componentConfig;
|
||||
@Autowired
|
||||
private ProtocolComponentRepository componentRepository;
|
||||
@Autowired
|
||||
private DeviceBehaviourService deviceBehaviourService;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
|
@ -61,16 +64,18 @@ public class BizComponentManager {
|
|||
} catch (Throwable e) {
|
||||
throw new BizException("get component instance error");
|
||||
}
|
||||
componentInstance.create(new CompConfig(300, component.getConfig()));
|
||||
|
||||
try {
|
||||
String componentScript = FileUtils.readFileToString(path.
|
||||
resolve(ProtocolComponent.SCRIPT_FILE_NAME).toFile(), "UTF-8");
|
||||
componentInstance.setScript(componentScript);
|
||||
register(id, componentInstance);
|
||||
componentInstance.putScriptEnv("deviceBehaviour", deviceBehaviourService);
|
||||
componentInstance.putScriptEnv("apiTool", new ApiTool());
|
||||
} catch (IOException e) {
|
||||
throw new BizException("get component script error", e);
|
||||
}
|
||||
componentInstance.create(new CompConfig(300, component.getConfig()));
|
||||
|
||||
register(id, componentInstance);
|
||||
}
|
||||
|
||||
public void register(String id, IComponent component) {
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package cc.iotkit.comps;
|
||||
|
||||
|
||||
import cc.iotkit.model.protocol.ProtocolComponent;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class ComponentManager {
|
||||
|
||||
@Autowired
|
||||
private BizComponentManager bizComponentManager;
|
||||
|
||||
@Autowired
|
||||
private DeviceComponentManager deviceComponentManager;
|
||||
|
||||
|
||||
public void register(ProtocolComponent component) {
|
||||
String type = component.getType();
|
||||
if (ProtocolComponent.TYPE_BIZ.equals(type)) {
|
||||
bizComponentManager.register(component);
|
||||
} else if (ProtocolComponent.TYPE_DEVICE.equals(type)) {
|
||||
deviceComponentManager.register(component);
|
||||
}
|
||||
}
|
||||
|
||||
public void deRegister(String id) {
|
||||
bizComponentManager.deRegister(id);
|
||||
deviceComponentManager.deRegister(id);
|
||||
}
|
||||
|
||||
public void start(String id) {
|
||||
bizComponentManager.start(id);
|
||||
deviceComponentManager.start(id);
|
||||
}
|
||||
|
||||
public void stop(String id) {
|
||||
bizComponentManager.stop(id);
|
||||
deviceComponentManager.stop(id);
|
||||
}
|
||||
|
||||
public boolean isRunning(String id) {
|
||||
return bizComponentManager.isRunning(id) || deviceComponentManager.isRunning(id);
|
||||
}
|
||||
|
||||
}
|
43
protocol-gateway/component-server/src/main/java/cc/iotkit/comps/DeviceComponentManager.java
Normal file → Executable file
43
protocol-gateway/component-server/src/main/java/cc/iotkit/comps/DeviceComponentManager.java
Normal file → Executable file
|
@ -9,11 +9,16 @@ import cc.iotkit.comp.IDeviceComponent;
|
|||
import cc.iotkit.comps.config.CacheKey;
|
||||
import cc.iotkit.comps.config.ComponentConfig;
|
||||
import cc.iotkit.comps.service.DeviceBehaviourService;
|
||||
import cc.iotkit.converter.Device;
|
||||
import cc.iotkit.converter.DeviceMessage;
|
||||
import cc.iotkit.converter.ScriptConverter;
|
||||
import cc.iotkit.converter.ThingService;
|
||||
import cc.iotkit.dao.DeviceCache;
|
||||
import cc.iotkit.dao.ProductCache;
|
||||
import cc.iotkit.dao.ProtocolComponentRepository;
|
||||
import cc.iotkit.model.device.DeviceInfo;
|
||||
import cc.iotkit.model.device.message.ThingModelMessage;
|
||||
import cc.iotkit.model.product.Product;
|
||||
import cc.iotkit.model.protocol.ProtocolComponent;
|
||||
import cc.iotkit.model.protocol.ProtocolConverter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
@ -46,11 +51,16 @@ public class DeviceComponentManager {
|
|||
private ComponentConfig componentConfig;
|
||||
@Autowired
|
||||
private ProtocolComponentRepository componentRepository;
|
||||
@Autowired
|
||||
private DeviceCache deviceCache;
|
||||
@Autowired
|
||||
ProductCache productCache;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
try {
|
||||
List<ProtocolComponent> componentList = componentRepository.findByState(ProtocolComponent.STATE_RUNNING);
|
||||
List<ProtocolComponent> componentList = componentRepository.findByStateAndType(
|
||||
ProtocolComponent.STATE_RUNNING, ProtocolComponent.TYPE_DEVICE);
|
||||
for (ProtocolComponent component : componentList) {
|
||||
register(component);
|
||||
start(component.getId());
|
||||
|
@ -83,6 +93,7 @@ public class DeviceComponentManager {
|
|||
resolve(ProtocolConverter.SCRIPT_FILE_NAME).toFile(), "UTF-8");
|
||||
|
||||
scriptConverter.setScript(converterScript);
|
||||
scriptConverter.putScriptEnv("component", componentInstance);
|
||||
componentInstance.setConverter(scriptConverter);
|
||||
|
||||
String componentScript = FileUtils.readFileToString(path.
|
||||
|
@ -115,10 +126,13 @@ public class DeviceComponentManager {
|
|||
if (component == null) {
|
||||
return;
|
||||
}
|
||||
component.setHandler(
|
||||
new DeviceMessageHandler(this, component,
|
||||
component.getScript(), component.getConverter(),
|
||||
deviceBehaviourService));
|
||||
DeviceMessageHandler messageHandler = new DeviceMessageHandler(this, component,
|
||||
component.getScript(), component.getConverter(),
|
||||
deviceBehaviourService);
|
||||
messageHandler.putScriptEnv("apiTool", new ApiTool());
|
||||
messageHandler.putScriptEnv("deviceBehaviour", deviceBehaviourService);
|
||||
|
||||
component.setHandler(messageHandler);
|
||||
component.start();
|
||||
states.put(id, true);
|
||||
}
|
||||
|
@ -142,16 +156,29 @@ public class DeviceComponentManager {
|
|||
throw new BizException("there is no components");
|
||||
}
|
||||
|
||||
DeviceInfo deviceInfo = deviceCache.getDeviceInfo(service.getProductKey(), service.getDeviceName());
|
||||
Product product = productCache.findById(service.getProductKey());
|
||||
String linkPk = service.getProductKey();
|
||||
String linkDn = service.getDeviceName();
|
||||
|
||||
if (product.isTransparent()) {
|
||||
//如果是透传设备,取父级设备进行链路查找
|
||||
DeviceInfo parent = deviceCache.get(deviceInfo.getParentId());
|
||||
linkPk = parent.getProductKey();
|
||||
linkDn = parent.getDeviceName();
|
||||
}
|
||||
|
||||
for (IDeviceComponent com : components.values()) {
|
||||
if (com.exist(service.getProductKey(), service.getDeviceName())) {
|
||||
if (com.exist(linkPk, linkDn)) {
|
||||
Device device = new Device(deviceInfo.getDeviceId(), deviceInfo.getModel(), product.isTransparent());
|
||||
//对下发消息进行编码转换
|
||||
DeviceMessage message = com.getConverter().encode(service, null);
|
||||
DeviceMessage message = com.getConverter().encode(service, device);
|
||||
if (message == null) {
|
||||
throw new BizException("encode send message failed");
|
||||
}
|
||||
//保存设备端mid与平台mid对应关系
|
||||
redisTemplate.opsForValue().set(
|
||||
CacheKey.getKeyCmdMid(service.getDeviceName(), message.getMid()),
|
||||
CacheKey.getKeyCmdMid(message.getDeviceName(), message.getMid()),
|
||||
service.getMid(), com.getConfig().getCmdTimeout(), TimeUnit.SECONDS);
|
||||
com.send(message);
|
||||
|
||||
|
|
7
protocol-gateway/component-server/src/main/java/cc/iotkit/comps/DeviceMessageHandler.java
Normal file → Executable file
7
protocol-gateway/component-server/src/main/java/cc/iotkit/comps/DeviceMessageHandler.java
Normal file → Executable file
|
@ -156,7 +156,7 @@ public class DeviceMessageHandler implements IMessageHandler {
|
|||
|
||||
//服务回复需要重新对应mid
|
||||
if (thingModelMessage.getIdentifier().endsWith("_reply")) {
|
||||
String platformMid = deviceComponentManager.getPlatformMid(message.getDeviceName(), message.getMid());
|
||||
String platformMid = deviceComponentManager.getPlatformMid(thingModelMessage.getDeviceName(), message.getMid());
|
||||
if (platformMid == null) {
|
||||
platformMid = UniqueIdUtil.newRequestId();
|
||||
}
|
||||
|
@ -196,6 +196,11 @@ public class DeviceMessageHandler implements IMessageHandler {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putScriptEnv(String key, Object value) {
|
||||
engine.put(key, value);
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Action {
|
||||
public static final String TYPE_ACK = "ack";
|
||||
|
|
|
@ -8,13 +8,13 @@ import cc.iotkit.common.utils.UniqueIdUtil;
|
|||
import cc.iotkit.comp.model.DeviceState;
|
||||
import cc.iotkit.comp.model.RegisterInfo;
|
||||
import cc.iotkit.comps.config.ServerConfig;
|
||||
import cc.iotkit.dao.DeviceCache;
|
||||
import cc.iotkit.dao.DeviceRepository;
|
||||
import cc.iotkit.dao.ProductRepository;
|
||||
import cc.iotkit.dao.*;
|
||||
import cc.iotkit.model.device.DeviceInfo;
|
||||
import cc.iotkit.model.device.message.ThingModelMessage;
|
||||
import cc.iotkit.model.product.Product;
|
||||
import cc.iotkit.model.product.ProductModel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.pulsar.client.api.Producer;
|
||||
import org.apache.pulsar.client.api.PulsarClient;
|
||||
import org.apache.pulsar.client.api.PulsarClientException;
|
||||
|
@ -34,12 +34,16 @@ public class DeviceBehaviourService {
|
|||
@Autowired
|
||||
private ProductRepository productRepository;
|
||||
@Autowired
|
||||
private ProductModelRepository productModelRepository;
|
||||
@Autowired
|
||||
private ProductCache productCache;
|
||||
@Autowired
|
||||
private DeviceRepository deviceRepository;
|
||||
@Autowired
|
||||
private ServerConfig serverConfig;
|
||||
@Autowired
|
||||
private DeviceCache deviceCache;
|
||||
@Autowired
|
||||
// @Autowired
|
||||
private DeviceStateHolder deviceStateHolder;
|
||||
|
||||
private Producer<ThingModelMessage> deviceMessageProducer;
|
||||
|
@ -69,17 +73,6 @@ public class DeviceBehaviourService {
|
|||
subDevice.getTag(), null));
|
||||
}
|
||||
}
|
||||
|
||||
//设备注册消息
|
||||
ThingModelMessage modelMessage = new ThingModelMessage(
|
||||
UniqueIdUtil.newRequestId(), "",
|
||||
info.getProductKey(), info.getDeviceName(),
|
||||
ThingModelMessage.TYPE_LIFETIME, "register",
|
||||
0, new HashMap<>(), System.currentTimeMillis(),
|
||||
System.currentTimeMillis()
|
||||
);
|
||||
|
||||
reportMessage(modelMessage);
|
||||
} catch (BizException e) {
|
||||
log.error("register device error", e);
|
||||
throw e;
|
||||
|
@ -91,33 +84,75 @@ public class DeviceBehaviourService {
|
|||
|
||||
public DeviceInfo register(String parentId, RegisterInfo info) {
|
||||
String pk = info.getProductKey();
|
||||
String dn = info.getDeviceName();
|
||||
String model = info.getModel();
|
||||
|
||||
//子设备注册处理
|
||||
if (parentId != null) {
|
||||
//透传设备:pk为空、model不为空,使用model查询产品
|
||||
if (StringUtils.isBlank(pk) && StringUtils.isNotBlank(model)) {
|
||||
ProductModel productModel = productModelRepository.findByModel(model);
|
||||
if (productModel == null) {
|
||||
throw new BizException("product model does not exist");
|
||||
}
|
||||
pk = productModel.getProductKey();
|
||||
}
|
||||
}
|
||||
|
||||
Optional<Product> optProduct = productRepository.findById(pk);
|
||||
if (!optProduct.isPresent()) {
|
||||
throw new BizException("Product does not exist");
|
||||
}
|
||||
String uid = optProduct.get().getUid();
|
||||
Product product = optProduct.get();
|
||||
String uid = product.getUid();
|
||||
DeviceInfo device = deviceRepository.findByProductKeyAndDeviceName(pk, info.getDeviceName());
|
||||
boolean reportMsg = false;
|
||||
|
||||
if (device != null) {
|
||||
log.info("device already registered");
|
||||
//更换网关重新注册更新父级ID
|
||||
device.setModel(model);
|
||||
} else {
|
||||
//不存在,注册新设备
|
||||
device = new DeviceInfo();
|
||||
device.setId(DeviceUtil.newDeviceId(dn));
|
||||
device.setParentId(parentId);
|
||||
deviceRepository.save(device);
|
||||
return device;
|
||||
device.setUid(uid);
|
||||
device.setDeviceId(device.getId());
|
||||
device.setProductKey(pk);
|
||||
device.setDeviceName(dn);
|
||||
device.setModel(model);
|
||||
//默认离线
|
||||
device.setState(new DeviceInfo.State(false, null, null));
|
||||
device.setCreateAt(System.currentTimeMillis());
|
||||
reportMsg = true;
|
||||
}
|
||||
//不存在,注册新设备
|
||||
device = new DeviceInfo();
|
||||
device.setId(DeviceUtil.newDeviceId(info.getDeviceName()));
|
||||
device.setParentId(parentId);
|
||||
device.setUid(uid);
|
||||
device.setDeviceId(device.getId());
|
||||
device.setProductKey(pk);
|
||||
device.setDeviceName(info.getDeviceName());
|
||||
device.setState(new DeviceInfo.State(false, null, null));
|
||||
device.setCreateAt(System.currentTimeMillis());
|
||||
|
||||
//透传设备,默认在线
|
||||
if (product.isTransparent()) {
|
||||
device.setState(new DeviceInfo.State(true, System.currentTimeMillis(), null));
|
||||
}
|
||||
|
||||
if (parentId != null) {
|
||||
//子设备更换网关重新注册更新父级ID
|
||||
device.setParentId(parentId);
|
||||
reportMsg = true;
|
||||
}
|
||||
deviceRepository.save(device);
|
||||
log.info("device registered:{}", JsonUtil.toJsonString(device));
|
||||
|
||||
//新设备或更换网关需要产生注册消息
|
||||
if (reportMsg) {
|
||||
log.info("device registered:{}", JsonUtil.toJsonString(device));
|
||||
//新注册设备注册消息
|
||||
ThingModelMessage modelMessage = new ThingModelMessage(
|
||||
UniqueIdUtil.newRequestId(), "",
|
||||
pk, dn,
|
||||
ThingModelMessage.TYPE_LIFETIME, "register",
|
||||
0, new HashMap<>(), System.currentTimeMillis(),
|
||||
System.currentTimeMillis()
|
||||
);
|
||||
|
||||
reportMessage(modelMessage);
|
||||
}
|
||||
|
||||
return device;
|
||||
}
|
||||
|
@ -155,11 +190,17 @@ public class DeviceBehaviourService {
|
|||
}
|
||||
deviceStateChange(device, online);
|
||||
|
||||
//可能是父设备,父设备离线,子设备也要离线
|
||||
if (!online && device.getParentId() == null) {
|
||||
List<DeviceInfo> subDevices = deviceRepository.findByParentId(device.getDeviceId());
|
||||
for (DeviceInfo subDevice : subDevices) {
|
||||
deviceStateChange(subDevice, false);
|
||||
if (device.getParentId() != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<DeviceInfo> subDevices = deviceRepository.findByParentId(device.getDeviceId());
|
||||
for (DeviceInfo subDevice : subDevices) {
|
||||
Product product = productCache.findById(subDevice.getProductKey());
|
||||
Boolean transparent = product.getTransparent();
|
||||
//透传设备父设备上线,子设备也上线。非透传设备父设备离线,子设备才离线
|
||||
if (transparent != null && transparent || !online) {
|
||||
deviceStateChange(subDevice, online);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -168,11 +209,11 @@ public class DeviceBehaviourService {
|
|||
if (online) {
|
||||
device.getState().setOnline(true);
|
||||
device.getState().setOnlineTime(System.currentTimeMillis());
|
||||
deviceStateHolder.online(device.getDeviceId());
|
||||
// deviceStateHolder.online(device.getDeviceId());
|
||||
} else {
|
||||
device.getState().setOnline(false);
|
||||
device.getState().setOfflineTime(System.currentTimeMillis());
|
||||
deviceStateHolder.offline(device.getDeviceId());
|
||||
// deviceStateHolder.offline(device.getDeviceId());
|
||||
}
|
||||
deviceRepository.save(device);
|
||||
|
||||
|
@ -192,7 +233,7 @@ public class DeviceBehaviourService {
|
|||
|
||||
public void reportMessage(ThingModelMessage message) {
|
||||
try {
|
||||
DeviceInfo device = deviceCache.findByProductKeyAndDeviceName(message.getProductKey(),
|
||||
DeviceInfo device = deviceCache.getDeviceInfo(message.getProductKey(),
|
||||
message.getDeviceName());
|
||||
if (device == null) {
|
||||
return;
|
||||
|
@ -209,4 +250,12 @@ public class DeviceBehaviourService {
|
|||
log.error("send thing model message error", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提供给js调用的方法
|
||||
*/
|
||||
public void reportMessage(String jsonMsg) {
|
||||
ThingModelMessage message = JsonUtil.parse(jsonMsg, ThingModelMessage.class);
|
||||
reportMessage(message);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ import java.util.concurrent.TimeUnit;
|
|||
* 设备状态维持,每1分钟更新一次心跳
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
//@Service
|
||||
public class DeviceStateHolder implements MessageListener<DeviceStateHolder.OfflineMessage> {
|
||||
|
||||
private ScheduledThreadPoolExecutor stateHolderTask;
|
||||
|
|
4
protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractDeviceComponent.java
Normal file → Executable file
4
protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractDeviceComponent.java
Normal file → Executable file
|
@ -38,4 +38,8 @@ public abstract class AbstractDeviceComponent implements IDeviceComponent {
|
|||
public CompConfig getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putScriptEnv(String key, Object value) {
|
||||
}
|
||||
}
|
||||
|
|
5
protocol-gateway/component/src/main/java/cc/iotkit/comp/IComponent.java
Normal file → Executable file
5
protocol-gateway/component/src/main/java/cc/iotkit/comp/IComponent.java
Normal file → Executable file
|
@ -15,4 +15,9 @@ public interface IComponent {
|
|||
void setScript(String script);
|
||||
|
||||
String getScript();
|
||||
|
||||
/**
|
||||
* 添加脚本环境变量
|
||||
*/
|
||||
void putScriptEnv(String key, Object value);
|
||||
}
|
||||
|
|
0
protocol-gateway/component/src/main/java/cc/iotkit/comp/IDeviceComponent.java
Normal file → Executable file
0
protocol-gateway/component/src/main/java/cc/iotkit/comp/IDeviceComponent.java
Normal file → Executable file
|
@ -7,4 +7,9 @@ import java.util.Map;
|
|||
public interface IMessageHandler {
|
||||
|
||||
ReceiveResult onReceive(Map<String, Object> head, String type, String msg);
|
||||
|
||||
/**
|
||||
* 添加脚本环境变量
|
||||
*/
|
||||
void putScriptEnv(String key, Object value);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,21 @@
|
|||
package cc.iotkit.converter;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Device {
|
||||
|
||||
private String deviceId;
|
||||
|
||||
private String model;
|
||||
|
||||
/**
|
||||
* 是否透传
|
||||
*/
|
||||
private Boolean transparent;
|
||||
|
||||
}
|
||||
|
|
|
@ -10,4 +10,5 @@ public interface IConverter {
|
|||
|
||||
DeviceMessage encode(ThingService<?> service, Device device);
|
||||
|
||||
void putScriptEnv(String key, Object value);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,12 @@ public class ScriptConverter implements IConverter {
|
|||
|
||||
public ThingModelMessage decode(DeviceMessage msg) {
|
||||
try {
|
||||
ScriptObjectMirror result = (ScriptObjectMirror) engine.invokeMethod(scriptObj, "decode", msg);
|
||||
Object rst = engine.invokeMethod(scriptObj, "decode", msg);
|
||||
if (rst instanceof ThingModelMessage) {
|
||||
return (ThingModelMessage) rst;
|
||||
}
|
||||
|
||||
ScriptObjectMirror result = (ScriptObjectMirror) rst;
|
||||
ThingModelMessage modelMessage = new ThingModelMessage();
|
||||
BeanUtils.populate(modelMessage, result);
|
||||
return modelMessage;
|
||||
|
@ -53,4 +58,8 @@ public class ScriptConverter implements IConverter {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putScriptEnv(String key, Object value) {
|
||||
engine.put(key, value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,19 +43,19 @@
|
|||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-core</artifactId>
|
||||
<version>4.2.6</version>
|
||||
<version>4.2.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-web-proxy</artifactId>
|
||||
<version>4.2.6</version>
|
||||
<version>4.2.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-mqtt</artifactId>
|
||||
<version>4.2.6</version>
|
||||
<version>4.2.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
0
protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/EmqxDeviceComponent.java
Normal file → Executable file
0
protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/EmqxDeviceComponent.java
Normal file → Executable file
Binary file not shown.
|
@ -0,0 +1,69 @@
|
|||
<?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/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<artifactId>protocol-gateway</artifactId>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>http-biz-component</artifactId>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.2.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<artifactSet>
|
||||
<includes>
|
||||
<include>io.vertx:vertx-web-proxy</include>
|
||||
<include>io.vertx:vertx-web</include>
|
||||
<include>io.vertx:vertx-bridge-common</include>
|
||||
<include>io.vertx:vertx-http-proxy</include>
|
||||
<include>io.vertx:vertx-core</include>
|
||||
<include>io.netty:netty-codec-http2</include>
|
||||
</includes>
|
||||
</artifactSet>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>8</source>
|
||||
<target>8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.22</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-web-proxy</artifactId>
|
||||
<version>4.2.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<artifactId>component</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<properties>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
</properties>
|
||||
</project>
|
|
@ -28,17 +28,49 @@
|
|||
<artifactId>vertx-web-proxy</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-web-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<artifactId>component</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.2.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<artifactSet>
|
||||
<includes>
|
||||
<include>io.vertx:vertx-web-proxy</include>
|
||||
<include>io.vertx:vertx-web</include>
|
||||
<include>io.vertx:vertx-bridge-common</include>
|
||||
<include>io.vertx:vertx-http-proxy</include>
|
||||
<include>io.vertx:vertx-core</include>
|
||||
<include>io.netty:netty-codec-http2</include>
|
||||
</includes>
|
||||
</artifactSet>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>8</source>
|
||||
<target>8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -1,137 +0,0 @@
|
|||
package cc.iotkit.comp.biz;
|
||||
|
||||
import cc.iotkit.common.Constants;
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.core.buffer.Buffer;
|
||||
import io.vertx.ext.web.client.HttpRequest;
|
||||
import io.vertx.ext.web.client.WebClient;
|
||||
import io.vertx.ext.web.client.WebClientOptions;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* 平台API调用工具类
|
||||
*/
|
||||
public class ApiTool {
|
||||
|
||||
private static final Vertx vertx;
|
||||
private static final WebClient client;
|
||||
|
||||
static {
|
||||
if (Vertx.currentContext() == null) {
|
||||
vertx = Vertx.vertx();
|
||||
} else {
|
||||
vertx = Vertx.currentContext().owner();
|
||||
}
|
||||
|
||||
WebClientOptions options = new WebClientOptions()
|
||||
.setUserAgent("component-api-tool");
|
||||
options.setKeepAlive(false);
|
||||
client = WebClient.create(vertx, options);
|
||||
}
|
||||
|
||||
private static String host;
|
||||
private static int port;
|
||||
private static int timeout;
|
||||
|
||||
public static void config(String host, int port, int timeout) {
|
||||
ApiTool.host = host;
|
||||
ApiTool.port = port;
|
||||
ApiTool.timeout = timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户的设备列表
|
||||
*/
|
||||
public static ApiResponse getDevices(String token) {
|
||||
HttpRequest<Buffer> request = client
|
||||
.post(port, host, Paths.get(Constants.API.DEVICE_BASE, Constants.API.DEVICE_LIST
|
||||
.replace("size", "1000")
|
||||
.replace("page", "1")).toString())
|
||||
.timeout(timeout)
|
||||
.putHeader("authorization", "Bearer " + token);
|
||||
return sendJson(request, new HashMap<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备详情
|
||||
*/
|
||||
public static ApiResponse getDeviceDetail(String token, String deviceId) {
|
||||
HttpRequest<Buffer> request = client
|
||||
.post(port, host, Paths.get(Constants.API.DEVICE_BASE, Constants.API.DEVICE_DETAIL
|
||||
.replace("deviceId", deviceId)).toString())
|
||||
.timeout(timeout)
|
||||
.putHeader("authorization", "Bearer " + token);
|
||||
return sendJson(request, new HashMap<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置属性
|
||||
*/
|
||||
public static ApiResponse setProperties(String token, String deviceId, Map<String, Object> properties) {
|
||||
HttpRequest<Buffer> request = client
|
||||
.post(port, host, Paths.get(Constants.API.DEVICE_BASE, Constants.API.DEVICE_SET_PROPERTIES
|
||||
.replace("deviceId", deviceId)).toString())
|
||||
.timeout(timeout)
|
||||
.putHeader("authorization", "Bearer " + token);
|
||||
return sendJson(request, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用服务
|
||||
*/
|
||||
public static ApiResponse invokeService(String token, String deviceId, String service, Map<String, Object> params) {
|
||||
HttpRequest<Buffer> request = client
|
||||
.post(port, host, Paths.get(Constants.API.DEVICE_BASE, Constants.API.DEVICE_INVOKE_SERVICE
|
||||
.replace("deviceId", deviceId)
|
||||
.replace("service", service)).toString())
|
||||
.timeout(timeout)
|
||||
.putHeader("authorization", "Bearer " + token);
|
||||
return sendJson(request, params);
|
||||
}
|
||||
|
||||
private static ApiResponse sendJson(HttpRequest<Buffer> request, Map<String, Object> params) {
|
||||
AtomicReference<ApiResponse> apiResponse = new AtomicReference<>(new ApiResponse(500, "", null));
|
||||
try {
|
||||
//转为同步模式便于提供给js调用
|
||||
CountDownLatch wait = new CountDownLatch(1);
|
||||
request.sendJson(params)
|
||||
.onSuccess((response) -> {
|
||||
System.out.println(response.bodyAsString());
|
||||
apiResponse.set(response.bodyAsJson(ApiResponse.class));
|
||||
wait.countDown();
|
||||
})
|
||||
.onFailure((err) -> {
|
||||
err.printStackTrace();
|
||||
wait.countDown();
|
||||
});
|
||||
if (wait.await(timeout, TimeUnit.MILLISECONDS)) {
|
||||
return apiResponse.get();
|
||||
} else {
|
||||
apiResponse.get().setCode(500);
|
||||
apiResponse.get().setMessage("request timeout");
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
apiResponse.get().setCode(500);
|
||||
apiResponse.get().setMessage(e.getMessage());
|
||||
}
|
||||
return apiResponse.get();
|
||||
}
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class ApiResponse {
|
||||
private int code;
|
||||
private String message;
|
||||
private Object data;
|
||||
}
|
||||
}
|
112
protocol-gateway/http-biz-component/src/main/java/cc/iotkit/comp/biz/HttpBizComponent.java
Normal file → Executable file
112
protocol-gateway/http-biz-component/src/main/java/cc/iotkit/comp/biz/HttpBizComponent.java
Normal file → Executable file
|
@ -6,6 +6,7 @@ import cc.iotkit.comp.IComponent;
|
|||
import io.vertx.core.MultiMap;
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.core.http.HttpServer;
|
||||
import io.vertx.core.http.HttpServerRequest;
|
||||
import io.vertx.core.http.HttpServerResponse;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.ext.web.Router;
|
||||
|
@ -22,8 +23,8 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Data
|
||||
@Slf4j
|
||||
public class HttpBizComponent implements IComponent {
|
||||
|
||||
private final Vertx vertx = Vertx.vertx();
|
||||
|
@ -32,7 +33,9 @@ public class HttpBizComponent implements IComponent {
|
|||
|
||||
private Object scriptObj;
|
||||
|
||||
private HttpConfig config;
|
||||
private CompConfig config;
|
||||
|
||||
private HttpConfig httpConfig;
|
||||
|
||||
private String script;
|
||||
|
||||
|
@ -40,7 +43,7 @@ public class HttpBizComponent implements IComponent {
|
|||
|
||||
@Override
|
||||
public void create(CompConfig config) {
|
||||
this.config = JsonUtil.parse(config.getOther(), HttpConfig.class);
|
||||
this.httpConfig = JsonUtil.parse(config.getOther(), HttpConfig.class);
|
||||
try {
|
||||
scriptObj = engine.eval(String.format("new (function () {\n%s})()", script));
|
||||
} catch (ScriptException e) {
|
||||
|
@ -54,53 +57,80 @@ public class HttpBizComponent implements IComponent {
|
|||
Router backendRouter = Router.router(vertx);
|
||||
backendRouter.route().handler(BodyHandler.create())
|
||||
.handler(rc -> {
|
||||
Map<String, Object> httpHeader = getData(rc.request().headers());
|
||||
log.info("request header:{}", JsonUtil.toJsonString(httpHeader));
|
||||
Map<String, List<Object>> httpParams = getListData(rc.request().params());
|
||||
log.info("request params:{}", JsonUtil.toJsonString(httpParams));
|
||||
try {
|
||||
Map<String, Object> httpHeader = getData(rc.request().headers());
|
||||
log.info("request header:{}", JsonUtil.toJsonString(httpHeader));
|
||||
Map<String, List<Object>> httpParams = getListData(rc.request().params());
|
||||
log.info("request params:{}", JsonUtil.toJsonString(httpParams));
|
||||
|
||||
String contentType = rc.request().headers().get("Content-Type");
|
||||
JsonObject responseHeader = new JsonObject();
|
||||
if ("application/json".equals(contentType)) {
|
||||
String bodyStr = rc.toString();
|
||||
Map body = JsonUtil.parse(bodyStr, Map.class);
|
||||
log.info("request body:{}", bodyStr);
|
||||
HttpServerRequest httpRequest = rc.request();
|
||||
String contentType = httpRequest.headers().get("Content-Type");
|
||||
JsonObject responseHeader = new JsonObject();
|
||||
if ("application/json".equals(contentType)) {
|
||||
String bodyStr = rc.getBody().toString();
|
||||
Map body = JsonUtil.parse(bodyStr, Map.class);
|
||||
log.info("request body:{}", bodyStr);
|
||||
|
||||
String response = "unknown error";
|
||||
String name = "onReceive";
|
||||
if (((ScriptObjectMirror) scriptObj).get(name) != null) {
|
||||
try {
|
||||
Object result = engine.invokeMethod(scriptObj, name, body);
|
||||
Object resultObj = JsonUtil.toObject((ScriptObjectMirror) result);
|
||||
if (resultObj instanceof Map) {
|
||||
JsonObject data = JsonObject.mapFrom(resultObj);
|
||||
responseHeader = data.getJsonObject("header");
|
||||
response = data.getString("content");
|
||||
String response = "unknown error";
|
||||
String name = "onReceive";
|
||||
if (((ScriptObjectMirror) scriptObj).get(name) != null) {
|
||||
try {
|
||||
Object result = engine.invokeMethod(scriptObj,
|
||||
name,
|
||||
httpRequest.method().name(),
|
||||
httpRequest.path(),
|
||||
httpHeader,
|
||||
httpParams,
|
||||
body);
|
||||
Object resultObj = JsonUtil.toObject((ScriptObjectMirror) result);
|
||||
if (resultObj instanceof Map) {
|
||||
JsonObject data = JsonObject.mapFrom(resultObj);
|
||||
responseHeader = data.getJsonObject("header");
|
||||
response = data.getString("content");
|
||||
response = response == null ? "" : response;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
log.error("invokeMethod onReceive error", e);
|
||||
response = e.getMessage();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
log.error("invokeMethod onReceive error", e);
|
||||
response = e.getMessage();
|
||||
} else {
|
||||
log.error("required [onReceive] method");
|
||||
}
|
||||
|
||||
HttpServerResponse httpServerResponse = rc.response();
|
||||
//设置响应头
|
||||
responseHeader.getMap().forEach((key, value) -> {
|
||||
//大写转换
|
||||
key = key.replaceAll("([A-Z])", "-$1").toLowerCase();
|
||||
httpServerResponse.putHeader(key, value.toString());
|
||||
});
|
||||
|
||||
log.info("response,header:{},content:{}", responseHeader, response);
|
||||
//设置响应内容
|
||||
httpServerResponse
|
||||
.end(response);
|
||||
} else {
|
||||
log.error("required [onReceive] method");
|
||||
rc.response().end("");
|
||||
}
|
||||
|
||||
HttpServerResponse httpServerResponse = rc.response();
|
||||
//设置响应头
|
||||
responseHeader.getMap().forEach((key, value) -> {
|
||||
//大写转换
|
||||
key = key.replaceAll("([A-Z])", "-$1").toLowerCase();
|
||||
httpServerResponse.putHeader(key, value.toString());
|
||||
});
|
||||
|
||||
log.info("response,header:{},content:{}", responseHeader, response);
|
||||
//设置响应内容
|
||||
httpServerResponse
|
||||
.end(response);
|
||||
} catch (Throwable e) {
|
||||
log.error("handle request error", e);
|
||||
rc.response().end("server error:" + e.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
backendServer.requestHandler(backendRouter).listen(config.getPort());
|
||||
backendServer.requestHandler(backendRouter)
|
||||
.listen(httpConfig.getPort(), (http) -> {
|
||||
if (http.succeeded()) {
|
||||
log.info("http server create succeed,port:{}", httpConfig.getPort());
|
||||
} else {
|
||||
log.error("http server create failed", http.cause());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putScriptEnv(String key, Object value) {
|
||||
engine.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
0
protocol-gateway/http-biz-component/src/main/java/cc/iotkit/comp/biz/HttpConfig.java
Normal file → Executable file
0
protocol-gateway/http-biz-component/src/main/java/cc/iotkit/comp/biz/HttpConfig.java
Normal file → Executable file
|
@ -0,0 +1,36 @@
|
|||
//引用api工具类
|
||||
var apiTool = Java.type("cc.iotkit.comp.biz.ApiTool");
|
||||
//api配置
|
||||
apiTool.config("http://localhost",8086,3000);
|
||||
|
||||
this.onReceive=function(method,path,header,params,body){
|
||||
//method:post、get、delete...
|
||||
//path:请求路径
|
||||
//header:http请求头数据,结构:{xx:xx,yy:yy}
|
||||
//params:请求参数,结构:{xx:[...],yy:[...]}
|
||||
//body:请求体,当提交的数据为json格式时使用,结构:{xx:xx,yy:yy}
|
||||
apiTool.log("onReceive method:"+method);
|
||||
apiTool.log("onReceive path:"+path);
|
||||
apiTool.log("onReceive header:"+header);
|
||||
apiTool.log("onReceive params:"+params);
|
||||
apiTool.log("onReceive body:"+body);
|
||||
var duHeader=body.header;
|
||||
var namespace=duHeader.namespace;
|
||||
var requestName=duHeader.name;
|
||||
var messageId=duHeader.messageId;
|
||||
var duPayload=duHeader.payload;
|
||||
var token=duHeader.accessToken;
|
||||
|
||||
//设备发现
|
||||
if(namespace=="DuerOS.ConnectedHome.Discovery" && requestName=="DiscoverAppliancesRequest"){
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
url:"xx",//不指定直接作为响应返回
|
||||
header:{
|
||||
contentType:"xx"
|
||||
},
|
||||
content:"xx"
|
||||
}
|
||||
}
|
0
protocol-gateway/http-biz-component/src/main/resources/component.spi
Normal file → Executable file
0
protocol-gateway/http-biz-component/src/main/resources/component.spi
Normal file → Executable file
|
@ -30,6 +30,7 @@ public class Application {
|
|||
gateway2.addSubDevice("cGCrkK7Ex4FESAwe", "ABE12300001", "S1");
|
||||
gateway2.addSubDevice("cGCrkK7Ex4FESAwe", "ABE12300002", "S1");
|
||||
gateway2.addSubDevice("6kYp6jszrDns2yh4", "ABE12400001", "S1");
|
||||
gateway2.addSubDevice("", "ABE12500001", "M1");
|
||||
gateway2.start();
|
||||
}).start();
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import cc.iotkit.simulator.config.Mqtt;
|
|||
import lombok.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.paho.client.mqttv3.*;
|
||||
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
|
||||
|
||||
|
@ -120,9 +121,14 @@ public class Gateway extends Device {
|
|||
//子设备注册成功
|
||||
if (response.code == 0) {
|
||||
Map<String, Object> data = response.getData();
|
||||
String productKey = data.get("productKey").toString();
|
||||
if (StringUtils.isBlank(productKey)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//订阅子设备消息
|
||||
String subTopic = String.format("/sys/%s/%s/c/#",
|
||||
data.get("productKey"), data.get("deviceName"));
|
||||
productKey, data.get("deviceName"));
|
||||
log.info("subscribe topic:{}", subTopic);
|
||||
client.subscribe(subTopic);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
<include>io.vertx:vertx-core</include>
|
||||
<include>io.vertx:vertx-mqtt</include>
|
||||
<include>io.netty:netty-codec-mqtt</include>
|
||||
<include>org.luaj:luaj-jse</include>
|
||||
</includes>
|
||||
</artifactSet>
|
||||
</configuration>
|
||||
|
@ -43,13 +44,13 @@
|
|||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-core</artifactId>
|
||||
<version>4.2.6</version>
|
||||
<version>4.2.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-mqtt</artifactId>
|
||||
<version>4.2.6</version>
|
||||
<version>4.2.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -70,6 +71,12 @@
|
|||
<version>1.7.32</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.luaj</groupId>
|
||||
<artifactId>luaj-jse</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
|
@ -82,5 +89,11 @@
|
|||
<version>0.1.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<artifactId>dao</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -38,6 +38,11 @@
|
|||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.luaj</groupId>
|
||||
<artifactId>luaj-jse</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
|
@ -48,6 +53,11 @@
|
|||
<artifactId>component</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<artifactId>dao</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -70,6 +80,7 @@
|
|||
<include>io.vertx:vertx-core</include>
|
||||
<include>io.vertx:vertx-mqtt</include>
|
||||
<include>io.netty:netty-codec-mqtt</include>
|
||||
<include>org.luaj:luaj-jse</include>
|
||||
</includes>
|
||||
</artifactSet>
|
||||
</configuration>
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package cc.iotkit.comp.mqtt;
|
||||
|
||||
import cc.iotkit.converter.DeviceMessage;
|
||||
import cc.iotkit.converter.ThingService;
|
||||
import cc.iotkit.model.device.message.ThingModelMessage;
|
||||
|
||||
public interface IScripter {
|
||||
|
||||
void setScript(String script);
|
||||
|
||||
/**
|
||||
* 透传解码
|
||||
*/
|
||||
ThingModelMessage decode(TransparentMsg msg);
|
||||
|
||||
/**
|
||||
* 透传编码
|
||||
*/
|
||||
TransparentMsg encode(ThingService<?> service);
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package cc.iotkit.comp.mqtt;
|
||||
|
||||
import cc.iotkit.converter.ThingService;
|
||||
import cc.iotkit.model.device.message.ThingModelMessage;
|
||||
|
||||
public class JsScripter implements IScripter {
|
||||
|
||||
@Override
|
||||
public void setScript(String script) {
|
||||
}
|
||||
|
||||
public ThingModelMessage decode(TransparentMsg msg) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public TransparentMsg encode(ThingService<?> service) {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
package cc.iotkit.comp.mqtt;
|
||||
|
||||
import cc.iotkit.converter.ThingService;
|
||||
import cc.iotkit.model.device.message.ThingModelMessage;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.beanutils.BeanUtils;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.script.LuaScriptEngine;
|
||||
|
||||
import javax.script.Compilable;
|
||||
import javax.script.CompiledScript;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.SimpleBindings;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
public class LuaScripter implements IScripter {
|
||||
|
||||
private final LuaScriptEngine engine = (LuaScriptEngine) (
|
||||
new ScriptEngineManager().getEngineByName("luaj"));
|
||||
|
||||
private LuaValue decoder;
|
||||
private LuaValue encoder;
|
||||
|
||||
@Override
|
||||
public void setScript(String script) {
|
||||
try {
|
||||
CompiledScript compiledScript = ((Compilable) engine).compile(script);
|
||||
SimpleBindings bindings = new SimpleBindings();
|
||||
compiledScript.eval(bindings);
|
||||
decoder = (LuaValue) bindings.get("decode");
|
||||
encoder = (LuaValue) bindings.get("encode");
|
||||
} catch (Throwable e) {
|
||||
log.error("compile script error", e);
|
||||
}
|
||||
}
|
||||
|
||||
public ThingModelMessage decode(TransparentMsg msg) {
|
||||
try {
|
||||
LuaTable table = new LuaTable();
|
||||
table.set("model", msg.getModel());
|
||||
table.set("mac", msg.getMac());
|
||||
table.set("data", msg.getData());
|
||||
Map result = (Map) parse(decoder.call(table));
|
||||
ThingModelMessage modelMessage = new ThingModelMessage();
|
||||
BeanUtils.populate(modelMessage, result);
|
||||
|
||||
modelMessage.setProductKey(msg.getProductKey());
|
||||
modelMessage.setDeviceName(msg.getMac());
|
||||
return modelMessage;
|
||||
} catch (Throwable e) {
|
||||
log.error("execute decode script error", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public TransparentMsg encode(ThingService<?> service) {
|
||||
try {
|
||||
LuaTable table = new LuaTable();
|
||||
table.set("identifier", service.getIdentifier());
|
||||
table.set("type", service.getType());
|
||||
table.set("productKey", service.getProductKey());
|
||||
table.set("deviceName", service.getDeviceName());
|
||||
table.set("mid", service.getMid());
|
||||
Object params = service.getParams();
|
||||
LuaTable tableParams = new LuaTable();
|
||||
if (params instanceof Map) {
|
||||
((Map<?, ?>) params).forEach((key, val) -> tableParams.set(key.toString(), parse(val)));
|
||||
}
|
||||
table.set("params", tableParams);
|
||||
LuaValue result = encoder.call(table);
|
||||
Map map = (Map) parse(result);
|
||||
TransparentMsg message = new TransparentMsg();
|
||||
BeanUtils.populate(message, map);
|
||||
return message;
|
||||
} catch (Throwable e) {
|
||||
log.error("execute encode script error", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Object parse(LuaValue value) {
|
||||
String type = value.typename();
|
||||
switch (type) {
|
||||
case "string":
|
||||
return value.toString();
|
||||
case "number":
|
||||
case "int":
|
||||
return value.toint();
|
||||
case "table":
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
LuaTable table = (LuaTable) value;
|
||||
int arrLen = table.rawlen();
|
||||
if (arrLen > 0) {
|
||||
//数组转换
|
||||
List<Object> list = new ArrayList<>();
|
||||
for (LuaValue key : table.keys()) {
|
||||
list.add(parse(table.get(key)));
|
||||
}
|
||||
return list;
|
||||
} else {
|
||||
//map转换
|
||||
for (LuaValue key : table.keys()) {
|
||||
data.put(key.toString(), parse(table.get(key)));
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private LuaValue parse(Object value) {
|
||||
if (value instanceof String) {
|
||||
return LuaValue.valueOf(value.toString());
|
||||
}
|
||||
if (value instanceof Integer) {
|
||||
return LuaValue.valueOf((Integer) value);
|
||||
}
|
||||
return new LuaTable();
|
||||
}
|
||||
|
||||
}
|
20
protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttDeviceComponent.java
Normal file → Executable file
20
protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttDeviceComponent.java
Normal file → Executable file
|
@ -6,12 +6,15 @@ import cc.iotkit.comp.AbstractDeviceComponent;
|
|||
import cc.iotkit.comp.CompConfig;
|
||||
import cc.iotkit.comp.model.DeviceState;
|
||||
import cc.iotkit.converter.DeviceMessage;
|
||||
import cc.iotkit.converter.ThingService;
|
||||
import cc.iotkit.model.device.message.ThingModelMessage;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.Vertx;
|
||||
import lombok.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.beanutils.BeanUtils;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
@ -24,6 +27,7 @@ public class MqttDeviceComponent extends AbstractDeviceComponent {
|
|||
private String deployedId;
|
||||
private MqttVerticle mqttVerticle;
|
||||
private final Map<String, Device> deviceChildToParent = new HashMap<>();
|
||||
private TransparentConverter transparentConverter = new TransparentConverter();
|
||||
|
||||
public void create(CompConfig config) {
|
||||
super.create(config);
|
||||
|
@ -122,6 +126,22 @@ public class MqttDeviceComponent extends AbstractDeviceComponent {
|
|||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 透传解码
|
||||
*/
|
||||
public ThingModelMessage transparentDecode(Map<String, Object> msg) throws InvocationTargetException, IllegalAccessException {
|
||||
TransparentMsg transparentMsg = new TransparentMsg();
|
||||
BeanUtils.populate(transparentMsg, msg);
|
||||
return transparentConverter.decode(transparentMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 透传编码
|
||||
*/
|
||||
public DeviceMessage transparentEncode(ThingService<?> service, cc.iotkit.converter.Device device) {
|
||||
return transparentConverter.encode(service, device);
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Message {
|
||||
private String topic;
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
package cc.iotkit.comp.mqtt;
|
||||
|
||||
|
||||
import cc.iotkit.converter.Device;
|
||||
import cc.iotkit.converter.DeviceMessage;
|
||||
import cc.iotkit.converter.ThingService;
|
||||
import cc.iotkit.dao.DeviceCache;
|
||||
import cc.iotkit.dao.ProductCache;
|
||||
import cc.iotkit.model.device.DeviceInfo;
|
||||
import cc.iotkit.model.device.message.ThingModelMessage;
|
||||
import cc.iotkit.model.product.ProductModel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
public class TransparentConverter {
|
||||
|
||||
private final Map<String, IScripter> scripters = new HashMap<>();
|
||||
private final Map<String, String> scripts = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 透传解码
|
||||
*/
|
||||
public ThingModelMessage decode(TransparentMsg msg) {
|
||||
//通过上报消息中的model取得对应的产品
|
||||
String productKey = checkScriptUpdate(msg.getModel());
|
||||
msg.setProductKey(productKey);
|
||||
return scripters.get(productKey).decode(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 透传编码
|
||||
*/
|
||||
public DeviceMessage encode(ThingService<?> service, Device device) {
|
||||
String productKey = service.getProductKey();
|
||||
checkScriptUpdate(device.getModel());
|
||||
TransparentMsg transparentMsg = scripters.get(productKey).encode(service);
|
||||
//转换成网关消息
|
||||
String deviceName = service.getDeviceName();
|
||||
DeviceInfo gateway = getGatewayInfo(productKey, deviceName);
|
||||
DeviceMessage message = new DeviceMessage();
|
||||
message.setProductKey(gateway.getProductKey());
|
||||
message.setDeviceName(gateway.getDeviceName());
|
||||
message.setMid(transparentMsg.getMid());
|
||||
//透传格式消息内容,mac、model、data
|
||||
message.setContent(transparentMsg);
|
||||
return message;
|
||||
}
|
||||
|
||||
private ProductModel getScript(String model) {
|
||||
return ProductCache.getInstance().getProductScriptByModel(model);
|
||||
}
|
||||
|
||||
private DeviceInfo getGatewayInfo(String subPk, String subDn) {
|
||||
String parentId = DeviceCache.getInstance().getDeviceInfo(subPk, subDn).getParentId();
|
||||
return DeviceCache.getInstance().get(parentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查产品脚本是否更新
|
||||
*/
|
||||
private String checkScriptUpdate(String model) {
|
||||
ProductModel productModel = getScript(model);
|
||||
String productKey = productModel.getProductKey();
|
||||
String script = productModel.getScript();
|
||||
|
||||
String oldScript = scripts.get(productKey);
|
||||
if (script.equals(oldScript)) {
|
||||
return productKey;
|
||||
}
|
||||
|
||||
String type = productModel.getType();
|
||||
if (ProductModel.TYPE_LUA.equals(type)) {
|
||||
scripters.putIfAbsent(productKey, new LuaScripter());
|
||||
} else if (ProductModel.TYPE_JS.equals(type)) {
|
||||
scripters.putIfAbsent(productKey, new JsScripter());
|
||||
}
|
||||
|
||||
//更新脚本
|
||||
IScripter scripter = scripters.get(productKey);
|
||||
scripter.setScript(script);
|
||||
scripts.put(productKey, script);
|
||||
return productKey;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package cc.iotkit.comp.mqtt;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class TransparentMsg {
|
||||
|
||||
private String productKey;
|
||||
|
||||
/**
|
||||
* 生成给设备端的消息id
|
||||
*/
|
||||
private String mid;
|
||||
|
||||
private String model;
|
||||
|
||||
private String mac;
|
||||
|
||||
private String data;
|
||||
|
||||
}
|
|
@ -38,10 +38,10 @@ public class DeviceCondition {
|
|||
String[] pkDn = device.split("/");
|
||||
if (pkDn.length < 2) {
|
||||
//用deviceId取
|
||||
deviceInfo = deviceCache.findByDeviceId(device);
|
||||
deviceInfo = deviceCache.get(device);
|
||||
} else {
|
||||
//用pk/dn取
|
||||
deviceInfo = deviceCache.findByProductKeyAndDeviceName(pkDn[0], pkDn[1]);
|
||||
deviceInfo = deviceCache.getDeviceInfo(pkDn[0], pkDn[1]);
|
||||
}
|
||||
Object left = null;
|
||||
if ("property".equals(type)) {
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.0</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<source>11</source>
|
||||
<target>11</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
Loading…
Reference in New Issue