Commit c5a655616700a293cd809aca088cff441ab6fd38
Merge branch '20221104' into 'master'
refactor: TCP对象优化 See merge request huang/thingsboard3.3.2!140
Showing
27 changed files
with
1307 additions
and
644 deletions
@@ -71,89 +71,63 @@ public class YtDeviceController extends BaseController { | @@ -71,89 +71,63 @@ public class YtDeviceController extends BaseController { | ||
71 | deviceService.validateFormdata(currentTenantId, deviceDTO); | 71 | deviceService.validateFormdata(currentTenantId, deviceDTO); |
72 | 72 | ||
73 | 73 | ||
74 | - DeviceDTO newDeviceDTO = null; | ||
75 | - boolean isIncludeRelation = false; | ||
76 | 74 | ||
75 | + | ||
76 | + /**网关是否有效*/ | ||
77 | String gatewayId = deviceDTO.getGatewayId(); | 77 | String gatewayId = deviceDTO.getGatewayId(); |
78 | - DeviceDTO gateWayDevice = null; | 78 | + DeviceDTO gateWay = null; |
79 | if (StringUtils.isNotEmpty(gatewayId)) { | 79 | if (StringUtils.isNotEmpty(gatewayId)) { |
80 | - gateWayDevice = | ||
81 | - deviceService.checkDeviceByTenantIdAndDeviceId( | ||
82 | - getCurrentUser().getCurrentTenantId(), gatewayId); | ||
83 | - | ||
84 | - // 第一步判断该网关设备是否存在于该租户下面 | ||
85 | - if (null == gateWayDevice) { | 80 | + gateWay = deviceService.checkDeviceByTenantIdAndDeviceId(getCurrentUser().getCurrentTenantId(), gatewayId); |
81 | + if (null == gateWay) { | ||
86 | throw new YtDataValidationException( | 82 | throw new YtDataValidationException( |
87 | ErrorMessage.DEVICE_NOT_EXISTENCE_IN_TENANT.getMessage()); | 83 | ErrorMessage.DEVICE_NOT_EXISTENCE_IN_TENANT.getMessage()); |
88 | } | 84 | } |
89 | } | 85 | } |
90 | 86 | ||
91 | - /** 子设备编辑时,TB中已经存在关联关系则值更新设备表信息 */ | ||
92 | - String selfTbDeviceIdStr = deviceDTO.getTbDeviceId(); | ||
93 | - if (selfTbDeviceIdStr != null | ||
94 | - && deviceDTO.getDeviceType().equals(DeviceTypeEnum.SENSOR) | ||
95 | - && StringUtils.isNotEmpty(gatewayId)) { | ||
96 | - | ||
97 | - // 第二步判断网关子设备是否已关联到网关设备 | ||
98 | - EntityId entityId = | ||
99 | - EntityIdFactory.getByTypeAndId( | ||
100 | - "DEVICE", selfTbDeviceIdStr); // gateWayDevice.getTbDeviceId() | ||
101 | - List<EntityRelationInfo> list = | ||
102 | - relationService.findInfoByTo(getTenantId(), entityId, RelationTypeGroup.COMMON).get(); | ||
103 | - | ||
104 | - for (EntityRelationInfo entityRelationInfo : list) { | ||
105 | - if (entityRelationInfo.getTo().getId().equals(selfTbDeviceIdStr) | ||
106 | - && entityRelationInfo.getFrom().getId().equals(gatewayId)) { | ||
107 | - deviceDTO.setTbDeviceId(entityRelationInfo.getTo().toString()); | ||
108 | - newDeviceDTO = | ||
109 | - deviceService.insertOrUpdate(getCurrentUser().getCurrentTenantId(), deviceDTO); | ||
110 | - isIncludeRelation = true; | ||
111 | - break; | ||
112 | - } | ||
113 | - } | ||
114 | - } | ||
115 | 87 | ||
116 | - /** 需要更新设备表和关联关系表 */ | ||
117 | - if (!isIncludeRelation) { | ||
118 | - Device tbDevice = buildTbDeviceFromDeviceDTO(getCurrentUser().getTenantId(), deviceDTO); | ||
119 | - | ||
120 | - DeviceId selfTbId = updateTbDevice(tbDevice, deviceDTO.getDeviceToken()); | ||
121 | - selfTbDeviceIdStr = selfTbId.getId().toString(); | ||
122 | - deviceDTO.setTbDeviceId(selfTbDeviceIdStr); | ||
123 | - newDeviceDTO = deviceService.insertOrUpdate(getCurrentUser().getCurrentTenantId(), deviceDTO); | ||
124 | - | ||
125 | - if (deviceDTO.getDeviceType().equals(DeviceTypeEnum.SENSOR) | ||
126 | - && StringUtils.isNotEmpty(selfTbDeviceIdStr)) { | ||
127 | - // 删除原來的关联关系 | ||
128 | - List<DeviceDTO> list = | ||
129 | - deviceService.findGateWayDeviceByTbDeviceId( | ||
130 | - getCurrentUser().getCurrentTenantId(), selfTbDeviceIdStr); | ||
131 | - if (null != list && list.size() > 0) { | ||
132 | - DeviceId form = new DeviceId(UUID.fromString(list.get(0).getTbDeviceId())); | ||
133 | - EntityRelation relation = | ||
134 | - new EntityRelation( | ||
135 | - form, selfTbId, FastIotConstants.Relation.relationType, RelationTypeGroup.COMMON); | ||
136 | - boolean found = | ||
137 | - relationService.deleteRelation( | ||
138 | - getTenantId(), | ||
139 | - form, | ||
140 | - selfTbId, | ||
141 | - FastIotConstants.Relation.relationType, | ||
142 | - RelationTypeGroup.COMMON); | ||
143 | - | ||
144 | - if (!found) { | ||
145 | - throw new ThingsboardException( | ||
146 | - "Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND); | ||
147 | - } | ||
148 | - sendRelationNotificationMsg( | ||
149 | - getTenantId(), relation, EdgeEventActionType.RELATION_DELETED); | ||
150 | - } | ||
151 | 88 | ||
152 | - if (gateWayDevice != null) { | ||
153 | - addRelation(getTenantId(), gateWayDevice.getTbDeviceId(), selfTbDeviceIdStr); | 89 | + |
90 | + /** 子设备编辑业务逻辑: 设备地址码必须同时设置到附加信息字段内。 | ||
91 | + * 1、新增或编辑网关和直连设备 | ||
92 | + * 2、新增网关子设备 | ||
93 | + * 3、编辑网关子设备时,关联关系已存在(未切换网关) | ||
94 | + * 4、编辑网关子设备时,关联关系不存在(切换网关) | ||
95 | + * 5、编辑网关子设备时,修改其它设备信息,例如:设备名称等。 | ||
96 | + * */ | ||
97 | + Device tbDevice = buildTbDeviceFromDeviceDTO(getCurrentUser().getTenantId(), deviceDTO); | ||
98 | + DeviceId selfTbId = updateTbDevice(tbDevice, deviceDTO.getDeviceToken()); | ||
99 | + String selfTbIdStr = selfTbId.getId().toString(); | ||
100 | + deviceDTO.setTbDeviceId(selfTbIdStr); | ||
101 | + | ||
102 | + | ||
103 | + if (selfTbIdStr != null | ||
104 | + && deviceDTO.getDeviceType().equals(DeviceTypeEnum.SENSOR) | ||
105 | + && StringUtils.isNotEmpty(gatewayId)) { | ||
106 | + boolean relationNotMatched = true; | ||
107 | + | ||
108 | + EntityId slaveId = EntityIdFactory.getByTypeAndId("DEVICE", selfTbIdStr); | ||
109 | + List<EntityRelationInfo> relations = relationService.findInfoByTo(getTenantId(), slaveId, RelationTypeGroup.COMMON).get(); | ||
110 | + | ||
111 | + for (EntityRelationInfo relationInfo : relations) { | ||
112 | + if(!FastIotConstants.Relation.relationType.equals(relationInfo.getType())){ | ||
113 | + continue; | ||
114 | + } | ||
115 | + if (relationInfo.getFrom().getId().toString().equals(gateWay.getTbDeviceId())) { | ||
116 | + relationNotMatched = false; | ||
117 | + }else { | ||
118 | + relationService.deleteRelation(getTenantId(),relationInfo); | ||
119 | + sendRelationNotificationMsg(getTenantId(), relationInfo, EdgeEventActionType.RELATION_DELETED); | ||
154 | } | 120 | } |
155 | } | 121 | } |
122 | + | ||
123 | + if(relationNotMatched){ | ||
124 | + addRelation(getTenantId(), gateWay.getTbDeviceId(), selfTbIdStr); | ||
125 | + } | ||
156 | } | 126 | } |
127 | + | ||
128 | + | ||
129 | + | ||
130 | + DeviceDTO newDeviceDTO = deviceService.insertOrUpdate(getCurrentUser().getCurrentTenantId(), deviceDTO); | ||
157 | return ResponseEntity.ok(newDeviceDTO); | 131 | return ResponseEntity.ok(newDeviceDTO); |
158 | } | 132 | } |
159 | 133 | ||
@@ -452,6 +426,8 @@ public class YtDeviceController extends BaseController { | @@ -452,6 +426,8 @@ public class YtDeviceController extends BaseController { | ||
452 | DeviceId id = new DeviceId(UUID.fromString(deviceId)); | 426 | DeviceId id = new DeviceId(UUID.fromString(deviceId)); |
453 | tbDevice.setId(id); | 427 | tbDevice.setId(id); |
454 | } | 428 | } |
429 | + | ||
430 | + /**扩展设备附加信息,例如:设备地址码、上下线时间等*/ | ||
455 | ObjectNode additionalInfo = objectMapper.createObjectNode(); | 431 | ObjectNode additionalInfo = objectMapper.createObjectNode(); |
456 | additionalInfo.put( | 432 | additionalInfo.put( |
457 | "gateway", | 433 | "gateway", |
@@ -465,6 +441,10 @@ public class YtDeviceController extends BaseController { | @@ -465,6 +441,10 @@ public class YtDeviceController extends BaseController { | ||
465 | .map(JsonNode::asText) | 441 | .map(JsonNode::asText) |
466 | .orElse("")); | 442 | .orElse("")); |
467 | additionalInfo.put("overwriteActivityTime", false); | 443 | additionalInfo.put("overwriteActivityTime", false); |
444 | + //TCP协议需要设备地址码分发数据给对应设备 | ||
445 | + if(StringUtils.isNotEmpty(deviceDTO.getCode())){ | ||
446 | + additionalInfo.put(FastIotConstants.TCP_DEVICE_IDENTIFY_FILED,deviceDTO.getCode()); | ||
447 | + } | ||
468 | 448 | ||
469 | DeviceProfileId deviceProfileId = | 449 | DeviceProfileId deviceProfileId = |
470 | new DeviceProfileId(UUID.fromString(deviceDTO.getProfileId())); | 450 | new DeviceProfileId(UUID.fromString(deviceDTO.getProfileId())); |
@@ -228,7 +228,7 @@ public class YtDeviceScriptController extends BaseController { | @@ -228,7 +228,7 @@ public class YtDeviceScriptController extends BaseController { | ||
228 | DeviceProfileDTO deviceProfileDTO, String scriptId, String scriptText) { | 228 | DeviceProfileDTO deviceProfileDTO, String scriptId, String scriptText) { |
229 | DeviceProfile tbDeviceProfile = new DeviceProfile(); | 229 | DeviceProfile tbDeviceProfile = new DeviceProfile(); |
230 | if (StringUtils.isNotBlank(deviceProfileDTO.getId())) { | 230 | if (StringUtils.isNotBlank(deviceProfileDTO.getId())) { |
231 | - UUID profileId = UUID.fromString(deviceProfileDTO.getId()); | 231 | + UUID profileId = UUID.fromString(deviceProfileDTO.getTbProfileId()); |
232 | tbDeviceProfile.setId(new DeviceProfileId(profileId)); | 232 | tbDeviceProfile.setId(new DeviceProfileId(profileId)); |
233 | tbDeviceProfile.setCreatedTime( | 233 | tbDeviceProfile.setCreatedTime( |
234 | deviceProfileDTO.getCreateTime().toInstant(ZoneOffset.of("+8")).toEpochMilli()); | 234 | deviceProfileDTO.getCreateTime().toInstant(ZoneOffset.of("+8")).toEpochMilli()); |
@@ -60,6 +60,7 @@ import org.thingsboard.server.common.data.page.PageLink; | @@ -60,6 +60,7 @@ import org.thingsboard.server.common.data.page.PageLink; | ||
60 | import org.thingsboard.server.common.data.relation.EntityRelation; | 60 | import org.thingsboard.server.common.data.relation.EntityRelation; |
61 | import org.thingsboard.server.common.data.security.DeviceCredentials; | 61 | import org.thingsboard.server.common.data.security.DeviceCredentials; |
62 | import org.thingsboard.server.common.data.security.DeviceCredentialsType; | 62 | import org.thingsboard.server.common.data.security.DeviceCredentialsType; |
63 | +import org.thingsboard.server.common.data.yunteng.dto.DeviceDTO; | ||
63 | import org.thingsboard.server.common.msg.EncryptionUtil; | 64 | import org.thingsboard.server.common.msg.EncryptionUtil; |
64 | import org.thingsboard.server.common.msg.TbMsg; | 65 | import org.thingsboard.server.common.msg.TbMsg; |
65 | import org.thingsboard.server.common.msg.TbMsgDataType; | 66 | import org.thingsboard.server.common.msg.TbMsgDataType; |
@@ -277,7 +278,24 @@ public class DefaultTransportApiService implements TransportApiService { | @@ -277,7 +278,24 @@ public class DefaultTransportApiService implements TransportApiService { | ||
277 | Lock deviceCreationLock = deviceCreationLocks.computeIfAbsent(requestMsg.getDeviceName(), id -> new ReentrantLock()); | 278 | Lock deviceCreationLock = deviceCreationLocks.computeIfAbsent(requestMsg.getDeviceName(), id -> new ReentrantLock()); |
278 | deviceCreationLock.lock(); | 279 | deviceCreationLock.lock(); |
279 | try { | 280 | try { |
280 | - Device device = deviceService.findDeviceByTenantIdAndName(gateway.getTenantId(), requestMsg.getDeviceName()); | 281 | + |
282 | + //Thingskit function | ||
283 | + String slaveName = requestMsg.getDeviceName(); | ||
284 | + if(gateway.getDeviceData().getTransportConfiguration().getType() == DeviceTransportType.TCP) { | ||
285 | + DeviceDTO iotDev = ytDeviceService.findSlaveDevice(gateway.getTenantId().getId().toString() | ||
286 | + , gateway.getId().getId().toString() | ||
287 | + ,requestMsg.getDeviceName()); | ||
288 | + if(iotDev == null ){ | ||
289 | + GetOrCreateDeviceFromGatewayResponseMsg.Builder builder = GetOrCreateDeviceFromGatewayResponseMsg.newBuilder(); | ||
290 | + return TransportApiResponseMsg.newBuilder() | ||
291 | + .setGetOrCreateDeviceResponseMsg(builder.build()) | ||
292 | + .build(); | ||
293 | + } | ||
294 | + slaveName = iotDev.getName(); | ||
295 | + } | ||
296 | + | ||
297 | + Device device = deviceService.findDeviceByTenantIdAndName(gateway.getTenantId(), slaveName); | ||
298 | + | ||
281 | if (device == null) { | 299 | if (device == null) { |
282 | TenantId tenantId = gateway.getTenantId(); | 300 | TenantId tenantId = gateway.getTenantId(); |
283 | device = new Device(); | 301 | device = new Device(); |
@@ -43,6 +43,8 @@ public interface DeviceProfileService { | @@ -43,6 +43,8 @@ public interface DeviceProfileService { | ||
43 | 43 | ||
44 | DeviceProfile createDefaultDeviceProfile(TenantId tenantId); | 44 | DeviceProfile createDefaultDeviceProfile(TenantId tenantId); |
45 | 45 | ||
46 | + DeviceProfile createDeviceProfile(TenantId tenantId,String name); | ||
47 | + | ||
46 | DeviceProfile findDefaultDeviceProfile(TenantId tenantId); | 48 | DeviceProfile findDefaultDeviceProfile(TenantId tenantId); |
47 | 49 | ||
48 | DeviceProfileInfo findDefaultDeviceProfileInfo(TenantId tenantId); | 50 | DeviceProfileInfo findDefaultDeviceProfileInfo(TenantId tenantId); |
@@ -27,8 +27,13 @@ public class YtTcpDeviceProfileTransportConfiguration implements DeviceProfileTr | @@ -27,8 +27,13 @@ public class YtTcpDeviceProfileTransportConfiguration implements DeviceProfileTr | ||
27 | private TcpDataTypeEnum dataFormat = TcpDataTypeEnum.HEX; | 27 | private TcpDataTypeEnum dataFormat = TcpDataTypeEnum.HEX; |
28 | private String scriptId; | 28 | private String scriptId; |
29 | private String scriptText; | 29 | private String scriptText; |
30 | - private String pingText; | ||
31 | - | 30 | +// private String pingText; |
31 | + @NoXss | ||
32 | + private String telemetryTopic = "03"; | ||
33 | + @NoXss | ||
34 | + private String attributesTopic = "01"; | ||
35 | + @NoXss | ||
36 | + private String rpcTopic = "05"; | ||
32 | @Override | 37 | @Override |
33 | public DeviceTransportType getType() { | 38 | public DeviceTransportType getType() { |
34 | return DeviceTransportType.TCP; | 39 | return DeviceTransportType.TCP; |
@@ -12,6 +12,7 @@ public interface FastIotConstants { | @@ -12,6 +12,7 @@ public interface FastIotConstants { | ||
12 | String CHART_EXECUTE_CONDITION = "executeCondition"; | 12 | String CHART_EXECUTE_CONDITION = "executeCondition"; |
13 | String CHART_EXECUTE_ATTRIBUTES = "executeAttributes"; | 13 | String CHART_EXECUTE_ATTRIBUTES = "executeAttributes"; |
14 | String ASSERT_DEFAULT_NAME = "default"; | 14 | String ASSERT_DEFAULT_NAME = "default"; |
15 | + public static final String TCP_DEVICE_IDENTIFY_FILED = "deviceCode"; | ||
15 | class DefaultOrder { | 16 | class DefaultOrder { |
16 | public static final String CREATE_TIME="create_time"; | 17 | public static final String CREATE_TIME="create_time"; |
17 | } | 18 | } |
@@ -62,7 +63,6 @@ public interface FastIotConstants { | @@ -62,7 +63,6 @@ public interface FastIotConstants { | ||
62 | * LDAPS 远程方法调用 | 63 | * LDAPS 远程方法调用 |
63 | */ | 64 | */ |
64 | public static final String LOOKUP_LDAPS = "ldaps:"; | 65 | public static final String LOOKUP_LDAPS = "ldaps:"; |
65 | - | ||
66 | /** | 66 | /** |
67 | * 定时任务违规的字符 | 67 | * 定时任务违规的字符 |
68 | */ | 68 | */ |
@@ -53,6 +53,10 @@ public class DeviceDTO extends TenantDTO { | @@ -53,6 +53,10 @@ public class DeviceDTO extends TenantDTO { | ||
53 | groups = {AddGroup.class}) | 53 | groups = {AddGroup.class}) |
54 | private String sn; | 54 | private String sn; |
55 | 55 | ||
56 | + | ||
57 | + @ApiModelProperty(value = "设备标识符,例如:地址码") | ||
58 | + private String code; | ||
59 | + | ||
56 | @NotEmpty( | 60 | @NotEmpty( |
57 | message = "所属组织不能为空或者空字符串", | 61 | message = "所属组织不能为空或者空字符串", |
58 | groups = {AddGroup.class}) | 62 | groups = {AddGroup.class}) |
@@ -42,6 +42,7 @@ public class TcpTransportContext extends TransportContext { | @@ -42,6 +42,7 @@ public class TcpTransportContext extends TransportContext { | ||
42 | @Autowired(required = false) | 42 | @Autowired(required = false) |
43 | private TcpSslHandlerProvider sslHandlerProvider; | 43 | private TcpSslHandlerProvider sslHandlerProvider; |
44 | 44 | ||
45 | + /**注入多种数据协议处理器,例如:modbus等*/ | ||
45 | @Getter | 46 | @Getter |
46 | @Autowired | 47 | @Autowired |
47 | private JsonTcpAdaptor jsonTcpAdaptor; | 48 | private JsonTcpAdaptor jsonTcpAdaptor; |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.transport.tcp; | 16 | package org.thingsboard.server.transport.tcp; |
17 | 17 | ||
18 | -import com.google.gson.JsonParseException; | 18 | +import com.fasterxml.jackson.databind.JsonNode; |
19 | import io.netty.buffer.ByteBuf; | 19 | import io.netty.buffer.ByteBuf; |
20 | import io.netty.buffer.Unpooled; | 20 | import io.netty.buffer.Unpooled; |
21 | import io.netty.channel.ChannelFuture; | 21 | import io.netty.channel.ChannelFuture; |
@@ -28,11 +28,14 @@ import io.netty.util.concurrent.Future; | @@ -28,11 +28,14 @@ import io.netty.util.concurrent.Future; | ||
28 | import io.netty.util.concurrent.GenericFutureListener; | 28 | import io.netty.util.concurrent.GenericFutureListener; |
29 | import lombok.extern.slf4j.Slf4j; | 29 | import lombok.extern.slf4j.Slf4j; |
30 | import org.apache.commons.lang3.StringUtils; | 30 | import org.apache.commons.lang3.StringUtils; |
31 | -import org.thingsboard.server.common.data.*; | ||
32 | -import org.thingsboard.server.common.data.device.profile.MqttTopics; | 31 | +import org.thingsboard.server.common.data.DataConstants; |
32 | +import org.thingsboard.server.common.data.Device; | ||
33 | +import org.thingsboard.server.common.data.DeviceProfile; | ||
34 | +import org.thingsboard.server.common.data.DeviceTransportType; | ||
33 | import org.thingsboard.server.common.data.id.DeviceId; | 35 | import org.thingsboard.server.common.data.id.DeviceId; |
34 | import org.thingsboard.server.common.data.id.OtaPackageId; | 36 | import org.thingsboard.server.common.data.id.OtaPackageId; |
35 | import org.thingsboard.server.common.data.ota.OtaPackageType; | 37 | import org.thingsboard.server.common.data.ota.OtaPackageType; |
38 | +import org.thingsboard.server.common.data.rpc.RpcStatus; | ||
36 | import org.thingsboard.server.common.data.yunteng.enums.TcpDataTypeEnum; | 39 | import org.thingsboard.server.common.data.yunteng.enums.TcpDataTypeEnum; |
37 | import org.thingsboard.server.common.msg.EncryptionUtil; | 40 | import org.thingsboard.server.common.msg.EncryptionUtil; |
38 | import org.thingsboard.server.common.msg.tools.TbRateLimitsException; | 41 | import org.thingsboard.server.common.msg.tools.TbRateLimitsException; |
@@ -41,18 +44,22 @@ import org.thingsboard.server.common.transport.TransportService; | @@ -41,18 +44,22 @@ import org.thingsboard.server.common.transport.TransportService; | ||
41 | import org.thingsboard.server.common.transport.TransportServiceCallback; | 44 | import org.thingsboard.server.common.transport.TransportServiceCallback; |
42 | import org.thingsboard.server.common.transport.adaptor.AdaptorException; | 45 | import org.thingsboard.server.common.transport.adaptor.AdaptorException; |
43 | import org.thingsboard.server.common.transport.auth.SessionInfoCreator; | 46 | import org.thingsboard.server.common.transport.auth.SessionInfoCreator; |
47 | +import org.thingsboard.server.common.transport.auth.TransportDeviceInfo; | ||
44 | import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; | 48 | import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; |
49 | +import org.thingsboard.server.common.transport.service.DefaultTransportService; | ||
50 | +import org.thingsboard.server.common.transport.service.SessionMetaData; | ||
45 | import org.thingsboard.server.common.transport.util.SslUtil; | 51 | import org.thingsboard.server.common.transport.util.SslUtil; |
46 | import org.thingsboard.server.gen.transport.TransportProtos; | 52 | import org.thingsboard.server.gen.transport.TransportProtos; |
47 | -import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg; | ||
48 | import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg; | 53 | import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg; |
49 | -import org.thingsboard.server.queue.scheduler.SchedulerComponent; | ||
50 | import org.thingsboard.server.transport.tcp.adaptors.TcpTransportAdaptor; | 54 | import org.thingsboard.server.transport.tcp.adaptors.TcpTransportAdaptor; |
51 | -import org.thingsboard.server.transport.tcp.session.DeviceSessionCtx; | 55 | +import org.thingsboard.server.transport.tcp.session.TcpDeviceSessionCtx; |
52 | import org.thingsboard.server.transport.tcp.session.TCPMessage; | 56 | import org.thingsboard.server.transport.tcp.session.TCPMessage; |
57 | +import org.thingsboard.server.transport.tcp.session.TcpGatewaySessionHandler; | ||
53 | import org.thingsboard.server.transport.tcp.util.ByteUtils; | 58 | import org.thingsboard.server.transport.tcp.util.ByteUtils; |
54 | 59 | ||
55 | import javax.net.ssl.SSLPeerUnverifiedException; | 60 | import javax.net.ssl.SSLPeerUnverifiedException; |
61 | +import java.io.IOException; | ||
62 | +import java.io.UnsupportedEncodingException; | ||
56 | import java.net.InetSocketAddress; | 63 | import java.net.InetSocketAddress; |
57 | import java.security.cert.Certificate; | 64 | import java.security.cert.Certificate; |
58 | import java.security.cert.X509Certificate; | 65 | import java.security.cert.X509Certificate; |
@@ -62,13 +69,13 @@ import java.util.UUID; | @@ -62,13 +69,13 @@ import java.util.UUID; | ||
62 | import java.util.concurrent.ConcurrentHashMap; | 69 | import java.util.concurrent.ConcurrentHashMap; |
63 | import java.util.concurrent.ConcurrentMap; | 70 | import java.util.concurrent.ConcurrentMap; |
64 | import java.util.regex.Matcher; | 71 | import java.util.regex.Matcher; |
65 | -import java.util.regex.Pattern; | ||
66 | 72 | ||
67 | import static com.amazonaws.util.StringUtils.UTF8; | 73 | import static com.amazonaws.util.StringUtils.UTF8; |
68 | import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_ACCEPTED; | 74 | import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_ACCEPTED; |
69 | import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_REFUSED_NOT_AUTHORIZED; | 75 | import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_REFUSED_NOT_AUTHORIZED; |
70 | -import static io.netty.handler.codec.mqtt.MqttMessageType.*; | ||
71 | -import static io.netty.handler.codec.mqtt.MqttQoS.*; | 76 | +import static io.netty.handler.codec.mqtt.MqttMessageType.PUBACK; |
77 | +import static io.netty.handler.codec.mqtt.MqttMessageType.SUBACK; | ||
78 | +import static io.netty.handler.codec.mqtt.MqttQoS.AT_MOST_ONCE; | ||
72 | import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_CLOSED; | 79 | import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_CLOSED; |
73 | import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_OPEN; | 80 | import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_OPEN; |
74 | 81 | ||
@@ -78,25 +85,18 @@ import static org.thingsboard.server.common.transport.service.DefaultTransportSe | @@ -78,25 +85,18 @@ import static org.thingsboard.server.common.transport.service.DefaultTransportSe | ||
78 | @Slf4j | 85 | @Slf4j |
79 | public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements GenericFutureListener<Future<? super Void>>, SessionMsgListener { | 86 | public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements GenericFutureListener<Future<? super Void>>, SessionMsgListener { |
80 | 87 | ||
81 | - private static final Pattern FW_REQUEST_PATTERN = Pattern.compile(MqttTopics.DEVICE_FIRMWARE_REQUEST_TOPIC_PATTERN); | ||
82 | - private static final Pattern SW_REQUEST_PATTERN = Pattern.compile(MqttTopics.DEVICE_SOFTWARE_REQUEST_TOPIC_PATTERN); | ||
83 | - | ||
84 | - | ||
85 | - private static final String PAYLOAD_TOO_LARGE = "PAYLOAD_TOO_LARGE"; | ||
86 | - | ||
87 | - private static final MqttQoS MAX_SUPPORTED_QOS_LVL = AT_LEAST_ONCE; | ||
88 | 88 | ||
89 | private final UUID sessionId; | 89 | private final UUID sessionId; |
90 | private final TcpTransportContext context; | 90 | private final TcpTransportContext context; |
91 | private final TransportService transportService; | 91 | private final TransportService transportService; |
92 | - private final SchedulerComponent scheduler; | ||
93 | private final SslHandler sslHandler; | 92 | private final SslHandler sslHandler; |
94 | 93 | ||
95 | 94 | ||
96 | /**需要处理的消息队列,例如:需要下发给设备的,设备上传的。*/ | 95 | /**需要处理的消息队列,例如:需要下发给设备的,设备上传的。*/ |
97 | - final DeviceSessionCtx deviceSessionCtx; | 96 | + final TcpDeviceSessionCtx deviceSessionCtx; |
98 | volatile InetSocketAddress address; | 97 | volatile InetSocketAddress address; |
99 | 98 | ||
99 | + volatile TcpGatewaySessionHandler gatewaySessionHandler; | ||
100 | private final ConcurrentHashMap<String, String> otaPackSessions; | 100 | private final ConcurrentHashMap<String, String> otaPackSessions; |
101 | private final ConcurrentHashMap<String, Integer> chunkSizes; | 101 | private final ConcurrentHashMap<String, Integer> chunkSizes; |
102 | private final ConcurrentMap<Integer, TransportProtos.ToDeviceRpcRequestMsg> rpcAwaitingAck; | 102 | private final ConcurrentMap<Integer, TransportProtos.ToDeviceRpcRequestMsg> rpcAwaitingAck; |
@@ -107,9 +107,8 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | @@ -107,9 +107,8 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | ||
107 | this.sessionId = UUID.randomUUID(); | 107 | this.sessionId = UUID.randomUUID(); |
108 | this.context = context; | 108 | this.context = context; |
109 | this.transportService = context.getTransportService(); | 109 | this.transportService = context.getTransportService(); |
110 | - this.scheduler = context.getScheduler(); | ||
111 | this.sslHandler = sslHandler; | 110 | this.sslHandler = sslHandler; |
112 | - this.deviceSessionCtx = new DeviceSessionCtx(sessionId, context); | 111 | + this.deviceSessionCtx = new TcpDeviceSessionCtx(sessionId, context); |
113 | this.otaPackSessions = new ConcurrentHashMap<>(); | 112 | this.otaPackSessions = new ConcurrentHashMap<>(); |
114 | this.chunkSizes = new ConcurrentHashMap<>(); | 113 | this.chunkSizes = new ConcurrentHashMap<>(); |
115 | this.rpcAwaitingAck = new ConcurrentHashMap<>(); | 114 | this.rpcAwaitingAck = new ConcurrentHashMap<>(); |
@@ -136,8 +135,14 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | @@ -136,8 +135,14 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | ||
136 | try { | 135 | try { |
137 | if (msg instanceof ByteBuf) { | 136 | if (msg instanceof ByteBuf) { |
138 | ByteBuf message = (ByteBuf) msg; | 137 | ByteBuf message = (ByteBuf) msg; |
138 | + byte[] byteMsg = ByteUtils.buf2Bytes(message); | ||
139 | 139 | ||
140 | - processTcpMsg(ctx, ByteUtils.buf2Bytes(message)); | 140 | + deviceSessionCtx.setChannel(ctx); |
141 | + if (deviceSessionCtx.getDeviceInfo() == null || deviceSessionCtx.getDeviceProfile() == null) { | ||
142 | + processConnect(ctx, ByteUtils.getString(byteMsg, ByteUtils.UTF_8)); | ||
143 | + } else { | ||
144 | + enqueueRegularSessionMsg(ctx,message); | ||
145 | + } | ||
141 | 146 | ||
142 | } else { | 147 | } else { |
143 | log.debug("【{}】 Received non tcp message: 【{}】", sessionId, msg.getClass().getSimpleName()); | 148 | log.debug("【{}】 Received non tcp message: 【{}】", sessionId, msg.getClass().getSimpleName()); |
@@ -161,18 +166,10 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | @@ -161,18 +166,10 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | ||
161 | return address; | 166 | return address; |
162 | } | 167 | } |
163 | 168 | ||
164 | - void processTcpMsg(ChannelHandlerContext ctx, byte[] msg) { | ||
165 | - deviceSessionCtx.setChannel(ctx); | ||
166 | - if (deviceSessionCtx.getDeviceInfo() == null || deviceSessionCtx.getDeviceProfile() == null) { | ||
167 | - processConnect(ctx, ByteUtils.getString(msg, ByteUtils.UTF_8)); | ||
168 | - } else { | ||
169 | - enqueueRegularSessionMsg(ctx,msg); | ||
170 | - } | ||
171 | - } | ||
172 | 169 | ||
173 | 170 | ||
174 | 171 | ||
175 | - void enqueueRegularSessionMsg(ChannelHandlerContext ctx, byte[] msg) { | 172 | + void enqueueRegularSessionMsg(ChannelHandlerContext ctx, ByteBuf msg) { |
176 | final int queueSize = deviceSessionCtx.getMsgQueueSize(); | 173 | final int queueSize = deviceSessionCtx.getMsgQueueSize(); |
177 | if (queueSize >= context.getMessageQueueSizePerDeviceLimit()) { | 174 | if (queueSize >= context.getMessageQueueSizePerDeviceLimit()) { |
178 | log.info("Closing current session because msq queue size for device {} exceed limit {} with msgQueueSize counter {} and actual queue size {}", | 175 | log.info("Closing current session because msq queue size for device {} exceed limit {} with msgQueueSize counter {} and actual queue size {}", |
@@ -181,90 +178,79 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | @@ -181,90 +178,79 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | ||
181 | return; | 178 | return; |
182 | } | 179 | } |
183 | 180 | ||
184 | - deviceSessionCtx.addToQueue(new TCPMessage(MqttMessageType.PUBLISH,msg)); | ||
185 | - processMsgQueue(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 | 181 | + TCPMessage message =deviceSessionCtx.getPayloadAdaptor().createTcpMessage(deviceSessionCtx,msg); |
182 | + deviceSessionCtx.addToQueue(message); | ||
183 | + 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 | + | ||
186 | } | 185 | } |
187 | 186 | ||
188 | 187 | ||
189 | 188 | ||
190 | - void processMsgQueue(ChannelHandlerContext ctx) { | 189 | + void processQueueMessage(ChannelHandlerContext ctx) { |
191 | if (!deviceSessionCtx.isConnected()) { | 190 | if (!deviceSessionCtx.isConnected()) { |
192 | log.trace("[{}][{}] Postpone processing msg due to device is not connected. Msg queue size is {}", sessionId, deviceSessionCtx.getDeviceId(), deviceSessionCtx.getMsgQueueSize()); | 191 | log.trace("[{}][{}] Postpone processing msg due to device is not connected. Msg queue size is {}", sessionId, deviceSessionCtx.getDeviceId(), deviceSessionCtx.getMsgQueueSize()); |
193 | return; | 192 | return; |
194 | } | 193 | } |
195 | - deviceSessionCtx.tryProcessQueuedMsgs(msg -> processRegularSessionMsg(ctx, msg)); | ||
196 | - } | ||
197 | - | ||
198 | - void processRegularSessionMsg(ChannelHandlerContext ctx, TCPMessage msg) { | ||
199 | - switch (msg.getMessageType()) { | ||
200 | - case PUBLISH: | ||
201 | - processPublish(ctx, msg); | ||
202 | - break; | ||
203 | - case SUBSCRIBE: | ||
204 | -// processSubscribe(ctx, (MqttSubscribeMessage) msg); | ||
205 | - break; | ||
206 | - case UNSUBSCRIBE: | ||
207 | -// processUnsubscribe(ctx, (MqttUnsubscribeMessage) msg); | ||
208 | - break; | ||
209 | - | ||
210 | - case DISCONNECT: | ||
211 | - ctx.close(); | ||
212 | - break; | ||
213 | - case PUBACK: | ||
214 | -// int msgId = ((MqttPubAckMessage) msg).variableHeader().messageId(); | ||
215 | -// TransportProtos.ToDeviceRpcRequestMsg rpcRequest = rpcAwaitingAck.remove(msgId); | ||
216 | -// if (rpcRequest != null) { | ||
217 | -// transportService.process(deviceSessionCtx.getSessionInfo(), rpcRequest, RpcStatus.DELIVERED, TransportServiceCallback.EMPTY); | ||
218 | -// } | ||
219 | - break; | ||
220 | - default: | ||
221 | - break; | ||
222 | - } | 194 | + deviceSessionCtx.tryProcessQueuedMsgs(msg -> processDeviceSessionMsg(ctx, msg)); |
223 | } | 195 | } |
224 | 196 | ||
225 | - private ByteBuf toDeviceMsg(byte[] msgs){ | ||
226 | - return Unpooled.copiedBuffer(msgs); | ||
227 | - } | ||
228 | 197 | ||
229 | - private String textFromMessage(byte[] payload){ | ||
230 | - if(deviceSessionCtx.getPayloadType().equals(TcpDataTypeEnum.ASCII)){ | ||
231 | - return ByteUtils.getString(payload,ByteUtils.UTF_8); | ||
232 | - }else{ | ||
233 | - return ByteUtils.bytesToHex(payload); | ||
234 | - } | ||
235 | - } | ||
236 | - private void processPublish(ChannelHandlerContext ctx, TCPMessage mqttMsg) { | ||
237 | - if (!checkConnected(ctx, mqttMsg)) { | 198 | + |
199 | + | ||
200 | + | ||
201 | + | ||
202 | + private void processDeviceSessionMsg(ChannelHandlerContext ctx, TCPMessage tcpMessage) { | ||
203 | + if (!checkConnected(ctx, tcpMessage)) { | ||
238 | return; | 204 | return; |
239 | } | 205 | } |
240 | - if(deviceSessionCtx.getPingText().equals(mqttMsg.getMessage())){ | ||
241 | - ctx.channel().writeAndFlush(toDeviceMsg(mqttMsg.getMessage())); | 206 | + log.error("【{}】设备【{}】收到数据【{}】", sessionId,deviceSessionCtx.getDeviceId(), tcpMessage.getMessage()); |
207 | + if (!deviceSessionCtx.getDeviceCode().equals(tcpMessage.getMessage()) && gatewaySessionHandler != null) { | ||
208 | + processGatewayDeviceMsg(ctx, tcpMessage); | ||
242 | transportService.reportActivity(deviceSessionCtx.getSessionInfo()); | 209 | transportService.reportActivity(deviceSessionCtx.getSessionInfo()); |
243 | - return; | 210 | + } else { |
211 | + processDirectDeviceMsg(ctx,tcpMessage); | ||
244 | } | 212 | } |
245 | - String dataStr = textFromMessage(mqttMsg.getMessage()); | ||
246 | - log.trace("[{}][{}] Processing publish msg [{}]!", sessionId, deviceSessionCtx.getDeviceId(), dataStr); | ||
247 | - | ||
248 | - processDevicePublish(ctx, dataStr); | ||
249 | } | 213 | } |
250 | 214 | ||
251 | 215 | ||
252 | - private void processDevicePublish(ChannelHandlerContext ctx, String mqttMsg) { | 216 | + private void processGatewayDeviceMsg(ChannelHandlerContext ctx, TCPMessage tcpMessage) { |
217 | + log.trace("[{}][{}] Processing publish msg [{}]!", sessionId, deviceSessionCtx.getDeviceId(), tcpMessage.getMessage()); | ||
253 | try { | 218 | try { |
254 | -// Matcher fwMatcher; | 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)) { | ||
226 | + | ||
227 | + } else { | ||
228 | + transportService.reportActivity(deviceSessionCtx.getSessionInfo()); | ||
229 | + pushDeviceMsg(ctx,tcpMessage); | ||
230 | + } | ||
231 | + } catch (AdaptorException e) { | ||
232 | + log.debug("[{}] Failed to process publish msg [{}][{}]", sessionId, tcpMessage, e); | ||
233 | + ctx.close(); | ||
234 | + } | ||
235 | + } | ||
236 | + | ||
237 | + private void processDirectDeviceMsg(ChannelHandlerContext ctx, TCPMessage tcpMessage) { | ||
238 | + log.trace("[{}][{}] Processing publish msg [{}]!", sessionId, deviceSessionCtx.getDeviceId(), tcpMessage.getMessage()); | ||
239 | + try { | ||
240 | + String topicName = tcpMessage.getTopic(); | ||
255 | TcpTransportAdaptor payloadAdaptor = deviceSessionCtx.getPayloadAdaptor(); | 241 | TcpTransportAdaptor payloadAdaptor = deviceSessionCtx.getPayloadAdaptor(); |
256 | - TransportProtos.PostTelemetryMsg postTelemetryMsg = payloadAdaptor.convertToPostTelemetry(deviceSessionCtx, mqttMsg); | ||
257 | - transportService.process(deviceSessionCtx.getSessionInfo(), postTelemetryMsg, null); | ||
258 | -// if (deviceSessionCtx.isDeviceAttributesTopic(topicName)) { | ||
259 | -// TransportProtos.PostAttributeMsg postAttributeMsg = payloadAdaptor.convertToPostAttributes(deviceSessionCtx, mqttMsg); | ||
260 | -// transportService.process(deviceSessionCtx.getSessionInfo(), postAttributeMsg, getPubAckCallback(ctx, msgId, postAttributeMsg)); | ||
261 | -// } else if (deviceSessionCtx.isDeviceTelemetryTopic(topicName)) { | 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); | ||
262 | // } else if (topicName.startsWith(MqttTopics.DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX)) { | 248 | // } else if (topicName.startsWith(MqttTopics.DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX)) { |
263 | // TransportProtos.GetAttributeRequestMsg getAttributeMsg = payloadAdaptor.convertToGetAttributes(deviceSessionCtx, mqttMsg, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX); | 249 | // TransportProtos.GetAttributeRequestMsg getAttributeMsg = payloadAdaptor.convertToGetAttributes(deviceSessionCtx, mqttMsg, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX); |
264 | // transportService.process(deviceSessionCtx.getSessionInfo(), getAttributeMsg, getPubAckCallback(ctx, msgId, getAttributeMsg)); | 250 | // transportService.process(deviceSessionCtx.getSessionInfo(), getAttributeMsg, getPubAckCallback(ctx, msgId, getAttributeMsg)); |
265 | // attrReqTopicType = TopicType.V1; | 251 | // attrReqTopicType = TopicType.V1; |
266 | -// } else if (topicName.startsWith(MqttTopics.DEVICE_RPC_RESPONSE_TOPIC)) { | ||
267 | -// TransportProtos.ToDeviceRpcResponseMsg rpcResponseMsg = payloadAdaptor.convertToDeviceRpcResponse(deviceSessionCtx, mqttMsg, MqttTopics.DEVICE_RPC_RESPONSE_TOPIC); | 252 | + } else if (deviceSessionCtx.isToDeviceRpcResponseTopic(topicName)) { |
253 | +// TransportProtos.ToDeviceRpcResponseMsg rpcResponseMsg = payloadAdaptor.convertToDeviceRpcResponse(deviceSessionCtx, tcpMessage.getMessage(), MqttTopics.DEVICE_RPC_RESPONSE_TOPIC); | ||
268 | // transportService.process(deviceSessionCtx.getSessionInfo(), rpcResponseMsg, getPubAckCallback(ctx, msgId, rpcResponseMsg)); | 254 | // transportService.process(deviceSessionCtx.getSessionInfo(), rpcResponseMsg, getPubAckCallback(ctx, msgId, rpcResponseMsg)); |
269 | // } else if (topicName.startsWith(MqttTopics.DEVICE_RPC_REQUESTS_TOPIC)) { | 255 | // } else if (topicName.startsWith(MqttTopics.DEVICE_RPC_REQUESTS_TOPIC)) { |
270 | // TransportProtos.ToServerRpcRequestMsg rpcRequestMsg = payloadAdaptor.convertToServerRpcRequest(deviceSessionCtx, mqttMsg, MqttTopics.DEVICE_RPC_REQUESTS_TOPIC); | 256 | // TransportProtos.ToServerRpcRequestMsg rpcRequestMsg = payloadAdaptor.convertToServerRpcRequest(deviceSessionCtx, mqttMsg, MqttTopics.DEVICE_RPC_REQUESTS_TOPIC); |
@@ -328,12 +314,12 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | @@ -328,12 +314,12 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | ||
328 | // TransportProtos.GetAttributeRequestMsg getAttributeMsg = payloadAdaptor.convertToGetAttributes(deviceSessionCtx, mqttMsg, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_TOPIC_PREFIX); | 314 | // TransportProtos.GetAttributeRequestMsg getAttributeMsg = payloadAdaptor.convertToGetAttributes(deviceSessionCtx, mqttMsg, MqttTopics.DEVICE_ATTRIBUTES_REQUEST_SHORT_TOPIC_PREFIX); |
329 | // transportService.process(deviceSessionCtx.getSessionInfo(), getAttributeMsg, getPubAckCallback(ctx, msgId, getAttributeMsg)); | 315 | // transportService.process(deviceSessionCtx.getSessionInfo(), getAttributeMsg, getPubAckCallback(ctx, msgId, getAttributeMsg)); |
330 | // attrReqTopicType = TopicType.V2; | 316 | // attrReqTopicType = TopicType.V2; |
331 | -// } else { | ||
332 | -// transportService.reportActivity(deviceSessionCtx.getSessionInfo()); | ||
333 | -// ack(ctx, msgId); | ||
334 | -// } | 317 | + } else { |
318 | + transportService.reportActivity(deviceSessionCtx.getSessionInfo()); | ||
319 | + pushDeviceMsg(ctx,tcpMessage); | ||
320 | + } | ||
335 | } catch (AdaptorException e) { | 321 | } catch (AdaptorException e) { |
336 | - log.debug("[{}] Failed to process publish msg [{}][{}]", sessionId, mqttMsg, e); | 322 | + log.debug("[{}] Failed to process publish msg [{}][{}]", sessionId, tcpMessage, e); |
337 | ctx.close(); | 323 | ctx.close(); |
338 | } | 324 | } |
339 | } | 325 | } |
@@ -351,7 +337,7 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | @@ -351,7 +337,7 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | ||
351 | } | 337 | } |
352 | 338 | ||
353 | if (chunkSize > context.getMaxPayloadSize()) { | 339 | if (chunkSize > context.getMaxPayloadSize()) { |
354 | - sendOtaPackageError(ctx, PAYLOAD_TOO_LARGE); | 340 | +// sendOtaPackageError(ctx, PAYLOAD_TOO_LARGE); |
355 | return; | 341 | return; |
356 | } | 342 | } |
357 | 343 | ||
@@ -373,18 +359,16 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | @@ -373,18 +359,16 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | ||
373 | } | 359 | } |
374 | } | 360 | } |
375 | 361 | ||
376 | - private void ack(ChannelHandlerContext ctx, int msgId) { | ||
377 | - if (msgId > 0) { | ||
378 | - ctx.writeAndFlush(createMqttPubAckMsg(msgId)); | ||
379 | - } | ||
380 | - } | ||
381 | 362 | ||
382 | - private <T> TransportServiceCallback<Void> getPubAckCallback(final ChannelHandlerContext ctx, final int msgId, final T msg) { | 363 | + |
364 | + private <T> TransportServiceCallback<Void> getPubAckCallback(final ChannelHandlerContext ctx, final String msgId, final TCPMessage msg) { | ||
383 | return new TransportServiceCallback<>() { | 365 | return new TransportServiceCallback<>() { |
384 | @Override | 366 | @Override |
385 | public void onSuccess(Void dummy) { | 367 | public void onSuccess(Void dummy) { |
386 | log.trace("[{}] Published msg: {}", sessionId, msg); | 368 | log.trace("[{}] Published msg: {}", sessionId, msg); |
387 | - ack(ctx, msgId); | 369 | + if(StringUtils.isNotEmpty(msgId)){ |
370 | + pushDeviceMsg(ctx,msg); | ||
371 | + } | ||
388 | } | 372 | } |
389 | 373 | ||
390 | @Override | 374 | @Override |
@@ -395,39 +379,6 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | @@ -395,39 +379,6 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | ||
395 | }; | 379 | }; |
396 | } | 380 | } |
397 | 381 | ||
398 | - private class DeviceProvisionCallback implements TransportServiceCallback<ProvisionDeviceResponseMsg> { | ||
399 | - private final ChannelHandlerContext ctx; | ||
400 | - private final int msgId; | ||
401 | - private final TransportProtos.ProvisionDeviceRequestMsg msg; | ||
402 | - | ||
403 | - DeviceProvisionCallback(ChannelHandlerContext ctx, int msgId, TransportProtos.ProvisionDeviceRequestMsg msg) { | ||
404 | - this.ctx = ctx; | ||
405 | - this.msgId = msgId; | ||
406 | - this.msg = msg; | ||
407 | - } | ||
408 | - | ||
409 | - @Override | ||
410 | - public void onSuccess(TransportProtos.ProvisionDeviceResponseMsg provisionResponseMsg) { | ||
411 | -// log.trace("[{}] Published msg: {}", sessionId, msg); | ||
412 | -// ack(ctx, msgId); | ||
413 | -// try { | ||
414 | -// if (deviceSessionCtx.getProvisionPayloadType().equals(TransportPayloadType.JSON)) { | ||
415 | -// deviceSessionCtx.getContext().getJsonMqttAdaptor().convertToPublish(deviceSessionCtx, provisionResponseMsg).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); | ||
416 | -// } else { | ||
417 | -// deviceSessionCtx.getContext().getAscallAdaptor().convertToPublish(deviceSessionCtx, provisionResponseMsg).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); | ||
418 | -// } | ||
419 | -// scheduler.schedule((Callable<ChannelFuture>) ctx::close, 60, TimeUnit.SECONDS); | ||
420 | -// } catch (Exception e) { | ||
421 | -// log.trace("[{}] Failed to convert device attributes response to MQTT msg", sessionId, e); | ||
422 | -// } | ||
423 | - } | ||
424 | - | ||
425 | - @Override | ||
426 | - public void onError(Throwable e) { | ||
427 | - log.trace("[{}] Failed to publish msg: {}", sessionId, msg, e); | ||
428 | - ctx.close(); | ||
429 | - } | ||
430 | - } | ||
431 | 382 | ||
432 | private class OtaPackageCallback implements TransportServiceCallback<TransportProtos.GetOtaPackageResponseMsg> { | 383 | private class OtaPackageCallback implements TransportServiceCallback<TransportProtos.GetOtaPackageResponseMsg> { |
433 | private final ChannelHandlerContext ctx; | 384 | private final ChannelHandlerContext ctx; |
@@ -453,7 +404,7 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | @@ -453,7 +404,7 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | ||
453 | otaPackSessions.put(requestId, firmwareId.toString()); | 404 | otaPackSessions.put(requestId, firmwareId.toString()); |
454 | sendOtaPackage(ctx, msgId, firmwareId.toString(), requestId, chunkSize, chunk, OtaPackageType.valueOf(response.getType())); | 405 | sendOtaPackage(ctx, msgId, firmwareId.toString(), requestId, chunkSize, chunk, OtaPackageType.valueOf(response.getType())); |
455 | } else { | 406 | } else { |
456 | - sendOtaPackageError(ctx, response.getResponseStatus().toString()); | 407 | +// sendOtaPackageError(ctx, response.getResponseStatus().toString()); |
457 | } | 408 | } |
458 | } | 409 | } |
459 | 410 | ||
@@ -466,7 +417,7 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | @@ -466,7 +417,7 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | ||
466 | 417 | ||
467 | private void sendOtaPackage(ChannelHandlerContext ctx, int msgId, String firmwareId, String requestId, int chunkSize, int chunk, OtaPackageType type) { | 418 | private void sendOtaPackage(ChannelHandlerContext ctx, int msgId, String firmwareId, String requestId, int chunkSize, int chunk, OtaPackageType type) { |
468 | log.trace("[{}] Send firmware [{}] to device!", sessionId, firmwareId); | 419 | log.trace("[{}] Send firmware [{}] to device!", sessionId, firmwareId); |
469 | - ack(ctx, msgId); | 420 | + pushDeviceMsg(ctx,new TCPMessage(requestId)); |
470 | try { | 421 | try { |
471 | byte[] firmwareChunk = context.getOtaPackageDataCache().get(firmwareId, chunkSize, chunk); | 422 | byte[] firmwareChunk = context.getOtaPackageDataCache().get(firmwareId, chunkSize, chunk); |
472 | deviceSessionCtx.getPayloadAdaptor() | 423 | deviceSessionCtx.getPayloadAdaptor() |
@@ -477,174 +428,7 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | @@ -477,174 +428,7 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | ||
477 | } | 428 | } |
478 | } | 429 | } |
479 | 430 | ||
480 | - private void sendOtaPackageError(ChannelHandlerContext ctx, String error) { | ||
481 | - log.warn("[{}] {}", sessionId, error); | ||
482 | - deviceSessionCtx.getChannel().writeAndFlush(deviceSessionCtx | ||
483 | - .getPayloadAdaptor() | ||
484 | - .createMqttPublishMsg(deviceSessionCtx, MqttTopics.DEVICE_FIRMWARE_ERROR_TOPIC, error.getBytes())); | ||
485 | - ctx.close(); | ||
486 | - } | ||
487 | - | ||
488 | - private void processSubscribe(ChannelHandlerContext ctx, MqttSubscribeMessage mqttMsg) { | ||
489 | -// if (!checkConnected(ctx, mqttMsg)) { | ||
490 | -// return; | ||
491 | -// } | ||
492 | -// log.trace("[{}] Processing subscription [{}]!", sessionId, mqttMsg.variableHeader().messageId()); | ||
493 | -// List<Integer> grantedQoSList = new ArrayList<>(); | ||
494 | -// boolean activityReported = false; | ||
495 | -// for (MqttTopicSubscription subscription : mqttMsg.payload().topicSubscriptions()) { | ||
496 | -// String topic = subscription.topicName(); | ||
497 | -// MqttQoS reqQoS = subscription.qualityOfService(); | ||
498 | -// try { | ||
499 | -// switch (topic) { | ||
500 | -// case MqttTopics.DEVICE_ATTRIBUTES_TOPIC: { | ||
501 | -// processAttributesSubscribe(grantedQoSList, topic, reqQoS, TopicType.V1); | ||
502 | -// activityReported = true; | ||
503 | -// break; | ||
504 | -// } | ||
505 | -// case MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC: { | ||
506 | -// processAttributesSubscribe(grantedQoSList, topic, reqQoS, TopicType.V2); | ||
507 | -// activityReported = true; | ||
508 | -// break; | ||
509 | -// } | ||
510 | -// case MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC: { | ||
511 | -// processAttributesSubscribe(grantedQoSList, topic, reqQoS, TopicType.V2_JSON); | ||
512 | -// activityReported = true; | ||
513 | -// break; | ||
514 | -// } | ||
515 | -// case MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC: { | ||
516 | -// processAttributesSubscribe(grantedQoSList, topic, reqQoS, TopicType.V2_PROTO); | ||
517 | -// activityReported = true; | ||
518 | -// break; | ||
519 | -// } | ||
520 | -// case MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC: { | ||
521 | -// processRpcSubscribe(grantedQoSList, topic, reqQoS, TopicType.V1); | ||
522 | -// activityReported = true; | ||
523 | -// break; | ||
524 | -// } | ||
525 | -// case MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_TOPIC: { | ||
526 | -// processRpcSubscribe(grantedQoSList, topic, reqQoS, TopicType.V2); | ||
527 | -// activityReported = true; | ||
528 | -// break; | ||
529 | -// } | ||
530 | -// case MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_JSON_TOPIC: { | ||
531 | -// processRpcSubscribe(grantedQoSList, topic, reqQoS, TopicType.V2_JSON); | ||
532 | -// activityReported = true; | ||
533 | -// break; | ||
534 | -// } | ||
535 | -// case MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_PROTO_TOPIC: { | ||
536 | -// processRpcSubscribe(grantedQoSList, topic, reqQoS, TopicType.V2_PROTO); | ||
537 | -// activityReported = true; | ||
538 | -// break; | ||
539 | -// } | ||
540 | -// case MqttTopics.DEVICE_RPC_RESPONSE_SUB_TOPIC: | ||
541 | -// case MqttTopics.DEVICE_RPC_RESPONSE_SUB_SHORT_TOPIC: | ||
542 | -// case MqttTopics.DEVICE_RPC_RESPONSE_SUB_SHORT_JSON_TOPIC: | ||
543 | -// case MqttTopics.DEVICE_RPC_RESPONSE_SUB_SHORT_PROTO_TOPIC: | ||
544 | -// case MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC: | ||
545 | -// case MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_TOPIC: | ||
546 | -// case MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_JSON_TOPIC: | ||
547 | -// case MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_PROTO_TOPIC: | ||
548 | -// case MqttTopics.GATEWAY_ATTRIBUTES_TOPIC: | ||
549 | -// case MqttTopics.GATEWAY_RPC_TOPIC: | ||
550 | -// case MqttTopics.GATEWAY_ATTRIBUTES_RESPONSE_TOPIC: | ||
551 | -// case MqttTopics.DEVICE_PROVISION_RESPONSE_TOPIC: | ||
552 | -// case MqttTopics.DEVICE_FIRMWARE_RESPONSES_TOPIC: | ||
553 | -// case MqttTopics.DEVICE_FIRMWARE_ERROR_TOPIC: | ||
554 | -// case MqttTopics.DEVICE_SOFTWARE_RESPONSES_TOPIC: | ||
555 | -// | ||
556 | -// break; | ||
557 | -// default: | ||
558 | -// log.warn("[{}] Failed to subscribe to [{}][{}]", sessionId, topic, reqQoS); | ||
559 | -// grantedQoSList.add(FAILURE.value()); | ||
560 | -// break; | ||
561 | -// } | ||
562 | -// } catch (Exception e) { | ||
563 | -// log.warn("[{}] Failed to subscribe to [{}][{}]", sessionId, topic, reqQoS, e); | ||
564 | -// grantedQoSList.add(FAILURE.value()); | ||
565 | -// } | ||
566 | -// } | ||
567 | -// if (!activityReported) { | ||
568 | -// transportService.reportActivity(deviceSessionCtx.getSessionInfo()); | ||
569 | -// } | ||
570 | -// ctx.writeAndFlush(createSubAckMessage(mqttMsg.variableHeader().messageId(), grantedQoSList)); | ||
571 | - } | ||
572 | 431 | ||
573 | -// private void processRpcSubscribe(List<Integer> grantedQoSList, String topic, MqttQoS reqQoS, TopicType topicType) { | ||
574 | -// transportService.process(deviceSessionCtx.getSessionInfo(), TransportProtos.SubscribeToRPCMsg.newBuilder().build(), null); | ||
575 | -// rpcSubTopicType = topicType; | ||
576 | -// } | ||
577 | -// | ||
578 | -// private void processAttributesSubscribe(List<Integer> grantedQoSList, String topic, MqttQoS reqQoS, TopicType topicType) { | ||
579 | -// transportService.process(deviceSessionCtx.getSessionInfo(), TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null); | ||
580 | -// attrSubTopicType = topicType; | ||
581 | -// } | ||
582 | - | ||
583 | - | ||
584 | - | ||
585 | - private void processUnsubscribe(ChannelHandlerContext ctx, MqttUnsubscribeMessage mqttMsg) { | ||
586 | -// if (!checkConnected(ctx, mqttMsg)) { | ||
587 | -// return; | ||
588 | -// } | ||
589 | -// boolean activityReported = false; | ||
590 | -// log.trace("[{}] Processing subscription [{}]!", sessionId, mqttMsg.variableHeader().messageId()); | ||
591 | -// for (String topicName : mqttMsg.payload().topics()) { | ||
592 | -// try { | ||
593 | -// switch (topicName) { | ||
594 | -// case MqttTopics.DEVICE_ATTRIBUTES_TOPIC: | ||
595 | -// case MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC: | ||
596 | -// case MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC: | ||
597 | -// case MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC: { | ||
598 | -// transportService.process(deviceSessionCtx.getSessionInfo(), | ||
599 | -// TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().setUnsubscribe(true).build(), null); | ||
600 | -// activityReported = true; | ||
601 | -// break; | ||
602 | -// } | ||
603 | -// case MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC: | ||
604 | -// case MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_TOPIC: | ||
605 | -// case MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_JSON_TOPIC: | ||
606 | -// case MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_PROTO_TOPIC: { | ||
607 | -// transportService.process(deviceSessionCtx.getSessionInfo(), | ||
608 | -// TransportProtos.SubscribeToRPCMsg.newBuilder().setUnsubscribe(true).build(), null); | ||
609 | -// activityReported = true; | ||
610 | -// break; | ||
611 | -// } | ||
612 | -// case MqttTopics.DEVICE_RPC_RESPONSE_SUB_TOPIC: | ||
613 | -// case MqttTopics.DEVICE_RPC_RESPONSE_SUB_SHORT_TOPIC: | ||
614 | -// case MqttTopics.DEVICE_RPC_RESPONSE_SUB_SHORT_JSON_TOPIC: | ||
615 | -// case MqttTopics.DEVICE_RPC_RESPONSE_SUB_SHORT_PROTO_TOPIC: | ||
616 | -// case MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC: | ||
617 | -// case MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_TOPIC: | ||
618 | -// case MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_JSON_TOPIC: | ||
619 | -// case MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_PROTO_TOPIC: | ||
620 | -// case MqttTopics.GATEWAY_ATTRIBUTES_TOPIC: | ||
621 | -// case MqttTopics.GATEWAY_RPC_TOPIC: | ||
622 | -// case MqttTopics.GATEWAY_ATTRIBUTES_RESPONSE_TOPIC: | ||
623 | -// case MqttTopics.DEVICE_PROVISION_RESPONSE_TOPIC: | ||
624 | -// case MqttTopics.DEVICE_FIRMWARE_RESPONSES_TOPIC: | ||
625 | -// case MqttTopics.DEVICE_FIRMWARE_ERROR_TOPIC: | ||
626 | -// case MqttTopics.DEVICE_SOFTWARE_RESPONSES_TOPIC: | ||
627 | -// case MqttTopics.DEVICE_SOFTWARE_ERROR_TOPIC: { | ||
628 | -// activityReported = true; | ||
629 | -// break; | ||
630 | -// } | ||
631 | -// } | ||
632 | -// } catch (Exception e) { | ||
633 | -// log.debug("[{}] Failed to process unsubscription [{}] to [{}]", sessionId, mqttMsg.variableHeader().messageId(), topicName); | ||
634 | -// } | ||
635 | -// } | ||
636 | -// if (!activityReported) { | ||
637 | -// transportService.reportActivity(deviceSessionCtx.getSessionInfo()); | ||
638 | -// } | ||
639 | -// ctx.writeAndFlush(createUnSubAckMessage(mqttMsg.variableHeader().messageId())); | ||
640 | - } | ||
641 | - | ||
642 | - private MqttMessage createUnSubAckMessage(int msgId) { | ||
643 | - MqttFixedHeader mqttFixedHeader = | ||
644 | - new MqttFixedHeader(UNSUBACK, false, AT_MOST_ONCE, false, 0); | ||
645 | - MqttMessageIdVariableHeader mqttMessageIdVariableHeader = MqttMessageIdVariableHeader.from(msgId); | ||
646 | - return new MqttMessage(mqttFixedHeader, mqttMessageIdVariableHeader); | ||
647 | - } | ||
648 | 432 | ||
649 | void processConnect(ChannelHandlerContext ctx, String accessToken) { | 433 | void processConnect(ChannelHandlerContext ctx, String accessToken) { |
650 | log.debug("[{}][{}] Processing connect msg for client: {}!", address, sessionId, accessToken); | 434 | log.debug("[{}][{}] Processing connect msg for client: {}!", address, sessionId, accessToken); |
@@ -772,7 +556,23 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | @@ -772,7 +556,23 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | ||
772 | } | 556 | } |
773 | } | 557 | } |
774 | 558 | ||
775 | - | 559 | + private void checkGatewaySession(SessionMetaData sessionMetaData) { |
560 | + TransportDeviceInfo device = deviceSessionCtx.getDeviceInfo(); | ||
561 | + try { | ||
562 | + JsonNode infoNode = context.getMapper().readTree(device.getAdditionalInfo()); | ||
563 | + if (infoNode != null) { | ||
564 | + JsonNode gatewayNode = infoNode.get("gateway"); | ||
565 | + if (gatewayNode != null && gatewayNode.asBoolean()) { | ||
566 | + gatewaySessionHandler = new TcpGatewaySessionHandler(deviceSessionCtx, sessionId); | ||
567 | + if (infoNode.has(DefaultTransportService.OVERWRITE_ACTIVITY_TIME) && infoNode.get(DefaultTransportService.OVERWRITE_ACTIVITY_TIME).isBoolean()) { | ||
568 | + sessionMetaData.setOverwriteActivityTime(infoNode.get(DefaultTransportService.OVERWRITE_ACTIVITY_TIME).asBoolean()); | ||
569 | + } | ||
570 | + } | ||
571 | + } | ||
572 | + } catch (IOException e) { | ||
573 | + log.trace("[{}][{}] Failed to fetch device additional info", sessionId, device.getDeviceName(), e); | ||
574 | + } | ||
575 | + } | ||
776 | 576 | ||
777 | @Override | 577 | @Override |
778 | public void operationComplete(Future<? super Void> future) throws Exception { | 578 | public void operationComplete(Future<? super Void> future) throws Exception { |
@@ -785,6 +585,9 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | @@ -785,6 +585,9 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | ||
785 | log.debug("[{}] Client disconnected!", sessionId); | 585 | log.debug("[{}] Client disconnected!", sessionId); |
786 | transportService.process(deviceSessionCtx.getSessionInfo(), SESSION_EVENT_MSG_CLOSED, null); | 586 | transportService.process(deviceSessionCtx.getSessionInfo(), SESSION_EVENT_MSG_CLOSED, null); |
787 | transportService.deregisterSession(deviceSessionCtx.getSessionInfo()); | 587 | transportService.deregisterSession(deviceSessionCtx.getSessionInfo()); |
588 | + if (gatewaySessionHandler != null) { | ||
589 | + gatewaySessionHandler.onGatewayDisconnect(); | ||
590 | + } | ||
788 | deviceSessionCtx.setDisconnected(); | 591 | deviceSessionCtx.setDisconnected(); |
789 | } | 592 | } |
790 | deviceSessionCtx.release(); | 593 | deviceSessionCtx.release(); |
@@ -804,11 +607,14 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | @@ -804,11 +607,14 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | ||
804 | transportService.process(deviceSessionCtx.getSessionInfo(), SESSION_EVENT_MSG_OPEN, new TransportServiceCallback<Void>() { | 607 | transportService.process(deviceSessionCtx.getSessionInfo(), SESSION_EVENT_MSG_OPEN, new TransportServiceCallback<Void>() { |
805 | @Override | 608 | @Override |
806 | public void onSuccess(Void msg) { | 609 | public void onSuccess(Void msg) { |
807 | - transportService.registerAsyncSession(deviceSessionCtx.getSessionInfo(), TcpTransportHandler.this); | 610 | + SessionMetaData sessionMetaData = transportService.registerAsyncSession(deviceSessionCtx.getSessionInfo(), TcpTransportHandler.this); |
611 | + checkGatewaySession(sessionMetaData); | ||
808 | ctx.writeAndFlush(createTcpConnAckMsg(CONNECTION_ACCEPTED)); | 612 | ctx.writeAndFlush(createTcpConnAckMsg(CONNECTION_ACCEPTED)); |
809 | deviceSessionCtx.setConnected(true); | 613 | deviceSessionCtx.setConnected(true); |
810 | log.debug("[{}] Client connected!", sessionId); | 614 | log.debug("[{}] Client connected!", sessionId); |
811 | - transportService.getCallbackExecutor().execute(() -> processMsgQueue(ctx)); //this callback will execute in Producer worker thread and hard or blocking work have to be submitted to the separate thread. | 615 | + |
616 | + transportService.process(deviceSessionCtx.getSessionInfo(), TransportProtos.SubscribeToRPCMsg.newBuilder().build(), null); | ||
617 | + transportService.getCallbackExecutor().execute(() -> processQueueMessage(ctx)); //this callback will execute in Producer worker thread and hard or blocking work have to be submitted to the separate thread. | ||
812 | } | 618 | } |
813 | 619 | ||
814 | @Override | 620 | @Override |
@@ -857,11 +663,10 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | @@ -857,11 +663,10 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | ||
857 | 663 | ||
858 | @Override | 664 | @Override |
859 | public void onToDeviceRpcRequest(UUID sessionId, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) { | 665 | public void onToDeviceRpcRequest(UUID sessionId, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) { |
860 | -// log.trace("[{}] Received RPC command to device", sessionId); | ||
861 | -// String baseTopic = rpcSubTopicType.getRpcRequestTopicBase(); | ||
862 | -// TcpTransportAdaptor adaptor = deviceSessionCtx.getAdaptor(rpcSubTopicType); | ||
863 | -// try { | ||
864 | -// adaptor.convertToPublish(deviceSessionCtx, rpcRequest, baseTopic).ifPresent(payload -> { | 666 | + log.error("【{}】下发RPC命令【{}】给设备【{}】", sessionId,rpcRequest.getParams(),deviceSessionCtx.getDeviceInfo().getDeviceName()); |
667 | + TcpTransportAdaptor adaptor = deviceSessionCtx.getPayloadAdaptor(); | ||
668 | + try { | ||
669 | + adaptor.convertToPublish(deviceSessionCtx, rpcRequest).ifPresent(payload -> { | ||
865 | // int msgId = ((MqttPublishMessage) payload).variableHeader().packetId(); | 670 | // int msgId = ((MqttPublishMessage) payload).variableHeader().packetId(); |
866 | // if (isAckExpected(payload)) { | 671 | // if (isAckExpected(payload)) { |
867 | // rpcAwaitingAck.put(msgId, rpcRequest); | 672 | // rpcAwaitingAck.put(msgId, rpcRequest); |
@@ -872,30 +677,31 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | @@ -872,30 +677,31 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | ||
872 | // } | 677 | // } |
873 | // }, Math.max(0, Math.min(deviceSessionCtx.getContext().getTimeout(), rpcRequest.getExpirationTime() - System.currentTimeMillis())), TimeUnit.MILLISECONDS); | 678 | // }, Math.max(0, Math.min(deviceSessionCtx.getContext().getTimeout(), rpcRequest.getExpirationTime() - System.currentTimeMillis())), TimeUnit.MILLISECONDS); |
874 | // } | 679 | // } |
875 | -// var cf = publish(payload, deviceSessionCtx); | ||
876 | -// cf.addListener(result -> { | ||
877 | -// if (result.cause() == null) { | 680 | + var cf = pushDeviceMsg(deviceSessionCtx.getChannel(), payload); |
681 | + cf.addListener(result -> { | ||
682 | + if (result.cause() == null) { | ||
878 | // if (!isAckExpected(payload)) { | 683 | // if (!isAckExpected(payload)) { |
879 | // transportService.process(deviceSessionCtx.getSessionInfo(), rpcRequest, RpcStatus.DELIVERED, TransportServiceCallback.EMPTY); | 684 | // transportService.process(deviceSessionCtx.getSessionInfo(), rpcRequest, RpcStatus.DELIVERED, TransportServiceCallback.EMPTY); |
880 | -// } else if (rpcRequest.getPersisted()) { | ||
881 | -// transportService.process(deviceSessionCtx.getSessionInfo(), rpcRequest, RpcStatus.SENT, TransportServiceCallback.EMPTY); | ||
882 | -// } | ||
883 | -// } else { | ||
884 | -// // TODO: send error | ||
885 | -// } | ||
886 | -// }); | ||
887 | -// }); | ||
888 | -// } catch (Exception e) { | ||
889 | -// transportService.process(deviceSessionCtx.getSessionInfo(), | ||
890 | -// TransportProtos.ToDeviceRpcResponseMsg.newBuilder() | ||
891 | -// .setRequestId(rpcRequest.getRequestId()).setError("Failed to convert device RPC command to MQTT msg").build(), TransportServiceCallback.EMPTY); | ||
892 | -// log.trace("[{}] Failed to convert device RPC command to MQTT msg", sessionId, e); | ||
893 | -// } | 685 | +// } else |
686 | + if (rpcRequest.getPersisted()) { | ||
687 | + transportService.process(deviceSessionCtx.getSessionInfo(), rpcRequest, RpcStatus.SENT, TransportServiceCallback.EMPTY); | ||
688 | + } | ||
689 | + } else { | ||
690 | + // TODO: send error | ||
691 | + } | ||
692 | + }); | ||
693 | + }); | ||
694 | + } catch (Exception e) { | ||
695 | + transportService.process(deviceSessionCtx.getSessionInfo(), | ||
696 | + TransportProtos.ToDeviceRpcResponseMsg.newBuilder() | ||
697 | + .setRequestId(rpcRequest.getRequestId()).setError("Failed to convert device RPC command to TCP msg").build(), TransportServiceCallback.EMPTY); | ||
698 | + log.error("[{}] Failed to convert device RPC command to TCP msg", sessionId, e); | ||
699 | + } | ||
894 | } | 700 | } |
895 | 701 | ||
896 | @Override | 702 | @Override |
897 | public void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg rpcResponse) { | 703 | public void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg rpcResponse) { |
898 | -// log.trace("[{}] Received RPC response from server", sessionId); | 704 | + log.error("[{}] 服务端响应设备的RPC请求", sessionId); |
899 | // String baseTopic = toServerRpcSubTopicType.getRpcResponseTopicBase(); | 705 | // String baseTopic = toServerRpcSubTopicType.getRpcResponseTopicBase(); |
900 | // TcpTransportAdaptor adaptor = deviceSessionCtx.getAdaptor(toServerRpcSubTopicType); | 706 | // TcpTransportAdaptor adaptor = deviceSessionCtx.getAdaptor(toServerRpcSubTopicType); |
901 | // try { | 707 | // try { |
@@ -905,8 +711,30 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | @@ -905,8 +711,30 @@ public class TcpTransportHandler extends ChannelInboundHandlerAdapter implements | ||
905 | // } | 711 | // } |
906 | } | 712 | } |
907 | 713 | ||
908 | - private ChannelFuture publish(MqttMessage message, DeviceSessionCtx deviceSessionCtx) { | ||
909 | - return deviceSessionCtx.getChannel().writeAndFlush(message); | 714 | + /** |
715 | + * 往设备推送消息 | ||
716 | + * @param tcp | ||
717 | + * @return | ||
718 | + */ | ||
719 | + private ChannelFuture pushDeviceMsg(ChannelHandlerContext ctx,TCPMessage tcp) { | ||
720 | + 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); | ||
731 | + ByteBuf payload = Unpooled.copiedBuffer(payloadInBytes); | ||
732 | + | ||
733 | + return ctx.writeAndFlush(payload); | ||
734 | + } catch (UnsupportedEncodingException e) { | ||
735 | + log.error(e.getMessage(),e); | ||
736 | + throw new RuntimeException(e); | ||
737 | + } | ||
910 | } | 738 | } |
911 | 739 | ||
912 | private boolean isAckExpected(MqttMessage message) { | 740 | private boolean isAckExpected(MqttMessage message) { |
common/transport/tcp/src/main/java/org/thingsboard/server/transport/tcp/adaptors/JsonTcpAdaptor.java
1 | /** | 1 | /** |
2 | * Copyright © 2016-2022 The Thingsboard Authors | 2 | * Copyright © 2016-2022 The Thingsboard Authors |
3 | - * | 3 | + * <p> |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with 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 | 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 | * Unless required by applicable law or agreed to in writing, software | 10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
@@ -23,30 +23,26 @@ import com.google.gson.JsonObject; | @@ -23,30 +23,26 @@ import com.google.gson.JsonObject; | ||
23 | import com.google.gson.JsonParser; | 23 | import com.google.gson.JsonParser; |
24 | import com.google.gson.JsonSyntaxException; | 24 | import com.google.gson.JsonSyntaxException; |
25 | import io.netty.buffer.ByteBuf; | 25 | import io.netty.buffer.ByteBuf; |
26 | -import io.netty.handler.codec.mqtt.MqttFixedHeader; | ||
27 | -import io.netty.handler.codec.mqtt.MqttMessage; | ||
28 | import io.netty.handler.codec.mqtt.MqttPublishMessage; | 26 | import io.netty.handler.codec.mqtt.MqttPublishMessage; |
29 | -import io.netty.handler.codec.mqtt.MqttPublishVariableHeader; | ||
30 | import lombok.extern.slf4j.Slf4j; | 27 | import lombok.extern.slf4j.Slf4j; |
31 | import org.springframework.beans.factory.annotation.Autowired; | 28 | import org.springframework.beans.factory.annotation.Autowired; |
32 | import org.springframework.stereotype.Component; | 29 | import org.springframework.stereotype.Component; |
33 | import org.springframework.util.StringUtils; | 30 | import org.springframework.util.StringUtils; |
34 | -import org.thingsboard.server.common.data.device.profile.MqttTopics; | ||
35 | import org.thingsboard.server.common.data.ota.OtaPackageType; | 31 | import org.thingsboard.server.common.data.ota.OtaPackageType; |
36 | import org.thingsboard.server.common.transport.adaptor.AdaptorException; | 32 | import org.thingsboard.server.common.transport.adaptor.AdaptorException; |
37 | import org.thingsboard.server.common.transport.adaptor.JsonConverter; | 33 | import org.thingsboard.server.common.transport.adaptor.JsonConverter; |
38 | -import org.thingsboard.server.gen.transport.TransportProtos; | ||
39 | import org.thingsboard.server.common.yunteng.script.YtScriptInvokeService; | 34 | import org.thingsboard.server.common.yunteng.script.YtScriptInvokeService; |
40 | import org.thingsboard.server.common.yunteng.script.YtScriptType; | 35 | import org.thingsboard.server.common.yunteng.script.YtScriptType; |
41 | -import org.thingsboard.server.transport.tcp.session.DeviceSessionCtx; | 36 | +import org.thingsboard.server.gen.transport.TransportProtos; |
37 | +import org.thingsboard.server.transport.tcp.session.TCPMessage; | ||
38 | +import org.thingsboard.server.transport.tcp.session.TcpDeviceWareSessionContext; | ||
42 | 39 | ||
40 | +import java.io.UnsupportedEncodingException; | ||
43 | import java.nio.charset.Charset; | 41 | import java.nio.charset.Charset; |
44 | import java.nio.charset.StandardCharsets; | 42 | import java.nio.charset.StandardCharsets; |
45 | import java.util.*; | 43 | import java.util.*; |
46 | import java.util.concurrent.ExecutionException; | 44 | import java.util.concurrent.ExecutionException; |
47 | 45 | ||
48 | -import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_SOFTWARE_FIRMWARE_RESPONSES_TOPIC_FORMAT; | ||
49 | - | ||
50 | 46 | ||
51 | /** | 47 | /** |
52 | * @author Andrew Shvayka | 48 | * @author Andrew Shvayka |
@@ -59,8 +55,9 @@ public class JsonTcpAdaptor implements TcpTransportAdaptor { | @@ -59,8 +55,9 @@ public class JsonTcpAdaptor implements TcpTransportAdaptor { | ||
59 | @Autowired | 55 | @Autowired |
60 | private YtScriptInvokeService jsEngine; | 56 | private YtScriptInvokeService jsEngine; |
61 | private static final JsonParser parser = new JsonParser(); | 57 | private static final JsonParser parser = new JsonParser(); |
58 | + | ||
62 | @Override | 59 | @Override |
63 | - public TransportProtos.PostTelemetryMsg convertToPostTelemetry(DeviceSessionCtx ctx, String inbound) throws AdaptorException { | 60 | + public TransportProtos.PostTelemetryMsg convertToPostTelemetry(TcpDeviceWareSessionContext ctx, String inbound) throws AdaptorException { |
64 | try { | 61 | try { |
65 | JsonElement payload = validatePayload(ctx, inbound, false); | 62 | JsonElement payload = validatePayload(ctx, inbound, false); |
66 | return JsonConverter.convertToTelemetryProto(payload); | 63 | return JsonConverter.convertToTelemetryProto(payload); |
@@ -80,7 +77,7 @@ public class JsonTcpAdaptor implements TcpTransportAdaptor { | @@ -80,7 +77,7 @@ public class JsonTcpAdaptor implements TcpTransportAdaptor { | ||
80 | } | 77 | } |
81 | 78 | ||
82 | @Override | 79 | @Override |
83 | - public TransportProtos.PostAttributeMsg convertToPostAttributes(DeviceSessionCtx ctx, MqttPublishMessage inbound) throws AdaptorException { | 80 | + public TransportProtos.PostAttributeMsg convertToPostAttributes(TcpDeviceWareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException { |
84 | String payload = validatePayload(ctx.getSessionId(), inbound.payload(), false); | 81 | String payload = validatePayload(ctx.getSessionId(), inbound.payload(), false); |
85 | try { | 82 | try { |
86 | return JsonConverter.convertToAttributesProto(new JsonParser().parse(payload)); | 83 | return JsonConverter.convertToAttributesProto(new JsonParser().parse(payload)); |
@@ -91,7 +88,7 @@ public class JsonTcpAdaptor implements TcpTransportAdaptor { | @@ -91,7 +88,7 @@ public class JsonTcpAdaptor implements TcpTransportAdaptor { | ||
91 | } | 88 | } |
92 | 89 | ||
93 | @Override | 90 | @Override |
94 | - public TransportProtos.ClaimDeviceMsg convertToClaimDevice(DeviceSessionCtx ctx, MqttPublishMessage inbound) throws AdaptorException { | 91 | + public TransportProtos.ClaimDeviceMsg convertToClaimDevice(TcpDeviceWareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException { |
95 | String payload = validatePayload(ctx.getSessionId(), inbound.payload(), true); | 92 | String payload = validatePayload(ctx.getSessionId(), inbound.payload(), true); |
96 | try { | 93 | try { |
97 | return JsonConverter.convertToClaimDeviceProto(ctx.getDeviceId(), payload); | 94 | return JsonConverter.convertToClaimDeviceProto(ctx.getDeviceId(), payload); |
@@ -102,7 +99,7 @@ public class JsonTcpAdaptor implements TcpTransportAdaptor { | @@ -102,7 +99,7 @@ public class JsonTcpAdaptor implements TcpTransportAdaptor { | ||
102 | } | 99 | } |
103 | 100 | ||
104 | @Override | 101 | @Override |
105 | - public TransportProtos.ProvisionDeviceRequestMsg convertToProvisionRequestMsg(DeviceSessionCtx ctx, MqttPublishMessage inbound) throws AdaptorException { | 102 | + public TransportProtos.ProvisionDeviceRequestMsg convertToProvisionRequestMsg(TcpDeviceWareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException { |
106 | String payload = validatePayload(ctx.getSessionId(), inbound.payload(), false); | 103 | String payload = validatePayload(ctx.getSessionId(), inbound.payload(), false); |
107 | try { | 104 | try { |
108 | return JsonConverter.convertToProvisionRequestMsg(payload); | 105 | return JsonConverter.convertToProvisionRequestMsg(payload); |
@@ -112,64 +109,73 @@ public class JsonTcpAdaptor implements TcpTransportAdaptor { | @@ -112,64 +109,73 @@ public class JsonTcpAdaptor implements TcpTransportAdaptor { | ||
112 | } | 109 | } |
113 | 110 | ||
114 | @Override | 111 | @Override |
115 | - public TransportProtos.GetAttributeRequestMsg convertToGetAttributes(DeviceSessionCtx ctx, MqttPublishMessage inbound, String topicBase) throws AdaptorException { | 112 | + public TransportProtos.GetAttributeRequestMsg convertToGetAttributes(TcpDeviceWareSessionContext ctx, MqttPublishMessage inbound, String topicBase) throws AdaptorException { |
116 | return processGetAttributeRequestMsg(inbound, topicBase); | 113 | return processGetAttributeRequestMsg(inbound, topicBase); |
117 | } | 114 | } |
118 | 115 | ||
119 | @Override | 116 | @Override |
120 | - public TransportProtos.ToDeviceRpcResponseMsg convertToDeviceRpcResponse(DeviceSessionCtx ctx, MqttPublishMessage inbound, String topicBase) throws AdaptorException { | 117 | + public TransportProtos.ToDeviceRpcResponseMsg convertToDeviceRpcResponse(TcpDeviceWareSessionContext ctx, String inbound, String topicBase) throws AdaptorException { |
121 | return processToDeviceRpcResponseMsg(inbound, topicBase); | 118 | return processToDeviceRpcResponseMsg(inbound, topicBase); |
122 | } | 119 | } |
123 | 120 | ||
124 | @Override | 121 | @Override |
125 | - public TransportProtos.ToServerRpcRequestMsg convertToServerRpcRequest(DeviceSessionCtx ctx, MqttPublishMessage inbound, String topicBase) throws AdaptorException { | 122 | + public TransportProtos.ToServerRpcRequestMsg convertToServerRpcRequest(TcpDeviceWareSessionContext ctx, MqttPublishMessage inbound, String topicBase) throws AdaptorException { |
126 | return processToServerRpcRequestMsg(ctx, inbound, topicBase); | 123 | return processToServerRpcRequestMsg(ctx, inbound, topicBase); |
127 | } | 124 | } |
128 | 125 | ||
129 | @Override | 126 | @Override |
130 | - public Optional<MqttMessage> convertToPublish(DeviceSessionCtx ctx, TransportProtos.GetAttributeResponseMsg responseMsg, String topicBase) throws AdaptorException { | 127 | + public Optional<TCPMessage> convertToPublish(TcpDeviceWareSessionContext ctx, TransportProtos.GetAttributeResponseMsg responseMsg, String topicBase) throws AdaptorException { |
131 | return processConvertFromAttributeResponseMsg(ctx, responseMsg, topicBase); | 128 | return processConvertFromAttributeResponseMsg(ctx, responseMsg, topicBase); |
132 | } | 129 | } |
133 | 130 | ||
134 | @Override | 131 | @Override |
135 | - public Optional<MqttMessage> convertToGatewayPublish(DeviceSessionCtx ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException { | 132 | + public Optional<TCPMessage> convertToGatewayPublish(TcpDeviceWareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException { |
136 | return processConvertFromGatewayAttributeResponseMsg(ctx, deviceName, responseMsg); | 133 | return processConvertFromGatewayAttributeResponseMsg(ctx, deviceName, responseMsg); |
137 | } | 134 | } |
138 | 135 | ||
139 | @Override | 136 | @Override |
140 | - public Optional<MqttMessage> convertToPublish(DeviceSessionCtx ctx, TransportProtos.AttributeUpdateNotificationMsg notificationMsg, String topic) { | ||
141 | - return Optional.of(createMqttPublishMsg(ctx, topic, JsonConverter.toJson(notificationMsg))); | 137 | + public Optional<TCPMessage> convertToPublish(TcpDeviceWareSessionContext ctx, TransportProtos.AttributeUpdateNotificationMsg notificationMsg, String topic) { |
138 | + return Optional.of(createTcpMessage(ctx, JsonConverter.toJson(notificationMsg))); | ||
142 | } | 139 | } |
143 | 140 | ||
144 | @Override | 141 | @Override |
145 | - public Optional<MqttMessage> convertToGatewayPublish(DeviceSessionCtx ctx, String deviceName, TransportProtos.AttributeUpdateNotificationMsg notificationMsg) { | 142 | + public Optional<TCPMessage> convertToGatewayPublish(TcpDeviceWareSessionContext ctx, String deviceName, TransportProtos.AttributeUpdateNotificationMsg notificationMsg) { |
146 | JsonObject result = JsonConverter.getJsonObjectForGateway(deviceName, notificationMsg); | 143 | JsonObject result = JsonConverter.getJsonObjectForGateway(deviceName, notificationMsg); |
147 | - return Optional.of(createMqttPublishMsg(ctx, MqttTopics.GATEWAY_ATTRIBUTES_TOPIC, result)); | 144 | + return Optional.of(createTcpMessage(ctx, result)); |
148 | } | 145 | } |
149 | 146 | ||
150 | @Override | 147 | @Override |
151 | - public Optional<MqttMessage> convertToPublish(DeviceSessionCtx ctx, TransportProtos.ToDeviceRpcRequestMsg rpcRequest, String topicBase) { | ||
152 | - return Optional.of(createMqttPublishMsg(ctx, topicBase + rpcRequest.getRequestId(), JsonConverter.toJson(rpcRequest, false))); | 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)); | ||
153 | } | 159 | } |
154 | 160 | ||
155 | @Override | 161 | @Override |
156 | - public Optional<MqttMessage> convertToGatewayPublish(DeviceSessionCtx ctx, String deviceName, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) { | ||
157 | - return Optional.of(createMqttPublishMsg(ctx, MqttTopics.GATEWAY_RPC_TOPIC, JsonConverter.toGatewayJson(deviceName, rpcRequest))); | 162 | + public Optional<TCPMessage> convertToGatewayPublish(TcpDeviceWareSessionContext ctx, String deviceName, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) { |
163 | + return Optional.of(createTcpMessage(ctx, JsonConverter.toGatewayJson(deviceName, rpcRequest))); | ||
158 | } | 164 | } |
159 | 165 | ||
160 | @Override | 166 | @Override |
161 | - public Optional<MqttMessage> convertToPublish(DeviceSessionCtx ctx, TransportProtos.ToServerRpcResponseMsg rpcResponse, String topicBase) { | ||
162 | - return Optional.of(createMqttPublishMsg(ctx, topicBase + rpcResponse.getRequestId(), JsonConverter.toJson(rpcResponse))); | 167 | + public Optional<TCPMessage> convertToPublish(TcpDeviceWareSessionContext ctx, TransportProtos.ToServerRpcResponseMsg rpcResponse, String topicBase) { |
168 | + return Optional.of(createTcpMessage(ctx, JsonConverter.toJson(rpcResponse))); | ||
163 | } | 169 | } |
164 | 170 | ||
165 | @Override | 171 | @Override |
166 | - public Optional<MqttMessage> convertToPublish(DeviceSessionCtx ctx, TransportProtos.ProvisionDeviceResponseMsg provisionResponse) { | ||
167 | - return Optional.of(createMqttPublishMsg(ctx, MqttTopics.DEVICE_PROVISION_RESPONSE_TOPIC, JsonConverter.toJson(provisionResponse))); | 172 | + public Optional<TCPMessage> convertToPublish(TcpDeviceWareSessionContext ctx, TransportProtos.ProvisionDeviceResponseMsg provisionResponse) { |
173 | + return Optional.of(createTcpMessage(ctx, JsonConverter.toJson(provisionResponse))); | ||
168 | } | 174 | } |
169 | 175 | ||
170 | @Override | 176 | @Override |
171 | - public Optional<MqttMessage> convertToPublish(DeviceSessionCtx ctx, byte[] firmwareChunk, String requestId, int chunk, OtaPackageType firmwareType) { | ||
172 | - return Optional.of(createMqttPublishMsg(ctx, String.format(DEVICE_SOFTWARE_FIRMWARE_RESPONSES_TOPIC_FORMAT, firmwareType.getKeyPrefix(), requestId, chunk), firmwareChunk)); | 177 | + public Optional<TCPMessage> convertToPublish(TcpDeviceWareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, OtaPackageType firmwareType) { |
178 | + return Optional.of(null); | ||
173 | } | 179 | } |
174 | 180 | ||
175 | public static JsonElement validateJsonPayload(UUID sessionId, ByteBuf payloadData) throws AdaptorException { | 181 | public static JsonElement validateJsonPayload(UUID sessionId, ByteBuf payloadData) throws AdaptorException { |
@@ -204,19 +210,20 @@ public class JsonTcpAdaptor implements TcpTransportAdaptor { | @@ -204,19 +210,20 @@ public class JsonTcpAdaptor implements TcpTransportAdaptor { | ||
204 | } | 210 | } |
205 | } | 211 | } |
206 | 212 | ||
207 | - private TransportProtos.ToDeviceRpcResponseMsg processToDeviceRpcResponseMsg(MqttPublishMessage inbound, String topicBase) throws AdaptorException { | ||
208 | - String topicName = inbound.variableHeader().topicName(); | ||
209 | - try { | ||
210 | - int requestId = getRequestId(topicName, topicBase); | ||
211 | - String payload = inbound.payload().toString(UTF8); | ||
212 | - return TransportProtos.ToDeviceRpcResponseMsg.newBuilder().setRequestId(requestId).setPayload(payload).build(); | ||
213 | - } catch (RuntimeException e) { | ||
214 | - log.debug("Failed to decode rpc response", e); | ||
215 | - throw new AdaptorException(e); | ||
216 | - } | 213 | + private TransportProtos.ToDeviceRpcResponseMsg processToDeviceRpcResponseMsg(String inbound, String topicBase) throws AdaptorException { |
214 | +// String topicName = inbound.variableHeader().topicName(); | ||
215 | +// try { | ||
216 | +// int requestId = getRequestId(topicName, topicBase); | ||
217 | +// String payload = inbound.payload().toString(UTF8); | ||
218 | +// return TransportProtos.ToDeviceRpcResponseMsg.newBuilder().setRequestId(requestId).setPayload(payload).build(); | ||
219 | +// } catch (RuntimeException e) { | ||
220 | +// log.debug("Failed to decode rpc response", e); | ||
221 | +// throw new AdaptorException(e); | ||
222 | +// } | ||
223 | + return null; | ||
217 | } | 224 | } |
218 | 225 | ||
219 | - private TransportProtos.ToServerRpcRequestMsg processToServerRpcRequestMsg(DeviceSessionCtx ctx, MqttPublishMessage inbound, String topicBase) throws AdaptorException { | 226 | + private TransportProtos.ToServerRpcRequestMsg processToServerRpcRequestMsg(TcpDeviceWareSessionContext ctx, MqttPublishMessage inbound, String topicBase) throws AdaptorException { |
220 | String topicName = inbound.variableHeader().topicName(); | 227 | String topicName = inbound.variableHeader().topicName(); |
221 | String payload = validatePayload(ctx.getSessionId(), inbound.payload(), false); | 228 | String payload = validatePayload(ctx.getSessionId(), inbound.payload(), false); |
222 | try { | 229 | try { |
@@ -228,37 +235,28 @@ public class JsonTcpAdaptor implements TcpTransportAdaptor { | @@ -228,37 +235,28 @@ public class JsonTcpAdaptor implements TcpTransportAdaptor { | ||
228 | } | 235 | } |
229 | } | 236 | } |
230 | 237 | ||
231 | - private Optional<MqttMessage> processConvertFromAttributeResponseMsg(DeviceSessionCtx ctx, TransportProtos.GetAttributeResponseMsg responseMsg, String topicBase) throws AdaptorException { | 238 | + private Optional<TCPMessage> processConvertFromAttributeResponseMsg(TcpDeviceWareSessionContext ctx, TransportProtos.GetAttributeResponseMsg responseMsg, String topicBase) throws AdaptorException { |
232 | if (!StringUtils.isEmpty(responseMsg.getError())) { | 239 | if (!StringUtils.isEmpty(responseMsg.getError())) { |
233 | throw new AdaptorException(responseMsg.getError()); | 240 | throw new AdaptorException(responseMsg.getError()); |
234 | } else { | 241 | } else { |
235 | int requestId = responseMsg.getRequestId(); | 242 | int requestId = responseMsg.getRequestId(); |
236 | if (requestId >= 0) { | 243 | if (requestId >= 0) { |
237 | - return Optional.of(createMqttPublishMsg(ctx, | ||
238 | - topicBase + requestId, | 244 | + return Optional.of(createTcpMessage(ctx, |
239 | JsonConverter.toJson(responseMsg))); | 245 | JsonConverter.toJson(responseMsg))); |
240 | } | 246 | } |
241 | return Optional.empty(); | 247 | return Optional.empty(); |
242 | } | 248 | } |
243 | } | 249 | } |
244 | 250 | ||
245 | - private Optional<MqttMessage> processConvertFromGatewayAttributeResponseMsg(DeviceSessionCtx ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException { | 251 | + private Optional<TCPMessage> processConvertFromGatewayAttributeResponseMsg(TcpDeviceWareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException { |
246 | if (!StringUtils.isEmpty(responseMsg.getError())) { | 252 | if (!StringUtils.isEmpty(responseMsg.getError())) { |
247 | throw new AdaptorException(responseMsg.getError()); | 253 | throw new AdaptorException(responseMsg.getError()); |
248 | } else { | 254 | } else { |
249 | JsonObject result = JsonConverter.getJsonObjectForGateway(deviceName, responseMsg); | 255 | JsonObject result = JsonConverter.getJsonObjectForGateway(deviceName, responseMsg); |
250 | - return Optional.of(createMqttPublishMsg(ctx, MqttTopics.GATEWAY_ATTRIBUTES_RESPONSE_TOPIC, result)); | 256 | + return Optional.of(createTcpMessage(ctx, result)); |
251 | } | 257 | } |
252 | } | 258 | } |
253 | 259 | ||
254 | - protected MqttPublishMessage createMqttPublishMsg(DeviceSessionCtx ctx, String topic, JsonElement json) { | ||
255 | - MqttFixedHeader mqttFixedHeader = null; | ||
256 | -// new MqttFixedHeader(MqttMessageType.PUBLISH, false, ctx.getQoSForTopic(topic), false, 0); | ||
257 | - MqttPublishVariableHeader header = new MqttPublishVariableHeader(topic, ctx.nextMsgId()); | ||
258 | - ByteBuf payload = ALLOCATOR.buffer(); | ||
259 | - payload.writeBytes(json.toString().getBytes(UTF8)); | ||
260 | - return new MqttPublishMessage(mqttFixedHeader, header, payload); | ||
261 | - } | ||
262 | 260 | ||
263 | private Set<String> toStringSet(JsonElement requestBody, String name) { | 261 | private Set<String> toStringSet(JsonElement requestBody, String name) { |
264 | JsonElement element = requestBody.getAsJsonObject().get(name); | 262 | JsonElement element = requestBody.getAsJsonObject().get(name); |
@@ -280,7 +278,7 @@ public class JsonTcpAdaptor implements TcpTransportAdaptor { | @@ -280,7 +278,7 @@ public class JsonTcpAdaptor implements TcpTransportAdaptor { | ||
280 | return payload; | 278 | return payload; |
281 | } | 279 | } |
282 | 280 | ||
283 | - private JsonElement validatePayload(DeviceSessionCtx session, String payload, boolean isEmptyPayloadAllowed) throws AdaptorException, ExecutionException, InterruptedException { | 281 | + private JsonElement validatePayload(TcpDeviceWareSessionContext session, String payload, boolean isEmptyPayloadAllowed) throws AdaptorException, ExecutionException, InterruptedException { |
284 | if (payload == null) { | 282 | if (payload == null) { |
285 | log.debug("[{}] Payload is empty!", session.getSessionId()); | 283 | log.debug("[{}] Payload is empty!", session.getSessionId()); |
286 | if (!isEmptyPayloadAllowed) { | 284 | if (!isEmptyPayloadAllowed) { |
@@ -306,4 +304,23 @@ public class JsonTcpAdaptor implements TcpTransportAdaptor { | @@ -306,4 +304,23 @@ public class JsonTcpAdaptor implements TcpTransportAdaptor { | ||
306 | return Integer.parseInt(topicName.substring(topic.length())); | 304 | return Integer.parseInt(topicName.substring(topic.length())); |
307 | } | 305 | } |
308 | 306 | ||
307 | + | ||
308 | + protected TCPMessage createTcpMessage(TcpDeviceWareSessionContext ctx, JsonElement json) { | ||
309 | +// TCPMessage msg = new TCPMessage(MqttMessageType.PUBLISH,); | ||
310 | +//// new MqttFixedHeader(MqttMessageType.PUBLISH, false, ctx.getQoSForTopic(topic), false, 0); | ||
311 | +// MqttPublishVariableHeader header = new MqttPublishVariableHeader(topic, ctx.nextMsgId()); | ||
312 | +// ByteBuf payload = ALLOCATOR.buffer(); | ||
313 | +// payload.writeBytes(json.toString().getBytes(UTF8)); | ||
314 | +// return new MqttPublishMessage(mqttFixedHeader, header, payload); | ||
315 | + return null; | ||
316 | + } | ||
317 | + | ||
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 | + | ||
309 | } | 326 | } |
@@ -16,79 +16,90 @@ | @@ -16,79 +16,90 @@ | ||
16 | package org.thingsboard.server.transport.tcp.adaptors; | 16 | package org.thingsboard.server.transport.tcp.adaptors; |
17 | 17 | ||
18 | import io.netty.buffer.ByteBuf; | 18 | import io.netty.buffer.ByteBuf; |
19 | -import io.netty.buffer.ByteBufAllocator; | ||
20 | -import io.netty.buffer.UnpooledByteBufAllocator; | ||
21 | -import io.netty.handler.codec.mqtt.MqttFixedHeader; | ||
22 | -import io.netty.handler.codec.mqtt.MqttMessage; | ||
23 | -import io.netty.handler.codec.mqtt.MqttMessageType; | ||
24 | import io.netty.handler.codec.mqtt.MqttPublishMessage; | 19 | import io.netty.handler.codec.mqtt.MqttPublishMessage; |
25 | -import io.netty.handler.codec.mqtt.MqttPublishVariableHeader; | ||
26 | import org.thingsboard.server.common.data.ota.OtaPackageType; | 20 | import org.thingsboard.server.common.data.ota.OtaPackageType; |
21 | +import org.thingsboard.server.common.data.yunteng.enums.TcpDataTypeEnum; | ||
27 | import org.thingsboard.server.common.transport.adaptor.AdaptorException; | 22 | import org.thingsboard.server.common.transport.adaptor.AdaptorException; |
28 | -import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; | ||
29 | -import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; | ||
30 | -import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; | ||
31 | -import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; | ||
32 | -import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg; | ||
33 | -import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg; | ||
34 | -import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg; | ||
35 | -import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg; | ||
36 | -import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg; | ||
37 | -import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcResponseMsg; | ||
38 | -import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcRequestMsg; | ||
39 | -import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg; | ||
40 | -import org.thingsboard.server.transport.tcp.session.DeviceSessionCtx; | 23 | +import org.thingsboard.server.gen.transport.TransportProtos.*; |
24 | +import org.thingsboard.server.transport.tcp.session.TcpDeviceWareSessionContext; | ||
25 | +import org.thingsboard.server.transport.tcp.session.TCPMessage; | ||
41 | 26 | ||
27 | +import java.io.UnsupportedEncodingException; | ||
28 | +import java.nio.charset.Charset; | ||
29 | +import java.nio.charset.StandardCharsets; | ||
42 | import java.util.Optional; | 30 | import java.util.Optional; |
43 | import java.util.UUID; | 31 | import java.util.UUID; |
44 | import java.util.concurrent.ExecutionException; | 32 | import java.util.concurrent.ExecutionException; |
45 | 33 | ||
46 | /** | 34 | /** |
47 | - * @author Andrew Shvayka | 35 | + * 将收到的数据流转换为接口需要的数据格式 |
36 | + * 1、基于解析脚本将ByteBuf转JSON对象。 | ||
37 | + * 2、将JSON对象转PROTOBUF对象。 | ||
48 | */ | 38 | */ |
49 | public interface TcpTransportAdaptor { | 39 | public interface TcpTransportAdaptor { |
50 | - | ||
51 | - ByteBufAllocator ALLOCATOR = new UnpooledByteBufAllocator(false); | ||
52 | - | ||
53 | - PostTelemetryMsg convertToPostTelemetry(DeviceSessionCtx ctx, String inbound) throws AdaptorException; | 40 | + static char[] HEX_VOCABLE = {'0', '1', '2', '3', '4', '5', '6', '7', |
41 | + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; | ||
42 | + static final Charset UTF8 = StandardCharsets.UTF_8; | ||
43 | + PostTelemetryMsg convertToPostTelemetry(TcpDeviceWareSessionContext ctx, String inbound) throws AdaptorException; | ||
54 | 44 | ||
55 | UUID getJsScriptEngineFunctionId(String scriptBody, String... argNames) throws ExecutionException, InterruptedException; | 45 | UUID getJsScriptEngineFunctionId(String scriptBody, String... argNames) throws ExecutionException, InterruptedException; |
56 | - PostAttributeMsg convertToPostAttributes(DeviceSessionCtx ctx, MqttPublishMessage inbound) throws AdaptorException; | ||
57 | - | ||
58 | - GetAttributeRequestMsg convertToGetAttributes(DeviceSessionCtx ctx, MqttPublishMessage inbound, String topicBase) throws AdaptorException; | 46 | + PostAttributeMsg convertToPostAttributes(TcpDeviceWareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException; |
59 | 47 | ||
60 | - ToDeviceRpcResponseMsg convertToDeviceRpcResponse(DeviceSessionCtx ctx, MqttPublishMessage mqttMsg, String topicBase) throws AdaptorException; | 48 | + GetAttributeRequestMsg convertToGetAttributes(TcpDeviceWareSessionContext ctx, MqttPublishMessage inbound, String topicBase) throws AdaptorException; |
61 | 49 | ||
62 | - ToServerRpcRequestMsg convertToServerRpcRequest(DeviceSessionCtx ctx, MqttPublishMessage mqttMsg, String topicBase) throws AdaptorException; | 50 | + ToDeviceRpcResponseMsg convertToDeviceRpcResponse(TcpDeviceWareSessionContext ctx, String mqttMsg, String topicBase) throws AdaptorException; |
63 | 51 | ||
64 | - ClaimDeviceMsg convertToClaimDevice(DeviceSessionCtx ctx, MqttPublishMessage inbound) throws AdaptorException; | 52 | + ToServerRpcRequestMsg convertToServerRpcRequest(TcpDeviceWareSessionContext ctx, MqttPublishMessage mqttMsg, String topicBase) throws AdaptorException; |
65 | 53 | ||
66 | - Optional<MqttMessage> convertToPublish(DeviceSessionCtx ctx, GetAttributeResponseMsg responseMsg, String topicBase) throws AdaptorException; | 54 | + ClaimDeviceMsg convertToClaimDevice(TcpDeviceWareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException; |
67 | 55 | ||
68 | - Optional<MqttMessage> convertToGatewayPublish(DeviceSessionCtx ctx, String deviceName, GetAttributeResponseMsg responseMsg) throws AdaptorException; | 56 | + Optional<TCPMessage> convertToPublish(TcpDeviceWareSessionContext ctx, GetAttributeResponseMsg responseMsg, String topicBase) throws AdaptorException; |
69 | 57 | ||
70 | - Optional<MqttMessage> convertToPublish(DeviceSessionCtx ctx, AttributeUpdateNotificationMsg notificationMsg, String topic) throws AdaptorException; | 58 | + Optional<TCPMessage> convertToGatewayPublish(TcpDeviceWareSessionContext ctx, String deviceName, GetAttributeResponseMsg responseMsg) throws AdaptorException; |
71 | 59 | ||
72 | - Optional<MqttMessage> convertToGatewayPublish(DeviceSessionCtx ctx, String deviceName, AttributeUpdateNotificationMsg notificationMsg) throws AdaptorException; | 60 | + Optional<TCPMessage> convertToPublish(TcpDeviceWareSessionContext ctx, AttributeUpdateNotificationMsg notificationMsg, String topic) throws AdaptorException; |
73 | 61 | ||
74 | - Optional<MqttMessage> convertToPublish(DeviceSessionCtx ctx, ToDeviceRpcRequestMsg rpcRequest, String topicBase) throws AdaptorException; | 62 | + Optional<TCPMessage> convertToGatewayPublish(TcpDeviceWareSessionContext ctx, String deviceName, AttributeUpdateNotificationMsg notificationMsg) throws AdaptorException; |
75 | 63 | ||
76 | - Optional<MqttMessage> convertToGatewayPublish(DeviceSessionCtx ctx, String deviceName, ToDeviceRpcRequestMsg rpcRequest) throws AdaptorException; | 64 | + Optional<TCPMessage> convertToPublish(TcpDeviceWareSessionContext ctx, ToDeviceRpcRequestMsg rpcRequest) throws AdaptorException, UnsupportedEncodingException; |
77 | 65 | ||
78 | - Optional<MqttMessage> convertToPublish(DeviceSessionCtx ctx, ToServerRpcResponseMsg rpcResponse, String topicBase) throws AdaptorException; | 66 | + Optional<TCPMessage> convertToGatewayPublish(TcpDeviceWareSessionContext ctx, String deviceName, ToDeviceRpcRequestMsg rpcRequest) throws AdaptorException; |
79 | 67 | ||
80 | - ProvisionDeviceRequestMsg convertToProvisionRequestMsg(DeviceSessionCtx ctx, MqttPublishMessage inbound) throws AdaptorException; | 68 | + Optional<TCPMessage> convertToPublish(TcpDeviceWareSessionContext ctx, ToServerRpcResponseMsg rpcResponse, String topicBase) throws AdaptorException; |
81 | 69 | ||
82 | - Optional<MqttMessage> convertToPublish(DeviceSessionCtx ctx, ProvisionDeviceResponseMsg provisionResponse) throws AdaptorException; | 70 | + ProvisionDeviceRequestMsg convertToProvisionRequestMsg(TcpDeviceWareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException; |
83 | 71 | ||
84 | - Optional<MqttMessage> convertToPublish(DeviceSessionCtx ctx, byte[] firmwareChunk, String requestId, int chunk, OtaPackageType firmwareType) throws AdaptorException; | 72 | + Optional<TCPMessage> convertToPublish(TcpDeviceWareSessionContext ctx, ProvisionDeviceResponseMsg provisionResponse) throws AdaptorException; |
85 | 73 | ||
86 | - default MqttPublishMessage createMqttPublishMsg(DeviceSessionCtx ctx, String topic, byte[] payloadInBytes) { | ||
87 | - MqttFixedHeader mqttFixedHeader =null; | ||
88 | -// new MqttFixedHeader(MqttMessageType.PUBLISH, false, ctx.getQoSForTopic(topic), false, 0); | ||
89 | - MqttPublishVariableHeader header = new MqttPublishVariableHeader(topic, ctx.nextMsgId()); | ||
90 | - ByteBuf payload = ALLOCATOR.buffer(); | ||
91 | - payload.writeBytes(payloadInBytes); | ||
92 | - return new MqttPublishMessage(mqttFixedHeader, header, payload); | 74 | + Optional<TCPMessage> convertToPublish(TcpDeviceWareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, OtaPackageType firmwareType) throws AdaptorException; |
75 | + public static byte[] toBytes(ByteBuf inbound) { | ||
76 | + byte[] bytes = new byte[inbound.readableBytes()]; | ||
77 | + int readerIndex = inbound.readerIndex(); | ||
78 | + inbound.getBytes(readerIndex, bytes); | ||
79 | + return bytes; | ||
80 | + } | ||
81 | + public static String bytesToHex(byte[] bs) { | ||
82 | + StringBuilder sb = new StringBuilder(); | ||
83 | + for (byte b : bs) { | ||
84 | + int high = (b >> 4) & 0x0f; | ||
85 | + int low = b & 0x0f; | ||
86 | + sb.append(HEX_VOCABLE[high]); | ||
87 | + sb.append(HEX_VOCABLE[low]); | ||
88 | + } | ||
89 | + return sb.toString(); | ||
90 | + } | ||
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; | ||
93 | } | 104 | } |
94 | } | 105 | } |
@@ -2,36 +2,28 @@ package org.thingsboard.server.transport.tcp.session; | @@ -2,36 +2,28 @@ package org.thingsboard.server.transport.tcp.session; | ||
2 | 2 | ||
3 | import io.netty.handler.codec.mqtt.MqttMessageType; | 3 | import io.netty.handler.codec.mqtt.MqttMessageType; |
4 | import lombok.Data; | 4 | import lombok.Data; |
5 | -import lombok.NoArgsConstructor; | ||
6 | -import lombok.ToString; | ||
7 | 5 | ||
8 | import java.io.Serializable; | 6 | import java.io.Serializable; |
9 | 7 | ||
10 | @Data | 8 | @Data |
11 | public class TCPMessage implements Serializable { | 9 | public class TCPMessage implements Serializable { |
10 | + | ||
11 | + /**消息ID,用于请求与响应的匹配,例如:modbus由地址码和功能码组成。*/ | ||
12 | private String requestId; | 12 | private String requestId; |
13 | - private MqttMessageType messageType; | ||
14 | - | ||
15 | - private byte[] message; | ||
16 | - private boolean hex; | ||
17 | - | ||
18 | - private String deviceId; | ||
19 | - | ||
20 | - /** | ||
21 | - * TCP 消息 | ||
22 | - * @param sn 设备sn | ||
23 | - * @param message 消息体 | ||
24 | - * @param hex 是否是16进制 | ||
25 | - */ | ||
26 | - public TCPMessage(MqttMessageType messageType, String deviceId, byte[] message, boolean hex){ | ||
27 | - this.messageType = messageType; | ||
28 | - this.deviceId = deviceId; | ||
29 | - this.message = message; | ||
30 | - this.hex = hex; | ||
31 | - } | ||
32 | 13 | ||
33 | - public TCPMessage(MqttMessageType messageType, byte[] message){ | ||
34 | - this.messageType = messageType; | 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){ | ||
35 | this.message = message; | 26 | this.message = message; |
36 | } | 27 | } |
28 | + | ||
37 | } | 29 | } |
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 | +package org.thingsboard.server.transport.tcp.session; | ||
17 | + | ||
18 | +import io.netty.channel.ChannelHandlerContext; | ||
19 | +import io.netty.util.ReferenceCountUtil; | ||
20 | +import lombok.Getter; | ||
21 | +import lombok.Setter; | ||
22 | +import lombok.extern.slf4j.Slf4j; | ||
23 | +import org.thingsboard.server.transport.tcp.TcpTransportContext; | ||
24 | + | ||
25 | +import java.util.UUID; | ||
26 | +import java.util.concurrent.ConcurrentLinkedQueue; | ||
27 | +import java.util.concurrent.atomic.AtomicInteger; | ||
28 | +import java.util.concurrent.locks.Lock; | ||
29 | +import java.util.concurrent.locks.ReentrantLock; | ||
30 | +import java.util.function.Consumer; | ||
31 | + | ||
32 | +/** | ||
33 | + * @author Andrew Shvayka | ||
34 | + */ | ||
35 | +@Slf4j | ||
36 | +public class TcpDeviceSessionCtx extends TcpDeviceWareSessionContext { | ||
37 | + | ||
38 | + @Getter | ||
39 | + @Setter | ||
40 | + private ChannelHandlerContext channel; | ||
41 | + | ||
42 | + | ||
43 | + private final AtomicInteger msgIdSeq = new AtomicInteger(0); | ||
44 | + | ||
45 | + private final ConcurrentLinkedQueue<TCPMessage> msgQueue = new ConcurrentLinkedQueue<>(); | ||
46 | + | ||
47 | + @Getter | ||
48 | + private final Lock msgQueueProcessorLock = new ReentrantLock(); | ||
49 | + | ||
50 | + private final AtomicInteger msgQueueSize = new AtomicInteger(0); | ||
51 | + | ||
52 | + @Getter | ||
53 | + @Setter | ||
54 | + private boolean provisionOnly = false; | ||
55 | + | ||
56 | + public TcpDeviceSessionCtx(UUID sessionId, TcpTransportContext context) { | ||
57 | + super(sessionId,context); | ||
58 | + } | ||
59 | + | ||
60 | + public int nextMsgId() { | ||
61 | + return msgIdSeq.incrementAndGet(); | ||
62 | + } | ||
63 | + | ||
64 | + | ||
65 | + | ||
66 | + | ||
67 | + | ||
68 | + | ||
69 | + | ||
70 | + | ||
71 | + | ||
72 | + | ||
73 | + | ||
74 | + | ||
75 | + | ||
76 | + public void addToQueue(TCPMessage msg) { | ||
77 | + msgQueueSize.incrementAndGet(); | ||
78 | + ReferenceCountUtil.retain(msg); | ||
79 | + msgQueue.add(msg); | ||
80 | + } | ||
81 | + | ||
82 | + public void tryProcessQueuedMsgs(Consumer<TCPMessage> msgProcessor) { | ||
83 | + while (!msgQueue.isEmpty()) { | ||
84 | + if (msgQueueProcessorLock.tryLock()) { | ||
85 | + try { | ||
86 | + TCPMessage msg; | ||
87 | + while ((msg = msgQueue.poll()) != null) { | ||
88 | + try { | ||
89 | + msgQueueSize.decrementAndGet(); | ||
90 | + msgProcessor.accept(msg); | ||
91 | + } finally { | ||
92 | + ReferenceCountUtil.safeRelease(msg); | ||
93 | + } | ||
94 | + } | ||
95 | + } finally { | ||
96 | + msgQueueProcessorLock.unlock(); | ||
97 | + } | ||
98 | + } else { | ||
99 | + return; | ||
100 | + } | ||
101 | + } | ||
102 | + } | ||
103 | + | ||
104 | + public int getMsgQueueSize() { | ||
105 | + return msgQueueSize.get(); | ||
106 | + } | ||
107 | + | ||
108 | + public void release() { | ||
109 | + if (!msgQueue.isEmpty()) { | ||
110 | + log.warn("doDisconnect for device {} but unprocessed messages {} left in the msg queue", getDeviceId(), msgQueue.size()); | ||
111 | + msgQueue.forEach(ReferenceCountUtil::safeRelease); | ||
112 | + msgQueue.clear(); | ||
113 | + } | ||
114 | + } | ||
115 | + | ||
116 | + | ||
117 | +} |
common/transport/tcp/src/main/java/org/thingsboard/server/transport/tcp/session/TcpDeviceWareSessionContext.java
renamed from
common/transport/tcp/src/main/java/org/thingsboard/server/transport/tcp/session/DeviceSessionCtx.java
@@ -15,86 +15,85 @@ | @@ -15,86 +15,85 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.transport.tcp.session; | 16 | package org.thingsboard.server.transport.tcp.session; |
17 | 17 | ||
18 | -import io.netty.channel.ChannelHandlerContext; | ||
19 | -import io.netty.util.ReferenceCountUtil; | 18 | +import com.fasterxml.jackson.core.JsonProcessingException; |
19 | +import com.fasterxml.jackson.databind.JsonNode; | ||
20 | import lombok.Getter; | 20 | import lombok.Getter; |
21 | -import lombok.Setter; | ||
22 | import lombok.extern.slf4j.Slf4j; | 21 | import lombok.extern.slf4j.Slf4j; |
23 | import org.thingsboard.server.common.data.DeviceProfile; | 22 | import org.thingsboard.server.common.data.DeviceProfile; |
24 | import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; | 23 | import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; |
25 | import org.thingsboard.server.common.data.device.profile.YtTcpDeviceProfileTransportConfiguration; | 24 | import org.thingsboard.server.common.data.device.profile.YtTcpDeviceProfileTransportConfiguration; |
25 | +import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants; | ||
26 | import org.thingsboard.server.common.data.yunteng.enums.TcpDataTypeEnum; | 26 | import org.thingsboard.server.common.data.yunteng.enums.TcpDataTypeEnum; |
27 | +import org.thingsboard.server.common.transport.auth.TransportDeviceInfo; | ||
27 | import org.thingsboard.server.common.transport.session.DeviceAwareSessionContext; | 28 | import org.thingsboard.server.common.transport.session.DeviceAwareSessionContext; |
28 | import org.thingsboard.server.gen.transport.TransportProtos; | 29 | import org.thingsboard.server.gen.transport.TransportProtos; |
29 | import org.thingsboard.server.transport.tcp.TcpTransportContext; | 30 | import org.thingsboard.server.transport.tcp.TcpTransportContext; |
30 | import org.thingsboard.server.transport.tcp.adaptors.TcpTransportAdaptor; | 31 | import org.thingsboard.server.transport.tcp.adaptors.TcpTransportAdaptor; |
31 | -import org.thingsboard.server.transport.tcp.util.ByteUtils; | ||
32 | 32 | ||
33 | import java.util.UUID; | 33 | import java.util.UUID; |
34 | -import java.util.concurrent.ConcurrentLinkedQueue; | ||
35 | import java.util.concurrent.ExecutionException; | 34 | import java.util.concurrent.ExecutionException; |
36 | -import java.util.concurrent.atomic.AtomicInteger; | ||
37 | -import java.util.concurrent.locks.Lock; | ||
38 | -import java.util.concurrent.locks.ReentrantLock; | ||
39 | -import java.util.function.Consumer; | ||
40 | 35 | ||
41 | /** | 36 | /** |
42 | * @author Andrew Shvayka | 37 | * @author Andrew Shvayka |
43 | */ | 38 | */ |
44 | @Slf4j | 39 | @Slf4j |
45 | -public class DeviceSessionCtx extends DeviceAwareSessionContext { | ||
46 | - | ||
47 | - @Getter | ||
48 | - @Setter | ||
49 | - private ChannelHandlerContext channel; | 40 | +public abstract class TcpDeviceWareSessionContext extends DeviceAwareSessionContext { |
50 | 41 | ||
51 | @Getter | 42 | @Getter |
52 | private final TcpTransportContext context; | 43 | private final TcpTransportContext context; |
53 | 44 | ||
54 | - private final AtomicInteger msgIdSeq = new AtomicInteger(0); | ||
55 | - | ||
56 | - private final ConcurrentLinkedQueue<TCPMessage> msgQueue = new ConcurrentLinkedQueue<>(); | ||
57 | - | 45 | + private volatile String telemetryTopicFilter ; |
46 | + private volatile String attributesTopicFilter; | ||
47 | + private volatile String toDeviceRpcResponseTopicFilter; | ||
58 | @Getter | 48 | @Getter |
59 | - private final Lock msgQueueProcessorLock = new ReentrantLock(); | 49 | + private volatile TcpDataTypeEnum payloadType = TcpDataTypeEnum.HEX; |
60 | 50 | ||
61 | - private final AtomicInteger msgQueueSize = new AtomicInteger(0); | 51 | + private volatile TcpTransportAdaptor adaptor; |
62 | 52 | ||
53 | + /**设备唯一标识符,例如:设备SN、设备地址码等。数据内携带标识符*/ | ||
63 | @Getter | 54 | @Getter |
64 | - @Setter | ||
65 | - private boolean provisionOnly = false; | 55 | + private volatile String deviceCode = "55"; |
56 | + | ||
66 | 57 | ||
67 | - // private volatile TcpTopicFilter telemetryTopicFilter = MqttTopicFilterFactory.getDefaultTelemetryFilter(); | ||
68 | -// private volatile TcpTopicFilter attributesTopicFilter = MqttTopicFilterFactory.getDefaultAttributesFilter(); | ||
69 | - @Getter | ||
70 | - private volatile TcpDataTypeEnum payloadType = TcpDataTypeEnum.HEX; | ||
71 | - @Getter | ||
72 | - private volatile byte[] pingText ; | ||
73 | - // private volatile Descriptors.Descriptor attributesDynamicMessageDescriptor; | ||
74 | -// private volatile Descriptors.Descriptor telemetryDynamicMessageDescriptor; | ||
75 | -// private volatile Descriptors.Descriptor rpcResponseDynamicMessageDescriptor; | ||
76 | -// private volatile DynamicMessage.Builder rpcRequestDynamicMessageBuilder; | ||
77 | - private volatile TcpTransportAdaptor adaptor; | ||
78 | @Getter | 58 | @Getter |
79 | private UUID scriptId; | 59 | private UUID scriptId; |
80 | 60 | ||
81 | - public DeviceSessionCtx(UUID sessionId, TcpTransportContext context) { | 61 | + public TcpDeviceWareSessionContext(UUID sessionId, TcpTransportContext context) { |
82 | super(sessionId); | 62 | super(sessionId); |
83 | this.context = context; | 63 | this.context = context; |
84 | this.adaptor = context.getJsonTcpAdaptor(); | 64 | this.adaptor = context.getJsonTcpAdaptor(); |
85 | } | 65 | } |
86 | 66 | ||
87 | - public int nextMsgId() { | ||
88 | - return msgIdSeq.incrementAndGet(); | 67 | + |
68 | + public boolean isDeviceTelemetryTopic(String topicName) { | ||
69 | + return telemetryTopicFilter.equals(topicName); | ||
89 | } | 70 | } |
90 | 71 | ||
72 | + public boolean isDeviceAttributesTopic(String topicName) { | ||
73 | + return attributesTopicFilter.equals(topicName); | ||
74 | + } | ||
75 | + public boolean isToDeviceRpcResponseTopic(String topicName) { | ||
76 | + return toDeviceRpcResponseTopicFilter.equals(topicName); | ||
77 | + } | ||
91 | 78 | ||
92 | public TcpTransportAdaptor getPayloadAdaptor() { | 79 | public TcpTransportAdaptor getPayloadAdaptor() { |
93 | - return adaptor; | 80 | + return this.adaptor; |
94 | } | 81 | } |
95 | 82 | ||
96 | 83 | ||
84 | + @Override | ||
85 | + public void setDeviceInfo(TransportDeviceInfo deviceInfo) { | ||
86 | + super.setDeviceInfo(deviceInfo); | ||
87 | + try { | ||
88 | + JsonNode additionalInfo = context.getMapper().readTree(deviceInfo.getAdditionalInfo()); | ||
89 | + if(additionalInfo !=null && additionalInfo.has(FastIotConstants.TCP_DEVICE_IDENTIFY_FILED)){ | ||
90 | + deviceCode = additionalInfo.get(FastIotConstants.TCP_DEVICE_IDENTIFY_FILED).asText(); | ||
91 | + } | ||
92 | + } catch (JsonProcessingException e) { | ||
93 | + log.trace("[{}][{}] Failed to fetch device additional info", sessionId, deviceInfo.getDeviceName(), e); | ||
94 | + } | ||
97 | 95 | ||
96 | + } | ||
98 | 97 | ||
99 | @Override | 98 | @Override |
100 | public void setDeviceProfile(DeviceProfile deviceProfile) { | 99 | public void setDeviceProfile(DeviceProfile deviceProfile) { |
@@ -118,7 +117,9 @@ public class DeviceSessionCtx extends DeviceAwareSessionContext { | @@ -118,7 +117,9 @@ public class DeviceSessionCtx extends DeviceAwareSessionContext { | ||
118 | } else { | 117 | } else { |
119 | payloadType = TcpDataTypeEnum.HEX; | 118 | payloadType = TcpDataTypeEnum.HEX; |
120 | } | 119 | } |
121 | - this.pingText = ByteUtils.getBytes(tcpConfiguration.getPingText(),ByteUtils.UTF_8); | 120 | + this.attributesTopicFilter = tcpConfiguration.getAttributesTopic(); |
121 | + this.telemetryTopicFilter = tcpConfiguration.getTelemetryTopic(); | ||
122 | + this.toDeviceRpcResponseTopicFilter = tcpConfiguration.getRpcTopic(); | ||
122 | String scriptBody = tcpConfiguration.getScriptText(); | 123 | String scriptBody = tcpConfiguration.getScriptText(); |
123 | try { | 124 | try { |
124 | this.scriptId = this.adaptor.getJsScriptEngineFunctionId(scriptBody); | 125 | this.scriptId = this.adaptor.getJsScriptEngineFunctionId(scriptBody); |
@@ -130,50 +131,4 @@ public class DeviceSessionCtx extends DeviceAwareSessionContext { | @@ -130,50 +131,4 @@ public class DeviceSessionCtx extends DeviceAwareSessionContext { | ||
130 | } | 131 | } |
131 | } | 132 | } |
132 | 133 | ||
133 | - | ||
134 | - | ||
135 | - | ||
136 | - | ||
137 | - | ||
138 | - public void addToQueue(TCPMessage msg) { | ||
139 | - msgQueueSize.incrementAndGet(); | ||
140 | - ReferenceCountUtil.retain(msg); | ||
141 | - msgQueue.add(msg); | ||
142 | - } | ||
143 | - | ||
144 | - public void tryProcessQueuedMsgs(Consumer<TCPMessage> msgProcessor) { | ||
145 | - while (!msgQueue.isEmpty()) { | ||
146 | - if (msgQueueProcessorLock.tryLock()) { | ||
147 | - try { | ||
148 | - TCPMessage msg; | ||
149 | - while ((msg = msgQueue.poll()) != null) { | ||
150 | - try { | ||
151 | - msgQueueSize.decrementAndGet(); | ||
152 | - msgProcessor.accept(msg); | ||
153 | - } finally { | ||
154 | - ReferenceCountUtil.safeRelease(msg); | ||
155 | - } | ||
156 | - } | ||
157 | - } finally { | ||
158 | - msgQueueProcessorLock.unlock(); | ||
159 | - } | ||
160 | - } else { | ||
161 | - return; | ||
162 | - } | ||
163 | - } | ||
164 | - } | ||
165 | - | ||
166 | - public int getMsgQueueSize() { | ||
167 | - return msgQueueSize.get(); | ||
168 | - } | ||
169 | - | ||
170 | - public void release() { | ||
171 | - if (!msgQueue.isEmpty()) { | ||
172 | - log.warn("doDisconnect for device {} but unprocessed messages {} left in the msg queue", getDeviceId(), msgQueue.size()); | ||
173 | - msgQueue.forEach(ReferenceCountUtil::safeRelease); | ||
174 | - msgQueue.clear(); | ||
175 | - } | ||
176 | - } | ||
177 | - | ||
178 | - | ||
179 | } | 134 | } |
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.transport.tcp.session; | ||
17 | + | ||
18 | +import io.netty.channel.ChannelFuture; | ||
19 | +import io.netty.handler.codec.mqtt.MqttMessage; | ||
20 | +import lombok.extern.slf4j.Slf4j; | ||
21 | +import org.thingsboard.server.common.data.DeviceProfile; | ||
22 | +import org.thingsboard.server.common.data.id.DeviceId; | ||
23 | +import org.thingsboard.server.common.data.rpc.RpcStatus; | ||
24 | +import org.thingsboard.server.common.transport.SessionMsgListener; | ||
25 | +import org.thingsboard.server.common.transport.TransportService; | ||
26 | +import org.thingsboard.server.common.transport.TransportServiceCallback; | ||
27 | +import org.thingsboard.server.common.transport.auth.TransportDeviceInfo; | ||
28 | +import org.thingsboard.server.common.transport.session.DeviceAwareSessionContext; | ||
29 | +import org.thingsboard.server.gen.transport.TransportProtos; | ||
30 | +import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; | ||
31 | +import org.thingsboard.server.transport.tcp.TcpTransportContext; | ||
32 | + | ||
33 | +import java.util.UUID; | ||
34 | + | ||
35 | +/** | ||
36 | + * Created by ashvayka on 19.01.17. | ||
37 | + */ | ||
38 | +@Slf4j | ||
39 | +public class TcpGatewayDeviceSessionCtx extends TcpDeviceWareSessionContext implements SessionMsgListener { | ||
40 | + | ||
41 | + private final TcpGatewaySessionHandler parent; | ||
42 | + private final TransportService transportService; | ||
43 | + | ||
44 | + public TcpGatewayDeviceSessionCtx(TcpTransportContext context, TcpGatewaySessionHandler parent, TransportDeviceInfo deviceInfo, | ||
45 | + DeviceProfile deviceProfile, TransportService transportService) { | ||
46 | + super(UUID.randomUUID(),context); | ||
47 | + this.parent = parent; | ||
48 | + setSessionInfo(SessionInfoProto.newBuilder() | ||
49 | + .setNodeId(parent.getNodeId()) | ||
50 | + .setSessionIdMSB(sessionId.getMostSignificantBits()) | ||
51 | + .setSessionIdLSB(sessionId.getLeastSignificantBits()) | ||
52 | + .setDeviceIdMSB(deviceInfo.getDeviceId().getId().getMostSignificantBits()) | ||
53 | + .setDeviceIdLSB(deviceInfo.getDeviceId().getId().getLeastSignificantBits()) | ||
54 | + .setTenantIdMSB(deviceInfo.getTenantId().getId().getMostSignificantBits()) | ||
55 | + .setTenantIdLSB(deviceInfo.getTenantId().getId().getLeastSignificantBits()) | ||
56 | + .setCustomerIdMSB(deviceInfo.getCustomerId().getId().getMostSignificantBits()) | ||
57 | + .setCustomerIdLSB(deviceInfo.getCustomerId().getId().getLeastSignificantBits()) | ||
58 | + .setDeviceName(deviceInfo.getDeviceName()) | ||
59 | + .setDeviceType(deviceInfo.getDeviceType()) | ||
60 | + .setGwSessionIdMSB(parent.getSessionId().getMostSignificantBits()) | ||
61 | + .setGwSessionIdLSB(parent.getSessionId().getLeastSignificantBits()) | ||
62 | + .setDeviceProfileIdMSB(deviceInfo.getDeviceProfileId().getId().getMostSignificantBits()) | ||
63 | + .setDeviceProfileIdLSB(deviceInfo.getDeviceProfileId().getId().getLeastSignificantBits()) | ||
64 | + .build()); | ||
65 | + setDeviceInfo(deviceInfo); | ||
66 | + setConnected(true); | ||
67 | + setDeviceProfile(deviceProfile); | ||
68 | + this.transportService = transportService; | ||
69 | + } | ||
70 | + | ||
71 | + @Override | ||
72 | + public UUID getSessionId() { | ||
73 | + return sessionId; | ||
74 | + } | ||
75 | + | ||
76 | + @Override | ||
77 | + public int nextMsgId() { | ||
78 | + return parent.nextMsgId(); | ||
79 | + } | ||
80 | + | ||
81 | + @Override | ||
82 | + 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 | + } | ||
88 | + } | ||
89 | + | ||
90 | + @Override | ||
91 | + public void onAttributeUpdate(UUID sessionId, TransportProtos.AttributeUpdateNotificationMsg notification) { | ||
92 | + 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 | + } | ||
99 | + | ||
100 | + @Override | ||
101 | + public void onToDeviceRpcRequest(UUID sessionId, TransportProtos.ToDeviceRpcRequestMsg request) { | ||
102 | + log.error("【{}】下发RPC命令【{}】给网关子设备", sessionId,request.getParams()); | ||
103 | + try { | ||
104 | + parent.getPayloadAdaptor().convertToPublish(this, request).ifPresent( | ||
105 | + payload -> { | ||
106 | + ChannelFuture channelFuture = parent.pushDeviceMsg(payload); | ||
107 | + if (request.getPersisted()) { | ||
108 | + channelFuture.addListener(result -> { | ||
109 | + if (result.cause() == null) { | ||
110 | + transportService.process(getSessionInfo(), request, RpcStatus.SENT, TransportServiceCallback.EMPTY); | ||
111 | + } | ||
112 | + }); | ||
113 | + } | ||
114 | + } | ||
115 | + ); | ||
116 | + } catch (Exception e) { | ||
117 | + transportService.process(getSessionInfo(), | ||
118 | + TransportProtos.ToDeviceRpcResponseMsg.newBuilder() | ||
119 | + .setRequestId(request.getRequestId()).setError("Failed to convert device RPC command to MQTT msg").build(), TransportServiceCallback.EMPTY); | ||
120 | + log.trace("[{}] Failed to convert device attributes response to MQTT msg", sessionId, e); | ||
121 | + } | ||
122 | + } | ||
123 | + | ||
124 | + @Override | ||
125 | + public void onRemoteSessionCloseCommand(UUID sessionId, TransportProtos.SessionCloseNotificationProto sessionCloseNotification) { | ||
126 | + log.trace("[{}] Received the remote command to close the session: {}", sessionId, sessionCloseNotification.getMessage()); | ||
127 | + parent.deregisterSession(getDeviceInfo().getDeviceName()); | ||
128 | + } | ||
129 | + | ||
130 | + @Override | ||
131 | + public void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg toServerResponse) { | ||
132 | + // This feature is not supported in the TB IoT Gateway yet. | ||
133 | + } | ||
134 | + | ||
135 | + @Override | ||
136 | + public void onDeviceDeleted(DeviceId deviceId) { | ||
137 | + parent.onDeviceDeleted(this.getSessionInfo().getDeviceName()); | ||
138 | + } | ||
139 | + | ||
140 | + private boolean isAckExpected(MqttMessage message) { | ||
141 | + return message.fixedHeader().qosLevel().value() > 0; | ||
142 | + } | ||
143 | + | ||
144 | +} |
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.transport.tcp.session; | ||
17 | + | ||
18 | + | ||
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.SettableFuture; | ||
23 | +import com.google.gson.*; | ||
24 | +import com.google.protobuf.InvalidProtocolBufferException; | ||
25 | +import com.google.protobuf.ProtocolStringList; | ||
26 | +import io.netty.buffer.ByteBuf; | ||
27 | +import io.netty.buffer.Unpooled; | ||
28 | +import io.netty.channel.ChannelFuture; | ||
29 | +import io.netty.channel.ChannelHandlerContext; | ||
30 | +import io.netty.handler.codec.mqtt.MqttPublishMessage; | ||
31 | +import lombok.extern.slf4j.Slf4j; | ||
32 | +import org.springframework.util.CollectionUtils; | ||
33 | +import org.springframework.util.ConcurrentReferenceHashMap; | ||
34 | +import org.springframework.util.StringUtils; | ||
35 | +import org.thingsboard.server.common.data.id.DeviceId; | ||
36 | +import org.thingsboard.server.common.data.yunteng.enums.TcpDataTypeEnum; | ||
37 | +import org.thingsboard.server.common.transport.TransportService; | ||
38 | +import org.thingsboard.server.common.transport.TransportServiceCallback; | ||
39 | +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 | +import org.thingsboard.server.common.transport.auth.GetOrCreateDeviceFromGatewayResponse; | ||
43 | +import org.thingsboard.server.common.transport.auth.TransportDeviceInfo; | ||
44 | +import org.thingsboard.server.gen.transport.TransportApiProtos; | ||
45 | +import org.thingsboard.server.gen.transport.TransportProtos; | ||
46 | +import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg; | ||
47 | +import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; | ||
48 | +import org.thingsboard.server.transport.tcp.TcpTransportContext; | ||
49 | +import org.thingsboard.server.transport.tcp.adaptors.TcpTransportAdaptor; | ||
50 | +import org.thingsboard.server.transport.tcp.util.ByteUtils; | ||
51 | + | ||
52 | +import javax.annotation.Nullable; | ||
53 | +import java.io.UnsupportedEncodingException; | ||
54 | +import java.util.*; | ||
55 | +import java.util.concurrent.ConcurrentHashMap; | ||
56 | +import java.util.concurrent.ConcurrentMap; | ||
57 | +import java.util.concurrent.locks.Lock; | ||
58 | +import java.util.concurrent.locks.ReentrantLock; | ||
59 | + | ||
60 | +import static org.springframework.util.ConcurrentReferenceHashMap.ReferenceType; | ||
61 | +import static org.thingsboard.server.common.transport.service.DefaultTransportService.*; | ||
62 | + | ||
63 | +/** | ||
64 | + * Created by ashvayka on 19.01.17. | ||
65 | + */ | ||
66 | +@Slf4j | ||
67 | +public class TcpGatewaySessionHandler { | ||
68 | + | ||
69 | + private static final String DEFAULT_DEVICE_TYPE = "default"; | ||
70 | + private static final String CAN_T_PARSE_VALUE = "Can't parse value: "; | ||
71 | + private static final String DEVICE_PROPERTY = "device"; | ||
72 | + | ||
73 | + private final TcpTransportContext context; | ||
74 | + private final TransportService transportService; | ||
75 | + private final TransportDeviceInfo gateway; | ||
76 | + private final UUID sessionId; | ||
77 | + private final ConcurrentMap<String, Lock> deviceCreationLockMap; | ||
78 | + private final ConcurrentMap<String, TcpGatewayDeviceSessionCtx> devices; | ||
79 | + private final ConcurrentMap<String, ListenableFuture<TcpGatewayDeviceSessionCtx>> deviceFutures; | ||
80 | + private final ChannelHandlerContext channel; | ||
81 | + private final TcpDeviceSessionCtx deviceSessionCtx; | ||
82 | + | ||
83 | + public TcpGatewaySessionHandler(TcpDeviceSessionCtx deviceSessionCtx, UUID sessionId) { | ||
84 | + this.context = deviceSessionCtx.getContext(); | ||
85 | + this.transportService = context.getTransportService(); | ||
86 | + this.deviceSessionCtx = deviceSessionCtx; | ||
87 | + this.gateway = deviceSessionCtx.getDeviceInfo(); | ||
88 | + this.sessionId = sessionId; | ||
89 | + this.devices = new ConcurrentHashMap<>(); | ||
90 | + this.deviceFutures = new ConcurrentHashMap<>(); | ||
91 | + this.deviceCreationLockMap = createWeakMap(); | ||
92 | + this.channel = deviceSessionCtx.getChannel(); | ||
93 | + } | ||
94 | + | ||
95 | + ConcurrentReferenceHashMap<String, Lock> createWeakMap() { | ||
96 | + return new ConcurrentReferenceHashMap<>(16, ReferenceType.WEAK); | ||
97 | + } | ||
98 | + | ||
99 | + | ||
100 | + | ||
101 | + | ||
102 | + | ||
103 | + public void onDeviceTelemetry(TCPMessage tcpMessage) throws AdaptorException { | ||
104 | + Futures.addCallback(checkDeviceConnected(tcpMessage.getDeviceCode()), | ||
105 | + new FutureCallback<>() { | ||
106 | + @Override | ||
107 | + 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 | + } | ||
116 | + } | ||
117 | + | ||
118 | + @Override | ||
119 | + public void onFailure(Throwable t) { | ||
120 | + log.debug("[{}] Failed to process device telemetry command: {}", sessionId, tcpMessage.getDeviceCode(), t); | ||
121 | + } | ||
122 | + }, context.getExecutor()); | ||
123 | + } | ||
124 | + | ||
125 | + | ||
126 | + | ||
127 | + | ||
128 | + | ||
129 | + | ||
130 | + | ||
131 | + public void onGatewayDisconnect() { | ||
132 | + devices.forEach(this::deregisterSession); | ||
133 | + } | ||
134 | + | ||
135 | + public void onDeviceDeleted(String deviceName) { | ||
136 | + deregisterSession(deviceName); | ||
137 | + } | ||
138 | + | ||
139 | + public String getNodeId() { | ||
140 | + return context.getNodeId(); | ||
141 | + } | ||
142 | + | ||
143 | + public UUID getSessionId() { | ||
144 | + return sessionId; | ||
145 | + } | ||
146 | + | ||
147 | + public TcpTransportAdaptor getPayloadAdaptor() { | ||
148 | + return deviceSessionCtx.getPayloadAdaptor(); | ||
149 | + } | ||
150 | + | ||
151 | + void deregisterSession(String deviceName) { | ||
152 | + TcpGatewayDeviceSessionCtx deviceSessionCtx = devices.remove(deviceName); | ||
153 | + if (deviceSessionCtx != null) { | ||
154 | + deregisterSession(deviceName, deviceSessionCtx); | ||
155 | + } else { | ||
156 | + log.debug("[{}] Device [{}] was already removed from the gateway session", sessionId, deviceName); | ||
157 | + } | ||
158 | + } | ||
159 | + | ||
160 | + | ||
161 | + | ||
162 | + int nextMsgId() { | ||
163 | + return deviceSessionCtx.nextMsgId(); | ||
164 | + } | ||
165 | + | ||
166 | + private boolean isJsonPayloadType() { | ||
167 | + return true;//deviceSessionCtx.isJsonPayloadType(); | ||
168 | + } | ||
169 | + | ||
170 | + private void processOnConnect(MqttPublishMessage msg, String deviceName, String deviceType) { | ||
171 | + log.trace("[{}] onDeviceConnect: {}", sessionId, deviceName); | ||
172 | + Futures.addCallback(onDeviceConnect(deviceName, deviceType), new FutureCallback<TcpGatewayDeviceSessionCtx>() { | ||
173 | + @Override | ||
174 | + public void onSuccess(@Nullable TcpGatewayDeviceSessionCtx result) { | ||
175 | + ack(msg); | ||
176 | + log.trace("[{}] onDeviceConnectOk: {}", sessionId, deviceName); | ||
177 | + } | ||
178 | + | ||
179 | + @Override | ||
180 | + public void onFailure(Throwable t) { | ||
181 | + log.warn("[{}] Failed to process device connect command: {}", sessionId, deviceName, t); | ||
182 | + | ||
183 | + } | ||
184 | + }, context.getExecutor()); | ||
185 | + } | ||
186 | + | ||
187 | + private ListenableFuture<TcpGatewayDeviceSessionCtx> onDeviceConnect(String deviceCode, String deviceType) { | ||
188 | + TcpGatewayDeviceSessionCtx result = devices.get(deviceCode); | ||
189 | + if (result == null) { | ||
190 | + Lock deviceCreationLock = deviceCreationLockMap.computeIfAbsent(deviceCode, s -> new ReentrantLock()); | ||
191 | + deviceCreationLock.lock(); | ||
192 | + try { | ||
193 | + result = devices.get(deviceCode); | ||
194 | + if (result == null) { | ||
195 | + return getDeviceCreationFuture(deviceCode, deviceType); | ||
196 | + } else { | ||
197 | + return Futures.immediateFuture(result); | ||
198 | + } | ||
199 | + } finally { | ||
200 | + deviceCreationLock.unlock(); | ||
201 | + } | ||
202 | + } else { | ||
203 | + return Futures.immediateFuture(result); | ||
204 | + } | ||
205 | + } | ||
206 | + | ||
207 | + private ListenableFuture<TcpGatewayDeviceSessionCtx> getDeviceCreationFuture(String deviceName, String deviceType) { | ||
208 | + final SettableFuture<TcpGatewayDeviceSessionCtx> futureToSet = SettableFuture.create(); | ||
209 | + ListenableFuture<TcpGatewayDeviceSessionCtx> future = deviceFutures.putIfAbsent(deviceName, futureToSet); | ||
210 | + if (future != null) { | ||
211 | + return future; | ||
212 | + } | ||
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); | ||
236 | + } | ||
237 | + | ||
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 | + } | ||
250 | + } | ||
251 | + | ||
252 | + private int getMsgId(MqttPublishMessage mqttMsg) { | ||
253 | + return mqttMsg.variableHeader().packetId(); | ||
254 | + } | ||
255 | + | ||
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 | + | ||
272 | + private void processOnDisconnect(MqttPublishMessage msg, String deviceName) { | ||
273 | + deregisterSession(deviceName); | ||
274 | + ack(msg); | ||
275 | + } | ||
276 | + | ||
277 | + | ||
278 | + | ||
279 | + | ||
280 | + private void processPostTelemetryMsg(TcpGatewayDeviceSessionCtx deviceCtx, TransportProtos.PostTelemetryMsg postTelemetryMsg, String deviceName, String msgId) { | ||
281 | + transportService.process(deviceCtx.getSessionInfo(), postTelemetryMsg, getPubAckCallback(channel, deviceName, msgId, postTelemetryMsg)); | ||
282 | + } | ||
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 | + | ||
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); | ||
340 | + } | ||
341 | + | ||
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 | + } | ||
351 | + } | ||
352 | + | ||
353 | + | ||
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 | + } | ||
380 | + } | ||
381 | + | ||
382 | + | ||
383 | + public void onDeviceRpcResponse(MqttPublishMessage mqttMsg) throws AdaptorException { | ||
384 | + int msgId = getMsgId(mqttMsg); | ||
385 | + ByteBuf payload = mqttMsg.payload(); | ||
386 | + JsonElement json = null;// JsonMqttAdaptor.validateJsonPayload(sessionId, payload); | ||
387 | + if (json.isJsonObject()) { | ||
388 | + JsonObject jsonObj = json.getAsJsonObject(); | ||
389 | + String deviceName = jsonObj.get(DEVICE_PROPERTY).getAsString(); | ||
390 | + Futures.addCallback(checkDeviceConnected(deviceName), | ||
391 | + new FutureCallback<TcpGatewayDeviceSessionCtx>() { | ||
392 | + @Override | ||
393 | + public void onSuccess(@Nullable TcpGatewayDeviceSessionCtx deviceCtx) { | ||
394 | + Integer requestId = jsonObj.get("id").getAsInt(); | ||
395 | + String data = jsonObj.get("data").toString(); | ||
396 | + TransportProtos.ToDeviceRpcResponseMsg rpcResponseMsg = TransportProtos.ToDeviceRpcResponseMsg.newBuilder() | ||
397 | + .setRequestId(requestId).setPayload(data).build(); | ||
398 | + processRpcResponseMsg(deviceCtx, rpcResponseMsg, deviceName, msgId); | ||
399 | + } | ||
400 | + | ||
401 | + @Override | ||
402 | + public void onFailure(Throwable t) { | ||
403 | + log.debug("[{}] Failed to process device Rpc response command: {}", sessionId, deviceName, t); | ||
404 | + } | ||
405 | + }, context.getExecutor()); | ||
406 | + } else { | ||
407 | + throw new JsonSyntaxException(CAN_T_PARSE_VALUE + json); | ||
408 | + } | ||
409 | + } | ||
410 | + | ||
411 | + | ||
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()); | ||
431 | + } | ||
432 | + | ||
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 | + | ||
445 | + private ListenableFuture<TcpGatewayDeviceSessionCtx> checkDeviceConnected(String deviceCode) { | ||
446 | + TcpGatewayDeviceSessionCtx ctx = devices.get(deviceCode); | ||
447 | + if (ctx == null) { | ||
448 | + log.debug("[{}] Missing device [{}] for the gateway session", sessionId, deviceCode); | ||
449 | + return onDeviceConnect(deviceCode, DEFAULT_DEVICE_TYPE); | ||
450 | + } else { | ||
451 | + return Futures.immediateFuture(ctx); | ||
452 | + } | ||
453 | + } | ||
454 | + | ||
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 | + | ||
479 | + private void deregisterSession(String deviceName, TcpGatewayDeviceSessionCtx deviceSessionCtx) { | ||
480 | + transportService.deregisterSession(deviceSessionCtx.getSessionInfo()); | ||
481 | + transportService.process(deviceSessionCtx.getSessionInfo(), SESSION_EVENT_MSG_CLOSED, null); | ||
482 | + log.debug("[{}] Removed device [{}] from the gateway session", sessionId, deviceName); | ||
483 | + } | ||
484 | + | ||
485 | + private <T> TransportServiceCallback<Void> getPubAckCallback(final ChannelHandlerContext ctx, final String deviceName, final String msgId, final T msg) { | ||
486 | + return new TransportServiceCallback<Void>() { | ||
487 | + @Override | ||
488 | + public void onSuccess(Void dummy) { | ||
489 | + log.trace("[{}][{}] Published msg: {}", sessionId, deviceName, msg); | ||
490 | + if(!StringUtils.isEmpty(msgId)){ | ||
491 | + pushDeviceMsg(new TCPMessage(msgId)); | ||
492 | + } | ||
493 | + } | ||
494 | + | ||
495 | + @Override | ||
496 | + public void onError(Throwable e) { | ||
497 | + log.trace("[{}] Failed to publish msg: {} for device: {}", sessionId, msg, deviceName, e); | ||
498 | + ctx.close(); | ||
499 | + } | ||
500 | + }; | ||
501 | + } | ||
502 | + /** | ||
503 | + * 往设备推送消息 | ||
504 | + * @param tcp | ||
505 | + * @return | ||
506 | + */ | ||
507 | + ChannelFuture pushDeviceMsg(TCPMessage tcp) { | ||
508 | + 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); | ||
519 | + ByteBuf payload = Unpooled.copiedBuffer(payloadInBytes); | ||
520 | + | ||
521 | + return channel.writeAndFlush(payload); | ||
522 | + } catch (UnsupportedEncodingException e) { | ||
523 | + log.error(e.getMessage(),e); | ||
524 | + throw new RuntimeException(e); | ||
525 | + } | ||
526 | + } | ||
527 | + private void ack(MqttPublishMessage msg) { | ||
528 | + int msgId = getMsgId(msg); | ||
529 | + if (msgId > 0) { | ||
530 | + channel.writeAndFlush(msg); | ||
531 | + } | ||
532 | + } | ||
533 | +} | ||
534 | + |
@@ -215,6 +215,12 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D | @@ -215,6 +215,12 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D | ||
215 | return doCreateDefaultDeviceProfile(tenantId, "default", true); | 215 | return doCreateDefaultDeviceProfile(tenantId, "default", true); |
216 | } | 216 | } |
217 | 217 | ||
218 | + @Override | ||
219 | + public DeviceProfile createDeviceProfile(TenantId tenantId, String name) { | ||
220 | + log.trace("Executing createDeviceProfile tenantId [{}]", tenantId); | ||
221 | + return doCreateDefaultDeviceProfile(tenantId, name, false); | ||
222 | + } | ||
223 | + | ||
218 | private DeviceProfile doCreateDefaultDeviceProfile(TenantId tenantId, String profileName, boolean defaultProfile) { | 224 | private DeviceProfile doCreateDefaultDeviceProfile(TenantId tenantId, String profileName, boolean defaultProfile) { |
219 | validateId(tenantId, INCORRECT_TENANT_ID + tenantId); | 225 | validateId(tenantId, INCORRECT_TENANT_ID + tenantId); |
220 | DeviceProfile deviceProfile = new DeviceProfile(); | 226 | DeviceProfile deviceProfile = new DeviceProfile(); |
@@ -140,8 +140,16 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe | @@ -140,8 +140,16 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe | ||
140 | 140 | ||
141 | //Thingskit function | 141 | //Thingskit function |
142 | DeviceProfile deviceProfile = deviceProfileService.createDefaultDeviceProfile(savedTenant.getId()); | 142 | DeviceProfile deviceProfile = deviceProfileService.createDefaultDeviceProfile(savedTenant.getId()); |
143 | - DeviceProfileDTO profileDTO = new DeviceProfileDTO(deviceProfile.getName(),deviceProfile.getTenantId(),deviceProfile.getId(), DeviceTypeEnum.DIRECT_CONNECTION); | 143 | + DeviceProfileDTO profileDTO = new DeviceProfileDTO(deviceProfile.getName(),deviceProfile.getTenantId(),deviceProfile.getId(), DeviceTypeEnum.SENSOR); |
144 | ytDeviceProfileService.insertOrUpdate(profileDTO); | 144 | ytDeviceProfileService.insertOrUpdate(profileDTO); |
145 | + DeviceProfile gatewayProfile = deviceProfileService.createDeviceProfile(savedTenant.getId(),"默认MQTT网关设备"); | ||
146 | + DeviceProfileDTO gatewayDTO = new DeviceProfileDTO(gatewayProfile.getName(),gatewayProfile.getTenantId(),gatewayProfile.getId(), DeviceTypeEnum.GATEWAY); | ||
147 | + ytDeviceProfileService.insertOrUpdate(gatewayDTO); | ||
148 | + DeviceProfile directProfile = deviceProfileService.createDeviceProfile(savedTenant.getId(),"默认MQTT直连设备"); | ||
149 | + DeviceProfileDTO directDTO = new DeviceProfileDTO(directProfile.getName(),directProfile.getTenantId(),directProfile.getId(), DeviceTypeEnum.DIRECT_CONNECTION); | ||
150 | + ytDeviceProfileService.insertOrUpdate(directDTO); | ||
151 | + | ||
152 | + | ||
145 | apiUsageStateService.createDefaultApiUsageState(savedTenant.getId(), null); | 153 | apiUsageStateService.createDefaultApiUsageState(savedTenant.getId(), null); |
146 | 154 | ||
147 | } | 155 | } |
@@ -23,6 +23,7 @@ public class YtDevice extends TenantBaseEntity { | @@ -23,6 +23,7 @@ public class YtDevice extends TenantBaseEntity { | ||
23 | private String gatewayId; | 23 | private String gatewayId; |
24 | private String brand; | 24 | private String brand; |
25 | private String label; | 25 | private String label; |
26 | + private String code; | ||
26 | @TableField(typeHandler = EnumTypeHandler.class) | 27 | @TableField(typeHandler = EnumTypeHandler.class) |
27 | private DeviceTypeEnum deviceType; | 28 | private DeviceTypeEnum deviceType; |
28 | private String sn; | 29 | private String sn; |
@@ -169,15 +169,7 @@ public class YtDeviceProfileServiceImpl | @@ -169,15 +169,7 @@ public class YtDeviceProfileServiceImpl | ||
169 | 169 | ||
170 | @Override | 170 | @Override |
171 | public List<DeviceProfileDTO> findDeviceProfile(String tenantId, String scriptId) { | 171 | public List<DeviceProfileDTO> findDeviceProfile(String tenantId, String scriptId) { |
172 | - LambdaQueryWrapper<YtDeviceProfileEntity> queryWrapper = | ||
173 | - new QueryWrapper<YtDeviceProfileEntity>() | ||
174 | - .lambda() | ||
175 | - .eq(YtDeviceProfileEntity::getTenantId, tenantId) | ||
176 | - .eq(StringUtils.isNotEmpty(scriptId), YtDeviceProfileEntity::getScriptId, scriptId); | ||
177 | - List<DeviceProfileDTO> results = | ||
178 | - baseMapper.selectList(queryWrapper).stream() | ||
179 | - .map(item -> item.getDTO(DeviceProfileDTO.class)) | ||
180 | - .collect(Collectors.toList()); | 172 | + List<DeviceProfileDTO> results = baseMapper.profileByScriptId(tenantId,scriptId); |
181 | return results; | 173 | return results; |
182 | } | 174 | } |
183 | } | 175 | } |
@@ -78,7 +78,13 @@ public class YtDeviceScriptServiceImpl extends AbstractBaseService<YtDeviceScrip | @@ -78,7 +78,13 @@ public class YtDeviceScriptServiceImpl extends AbstractBaseService<YtDeviceScrip | ||
78 | 78 | ||
79 | @Override | 79 | @Override |
80 | public String getScriptText(String tenantId, String scriptId) { | 80 | public String getScriptText(String tenantId, String scriptId) { |
81 | - return null; | 81 | + LambdaQueryWrapper<YtDeviceScriptEntity> queryWrapper = |
82 | + new QueryWrapper<YtDeviceScriptEntity>() | ||
83 | + .lambda() | ||
84 | + .eq(YtDeviceScriptEntity::getTenantId, tenantId) | ||
85 | + .eq(YtDeviceScriptEntity::getId, scriptId); | ||
86 | + YtDeviceScriptEntity result = baseMapper.selectOne(queryWrapper); | ||
87 | + return result ==null? null : result.getConvertJs(); | ||
82 | } | 88 | } |
83 | 89 | ||
84 | @Override | 90 | @Override |
@@ -262,12 +262,7 @@ public class YtDeviceServiceImpl extends AbstractBaseService<DeviceMapper, YtDev | @@ -262,12 +262,7 @@ public class YtDeviceServiceImpl extends AbstractBaseService<DeviceMapper, YtDev | ||
262 | if (StringUtils.isEmpty(tenantId) || StringUtils.isEmpty(deviceId)) { | 262 | if (StringUtils.isEmpty(tenantId) || StringUtils.isEmpty(deviceId)) { |
263 | throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage()); | 263 | throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage()); |
264 | } | 264 | } |
265 | - return baseMapper | ||
266 | - .selectOne( | ||
267 | - new LambdaQueryWrapper<YtDevice>() | ||
268 | - .eq(YtDevice::getTenantId, tenantId) | ||
269 | - .eq(YtDevice::getId, deviceId)) | ||
270 | - .getDTO(DeviceDTO.class); | 265 | + return baseMapper.selectDetail(tenantId,deviceId); |
271 | } | 266 | } |
272 | 267 | ||
273 | @Override | 268 | @Override |
@@ -490,6 +485,12 @@ public class YtDeviceServiceImpl extends AbstractBaseService<DeviceMapper, YtDev | @@ -490,6 +485,12 @@ public class YtDeviceServiceImpl extends AbstractBaseService<DeviceMapper, YtDev | ||
490 | return result; | 485 | return result; |
491 | } | 486 | } |
492 | 487 | ||
488 | + | ||
489 | + @Override | ||
490 | + public DeviceDTO findSlaveDevice(String tenantId, String masterId, String deviceCode) { | ||
491 | + return baseMapper.slaveDevice(tenantId,masterId,deviceCode); | ||
492 | + } | ||
493 | + | ||
493 | @Override | 494 | @Override |
494 | public List<String> findDeviceKeys( | 495 | public List<String> findDeviceKeys( |
495 | String tenantId, String customerId, String organizationId, List<String> deviceIds) { | 496 | String tenantId, String customerId, String organizationId, List<String> deviceIds) { |
@@ -108,7 +108,14 @@ public interface DeviceMapper extends BaseMapper<YtDevice> { | @@ -108,7 +108,14 @@ public interface DeviceMapper extends BaseMapper<YtDevice> { | ||
108 | List<SelectItemDTO> slaveDevices(@Param("customerId") String customerId, @Param("tenantId") String tenantId | 108 | List<SelectItemDTO> slaveDevices(@Param("customerId") String customerId, @Param("tenantId") String tenantId |
109 | , @Param("organizationIds") List<String> organizationIds, @Param("masterId") String masterId); | 109 | , @Param("organizationIds") List<String> organizationIds, @Param("masterId") String masterId); |
110 | 110 | ||
111 | - | 111 | + /** |
112 | + * TCP协议传输时,获取网关设备的从设备 | ||
113 | + * @param tenantId 租户ID | ||
114 | + * @param masterId 网关设备的TB_ID | ||
115 | + * @param code 网关子设备的标识符,例如:485协议的从设备地址码 | ||
116 | + * @return | ||
117 | + */ | ||
118 | + DeviceDTO slaveDevice(@Param("tenantId") String tenantId, @Param("masterId") String masterId, @Param("code") String code); | ||
112 | /** | 119 | /** |
113 | * 设备遥测数据指标名称 | 120 | * 设备遥测数据指标名称 |
114 | * | 121 | * |
@@ -22,4 +22,6 @@ public interface YtDeviceProfileMapper extends BaseMapper<YtDeviceProfileEntity> | @@ -22,4 +22,6 @@ public interface YtDeviceProfileMapper extends BaseMapper<YtDeviceProfileEntity> | ||
22 | 22 | ||
23 | IPage<DeviceProfileDTO> getProfilePage(IPage<?> page, @Param("tenantId") String tenantId, @Param("profileName") String profileName, @Param("transportType") String transportType); | 23 | IPage<DeviceProfileDTO> getProfilePage(IPage<?> page, @Param("tenantId") String tenantId, @Param("profileName") String profileName, @Param("transportType") String transportType); |
24 | 24 | ||
25 | + | ||
26 | + List<DeviceProfileDTO> profileByScriptId( @Param("tenantId") String tenantId, @Param("scriptId") String scriptId); | ||
25 | } | 27 | } |
@@ -122,6 +122,16 @@ public interface YtDeviceService extends BaseService<YtDevice> { | @@ -122,6 +122,16 @@ public interface YtDeviceService extends BaseService<YtDevice> { | ||
122 | */ | 122 | */ |
123 | List<SelectItemDTO> findSlaveDevices(String masterId,String tenantId,String customerId, String organizationId); | 123 | List<SelectItemDTO> findSlaveDevices(String masterId,String tenantId,String customerId, String organizationId); |
124 | 124 | ||
125 | + | ||
126 | + /** | ||
127 | + * TCP协议传输时,获取网关设备的从设备 | ||
128 | + * @param tenantId 租户ID | ||
129 | + * @param masterId 网关设备的TB_ID | ||
130 | + * @param deviceCode 网关子设备的标识符,例如:485协议的从设备地址码 | ||
131 | + * @return | ||
132 | + */ | ||
133 | + DeviceDTO findSlaveDevice(String tenantId,String masterId,String deviceCode); | ||
134 | + | ||
125 | /** | 135 | /** |
126 | * 设备遥测数据指标名称 | 136 | * 设备遥测数据指标名称 |
127 | * @param tenantId 租户ID | 137 | * @param tenantId 租户ID |
@@ -17,6 +17,7 @@ | @@ -17,6 +17,7 @@ | ||
17 | <result property="deviceType" column="device_type" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/> | 17 | <result property="deviceType" column="device_type" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/> |
18 | <result property="brand" column="brand" /> | 18 | <result property="brand" column="brand" /> |
19 | <result property="sn" column="sn"/> | 19 | <result property="sn" column="sn"/> |
20 | + <result property="code" column="code"/> | ||
20 | <result property="tenantId" column="tenant_id"/> | 21 | <result property="tenantId" column="tenant_id"/> |
21 | <result property="tbDeviceId" column="tb_device_id"/> | 22 | <result property="tbDeviceId" column="tb_device_id"/> |
22 | <result property="label" column="label"/> | 23 | <result property="label" column="label"/> |
@@ -60,9 +61,7 @@ | @@ -60,9 +61,7 @@ | ||
60 | </resultMap> | 61 | </resultMap> |
61 | 62 | ||
62 | <sql id="basicColumns"> | 63 | <sql id="basicColumns"> |
63 | - ifd | ||
64 | - . | ||
65 | - id | 64 | + ifd.id |
66 | ,ifd.sn,ifd.brand,ifd.name,ifd.device_info,ifd.profile_id,ifd.active_time,ifd.tenant_id,ifd.description | 65 | ,ifd.sn,ifd.brand,ifd.name,ifd.device_info,ifd.profile_id,ifd.active_time,ifd.tenant_id,ifd.description |
67 | ,ifd.tb_device_id,ifd.label,ifd.last_connect_time,ifd.device_type,ifd.device_state,ifd.create_time,ifd.update_time,ifd.creator, | 66 | ,ifd.tb_device_id,ifd.label,ifd.last_connect_time,ifd.device_type,ifd.device_state,ifd.create_time,ifd.update_time,ifd.creator, |
68 | ifd.updater,ifd.organization_id,ifd.alarm_status | 67 | ifd.updater,ifd.organization_id,ifd.alarm_status |
@@ -377,6 +376,17 @@ | @@ -377,6 +376,17 @@ | ||
377 | </where> | 376 | </where> |
378 | </select> | 377 | </select> |
379 | 378 | ||
379 | + <select id="slaveDevice" resultMap="deviceMap"> | ||
380 | + SELECT | ||
381 | + <include refid="basicColumns"/> | ||
382 | + FROM iotfs_device ifd | ||
383 | + <where> | ||
384 | + ifd.tenant_id = #{tenantId} | ||
385 | + AND ifd.gateway_id = #{masterId} | ||
386 | + AND ifd.code = #{code} | ||
387 | + </where> | ||
388 | + </select> | ||
389 | + | ||
380 | <select id="findDeviceKeys" resultType="string"> | 390 | <select id="findDeviceKeys" resultType="string"> |
381 | SELECT | 391 | SELECT |
382 | DISTINCT base.key as keyName | 392 | DISTINCT base.key as keyName |
@@ -59,7 +59,19 @@ | @@ -59,7 +59,19 @@ | ||
59 | AND iot.tenant_id = #{tenantId} | 59 | AND iot.tenant_id = #{tenantId} |
60 | </if> | 60 | </if> |
61 | <if test="id !=null and id !=''"> | 61 | <if test="id !=null and id !=''"> |
62 | - AND iot.id = #{id} | 62 | + AND (iot.id = #{id} OR iot.tb_profile_id = #{id}) |
63 | + </if> | ||
64 | + </where> | ||
65 | + </select> | ||
66 | + <select id="profileByScriptId" resultMap="detail"> | ||
67 | + SELECT | ||
68 | + <include refid="basicColumns"/> | ||
69 | + FROM device_profile base | ||
70 | + LEFT JOIN iotfs_device_profile iot ON iot.tb_profile_id = base.id::TEXT | ||
71 | + <where> | ||
72 | + iot.tenant_id = #{tenantId} | ||
73 | + <if test="scriptId !=null and scriptId !=''"> | ||
74 | + AND iot.script_id = #{scriptId} | ||
63 | </if> | 75 | </if> |
64 | </where> | 76 | </where> |
65 | </select> | 77 | </select> |