Commit e73eb81b0f7dfe83c06a4fd0fc4e46d48fed8fa4

Authored by xp.Huang
2 parents d46d9700 8492f88c

Merge branch 'TCP脚本转换' into 'master_dev'

refactor: TCP协议脚本转换实现方式调整

See merge request yunteng/thingskit!170
Showing 46 changed files with 1063 additions and 1207 deletions
... ... @@ -59,6 +59,7 @@ import org.thingsboard.server.common.data.widget.WidgetsBundle;
59 59 import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants;
60 60 import org.thingsboard.server.common.data.yunteng.core.exception.TkDataValidationException;
61 61 import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage;
  62 +import org.thingsboard.server.common.data.yunteng.enums.TkScriptFunctionType;
62 63 import org.thingsboard.server.dao.asset.AssetService;
63 64 import org.thingsboard.server.dao.attributes.AttributesService;
64 65 import org.thingsboard.server.dao.audit.AuditLogService;
... ... @@ -887,9 +888,9 @@ public abstract class BaseController {
887 888 * 构建设备配置的配置数据
888 889 * @param transportType 产品的通信协议
889 890 * @param deviceProfileData 空的设备配置数据
890   - * @param scriptText 自定义数据协议的解析脚本
  891 + * @return
891 892 */
892   - protected DeviceProfileData buildDeviceProfileData(String transportType,DeviceProfileData deviceProfileData,String scriptText) {
  893 + protected DeviceProfileData buildDeviceProfileData(String transportType,DeviceProfileData deviceProfileData) {
893 894 if(null == deviceProfileData){
894 895 deviceProfileData = new DeviceProfileData();
895 896 }
... ... @@ -899,10 +900,6 @@ public abstract class BaseController {
899 900 // 传输类型默认都是Default
900 901 if(transportType ==null || DeviceTransportType.DEFAULT.name().equals(transportType)){
901 902 deviceProfileData.setTransportConfiguration(new DefaultDeviceProfileTransportConfiguration());
902   - }else if(DeviceTransportType.TCP.name().equals(transportType)){
903   - TkTcpDeviceProfileTransportConfiguration tcpDeviceProfileTransportConfiguration = (TkTcpDeviceProfileTransportConfiguration) deviceProfileData.getTransportConfiguration();
904   - tcpDeviceProfileTransportConfiguration.setScriptText(scriptText);
905   - deviceProfileData.setTransportConfiguration(tcpDeviceProfileTransportConfiguration);
906 903 }else{
907 904 deviceProfileData.setTransportConfiguration(deviceProfileData.getTransportConfiguration());
908 905 }
... ... @@ -938,14 +935,16 @@ public abstract class BaseController {
938 935 DeviceProfile savedDeviceProfile =
939 936 checkNotNull(deviceProfileService.saveDeviceProfile(deviceProfile));
940 937
  938 + /**通知设备接入服务设备配置更新*/
941 939 tbClusterService.onDeviceProfileChange(savedDeviceProfile, null);
  940 + /**通知核心服务或规则引擎设备配置更新*/
942 941 tbClusterService.broadcastEntityStateChangeEvent(
943 942 deviceProfile.getTenantId(), savedDeviceProfile.getId(), ComponentLifecycleEvent.UPDATED);
944 943
945 944 logEntityAction(savedDeviceProfile.getId(), savedDeviceProfile, null, ActionType.UPDATED, null);
946 945
947 946 otaPackageStateService.update(savedDeviceProfile, isFirmwareChanged, isSoftwareChanged);
948   -
  947 + /**通知边缘服务设备配置更新*/
949 948 sendEntityNotificationMsg(
950 949 getTenantId(), savedDeviceProfile.getId(), EdgeEventActionType.UPDATED);
951 950 return savedDeviceProfile;
... ...
... ... @@ -32,7 +32,7 @@ import org.thingsboard.server.common.data.yunteng.enums.DeviceTypeEnum;
32 32 import org.thingsboard.server.common.data.yunteng.enums.OrderTypeEnum;
33 33 import org.thingsboard.server.common.data.yunteng.utils.tools.TkPageData;
34 34 import org.thingsboard.server.common.msg.queue.ServiceQueue;
35   -import org.thingsboard.server.common.yunteng.script.TkScriptFactory;
  35 +import org.thingsboard.server.transport.tcp.script.TkScriptFactory;
36 36 import org.thingsboard.server.controller.BaseController;
37 37 import org.thingsboard.server.dao.yunteng.service.TkDeviceScriptService;
38 38 import org.thingsboard.server.dao.yunteng.service.TkDeviceProfileService;
... ... @@ -293,17 +293,8 @@ public class TkDeviceProfileController extends BaseController {
293 293 tbDeviceProfile.setTransportType(DeviceTransportType.valueOf(transportType));
294 294 }
295 295
296   - if (DeviceTransportType.TCP.name().equals(transportType)) {
297   - TkTcpDeviceProfileTransportConfiguration tcpDeviceProfileTransportConfiguration =
298   - (TkTcpDeviceProfileTransportConfiguration)
299   - deviceProfileDTO.getProfileData().getTransportConfiguration();
300   - String scriptId = tcpDeviceProfileTransportConfiguration.getScriptId();
301   - scriptText = javaScriptService.getScriptText(deviceProfileDTO.getTenantId(), scriptId);
302   - deviceProfileDTO.setScriptId(scriptId);
303   - }
304   -
305 296 tbDeviceProfile.setProfileData(
306   - buildDeviceProfileData(transportType, deviceProfileDTO.getProfileData(), scriptText == null? TkScriptFactory.INCLUD_ORIGINAL_DATA:scriptText));
  297 + buildDeviceProfileData(transportType, deviceProfileDTO.getProfileData()));
307 298 return tbDeviceProfile;
308 299 }
309 300 }
... ...
... ... @@ -21,34 +21,32 @@ import org.thingsboard.server.common.data.DeviceProfile;
21 21 import org.thingsboard.server.common.data.DeviceProfileProvisionType;
22 22 import org.thingsboard.server.common.data.DeviceProfileType;
23 23 import org.thingsboard.server.common.data.DeviceTransportType;
24   -import org.thingsboard.server.common.data.audit.ActionType;
25   -import org.thingsboard.server.common.data.edge.EdgeEventActionType;
26 24 import org.thingsboard.server.common.data.exception.ThingsboardException;
27 25 import org.thingsboard.server.common.data.id.DeviceProfileId;
28 26 import org.thingsboard.server.common.data.id.RuleChainId;
29 27 import org.thingsboard.server.common.data.id.TenantId;
30   -import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
31 28 import org.thingsboard.server.common.data.yunteng.common.DeleteGroup;
32   -import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants;
33 29 import org.thingsboard.server.common.data.yunteng.core.exception.TkDataValidationException;
34 30 import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage;
35 31 import org.thingsboard.server.common.data.yunteng.dto.DeleteDTO;
36 32 import org.thingsboard.server.common.data.yunteng.dto.DeviceProfileDTO;
37 33 import org.thingsboard.server.common.data.yunteng.dto.TkDeviceScriptDTO;
38 34 import org.thingsboard.server.common.data.yunteng.enums.OrderTypeEnum;
  35 +import org.thingsboard.server.common.data.yunteng.enums.TkScriptFunctionType;
39 36 import org.thingsboard.server.common.data.yunteng.utils.tools.TkPageData;
40 37 import org.thingsboard.server.common.msg.queue.ServiceQueue;
41   -import org.thingsboard.server.common.yunteng.script.TkScriptFactory;
42   -import org.thingsboard.server.common.yunteng.script.TkScriptInvokeService;
43   -import org.thingsboard.server.common.yunteng.script.TkScriptType;
44 38 import org.thingsboard.server.controller.BaseController;
45 39 import org.thingsboard.server.dao.yunteng.service.TkDeviceProfileService;
46 40 import org.thingsboard.server.dao.yunteng.service.TkDeviceScriptService;
  41 +import org.thingsboard.server.transport.tcp.script.TkScriptInvokeService;
47 42
48 43 import java.sql.Timestamp;
49 44 import java.time.LocalDateTime;
50 45 import java.time.ZoneOffset;
51   -import java.util.*;
  46 +import java.util.HashMap;
  47 +import java.util.List;
  48 +import java.util.Map;
  49 +import java.util.UUID;
52 50 import java.util.concurrent.TimeUnit;
53 51
54 52 import static org.thingsboard.server.common.data.yunteng.constant.QueryConstant.*;
... ... @@ -58,210 +56,208 @@ import static org.thingsboard.server.common.data.yunteng.constant.QueryConstant.
58 56 @RequestMapping("api/yt/js")
59 57 @Api(tags = {"设备数据解析脚本管理"})
60 58 public class TkDeviceScriptController extends BaseController {
61   - private static final JsonParser parser = new JsonParser();
62   - private static final ObjectMapper objectMapper = new ObjectMapper();
63   - private final TkDeviceScriptService scriptService;
64   - private final TkDeviceProfileService ytDeviceProfileService;
65   - private final TkScriptInvokeService jsEngine;
  59 + private static final JsonParser parser = new JsonParser();
  60 + private static final ObjectMapper objectMapper = new ObjectMapper();
  61 + private final TkDeviceScriptService scriptService;
  62 + private final TkDeviceProfileService ytDeviceProfileService;
  63 + private final TkScriptInvokeService jsEngine;
66 64
67   - @PostMapping()
68   - @PreAuthorize("@check.checkPermissions({'TENANT_ADMIN'},{'api:yt:js:post','api:yt:js:update'})")
69   - @ApiOperation("创建 | 编辑")
70   - public ResponseEntity<TkDeviceScriptDTO> saveJavaScript(@RequestBody TkDeviceScriptDTO scriptDTO)
71   - throws ThingsboardException {
72   - String id = scriptDTO.getId();
73   - boolean created = StringUtils.isBlank(id);
74   - String tenantId = getCurrentUser().getCurrentTenantId();
75   - scriptDTO.setTenantId(tenantId);
76   - scriptService.validateFormdata(scriptDTO, created);
  65 + @PostMapping()
  66 + @PreAuthorize("@check.checkPermissions({'TENANT_ADMIN'},{'api:yt:js:post','api:yt:js:update'})")
  67 + @ApiOperation("创建 | 编辑")
  68 + public ResponseEntity<TkDeviceScriptDTO> saveJavaScript(@RequestBody TkDeviceScriptDTO scriptDTO)
  69 + throws ThingsboardException {
  70 + String id = scriptDTO.getId();
  71 + boolean created = StringUtils.isBlank(id);
  72 + String tenantId = getCurrentUser().getCurrentTenantId();
  73 + scriptDTO.setTenantId(tenantId);
  74 + scriptService.validateFormdata(scriptDTO, created);
77 75
78 76
79   - String creator = getCurrentUser().getCurrentUserId();
80   - scriptDTO.setCreator(creator);
81   - scriptDTO.setUpdater(creator);
82   - return ResponseEntity.ok(scriptService.insertOrUpdate(scriptDTO));
83   - }
84   -
85   - @PostMapping("/{id}/{status}")
86   - @PreAuthorize("@check.checkPermissions({'TENANT_ADMIN'},{'api:yt:js:post','api:yt:js:update:status'})")
87   - @ApiOperation("修改脚本状态")
88   - public ResponseEntity<Boolean> updateScriptStatus(
89   - @PathVariable("id") String id, @PathVariable("status") Integer status)
90   - throws ThingsboardException {
91   - /** 业务流程 1/3.编辑时同步刷新相关的设备配置 2/3.处理TB业务逻辑 3/3.处理业务平台的业务逻辑 */
92   - String tenantId = getCurrentUser().getCurrentTenantId();
93   - TkDeviceScriptDTO scriptDTO = scriptService.getDeviceScript(tenantId,id).get();
94   - if(scriptDTO ==null || scriptDTO.getStatus().equals(status)){
95   - return ResponseEntity.ok(false);
  77 + String creator = getCurrentUser().getCurrentUserId();
  78 + scriptDTO.setCreator(creator);
  79 + scriptDTO.setUpdater(creator);
  80 + return ResponseEntity.ok(scriptService.insertOrUpdate(scriptDTO));
96 81 }
97   - String convertJs = TkScriptFactory.INCLUD_ORIGINAL_DATA;
98 82
99   - if(1 == status){
100   - if(scriptDTO.isSaveOriginalData()){
101   - convertJs += scriptDTO.getConvertJs();
102   - }else{
103   - convertJs = scriptDTO.getConvertJs();
104   - }
105   - }
106   - List<DeviceProfileDTO> usedProfiles = ytDeviceProfileService.findDeviceProfile(tenantId, id,null);
107   - for (DeviceProfileDTO profile : usedProfiles) {
108   - DeviceProfile tbDeviceProfile =
109   - buildTbDeviceProfileFromDeviceProfileDTO(
110   - profile, tenantId, convertJs);
111   - updateTbDeviceProfile(tbDeviceProfile);
  83 + @PostMapping("/{id}/{status}")
  84 + @PreAuthorize("@check.checkPermissions({'TENANT_ADMIN'},{'api:yt:js:post','api:yt:js:update:status'})")
  85 + @ApiOperation("修改脚本状态")
  86 + public ResponseEntity<Boolean> updateScriptStatus(
  87 + @PathVariable("id") String id, @PathVariable("status") Integer status)
  88 + throws ThingsboardException {
  89 + /** 业务流程 1/3.编辑时同步刷新相关的设备配置 2/3.处理TB业务逻辑 3/3.处理业务平台的业务逻辑 */
  90 + String tenantId = getCurrentUser().getCurrentTenantId();
  91 + TkDeviceScriptDTO scriptDTO = scriptService.getDeviceScript(tenantId, id).get();
  92 + if (scriptDTO == null || scriptDTO.getStatus().equals(status)) {
  93 + return ResponseEntity.ok(false);
  94 + }
  95 +
  96 + /**脚本引擎启用/禁用时,刷新规则引擎中缓存的脚本ID对应的脚本内容,禁用时为默认脚本*/
  97 +// List<DeviceProfileDTO> usedProfiles = ytDeviceProfileService.findDeviceProfile(tenantId, id,null);
  98 +// for (DeviceProfileDTO profile : usedProfiles) {
  99 +// DeviceProfile tbDeviceProfile =
  100 +// buildTbDeviceProfileFromDeviceProfileDTO(
  101 +// profile, id,scriptDTO.getScriptType());
  102 +// updateTbDeviceProfile(tbDeviceProfile);
  103 +// }
  104 +
  105 + scriptService.updateScriptStatus(tenantId, id, status);
  106 + return ResponseEntity.ok(true);
112 107 }
113   - scriptService.updateScriptStatus(tenantId, id, status);
114   - return ResponseEntity.ok(true);
115   - }
116 108
117 109
118   - @GetMapping("{id}")
119   - @ApiOperation("详情")
120   - @PreAuthorize("@check.checkPermissions({'TENANT_ADMIN','CUSTOMER_USER'},{'api:yt:js:get'})")
121   - public ResponseEntity<TkDeviceScriptDTO> getDevice(@PathVariable("id") String id)
122   - throws ThingsboardException {
123   - return ResponseEntity.of(
124   - scriptService.getDeviceScript(getCurrentUser().getCurrentTenantId(), id));
125   - }
  110 + @GetMapping("{id}")
  111 + @ApiOperation("详情")
  112 + @PreAuthorize("@check.checkPermissions({'TENANT_ADMIN','CUSTOMER_USER'},{'api:yt:js:get'})")
  113 + public ResponseEntity<TkDeviceScriptDTO> getDevice(@PathVariable("id") String id)
  114 + throws ThingsboardException {
  115 + return ResponseEntity.of(
  116 + scriptService.getDeviceScript(getCurrentUser().getCurrentTenantId(), id));
  117 + }
  118 +
  119 + @GetMapping(params = {PAGE_SIZE, PAGE})
  120 + @ApiOperation("分页查询")
  121 + @PreAuthorize("@check.checkPermissions({'TENANT_ADMIN','CUSTOMER_USER'},{})")
  122 + public TkPageData<TkDeviceScriptDTO> pageDeviceScript(
  123 + @RequestParam(PAGE_SIZE) int pageSize,
  124 + @RequestParam(PAGE) int page,
  125 + @RequestParam(value = ORDER_FILED, required = false) String orderFiled,
  126 + @RequestParam(value = ORDER_TYPE, required = false) OrderTypeEnum orderType,
  127 + @RequestParam(value = "name", required = false) String name,
  128 + @RequestParam(value = "startTime", required = false) Long startTime,
  129 + @RequestParam(value = "endTime", required = false) Long endTime)
  130 + throws ThingsboardException {
  131 + Map<String, Object> queryMap = new HashMap<>();
  132 + queryMap.put(PAGE_SIZE, pageSize);
  133 + queryMap.put(PAGE, page);
  134 + queryMap.put(ORDER_FILED, orderFiled);
  135 + queryMap.put(ORDER_TYPE, orderType);
  136 + queryMap.put(CUSTOMER_ID, getCurrentUser().getCustomerId().toString());
  137 + queryMap.put(TENANT_ID, getCurrentUser().getCurrentTenantId());
126 138
127   - @GetMapping(params = {PAGE_SIZE, PAGE})
128   - @ApiOperation("分页查询")
129   - @PreAuthorize("@check.checkPermissions({'TENANT_ADMIN','CUSTOMER_USER'},{})")
130   - public TkPageData<TkDeviceScriptDTO> pageDeviceScript(
131   - @RequestParam(PAGE_SIZE) int pageSize,
132   - @RequestParam(PAGE) int page,
133   - @RequestParam(value = ORDER_FILED, required = false) String orderFiled,
134   - @RequestParam(value = ORDER_TYPE, required = false) OrderTypeEnum orderType,
135   - @RequestParam(value = "name", required = false) String name,
136   - @RequestParam(value = "startTime", required = false) Long startTime,
137   - @RequestParam(value = "endTime", required = false) Long endTime)
138   - throws ThingsboardException {
139   - Map<String, Object> queryMap = new HashMap<>();
140   - queryMap.put(PAGE_SIZE, pageSize);
141   - queryMap.put(PAGE, page);
142   - queryMap.put(ORDER_FILED, orderFiled);
143   - queryMap.put(ORDER_TYPE, orderType);
144   - queryMap.put(CUSTOMER_ID, getCurrentUser().getCustomerId().toString());
145   - queryMap.put(TENANT_ID, getCurrentUser().getCurrentTenantId());
  139 + if (!StringUtils.isEmpty(name)) {
  140 + queryMap.put("name", name);
  141 + }
  142 + if (null != startTime && null != endTime) {
  143 + if (startTime > endTime) {
  144 + throw new TkDataValidationException(
  145 + ErrorMessage.START_TIME_NOT_MORE_THAN_END_TIME.getMessage());
  146 + }
  147 + queryMap.put("startTime", new Timestamp(startTime).toLocalDateTime());
  148 + queryMap.put("endTime", new Timestamp(endTime).toLocalDateTime());
  149 + }
146 150
147   - if(!StringUtils.isEmpty(name)){
148   - queryMap.put("name", name);
  151 + return scriptService.page(queryMap, getCurrentUser().isTenantAdmin());
149 152 }
150   - if(null != startTime && null!=endTime){
151   - if (startTime > endTime) {
152   - throw new TkDataValidationException(
153   - ErrorMessage.START_TIME_NOT_MORE_THAN_END_TIME.getMessage());
154   - }
155   - queryMap.put("startTime", new Timestamp(startTime).toLocalDateTime());
156   - queryMap.put("endTime", new Timestamp(endTime).toLocalDateTime());
  153 +
  154 + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
  155 + @GetMapping("/me/list")
  156 + @ApiOperation("选项列表")
  157 + public ResponseEntity listDeviceScript() throws ThingsboardException {
  158 + List<TkDeviceScriptDTO> results =
  159 + scriptService.findDeviceScript(getCurrentUser().getCurrentTenantId());
  160 + return ResponseEntity.ok(results);
157 161 }
158 162
159   - return scriptService.page(queryMap, getCurrentUser().isTenantAdmin());
160   - }
  163 + @DeleteMapping
  164 + @ApiOperation("删除")
  165 + @PreAuthorize("@check.checkPermissions({'TENANT_ADMIN'},{'api:yt:js:delete'})")
  166 + public void deleteDevices(@Validated({DeleteGroup.class}) @RequestBody DeleteDTO deleteDTO)
  167 + throws ThingsboardException {
  168 + scriptService.deleteScriptes(getCurrentUser().getCurrentTenantId(), deleteDTO.getIds());
  169 + }
161 170
162   - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
163   - @GetMapping("/me/list")
164   - @ApiOperation("选项列表")
165   - public ResponseEntity listDeviceScript() throws ThingsboardException {
166   - List<TkDeviceScriptDTO> results =
167   - scriptService.findDeviceScript(getCurrentUser().getCurrentTenantId());
168   - return ResponseEntity.ok(results);
169   - }
  171 + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
  172 + @PostMapping("/test")
  173 + @ApiOperation("测试脚本执行结果")
  174 + public ResponseEntity<JsonNode> test(@RequestBody JsonNode inputParams)
  175 + throws ThingsboardException {
  176 + try {
  177 + String script = inputParams.get("script").asText();
  178 + String scriptType = inputParams.get("scriptType").asText();
  179 + String jsParam = inputParams.get("params").asText();
170 180
171   - @DeleteMapping
172   - @ApiOperation("删除")
173   - @PreAuthorize("@check.checkPermissions({'TENANT_ADMIN'},{'api:yt:js:delete'})")
174   - public void deleteDevices(@Validated({DeleteGroup.class}) @RequestBody DeleteDTO deleteDTO)
175   - throws ThingsboardException {
176   - scriptService.deleteScriptes(getCurrentUser().getCurrentTenantId(), deleteDTO.getIds());
177   - }
  181 + String output = "";
  182 + String errorText = "";
  183 + ScriptEngine engine = null;
  184 + try {
  185 + TkScriptFunctionType functionType = TkScriptFunctionType.valueOf(scriptType);
  186 + UUID scriptId = jsEngine.eval(null, functionType, script).get();
178 187
179   - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
180   - @PostMapping("/test")
181   - @ApiOperation("测试脚本执行结果")
182   - public ResponseEntity<JsonNode> test(@RequestBody JsonNode inputParams)
183   - throws ThingsboardException {
184   - try {
185   - String script = inputParams.get("script").asText();
186   - String jsParam = inputParams.get("params").asText();
187 188
188   - String output = "";
189   - String errorText = "";
190   - ScriptEngine engine = null;
191   - try {
192   - UUID scriptId = jsEngine.eval(TkScriptType.TCP_TRANSPORT_SCRIPT, script).get();
193   - ListenableFuture<String> result =
194   - Futures.transformAsync(
195   - jsEngine.invokeFunction(scriptId, jsParam),
196   - o -> {
197   - try {
198   - JsonElement json = parser.parse(o.toString());
199   - return Futures.immediateFuture(json.toString());
200   - } catch (Exception e) {
201   - return Futures.immediateFailedFuture(e);
202   - }
203   - },
204   - MoreExecutors.directExecutor());
  189 + ListenableFuture<String> result =
  190 + Futures.transformAsync(
  191 + jsEngine.invokeFunction(scriptId, jsParam),
  192 + o -> {
  193 + try {
  194 + JsonElement json = parser.parse(o.toString());
  195 + return Futures.immediateFuture(json.toString());
  196 + } catch (Exception e) {
  197 + return Futures.immediateFailedFuture(e);
  198 + }
  199 + },
  200 + MoreExecutors.directExecutor());
205 201
206   - output = result.get(20, TimeUnit.SECONDS);
207   - } catch (Exception e) {
208   - errorText = e.getMessage();
209   - } finally {
210   - if (engine != null) {
211   - engine.destroy();
  202 + output = result.get(20, TimeUnit.SECONDS);
  203 + jsEngine.release(scriptId);
  204 + } catch (Exception e) {
  205 + errorText = e.getMessage();
  206 + } finally {
  207 + if (engine != null) {
  208 + engine.destroy();
  209 + }
  210 + }
  211 + ObjectNode result = objectMapper.createObjectNode();
  212 + result.put("output", output);
  213 + result.put("error", errorText);
  214 + return ResponseEntity.ok(result);
  215 + } catch (Exception e) {
  216 + throw handleException(e);
212 217 }
213   - }
214   - ObjectNode result = objectMapper.createObjectNode();
215   - result.put("output", output);
216   - result.put("error", errorText);
217   - return ResponseEntity.ok(result);
218   - } catch (Exception e) {
219   - throw handleException(e);
220 218 }
221   - }
222 219
223   - /**
224   - * 构造调用TBDeviceProfile需要的参数
225   - *
226   - * @param deviceProfileDTO 页面接收的参数
227   - * @return 封装好的TBDeviceProfile
228   - */
229   - private DeviceProfile buildTbDeviceProfileFromDeviceProfileDTO(
230   - DeviceProfileDTO deviceProfileDTO, String scriptId, String scriptText) {
231   - DeviceProfile tbDeviceProfile = new DeviceProfile();
232   - if (StringUtils.isNotBlank(deviceProfileDTO.getId())) {
233   - UUID profileId = UUID.fromString(deviceProfileDTO.getTbProfileId());
234   - tbDeviceProfile.setId(new DeviceProfileId(profileId));
235   - tbDeviceProfile.setCreatedTime(
236   - deviceProfileDTO.getCreateTime().toInstant(ZoneOffset.of("+8")).toEpochMilli());
237   - } else {
238   - tbDeviceProfile.setCreatedTime(
239   - LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli());
240   - }
241   - tbDeviceProfile.setName(deviceProfileDTO.getName());
242   - tbDeviceProfile.setImage(deviceProfileDTO.getImage());
243   - tbDeviceProfile.setDescription(deviceProfileDTO.getDescription());
244   - tbDeviceProfile.setType(DeviceProfileType.DEFAULT);
245   - UUID tenantId = UUID.fromString(deviceProfileDTO.getTenantId());
246   - tbDeviceProfile.setTenantId(TenantId.fromUUID(tenantId));
247   - tbDeviceProfile.setDefault(deviceProfileDTO.isDefault());
  220 + /**
  221 + * 构造调用TBDeviceProfile需要的参数
  222 + *
  223 + * @param deviceProfileDTO 页面接收的参数
  224 + * @return 封装好的TBDeviceProfile
  225 + */
  226 + private DeviceProfile buildTbDeviceProfileFromDeviceProfileDTO(
  227 + DeviceProfileDTO deviceProfileDTO, String scriptId, TkScriptFunctionType scriptType) {
  228 + DeviceProfile tbDeviceProfile = new DeviceProfile();
  229 + if (StringUtils.isNotBlank(deviceProfileDTO.getId())) {
  230 + UUID profileId = UUID.fromString(deviceProfileDTO.getTbProfileId());
  231 + tbDeviceProfile.setId(new DeviceProfileId(profileId));
  232 + tbDeviceProfile.setCreatedTime(
  233 + deviceProfileDTO.getCreateTime().toInstant(ZoneOffset.of("+8")).toEpochMilli());
  234 + } else {
  235 + tbDeviceProfile.setCreatedTime(
  236 + LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli());
  237 + }
  238 + tbDeviceProfile.setName(deviceProfileDTO.getName());
  239 + tbDeviceProfile.setImage(deviceProfileDTO.getImage());
  240 + tbDeviceProfile.setDescription(deviceProfileDTO.getDescription());
  241 + tbDeviceProfile.setType(DeviceProfileType.DEFAULT);
  242 + UUID tenantId = UUID.fromString(deviceProfileDTO.getTenantId());
  243 + tbDeviceProfile.setTenantId(TenantId.fromUUID(tenantId));
  244 + tbDeviceProfile.setDefault(deviceProfileDTO.isDefault());
248 245
249   - // 获取当前租户的默认规则链
250   - if (StringUtils.isNotBlank(deviceProfileDTO.getDefaultRuleChainId())) {
251   - UUID chainId = UUID.fromString(deviceProfileDTO.getDefaultRuleChainId());
252   - tbDeviceProfile.setDefaultRuleChainId(new RuleChainId(chainId));
253   - }
  246 + // 获取当前租户的默认规则链
  247 + if (StringUtils.isNotBlank(deviceProfileDTO.getDefaultRuleChainId())) {
  248 + UUID chainId = UUID.fromString(deviceProfileDTO.getDefaultRuleChainId());
  249 + tbDeviceProfile.setDefaultRuleChainId(new RuleChainId(chainId));
  250 + }
254 251
255   - tbDeviceProfile.setDefaultQueueName(ServiceQueue.MAIN);
256   - tbDeviceProfile.setProvisionType(DeviceProfileProvisionType.DISABLED);
  252 + tbDeviceProfile.setDefaultQueueName(ServiceQueue.MAIN);
  253 + tbDeviceProfile.setProvisionType(DeviceProfileProvisionType.DISABLED);
257 254
258   - // 传输类型默认都是Default
259   - String transportType = deviceProfileDTO.getTransportType();
260   - tbDeviceProfile.setTransportType(DeviceTransportType.valueOf(transportType));
  255 + // 传输类型默认都是Default
  256 + String transportType = deviceProfileDTO.getTransportType();
  257 + tbDeviceProfile.setTransportType(DeviceTransportType.valueOf(transportType));
261 258
262   - deviceProfileDTO.setScriptId(scriptId);
263   - tbDeviceProfile.setProfileData(
264   - buildDeviceProfileData(transportType, deviceProfileDTO.getProfileData(), scriptText));
265   - return tbDeviceProfile;
266   - }
  259 + tbDeviceProfile.setProfileData(
  260 + buildDeviceProfileData(transportType, deviceProfileDTO.getProfileData()));
  261 + return tbDeviceProfile;
  262 + }
267 263 }
... ...
... ... @@ -61,6 +61,8 @@ import org.thingsboard.server.common.data.relation.EntityRelation;
61 61 import org.thingsboard.server.common.data.security.DeviceCredentials;
62 62 import org.thingsboard.server.common.data.security.DeviceCredentialsType;
63 63 import org.thingsboard.server.common.data.yunteng.dto.DeviceDTO;
  64 +import org.thingsboard.server.common.data.yunteng.dto.TkDeviceScriptDTO;
  65 +import org.thingsboard.server.common.data.yunteng.enums.TkScriptFunctionType;
64 66 import org.thingsboard.server.common.msg.EncryptionUtil;
65 67 import org.thingsboard.server.common.msg.TbMsg;
66 68 import org.thingsboard.server.common.msg.TbMsgDataType;
... ... @@ -75,6 +77,7 @@ import org.thingsboard.server.dao.device.provision.ProvisionResponse;
75 77 import org.thingsboard.server.dao.ota.OtaPackageService;
76 78 import org.thingsboard.server.dao.relation.RelationService;
77 79 import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
  80 +import org.thingsboard.server.dao.yunteng.service.TkDeviceScriptService;
78 81 import org.thingsboard.server.dao.yunteng.service.TkDeviceService;
79 82 import org.thingsboard.server.gen.transport.TransportProtos;
80 83 import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto;
... ... @@ -102,6 +105,8 @@ import org.thingsboard.server.service.install.DefaultSystemDataLoaderService;
102 105 import org.thingsboard.server.service.profile.TbDeviceProfileCache;
103 106 import org.thingsboard.server.service.resource.TbResourceService;
104 107
  108 +import java.util.Arrays;
  109 +import java.util.List;
105 110 import java.util.Optional;
106 111 import java.util.UUID;
107 112 import java.util.concurrent.ConcurrentHashMap;
... ... @@ -129,6 +134,7 @@ public class DefaultTransportApiService implements TransportApiService {
129 134 private final TbApiUsageStateService apiUsageStateService;
130 135 private final DeviceService deviceService;
131 136 private final TkDeviceService ytDeviceService;
  137 + private final TkDeviceScriptService scriptService;
132 138 private final RelationService relationService;
133 139 private final DeviceCredentialsService deviceCredentialsService;
134 140 private final DbCallbackExecutorService dbCallbackExecutorService;
... ... @@ -182,6 +188,12 @@ public class DefaultTransportApiService implements TransportApiService {
182 188 result = handle(transportApiRequestMsg.getOtaPackageRequestMsg());
183 189 }
184 190
  191 + //Thingskit function
  192 + else if (transportApiRequestMsg.hasScript()) {
  193 + result = handle(transportApiRequestMsg.getScript());
  194 + }
  195 +
  196 +
185 197 return Futures.transform(Optional.ofNullable(result).orElseGet(this::getEmptyTransportApiResponseFuture),
186 198 value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()),
187 199 MoreExecutors.directExecutor());
... ... @@ -279,25 +291,21 @@ public class DefaultTransportApiService implements TransportApiService {
279 291 Lock deviceCreationLock = deviceCreationLocks.computeIfAbsent(requestMsg.getDeviceName(), id -> new ReentrantLock());
280 292 deviceCreationLock.lock();
281 293 try {
  294 + Device device = deviceService.findDeviceByTenantIdAndName(gateway.getTenantId(), requestMsg.getDeviceName());
  295 +
  296 + if (device == null) {
  297 +
282 298
283   - //Thingskit function
284   - String slaveName = requestMsg.getDeviceName();
285   - if(gateway.getDeviceData().getTransportConfiguration().getType() == DeviceTransportType.TCP) {
286   - DeviceDTO iotDev = ytDeviceService.findSlaveDevice(gateway.getTenantId().getId().toString()
287   - , gateway.getId().getId().toString()
288   - ,requestMsg.getDeviceName());
289   - if(iotDev == null ){
  299 +
  300 + //Thingskit function
  301 + if(gateway.getDeviceData().getTransportConfiguration().getType() == DeviceTransportType.TCP) {
290 302 GetOrCreateDeviceFromGatewayResponseMsg.Builder builder = GetOrCreateDeviceFromGatewayResponseMsg.newBuilder();
291 303 return TransportApiResponseMsg.newBuilder()
292 304 .setGetOrCreateDeviceResponseMsg(builder.build())
293 305 .build();
294 306 }
295   - slaveName = iotDev.getName();
296   - }
297 307
298   - Device device = deviceService.findDeviceByTenantIdAndName(gateway.getTenantId(), slaveName);
299 308
300   - if (device == null) {
301 309 TenantId tenantId = gateway.getTenantId();
302 310 device = new Device();
303 311 device.setTenantId(tenantId);
... ... @@ -666,4 +674,35 @@ public class DefaultTransportApiService implements TransportApiService {
666 674 private Long checkLong(Long l) {
667 675 return l != null ? l : 0;
668 676 }
  677 +
  678 +
  679 +
  680 + //Thingskit function
  681 + private ListenableFuture<TransportApiResponseMsg> handle(TransportProtos.ScriptProto requestMsg) {
  682 +
  683 + int type = requestMsg.getFunctionType();
  684 + UUID scriptId = getUUID(requestMsg.getScriptIdLSB(),requestMsg.getScriptIdMSB());
  685 +
  686 + List<TkDeviceScriptDTO> allScriptes = scriptService.getScriptes(Arrays.stream(TkScriptFunctionType.values()).filter(f->f.ordinal()==type).findFirst().get(),null,null,scriptId);
  687 + TransportApiResponseMsg.Builder responseBuilder = TransportApiResponseMsg.newBuilder();
  688 + allScriptes.forEach(item->{
  689 + UUID tenantId = UUID.fromString(item.getTenantId());
  690 + UUID id = UUID.fromString(item.getId());
  691 + responseBuilder.addScriptsResponseMsg(TransportProtos.ScriptProto.newBuilder()
  692 + .setConvertJs(item.getConvertJs())
  693 + .setTenantIdLSB(tenantId.getLeastSignificantBits())
  694 + .setTenantIdMSB(tenantId.getMostSignificantBits())
  695 + .setScriptIdLSB(id.getLeastSignificantBits())
  696 + .setScriptIdMSB(id.getMostSignificantBits())
  697 + .setFunctionType(item.getScriptType().ordinal())
  698 + );
  699 + });
  700 + return Futures.immediateFuture(responseBuilder.build());
  701 + }
  702 + private UUID getUUID(long lsb,long msb){
  703 + if(lsb==0 && msb==0){
  704 + return null;
  705 + }
  706 + return new UUID(msb,lsb);
  707 + }
669 708 }
... ...
... ... @@ -679,6 +679,9 @@ message TransportApiRequestMsg {
679 679 GetSnmpDevicesRequestMsg snmpDevicesRequestMsg = 11;
680 680 GetDeviceRequestMsg deviceRequestMsg = 12;
681 681 GetDeviceCredentialsRequestMsg deviceCredentialsRequestMsg = 13;
  682 +
  683 + //Thingskit function
  684 + ScriptProto script = 14;
682 685 }
683 686
684 687 /* Response from ThingsBoard Core Service to Transport Service */
... ... @@ -693,6 +696,9 @@ message TransportApiResponseMsg {
693 696 GetOtaPackageResponseMsg otaPackageResponseMsg = 8;
694 697 GetDeviceResponseMsg deviceResponseMsg = 9;
695 698 GetDeviceCredentialsResponseMsg deviceCredentialsResponseMsg = 10;
  699 +
  700 + //Thingskit function
  701 + repeated ScriptProto scriptsResponseMsg = 11;
696 702 }
697 703
698 704 /* Messages that are handled by ThingsBoard Core Service */
... ... @@ -769,3 +775,22 @@ message ToOtaPackageStateServiceMsg {
769 775 int64 otaPackageIdLSB = 7;
770 776 string type = 8;
771 777 }
  778 +
  779 +
  780 +
  781 +
  782 +
  783 +
  784 +
  785 +
  786 +//Thingskit function 请求:functionType、;响应:tenantId、projectId、scriptId、convertJs
  787 +message ScriptProto{
  788 + int64 tenantIdMSB = 1;
  789 + int64 tenantIdLSB = 2;
  790 +// int64 projectIdMSB = 3;
  791 +// int64 projectIdLSB = 4;
  792 + int64 scriptIdMSB = 5;
  793 + int64 scriptIdLSB = 6;
  794 + int32 functionType = 7;
  795 + string convertJs = 8;
  796 +}
... ...
1   -/**
2   - * Copyright © 2016-2022 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16 1 package org.thingsboard.server.common.data.device.profile;
17 2
18 3 import lombok.Data;
19 4 import org.thingsboard.server.common.data.DeviceTransportType;
20 5 import org.thingsboard.server.common.data.validation.NoXss;
21   -import org.thingsboard.server.common.data.yunteng.enums.TcpDataTypeEnum;
22 6
23 7 @Data
24 8 public class TkTcpDeviceProfileTransportConfiguration implements DeviceProfileTransportConfiguration {
25   -
26   - @NoXss
27   - private TcpDataTypeEnum dataFormat = TcpDataTypeEnum.HEX;
28   - private String scriptId;
29   - private String scriptText;
30   -// private String pingText;
  9 + /**
  10 + * 鉴权脚本ID:解析脚本鉴权信息,正确解析结果如下:
  11 + * clientId: 设备鉴权客户端ID
  12 + * userName: 设备鉴权用户名
  13 + * password: 设备鉴权密码
  14 + * success :鉴权成功返回内容
  15 + */
31 16 @NoXss
32   - private String telemetryTopic = "03";
  17 + private String authScriptId;
  18 + /**
  19 + * 上行脚本ID:设备推送给平台
  20 + */
33 21 @NoXss
34   - private String attributesTopic = "01";
  22 + private String upScriptId;
  23 + /**
  24 + * 下行脚本ID:平台推送给设备
  25 + */
35 26 @NoXss
36   - private String rpcTopic = "05";
  27 + private String downScriptId;
  28 +
37 29 @Override
38 30 public DeviceTransportType getType() {
39 31 return DeviceTransportType.TCP;
40 32 }
41 33
42 34
43   -
44   -
45 35 }
... ...
... ... @@ -31,9 +31,7 @@ public class DeviceProfileDTO extends BaseDTO {
31 31 @ApiModelProperty(value = "描述")
32 32 private String description;
33 33
34   - /** TCP协议的解析脚本ID,由后端自己回填 */
35   - @ApiModelProperty(value = "解析脚本ID")
36   - private String scriptId;
  34 +
37 35
38 36 @ApiModelProperty(value = "租户ID")
39 37 private String tenantId;
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto;
  2 +
  3 +import io.swagger.annotations.ApiModelProperty;
  4 +import lombok.Data;
  5 +
  6 +import javax.validation.constraints.NotEmpty;
  7 +import java.io.Serializable;
  8 +import java.util.Map;
  9 +
  10 +
  11 +@Data
  12 +public class TkDeviceRpcDTO implements Serializable {
  13 +
  14 + @ApiModelProperty(value = "命令下发方法名、功能名")
  15 + @NotEmpty(message = "功能名不能为空或者空字符串")
  16 + private String method;
  17 +
  18 + @ApiModelProperty(value = "设备名称。添加设备时,设备名称的内容必须与脚本用到的设备标识一致。")
  19 + @NotEmpty(message = "设备名称不能为空或者空字符串")
  20 + private String deviceCode;
  21 +
  22 + @ApiModelProperty(value = "数据校验算法")
  23 + private String check;
  24 +
  25 + @ApiModelProperty(value = "数据相关信息,例如:寄存器地址和寄存器数")
  26 + @NotEmpty(message = "数据相关信息不能为空或者空字符串")
  27 + private Map<String, Object> params;
  28 +}
... ...
... ... @@ -5,7 +5,7 @@ import lombok.Data;
5 5 import lombok.EqualsAndHashCode;
6 6 import org.thingsboard.server.common.data.yunteng.common.AddGroup;
7 7 import org.thingsboard.server.common.data.yunteng.common.UpdateGroup;
8   -import org.thingsboard.server.common.data.yunteng.enums.TcpDataTypeEnum;
  8 +import org.thingsboard.server.common.data.yunteng.enums.TkScriptFunctionType;
9 9
10 10 import javax.validation.constraints.NotEmpty;
11 11 import javax.validation.constraints.NotNull;
... ... @@ -14,36 +14,37 @@ import javax.validation.constraints.NotNull;
14 14 @Data
15 15 public class TkDeviceScriptDTO extends BaseDTO {
16 16
17   - @ApiModelProperty(value = "解析脚本名称")
18   - @NotEmpty(
19   - message = "解析脚本名称不能为空或者空字符串",
20   - groups = {AddGroup.class, UpdateGroup.class})
21   - private String name;
  17 + @ApiModelProperty(value = "解析脚本名称")
  18 + @NotEmpty(
  19 + message = "解析脚本名称不能为空或者空字符串",
  20 + groups = {AddGroup.class, UpdateGroup.class})
  21 + private String name;
22 22
23   - @ApiModelProperty(value = "租户ID")
24   - private String tenantId;
  23 + @ApiModelProperty(value = "租户ID")
  24 + private String tenantId;
25 25
26   - @ApiModelProperty(value = "脚本描述")
27   - private String description;
  26 + @ApiModelProperty(value = "脚本描述")
  27 + private String description;
28 28
29   - @ApiModelProperty(value = "解析脚本方法体内容")
30   - @NotEmpty(
31   - message = "解析脚本内容不能为空或者空字符串",
32   - groups = {AddGroup.class, UpdateGroup.class})
33   - private String convertJs;
  29 + @ApiModelProperty(value = "解析脚本方法体内容")
  30 + @NotEmpty(
  31 + message = "解析脚本内容不能为空或者空字符串",
  32 + groups = {AddGroup.class, UpdateGroup.class})
  33 + private String convertJs;
34 34
35   - @ApiModelProperty(value = "状态:0禁用 1启用")
36   - @NotNull(message = "状态不能为空", groups = UpdateGroup.class)
37   - private Integer status;
  35 + @ApiModelProperty(value = "状态:0禁用 1启用")
  36 + @NotNull(message = "状态不能为空", groups = UpdateGroup.class)
  37 + private Integer status;
38 38
39   - @ApiModelProperty(value = "脚本编数据编码类型:HEX ASCII")
40   - private TcpDataTypeEnum dataType;
  39 + @ApiModelProperty(value = "脚本类型:AUTHENTICATION、SERVER_TO_DEVICE、DEVICE_TO_SERVER")
  40 + private TkScriptFunctionType scriptType;
41 41
42   - @ApiModelProperty(value = "保存原始数据:默认false")
43   - @NotNull(
44   - message = "保存原始数据不能为空",
45   - groups = {AddGroup.class})
46   - private boolean saveOriginalData;
  42 + @ApiModelProperty(value = "保存原始数据:默认false")
  43 + @NotNull(
  44 + message = "保存原始数据不能为空",
  45 + groups = {AddGroup.class})
  46 + private boolean saveOriginalData;
47 47
48   - public TkDeviceScriptDTO() {}
  48 + public TkDeviceScriptDTO() {
  49 + }
49 50 }
... ...
1   -package org.thingsboard.server.common.data.yunteng.enums;
2   -
3   -/**
4   - * 编码类型
5   - */
6   -public enum TcpDataTypeEnum {
7   - HEX,
8   - JSON,
9   - ASCII
10   -}
  1 +package org.thingsboard.server.common.data.yunteng.enums;
  2 +
  3 +public enum TkScriptFunctionType {
  4 + TRANSPORT_TCP_AUTH,
  5 + //var attrData = {};attrData.source= params;out.attributes = attrData;var teleData = {};teleData.source= params;out.telemetries = teleData;out.ackMsg = params;out.deviceName = params;out.ts = Date.now();
  6 + TRANSPORT_TCP_UP,
  7 + TRANSPORT_TCP_DOWN,
  8 + RULE_ENGINE_TRANSFORM
  9 +}
... ...
... ... @@ -25,6 +25,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
25 25 import org.springframework.stereotype.Component;
26 26 import org.thingsboard.server.common.transport.TransportContext;
27 27 import org.thingsboard.server.transport.tcp.adaptors.JsonTcpAdaptor;
  28 +import org.thingsboard.server.transport.tcp.script.TkScriptInvokeService;
28 29
29 30 import javax.annotation.PostConstruct;
30 31 import java.net.InetSocketAddress;
... ... @@ -47,6 +48,9 @@ public class TcpTransportContext extends TransportContext {
47 48 @Autowired
48 49 private JsonTcpAdaptor jsonTcpAdaptor;
49 50
  51 + @Getter
  52 + @Autowired
  53 + private TkScriptInvokeService jsEngine;
50 54
51 55 @Getter
52 56 @Value("${transport.tcp.netty.max_payload_size}")
... ...
1 1 /**
2 2 * Copyright © 2016-2022 The Thingsboard Authors
3   - *
  3 + * <p>
4 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 5 * you may not use this file except in compliance with the License.
6 6 * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
  7 + * <p>
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + * <p>
10 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
12 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
... ... @@ -16,6 +16,10 @@
16 16 package org.thingsboard.server.transport.tcp;
17 17
18 18 import com.fasterxml.jackson.databind.JsonNode;
  19 +import com.google.common.util.concurrent.FutureCallback;
  20 +import com.google.common.util.concurrent.Futures;
  21 +import com.google.common.util.concurrent.ListenableFuture;
  22 +import com.google.common.util.concurrent.MoreExecutors;
19 23 import io.netty.buffer.ByteBuf;
20 24 import io.netty.buffer.Unpooled;
21 25 import io.netty.channel.ChannelFuture;
... ... @@ -28,16 +32,16 @@ import io.netty.util.concurrent.Future;
28 32 import io.netty.util.concurrent.GenericFutureListener;
29 33 import lombok.extern.slf4j.Slf4j;
30 34 import org.apache.commons.lang3.StringUtils;
  35 +import org.checkerframework.checker.nullness.qual.Nullable;
  36 +import org.thingsboard.common.util.JacksonUtil;
31 37 import org.thingsboard.server.common.data.DataConstants;
32 38 import org.thingsboard.server.common.data.Device;
33 39 import org.thingsboard.server.common.data.DeviceProfile;
34 40 import org.thingsboard.server.common.data.DeviceTransportType;
  41 +import org.thingsboard.server.common.data.device.profile.TkTcpDeviceProfileTransportConfiguration;
35 42 import org.thingsboard.server.common.data.id.DeviceId;
36   -import org.thingsboard.server.common.data.id.OtaPackageId;
37   -import org.thingsboard.server.common.data.ota.OtaPackageType;
38 43 import org.thingsboard.server.common.data.rpc.RpcStatus;
39   -import org.thingsboard.server.common.data.yunteng.enums.TcpDataTypeEnum;
40   -import org.thingsboard.server.common.msg.EncryptionUtil;
  44 +import org.thingsboard.server.common.data.yunteng.enums.TkScriptFunctionType;
41 45 import org.thingsboard.server.common.msg.tools.TbRateLimitsException;
42 46 import org.thingsboard.server.common.transport.SessionMsgListener;
43 47 import org.thingsboard.server.common.transport.TransportService;
... ... @@ -48,31 +52,28 @@ import org.thingsboard.server.common.transport.auth.TransportDeviceInfo;
48 52 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
49 53 import org.thingsboard.server.common.transport.service.DefaultTransportService;
50 54 import org.thingsboard.server.common.transport.service.SessionMetaData;
51   -import org.thingsboard.server.common.transport.util.SslUtil;
52 55 import org.thingsboard.server.gen.transport.TransportProtos;
53   -import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg;
  56 +import org.thingsboard.server.gen.transport.TransportProtos.ScriptProto;
  57 +import org.thingsboard.server.transport.tcp.adaptors.TcpAuthEntry;
54 58 import org.thingsboard.server.transport.tcp.adaptors.TcpTransportAdaptor;
  59 +import org.thingsboard.server.transport.tcp.adaptors.TcpUpEntry;
  60 +import org.thingsboard.server.transport.tcp.script.TkScriptFactory;
55 61 import org.thingsboard.server.transport.tcp.session.TcpDeviceSessionCtx;
56   -import org.thingsboard.server.transport.tcp.session.TCPMessage;
57 62 import org.thingsboard.server.transport.tcp.session.TcpGatewaySessionHandler;
58 63 import org.thingsboard.server.transport.tcp.util.ByteUtils;
59 64
60   -import javax.net.ssl.SSLPeerUnverifiedException;
61 65 import java.io.IOException;
62 66 import java.io.UnsupportedEncodingException;
63 67 import java.net.InetSocketAddress;
64   -import java.security.cert.Certificate;
65   -import java.security.cert.X509Certificate;
66 68 import java.util.List;
  69 +import java.util.Map;
67 70 import java.util.Optional;
68 71 import java.util.UUID;
69 72 import java.util.concurrent.ConcurrentHashMap;
70 73 import java.util.concurrent.ConcurrentMap;
71   -import java.util.regex.Matcher;
  74 +import java.util.concurrent.atomic.AtomicInteger;
72 75
73   -import static com.amazonaws.util.StringUtils.UTF8;
74 76 import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_ACCEPTED;
75   -import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_REFUSED_NOT_AUTHORIZED;
76 77 import static io.netty.handler.codec.mqtt.MqttMessageType.PUBACK;
77 78 import static io.netty.handler.codec.mqtt.MqttMessageType.SUBACK;
78 79 import static io.netty.handler.codec.mqtt.MqttQoS.AT_MOST_ONCE;
... ... @@ -92,7 +93,9 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements
92 93 private final SslHandler sslHandler;
93 94
94 95
95   - /**需要处理的消息队列,例如:需要下发给设备的,设备上传的。*/
  96 + /**
  97 + * 需要处理的消息队列,例如:需要下发给设备的,设备上传的。
  98 + */
96 99 final TcpDeviceSessionCtx deviceSessionCtx;
97 100 volatile InetSocketAddress address;
98 101
... ... @@ -100,7 +103,8 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements
100 103 private final ConcurrentHashMap<String, String> otaPackSessions;
101 104 private final ConcurrentHashMap<String, Integer> chunkSizes;
102 105 private final ConcurrentMap<Integer, TransportProtos.ToDeviceRpcRequestMsg> rpcAwaitingAck;
103   -
  106 + private final ConcurrentMap<UUID, String> authScripts;
  107 + private final AtomicInteger authedCounter = new AtomicInteger();
104 108
105 109
106 110 TcpTransportHandler(TcpTransportContext context, SslHandler sslHandler) {
... ... @@ -112,6 +116,22 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements
112 116 this.otaPackSessions = new ConcurrentHashMap<>();
113 117 this.chunkSizes = new ConcurrentHashMap<>();
114 118 this.rpcAwaitingAck = new ConcurrentHashMap<>();
  119 + this.authScripts = new ConcurrentHashMap<>();
  120 + List<ScriptProto> authScripts = this.transportService.getScripts(ScriptProto.newBuilder().setFunctionType(TkScriptFunctionType.TRANSPORT_TCP_AUTH.ordinal()).build());
  121 + authScripts.stream().forEach(i -> {
  122 + UUID scriptId = new UUID(i.getScriptIdMSB(), i.getScriptIdLSB());
  123 + deviceSessionCtx.cacheScript(scriptId, TkScriptFunctionType.TRANSPORT_TCP_AUTH, i.getConvertJs(), new FutureCallback<UUID>() {
  124 + @Override
  125 + public void onSuccess(@Nullable UUID result) {
  126 + TcpTransportHandler.this.authScripts.put(scriptId, result.toString());
  127 + }
  128 +
  129 + @Override
  130 + public void onFailure(Throwable t) {
  131 + }
  132 + });
  133 +
  134 + });
115 135 }
116 136
117 137 @Override
... ... @@ -136,12 +156,13 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements
136 156 if (msg instanceof ByteBuf) {
137 157 ByteBuf message = (ByteBuf) msg;
138 158 byte[] byteMsg = ByteUtils.buf2Bytes(message);
139   -
  159 + String msgStr = ByteUtils.getString(byteMsg, ByteUtils.UTF_8);
  160 + log.error("会话【{}】收到设备【{}】来自【{}】数据【{}】", sessionId, deviceSessionCtx.getDeviceId(), address, msgStr);
140 161 deviceSessionCtx.setChannel(ctx);
141   - if (deviceSessionCtx.getDeviceInfo() == null || deviceSessionCtx.getDeviceProfile() == null) {
142   - processConnect(ctx, ByteUtils.getString(byteMsg, ByteUtils.UTF_8));
  162 + if (deviceSessionCtx.getDeviceInfo() == null || deviceSessionCtx.getDeviceProfile() == null) {
  163 + processConnect(ctx, msgStr);
143 164 } else {
144   - enqueueRegularSessionMsg(ctx,message);
  165 + enqueueRegularSessionMsg(ctx, msgStr);
145 166 }
146 167
147 168 } else {
... ... @@ -167,9 +188,7 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements
167 188 }
168 189
169 190
170   -
171   -
172   - void enqueueRegularSessionMsg(ChannelHandlerContext ctx, ByteBuf msg) {
  191 + void enqueueRegularSessionMsg(ChannelHandlerContext ctx, String msg) {
173 192 final int queueSize = deviceSessionCtx.getMsgQueueSize();
174 193 if (queueSize >= context.getMessageQueueSizePerDeviceLimit()) {
175 194 log.info("Closing current session because msq queue size for device {} exceed limit {} with msgQueueSize counter {} and actual queue size {}",
... ... @@ -178,14 +197,12 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements
178 197 return;
179 198 }
180 199
181   - TCPMessage message =deviceSessionCtx.getPayloadAdaptor().createTcpMessage(deviceSessionCtx,msg);
182   - deviceSessionCtx.addToQueue(message);
  200 + deviceSessionCtx.addToQueue(msg);
183 201 processQueueMessage(ctx); //Under the normal conditions the msg queue will contain 0 messages. Many messages will be processed on device connect event in separate thread pool
184 202
185 203 }
186 204
187 205
188   -
189 206 void processQueueMessage(ChannelHandlerContext ctx) {
190 207 if (!deviceSessionCtx.isConnected()) {
191 208 log.trace("[{}][{}] Postpone processing msg due to device is not connected. Msg queue size is {}", sessionId, deviceSessionCtx.getDeviceId(), deviceSessionCtx.getMsgQueueSize());
... ... @@ -195,128 +212,81 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements
195 212 }
196 213
197 214
  215 + private void processDeviceSessionMsg(ChannelHandlerContext ctx, String tcpMessage) {
  216 + if (!checkConnected(ctx, tcpMessage)) {
  217 + return;
  218 + }
  219 + deviceSessionCtx.doUpScript(tcpMessage, r -> {
  220 + if (gatewaySessionHandler != null) {
  221 + processGatewayDeviceMsg(ctx, r);
198 222
  223 + if (!hasDatas(r.getDatas(), true)) {
  224 + transportService.reportActivity(deviceSessionCtx.getSessionInfo());
  225 + return;
  226 + }
  227 + }
199 228
200 229
  230 + processDirectDeviceMsg(ctx, r);
  231 + });
201 232
202   - private void processDeviceSessionMsg(ChannelHandlerContext ctx, TCPMessage tcpMessage) {
203   - if (!checkConnected(ctx, tcpMessage)) {
204   - return;
  233 + }
  234 +
  235 +
  236 + private boolean hasDatas(Map<String, Object> datas, boolean includeSource) {
  237 + if (datas == null || datas.isEmpty()) {
  238 + return false;
205 239 }
206   - log.error("【{}】设备【{}】收到数据【{}】", sessionId,deviceSessionCtx.getDeviceId(), tcpMessage.getMessage());
207   - if (!deviceSessionCtx.getDeviceCode().equals(tcpMessage.getMessage()) && gatewaySessionHandler != null) {
208   - processGatewayDeviceMsg(ctx, tcpMessage);
209   - transportService.reportActivity(deviceSessionCtx.getSessionInfo());
210   - } else {
211   - processDirectDeviceMsg(ctx,tcpMessage);
  240 + if (includeSource && !datas.containsKey(TkScriptFactory.ORIGINAL_DATA_FILED)) {
  241 + return false;
212 242 }
  243 + return true;
213 244 }
214 245
215 246
216   - private void processGatewayDeviceMsg(ChannelHandlerContext ctx, TCPMessage tcpMessage) {
217   - log.trace("[{}][{}] Processing publish msg [{}]!", sessionId, deviceSessionCtx.getDeviceId(), tcpMessage.getMessage());
  247 + private void processGatewayDeviceMsg(ChannelHandlerContext ctx, TcpUpEntry tcpMessage) {
  248 + log.trace("[{}][{}] Processing publish msg [{}]!", sessionId, deviceSessionCtx.getDeviceId(), tcpMessage);
218 249 try {
219   - String topicName = tcpMessage.getTopic();
220   - if (deviceSessionCtx.isDeviceAttributesTopic(topicName)) {
221   - gatewaySessionHandler.onDeviceAttributes(tcpMessage);
222   - } else if (deviceSessionCtx.isDeviceTelemetryTopic(topicName)) {
223   - gatewaySessionHandler.onDeviceTelemetry(tcpMessage);
224   -
225   - } else if (deviceSessionCtx.isToDeviceRpcResponseTopic(topicName)) {
  250 + Map<String, Object> datas = tcpMessage.getDatas();
  251 + if (hasDatas(datas, false)) {
  252 + datas.forEach((devName, param) -> {
  253 + if (TkScriptFactory.ORIGINAL_DATA_FILED.equals(devName)) {
  254 + return;
  255 + }
  256 + if (tcpMessage.getTelemetry()) {
  257 + gatewaySessionHandler.onDeviceTelemetry(devName, tcpMessage.getRequestId(), param.toString());
  258 + } else {
  259 + gatewaySessionHandler.onDeviceAttributes(devName, tcpMessage.getRequestId(), param.toString());
  260 + }
226 261
  262 + });
227 263 } else {
228 264 transportService.reportActivity(deviceSessionCtx.getSessionInfo());
229   - pushDeviceMsg(ctx,tcpMessage);
  265 + pushDeviceMsg(ctx, tcpMessage.getAckMsg());
230 266 }
231   - } catch (AdaptorException e) {
  267 + } catch (Exception e) {
232 268 log.debug("[{}] Failed to process publish msg [{}][{}]", sessionId, tcpMessage, e);
233 269 ctx.close();
234 270 }
235 271 }
236 272
237   - private void processDirectDeviceMsg(ChannelHandlerContext ctx, TCPMessage tcpMessage) {
238   - log.trace("[{}][{}] Processing publish msg [{}]!", sessionId, deviceSessionCtx.getDeviceId(), tcpMessage.getMessage());
  273 + private void processDirectDeviceMsg(ChannelHandlerContext ctx, TcpUpEntry tcpMessage) {
  274 + log.trace("[{}][{}] Processing publish msg [{}]!", sessionId, deviceSessionCtx.getDeviceId(), tcpMessage);
239 275 try {
240   - String topicName = tcpMessage.getTopic();
241 276 TcpTransportAdaptor payloadAdaptor = deviceSessionCtx.getPayloadAdaptor();
242   - if (deviceSessionCtx.isDeviceAttributesTopic(topicName)) {
243   -// TransportProtos.PostAttributeMsg postAttributeMsg = payloadAdaptor.convertToPostAttributes(deviceSessionCtx, tcpMessage.getMessage());
244   -// transportService.process(deviceSessionCtx.getSessionInfo(), postAttributeMsg, getPubAckCallback(ctx, tcpMessage.getRequestId(), postAttributeMsg));
245   - } else if (deviceSessionCtx.isDeviceTelemetryTopic(topicName)) {
246   - TransportProtos.PostTelemetryMsg postTelemetryMsg = payloadAdaptor.convertToPostTelemetry(deviceSessionCtx, tcpMessage.getMessage());
247   - transportService.process(deviceSessionCtx.getSessionInfo(), postTelemetryMsg, null);
248   -// } else if (topicName.startsWith(MqttTopics.DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX)) {
249   -// TransportProtos.GetAttributeRequestMsg getAttributeMsg = payloadAdaptor.convertToGetAttributes(deviceSessionCtx, mqttMsg, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX);
250   -// transportService.process(deviceSessionCtx.getSessionInfo(), getAttributeMsg, getPubAckCallback(ctx, msgId, getAttributeMsg));
251   -// attrReqTopicType = TopicType.V1;
252   - } else if (deviceSessionCtx.isToDeviceRpcResponseTopic(topicName)) {
253   -// TransportProtos.ToDeviceRpcResponseMsg rpcResponseMsg = payloadAdaptor.convertToDeviceRpcResponse(deviceSessionCtx, tcpMessage.getMessage(), MqttTopics.DEVICE_RPC_RESPONSE_TOPIC);
254   -// transportService.process(deviceSessionCtx.getSessionInfo(), rpcResponseMsg, getPubAckCallback(ctx, msgId, rpcResponseMsg));
255   -// } else if (topicName.startsWith(MqttTopics.DEVICE_RPC_REQUESTS_TOPIC)) {
256   -// TransportProtos.ToServerRpcRequestMsg rpcRequestMsg = payloadAdaptor.convertToServerRpcRequest(deviceSessionCtx, mqttMsg, MqttTopics.DEVICE_RPC_REQUESTS_TOPIC);
257   -// transportService.process(deviceSessionCtx.getSessionInfo(), rpcRequestMsg, getPubAckCallback(ctx, msgId, rpcRequestMsg));
258   -// toServerRpcSubTopicType = TopicType.V1;
259   -// } else if (topicName.equals(MqttTopics.DEVICE_CLAIM_TOPIC)) {
260   -// TransportProtos.ClaimDeviceMsg claimDeviceMsg = payloadAdaptor.convertToClaimDevice(deviceSessionCtx, mqttMsg);
261   -// transportService.process(deviceSessionCtx.getSessionInfo(), claimDeviceMsg, getPubAckCallback(ctx, msgId, claimDeviceMsg));
262   -// } else if ((fwMatcher = FW_REQUEST_PATTERN.matcher(topicName)).find()) {
263   -// getOtaPackageCallback(ctx, mqttMsg, msgId, fwMatcher, OtaPackageType.FIRMWARE);
264   -// } else if ((fwMatcher = SW_REQUEST_PATTERN.matcher(topicName)).find()) {
265   -// getOtaPackageCallback(ctx, mqttMsg, msgId, fwMatcher, OtaPackageType.SOFTWARE);
266   -// } else if (topicName.equals(MqttTopics.DEVICE_TELEMETRY_SHORT_TOPIC)) {
267   -// TransportProtos.PostTelemetryMsg postTelemetryMsg = payloadAdaptor.convertToPostTelemetry(deviceSessionCtx, mqttMsg);
268   -// transportService.process(deviceSessionCtx.getSessionInfo(), postTelemetryMsg, getPubAckCallback(ctx, msgId, postTelemetryMsg));
269   -// } else if (topicName.equals(MqttTopics.DEVICE_TELEMETRY_SHORT_JSON_TOPIC)) {
270   -// TransportProtos.PostTelemetryMsg postTelemetryMsg = context.getJsonMqttAdaptor().convertToPostTelemetry(deviceSessionCtx, mqttMsg);
271   -// transportService.process(deviceSessionCtx.getSessionInfo(), postTelemetryMsg, getPubAckCallback(ctx, msgId, postTelemetryMsg));
272   -// } else if (topicName.equals(MqttTopics.DEVICE_TELEMETRY_SHORT_PROTO_TOPIC)) {
273   -// TransportProtos.PostTelemetryMsg postTelemetryMsg = context.getAscallAdaptor().convertToPostTelemetry(deviceSessionCtx, mqttMsg);
274   -// transportService.process(deviceSessionCtx.getSessionInfo(), postTelemetryMsg, getPubAckCallback(ctx, msgId, postTelemetryMsg));
275   -// } else if (topicName.equals(MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC)) {
276   -// TransportProtos.PostAttributeMsg postAttributeMsg = payloadAdaptor.convertToPostAttributes(deviceSessionCtx, mqttMsg);
277   -// transportService.process(deviceSessionCtx.getSessionInfo(), postAttributeMsg, getPubAckCallback(ctx, msgId, postAttributeMsg));
278   -// } else if (topicName.equals(MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC)) {
279   -// TransportProtos.PostAttributeMsg postAttributeMsg = context.getJsonMqttAdaptor().convertToPostAttributes(deviceSessionCtx, mqttMsg);
280   -// transportService.process(deviceSessionCtx.getSessionInfo(), postAttributeMsg, getPubAckCallback(ctx, msgId, postAttributeMsg));
281   -// } else if (topicName.equals(MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC)) {
282   -// TransportProtos.PostAttributeMsg postAttributeMsg = context.getAscallAdaptor().convertToPostAttributes(deviceSessionCtx, mqttMsg);
283   -// transportService.process(deviceSessionCtx.getSessionInfo(), postAttributeMsg, getPubAckCallback(ctx, msgId, postAttributeMsg));
284   -// } else if (topicName.startsWith(MqttTopics.DEVICE_RPC_RESPONSE_SHORT_JSON_TOPIC)) {
285   -// TransportProtos.ToDeviceRpcResponseMsg rpcResponseMsg = context.getJsonMqttAdaptor().convertToDeviceRpcResponse(deviceSessionCtx, mqttMsg, MqttTopics.DEVICE_RPC_RESPONSE_SHORT_JSON_TOPIC);
286   -// transportService.process(deviceSessionCtx.getSessionInfo(), rpcResponseMsg, getPubAckCallback(ctx, msgId, rpcResponseMsg));
287   -// } else if (topicName.startsWith(MqttTopics.DEVICE_RPC_RESPONSE_SHORT_PROTO_TOPIC)) {
288   -// TransportProtos.ToDeviceRpcResponseMsg rpcResponseMsg = context.getAscallAdaptor().convertToDeviceRpcResponse(deviceSessionCtx, mqttMsg, MqttTopics.DEVICE_RPC_RESPONSE_SHORT_PROTO_TOPIC);
289   -// transportService.process(deviceSessionCtx.getSessionInfo(), rpcResponseMsg, getPubAckCallback(ctx, msgId, rpcResponseMsg));
290   -// } else if (topicName.startsWith(MqttTopics.DEVICE_RPC_RESPONSE_SHORT_TOPIC)) {
291   -// TransportProtos.ToDeviceRpcResponseMsg rpcResponseMsg = payloadAdaptor.convertToDeviceRpcResponse(deviceSessionCtx, mqttMsg, MqttTopics.DEVICE_RPC_RESPONSE_SHORT_TOPIC);
292   -// transportService.process(deviceSessionCtx.getSessionInfo(), rpcResponseMsg, getPubAckCallback(ctx, msgId, rpcResponseMsg));
293   -// } else if (topicName.startsWith(MqttTopics.DEVICE_RPC_REQUESTS_SHORT_JSON_TOPIC)) {
294   -// TransportProtos.ToServerRpcRequestMsg rpcRequestMsg = context.getJsonMqttAdaptor().convertToServerRpcRequest(deviceSessionCtx, mqttMsg, MqttTopics.DEVICE_RPC_REQUESTS_SHORT_JSON_TOPIC);
295   -// transportService.process(deviceSessionCtx.getSessionInfo(), rpcRequestMsg, getPubAckCallback(ctx, msgId, rpcRequestMsg));
296   -// toServerRpcSubTopicType = TopicType.V2_JSON;
297   -// } else if (topicName.startsWith(MqttTopics.DEVICE_RPC_REQUESTS_SHORT_PROTO_TOPIC)) {
298   -// TransportProtos.ToServerRpcRequestMsg rpcRequestMsg = context.getAscallAdaptor().convertToServerRpcRequest(deviceSessionCtx, mqttMsg, MqttTopics.DEVICE_RPC_REQUESTS_SHORT_PROTO_TOPIC);
299   -// transportService.process(deviceSessionCtx.getSessionInfo(), rpcRequestMsg, getPubAckCallback(ctx, msgId, rpcRequestMsg));
300   -// toServerRpcSubTopicType = TopicType.V2_PROTO;
301   -// } else if (topicName.startsWith(MqttTopics.DEVICE_RPC_REQUESTS_SHORT_TOPIC)) {
302   -// TransportProtos.ToServerRpcRequestMsg rpcRequestMsg = payloadAdaptor.convertToServerRpcRequest(deviceSessionCtx, mqttMsg, MqttTopics.DEVICE_RPC_REQUESTS_SHORT_TOPIC);
303   -// transportService.process(deviceSessionCtx.getSessionInfo(), rpcRequestMsg, getPubAckCallback(ctx, msgId, rpcRequestMsg));
304   -// toServerRpcSubTopicType = TopicType.V2;
305   -// } else if (topicName.startsWith(MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_JSON_TOPIC_PREFIX)) {
306   -// TransportProtos.GetAttributeRequestMsg getAttributeMsg = context.getJsonMqttAdaptor().convertToGetAttributes(deviceSessionCtx, mqttMsg, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_JSON_TOPIC_PREFIX);
307   -// transportService.process(deviceSessionCtx.getSessionInfo(), getAttributeMsg, getPubAckCallback(ctx, msgId, getAttributeMsg));
308   -// attrReqTopicType = TopicType.V2_JSON;
309   -// } else if (topicName.startsWith(MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_PROTO_TOPIC_PREFIX)) {
310   -// TransportProtos.GetAttributeRequestMsg getAttributeMsg = context.getAscallAdaptor().convertToGetAttributes(deviceSessionCtx, mqttMsg, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_PROTO_TOPIC_PREFIX);
311   -// transportService.process(deviceSessionCtx.getSessionInfo(), getAttributeMsg, getPubAckCallback(ctx, msgId, getAttributeMsg));
312   -// attrReqTopicType = TopicType.V2_PROTO;
313   -// } else if (topicName.startsWith(MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_TOPIC_PREFIX)) {
314   -// TransportProtos.GetAttributeRequestMsg getAttributeMsg = payloadAdaptor.convertToGetAttributes(deviceSessionCtx, mqttMsg, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_TOPIC_PREFIX);
315   -// transportService.process(deviceSessionCtx.getSessionInfo(), getAttributeMsg, getPubAckCallback(ctx, msgId, getAttributeMsg));
316   -// attrReqTopicType = TopicType.V2;
  277 + Map<String, Object> datas = tcpMessage.getDatas();
  278 + if (hasDatas(datas, false)) {
  279 + String dataStr = JacksonUtil.toString(datas);
  280 + if (tcpMessage.getTelemetry()) {
  281 + TransportProtos.PostTelemetryMsg postTelemetryMsg = payloadAdaptor.convertToPostTelemetry(deviceSessionCtx, dataStr);
  282 + transportService.process(deviceSessionCtx.getSessionInfo(), postTelemetryMsg, getPubAckCallback(ctx, tcpMessage));
  283 + } else {
  284 + TransportProtos.PostAttributeMsg postAttributeMsg = payloadAdaptor.convertToPostAttributes(deviceSessionCtx, dataStr);
  285 + transportService.process(deviceSessionCtx.getSessionInfo(), postAttributeMsg, getPubAckCallback(ctx, tcpMessage));
  286 + }
317 287 } else {
318 288 transportService.reportActivity(deviceSessionCtx.getSessionInfo());
319   - pushDeviceMsg(ctx,tcpMessage);
  289 + pushDeviceMsg(ctx, tcpMessage.getAckMsg());
320 290 }
321 291 } catch (AdaptorException e) {
322 292 log.debug("[{}] Failed to process publish msg [{}][{}]", sessionId, tcpMessage, e);
... ... @@ -324,50 +294,14 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements
324 294 }
325 295 }
326 296
327   - private void getOtaPackageCallback(ChannelHandlerContext ctx, MqttPublishMessage mqttMsg, int msgId, Matcher fwMatcher, OtaPackageType type) {
328   - String payload = mqttMsg.content().toString(UTF8);
329   - int chunkSize = StringUtils.isNotEmpty(payload) ? Integer.parseInt(payload) : 0;
330   - String requestId = fwMatcher.group("requestId");
331   - int chunk = Integer.parseInt(fwMatcher.group("chunk"));
332   -
333   - if (chunkSize > 0) {
334   - this.chunkSizes.put(requestId, chunkSize);
335   - } else {
336   - chunkSize = chunkSizes.getOrDefault(requestId, 0);
337   - }
338   -
339   - if (chunkSize > context.getMaxPayloadSize()) {
340   -// sendOtaPackageError(ctx, PAYLOAD_TOO_LARGE);
341   - return;
342   - }
343   -
344   - String otaPackageId = otaPackSessions.get(requestId);
345   -
346   - if (otaPackageId != null) {
347   - sendOtaPackage(ctx, mqttMsg.variableHeader().packetId(), otaPackageId, requestId, chunkSize, chunk, type);
348   - } else {
349   - TransportProtos.SessionInfoProto sessionInfo = deviceSessionCtx.getSessionInfo();
350   - TransportProtos.GetOtaPackageRequestMsg getOtaPackageRequestMsg = TransportProtos.GetOtaPackageRequestMsg.newBuilder()
351   - .setDeviceIdMSB(sessionInfo.getDeviceIdMSB())
352   - .setDeviceIdLSB(sessionInfo.getDeviceIdLSB())
353   - .setTenantIdMSB(sessionInfo.getTenantIdMSB())
354   - .setTenantIdLSB(sessionInfo.getTenantIdLSB())
355   - .setType(type.name())
356   - .build();
357   - transportService.process(deviceSessionCtx.getSessionInfo(), getOtaPackageRequestMsg,
358   - new OtaPackageCallback(ctx, msgId, getOtaPackageRequestMsg, requestId, chunkSize, chunk));
359   - }
360   - }
361   -
362   -
363 297
364   - private <T> TransportServiceCallback<Void> getPubAckCallback(final ChannelHandlerContext ctx, final String msgId, final TCPMessage msg) {
  298 + private <T> TransportServiceCallback<Void> getPubAckCallback(final ChannelHandlerContext ctx, final TcpUpEntry msg) {
365 299 return new TransportServiceCallback<>() {
366 300 @Override
367 301 public void onSuccess(Void dummy) {
368 302 log.trace("[{}] Published msg: {}", sessionId, msg);
369   - if(StringUtils.isNotEmpty(msgId)){
370   - pushDeviceMsg(ctx,msg);
  303 + if (StringUtils.isNotEmpty(msg.getAckMsg())) {
  304 + pushDeviceMsg(ctx, msg.getAckMsg());
371 305 }
372 306 }
373 307
... ... @@ -380,138 +314,63 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements
380 314 }
381 315
382 316
383   - private class OtaPackageCallback implements TransportServiceCallback<TransportProtos.GetOtaPackageResponseMsg> {
384   - private final ChannelHandlerContext ctx;
385   - private final int msgId;
386   - private final TransportProtos.GetOtaPackageRequestMsg msg;
387   - private final String requestId;
388   - private final int chunkSize;
389   - private final int chunk;
390   -
391   - OtaPackageCallback(ChannelHandlerContext ctx, int msgId, TransportProtos.GetOtaPackageRequestMsg msg, String requestId, int chunkSize, int chunk) {
392   - this.ctx = ctx;
393   - this.msgId = msgId;
394   - this.msg = msg;
395   - this.requestId = requestId;
396   - this.chunkSize = chunkSize;
397   - this.chunk = chunk;
398   - }
399   -
400   - @Override
401   - public void onSuccess(TransportProtos.GetOtaPackageResponseMsg response) {
402   - if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())) {
403   - OtaPackageId firmwareId = new OtaPackageId(new UUID(response.getOtaPackageIdMSB(), response.getOtaPackageIdLSB()));
404   - otaPackSessions.put(requestId, firmwareId.toString());
405   - sendOtaPackage(ctx, msgId, firmwareId.toString(), requestId, chunkSize, chunk, OtaPackageType.valueOf(response.getType()));
406   - } else {
407   -// sendOtaPackageError(ctx, response.getResponseStatus().toString());
408   - }
409   - }
410   -
411   - @Override
412   - public void onError(Throwable e) {
413   - log.trace("[{}] Failed to get firmware: {}", sessionId, msg, e);
414   - ctx.close();
415   - }
416   - }
417   -
418   - private void sendOtaPackage(ChannelHandlerContext ctx, int msgId, String firmwareId, String requestId, int chunkSize, int chunk, OtaPackageType type) {
419   - log.trace("[{}] Send firmware [{}] to device!", sessionId, firmwareId);
420   - pushDeviceMsg(ctx,new TCPMessage(requestId));
421   - try {
422   - byte[] firmwareChunk = context.getOtaPackageDataCache().get(firmwareId, chunkSize, chunk);
423   - deviceSessionCtx.getPayloadAdaptor()
424   - .convertToPublish(deviceSessionCtx, firmwareChunk, requestId, chunk, type)
425   - .ifPresent(deviceSessionCtx.getChannel()::writeAndFlush);
426   - } catch (Exception e) {
427   - log.trace("[{}] Failed to send firmware response!", sessionId, e);
428   - }
429   - }
430   -
431   -
432   -
433 317 void processConnect(ChannelHandlerContext ctx, String accessToken) {
434 318 log.debug("[{}][{}] Processing connect msg for client: {}!", address, sessionId, accessToken);
435 319
436 320 if (DataConstants.PROVISION.equals(accessToken) || DataConstants.PROVISION.equals(accessToken)) {
437 321 deviceSessionCtx.setProvisionOnly(true);
438   - ctx.writeAndFlush(createTcpConnAckMsg(CONNECTION_ACCEPTED));
  322 + ctx.writeAndFlush(createTcpConnAckMsg(CONNECTION_ACCEPTED.name()));
439 323 } else {
440   - X509Certificate cert;
441   - if (sslHandler != null && (cert = getX509Certificate()) != null) {
442   -// processX509CertConnect(ctx, cert, msg);
443   - } else {
444   - processAuthTokenConnect(ctx, accessToken);
445   - }
  324 + authScripts.forEach((id, idStr) -> {
  325 + ListenableFuture item = context.getJsEngine().invokeFunction(id, accessToken);
  326 + Futures.addCallback(item, new FutureCallback<String>() {
  327 + @Override
  328 + public void onSuccess(@Nullable String result) {
  329 + processAuthTokenConnect(ctx, id, JacksonUtil.fromString(result, TcpAuthEntry.class));
  330 + }
  331 +
  332 + @Override
  333 + public void onFailure(Throwable t) {
  334 + onValidateFailed(ctx, MqttConnectReturnCode.CONNECTION_REFUSED_PAYLOAD_FORMAT_INVALID);
  335 + }
  336 + }, MoreExecutors.directExecutor());
  337 +
  338 + });
446 339 }
447 340 }
448 341
449   - private void processAuthTokenConnect(ChannelHandlerContext ctx, String accessToken) {
  342 + private void processAuthTokenConnect(ChannelHandlerContext ctx, UUID scriptId, TcpAuthEntry accessToken) {
450 343
451 344 log.debug("[{}][{}] Processing connect msg for client with user name: {}!", address, sessionId, accessToken);
452   - TransportProtos.ValidateDeviceTokenRequestMsg.Builder request = TransportProtos.ValidateDeviceTokenRequestMsg.newBuilder()
453   - .setToken(accessToken);
  345 + TransportProtos.ValidateDeviceTokenRequestMsg.Builder request = TransportProtos.ValidateDeviceTokenRequestMsg.newBuilder();
  346 + if (null != accessToken.getClientId()) {
  347 + }
  348 + if (null != accessToken.getUserName()) {
  349 + }
  350 + if (null == accessToken.getPassword()) {
  351 + onValidateFailed(ctx, MqttConnectReturnCode.CONNECTION_REFUSED_PAYLOAD_FORMAT_INVALID);
  352 + return;
  353 + }
  354 + request.setToken(accessToken.getPassword());
454 355
455 356 transportService.process(DeviceTransportType.TCP, request.build(),
456 357 new TransportServiceCallback<>() {
457 358 @Override
458 359 public void onSuccess(ValidateDeviceCredentialsResponse msg) {
459   - onValidateDeviceResponse(msg, ctx);
  360 + onValidateDeviceResponse(msg, ctx, accessToken, scriptId);
460 361 }
461 362
462 363 @Override
463 364 public void onError(Throwable e) {
464 365 log.trace("[{}] Failed to process credentials: {}", address, accessToken, e);
465   - ctx.writeAndFlush(createTcpConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE));
466   - ctx.close();
  366 + onValidateFailed(ctx, MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE);
467 367 }
468 368 });
469 369 }
470 370
471   - private void processX509CertConnect(ChannelHandlerContext ctx, X509Certificate cert, MqttConnectMessage connectMessage) {
472   - try {
473   - if (!context.isSkipValidityCheckForClientCert()) {
474   - cert.checkValidity();
475   - }
476   - String strCert = SslUtil.getCertificateString(cert);
477   - String sha3Hash = EncryptionUtil.getSha3Hash(strCert);
478   - transportService.process(DeviceTransportType.MQTT, ValidateDeviceX509CertRequestMsg.newBuilder().setHash(sha3Hash).build(),
479   - new TransportServiceCallback<>() {
480   - @Override
481   - public void onSuccess(ValidateDeviceCredentialsResponse msg) {
482   - onValidateDeviceResponse(msg, ctx);
483   - }
484   -
485   - @Override
486   - public void onError(Throwable e) {
487   - log.trace("[{}] Failed to process credentials: {}", address, sha3Hash, e);
488   - ctx.writeAndFlush(createTcpConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE));
489   - ctx.close();
490   - }
491   - });
492   - } catch (Exception e) {
493   - context.onAuthFailure(address);
494   - ctx.writeAndFlush(createTcpConnAckMsg(CONNECTION_REFUSED_NOT_AUTHORIZED));
495   - log.trace("[{}] X509 auth failure: {}", sessionId, address, e);
496   - ctx.close();
497   - }
498   - }
499   -
500   - private X509Certificate getX509Certificate() {
501   - try {
502   - Certificate[] certChain = sslHandler.engine().getSession().getPeerCertificates();
503   - if (certChain.length > 0) {
504   - return (X509Certificate) certChain[0];
505   - }
506   - } catch (SSLPeerUnverifiedException e) {
507   - log.warn(e.getMessage());
508   - return null;
509   - }
510   - return null;
511   - }
512 371
513   - private ByteBuf createTcpConnAckMsg(MqttConnectReturnCode msg) {
514   - return Unpooled.copiedBuffer(ByteUtils.hexStr2Bytes(msg.name()));
  372 + private ByteBuf createTcpConnAckMsg(String msg) {
  373 + return Unpooled.copiedBuffer(ByteUtils.getBytes(msg, ByteUtils.UTF_8));
515 374 }
516 375
517 376 @Override
... ... @@ -538,7 +397,6 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements
538 397 }
539 398
540 399
541   -
542 400 public static MqttPubAckMessage createMqttPubAckMsg(int requestId) {
543 401 MqttFixedHeader mqttFixedHeader =
544 402 new MqttFixedHeader(PUBACK, false, AT_MOST_ONCE, false, 0);
... ... @@ -547,7 +405,7 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements
547 405 return new MqttPubAckMessage(mqttFixedHeader, mqttMsgIdVariableHeader);
548 406 }
549 407
550   - private boolean checkConnected(ChannelHandlerContext ctx, TCPMessage msg) {
  408 + private boolean checkConnected(ChannelHandlerContext ctx, String msg) {
551 409 if (deviceSessionCtx.isConnected()) {
552 410 return true;
553 411 } else {
... ... @@ -594,22 +452,28 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements
594 452 }
595 453
596 454
597   - private void onValidateDeviceResponse(ValidateDeviceCredentialsResponse msg, ChannelHandlerContext ctx) {
  455 + private void onValidateDeviceResponse(ValidateDeviceCredentialsResponse msg, ChannelHandlerContext ctx, TcpAuthEntry authEntry, UUID scriptId) {
598 456 if (!msg.hasDeviceInfo()) {
599 457 context.onAuthFailure(address);
600   - ctx.writeAndFlush(createTcpConnAckMsg(CONNECTION_REFUSED_NOT_AUTHORIZED));
601   - ctx.close();
  458 + onValidateFailed(ctx, MqttConnectReturnCode.CONNECTION_REFUSED_NOT_AUTHORIZED);
602 459 } else {
  460 + DeviceProfile profile = msg.getDeviceProfile();
  461 + TkTcpDeviceProfileTransportConfiguration tcpConfig = (TkTcpDeviceProfileTransportConfiguration) profile.getProfileData().getTransportConfiguration();
  462 + if (scriptId != null && !tcpConfig.getAuthScriptId().equals(scriptId.toString())) {
  463 + authedCounter.incrementAndGet();
  464 + return;
  465 + }
603 466 context.onAuthSuccess(address);
604 467 deviceSessionCtx.setDeviceInfo(msg.getDeviceInfo());
605   - deviceSessionCtx.setDeviceProfile(msg.getDeviceProfile());
  468 + deviceSessionCtx.setDeviceProfile(profile);
606 469 deviceSessionCtx.setSessionInfo(SessionInfoCreator.create(msg, context, sessionId));
607 470 transportService.process(deviceSessionCtx.getSessionInfo(), SESSION_EVENT_MSG_OPEN, new TransportServiceCallback<Void>() {
608 471 @Override
609 472 public void onSuccess(Void msg) {
  473 + authedCounter.incrementAndGet();
610 474 SessionMetaData sessionMetaData = transportService.registerAsyncSession(deviceSessionCtx.getSessionInfo(), TcpTransportHandler.this);
611 475 checkGatewaySession(sessionMetaData);
612   - ctx.writeAndFlush(createTcpConnAckMsg(CONNECTION_ACCEPTED));
  476 + ctx.writeAndFlush(createTcpConnAckMsg(authEntry.getSuccess()));
613 477 deviceSessionCtx.setConnected(true);
614 478 log.debug("[{}] Client connected!", sessionId);
615 479
... ... @@ -624,13 +488,20 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements
624 488 } else {
625 489 log.warn("[{}] Failed to submit session event", sessionId, e);
626 490 }
627   - ctx.writeAndFlush(createTcpConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE));
628   - ctx.close();
  491 + onValidateFailed(ctx, MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE);
629 492 }
630 493 });
631 494 }
632 495 }
633 496
  497 + private void onValidateFailed(ChannelHandlerContext ctx, MqttConnectReturnCode msg) {
  498 + authedCounter.incrementAndGet();
  499 + if (authScripts.size() == authedCounter.incrementAndGet()) {
  500 + ctx.writeAndFlush(createTcpConnAckMsg(msg.name()));
  501 + ctx.close();
  502 + }
  503 + }
  504 +
634 505 @Override
635 506 public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg response) {
636 507 // log.trace("[{}] Received get attributes response", sessionId);
... ... @@ -663,7 +534,7 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements
663 534
664 535 @Override
665 536 public void onToDeviceRpcRequest(UUID sessionId, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) {
666   - log.error("【{}】下发RPC命令【{}】给设备【{}】", sessionId,rpcRequest.getParams(),deviceSessionCtx.getDeviceInfo().getDeviceName());
  537 + log.error("【{}】下发RPC命令【{}】给设备【{}】", sessionId, rpcRequest.getParams(), deviceSessionCtx.getDeviceInfo().getDeviceName());
667 538 TcpTransportAdaptor adaptor = deviceSessionCtx.getPayloadAdaptor();
668 539 try {
669 540 adaptor.convertToPublish(deviceSessionCtx, rpcRequest).ifPresent(payload -> {
... ... @@ -677,7 +548,7 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements
677 548 // }
678 549 // }, Math.max(0, Math.min(deviceSessionCtx.getContext().getTimeout(), rpcRequest.getExpirationTime() - System.currentTimeMillis())), TimeUnit.MILLISECONDS);
679 550 // }
680   - var cf = pushDeviceMsg(deviceSessionCtx.getChannel(), payload);
  551 + var cf = pushDeviceMsg(deviceSessionCtx.getChannel(), payload.getDatas());
681 552 cf.addListener(result -> {
682 553 if (result.cause() == null) {
683 554 // if (!isAckExpected(payload)) {
... ... @@ -713,33 +584,22 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements
713 584
714 585 /**
715 586 * 往设备推送消息
716   - * @param tcp
  587 + *
  588 + * @param message
717 589 * @return
718 590 */
719   - private ChannelFuture pushDeviceMsg(ChannelHandlerContext ctx,TCPMessage tcp) {
  591 + private ChannelFuture pushDeviceMsg(ChannelHandlerContext ctx, String message) {
720 592 try {
721   - String message = tcp.getMessage();
722   - byte[] payloadInBytes ;
723   - if(deviceSessionCtx.getPayloadType().equals(TcpDataTypeEnum.HEX)){
724   - payloadInBytes = ByteUtils.hexStr2Bytes(message);
725   - }else{
726   - payloadInBytes = message.getBytes(ByteUtils.UTF_8);
727   - }
728   -// ByteBufAllocator ALLOCATOR = new UnpooledByteBufAllocator(false);
729   -// ByteBuf payload = ALLOCATOR.buffer();
730   -// payload.writeBytes(payloadInBytes);
  593 + byte[] payloadInBytes = message.getBytes(ByteUtils.UTF_8);
731 594 ByteBuf payload = Unpooled.copiedBuffer(payloadInBytes);
732 595
733 596 return ctx.writeAndFlush(payload);
734 597 } catch (UnsupportedEncodingException e) {
735   - log.error(e.getMessage(),e);
  598 + log.error(e.getMessage(), e);
736 599 throw new RuntimeException(e);
737 600 }
738 601 }
739 602
740   - private boolean isAckExpected(MqttMessage message) {
741   - return message.fixedHeader().qosLevel().value() > 0;
742   - }
743 603
744 604 @Override
745 605 public void onDeviceProfileUpdate(TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile) {
... ...
... ... @@ -25,19 +25,15 @@ import com.google.gson.JsonSyntaxException;
25 25 import io.netty.buffer.ByteBuf;
26 26 import io.netty.handler.codec.mqtt.MqttPublishMessage;
27 27 import lombok.extern.slf4j.Slf4j;
28   -import org.springframework.beans.factory.annotation.Autowired;
29 28 import org.springframework.stereotype.Component;
30 29 import org.springframework.util.StringUtils;
  30 +import org.thingsboard.common.util.JacksonUtil;
31 31 import org.thingsboard.server.common.data.ota.OtaPackageType;
32 32 import org.thingsboard.server.common.transport.adaptor.AdaptorException;
33 33 import org.thingsboard.server.common.transport.adaptor.JsonConverter;
34   -import org.thingsboard.server.common.yunteng.script.TkScriptInvokeService;
35   -import org.thingsboard.server.common.yunteng.script.TkScriptType;
36 34 import org.thingsboard.server.gen.transport.TransportProtos;
37   -import org.thingsboard.server.transport.tcp.session.TCPMessage;
38 35 import org.thingsboard.server.transport.tcp.session.TcpDeviceWareSessionContext;
39 36
40   -import java.io.UnsupportedEncodingException;
41 37 import java.nio.charset.Charset;
42 38 import java.nio.charset.StandardCharsets;
43 39 import java.util.*;
... ... @@ -52,33 +48,22 @@ import java.util.concurrent.ExecutionException;
52 48 public class JsonTcpAdaptor implements TcpTransportAdaptor {
53 49
54 50 protected static final Charset UTF8 = StandardCharsets.UTF_8;
55   - @Autowired
56   - private TkScriptInvokeService jsEngine;
57 51 private static final JsonParser parser = new JsonParser();
58 52
  53 +
59 54 @Override
60   - public TransportProtos.PostTelemetryMsg convertToPostTelemetry(TcpDeviceWareSessionContext ctx, String inbound) throws AdaptorException {
  55 + public TransportProtos.PostTelemetryMsg convertToPostTelemetry(TcpDeviceWareSessionContext ctx, String payload) throws AdaptorException {
61 56 try {
62   - JsonElement payload = validatePayload(ctx, inbound, false);
63   - return JsonConverter.convertToTelemetryProto(payload);
  57 + return JsonConverter.convertToTelemetryProto(new JsonParser().parse(payload));
64 58 } catch (IllegalStateException | JsonSyntaxException ex) {
65 59 log.debug("Failed to decode post telemetry request", ex);
66 60 throw new AdaptorException(ex);
67   - } catch (ExecutionException e) {
68   - throw new RuntimeException(e);
69   - } catch (InterruptedException e) {
70   - throw new RuntimeException(e);
71 61 }
72 62 }
73 63
74   - @Override
75   - public UUID getJsScriptEngineFunctionId(String scriptBody, String... argNames) throws ExecutionException, InterruptedException {
76   - return jsEngine.eval(TkScriptType.TCP_TRANSPORT_SCRIPT, scriptBody, argNames).get();
77   - }
78 64
79 65 @Override
80   - public TransportProtos.PostAttributeMsg convertToPostAttributes(TcpDeviceWareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException {
81   - String payload = validatePayload(ctx.getSessionId(), inbound.payload(), false);
  66 + public TransportProtos.PostAttributeMsg convertToPostAttributes(TcpDeviceWareSessionContext ctx, String payload) throws AdaptorException {
82 67 try {
83 68 return JsonConverter.convertToAttributesProto(new JsonParser().parse(payload));
84 69 } catch (IllegalStateException | JsonSyntaxException ex) {
... ... @@ -124,57 +109,44 @@ public class JsonTcpAdaptor implements TcpTransportAdaptor {
124 109 }
125 110
126 111 @Override
127   - public Optional<TCPMessage> convertToPublish(TcpDeviceWareSessionContext ctx, TransportProtos.GetAttributeResponseMsg responseMsg, String topicBase) throws AdaptorException {
  112 + public Optional<TcpUpEntry> convertToPublish(TcpDeviceWareSessionContext ctx, TransportProtos.GetAttributeResponseMsg responseMsg, String topicBase) throws AdaptorException {
128 113 return processConvertFromAttributeResponseMsg(ctx, responseMsg, topicBase);
129 114 }
130 115
131 116 @Override
132   - public Optional<TCPMessage> convertToGatewayPublish(TcpDeviceWareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException {
  117 + public Optional<TcpUpEntry> convertToGatewayPublish(TcpDeviceWareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException {
133 118 return processConvertFromGatewayAttributeResponseMsg(ctx, deviceName, responseMsg);
134 119 }
135 120
136 121 @Override
137   - public Optional<TCPMessage> convertToPublish(TcpDeviceWareSessionContext ctx, TransportProtos.AttributeUpdateNotificationMsg notificationMsg, String topic) {
  122 + public Optional<TcpUpEntry> convertToPublish(TcpDeviceWareSessionContext ctx, TransportProtos.AttributeUpdateNotificationMsg notificationMsg, String topic) {
138 123 return Optional.of(createTcpMessage(ctx, JsonConverter.toJson(notificationMsg)));
139 124 }
140 125
141   - @Override
142   - public Optional<TCPMessage> convertToGatewayPublish(TcpDeviceWareSessionContext ctx, String deviceName, TransportProtos.AttributeUpdateNotificationMsg notificationMsg) {
143   - JsonObject result = JsonConverter.getJsonObjectForGateway(deviceName, notificationMsg);
144   - return Optional.of(createTcpMessage(ctx, result));
145   - }
146 126
147 127 @Override
148   - public Optional<TCPMessage> convertToPublish(TcpDeviceWareSessionContext ctx, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) throws UnsupportedEncodingException {
149   - byte[] result = null;
150   - String payload = rpcRequest.getParams();//methodThingskit
151   -// if(ctx.getPayloadType().equals(TcpDataTypeEnum.ASCII)){
152   -// }else{
153   -// result= ByteUtils.hexToBytes(payload);
154   -// }
155   - if (!payload.startsWith("{") && !payload.endsWith("}")) {
156   - payload = payload.replace("\"","");;
157   - }
158   - return Optional.of(createTcpMessage(ctx, payload));
  128 + public Optional<TcpDownEntry> convertToPublish(TcpDeviceWareSessionContext ctx, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) throws ExecutionException, InterruptedException {
  129 + ListenableFuture<Object> result = ctx.getContext().getJsEngine().invokeFunction(ctx.getRpcScriptId(), rpcRequest.getParams());
  130 + return Optional.of(Futures.transform(result, t -> JacksonUtil.fromString(t.toString(), TcpDownEntry.class), MoreExecutors.directExecutor()).get());
159 131 }
160 132
161 133 @Override
162   - public Optional<TCPMessage> convertToGatewayPublish(TcpDeviceWareSessionContext ctx, String deviceName, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) {
  134 + public Optional<TcpUpEntry> convertToGatewayPublish(TcpDeviceWareSessionContext ctx, String deviceName, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) {
163 135 return Optional.of(createTcpMessage(ctx, JsonConverter.toGatewayJson(deviceName, rpcRequest)));
164 136 }
165 137
166 138 @Override
167   - public Optional<TCPMessage> convertToPublish(TcpDeviceWareSessionContext ctx, TransportProtos.ToServerRpcResponseMsg rpcResponse, String topicBase) {
  139 + public Optional<TcpUpEntry> convertToPublish(TcpDeviceWareSessionContext ctx, TransportProtos.ToServerRpcResponseMsg rpcResponse, String topicBase) {
168 140 return Optional.of(createTcpMessage(ctx, JsonConverter.toJson(rpcResponse)));
169 141 }
170 142
171 143 @Override
172   - public Optional<TCPMessage> convertToPublish(TcpDeviceWareSessionContext ctx, TransportProtos.ProvisionDeviceResponseMsg provisionResponse) {
  144 + public Optional<TcpUpEntry> convertToPublish(TcpDeviceWareSessionContext ctx, TransportProtos.ProvisionDeviceResponseMsg provisionResponse) {
173 145 return Optional.of(createTcpMessage(ctx, JsonConverter.toJson(provisionResponse)));
174 146 }
175 147
176 148 @Override
177   - public Optional<TCPMessage> convertToPublish(TcpDeviceWareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, OtaPackageType firmwareType) {
  149 + public Optional<TcpUpEntry> convertToPublish(TcpDeviceWareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, OtaPackageType firmwareType) {
178 150 return Optional.of(null);
179 151 }
180 152
... ... @@ -235,7 +207,7 @@ public class JsonTcpAdaptor implements TcpTransportAdaptor {
235 207 }
236 208 }
237 209
238   - private Optional<TCPMessage> processConvertFromAttributeResponseMsg(TcpDeviceWareSessionContext ctx, TransportProtos.GetAttributeResponseMsg responseMsg, String topicBase) throws AdaptorException {
  210 + private Optional<TcpUpEntry> processConvertFromAttributeResponseMsg(TcpDeviceWareSessionContext ctx, TransportProtos.GetAttributeResponseMsg responseMsg, String topicBase) throws AdaptorException {
239 211 if (!StringUtils.isEmpty(responseMsg.getError())) {
240 212 throw new AdaptorException(responseMsg.getError());
241 213 } else {
... ... @@ -248,7 +220,7 @@ public class JsonTcpAdaptor implements TcpTransportAdaptor {
248 220 }
249 221 }
250 222
251   - private Optional<TCPMessage> processConvertFromGatewayAttributeResponseMsg(TcpDeviceWareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException {
  223 + private Optional<TcpUpEntry> processConvertFromGatewayAttributeResponseMsg(TcpDeviceWareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException {
252 224 if (!StringUtils.isEmpty(responseMsg.getError())) {
253 225 throw new AdaptorException(responseMsg.getError());
254 226 } else {
... ... @@ -278,34 +250,13 @@ public class JsonTcpAdaptor implements TcpTransportAdaptor {
278 250 return payload;
279 251 }
280 252
281   - private JsonElement validatePayload(TcpDeviceWareSessionContext session, String payload, boolean isEmptyPayloadAllowed) throws AdaptorException, ExecutionException, InterruptedException {
282   - if (payload == null) {
283   - log.debug("[{}] Payload is empty!", session.getSessionId());
284   - if (!isEmptyPayloadAllowed) {
285   - throw new AdaptorException(new IllegalArgumentException("Payload is empty!"));
286   - }
287   - }
288   -// jsEngine.invokeFunction();
289   -// new JsonParser().parse(payload)
290   -// return payload;
291   - ListenableFuture<JsonElement> result = Futures.transformAsync(jsEngine.invokeFunction(session.getScriptId(), payload),
292   - o -> {
293   - try {
294   - return Futures.immediateFuture(parser.parse(o.toString()));
295   - } catch (Exception e) {
296   - return Futures.immediateFailedFuture(e);
297   - }
298   - }, MoreExecutors.directExecutor());
299   -
300   - return result.get();
301   - }
302 253
303 254 private int getRequestId(String topicName, String topic) {
304 255 return Integer.parseInt(topicName.substring(topic.length()));
305 256 }
306 257
307 258
308   - protected TCPMessage createTcpMessage(TcpDeviceWareSessionContext ctx, JsonElement json) {
  259 + protected TcpUpEntry createTcpMessage(TcpDeviceWareSessionContext ctx, JsonElement json) {
309 260 // TCPMessage msg = new TCPMessage(MqttMessageType.PUBLISH,);
310 261 //// new MqttFixedHeader(MqttMessageType.PUBLISH, false, ctx.getQoSForTopic(topic), false, 0);
311 262 // MqttPublishVariableHeader header = new MqttPublishVariableHeader(topic, ctx.nextMsgId());
... ... @@ -315,12 +266,5 @@ public class JsonTcpAdaptor implements TcpTransportAdaptor {
315 266 return null;
316 267 }
317 268
318   - protected TCPMessage createTcpMessage(TcpDeviceWareSessionContext ctx, String payload) {
319   - TCPMessage message = new TCPMessage(payload);
320   - message.setRequestId(payload.substring(0, 4));
321   - message.setTopic(payload.substring(2, 4));
322   - message.setDeviceCode(payload.substring(0, 2));
323   - return message;
324   - }
325 269
326 270 }
... ...
  1 +package org.thingsboard.server.transport.tcp.adaptors;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import java.io.Serializable;
  6 +
  7 +@Data
  8 +public class TcpAuthEntry implements Serializable {
  9 + /** clientId: 设备鉴权客户端ID */
  10 + private String clientId;
  11 + /** userName: 设备鉴权用户名 */
  12 + private String userName;
  13 + /** password: 设备鉴权密码 */
  14 + private String password;
  15 + /** success :鉴权成功返回内容 */
  16 + private String success;
  17 +
  18 +}
... ...
  1 +package org.thingsboard.server.transport.tcp.adaptors;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Data;
  5 +
  6 +import java.io.Serializable;
  7 +import java.util.UUID;
  8 +
  9 +/**
  10 + * 下行脚本
  11 + */
  12 +@Data
  13 +@AllArgsConstructor
  14 +public class TcpDownEntry implements Serializable {
  15 +
  16 + /**
  17 + * 消息ID,用于请求与响应的匹配,例如:modbus由地址码和功能码组成。
  18 + */
  19 + private UUID requestId;
  20 + /**
  21 + * 设备名称、设备标识
  22 + */
  23 + private String deviceName;
  24 + /**
  25 + * 下发给设备的最终内容
  26 + */
  27 + private String datas;
  28 +}
... ...
1 1 /**
2 2 * Copyright © 2016-2022 The Thingsboard Authors
3   - *
  3 + * <p>
4 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 5 * you may not use this file except in compliance with the License.
6 6 * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
  7 + * <p>
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + * <p>
10 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
12 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
... ... @@ -18,17 +18,13 @@ package org.thingsboard.server.transport.tcp.adaptors;
18 18 import io.netty.buffer.ByteBuf;
19 19 import io.netty.handler.codec.mqtt.MqttPublishMessage;
20 20 import org.thingsboard.server.common.data.ota.OtaPackageType;
21   -import org.thingsboard.server.common.data.yunteng.enums.TcpDataTypeEnum;
22 21 import org.thingsboard.server.common.transport.adaptor.AdaptorException;
23 22 import org.thingsboard.server.gen.transport.TransportProtos.*;
24 23 import org.thingsboard.server.transport.tcp.session.TcpDeviceWareSessionContext;
25   -import org.thingsboard.server.transport.tcp.session.TCPMessage;
26 24
27   -import java.io.UnsupportedEncodingException;
28 25 import java.nio.charset.Charset;
29 26 import java.nio.charset.StandardCharsets;
30 27 import java.util.Optional;
31   -import java.util.UUID;
32 28 import java.util.concurrent.ExecutionException;
33 29
34 30 /**
... ... @@ -40,10 +36,20 @@ public interface TcpTransportAdaptor {
40 36 static char[] HEX_VOCABLE = {'0', '1', '2', '3', '4', '5', '6', '7',
41 37 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
42 38 static final Charset UTF8 = StandardCharsets.UTF_8;
  39 +
  40 +
  41 + /**
  42 + * 设备数据转遥测数据
  43 + *
  44 + * @param ctx
  45 + * @param inbound 设备上报的数据字符串
  46 + * @return 平台需要的遥测数据
  47 + * @throws AdaptorException
  48 + */
43 49 PostTelemetryMsg convertToPostTelemetry(TcpDeviceWareSessionContext ctx, String inbound) throws AdaptorException;
44 50
45   - UUID getJsScriptEngineFunctionId(String scriptBody, String... argNames) throws ExecutionException, InterruptedException;
46   - PostAttributeMsg convertToPostAttributes(TcpDeviceWareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException;
  51 +
  52 + PostAttributeMsg convertToPostAttributes(TcpDeviceWareSessionContext ctx, String inbound) throws AdaptorException;
47 53
48 54 GetAttributeRequestMsg convertToGetAttributes(TcpDeviceWareSessionContext ctx, MqttPublishMessage inbound, String topicBase) throws AdaptorException;
49 55
... ... @@ -53,31 +59,32 @@ public interface TcpTransportAdaptor {
53 59
54 60 ClaimDeviceMsg convertToClaimDevice(TcpDeviceWareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException;
55 61
56   - Optional<TCPMessage> convertToPublish(TcpDeviceWareSessionContext ctx, GetAttributeResponseMsg responseMsg, String topicBase) throws AdaptorException;
  62 + Optional<TcpUpEntry> convertToPublish(TcpDeviceWareSessionContext ctx, GetAttributeResponseMsg responseMsg, String topicBase) throws AdaptorException;
57 63
58   - Optional<TCPMessage> convertToGatewayPublish(TcpDeviceWareSessionContext ctx, String deviceName, GetAttributeResponseMsg responseMsg) throws AdaptorException;
  64 + Optional<TcpUpEntry> convertToGatewayPublish(TcpDeviceWareSessionContext ctx, String deviceName, GetAttributeResponseMsg responseMsg) throws AdaptorException;
59 65
60   - Optional<TCPMessage> convertToPublish(TcpDeviceWareSessionContext ctx, AttributeUpdateNotificationMsg notificationMsg, String topic) throws AdaptorException;
  66 + Optional<TcpUpEntry> convertToPublish(TcpDeviceWareSessionContext ctx, AttributeUpdateNotificationMsg notificationMsg, String topic) throws AdaptorException;
61 67
62   - Optional<TCPMessage> convertToGatewayPublish(TcpDeviceWareSessionContext ctx, String deviceName, AttributeUpdateNotificationMsg notificationMsg) throws AdaptorException;
63 68
64   - Optional<TCPMessage> convertToPublish(TcpDeviceWareSessionContext ctx, ToDeviceRpcRequestMsg rpcRequest) throws AdaptorException, UnsupportedEncodingException;
  69 + Optional<TcpDownEntry> convertToPublish(TcpDeviceWareSessionContext ctx, ToDeviceRpcRequestMsg rpcRequest) throws ExecutionException, InterruptedException;
65 70
66   - Optional<TCPMessage> convertToGatewayPublish(TcpDeviceWareSessionContext ctx, String deviceName, ToDeviceRpcRequestMsg rpcRequest) throws AdaptorException;
  71 + Optional<TcpUpEntry> convertToGatewayPublish(TcpDeviceWareSessionContext ctx, String deviceName, ToDeviceRpcRequestMsg rpcRequest) throws AdaptorException;
67 72
68   - Optional<TCPMessage> convertToPublish(TcpDeviceWareSessionContext ctx, ToServerRpcResponseMsg rpcResponse, String topicBase) throws AdaptorException;
  73 + Optional<TcpUpEntry> convertToPublish(TcpDeviceWareSessionContext ctx, ToServerRpcResponseMsg rpcResponse, String topicBase) throws AdaptorException;
69 74
70 75 ProvisionDeviceRequestMsg convertToProvisionRequestMsg(TcpDeviceWareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException;
71 76
72   - Optional<TCPMessage> convertToPublish(TcpDeviceWareSessionContext ctx, ProvisionDeviceResponseMsg provisionResponse) throws AdaptorException;
  77 + Optional<TcpUpEntry> convertToPublish(TcpDeviceWareSessionContext ctx, ProvisionDeviceResponseMsg provisionResponse) throws AdaptorException;
  78 +
  79 + Optional<TcpUpEntry> convertToPublish(TcpDeviceWareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, OtaPackageType firmwareType) throws AdaptorException;
73 80
74   - Optional<TCPMessage> convertToPublish(TcpDeviceWareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, OtaPackageType firmwareType) throws AdaptorException;
75 81 public static byte[] toBytes(ByteBuf inbound) {
76 82 byte[] bytes = new byte[inbound.readableBytes()];
77 83 int readerIndex = inbound.readerIndex();
78 84 inbound.getBytes(readerIndex, bytes);
79 85 return bytes;
80 86 }
  87 +
81 88 public static String bytesToHex(byte[] bs) {
82 89 StringBuilder sb = new StringBuilder();
83 90 for (byte b : bs) {
... ... @@ -88,18 +95,4 @@ public interface TcpTransportAdaptor {
88 95 }
89 96 return sb.toString();
90 97 }
91   - default TCPMessage createTcpMessage(TcpDeviceWareSessionContext ctx, ByteBuf payload) {
92   - String payloadStr;
93   - if(ctx.getPayloadType().equals(TcpDataTypeEnum.HEX)){
94   - byte[] payloadBytes = toBytes(payload);
95   - payloadStr = bytesToHex(payloadBytes);
96   - }else{
97   - payloadStr = payload.toString(UTF8);
98   - }
99   - TCPMessage message = new TCPMessage(payloadStr);
100   - message.setRequestId(payloadStr.substring(0,4));
101   - message.setTopic(payloadStr.substring(2,4));
102   - message.setDeviceCode(payloadStr.substring(0,2));
103   - return message;
104   - }
105 98 }
... ...
  1 +package org.thingsboard.server.transport.tcp.adaptors;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Data;
  5 +
  6 +import java.io.Serializable;
  7 +import java.util.Map;
  8 +import java.util.UUID;
  9 +
  10 +/**
  11 + * 上行脚本解析对象
  12 + * 字符串解析为JSON对象
  13 + */
  14 +@Data
  15 +@AllArgsConstructor
  16 +public class TcpUpEntry implements Serializable {
  17 +
  18 + /**
  19 + * 消息ID,用于请求与响应的匹配,例如:modbus由地址码和功能码组成。
  20 + */
  21 + private UUID requestId;
  22 +
  23 + /**
  24 + * 设备上报的设备端数据,格式:网关设备多个子设备,直连设备多个指标
  25 + */
  26 + private Map<String, Object> datas;
  27 + /**
  28 + * datas存放的是遥测数据还是设备端属性
  29 + */
  30 + private Boolean telemetry;
  31 + /**
  32 + * 数据成功处理后的响应内容
  33 + */
  34 + private String ackMsg;
  35 + /**
  36 + * 设备名称、设备标识
  37 + */
  38 + private String deviceName;
  39 + /**
  40 + * 指标采集时间
  41 + */
  42 + private Long ts;
  43 +
  44 + public TcpUpEntry(UUID requestId) {
  45 + this.requestId = requestId;
  46 + }
  47 +}
... ...
common/transport/tcp/src/main/java/org/thingsboard/server/transport/tcp/script/AbstractNashornTkScriptInvokeService.java renamed from common/transport/transport-api/src/main/java/org/thingsboard/server/common/yunteng/script/AbstractNashornTkScriptInvokeService.java
1   -/**
2   - * Copyright © 2016-2022 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.common.yunteng.script;
  1 +package org.thingsboard.server.transport.tcp.script;
17 2
18 3 import com.google.common.util.concurrent.FutureCallback;
19 4 import com.google.common.util.concurrent.Futures;
... ...
common/transport/tcp/src/main/java/org/thingsboard/server/transport/tcp/script/AbstractTkScriptInvokeService.java renamed from common/transport/transport-api/src/main/java/org/thingsboard/server/common/yunteng/script/AbstractTkScriptInvokeService.java
... ... @@ -13,12 +13,13 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.common.yunteng.script;
  16 +package org.thingsboard.server.transport.tcp.script;
17 17
18 18 import com.google.common.util.concurrent.Futures;
19 19 import com.google.common.util.concurrent.ListenableFuture;
20 20 import lombok.extern.slf4j.Slf4j;
21 21 import org.thingsboard.common.util.ThingsBoardThreadFactory;
  22 +import org.thingsboard.server.common.data.yunteng.enums.TkScriptFunctionType;
22 23
23 24 import java.util.Map;
24 25 import java.util.UUID;
... ... @@ -54,10 +55,10 @@ public abstract class AbstractTkScriptInvokeService implements TkScriptInvokeSer
54 55 }
55 56
56 57 @Override
57   - public ListenableFuture<UUID> eval(TkScriptType scriptType, String scriptBody, String... argNames) {
58   - UUID scriptId = UUID.randomUUID();
  58 + public ListenableFuture<UUID> eval(UUID id,TkScriptFunctionType scriptType, String scriptBody) {
  59 + UUID scriptId = id == null?UUID.randomUUID():id;
59 60 String functionName = "invokeInternal_" + scriptId.toString().replace('-', '_');
60   - String jsScript = generateJsScript(scriptType, functionName, scriptBody, argNames);
  61 + String jsScript = generateJsScript(scriptType, functionName, scriptBody);
61 62 return doEval(scriptId, functionName, jsScript);
62 63 }
63 64
... ... @@ -109,10 +110,9 @@ public abstract class AbstractTkScriptInvokeService implements TkScriptInvokeSer
109 110 disableListInfo.incrementAndGet();
110 111 }
111 112
112   - private String generateJsScript(TkScriptType scriptType, String functionName, String scriptBody, String... argNames) {
113   - if (scriptType == TkScriptType.TCP_TRANSPORT_SCRIPT) {
114   - return TkScriptFactory.generateRuleNodeScript(functionName, scriptBody, argNames);
115   -
  113 + private String generateJsScript(TkScriptFunctionType scriptType, String functionName, String scriptBody) {
  114 + if (TkScriptFunctionType.valueOf(scriptType.name()) != null) {
  115 + return TkScriptFactory.generateTcpScript(scriptType,functionName, scriptBody);
116 116 }
117 117 throw new RuntimeException("No script factory implemented for scriptType: " + scriptType);
118 118 }
... ...
common/transport/tcp/src/main/java/org/thingsboard/server/transport/tcp/script/NashornTkScriptInvokeService.java renamed from common/transport/transport-api/src/main/java/org/thingsboard/server/common/yunteng/script/NashornTkScriptInvokeService.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.common.yunteng.script;
  16 +package org.thingsboard.server.transport.tcp.script;
17 17
18 18 import lombok.extern.slf4j.Slf4j;
19 19 import org.springframework.beans.factory.annotation.Value;
... ...
common/transport/tcp/src/main/java/org/thingsboard/server/transport/tcp/script/RemoteJsRequestEncoder.java renamed from common/transport/transport-api/src/main/java/org/thingsboard/server/common/yunteng/script/RemoteJsRequestEncoder.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.common.yunteng.script;
  16 +package org.thingsboard.server.transport.tcp.script;
17 17
18 18 import com.google.protobuf.InvalidProtocolBufferException;
19 19 import com.google.protobuf.util.JsonFormat;
... ...
common/transport/tcp/src/main/java/org/thingsboard/server/transport/tcp/script/RemoteJsResponseDecoder.java renamed from common/transport/transport-api/src/main/java/org/thingsboard/server/common/yunteng/script/RemoteJsResponseDecoder.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.common.yunteng.script;
  16 +package org.thingsboard.server.transport.tcp.script;
17 17
18 18 import com.google.protobuf.util.JsonFormat;
19 19 import org.thingsboard.server.gen.js.JsInvokeProtos;
... ...
common/transport/tcp/src/main/java/org/thingsboard/server/transport/tcp/script/TkRemoteJsInvokeService.java renamed from common/transport/transport-api/src/main/java/org/thingsboard/server/common/yunteng/script/TkRemoteJsInvokeService.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.common.yunteng.script;
  16 +package org.thingsboard.server.transport.tcp.script;
17 17
18 18 import com.google.common.util.concurrent.FutureCallback;
19 19 import com.google.common.util.concurrent.Futures;
... ...
common/transport/tcp/src/main/java/org/thingsboard/server/transport/tcp/script/TkScriptExecutorService.java renamed from common/transport/transport-api/src/main/java/org/thingsboard/server/common/yunteng/script/TkScriptExecutorService.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.common.yunteng.script;
  16 +package org.thingsboard.server.transport.tcp.script;
17 17
18 18 import org.springframework.beans.factory.annotation.Value;
19 19 import org.springframework.stereotype.Component;
... ...
  1 +package org.thingsboard.server.transport.tcp.script;
  2 +
  3 +import org.apache.commons.lang3.StringUtils;
  4 +import org.thingsboard.server.common.data.yunteng.enums.TkScriptFunctionType;
  5 +
  6 +public class TkScriptFactory {
  7 +
  8 + /**
  9 + * 脚本函数入参:数据配置
  10 + */
  11 + public static final String MSG = "params";
  12 + /**
  13 + * 脚本函数入参:RPC功能名
  14 + */
  15 + public static final String METHODNAME = "thingsKit";
  16 + public static final String SCRIPT_FUNCTION_NAME = "tcpTransportFunc";
  17 + public static final String ORIGINAL_DATA_FILED = "source";
  18 + public static final String INCLUD_ORIGINAL_DATA = "out." + ORIGINAL_DATA_FILED + "=params;";
  19 +
  20 + private static final String JS_WRAPPER_PREFIX_TEMPLATE = "function %s(params) { " +
  21 + " var out = new Object(); " +
  22 + " return JSON.stringify(%s(params));" +
  23 + " function %s(%s) {";
  24 + private static final String JS_DOWN_WRAPPER_PREFIX_TEMPLATE = "function %s(params) { " +//"function %s(method,params) { "
  25 + " var out = new Object(); " +
  26 + " return JSON.stringify(%s(params));" + //" return JSON.stringify(%s(method,params));"
  27 + " function %s(%s) {";//" function %s(%s,%s) {"
  28 + private static final String JS_UP_WRAPPER_PREFIX_TEMPLATE = "function %s(params) { " +
  29 + " var out = new Object(); " +
  30 + " return JSON.stringify(%s(params));" +
  31 + " function %s(%s) {";
  32 + private static final String JS_WRAPPER_SUFFIX = "return out; \n }" +
  33 + "\n}";
  34 +
  35 +
  36 + /**
  37 + * 构建完整的脚本函数
  38 + *
  39 + * @param scriptType 脚本类型
  40 + * @param functionName 脚本函数名
  41 + * @param scriptBody 自定义的脚本函数体
  42 + * @param argNames 脚本函数入参
  43 + * @return
  44 + */
  45 + public static String generateTcpScript(TkScriptFunctionType scriptType, String functionName, String scriptBody, String... argNames) {
  46 + String jsWrapperPrefix;
  47 + String msgArg = argNames.length >= 1 ? argNames[0] : MSG;
  48 +// String methodName = argNames.length >= 2 ? argNames[0] : METHODNAME;
  49 + switch (scriptType) {
  50 + case TRANSPORT_TCP_UP:
  51 + jsWrapperPrefix = String.format(JS_UP_WRAPPER_PREFIX_TEMPLATE
  52 + , functionName
  53 + , SCRIPT_FUNCTION_NAME
  54 + , SCRIPT_FUNCTION_NAME, msgArg);
  55 + break;
  56 + case TRANSPORT_TCP_DOWN:
  57 + jsWrapperPrefix = String.format(JS_DOWN_WRAPPER_PREFIX_TEMPLATE
  58 + , functionName
  59 + , SCRIPT_FUNCTION_NAME
  60 + , SCRIPT_FUNCTION_NAME, msgArg);
  61 + break;
  62 + default:
  63 + jsWrapperPrefix = String.format(JS_WRAPPER_PREFIX_TEMPLATE
  64 + , functionName
  65 + , SCRIPT_FUNCTION_NAME
  66 + , SCRIPT_FUNCTION_NAME, msgArg);
  67 + }
  68 +
  69 +
  70 + String result = jsWrapperPrefix + (StringUtils.isEmpty(scriptBody) ? INCLUD_ORIGINAL_DATA : scriptBody) + JS_WRAPPER_SUFFIX;
  71 + return result;
  72 + }
  73 +
  74 +}
... ...
common/transport/tcp/src/main/java/org/thingsboard/server/transport/tcp/script/TkScriptInvokeRequest.java renamed from common/transport/transport-api/src/main/java/org/thingsboard/server/common/yunteng/script/TkScriptInvokeRequest.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.common.yunteng.script;
  16 +package org.thingsboard.server.transport.tcp.script;
17 17
18 18 import java.util.List;
19 19
... ...
common/transport/tcp/src/main/java/org/thingsboard/server/transport/tcp/script/TkScriptInvokeResponse.java renamed from common/transport/transport-api/src/main/java/org/thingsboard/server/common/yunteng/script/TkScriptInvokeResponse.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.common.yunteng.script;
  16 +package org.thingsboard.server.transport.tcp.script;
17 17
18 18 import java.util.List;
19 19
... ...
common/transport/tcp/src/main/java/org/thingsboard/server/transport/tcp/script/TkScriptInvokeService.java renamed from common/transport/transport-api/src/main/java/org/thingsboard/server/common/yunteng/script/TkScriptInvokeService.java
... ... @@ -13,18 +13,37 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.common.yunteng.script;
  16 +package org.thingsboard.server.transport.tcp.script;
17 17
18 18 import com.google.common.util.concurrent.ListenableFuture;
  19 +import org.thingsboard.server.common.data.yunteng.enums.TkScriptFunctionType;
19 20
20 21 import java.util.UUID;
21 22
22 23 public interface TkScriptInvokeService {
23 24
24   - ListenableFuture<UUID> eval(TkScriptType scriptType, String scriptBody, String... argNames);
  25 + /**
  26 + * 编译脚本函数
  27 + * @param scriptId 脚本函数的唯一UUID,为空时随机生成
  28 + * @param scriptType 脚本函数类型
  29 + * @param scriptBody 脚本函数方法体
  30 + * @return 返回脚本函数的UUID
  31 + */
  32 + ListenableFuture<UUID> eval(UUID scriptId, TkScriptFunctionType scriptType, String scriptBody);
25 33
  34 + /**
  35 + * 执行脚本函数
  36 + * @param scriptId 脚本函数的唯一UUID
  37 + * @param args 脚本函数的实际参数
  38 + * @return 脚本函数执行结果
  39 + */
26 40 ListenableFuture<Object> invokeFunction(UUID scriptId, Object... args);
27 41
  42 + /**
  43 + * 释放缓存的脚本函数内容。临时测试脚本函数后需要释放缓存的相关内容
  44 + * @param scriptId 脚本函数的唯一UUID
  45 + * @return
  46 + */
28 47 ListenableFuture<Void> release(UUID scriptId);
29 48
30 49 }
... ...
common/transport/tcp/src/main/java/org/thingsboard/server/transport/tcp/script/TkScriptStatCallback.java renamed from common/transport/transport-api/src/main/java/org/thingsboard/server/common/yunteng/script/TkScriptStatCallback.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.common.yunteng.script;
  16 +package org.thingsboard.server.transport.tcp.script;
17 17
18 18 import com.google.common.util.concurrent.FutureCallback;
19 19 import lombok.AllArgsConstructor;
... ...
1   -package org.thingsboard.server.transport.tcp.session;
2   -
3   -import io.netty.handler.codec.mqtt.MqttMessageType;
4   -import lombok.Data;
5   -
6   -import java.io.Serializable;
7   -
8   -@Data
9   -public class TCPMessage implements Serializable {
10   -
11   - /**消息ID,用于请求与响应的匹配,例如:modbus由地址码和功能码组成。*/
12   - private String requestId;
13   -
14   -
15   - private String message;
16   -
17   - /**数据主题,例如:modbus的功能码等。*/
18   - private String topic;
19   -
20   - /**设备地址码,例如:modbus的地址吗*/
21   - private String deviceCode;
22   -
23   -
24   -
25   - public TCPMessage(String message){
26   - this.message = message;
27   - }
28   -
29   -}
... ... @@ -21,6 +21,7 @@ import lombok.Getter;
21 21 import lombok.Setter;
22 22 import lombok.extern.slf4j.Slf4j;
23 23 import org.thingsboard.server.transport.tcp.TcpTransportContext;
  24 +import org.thingsboard.server.transport.tcp.adaptors.TcpUpEntry;
24 25
25 26 import java.util.UUID;
26 27 import java.util.concurrent.ConcurrentLinkedQueue;
... ... @@ -42,7 +43,7 @@ public class TcpDeviceSessionCtx extends TcpDeviceWareSessionContext {
42 43
43 44 private final AtomicInteger msgIdSeq = new AtomicInteger(0);
44 45
45   - private final ConcurrentLinkedQueue<TCPMessage> msgQueue = new ConcurrentLinkedQueue<>();
  46 + private final ConcurrentLinkedQueue<String> msgQueue = new ConcurrentLinkedQueue<>();
46 47
47 48 @Getter
48 49 private final Lock msgQueueProcessorLock = new ReentrantLock();
... ... @@ -73,17 +74,17 @@ public class TcpDeviceSessionCtx extends TcpDeviceWareSessionContext {
73 74
74 75
75 76
76   - public void addToQueue(TCPMessage msg) {
  77 + public void addToQueue(String msg) {
77 78 msgQueueSize.incrementAndGet();
78 79 ReferenceCountUtil.retain(msg);
79 80 msgQueue.add(msg);
80 81 }
81 82
82   - public void tryProcessQueuedMsgs(Consumer<TCPMessage> msgProcessor) {
  83 + public void tryProcessQueuedMsgs(Consumer<String> msgProcessor) {
83 84 while (!msgQueue.isEmpty()) {
84 85 if (msgQueueProcessorLock.tryLock()) {
85 86 try {
86   - TCPMessage msg;
  87 + String msg;
87 88 while ((msg = msgQueue.poll()) != null) {
88 89 try {
89 90 msgQueueSize.decrementAndGet();
... ...
1   -/**
2   - * Copyright © 2016-2022 The Thingsboard Authors
3   - * <p>
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - * <p>
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - * <p>
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16 1 package org.thingsboard.server.transport.tcp.session;
17 2
18   -import com.fasterxml.jackson.core.JsonProcessingException;
19   -import com.fasterxml.jackson.databind.JsonNode;
  3 +import com.google.common.util.concurrent.FutureCallback;
  4 +import com.google.common.util.concurrent.Futures;
  5 +import com.google.common.util.concurrent.ListenableFuture;
  6 +import com.google.common.util.concurrent.MoreExecutors;
20 7 import lombok.Getter;
21 8 import lombok.extern.slf4j.Slf4j;
  9 +import org.jetbrains.annotations.Nullable;
  10 +import org.thingsboard.common.util.JacksonUtil;
22 11 import org.thingsboard.server.common.data.DeviceProfile;
23 12 import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
24 13 import org.thingsboard.server.common.data.device.profile.TkTcpDeviceProfileTransportConfiguration;
25   -import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants;
26   -import org.thingsboard.server.common.data.yunteng.enums.TcpDataTypeEnum;
  14 +import org.thingsboard.server.common.data.yunteng.enums.TkScriptFunctionType;
27 15 import org.thingsboard.server.common.transport.auth.TransportDeviceInfo;
28 16 import org.thingsboard.server.common.transport.session.DeviceAwareSessionContext;
29   -import org.thingsboard.server.common.yunteng.script.TkScriptFactory;
30 17 import org.thingsboard.server.gen.transport.TransportProtos;
31 18 import org.thingsboard.server.transport.tcp.TcpTransportContext;
32 19 import org.thingsboard.server.transport.tcp.adaptors.TcpTransportAdaptor;
  20 +import org.thingsboard.server.transport.tcp.adaptors.TcpUpEntry;
33 21
34 22 import java.util.UUID;
35   -import java.util.concurrent.ExecutionException;
  23 +import java.util.function.Consumer;
36 24
37 25 /**
38 26 * @author Andrew Shvayka
... ... @@ -42,22 +30,19 @@ public abstract class TcpDeviceWareSessionContext extends DeviceAwareSessionCont
42 30
43 31 @Getter
44 32 private final TcpTransportContext context;
45   -
46   - private volatile String telemetryTopicFilter ;
47   - private volatile String attributesTopicFilter;
48   - private volatile String toDeviceRpcResponseTopicFilter;
49 33 @Getter
50   - private volatile TcpDataTypeEnum payloadType = TcpDataTypeEnum.HEX;
51   -
52   - private volatile TcpTransportAdaptor adaptor;
53   -
54   - /**设备唯一标识符,例如:设备SN、设备地址码等。数据内携带标识符*/
  34 + private volatile UUID authScriptId;
55 35 @Getter
56   - private volatile String deviceCode = "55";
57   -
  36 + private volatile UUID telemetryScriptId;
  37 + @Getter
  38 + private volatile UUID rpcScriptId;
58 39
  40 + /**
  41 + * 设备唯一标识符,例如:设备SN、设备地址码等。数据内携带标识符
  42 + */
59 43 @Getter
60   - private UUID scriptId;
  44 + private volatile String deviceName;
  45 + private volatile TcpTransportAdaptor adaptor;
61 46
62 47 public TcpDeviceWareSessionContext(UUID sessionId, TcpTransportContext context) {
63 48 super(sessionId);
... ... @@ -66,17 +51,6 @@ public abstract class TcpDeviceWareSessionContext extends DeviceAwareSessionCont
66 51 }
67 52
68 53
69   - public boolean isDeviceTelemetryTopic(String topicName) {
70   - return telemetryTopicFilter.equals(topicName);
71   - }
72   -
73   - public boolean isDeviceAttributesTopic(String topicName) {
74   - return attributesTopicFilter.equals(topicName);
75   - }
76   - public boolean isToDeviceRpcResponseTopic(String topicName) {
77   - return toDeviceRpcResponseTopicFilter.equals(topicName);
78   - }
79   -
80 54 public TcpTransportAdaptor getPayloadAdaptor() {
81 55 return this.adaptor;
82 56 }
... ... @@ -85,15 +59,7 @@ public abstract class TcpDeviceWareSessionContext extends DeviceAwareSessionCont
85 59 @Override
86 60 public void setDeviceInfo(TransportDeviceInfo deviceInfo) {
87 61 super.setDeviceInfo(deviceInfo);
88   - try {
89   - JsonNode additionalInfo = context.getMapper().readTree(deviceInfo.getAdditionalInfo());
90   - if(additionalInfo !=null && additionalInfo.has(FastIotConstants.TCP_DEVICE_IDENTIFY_FILED)){
91   - deviceCode = additionalInfo.get(FastIotConstants.TCP_DEVICE_IDENTIFY_FILED).asText();
92   - }
93   - } catch (JsonProcessingException e) {
94   - log.trace("[{}][{}] Failed to fetch device additional info", sessionId, deviceInfo.getDeviceName(), e);
95   - }
96   -
  62 + deviceName = deviceInfo.getDeviceName();
97 63 }
98 64
99 65 @Override
... ... @@ -108,28 +74,71 @@ public abstract class TcpDeviceWareSessionContext extends DeviceAwareSessionCont
108 74 updateDeviceSessionConfiguration(deviceProfile);
109 75 }
110 76
111   - private void updateDeviceSessionConfiguration(DeviceProfile deviceProfile){
  77 + private void updateDeviceSessionConfiguration(DeviceProfile deviceProfile) {
112 78 DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
113 79
114 80 TkTcpDeviceProfileTransportConfiguration tcpConfiguration = (TkTcpDeviceProfileTransportConfiguration) transportConfiguration;
115   - payloadType = tcpConfiguration.getDataFormat();
116   - if (TcpDataTypeEnum.ASCII.equals(payloadType)) {
117   - payloadType = TcpDataTypeEnum.ASCII;
118   - } else {
119   - payloadType = TcpDataTypeEnum.HEX;
120   - }
121   - this.attributesTopicFilter = tcpConfiguration.getAttributesTopic();
122   - this.telemetryTopicFilter = tcpConfiguration.getTelemetryTopic();
123   - this.toDeviceRpcResponseTopicFilter = tcpConfiguration.getRpcTopic();
124   - String scriptBody = tcpConfiguration.getScriptText();
125   - try {
126   - this.scriptId = this.adaptor.getJsScriptEngineFunctionId(scriptBody==null? TkScriptFactory.INCLUD_ORIGINAL_DATA:scriptBody);
127   - } catch (ExecutionException e) {
128   - log.warn("设备配置【{}】的脚本【{}】解析异常",deviceProfile.getSearchText(),scriptBody);
129   - throw new RuntimeException(e);
130   - } catch (InterruptedException e) {
131   - throw new RuntimeException(e);
  81 + this.authScriptId = UUID.fromString(tcpConfiguration.getAuthScriptId());
  82 +
  83 + this.telemetryScriptId = UUID.fromString(tcpConfiguration.getUpScriptId());
  84 + TransportProtos.ScriptProto upScript = context.getTransportService().getScripts(TransportProtos.ScriptProto.newBuilder().setScriptIdLSB(telemetryScriptId.getLeastSignificantBits()).setScriptIdMSB(telemetryScriptId.getMostSignificantBits()).build()).get(0);
  85 + cacheScript(telemetryScriptId, TkScriptFunctionType.TRANSPORT_TCP_UP, upScript.getConvertJs(), null);
  86 +
  87 + this.rpcScriptId = UUID.fromString(tcpConfiguration.getDownScriptId());
  88 + TransportProtos.ScriptProto downScript = context.getTransportService().getScripts(TransportProtos.ScriptProto.newBuilder().setScriptIdLSB(rpcScriptId.getLeastSignificantBits()).setScriptIdMSB(rpcScriptId.getMostSignificantBits()).build()).get(0);
  89 + cacheScript(rpcScriptId, TkScriptFunctionType.TRANSPORT_TCP_DOWN, downScript.getConvertJs(), null);
  90 + }
  91 +
  92 + /**
  93 + * 编译并缓存脚本引擎
  94 + *
  95 + * @param scriptId 脚本引擎ID
  96 + * @param scriptType 脚本类型
  97 + * @param convertStr 脚本内容
  98 + * @param callback 脚本引擎执行成功的回调函数
  99 + */
  100 + public void cacheScript(UUID scriptId, TkScriptFunctionType scriptType, String convertStr, FutureCallback callback) {
  101 + ListenableFuture<UUID> result = context.getJsEngine().eval(scriptId, scriptType, convertStr);
  102 + if (callback == null) {
  103 + callback = new FutureCallback() {
  104 + @Override
  105 + public void onSuccess(@Nullable Object result) {
  106 +
  107 + }
  108 +
  109 + @Override
  110 + public void onFailure(Throwable t) {
  111 + log.error(String.format("脚本【%s】解析时出现异常:【%s】", convertStr, t));
  112 + }
  113 + };
132 114 }
  115 + Futures.addCallback(result, callback, MoreExecutors.directExecutor());
  116 + }
  117 +
  118 + /**
  119 + * 执行上行数据的解析脚本
  120 + *
  121 + * @param scriptParam 脚本函数入参
  122 + * @param onSuccess 脚本执行成功后的业务逻辑
  123 + */
  124 + public void doUpScript(String scriptParam, Consumer<TcpUpEntry> onSuccess) {
  125 + ListenableFuture future = context.getJsEngine().invokeFunction(this.telemetryScriptId, scriptParam);
  126 + Futures.addCallback(future, new FutureCallback<String>() {
  127 +
  128 + @Override
  129 + public void onSuccess(@org.checkerframework.checker.nullness.qual.Nullable String str) {
  130 + TcpUpEntry result = JacksonUtil.fromString(str, TcpUpEntry.class);
  131 + if (result == null) {
  132 + return;
  133 + }
  134 + onSuccess.accept(result);
  135 + }
  136 +
  137 + @Override
  138 + public void onFailure(Throwable t) {
  139 + log.error(t.getMessage());
  140 + }
  141 + }, MoreExecutors.directExecutor());
133 142 }
134 143
135 144 }
... ...
1 1 /**
2 2 * Copyright © 2016-2022 The Thingsboard Authors
3   - *
  3 + * <p>
4 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 5 * you may not use this file except in compliance with the License.
6 6 * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
  7 + * <p>
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + * <p>
10 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
12 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
... ... @@ -25,7 +25,6 @@ import org.thingsboard.server.common.transport.SessionMsgListener;
25 25 import org.thingsboard.server.common.transport.TransportService;
26 26 import org.thingsboard.server.common.transport.TransportServiceCallback;
27 27 import org.thingsboard.server.common.transport.auth.TransportDeviceInfo;
28   -import org.thingsboard.server.common.transport.session.DeviceAwareSessionContext;
29 28 import org.thingsboard.server.gen.transport.TransportProtos;
30 29 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
31 30 import org.thingsboard.server.transport.tcp.TcpTransportContext;
... ... @@ -43,7 +42,7 @@ public class TcpGatewayDeviceSessionCtx extends TcpDeviceWareSessionContext impl
43 42
44 43 public TcpGatewayDeviceSessionCtx(TcpTransportContext context, TcpGatewaySessionHandler parent, TransportDeviceInfo deviceInfo,
45 44 DeviceProfile deviceProfile, TransportService transportService) {
46   - super(UUID.randomUUID(),context);
  45 + super(UUID.randomUUID(), context);
47 46 this.parent = parent;
48 47 setSessionInfo(SessionInfoProto.newBuilder()
49 48 .setNodeId(parent.getNodeId())
... ... @@ -80,30 +79,21 @@ public class TcpGatewayDeviceSessionCtx extends TcpDeviceWareSessionContext impl
80 79
81 80 @Override
82 81 public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg response) {
83   - try {
84   - parent.getPayloadAdaptor().convertToGatewayPublish(this, getDeviceInfo().getDeviceName(), response).ifPresent(parent::pushDeviceMsg);
85   - } catch (Exception e) {
86   - log.trace("[{}] Failed to convert device attributes response to MQTT msg", sessionId, e);
87   - }
  82 + log.trace("[{}] convert device attributes response to TCP msg", sessionId, response);
88 83 }
89 84
90 85 @Override
91 86 public void onAttributeUpdate(UUID sessionId, TransportProtos.AttributeUpdateNotificationMsg notification) {
92 87 log.trace("[{}] Received attributes update notification to device", sessionId);
93   - try {
94   - parent.getPayloadAdaptor().convertToGatewayPublish(this, getDeviceInfo().getDeviceName(), notification).ifPresent(parent::pushDeviceMsg);
95   - } catch (Exception e) {
96   - log.trace("[{}] Failed to convert device attributes response to MQTT msg", sessionId, e);
97   - }
98 88 }
99 89
100 90 @Override
101 91 public void onToDeviceRpcRequest(UUID sessionId, TransportProtos.ToDeviceRpcRequestMsg request) {
102   - log.error("【{}】下发RPC命令【{}】给网关子设备", sessionId,request.getParams());
  92 + log.error("【{}】下发RPC命令【{}】给网关子设备", sessionId, request.getParams());
103 93 try {
104 94 parent.getPayloadAdaptor().convertToPublish(this, request).ifPresent(
105 95 payload -> {
106   - ChannelFuture channelFuture = parent.pushDeviceMsg(payload);
  96 + ChannelFuture channelFuture = parent.pushDeviceMsg(payload.getDatas());
107 97 if (request.getPersisted()) {
108 98 channelFuture.addListener(result -> {
109 99 if (result.cause() == null) {
... ...
1 1 /**
2 2 * Copyright © 2016-2022 The Thingsboard Authors
3   - *
  3 + * <p>
4 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 5 * you may not use this file except in compliance with the License.
6 6 * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
  7 + * <p>
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + * <p>
10 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
12 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
... ... @@ -20,28 +20,23 @@ import com.google.common.util.concurrent.FutureCallback;
20 20 import com.google.common.util.concurrent.Futures;
21 21 import com.google.common.util.concurrent.ListenableFuture;
22 22 import com.google.common.util.concurrent.SettableFuture;
23   -import com.google.gson.*;
24   -import com.google.protobuf.InvalidProtocolBufferException;
25   -import com.google.protobuf.ProtocolStringList;
  23 +import com.google.gson.JsonElement;
  24 +import com.google.gson.JsonObject;
  25 +import com.google.gson.JsonSyntaxException;
26 26 import io.netty.buffer.ByteBuf;
27 27 import io.netty.buffer.Unpooled;
28 28 import io.netty.channel.ChannelFuture;
29 29 import io.netty.channel.ChannelHandlerContext;
30 30 import io.netty.handler.codec.mqtt.MqttPublishMessage;
31 31 import lombok.extern.slf4j.Slf4j;
32   -import org.springframework.util.CollectionUtils;
33 32 import org.springframework.util.ConcurrentReferenceHashMap;
34 33 import org.springframework.util.StringUtils;
35   -import org.thingsboard.server.common.data.id.DeviceId;
36   -import org.thingsboard.server.common.data.yunteng.enums.TcpDataTypeEnum;
  34 +import org.thingsboard.common.util.JacksonUtil;
37 35 import org.thingsboard.server.common.transport.TransportService;
38 36 import org.thingsboard.server.common.transport.TransportServiceCallback;
39 37 import org.thingsboard.server.common.transport.adaptor.AdaptorException;
40   -import org.thingsboard.server.common.transport.adaptor.JsonConverter;
41   -import org.thingsboard.server.common.transport.adaptor.ProtoConverter;
42 38 import org.thingsboard.server.common.transport.auth.GetOrCreateDeviceFromGatewayResponse;
43 39 import org.thingsboard.server.common.transport.auth.TransportDeviceInfo;
44   -import org.thingsboard.server.gen.transport.TransportApiProtos;
45 40 import org.thingsboard.server.gen.transport.TransportProtos;
46 41 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg;
47 42 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
... ... @@ -51,7 +46,7 @@ import org.thingsboard.server.transport.tcp.util.ByteUtils;
51 46
52 47 import javax.annotation.Nullable;
53 48 import java.io.UnsupportedEncodingException;
54   -import java.util.*;
  49 +import java.util.UUID;
55 50 import java.util.concurrent.ConcurrentHashMap;
56 51 import java.util.concurrent.ConcurrentMap;
57 52 import java.util.concurrent.locks.Lock;
... ... @@ -97,37 +92,29 @@ public class TcpGatewaySessionHandler {
97 92 }
98 93
99 94
100   -
101   -
102   -
103   - public void onDeviceTelemetry(TCPMessage tcpMessage) throws AdaptorException {
104   - Futures.addCallback(checkDeviceConnected(tcpMessage.getDeviceCode()),
  95 + public void onDeviceTelemetry(String deviceName, UUID requestId, String deviceDataStr) {
  96 + Futures.addCallback(checkDeviceConnected(deviceName),
105 97 new FutureCallback<>() {
106 98 @Override
107 99 public void onSuccess(@Nullable TcpGatewayDeviceSessionCtx deviceCtx) {
108   - String deviceName = deviceCtx.getDeviceInfo().getDeviceName();
109   - try {
110   - TransportProtos.PostTelemetryMsg postTelemetryMsg = deviceCtx.getPayloadAdaptor().convertToPostTelemetry(deviceCtx,tcpMessage.getMessage());
111   - processPostTelemetryMsg(deviceCtx, postTelemetryMsg, deviceName, tcpMessage.getRequestId());
112   - } catch (Throwable e) {
113   - log.warn("[{}][{}] Failed to convert telemetry: {}", gateway.getDeviceId(), deviceName, tcpMessage.getMessage(), e);
114   - channel.close();
115   - }
  100 + deviceCtx.doUpScript(deviceDataStr, r -> {
  101 + try {
  102 + TransportProtos.PostTelemetryMsg postTelemetryMsg = deviceCtx.getPayloadAdaptor().convertToPostTelemetry(deviceCtx, JacksonUtil.toString(r.getDatas()));
  103 + processPostTelemetryMsg(deviceCtx, postTelemetryMsg, deviceName, requestId);
  104 + } catch (AdaptorException e) {
  105 + log.warn("[{}][{}] Failed to convert telemetry: {}", gateway.getDeviceId(), deviceName, deviceDataStr, e);
  106 + }
  107 + });
116 108 }
117 109
118 110 @Override
119 111 public void onFailure(Throwable t) {
120   - log.debug("[{}] Failed to process device telemetry command: {}", sessionId, tcpMessage.getDeviceCode(), t);
  112 + log.debug("[{}] Failed to process device telemetry command: {}", sessionId, deviceName, t);
121 113 }
122 114 }, context.getExecutor());
123 115 }
124 116
125 117
126   -
127   -
128   -
129   -
130   -
131 118 public void onGatewayDisconnect() {
132 119 devices.forEach(this::deregisterSession);
133 120 }
... ... @@ -158,7 +145,6 @@ public class TcpGatewaySessionHandler {
158 145 }
159 146
160 147
161   -
162 148 int nextMsgId() {
163 149 return deviceSessionCtx.nextMsgId();
164 150 }
... ... @@ -210,64 +196,49 @@ public class TcpGatewaySessionHandler {
210 196 if (future != null) {
211 197 return future;
212 198 }
213   - try {
214   - transportService.process(GetOrCreateDeviceFromGatewayRequestMsg.newBuilder()
215   - .setDeviceName(deviceName)
216   - .setDeviceType(deviceType)
217   - .setGatewayIdMSB(gateway.getDeviceId().getId().getMostSignificantBits())
218   - .setGatewayIdLSB(gateway.getDeviceId().getId().getLeastSignificantBits()).build(),
219   - new TransportServiceCallback<GetOrCreateDeviceFromGatewayResponse>() {
220   - @Override
221   - public void onSuccess(GetOrCreateDeviceFromGatewayResponse msg) {
222   - TcpGatewayDeviceSessionCtx deviceSessionCtx = new TcpGatewayDeviceSessionCtx(context,TcpGatewaySessionHandler.this, msg.getDeviceInfo(), msg.getDeviceProfile(), transportService);
223   - if (devices.putIfAbsent(deviceName, deviceSessionCtx) == null) {
224   - log.trace("[{}] First got or created device [{}], type [{}] for the gateway session", sessionId, deviceName, deviceType);
225   - SessionInfoProto deviceSessionInfo = deviceSessionCtx.getSessionInfo();
226   - transportService.registerAsyncSession(deviceSessionInfo, deviceSessionCtx);
227   - transportService.process(TransportProtos.TransportToDeviceActorMsg.newBuilder()
228   - .setSessionInfo(deviceSessionInfo)
229   - .setSessionEvent(SESSION_EVENT_MSG_OPEN)
230   - .setSubscribeToAttributes(SUBSCRIBE_TO_ATTRIBUTE_UPDATES_ASYNC_MSG)
231   - .setSubscribeToRPC(SUBSCRIBE_TO_RPC_ASYNC_MSG)
232   - .build(), null);
233   - }
234   - futureToSet.set(devices.get(deviceName));
235   - deviceFutures.remove(deviceName);
  199 + try {
  200 + transportService.process(GetOrCreateDeviceFromGatewayRequestMsg.newBuilder()
  201 + .setDeviceName(deviceName)
  202 + .setDeviceType(deviceType)
  203 + .setGatewayIdMSB(gateway.getDeviceId().getId().getMostSignificantBits())
  204 + .setGatewayIdLSB(gateway.getDeviceId().getId().getLeastSignificantBits()).build(),
  205 + new TransportServiceCallback<GetOrCreateDeviceFromGatewayResponse>() {
  206 + @Override
  207 + public void onSuccess(GetOrCreateDeviceFromGatewayResponse msg) {
  208 + TcpGatewayDeviceSessionCtx deviceSessionCtx = new TcpGatewayDeviceSessionCtx(context, TcpGatewaySessionHandler.this, msg.getDeviceInfo(), msg.getDeviceProfile(), transportService);
  209 + if (devices.putIfAbsent(deviceName, deviceSessionCtx) == null) {
  210 + log.trace("[{}] First got or created device [{}], type [{}] for the gateway session", sessionId, deviceName, deviceType);
  211 + SessionInfoProto deviceSessionInfo = deviceSessionCtx.getSessionInfo();
  212 + transportService.registerAsyncSession(deviceSessionInfo, deviceSessionCtx);
  213 + transportService.process(TransportProtos.TransportToDeviceActorMsg.newBuilder()
  214 + .setSessionInfo(deviceSessionInfo)
  215 + .setSessionEvent(SESSION_EVENT_MSG_OPEN)
  216 + .setSubscribeToAttributes(SUBSCRIBE_TO_ATTRIBUTE_UPDATES_ASYNC_MSG)
  217 + .setSubscribeToRPC(SUBSCRIBE_TO_RPC_ASYNC_MSG)
  218 + .build(), null);
236 219 }
  220 + futureToSet.set(devices.get(deviceName));
  221 + deviceFutures.remove(deviceName);
  222 + }
237 223
238   - @Override
239   - public void onError(Throwable e) {
240   - log.warn("[{}] Failed to process device connect command: {}", sessionId, deviceName, e);
241   - futureToSet.setException(e);
242   - deviceFutures.remove(deviceName);
243   - }
244   - });
245   - return futureToSet;
246   - } catch (Throwable e) {
247   - deviceFutures.remove(deviceName);
248   - throw e;
249   - }
  224 + @Override
  225 + public void onError(Throwable e) {
  226 + log.warn("[{}] Failed to process device connect command: {}", sessionId, deviceName, e);
  227 + futureToSet.setException(e);
  228 + deviceFutures.remove(deviceName);
  229 + }
  230 + });
  231 + return futureToSet;
  232 + } catch (Throwable e) {
  233 + deviceFutures.remove(deviceName);
  234 + throw e;
  235 + }
250 236 }
251 237
252 238 private int getMsgId(MqttPublishMessage mqttMsg) {
253 239 return mqttMsg.variableHeader().packetId();
254 240 }
255 241
256   - public void onDeviceConnect(MqttPublishMessage mqttMsg) throws AdaptorException {
257   - JsonElement json = getJson(mqttMsg);
258   - String deviceName = checkDeviceName(getDeviceName(json));
259   - String deviceType = getDeviceType(json);
260   - processOnConnect(mqttMsg, deviceName, deviceType);
261   - }
262   -
263   -
264   -
265   - public void onDeviceDisconnect(MqttPublishMessage mqttMsg) throws AdaptorException {
266   - String deviceName = checkDeviceName(getDeviceName(getJson(mqttMsg)));
267   - processOnDisconnect(mqttMsg, deviceName);
268   - }
269   -
270   -
271 242
272 243 private void processOnDisconnect(MqttPublishMessage msg, String deviceName) {
273 244 deregisterSession(deviceName);
... ... @@ -275,113 +246,40 @@ public class TcpGatewaySessionHandler {
275 246 }
276 247
277 248
278   -
279   -
280   - private void processPostTelemetryMsg(TcpGatewayDeviceSessionCtx deviceCtx, TransportProtos.PostTelemetryMsg postTelemetryMsg, String deviceName, String msgId) {
  249 + private void processPostTelemetryMsg(TcpGatewayDeviceSessionCtx deviceCtx, TransportProtos.PostTelemetryMsg postTelemetryMsg, String deviceName, UUID msgId) {
281 250 transportService.process(deviceCtx.getSessionInfo(), postTelemetryMsg, getPubAckCallback(channel, deviceName, msgId, postTelemetryMsg));
282 251 }
283   - public void onDeviceClaim(MqttPublishMessage mqttMsg) throws AdaptorException {
284   - int msgId = getMsgId(mqttMsg);
285   - ByteBuf payload = mqttMsg.payload();
286   - JsonElement json = null;//JsonMqttAdaptor.validateJsonPayload(sessionId, payload);
287   - if (json.isJsonObject()) {
288   - JsonObject jsonObj = json.getAsJsonObject();
289   - for (Map.Entry<String, JsonElement> deviceEntry : jsonObj.entrySet()) {
290   - String deviceName = deviceEntry.getKey();
291   - Futures.addCallback(checkDeviceConnected(deviceName),
292   - new FutureCallback<TcpGatewayDeviceSessionCtx>() {
293   - @Override
294   - public void onSuccess(@Nullable TcpGatewayDeviceSessionCtx deviceCtx) {
295   - if (!deviceEntry.getValue().isJsonObject()) {
296   - throw new JsonSyntaxException(CAN_T_PARSE_VALUE + json);
297   - }
298   - try {
299   - DeviceId deviceId = deviceCtx.getDeviceId();
300   - TransportProtos.ClaimDeviceMsg claimDeviceMsg = JsonConverter.convertToClaimDeviceProto(deviceId, deviceEntry.getValue());
301   - processClaimDeviceMsg(deviceCtx, claimDeviceMsg, deviceName, msgId);
302   - } catch (Throwable e) {
303   - log.warn("[{}][{}] Failed to convert claim message: {}", gateway.getDeviceId(), deviceName, deviceEntry.getValue(), e);
304   - }
305   - }
306   -
307   - @Override
308   - public void onFailure(Throwable t) {
309   - log.debug("[{}] Failed to process device claiming command: {}", sessionId, deviceName, t);
310   - }
311   - }, context.getExecutor());
312   - }
313   - } else {
314   - throw new JsonSyntaxException(CAN_T_PARSE_VALUE + json);
315   - }
316   - }
317   -
318   -
319   - private void processClaimDeviceMsg(TcpGatewayDeviceSessionCtx deviceCtx, TransportProtos.ClaimDeviceMsg claimDeviceMsg, String deviceName, int msgId) {
320   - transportService.process(deviceCtx.getSessionInfo(), claimDeviceMsg, getPubAckCallback(channel, deviceName, msgId+"", claimDeviceMsg));
321   - }
322 252
323   - public void onDeviceAttributes(TCPMessage mqttMsg) throws AdaptorException {
324   - int msgId = 0;//getMsgId(mqttMsg);
325   - ByteBuf payload = null;//mqttMsg.payload();
326   - JsonElement json = null;//JsonMqttAdaptor.validateJsonPayload(sessionId, payload);
327   - if (json.isJsonObject()) {
328   - JsonObject jsonObj = json.getAsJsonObject();
329   - for (Map.Entry<String, JsonElement> deviceEntry : jsonObj.entrySet()) {
330   - String deviceName = deviceEntry.getKey();
331   - Futures.addCallback(checkDeviceConnected(deviceName),
332   - new FutureCallback<TcpGatewayDeviceSessionCtx>() {
333   - @Override
334   - public void onSuccess(@Nullable TcpGatewayDeviceSessionCtx deviceCtx) {
335   - if (!deviceEntry.getValue().isJsonObject()) {
336   - throw new JsonSyntaxException(CAN_T_PARSE_VALUE + json);
337   - }
338   - TransportProtos.PostAttributeMsg postAttributeMsg = JsonConverter.convertToAttributesProto(deviceEntry.getValue().getAsJsonObject());
339   - processPostAttributesMsg(deviceCtx, postAttributeMsg, deviceName, msgId);
  253 + public void onDeviceAttributes(String deviceName, UUID requestId, String deviceDataStr) {
  254 + Futures.addCallback(checkDeviceConnected(deviceName),
  255 + new FutureCallback<TcpGatewayDeviceSessionCtx>() {
  256 + @Override
  257 + public void onSuccess(@Nullable TcpGatewayDeviceSessionCtx deviceCtx) {
  258 + deviceCtx.doUpScript(deviceDataStr, r -> {
  259 + try {
  260 + TransportProtos.PostAttributeMsg postAttributeMsg = deviceCtx.getPayloadAdaptor().convertToPostAttributes(deviceCtx, JacksonUtil.toString(r.getDatas()));
  261 + processPostAttributesMsg(deviceCtx, postAttributeMsg, deviceName, requestId);
  262 + } catch (AdaptorException e) {
  263 + log.warn("[{}][{}] Failed to convert telemetry: {}", gateway.getDeviceId(), deviceName, deviceDataStr, e);
340 264 }
  265 + });
  266 + }
341 267
342   - @Override
343   - public void onFailure(Throwable t) {
344   - log.debug("[{}] Failed to process device attributes command: {}", sessionId, deviceName, t);
345   - }
346   - }, context.getExecutor());
347   - }
348   - } else {
349   - throw new JsonSyntaxException(CAN_T_PARSE_VALUE + json);
350   - }
  268 + @Override
  269 + public void onFailure(Throwable t) {
  270 + log.debug("[{}] Failed to process device attributes command: {}", sessionId, deviceName, t);
  271 + }
  272 + }, context.getExecutor());
351 273 }
352 274
353 275
354   - private void processPostAttributesMsg(TcpGatewayDeviceSessionCtx deviceCtx, TransportProtos.PostAttributeMsg postAttributeMsg, String deviceName, int msgId) {
355   - transportService.process(deviceCtx.getSessionInfo(), postAttributeMsg, getPubAckCallback(channel, deviceName, msgId+"", postAttributeMsg));
356   - }
357   -
358   - public void onDeviceAttributesRequest(MqttPublishMessage mqttMsg) throws AdaptorException {
359   - JsonElement json = null;//JsonMqttAdaptor.validateJsonPayload(sessionId, msg.payload());
360   - if (json.isJsonObject()) {
361   - JsonObject jsonObj = json.getAsJsonObject();
362   - int requestId = jsonObj.get("id").getAsInt();
363   - String deviceName = jsonObj.get(DEVICE_PROPERTY).getAsString();
364   - boolean clientScope = jsonObj.get("client").getAsBoolean();
365   - Set<String> keys;
366   - if (jsonObj.has("key")) {
367   - keys = Collections.singleton(jsonObj.get("key").getAsString());
368   - } else {
369   - JsonArray keysArray = jsonObj.get("keys").getAsJsonArray();
370   - keys = new HashSet<>();
371   - for (JsonElement keyObj : keysArray) {
372   - keys.add(keyObj.getAsString());
373   - }
374   - }
375   - TransportProtos.GetAttributeRequestMsg requestMsg = toGetAttributeRequestMsg(requestId, clientScope, keys);
376   - processGetAttributeRequestMessage(mqttMsg, deviceName, requestMsg);
377   - } else {
378   - throw new JsonSyntaxException(CAN_T_PARSE_VALUE + json);
379   - }
  276 + private void processPostAttributesMsg(TcpGatewayDeviceSessionCtx deviceCtx, TransportProtos.PostAttributeMsg postAttributeMsg, String deviceName, UUID msgId) {
  277 + transportService.process(deviceCtx.getSessionInfo(), postAttributeMsg, getPubAckCallback(channel, deviceName, msgId, postAttributeMsg));
380 278 }
381 279
382 280
383 281 public void onDeviceRpcResponse(MqttPublishMessage mqttMsg) throws AdaptorException {
384   - int msgId = getMsgId(mqttMsg);
  282 + UUID msgId = null;
385 283 ByteBuf payload = mqttMsg.payload();
386 284 JsonElement json = null;// JsonMqttAdaptor.validateJsonPayload(sessionId, payload);
387 285 if (json.isJsonObject()) {
... ... @@ -409,38 +307,10 @@ public class TcpGatewaySessionHandler {
409 307 }
410 308
411 309
412   - private void processRpcResponseMsg(TcpGatewayDeviceSessionCtx deviceCtx, TransportProtos.ToDeviceRpcResponseMsg rpcResponseMsg, String deviceName, int msgId) {
413   - transportService.process(deviceCtx.getSessionInfo(), rpcResponseMsg, getPubAckCallback(channel, deviceName, msgId+"", rpcResponseMsg));
414   - }
415   -
416   - private void processGetAttributeRequestMessage(MqttPublishMessage mqttMsg, String deviceName, TransportProtos.GetAttributeRequestMsg requestMsg) {
417   - int msgId = getMsgId(mqttMsg);
418   - Futures.addCallback(checkDeviceConnected(deviceName),
419   - new FutureCallback<TcpGatewayDeviceSessionCtx>() {
420   - @Override
421   - public void onSuccess(@Nullable TcpGatewayDeviceSessionCtx deviceCtx) {
422   - transportService.process(deviceCtx.getSessionInfo(), requestMsg, getPubAckCallback(channel, deviceName, msgId+"", requestMsg));
423   - }
424   -
425   - @Override
426   - public void onFailure(Throwable t) {
427   - ack(mqttMsg);
428   - log.debug("[{}] Failed to process device attributes request command: {}", sessionId, deviceName, t);
429   - }
430   - }, context.getExecutor());
  310 + private void processRpcResponseMsg(TcpGatewayDeviceSessionCtx deviceCtx, TransportProtos.ToDeviceRpcResponseMsg rpcResponseMsg, String deviceName, UUID msgId) {
  311 + transportService.process(deviceCtx.getSessionInfo(), rpcResponseMsg, getPubAckCallback(channel, deviceName, msgId, rpcResponseMsg));
431 312 }
432 313
433   - private TransportProtos.GetAttributeRequestMsg toGetAttributeRequestMsg(int requestId, boolean clientScope, Set<String> keys) {
434   - TransportProtos.GetAttributeRequestMsg.Builder result = TransportProtos.GetAttributeRequestMsg.newBuilder();
435   - result.setRequestId(requestId);
436   -
437   - if (clientScope) {
438   - result.addAllClientAttributeNames(keys);
439   - } else {
440   - result.addAllSharedAttributeNames(keys);
441   - }
442   - return result.build();
443   - }
444 314
445 315 private ListenableFuture<TcpGatewayDeviceSessionCtx> checkDeviceConnected(String deviceCode) {
446 316 TcpGatewayDeviceSessionCtx ctx = devices.get(deviceCode);
... ... @@ -452,29 +322,6 @@ public class TcpGatewaySessionHandler {
452 322 }
453 323 }
454 324
455   - private String checkDeviceName(String deviceName) {
456   - if (StringUtils.isEmpty(deviceName)) {
457   - throw new RuntimeException("Device name is empty!");
458   - } else {
459   - return deviceName;
460   - }
461   - }
462   -
463   - private String getDeviceName(JsonElement json) {
464   - return json.getAsJsonObject().get(DEVICE_PROPERTY).getAsString();
465   - }
466   -
467   - private String getDeviceType(JsonElement json) {
468   - JsonElement type = json.getAsJsonObject().get("type");
469   - return type == null || type instanceof JsonNull ? DEFAULT_DEVICE_TYPE : type.getAsString();
470   - }
471   -
472   - private JsonElement getJson(MqttPublishMessage mqttMsg) throws AdaptorException {
473   - return null;//JsonMqttAdaptor.validateJsonPayload(sessionId, mqttMsg.payload());
474   - }
475   -
476   -
477   -
478 325
479 326 private void deregisterSession(String deviceName, TcpGatewayDeviceSessionCtx deviceSessionCtx) {
480 327 transportService.deregisterSession(deviceSessionCtx.getSessionInfo());
... ... @@ -482,13 +329,13 @@ public class TcpGatewaySessionHandler {
482 329 log.debug("[{}] Removed device [{}] from the gateway session", sessionId, deviceName);
483 330 }
484 331
485   - private <T> TransportServiceCallback<Void> getPubAckCallback(final ChannelHandlerContext ctx, final String deviceName, final String msgId, final T msg) {
  332 + private <T> TransportServiceCallback<Void> getPubAckCallback(final ChannelHandlerContext ctx, final String deviceName, final UUID msgId, final T msg) {
486 333 return new TransportServiceCallback<Void>() {
487 334 @Override
488 335 public void onSuccess(Void dummy) {
489 336 log.trace("[{}][{}] Published msg: {}", sessionId, deviceName, msg);
490   - if(!StringUtils.isEmpty(msgId)){
491   - pushDeviceMsg(new TCPMessage(msgId));
  337 + if (!StringUtils.isEmpty(msgId)) {
  338 + pushDeviceMsg(msgId.toString());
492 339 }
493 340 }
494 341
... ... @@ -499,31 +346,25 @@ public class TcpGatewaySessionHandler {
499 346 }
500 347 };
501 348 }
  349 +
502 350 /**
503 351 * 往设备推送消息
504   - * @param tcp
  352 + * @param message
505 353 * @return
506 354 */
507   - ChannelFuture pushDeviceMsg(TCPMessage tcp) {
  355 + ChannelFuture pushDeviceMsg(String message) {
508 356 try {
509   - String message = tcp.getMessage();
510   - byte[] payloadInBytes ;
511   - if(deviceSessionCtx.getPayloadType().equals(TcpDataTypeEnum.HEX)){
512   - payloadInBytes = ByteUtils.hexStr2Bytes(message);
513   - }else{
514   - payloadInBytes = message.getBytes(ByteUtils.UTF_8);
515   - }
516   -// ByteBufAllocator ALLOCATOR = new UnpooledByteBufAllocator(false);
517   -// ByteBuf payload = ALLOCATOR.buffer();
518   -// payload.writeBytes(payloadInBytes);
  357 + byte[] payloadInBytes;
  358 + payloadInBytes = message.getBytes(ByteUtils.UTF_8);
519 359 ByteBuf payload = Unpooled.copiedBuffer(payloadInBytes);
520 360
521 361 return channel.writeAndFlush(payload);
522 362 } catch (UnsupportedEncodingException e) {
523   - log.error(e.getMessage(),e);
  363 + log.error(e.getMessage(), e);
524 364 throw new RuntimeException(e);
525 365 }
526 366 }
  367 +
527 368 private void ack(MqttPublishMessage msg) {
528 369 int msgId = getMsgId(msg);
529 370 if (msgId > 0) {
... ...
... ... @@ -57,7 +57,9 @@ import org.thingsboard.server.gen.transport.TransportProtos.ValidateBasicMqttCre
57 57 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg;
58 58 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg;
59 59 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg;
  60 +import org.thingsboard.server.gen.transport.TransportProtos.ScriptProto;
60 61
  62 +import java.util.List;
61 63 import java.util.concurrent.ExecutorService;
62 64 import java.util.concurrent.atomic.AtomicInteger;
63 65
... ... @@ -76,6 +78,8 @@ public interface TransportService {
76 78
77 79 GetDeviceCredentialsResponseMsg getDeviceCredentials(GetDeviceCredentialsRequestMsg requestMsg);
78 80
  81 +
  82 +
79 83 void process(DeviceTransportType transportType, ValidateDeviceTokenRequestMsg msg,
80 84 TransportServiceCallback<ValidateDeviceCredentialsResponse> callback);
81 85
... ... @@ -145,4 +149,11 @@ public interface TransportService {
145 149 boolean hasSession(SessionInfoProto sessionInfo);
146 150
147 151 void createGaugeStats(String openConnections, AtomicInteger connectionsCounter);
  152 +
  153 +
  154 +
  155 +
  156 +
  157 + //Thingskit function
  158 + List<ScriptProto> getScripts(ScriptProto msg);
148 159 }
... ...
... ... @@ -81,6 +81,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg;
81 81 import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg;
82 82 import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg;
83 83 import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg;
  84 +import org.thingsboard.server.gen.transport.TransportProtos.ScriptProto;
84 85 import org.thingsboard.server.queue.TbQueueCallback;
85 86 import org.thingsboard.server.queue.TbQueueConsumer;
86 87 import org.thingsboard.server.queue.TbQueueMsgMetadata;
... ... @@ -315,6 +316,8 @@ public class DefaultTransportService implements TransportService {
315 316 }
316 317 }
317 318
  319 +
  320 +
318 321 @Override
319 322 public TransportProtos.GetSnmpDevicesResponseMsg getSnmpDevicesIds(TransportProtos.GetSnmpDevicesRequestMsg requestMsg) {
320 323 TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>(
... ... @@ -1241,4 +1244,25 @@ public class DefaultTransportService implements TransportService {
1241 1244 log.info("Transport Stats: {}", values);
1242 1245 }
1243 1246 }
  1247 +
  1248 +
  1249 +
  1250 +
  1251 +
  1252 +
  1253 +
  1254 +
  1255 +
  1256 + //Thingskit function
  1257 + @Override
  1258 + public List<ScriptProto> getScripts(ScriptProto msg) {
  1259 + TbProtoQueueMsg<TransportProtos.TransportApiRequestMsg> protoMsg =
  1260 + new TbProtoQueueMsg<>(UUID.randomUUID(), TransportProtos.TransportApiRequestMsg.newBuilder().setScript(msg).build());
  1261 + try {
  1262 + TbProtoQueueMsg<TransportApiResponseMsg> response = transportApiRequestTemplate.send(protoMsg).get();
  1263 + return response.getValue().getScriptsResponseMsgList();
  1264 + } catch (InterruptedException | ExecutionException e) {
  1265 + throw new RuntimeException(e);
  1266 + }
  1267 + }
1244 1268 }
... ...
1   -/**
2   - * Copyright © 2016-2022 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.common.yunteng.script;
17   -
18   -public class TkScriptFactory {
19   -
20   - public static final String MSG = "params";
21   -
22   - public static final String RULE_NODE_FUNCTION_NAME = "tcpTransportFunc";
23   -
24   - public static final String INCLUD_ORIGINAL_DATA = "out.source=params;";
25   - private static final String JS_WRAPPER_PREFIX_TEMPLATE = "function %s(params) { " +
26   - " var out = new Object(); " +
27   - " return JSON.stringify(%s(params));" +
28   - " function %s(%s) {";
29   - private static final String JS_WRAPPER_SUFFIX = "return out; \n }" +
30   - "\n}";
31   -
32   -
33   - public static String generateRuleNodeScript(String functionName, String scriptBody, String... argNames) {
34   - String msgArg;
35   -
36   - msgArg = (argNames != null && argNames.length >= 1) ? argNames[0]:MSG;
37   -
38   - String jsWrapperPrefix = String.format(JS_WRAPPER_PREFIX_TEMPLATE
39   - , functionName
40   - ,RULE_NODE_FUNCTION_NAME
41   - , RULE_NODE_FUNCTION_NAME, msgArg);
42   - String result = jsWrapperPrefix + scriptBody + JS_WRAPPER_SUFFIX;
43   - return result;
44   - }
45   -
46   -}
1   -/**
2   - * Copyright © 2016-2022 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.common.yunteng.script;
17   -
18   -public enum TkScriptType {
19   - TCP_TRANSPORT_SCRIPT
20   -}
... ... @@ -7,21 +7,27 @@ import lombok.EqualsAndHashCode;
7 7 import org.apache.ibatis.type.BooleanTypeHandler;
8 8 import org.apache.ibatis.type.EnumTypeHandler;
9 9 import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
10   -import org.thingsboard.server.common.data.yunteng.enums.TcpDataTypeEnum;
  10 +import org.thingsboard.server.common.data.yunteng.enums.TkScriptFunctionType;
11 11
12 12 @Data
13 13 @TableName(value = ModelConstants.Table.TK_DEVICE_SCRIPT_TABLE_NAME, autoResultMap = true)
14 14 @EqualsAndHashCode(callSuper = true)
15 15 public class TkDeviceScriptEntity extends TenantBaseEntity {
16   - private String name;
17   - private String convertJs;
18   - /** 告警状态:0:正常 1:告警 */
19   - private Integer status;
  16 + private String name;
  17 + private String convertJs;
  18 + /**
  19 + * 告警状态:0:正常 1:告警
  20 + */
  21 + private Integer status;
20 22
21   - private String description;
22   - @TableField(typeHandler = BooleanTypeHandler.class)
23   - private boolean saveOriginalData;
24   - /** 脚本编数据编码类型 */
25   - @TableField(typeHandler = EnumTypeHandler.class)
26   - private TcpDataTypeEnum dataType;
  23 + private String description;
  24 + @TableField(typeHandler = BooleanTypeHandler.class)
  25 + private boolean saveOriginalData;
  26 +
  27 +
  28 + /**
  29 + * 脚本类型
  30 + */
  31 + @TableField(typeHandler = EnumTypeHandler.class)
  32 + private TkScriptFunctionType scriptType;
27 33 }
... ...
... ... @@ -19,6 +19,7 @@ import org.thingsboard.server.common.data.yunteng.core.exception.TkDataValidatio
19 19 import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage;
20 20 import org.thingsboard.server.common.data.yunteng.dto.*;
21 21 import org.thingsboard.server.common.data.yunteng.enums.DeviceTypeEnum;
  22 +import org.thingsboard.server.common.data.yunteng.enums.TransportTypeEnum;
22 23 import org.thingsboard.server.common.data.yunteng.utils.tools.TkPageData;
23 24 import org.thingsboard.server.dao.yunteng.entities.*;
24 25 import org.thingsboard.server.dao.yunteng.jpa.dao.TkJpaDeviceProfileDao;
... ... @@ -244,22 +245,11 @@ public class TkDeviceProfileServiceImpl
244 245 }
245 246
246 247 @Override
247   - public List<DeviceProfileDTO> findDeviceProfileByIds(String tenantId, List<String> ids) {
  248 + public List<DeviceProfileDTO> findDeviceProfileByIds(String tenantId, List<String> ids, TransportTypeEnum transportType) {
248 249 if (StringUtils.isEmpty(tenantId) || null == ids) {
249 250 throw new TkDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
250 251 }
251   - List<TkDeviceProfileEntity> entities =
252   - baseMapper.selectList(
253   - new LambdaQueryWrapper<TkDeviceProfileEntity>()
254   - .eq(TkDeviceProfileEntity::getTenantId, tenantId)
255   - .in(TkDeviceProfileEntity::getId, ids));
256   -
257   - if (null == entities || entities.isEmpty()) {
258   - return null;
259   - }
260   - return entities.stream()
261   - .map(obj -> obj.getDTO(DeviceProfileDTO.class))
262   - .collect(Collectors.toList());
  252 + return baseMapper.profileByTransportAndIds(tenantId,ids,transportType);
263 253 }
264 254
265 255 @Override
... ...
... ... @@ -8,6 +8,7 @@ import lombok.extern.slf4j.Slf4j;
8 8 import org.apache.commons.lang3.StringUtils;
9 9 import org.springframework.stereotype.Service;
10 10 import org.springframework.transaction.annotation.Transactional;
  11 +import org.thingsboard.server.common.data.device.profile.TkTcpDeviceProfileTransportConfiguration;
11 12 import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants;
12 13 import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
13 14 import org.thingsboard.server.common.data.yunteng.constant.QueryConstant;
... ... @@ -17,6 +18,8 @@ import org.thingsboard.server.common.data.yunteng.dto.DeviceDTO;
17 18 import org.thingsboard.server.common.data.yunteng.dto.DeviceProfileDTO;
18 19 import org.thingsboard.server.common.data.yunteng.dto.TkCustomerDeviceDTO;
19 20 import org.thingsboard.server.common.data.yunteng.dto.TkDeviceScriptDTO;
  21 +import org.thingsboard.server.common.data.yunteng.enums.TkScriptFunctionType;
  22 +import org.thingsboard.server.common.data.yunteng.enums.TransportTypeEnum;
20 23 import org.thingsboard.server.common.data.yunteng.utils.tools.TkPageData;
21 24 import org.thingsboard.server.dao.yunteng.entities.TkDeviceProfileEntity;
22 25 import org.thingsboard.server.dao.yunteng.entities.TkDeviceScriptEntity;
... ... @@ -98,14 +101,21 @@ public class TkDeviceScriptServiceImpl
98 101 }
99 102
100 103 @Override
101   - public String getScriptText(String tenantId, String scriptId) {
  104 + public List<TkDeviceScriptDTO> getScriptes(TkScriptFunctionType type, UUID tenantId, UUID projectId, UUID scriptId){
102 105 LambdaQueryWrapper<TkDeviceScriptEntity> queryWrapper =
103   - new QueryWrapper<TkDeviceScriptEntity>()
104   - .lambda()
105   - .eq(TkDeviceScriptEntity::getTenantId, tenantId)
106   - .eq(TkDeviceScriptEntity::getId, scriptId);
107   - TkDeviceScriptEntity result = baseMapper.selectOne(queryWrapper);
108   - return (result == null || result.getStatus() == 0) ? null : result.getConvertJs();
  106 + new QueryWrapper<TkDeviceScriptEntity>().lambda();
  107 + if(scriptId == null){
  108 + queryWrapper.eq(TkDeviceScriptEntity::getScriptType, type);
  109 + }else{
  110 + queryWrapper.eq(TkDeviceScriptEntity::getId, scriptId.toString());
  111 + }
  112 + if(tenantId != null){
  113 + queryWrapper.eq(TkDeviceScriptEntity::getTenantId, tenantId.toString());
  114 + }
  115 + List<TkDeviceScriptEntity> result = baseMapper.selectList(queryWrapper);
  116 + return result.stream()
  117 + .map(item -> item.getDTO(TkDeviceScriptDTO.class))
  118 + .collect(Collectors.toList());
109 119 }
110 120
111 121 @Override
... ... @@ -264,13 +274,19 @@ public class TkDeviceScriptServiceImpl
264 274 .map(DeviceDTO::getDeviceProfileId)
265 275 .collect(Collectors.toList());
266 276 List<DeviceProfileDTO> deviceProfileDTOList =
267   - tkDeviceProfileService.findDeviceProfileByIds(tenantId, deviceProfiles);
  277 + tkDeviceProfileService.findDeviceProfileByIds(tenantId, deviceProfiles, TransportTypeEnum.TCP);
268 278 return Optional.ofNullable(deviceProfileDTOList)
269 279 .map(
270   - deviceProfileDTOS ->
271   - deviceProfileDTOS.stream()
272   - .map(DeviceProfileDTO::getScriptId)
273   - .collect(Collectors.toSet()))
  280 + deviceProfileDTOS ->{
  281 + Set<String> tcpScriptes = new HashSet<>();
  282 + deviceProfileDTOS.forEach(p->{
  283 + TkTcpDeviceProfileTransportConfiguration config = (TkTcpDeviceProfileTransportConfiguration) p.getProfileData().getTransportConfiguration();
  284 + tcpScriptes.add(config.getUpScriptId());
  285 + tcpScriptes.add(config.getUpScriptId());
  286 + tcpScriptes.add(config.getUpScriptId());
  287 + });
  288 + return tcpScriptes;
  289 + })
274 290 .orElse(null);
275 291 }
276 292 return null;
... ...
... ... @@ -7,6 +7,7 @@ import org.apache.ibatis.annotations.Param;
7 7 import org.thingsboard.server.common.data.DeviceTransportType;
8 8 import org.thingsboard.server.common.data.yunteng.dto.*;
9 9 import org.thingsboard.server.common.data.yunteng.enums.DeviceTypeEnum;
  10 +import org.thingsboard.server.common.data.yunteng.enums.TransportTypeEnum;
10 11 import org.thingsboard.server.dao.yunteng.entities.TkDeviceProfileEntity;
11 12
12 13 import java.util.List;
... ... @@ -28,10 +29,17 @@ public interface TkDeviceProfileMapper extends BaseMapper<TkDeviceProfileEntity>
28 29 @Param("transportType") String transportType,
29 30 @Param("deviceProfileIds") List<String> deviceProfileIds);
30 31
  32 + @Deprecated
31 33 List<DeviceProfileDTO> profileByScriptId(
32   - @Param("tenantId") String tenantId,
33   - @Param("scriptId") String scriptId,
34   - @Param("deviceType") DeviceTypeEnum deviceType);
  34 + @Param("tenantId") String tenantId,
  35 + @Param("scriptId") String scriptId,
  36 + @Param("deviceType") DeviceTypeEnum deviceType);
  37 +
  38 + List<DeviceProfileDTO> profileByTransportAndIds(
  39 + @Param("tenantId") String tenantId,
  40 + @Param("projectIds") List<String> projectIds,
  41 + @Param("deviceType") TransportTypeEnum transportType);
  42 +
35 43
36 44 List<String> getDeviceProfileIds(
37 45 @Param("tenantId") String tenantId,
... ...
... ... @@ -3,6 +3,7 @@ package org.thingsboard.server.dao.yunteng.service;
3 3 import org.thingsboard.server.common.data.id.CustomerId;
4 4 import org.thingsboard.server.common.data.yunteng.dto.DeviceProfileDTO;
5 5 import org.thingsboard.server.common.data.yunteng.enums.DeviceTypeEnum;
  6 +import org.thingsboard.server.common.data.yunteng.enums.TransportTypeEnum;
6 7 import org.thingsboard.server.common.data.yunteng.utils.tools.TkPageData;
7 8 import org.thingsboard.server.dao.yunteng.entities.TkDeviceProfileEntity;
8 9
... ... @@ -29,7 +30,7 @@ public interface TkDeviceProfileService extends BaseService<TkDeviceProfileEntit
29 30 List<DeviceProfileDTO> findCustomerDeviceProfiles(
30 31 String tenantId, CustomerId customerId, DeviceTypeEnum deviceType);
31 32
32   - List<DeviceProfileDTO> findDeviceProfileByIds(String tenantId, List<String> ids);
  33 + List<DeviceProfileDTO> findDeviceProfileByIds(String tenantId, List<String> ids, TransportTypeEnum transportType);
33 34
34 35 List<DeviceProfileDTO> findDeviceProfile(String tenantId);
35 36 /** 验证表单数据有效性 */
... ...
1 1 package org.thingsboard.server.dao.yunteng.service;
2 2
3 3 import org.thingsboard.server.common.data.yunteng.dto.TkDeviceScriptDTO;
  4 +import org.thingsboard.server.common.data.yunteng.enums.TkScriptFunctionType;
4 5 import org.thingsboard.server.common.data.yunteng.utils.tools.TkPageData;
5 6 import org.thingsboard.server.dao.yunteng.entities.TkDeviceScriptEntity;
6 7
7   -import java.util.List;
8   -import java.util.Map;
9   -import java.util.Optional;
10   -import java.util.Set;
  8 +import java.util.*;
11 9
12 10 public interface TkDeviceScriptService extends BaseService<TkDeviceScriptEntity>{
13 11
... ... @@ -17,7 +15,7 @@ public interface TkDeviceScriptService extends BaseService<TkDeviceScriptEntity>
17 15 * @param scriptId
18 16 * @return
19 17 */
20   - String getScriptText(String tenantId, String scriptId);
  18 + List<TkDeviceScriptDTO> getScriptes(TkScriptFunctionType type, UUID tenantId, UUID projectId, UUID scriptId);
21 19
22 20 TkDeviceScriptDTO insertOrUpdate(TkDeviceScriptDTO deviceDTO);
23 21
... ...
... ... @@ -12,7 +12,6 @@
12 12 <result property="image" column="image"/>
13 13 <result property="description" column="description"/>
14 14 <result property="tenantId" column="tenant_id"/>
15   - <result property="scriptId" column="script_id"/>
16 15 <result property="transportType" column="transport_type"/>
17 16 <result property="provisionType" column="provision_type"/>
18 17 <result property="deviceType" column="device_type" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
... ... @@ -86,6 +85,25 @@
86 85 </where>
87 86 </select>
88 87
  88 + <select id="profileByTransportAndIds" resultMap="detail">
  89 + SELECT
  90 + <include refid="basicColumns"/>
  91 + FROM device_profile base
  92 + LEFT JOIN tk_device_profile iot ON iot.tb_profile_id = base.id::TEXT
  93 + <where>
  94 + iot.tenant_id = #{tenantId}
  95 + <if test="projectIds != null">
  96 + AND iot.id IN
  97 + <foreach collection="projectIds" item="id" open="(" separator="," close=")">
  98 + #{id}
  99 + </foreach>
  100 + </if>
  101 + <if test="transportType !=null">
  102 + AND iot.transport_type = #{transportType}
  103 + </if>
  104 + </where>
  105 + </select>
  106 +
89 107 <select id="getDeviceProfileIds" resultType="java.lang.String">
90 108 SELECT iot.id
91 109 FROM device_profile base
... ...