Commit 854307fd780068e429f601f1853ec1bd0fd1ebcb
Merge branch 'master' of github.com:thingsboard/thingsboard
Showing
86 changed files
with
1778 additions
and
581 deletions
@@ -197,3 +197,17 @@ $$; | @@ -197,3 +197,17 @@ $$; | ||
197 | ALTER TABLE api_usage_state | 197 | ALTER TABLE api_usage_state |
198 | ADD COLUMN IF NOT EXISTS alarm_exec VARCHAR(32); | 198 | ADD COLUMN IF NOT EXISTS alarm_exec VARCHAR(32); |
199 | UPDATE api_usage_state SET alarm_exec = 'ENABLED' WHERE alarm_exec IS NULL; | 199 | UPDATE api_usage_state SET alarm_exec = 'ENABLED' WHERE alarm_exec IS NULL; |
200 | + | ||
201 | +CREATE TABLE IF NOT EXISTS rpc ( | ||
202 | + id uuid NOT NULL CONSTRAINT rpc_pkey PRIMARY KEY, | ||
203 | + created_time bigint NOT NULL, | ||
204 | + tenant_id uuid NOT NULL, | ||
205 | + device_id uuid NOT NULL, | ||
206 | + expiration_time bigint NOT NULL, | ||
207 | + request varchar(10000000) NOT NULL, | ||
208 | + response varchar(10000000), | ||
209 | + status varchar(255) NOT NULL | ||
210 | +); | ||
211 | + | ||
212 | +CREATE INDEX IF NOT EXISTS idx_rpc_tenant_id_device_id ON rpc(tenant_id, device_id); | ||
213 | + |
@@ -65,6 +65,7 @@ import org.thingsboard.server.dao.relation.RelationService; | @@ -65,6 +65,7 @@ import org.thingsboard.server.dao.relation.RelationService; | ||
65 | import org.thingsboard.server.dao.resource.ResourceService; | 65 | import org.thingsboard.server.dao.resource.ResourceService; |
66 | import org.thingsboard.server.dao.rule.RuleChainService; | 66 | import org.thingsboard.server.dao.rule.RuleChainService; |
67 | import org.thingsboard.server.dao.rule.RuleNodeStateService; | 67 | import org.thingsboard.server.dao.rule.RuleNodeStateService; |
68 | +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; | ||
68 | import org.thingsboard.server.dao.tenant.TenantProfileService; | 69 | import org.thingsboard.server.dao.tenant.TenantProfileService; |
69 | import org.thingsboard.server.dao.tenant.TenantService; | 70 | import org.thingsboard.server.dao.tenant.TenantService; |
70 | import org.thingsboard.server.dao.timeseries.TimeseriesService; | 71 | import org.thingsboard.server.dao.timeseries.TimeseriesService; |
@@ -80,9 +81,9 @@ import org.thingsboard.server.service.executors.ExternalCallExecutorService; | @@ -80,9 +81,9 @@ import org.thingsboard.server.service.executors.ExternalCallExecutorService; | ||
80 | import org.thingsboard.server.service.executors.SharedEventLoopGroupService; | 81 | import org.thingsboard.server.service.executors.SharedEventLoopGroupService; |
81 | import org.thingsboard.server.service.mail.MailExecutorService; | 82 | import org.thingsboard.server.service.mail.MailExecutorService; |
82 | import org.thingsboard.server.service.profile.TbDeviceProfileCache; | 83 | import org.thingsboard.server.service.profile.TbDeviceProfileCache; |
83 | -import org.thingsboard.server.dao.tenant.TbTenantProfileCache; | ||
84 | import org.thingsboard.server.service.queue.TbClusterService; | 84 | import org.thingsboard.server.service.queue.TbClusterService; |
85 | import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService; | 85 | import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService; |
86 | +import org.thingsboard.server.service.rpc.TbRpcService; | ||
86 | import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService; | 87 | import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService; |
87 | import org.thingsboard.server.service.script.JsExecutorService; | 88 | import org.thingsboard.server.service.script.JsExecutorService; |
88 | import org.thingsboard.server.service.script.JsInvokeService; | 89 | import org.thingsboard.server.service.script.JsInvokeService; |
@@ -303,23 +304,33 @@ public class ActorSystemContext { | @@ -303,23 +304,33 @@ public class ActorSystemContext { | ||
303 | 304 | ||
304 | @Lazy | 305 | @Lazy |
305 | @Autowired(required = false) | 306 | @Autowired(required = false) |
306 | - @Getter private EdgeService edgeService; | 307 | + @Getter |
308 | + private EdgeService edgeService; | ||
307 | 309 | ||
308 | @Lazy | 310 | @Lazy |
309 | @Autowired(required = false) | 311 | @Autowired(required = false) |
310 | - @Getter private EdgeEventService edgeEventService; | 312 | + @Getter |
313 | + private EdgeEventService edgeEventService; | ||
311 | 314 | ||
312 | @Lazy | 315 | @Lazy |
313 | @Autowired(required = false) | 316 | @Autowired(required = false) |
314 | - @Getter private EdgeRpcService edgeRpcService; | 317 | + @Getter |
318 | + private EdgeRpcService edgeRpcService; | ||
315 | 319 | ||
316 | @Lazy | 320 | @Lazy |
317 | @Autowired(required = false) | 321 | @Autowired(required = false) |
318 | - @Getter private ResourceService resourceService; | 322 | + @Getter |
323 | + private ResourceService resourceService; | ||
319 | 324 | ||
320 | @Lazy | 325 | @Lazy |
321 | @Autowired(required = false) | 326 | @Autowired(required = false) |
322 | - @Getter private OtaPackageService otaPackageService; | 327 | + @Getter |
328 | + private OtaPackageService otaPackageService; | ||
329 | + | ||
330 | + @Lazy | ||
331 | + @Autowired(required = false) | ||
332 | + @Getter | ||
333 | + private TbRpcService tbRpcService; | ||
323 | 334 | ||
324 | @Value("${actors.session.max_concurrent_sessions_per_device:1}") | 335 | @Value("${actors.session.max_concurrent_sessions_per_device:1}") |
325 | @Getter | 336 | @Getter |
@@ -46,7 +46,7 @@ public class DeviceActor extends ContextAwareActor { | @@ -46,7 +46,7 @@ public class DeviceActor extends ContextAwareActor { | ||
46 | super.init(ctx); | 46 | super.init(ctx); |
47 | log.debug("[{}][{}] Starting device actor.", processor.tenantId, processor.deviceId); | 47 | log.debug("[{}][{}] Starting device actor.", processor.tenantId, processor.deviceId); |
48 | try { | 48 | try { |
49 | - processor.initSessionTimeout(ctx); | 49 | + processor.init(ctx); |
50 | log.debug("[{}][{}] Device actor started.", processor.tenantId, processor.deviceId); | 50 | log.debug("[{}][{}] Device actor started.", processor.tenantId, processor.deviceId); |
51 | } catch (Exception e) { | 51 | } catch (Exception e) { |
52 | log.warn("[{}][{}] Unknown failure", processor.tenantId, processor.deviceId, e); | 52 | log.warn("[{}][{}] Unknown failure", processor.tenantId, processor.deviceId, e); |
@@ -23,6 +23,7 @@ import com.google.common.util.concurrent.MoreExecutors; | @@ -23,6 +23,7 @@ import com.google.common.util.concurrent.MoreExecutors; | ||
23 | import com.google.protobuf.InvalidProtocolBufferException; | 23 | import com.google.protobuf.InvalidProtocolBufferException; |
24 | import lombok.extern.slf4j.Slf4j; | 24 | import lombok.extern.slf4j.Slf4j; |
25 | import org.apache.commons.collections.CollectionUtils; | 25 | import org.apache.commons.collections.CollectionUtils; |
26 | +import org.thingsboard.common.util.JacksonUtil; | ||
26 | import org.thingsboard.rule.engine.api.RpcError; | 27 | import org.thingsboard.rule.engine.api.RpcError; |
27 | import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; | 28 | import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; |
28 | import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg; | 29 | import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg; |
@@ -38,12 +39,17 @@ import org.thingsboard.server.common.data.edge.EdgeEventActionType; | @@ -38,12 +39,17 @@ import org.thingsboard.server.common.data.edge.EdgeEventActionType; | ||
38 | import org.thingsboard.server.common.data.edge.EdgeEventType; | 39 | import org.thingsboard.server.common.data.edge.EdgeEventType; |
39 | import org.thingsboard.server.common.data.id.DeviceId; | 40 | import org.thingsboard.server.common.data.id.DeviceId; |
40 | import org.thingsboard.server.common.data.id.EdgeId; | 41 | import org.thingsboard.server.common.data.id.EdgeId; |
42 | +import org.thingsboard.server.common.data.id.RpcId; | ||
41 | import org.thingsboard.server.common.data.id.TenantId; | 43 | import org.thingsboard.server.common.data.id.TenantId; |
42 | import org.thingsboard.server.common.data.kv.AttributeKey; | 44 | import org.thingsboard.server.common.data.kv.AttributeKey; |
43 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; | 45 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
44 | import org.thingsboard.server.common.data.kv.KvEntry; | 46 | import org.thingsboard.server.common.data.kv.KvEntry; |
47 | +import org.thingsboard.server.common.data.page.PageData; | ||
48 | +import org.thingsboard.server.common.data.page.PageLink; | ||
45 | import org.thingsboard.server.common.data.relation.EntityRelation; | 49 | import org.thingsboard.server.common.data.relation.EntityRelation; |
46 | import org.thingsboard.server.common.data.relation.RelationTypeGroup; | 50 | import org.thingsboard.server.common.data.relation.RelationTypeGroup; |
51 | +import org.thingsboard.server.common.data.rpc.Rpc; | ||
52 | +import org.thingsboard.server.common.data.rpc.RpcStatus; | ||
47 | import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; | 53 | import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; |
48 | import org.thingsboard.server.common.data.security.DeviceCredentials; | 54 | import org.thingsboard.server.common.data.security.DeviceCredentials; |
49 | import org.thingsboard.server.common.data.security.DeviceCredentialsType; | 55 | import org.thingsboard.server.common.data.security.DeviceCredentialsType; |
@@ -52,8 +58,8 @@ import org.thingsboard.server.common.msg.TbMsgMetaData; | @@ -52,8 +58,8 @@ import org.thingsboard.server.common.msg.TbMsgMetaData; | ||
52 | import org.thingsboard.server.common.msg.queue.TbCallback; | 58 | import org.thingsboard.server.common.msg.queue.TbCallback; |
53 | import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; | 59 | import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; |
54 | import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; | 60 | import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; |
55 | -import org.thingsboard.server.gen.transport.TransportProtos; | ||
56 | import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; | 61 | import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; |
62 | +import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; | ||
57 | import org.thingsboard.server.gen.transport.TransportProtos.DeviceSessionsCacheEntry; | 63 | import org.thingsboard.server.gen.transport.TransportProtos.DeviceSessionsCacheEntry; |
58 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; | 64 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; |
59 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; | 65 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; |
@@ -68,10 +74,12 @@ import org.thingsboard.server.gen.transport.TransportProtos.SessionType; | @@ -68,10 +74,12 @@ import org.thingsboard.server.gen.transport.TransportProtos.SessionType; | ||
68 | import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToAttributeUpdatesMsg; | 74 | import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToAttributeUpdatesMsg; |
69 | import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToRPCMsg; | 75 | import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToRPCMsg; |
70 | import org.thingsboard.server.gen.transport.TransportProtos.SubscriptionInfoProto; | 76 | import org.thingsboard.server.gen.transport.TransportProtos.SubscriptionInfoProto; |
77 | +import org.thingsboard.server.gen.transport.TransportProtos.ToDevicePersistedRpcResponseMsg; | ||
71 | import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg; | 78 | import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg; |
72 | import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcResponseMsg; | 79 | import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcResponseMsg; |
73 | import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg; | 80 | import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg; |
74 | import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; | 81 | import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
82 | +import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCredentialsProto; | ||
75 | import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; | 83 | import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; |
76 | import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; | 84 | import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; |
77 | import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; | 85 | import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; |
@@ -162,20 +170,19 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -162,20 +170,19 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
162 | 170 | ||
163 | void processRpcRequest(TbActorCtx context, ToDeviceRpcRequestActorMsg msg) { | 171 | void processRpcRequest(TbActorCtx context, ToDeviceRpcRequestActorMsg msg) { |
164 | ToDeviceRpcRequest request = msg.getMsg(); | 172 | ToDeviceRpcRequest request = msg.getMsg(); |
165 | - ToDeviceRpcRequestBody body = request.getBody(); | ||
166 | - ToDeviceRpcRequestMsg rpcRequest = ToDeviceRpcRequestMsg.newBuilder() | ||
167 | - .setRequestId(rpcSeq++) | ||
168 | - .setMethodName(body.getMethod()) | ||
169 | - .setParams(body.getParams()) | ||
170 | - .setExpirationTime(request.getExpirationTime()) | ||
171 | - .setRequestIdMSB(request.getId().getMostSignificantBits()) | ||
172 | - .setRequestIdLSB(request.getId().getLeastSignificantBits()) | ||
173 | - .build(); | 173 | + ToDeviceRpcRequestMsg rpcRequest = creteToDeviceRpcRequestMsg(request); |
174 | 174 | ||
175 | long timeout = request.getExpirationTime() - System.currentTimeMillis(); | 175 | long timeout = request.getExpirationTime() - System.currentTimeMillis(); |
176 | + boolean persisted = request.isPersisted(); | ||
177 | + | ||
176 | if (timeout <= 0) { | 178 | if (timeout <= 0) { |
177 | log.debug("[{}][{}] Ignoring message due to exp time reached, {}", deviceId, request.getId(), request.getExpirationTime()); | 179 | log.debug("[{}][{}] Ignoring message due to exp time reached, {}", deviceId, request.getId(), request.getExpirationTime()); |
180 | + if (persisted) { | ||
181 | + createRpc(request, RpcStatus.TIMEOUT); | ||
182 | + } | ||
178 | return; | 183 | return; |
184 | + } else if (persisted) { | ||
185 | + createRpc(request, RpcStatus.QUEUED); | ||
179 | } | 186 | } |
180 | 187 | ||
181 | boolean sent; | 188 | boolean sent; |
@@ -192,10 +199,16 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -192,10 +199,16 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
192 | syncSessionSet.add(key); | 199 | syncSessionSet.add(key); |
193 | } | 200 | } |
194 | }); | 201 | }); |
195 | - log.trace("46) Rpc syncSessionSet [{}] subscription after sent [{}]",syncSessionSet, rpcSubscriptions); | 202 | + log.trace("46) Rpc syncSessionSet [{}] subscription after sent [{}]", syncSessionSet, rpcSubscriptions); |
196 | syncSessionSet.forEach(rpcSubscriptions::remove); | 203 | syncSessionSet.forEach(rpcSubscriptions::remove); |
197 | } | 204 | } |
198 | 205 | ||
206 | + if (persisted && !(sent || request.isOneway())) { | ||
207 | + ObjectNode response = JacksonUtil.newObjectNode(); | ||
208 | + response.put("rpcId", request.getId().toString()); | ||
209 | + systemContext.getTbCoreDeviceRpcService().processRpcResponseFromDeviceActor(new FromDeviceRpcResponse(msg.getMsg().getId(), JacksonUtil.toString(response), null)); | ||
210 | + } | ||
211 | + | ||
199 | if (request.isOneway() && sent) { | 212 | if (request.isOneway() && sent) { |
200 | log.debug("[{}] Rpc command response sent [{}]!", deviceId, request.getId()); | 213 | log.debug("[{}] Rpc command response sent [{}]!", deviceId, request.getId()); |
201 | systemContext.getTbCoreDeviceRpcService().processRpcResponseFromDeviceActor(new FromDeviceRpcResponse(msg.getMsg().getId(), null, null)); | 214 | systemContext.getTbCoreDeviceRpcService().processRpcResponseFromDeviceActor(new FromDeviceRpcResponse(msg.getMsg().getId(), null, null)); |
@@ -209,6 +222,32 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -209,6 +222,32 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
209 | } | 222 | } |
210 | } | 223 | } |
211 | 224 | ||
225 | + private Rpc createRpc(ToDeviceRpcRequest request, RpcStatus status) { | ||
226 | + Rpc rpc = new Rpc(new RpcId(request.getId())); | ||
227 | + rpc.setCreatedTime(System.currentTimeMillis()); | ||
228 | + rpc.setTenantId(tenantId); | ||
229 | + rpc.setDeviceId(deviceId); | ||
230 | + rpc.setExpirationTime(request.getExpirationTime()); | ||
231 | + rpc.setRequest(JacksonUtil.valueToTree(request)); | ||
232 | + rpc.setStatus(status); | ||
233 | + systemContext.getTbRpcService().save(tenantId, rpc); | ||
234 | + return systemContext.getTbRpcService().save(tenantId, rpc); | ||
235 | + } | ||
236 | + | ||
237 | + private ToDeviceRpcRequestMsg creteToDeviceRpcRequestMsg(ToDeviceRpcRequest request) { | ||
238 | + ToDeviceRpcRequestBody body = request.getBody(); | ||
239 | + return ToDeviceRpcRequestMsg.newBuilder() | ||
240 | + .setRequestId(rpcSeq++) | ||
241 | + .setMethodName(body.getMethod()) | ||
242 | + .setParams(body.getParams()) | ||
243 | + .setExpirationTime(request.getExpirationTime()) | ||
244 | + .setRequestIdMSB(request.getId().getMostSignificantBits()) | ||
245 | + .setRequestIdLSB(request.getId().getLeastSignificantBits()) | ||
246 | + .setOneway(request.isOneway()) | ||
247 | + .setPersisted(request.isPersisted()) | ||
248 | + .build(); | ||
249 | + } | ||
250 | + | ||
212 | void processRpcResponsesFromEdge(TbActorCtx context, FromDeviceRpcResponseActorMsg responseMsg) { | 251 | void processRpcResponsesFromEdge(TbActorCtx context, FromDeviceRpcResponseActorMsg responseMsg) { |
213 | log.debug("[{}] Processing rpc command response from edge session", deviceId); | 252 | log.debug("[{}] Processing rpc command response from edge session", deviceId); |
214 | ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(responseMsg.getRequestId()); | 253 | ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(responseMsg.getRequestId()); |
@@ -230,6 +269,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -230,6 +269,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
230 | ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(msg.getId()); | 269 | ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(msg.getId()); |
231 | if (requestMd != null) { | 270 | if (requestMd != null) { |
232 | log.debug("[{}] RPC request [{}] timeout detected!", deviceId, msg.getId()); | 271 | log.debug("[{}] RPC request [{}] timeout detected!", deviceId, msg.getId()); |
272 | + systemContext.getTbRpcService().save(tenantId, new RpcId(requestMd.getMsg().getMsg().getId()), RpcStatus.TIMEOUT, null); | ||
233 | systemContext.getTbCoreDeviceRpcService().processRpcResponseFromDeviceActor(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(), | 273 | systemContext.getTbCoreDeviceRpcService().processRpcResponseFromDeviceActor(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(), |
234 | null, requestMd.isSent() ? RpcError.TIMEOUT : RpcError.NO_ACTIVE_CONNECTION)); | 274 | null, requestMd.isSent() ? RpcError.TIMEOUT : RpcError.NO_ACTIVE_CONNECTION)); |
235 | } | 275 | } |
@@ -271,7 +311,10 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -271,7 +311,10 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
271 | .setExpirationTime(request.getExpirationTime()) | 311 | .setExpirationTime(request.getExpirationTime()) |
272 | .setRequestIdMSB(request.getId().getMostSignificantBits()) | 312 | .setRequestIdMSB(request.getId().getMostSignificantBits()) |
273 | .setRequestIdLSB(request.getId().getLeastSignificantBits()) | 313 | .setRequestIdLSB(request.getId().getLeastSignificantBits()) |
314 | + .setOneway(request.isOneway()) | ||
315 | + .setPersisted(request.isPersisted()) | ||
274 | .build(); | 316 | .build(); |
317 | + | ||
275 | sendToTransport(rpcRequest, sessionId, nodeId); | 318 | sendToTransport(rpcRequest, sessionId, nodeId); |
276 | }; | 319 | }; |
277 | } | 320 | } |
@@ -279,31 +322,39 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -279,31 +322,39 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
279 | void process(TbActorCtx context, TransportToDeviceActorMsgWrapper wrapper) { | 322 | void process(TbActorCtx context, TransportToDeviceActorMsgWrapper wrapper) { |
280 | TransportToDeviceActorMsg msg = wrapper.getMsg(); | 323 | TransportToDeviceActorMsg msg = wrapper.getMsg(); |
281 | TbCallback callback = wrapper.getCallback(); | 324 | TbCallback callback = wrapper.getCallback(); |
325 | + var sessionInfo = msg.getSessionInfo(); | ||
326 | + | ||
282 | if (msg.hasSessionEvent()) { | 327 | if (msg.hasSessionEvent()) { |
283 | - processSessionStateMsgs(msg.getSessionInfo(), msg.getSessionEvent()); | 328 | + processSessionStateMsgs(sessionInfo, msg.getSessionEvent()); |
284 | } | 329 | } |
285 | if (msg.hasSubscribeToAttributes()) { | 330 | if (msg.hasSubscribeToAttributes()) { |
286 | - processSubscriptionCommands(context, msg.getSessionInfo(), msg.getSubscribeToAttributes()); | 331 | + processSubscriptionCommands(context, sessionInfo, msg.getSubscribeToAttributes()); |
287 | } | 332 | } |
288 | if (msg.hasSubscribeToRPC()) { | 333 | if (msg.hasSubscribeToRPC()) { |
289 | - processSubscriptionCommands(context, msg.getSessionInfo(), msg.getSubscribeToRPC()); | 334 | + processSubscriptionCommands(context, sessionInfo, msg.getSubscribeToRPC()); |
335 | + } | ||
336 | + if (msg.hasSendPendingRPC()) { | ||
337 | + sendPendingRequests(context, getSessionId(sessionInfo), sessionInfo); | ||
290 | } | 338 | } |
291 | if (msg.hasGetAttributes()) { | 339 | if (msg.hasGetAttributes()) { |
292 | - handleGetAttributesRequest(context, msg.getSessionInfo(), msg.getGetAttributes()); | 340 | + handleGetAttributesRequest(context, sessionInfo, msg.getGetAttributes()); |
293 | } | 341 | } |
294 | if (msg.hasToDeviceRPCCallResponse()) { | 342 | if (msg.hasToDeviceRPCCallResponse()) { |
295 | - processRpcResponses(context, msg.getSessionInfo(), msg.getToDeviceRPCCallResponse()); | 343 | + processRpcResponses(context, sessionInfo, msg.getToDeviceRPCCallResponse()); |
296 | } | 344 | } |
297 | if (msg.hasSubscriptionInfo()) { | 345 | if (msg.hasSubscriptionInfo()) { |
298 | - handleSessionActivity(context, msg.getSessionInfo(), msg.getSubscriptionInfo()); | 346 | + handleSessionActivity(context, sessionInfo, msg.getSubscriptionInfo()); |
299 | } | 347 | } |
300 | if (msg.hasClaimDevice()) { | 348 | if (msg.hasClaimDevice()) { |
301 | - handleClaimDeviceMsg(context, msg.getSessionInfo(), msg.getClaimDevice()); | 349 | + handleClaimDeviceMsg(context, sessionInfo, msg.getClaimDevice()); |
350 | + } | ||
351 | + if (msg.hasPersistedRpcResponseMsg()) { | ||
352 | + processPersistedRpcResponses(context, sessionInfo, msg.getPersistedRpcResponseMsg()); | ||
302 | } | 353 | } |
303 | callback.onSuccess(); | 354 | callback.onSuccess(); |
304 | } | 355 | } |
305 | 356 | ||
306 | - private void handleClaimDeviceMsg(TbActorCtx context, SessionInfoProto sessionInfo, TransportProtos.ClaimDeviceMsg msg) { | 357 | + private void handleClaimDeviceMsg(TbActorCtx context, SessionInfoProto sessionInfo, ClaimDeviceMsg msg) { |
307 | DeviceId deviceId = new DeviceId(new UUID(msg.getDeviceIdMSB(), msg.getDeviceIdLSB())); | 358 | DeviceId deviceId = new DeviceId(new UUID(msg.getDeviceIdMSB(), msg.getDeviceIdLSB())); |
308 | systemContext.getClaimDevicesService().registerClaimingInfo(tenantId, deviceId, msg.getSecretKey(), msg.getDurationMs()); | 359 | systemContext.getClaimDevicesService().registerClaimingInfo(tenantId, deviceId, msg.getSecretKey(), msg.getDurationMs()); |
309 | } | 360 | } |
@@ -442,11 +493,22 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -442,11 +493,22 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
442 | if (success) { | 493 | if (success) { |
443 | systemContext.getTbCoreDeviceRpcService().processRpcResponseFromDeviceActor(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(), | 494 | systemContext.getTbCoreDeviceRpcService().processRpcResponseFromDeviceActor(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(), |
444 | responseMsg.getPayload(), null)); | 495 | responseMsg.getPayload(), null)); |
496 | + if (requestMd.getMsg().getMsg().isPersisted()) { | ||
497 | + systemContext.getTbRpcService().save(tenantId, new RpcId(requestMd.getMsg().getMsg().getId()), RpcStatus.SUCCESSFUL, JacksonUtil.toJsonNode(responseMsg.getPayload())); | ||
498 | + } | ||
445 | } else { | 499 | } else { |
446 | log.debug("[{}] Rpc command response [{}] is stale!", deviceId, responseMsg.getRequestId()); | 500 | log.debug("[{}] Rpc command response [{}] is stale!", deviceId, responseMsg.getRequestId()); |
501 | + if (requestMd.getMsg().getMsg().isPersisted()) { | ||
502 | + systemContext.getTbRpcService().save(tenantId, new RpcId(requestMd.getMsg().getMsg().getId()), RpcStatus.FAILED, JacksonUtil.toJsonNode(responseMsg.getPayload())); | ||
503 | + } | ||
447 | } | 504 | } |
448 | } | 505 | } |
449 | 506 | ||
507 | + private void processPersistedRpcResponses(TbActorCtx context, SessionInfoProto sessionInfo, ToDevicePersistedRpcResponseMsg responseMsg) { | ||
508 | + UUID rpcId = new UUID(responseMsg.getRequestIdMSB(), responseMsg.getRequestIdLSB()); | ||
509 | + systemContext.getTbRpcService().save(tenantId, new RpcId(rpcId), RpcStatus.valueOf(responseMsg.getStatus()), null); | ||
510 | + } | ||
511 | + | ||
450 | private void processSubscriptionCommands(TbActorCtx context, SessionInfoProto sessionInfo, SubscribeToAttributeUpdatesMsg subscribeCmd) { | 512 | private void processSubscriptionCommands(TbActorCtx context, SessionInfoProto sessionInfo, SubscribeToAttributeUpdatesMsg subscribeCmd) { |
451 | UUID sessionId = getSessionId(sessionInfo); | 513 | UUID sessionId = getSessionId(sessionInfo); |
452 | if (subscribeCmd.getUnsubscribe()) { | 514 | if (subscribeCmd.getUnsubscribe()) { |
@@ -565,7 +627,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -565,7 +627,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
565 | 627 | ||
566 | void notifyTransportAboutProfileUpdate(UUID sessionId, SessionInfoMetaData sessionMd, DeviceCredentials deviceCredentials) { | 628 | void notifyTransportAboutProfileUpdate(UUID sessionId, SessionInfoMetaData sessionMd, DeviceCredentials deviceCredentials) { |
567 | log.info("2) LwM2Mtype: "); | 629 | log.info("2) LwM2Mtype: "); |
568 | - TransportProtos.ToTransportUpdateCredentialsProto.Builder notification = TransportProtos.ToTransportUpdateCredentialsProto.newBuilder(); | 630 | + ToTransportUpdateCredentialsProto.Builder notification = ToTransportUpdateCredentialsProto.newBuilder(); |
569 | notification.addCredentialsId(deviceCredentials.getCredentialsId()); | 631 | notification.addCredentialsId(deviceCredentials.getCredentialsId()); |
570 | notification.addCredentialsValue(deviceCredentials.getCredentialsValue()); | 632 | notification.addCredentialsValue(deviceCredentials.getCredentialsValue()); |
571 | ToTransportMsg msg = ToTransportMsg.newBuilder() | 633 | ToTransportMsg msg = ToTransportMsg.newBuilder() |
@@ -640,7 +702,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -640,7 +702,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
640 | ListenableFuture<EdgeEvent> future = systemContext.getEdgeEventService().saveAsync(edgeEvent); | 702 | ListenableFuture<EdgeEvent> future = systemContext.getEdgeEventService().saveAsync(edgeEvent); |
641 | Futures.addCallback(future, new FutureCallback<EdgeEvent>() { | 703 | Futures.addCallback(future, new FutureCallback<EdgeEvent>() { |
642 | @Override | 704 | @Override |
643 | - public void onSuccess( EdgeEvent result) { | 705 | + public void onSuccess(EdgeEvent result) { |
644 | systemContext.getClusterService().onEdgeEventUpdate(tenantId, edgeId); | 706 | systemContext.getClusterService().onEdgeEventUpdate(tenantId, edgeId); |
645 | } | 707 | } |
646 | 708 | ||
@@ -756,8 +818,26 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -756,8 +818,26 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
756 | .addAllSessions(sessionsList).build().toByteArray()); | 818 | .addAllSessions(sessionsList).build().toByteArray()); |
757 | } | 819 | } |
758 | 820 | ||
759 | - void initSessionTimeout(TbActorCtx ctx) { | 821 | + void init(TbActorCtx ctx) { |
760 | schedulePeriodicMsgWithDelay(ctx, SessionTimeoutCheckMsg.instance(), systemContext.getSessionReportTimeout(), systemContext.getSessionReportTimeout()); | 822 | schedulePeriodicMsgWithDelay(ctx, SessionTimeoutCheckMsg.instance(), systemContext.getSessionReportTimeout(), systemContext.getSessionReportTimeout()); |
823 | + PageLink pageLink = new PageLink(1024); | ||
824 | + PageData<Rpc> pageData; | ||
825 | + do { | ||
826 | + pageData = systemContext.getTbRpcService().findAllByDeviceIdAndStatus(tenantId, deviceId, RpcStatus.QUEUED, pageLink); | ||
827 | + pageData.getData().forEach(rpc -> { | ||
828 | + ToDeviceRpcRequest msg = JacksonUtil.convertValue(rpc.getRequest(), ToDeviceRpcRequest.class); | ||
829 | + long timeout = rpc.getExpirationTime() - System.currentTimeMillis(); | ||
830 | + if (timeout <= 0) { | ||
831 | + rpc.setStatus(RpcStatus.TIMEOUT); | ||
832 | + systemContext.getTbRpcService().save(tenantId, rpc); | ||
833 | + } else { | ||
834 | + registerPendingRpcRequest(ctx, new ToDeviceRpcRequestActorMsg(systemContext.getServiceId(), msg), false, creteToDeviceRpcRequestMsg(msg), timeout); | ||
835 | + } | ||
836 | + }); | ||
837 | + if (pageData.hasNext()) { | ||
838 | + pageLink = pageLink.nextPageLink(); | ||
839 | + } | ||
840 | + } while (pageData.hasNext()); | ||
761 | } | 841 | } |
762 | 842 | ||
763 | void checkSessionsTimeout() { | 843 | void checkSessionsTimeout() { |
@@ -69,6 +69,7 @@ import org.thingsboard.server.common.data.id.EntityId; | @@ -69,6 +69,7 @@ import org.thingsboard.server.common.data.id.EntityId; | ||
69 | import org.thingsboard.server.common.data.id.EntityIdFactory; | 69 | import org.thingsboard.server.common.data.id.EntityIdFactory; |
70 | import org.thingsboard.server.common.data.id.EntityViewId; | 70 | import org.thingsboard.server.common.data.id.EntityViewId; |
71 | import org.thingsboard.server.common.data.id.OtaPackageId; | 71 | import org.thingsboard.server.common.data.id.OtaPackageId; |
72 | +import org.thingsboard.server.common.data.id.RpcId; | ||
72 | import org.thingsboard.server.common.data.id.TbResourceId; | 73 | import org.thingsboard.server.common.data.id.TbResourceId; |
73 | import org.thingsboard.server.common.data.id.RuleChainId; | 74 | import org.thingsboard.server.common.data.id.RuleChainId; |
74 | import org.thingsboard.server.common.data.id.RuleNodeId; | 75 | import org.thingsboard.server.common.data.id.RuleNodeId; |
@@ -83,6 +84,7 @@ import org.thingsboard.server.common.data.page.TimePageLink; | @@ -83,6 +84,7 @@ import org.thingsboard.server.common.data.page.TimePageLink; | ||
83 | import org.thingsboard.server.common.data.plugin.ComponentDescriptor; | 84 | import org.thingsboard.server.common.data.plugin.ComponentDescriptor; |
84 | import org.thingsboard.server.common.data.plugin.ComponentType; | 85 | import org.thingsboard.server.common.data.plugin.ComponentType; |
85 | import org.thingsboard.server.common.data.relation.EntityRelation; | 86 | import org.thingsboard.server.common.data.relation.EntityRelation; |
87 | +import org.thingsboard.server.common.data.rpc.Rpc; | ||
86 | import org.thingsboard.server.common.data.rule.RuleChain; | 88 | import org.thingsboard.server.common.data.rule.RuleChain; |
87 | import org.thingsboard.server.common.data.rule.RuleChainType; | 89 | import org.thingsboard.server.common.data.rule.RuleChainType; |
88 | import org.thingsboard.server.common.data.rule.RuleNode; | 90 | import org.thingsboard.server.common.data.rule.RuleNode; |
@@ -106,6 +108,7 @@ import org.thingsboard.server.dao.model.ModelConstants; | @@ -106,6 +108,7 @@ import org.thingsboard.server.dao.model.ModelConstants; | ||
106 | import org.thingsboard.server.dao.oauth2.OAuth2ConfigTemplateService; | 108 | import org.thingsboard.server.dao.oauth2.OAuth2ConfigTemplateService; |
107 | import org.thingsboard.server.dao.oauth2.OAuth2Service; | 109 | import org.thingsboard.server.dao.oauth2.OAuth2Service; |
108 | import org.thingsboard.server.dao.relation.RelationService; | 110 | import org.thingsboard.server.dao.relation.RelationService; |
111 | +import org.thingsboard.server.dao.rpc.RpcService; | ||
109 | import org.thingsboard.server.dao.rule.RuleChainService; | 112 | import org.thingsboard.server.dao.rule.RuleChainService; |
110 | import org.thingsboard.server.dao.tenant.TbTenantProfileCache; | 113 | import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
111 | import org.thingsboard.server.dao.tenant.TenantProfileService; | 114 | import org.thingsboard.server.dao.tenant.TenantProfileService; |
@@ -246,6 +249,9 @@ public abstract class BaseController { | @@ -246,6 +249,9 @@ public abstract class BaseController { | ||
246 | protected OtaPackageStateService otaPackageStateService; | 249 | protected OtaPackageStateService otaPackageStateService; |
247 | 250 | ||
248 | @Autowired | 251 | @Autowired |
252 | + protected RpcService rpcService; | ||
253 | + | ||
254 | + @Autowired | ||
249 | protected TbQueueProducerProvider producerProvider; | 255 | protected TbQueueProducerProvider producerProvider; |
250 | 256 | ||
251 | @Autowired | 257 | @Autowired |
@@ -786,6 +792,18 @@ public abstract class BaseController { | @@ -786,6 +792,18 @@ public abstract class BaseController { | ||
786 | } | 792 | } |
787 | } | 793 | } |
788 | 794 | ||
795 | + Rpc checkRpcId(RpcId rpcId, Operation operation) throws ThingsboardException { | ||
796 | + try { | ||
797 | + validateId(rpcId, "Incorrect rpcId " + rpcId); | ||
798 | + Rpc rpc = rpcService.findById(getCurrentUser().getTenantId(), rpcId); | ||
799 | + checkNotNull(rpc); | ||
800 | + accessControlService.checkPermission(getCurrentUser(), Resource.RPC, operation, rpcId, rpc); | ||
801 | + return rpc; | ||
802 | + } catch (Exception e) { | ||
803 | + throw handleException(e, false); | ||
804 | + } | ||
805 | + } | ||
806 | + | ||
789 | @SuppressWarnings("unchecked") | 807 | @SuppressWarnings("unchecked") |
790 | protected <I extends EntityId> I emptyId(EntityType entityType) { | 808 | protected <I extends EntityId> I emptyId(EntityType entityType) { |
791 | return (I) EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID); | 809 | return (I) EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID); |
@@ -29,6 +29,7 @@ import org.springframework.web.bind.annotation.PathVariable; | @@ -29,6 +29,7 @@ import org.springframework.web.bind.annotation.PathVariable; | ||
29 | import org.springframework.web.bind.annotation.RequestBody; | 29 | import org.springframework.web.bind.annotation.RequestBody; |
30 | import org.springframework.web.bind.annotation.RequestMapping; | 30 | import org.springframework.web.bind.annotation.RequestMapping; |
31 | import org.springframework.web.bind.annotation.RequestMethod; | 31 | import org.springframework.web.bind.annotation.RequestMethod; |
32 | +import org.springframework.web.bind.annotation.RequestParam; | ||
32 | import org.springframework.web.bind.annotation.ResponseBody; | 33 | import org.springframework.web.bind.annotation.ResponseBody; |
33 | import org.springframework.web.bind.annotation.RestController; | 34 | import org.springframework.web.bind.annotation.RestController; |
34 | import org.springframework.web.context.request.async.DeferredResult; | 35 | import org.springframework.web.context.request.async.DeferredResult; |
@@ -38,8 +39,13 @@ import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; | @@ -38,8 +39,13 @@ import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; | ||
38 | import org.thingsboard.server.common.data.exception.ThingsboardException; | 39 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
39 | import org.thingsboard.server.common.data.id.DeviceId; | 40 | import org.thingsboard.server.common.data.id.DeviceId; |
40 | import org.thingsboard.server.common.data.id.EntityId; | 41 | import org.thingsboard.server.common.data.id.EntityId; |
42 | +import org.thingsboard.server.common.data.id.RpcId; | ||
41 | import org.thingsboard.server.common.data.id.TenantId; | 43 | import org.thingsboard.server.common.data.id.TenantId; |
42 | import org.thingsboard.server.common.data.id.UUIDBased; | 44 | import org.thingsboard.server.common.data.id.UUIDBased; |
45 | +import org.thingsboard.server.common.data.page.PageData; | ||
46 | +import org.thingsboard.server.common.data.page.PageLink; | ||
47 | +import org.thingsboard.server.common.data.rpc.Rpc; | ||
48 | +import org.thingsboard.server.common.data.rpc.RpcStatus; | ||
43 | import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; | 49 | import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; |
44 | import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; | 50 | import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; |
45 | import org.thingsboard.server.queue.util.TbCoreComponent; | 51 | import org.thingsboard.server.queue.util.TbCoreComponent; |
@@ -93,6 +99,52 @@ public class RpcController extends BaseController { | @@ -93,6 +99,52 @@ public class RpcController extends BaseController { | ||
93 | return handleDeviceRPCRequest(false, new DeviceId(UUID.fromString(deviceIdStr)), requestBody); | 99 | return handleDeviceRPCRequest(false, new DeviceId(UUID.fromString(deviceIdStr)), requestBody); |
94 | } | 100 | } |
95 | 101 | ||
102 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | ||
103 | + @RequestMapping(value = "/persisted/{rpcId}", method = RequestMethod.GET) | ||
104 | + @ResponseBody | ||
105 | + public Rpc getPersistedRpc(@PathVariable("rpcId") String strRpc) throws ThingsboardException { | ||
106 | + checkParameter("RpcId", strRpc); | ||
107 | + try { | ||
108 | + RpcId rpcId = new RpcId(UUID.fromString(strRpc)); | ||
109 | + return checkRpcId(rpcId, Operation.READ); | ||
110 | + } catch (Exception e) { | ||
111 | + throw handleException(e); | ||
112 | + } | ||
113 | + } | ||
114 | + | ||
115 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | ||
116 | + @RequestMapping(value = "/persisted/{deviceId}", method = RequestMethod.GET) | ||
117 | + @ResponseBody | ||
118 | + public PageData<Rpc> getPersistedRpcByDevice(@PathVariable("deviceId") String strDeviceId, | ||
119 | + @RequestParam int pageSize, | ||
120 | + @RequestParam int page, | ||
121 | + @RequestParam RpcStatus rpcStatus, | ||
122 | + @RequestParam(required = false) String textSearch, | ||
123 | + @RequestParam(required = false) String sortProperty, | ||
124 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | ||
125 | + checkParameter("DeviceId", strDeviceId); | ||
126 | + try { | ||
127 | + TenantId tenantId = getCurrentUser().getTenantId(); | ||
128 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | ||
129 | + DeviceId deviceId = new DeviceId(UUID.fromString(strDeviceId)); | ||
130 | + return checkNotNull(rpcService.findAllByDeviceIdAndStatus(tenantId, deviceId, rpcStatus, pageLink)); | ||
131 | + } catch (Exception e) { | ||
132 | + throw handleException(e); | ||
133 | + } | ||
134 | + } | ||
135 | + | ||
136 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") | ||
137 | + @RequestMapping(value = "/persisted/{rpcId}", method = RequestMethod.DELETE) | ||
138 | + @ResponseBody | ||
139 | + public void deleteResource(@PathVariable("rpcId") String strRpc) throws ThingsboardException { | ||
140 | + checkParameter("RpcId", strRpc); | ||
141 | + try { | ||
142 | + rpcService.deleteRpc(getTenantId(), new RpcId(UUID.fromString(strRpc))); | ||
143 | + } catch (Exception e) { | ||
144 | + throw handleException(e); | ||
145 | + } | ||
146 | + } | ||
147 | + | ||
96 | private DeferredResult<ResponseEntity> handleDeviceRPCRequest(boolean oneWay, DeviceId deviceId, String requestBody) throws ThingsboardException { | 148 | private DeferredResult<ResponseEntity> handleDeviceRPCRequest(boolean oneWay, DeviceId deviceId, String requestBody) throws ThingsboardException { |
97 | try { | 149 | try { |
98 | JsonNode rpcRequestBody = jsonMapper.readTree(requestBody); | 150 | JsonNode rpcRequestBody = jsonMapper.readTree(requestBody); |
@@ -103,6 +155,7 @@ public class RpcController extends BaseController { | @@ -103,6 +155,7 @@ public class RpcController extends BaseController { | ||
103 | long timeout = rpcRequestBody.has("timeout") ? rpcRequestBody.get("timeout").asLong() : defaultTimeout; | 155 | long timeout = rpcRequestBody.has("timeout") ? rpcRequestBody.get("timeout").asLong() : defaultTimeout; |
104 | long expTime = System.currentTimeMillis() + Math.max(minTimeout, timeout); | 156 | long expTime = System.currentTimeMillis() + Math.max(minTimeout, timeout); |
105 | UUID rpcRequestUUID = rpcRequestBody.has("requestUUID") ? UUID.fromString(rpcRequestBody.get("requestUUID").asText()) : UUID.randomUUID(); | 157 | UUID rpcRequestUUID = rpcRequestBody.has("requestUUID") ? UUID.fromString(rpcRequestBody.get("requestUUID").asText()) : UUID.randomUUID(); |
158 | + boolean persisted = rpcRequestBody.has("persisted") && rpcRequestBody.get("persisted").asBoolean(); | ||
106 | accessValidator.validate(currentUser, Operation.RPC_CALL, deviceId, new HttpValidationCallback(response, new FutureCallback<DeferredResult<ResponseEntity>>() { | 159 | accessValidator.validate(currentUser, Operation.RPC_CALL, deviceId, new HttpValidationCallback(response, new FutureCallback<DeferredResult<ResponseEntity>>() { |
107 | @Override | 160 | @Override |
108 | public void onSuccess(@Nullable DeferredResult<ResponseEntity> result) { | 161 | public void onSuccess(@Nullable DeferredResult<ResponseEntity> result) { |
@@ -111,7 +164,8 @@ public class RpcController extends BaseController { | @@ -111,7 +164,8 @@ public class RpcController extends BaseController { | ||
111 | deviceId, | 164 | deviceId, |
112 | oneWay, | 165 | oneWay, |
113 | expTime, | 166 | expTime, |
114 | - body | 167 | + body, |
168 | + persisted | ||
115 | ); | 169 | ); |
116 | deviceRpcService.processRestApiRpcRequest(rpcRequest, fromDeviceRpcResponse -> reply(new LocalRequestMetaData(rpcRequest, currentUser, result), fromDeviceRpcResponse), currentUser); | 170 | deviceRpcService.processRestApiRpcRequest(rpcRequest, fromDeviceRpcResponse -> reply(new LocalRequestMetaData(rpcRequest, currentUser, result), fromDeviceRpcResponse), currentUser); |
117 | } | 171 | } |
@@ -157,6 +157,7 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService { | @@ -157,6 +157,7 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService { | ||
157 | metaData.putValue("originServiceId", serviceId); | 157 | metaData.putValue("originServiceId", serviceId); |
158 | metaData.putValue("expirationTime", Long.toString(msg.getExpirationTime())); | 158 | metaData.putValue("expirationTime", Long.toString(msg.getExpirationTime())); |
159 | metaData.putValue("oneway", Boolean.toString(msg.isOneway())); | 159 | metaData.putValue("oneway", Boolean.toString(msg.isOneway())); |
160 | + metaData.putValue("persisted", Boolean.toString(msg.isPersisted())); | ||
160 | 161 | ||
161 | Device device = deviceService.findDeviceById(msg.getTenantId(), msg.getDeviceId()); | 162 | Device device = deviceService.findDeviceById(msg.getTenantId(), msg.getDeviceId()); |
162 | if (device != null) { | 163 | if (device != null) { |
@@ -100,7 +100,7 @@ public class DefaultTbRuleEngineRpcService implements TbRuleEngineDeviceRpcServi | @@ -100,7 +100,7 @@ public class DefaultTbRuleEngineRpcService implements TbRuleEngineDeviceRpcServi | ||
100 | @Override | 100 | @Override |
101 | public void sendRpcRequestToDevice(RuleEngineDeviceRpcRequest src, Consumer<RuleEngineDeviceRpcResponse> consumer) { | 101 | public void sendRpcRequestToDevice(RuleEngineDeviceRpcRequest src, Consumer<RuleEngineDeviceRpcResponse> consumer) { |
102 | ToDeviceRpcRequest request = new ToDeviceRpcRequest(src.getRequestUUID(), src.getTenantId(), src.getDeviceId(), | 102 | ToDeviceRpcRequest request = new ToDeviceRpcRequest(src.getRequestUUID(), src.getTenantId(), src.getDeviceId(), |
103 | - src.isOneway(), src.getExpirationTime(), new ToDeviceRpcRequestBody(src.getMethod(), src.getBody())); | 103 | + src.isOneway(), src.getExpirationTime(), new ToDeviceRpcRequestBody(src.getMethod(), src.getBody()), src.isPersisted()); |
104 | forwardRpcRequestToDeviceActor(request, response -> { | 104 | forwardRpcRequestToDeviceActor(request, response -> { |
105 | if (src.isRestApiCall()) { | 105 | if (src.isRestApiCall()) { |
106 | sendRpcResponseToTbCore(src.getOriginServiceId(), response); | 106 | sendRpcResponseToTbCore(src.getOriginServiceId(), response); |
1 | +/** | ||
2 | + * Copyright © 2016-2021 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.service.rpc; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.databind.JsonNode; | ||
19 | +import lombok.RequiredArgsConstructor; | ||
20 | +import lombok.extern.slf4j.Slf4j; | ||
21 | +import org.springframework.stereotype.Service; | ||
22 | +import org.thingsboard.common.util.JacksonUtil; | ||
23 | +import org.thingsboard.server.common.data.id.DeviceId; | ||
24 | +import org.thingsboard.server.common.data.id.RpcId; | ||
25 | +import org.thingsboard.server.common.data.id.TenantId; | ||
26 | +import org.thingsboard.server.common.data.page.PageData; | ||
27 | +import org.thingsboard.server.common.data.page.PageLink; | ||
28 | +import org.thingsboard.server.common.data.rpc.Rpc; | ||
29 | +import org.thingsboard.server.common.data.rpc.RpcStatus; | ||
30 | +import org.thingsboard.server.common.msg.TbMsg; | ||
31 | +import org.thingsboard.server.common.msg.TbMsgMetaData; | ||
32 | +import org.thingsboard.server.dao.rpc.RpcService; | ||
33 | +import org.thingsboard.server.queue.util.TbCoreComponent; | ||
34 | +import org.thingsboard.server.service.queue.TbClusterService; | ||
35 | + | ||
36 | +@TbCoreComponent | ||
37 | +@Service | ||
38 | +@RequiredArgsConstructor | ||
39 | +@Slf4j | ||
40 | +public class TbRpcService { | ||
41 | + private final RpcService rpcService; | ||
42 | + private final TbClusterService tbClusterService; | ||
43 | + | ||
44 | + public Rpc save(TenantId tenantId, Rpc rpc) { | ||
45 | + Rpc saved = rpcService.save(rpc); | ||
46 | + pushRpcMsgToRuleEngine(tenantId, saved); | ||
47 | + return saved; | ||
48 | + } | ||
49 | + | ||
50 | + public void save(TenantId tenantId, RpcId rpcId, RpcStatus newStatus, JsonNode response) { | ||
51 | + Rpc foundRpc = rpcService.findById(tenantId, rpcId); | ||
52 | + if (foundRpc != null) { | ||
53 | + foundRpc.setStatus(newStatus); | ||
54 | + if (response != null) { | ||
55 | + foundRpc.setResponse(response); | ||
56 | + } | ||
57 | + Rpc saved = rpcService.save(foundRpc); | ||
58 | + pushRpcMsgToRuleEngine(tenantId, saved); | ||
59 | + } else { | ||
60 | + log.warn("[{}] Failed to update RPC status because RPC was already deleted", rpcId); | ||
61 | + } | ||
62 | + } | ||
63 | + | ||
64 | + private void pushRpcMsgToRuleEngine(TenantId tenantId, Rpc rpc) { | ||
65 | + TbMsg msg = TbMsg.newMsg("RPC_" + rpc.getStatus().name(), rpc.getDeviceId(), TbMsgMetaData.EMPTY, JacksonUtil.toString(rpc)); | ||
66 | + tbClusterService.pushMsgToRuleEngine(tenantId, rpc.getId(), msg, null); | ||
67 | + } | ||
68 | + | ||
69 | + public Rpc findRpcById(TenantId tenantId, RpcId rpcId) { | ||
70 | + return rpcService.findById(tenantId, rpcId); | ||
71 | + } | ||
72 | + | ||
73 | + public PageData<Rpc> findAllByDeviceIdAndStatus(TenantId tenantId, DeviceId deviceId, RpcStatus rpcStatus, PageLink pageLink) { | ||
74 | + return rpcService.findAllByDeviceIdAndStatus(tenantId, deviceId, rpcStatus, pageLink); | ||
75 | + } | ||
76 | + | ||
77 | +} |
@@ -47,11 +47,13 @@ import org.thingsboard.server.common.data.id.EntityId; | @@ -47,11 +47,13 @@ import org.thingsboard.server.common.data.id.EntityId; | ||
47 | import org.thingsboard.server.common.data.id.EntityIdFactory; | 47 | import org.thingsboard.server.common.data.id.EntityIdFactory; |
48 | import org.thingsboard.server.common.data.id.EntityViewId; | 48 | import org.thingsboard.server.common.data.id.EntityViewId; |
49 | import org.thingsboard.server.common.data.id.OtaPackageId; | 49 | import org.thingsboard.server.common.data.id.OtaPackageId; |
50 | +import org.thingsboard.server.common.data.id.RpcId; | ||
50 | import org.thingsboard.server.common.data.id.RuleChainId; | 51 | import org.thingsboard.server.common.data.id.RuleChainId; |
51 | import org.thingsboard.server.common.data.id.RuleNodeId; | 52 | import org.thingsboard.server.common.data.id.RuleNodeId; |
52 | import org.thingsboard.server.common.data.id.TbResourceId; | 53 | import org.thingsboard.server.common.data.id.TbResourceId; |
53 | import org.thingsboard.server.common.data.id.TenantId; | 54 | import org.thingsboard.server.common.data.id.TenantId; |
54 | import org.thingsboard.server.common.data.id.UserId; | 55 | import org.thingsboard.server.common.data.id.UserId; |
56 | +import org.thingsboard.server.common.data.rpc.Rpc; | ||
55 | import org.thingsboard.server.common.data.rule.RuleChain; | 57 | import org.thingsboard.server.common.data.rule.RuleChain; |
56 | import org.thingsboard.server.common.data.rule.RuleNode; | 58 | import org.thingsboard.server.common.data.rule.RuleNode; |
57 | import org.thingsboard.server.controller.HttpValidationCallback; | 59 | import org.thingsboard.server.controller.HttpValidationCallback; |
@@ -65,6 +67,7 @@ import org.thingsboard.server.dao.entityview.EntityViewService; | @@ -65,6 +67,7 @@ import org.thingsboard.server.dao.entityview.EntityViewService; | ||
65 | import org.thingsboard.server.dao.exception.IncorrectParameterException; | 67 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
66 | import org.thingsboard.server.dao.ota.OtaPackageService; | 68 | import org.thingsboard.server.dao.ota.OtaPackageService; |
67 | import org.thingsboard.server.dao.resource.ResourceService; | 69 | import org.thingsboard.server.dao.resource.ResourceService; |
70 | +import org.thingsboard.server.dao.rpc.RpcService; | ||
68 | import org.thingsboard.server.dao.rule.RuleChainService; | 71 | import org.thingsboard.server.dao.rule.RuleChainService; |
69 | import org.thingsboard.server.dao.tenant.TenantService; | 72 | import org.thingsboard.server.dao.tenant.TenantService; |
70 | import org.thingsboard.server.dao.usagerecord.ApiUsageStateService; | 73 | import org.thingsboard.server.dao.usagerecord.ApiUsageStateService; |
@@ -137,6 +140,9 @@ public class AccessValidator { | @@ -137,6 +140,9 @@ public class AccessValidator { | ||
137 | @Autowired | 140 | @Autowired |
138 | protected OtaPackageService otaPackageService; | 141 | protected OtaPackageService otaPackageService; |
139 | 142 | ||
143 | + @Autowired | ||
144 | + protected RpcService rpcService; | ||
145 | + | ||
140 | private ExecutorService executor; | 146 | private ExecutorService executor; |
141 | 147 | ||
142 | @PostConstruct | 148 | @PostConstruct |
@@ -235,6 +241,9 @@ public class AccessValidator { | @@ -235,6 +241,9 @@ public class AccessValidator { | ||
235 | case OTA_PACKAGE: | 241 | case OTA_PACKAGE: |
236 | validateOtaPackage(currentUser, operation, entityId, callback); | 242 | validateOtaPackage(currentUser, operation, entityId, callback); |
237 | return; | 243 | return; |
244 | + case RPC: | ||
245 | + validateRpc(currentUser, operation, entityId, callback); | ||
246 | + return; | ||
238 | default: | 247 | default: |
239 | //TODO: add support of other entities | 248 | //TODO: add support of other entities |
240 | throw new IllegalStateException("Not Implemented!"); | 249 | throw new IllegalStateException("Not Implemented!"); |
@@ -261,6 +270,22 @@ public class AccessValidator { | @@ -261,6 +270,22 @@ public class AccessValidator { | ||
261 | } | 270 | } |
262 | } | 271 | } |
263 | 272 | ||
273 | + private void validateRpc(final SecurityUser currentUser, Operation operation, EntityId entityId, FutureCallback<ValidationResult> callback) { | ||
274 | + ListenableFuture<Rpc> rpcFurure = rpcService.findRpcByIdAsync(currentUser.getTenantId(), new RpcId(entityId.getId())); | ||
275 | + Futures.addCallback(rpcFurure, getCallback(callback, rpc -> { | ||
276 | + if (rpc == null) { | ||
277 | + return ValidationResult.entityNotFound("Rpc with requested id wasn't found!"); | ||
278 | + } else { | ||
279 | + try { | ||
280 | + accessControlService.checkPermission(currentUser, Resource.RPC, operation, entityId, rpc); | ||
281 | + } catch (ThingsboardException e) { | ||
282 | + return ValidationResult.accessDenied(e.getMessage()); | ||
283 | + } | ||
284 | + return ValidationResult.ok(rpc); | ||
285 | + } | ||
286 | + }), executor); | ||
287 | + } | ||
288 | + | ||
264 | private void validateDeviceProfile(final SecurityUser currentUser, Operation operation, EntityId entityId, FutureCallback<ValidationResult> callback) { | 289 | private void validateDeviceProfile(final SecurityUser currentUser, Operation operation, EntityId entityId, FutureCallback<ValidationResult> callback) { |
265 | if (currentUser.isSystemAdmin()) { | 290 | if (currentUser.isSystemAdmin()) { |
266 | callback.onSuccess(ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION)); | 291 | callback.onSuccess(ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION)); |
@@ -41,6 +41,7 @@ public class CustomerUserPermissions extends AbstractPermissions { | @@ -41,6 +41,7 @@ public class CustomerUserPermissions extends AbstractPermissions { | ||
41 | put(Resource.WIDGETS_BUNDLE, widgetsPermissionChecker); | 41 | put(Resource.WIDGETS_BUNDLE, widgetsPermissionChecker); |
42 | put(Resource.WIDGET_TYPE, widgetsPermissionChecker); | 42 | put(Resource.WIDGET_TYPE, widgetsPermissionChecker); |
43 | put(Resource.EDGE, customerEntityPermissionChecker); | 43 | put(Resource.EDGE, customerEntityPermissionChecker); |
44 | + put(Resource.RPC, rpcPermissionChecker); | ||
44 | } | 45 | } |
45 | 46 | ||
46 | private static final PermissionChecker customerEntityPermissionChecker = | 47 | private static final PermissionChecker customerEntityPermissionChecker = |
@@ -138,4 +139,22 @@ public class CustomerUserPermissions extends AbstractPermissions { | @@ -138,4 +139,22 @@ public class CustomerUserPermissions extends AbstractPermissions { | ||
138 | } | 139 | } |
139 | 140 | ||
140 | }; | 141 | }; |
142 | + | ||
143 | + private static final PermissionChecker rpcPermissionChecker = new PermissionChecker.GenericPermissionChecker(Operation.READ) { | ||
144 | + | ||
145 | + @Override | ||
146 | + @SuppressWarnings("unchecked") | ||
147 | + public boolean hasPermission(SecurityUser user, Operation operation, EntityId entityId, HasTenantId entity) { | ||
148 | + if (!super.hasPermission(user, operation, entityId, entity)) { | ||
149 | + return false; | ||
150 | + } | ||
151 | + if (entity.getTenantId() == null || entity.getTenantId().isNullUid()) { | ||
152 | + return true; | ||
153 | + } | ||
154 | + if (!user.getTenantId().equals(entity.getTenantId())) { | ||
155 | + return false; | ||
156 | + } | ||
157 | + return true; | ||
158 | + } | ||
159 | + }; | ||
141 | } | 160 | } |
@@ -39,7 +39,8 @@ public enum Resource { | @@ -39,7 +39,8 @@ public enum Resource { | ||
39 | API_USAGE_STATE(EntityType.API_USAGE_STATE), | 39 | API_USAGE_STATE(EntityType.API_USAGE_STATE), |
40 | TB_RESOURCE(EntityType.TB_RESOURCE), | 40 | TB_RESOURCE(EntityType.TB_RESOURCE), |
41 | OTA_PACKAGE(EntityType.OTA_PACKAGE), | 41 | OTA_PACKAGE(EntityType.OTA_PACKAGE), |
42 | - EDGE(EntityType.EDGE); | 42 | + EDGE(EntityType.EDGE), |
43 | + RPC(EntityType.RPC); | ||
43 | 44 | ||
44 | private final EntityType entityType; | 45 | private final EntityType entityType; |
45 | 46 |
@@ -44,6 +44,7 @@ public class TenantAdminPermissions extends AbstractPermissions { | @@ -44,6 +44,7 @@ public class TenantAdminPermissions extends AbstractPermissions { | ||
44 | put(Resource.TB_RESOURCE, tbResourcePermissionChecker); | 44 | put(Resource.TB_RESOURCE, tbResourcePermissionChecker); |
45 | put(Resource.OTA_PACKAGE, tenantEntityPermissionChecker); | 45 | put(Resource.OTA_PACKAGE, tenantEntityPermissionChecker); |
46 | put(Resource.EDGE, tenantEntityPermissionChecker); | 46 | put(Resource.EDGE, tenantEntityPermissionChecker); |
47 | + put(Resource.RPC, tenantEntityPermissionChecker); | ||
47 | } | 48 | } |
48 | 49 | ||
49 | public static final PermissionChecker tenantEntityPermissionChecker = new PermissionChecker() { | 50 | public static final PermissionChecker tenantEntityPermissionChecker = new PermissionChecker() { |
@@ -22,6 +22,7 @@ import com.google.common.util.concurrent.Futures; | @@ -22,6 +22,7 @@ import com.google.common.util.concurrent.Futures; | ||
22 | import com.google.common.util.concurrent.ListenableFuture; | 22 | import com.google.common.util.concurrent.ListenableFuture; |
23 | import com.google.common.util.concurrent.MoreExecutors; | 23 | import com.google.common.util.concurrent.MoreExecutors; |
24 | import com.google.protobuf.ByteString; | 24 | import com.google.protobuf.ByteString; |
25 | +import lombok.RequiredArgsConstructor; | ||
25 | import lombok.extern.slf4j.Slf4j; | 26 | import lombok.extern.slf4j.Slf4j; |
26 | import org.springframework.stereotype.Service; | 27 | import org.springframework.stereotype.Service; |
27 | import org.springframework.util.StringUtils; | 28 | import org.springframework.util.StringUtils; |
@@ -41,13 +42,13 @@ import org.thingsboard.server.common.data.TenantProfile; | @@ -41,13 +42,13 @@ import org.thingsboard.server.common.data.TenantProfile; | ||
41 | import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; | 42 | import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; |
42 | import org.thingsboard.server.common.data.device.credentials.ProvisionDeviceCredentialsData; | 43 | import org.thingsboard.server.common.data.device.credentials.ProvisionDeviceCredentialsData; |
43 | import org.thingsboard.server.common.data.device.profile.ProvisionDeviceProfileCredentials; | 44 | import org.thingsboard.server.common.data.device.profile.ProvisionDeviceProfileCredentials; |
44 | -import org.thingsboard.server.common.data.ota.OtaPackageType; | ||
45 | -import org.thingsboard.server.common.data.ota.OtaPackageUtil; | ||
46 | import org.thingsboard.server.common.data.id.CustomerId; | 45 | import org.thingsboard.server.common.data.id.CustomerId; |
47 | import org.thingsboard.server.common.data.id.DeviceId; | 46 | import org.thingsboard.server.common.data.id.DeviceId; |
48 | import org.thingsboard.server.common.data.id.DeviceProfileId; | 47 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
49 | import org.thingsboard.server.common.data.id.OtaPackageId; | 48 | import org.thingsboard.server.common.data.id.OtaPackageId; |
50 | import org.thingsboard.server.common.data.id.TenantId; | 49 | import org.thingsboard.server.common.data.id.TenantId; |
50 | +import org.thingsboard.server.common.data.ota.OtaPackageType; | ||
51 | +import org.thingsboard.server.common.data.ota.OtaPackageUtil; | ||
51 | import org.thingsboard.server.common.data.page.PageData; | 52 | import org.thingsboard.server.common.data.page.PageData; |
52 | import org.thingsboard.server.common.data.page.PageLink; | 53 | import org.thingsboard.server.common.data.page.PageLink; |
53 | import org.thingsboard.server.common.data.relation.EntityRelation; | 54 | import org.thingsboard.server.common.data.relation.EntityRelation; |
@@ -108,6 +109,7 @@ import java.util.stream.Collectors; | @@ -108,6 +109,7 @@ import java.util.stream.Collectors; | ||
108 | @Slf4j | 109 | @Slf4j |
109 | @Service | 110 | @Service |
110 | @TbCoreComponent | 111 | @TbCoreComponent |
112 | +@RequiredArgsConstructor | ||
111 | public class DefaultTransportApiService implements TransportApiService { | 113 | public class DefaultTransportApiService implements TransportApiService { |
112 | 114 | ||
113 | private static final ObjectMapper mapper = new ObjectMapper(); | 115 | private static final ObjectMapper mapper = new ObjectMapper(); |
@@ -129,28 +131,6 @@ public class DefaultTransportApiService implements TransportApiService { | @@ -129,28 +131,6 @@ public class DefaultTransportApiService implements TransportApiService { | ||
129 | 131 | ||
130 | private final ConcurrentMap<String, ReentrantLock> deviceCreationLocks = new ConcurrentHashMap<>(); | 132 | private final ConcurrentMap<String, ReentrantLock> deviceCreationLocks = new ConcurrentHashMap<>(); |
131 | 133 | ||
132 | - public DefaultTransportApiService(TbDeviceProfileCache deviceProfileCache, | ||
133 | - TbTenantProfileCache tenantProfileCache, TbApiUsageStateService apiUsageStateService, DeviceService deviceService, | ||
134 | - RelationService relationService, DeviceCredentialsService deviceCredentialsService, | ||
135 | - DeviceStateService deviceStateService, DbCallbackExecutorService dbCallbackExecutorService, | ||
136 | - TbClusterService tbClusterService, DataDecodingEncodingService dataDecodingEncodingService, | ||
137 | - DeviceProvisionService deviceProvisionService, TbResourceService resourceService, OtaPackageService otaPackageService, OtaPackageDataCache otaPackageDataCache) { | ||
138 | - this.deviceProfileCache = deviceProfileCache; | ||
139 | - this.tenantProfileCache = tenantProfileCache; | ||
140 | - this.apiUsageStateService = apiUsageStateService; | ||
141 | - this.deviceService = deviceService; | ||
142 | - this.relationService = relationService; | ||
143 | - this.deviceCredentialsService = deviceCredentialsService; | ||
144 | - this.deviceStateService = deviceStateService; | ||
145 | - this.dbCallbackExecutorService = dbCallbackExecutorService; | ||
146 | - this.tbClusterService = tbClusterService; | ||
147 | - this.dataDecodingEncodingService = dataDecodingEncodingService; | ||
148 | - this.deviceProvisionService = deviceProvisionService; | ||
149 | - this.resourceService = resourceService; | ||
150 | - this.otaPackageService = otaPackageService; | ||
151 | - this.otaPackageDataCache = otaPackageDataCache; | ||
152 | - } | ||
153 | - | ||
154 | @Override | 134 | @Override |
155 | public ListenableFuture<TbProtoQueueMsg<TransportApiResponseMsg>> handle(TbProtoQueueMsg<TransportApiRequestMsg> tbProtoQueueMsg) { | 135 | public ListenableFuture<TbProtoQueueMsg<TransportApiResponseMsg>> handle(TbProtoQueueMsg<TransportApiRequestMsg> tbProtoQueueMsg) { |
156 | TransportApiRequestMsg transportApiRequestMsg = tbProtoQueueMsg.getValue(); | 136 | TransportApiRequestMsg transportApiRequestMsg = tbProtoQueueMsg.getValue(); |
1 | +/** | ||
2 | + * Copyright © 2016-2021 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.service.ttl.rpc; | ||
17 | + | ||
18 | +import lombok.RequiredArgsConstructor; | ||
19 | +import lombok.extern.slf4j.Slf4j; | ||
20 | +import org.springframework.beans.factory.annotation.Value; | ||
21 | +import org.springframework.scheduling.annotation.Scheduled; | ||
22 | +import org.springframework.stereotype.Service; | ||
23 | +import org.thingsboard.server.common.data.id.TenantId; | ||
24 | +import org.thingsboard.server.common.data.page.PageData; | ||
25 | +import org.thingsboard.server.common.data.page.PageLink; | ||
26 | +import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; | ||
27 | +import org.thingsboard.server.common.msg.queue.ServiceType; | ||
28 | +import org.thingsboard.server.dao.rpc.RpcDao; | ||
29 | +import org.thingsboard.server.dao.tenant.TbTenantProfileCache; | ||
30 | +import org.thingsboard.server.dao.tenant.TenantDao; | ||
31 | +import org.thingsboard.server.queue.discovery.PartitionService; | ||
32 | +import org.thingsboard.server.queue.util.TbCoreComponent; | ||
33 | + | ||
34 | +import java.util.Date; | ||
35 | +import java.util.Optional; | ||
36 | +import java.util.concurrent.TimeUnit; | ||
37 | + | ||
38 | +@TbCoreComponent | ||
39 | +@Service | ||
40 | +@Slf4j | ||
41 | +@RequiredArgsConstructor | ||
42 | +public class RpcCleanUpService { | ||
43 | + @Value("${sql.ttl.rpc.enabled}") | ||
44 | + private boolean ttlTaskExecutionEnabled; | ||
45 | + | ||
46 | + private final TenantDao tenantDao; | ||
47 | + private final PartitionService partitionService; | ||
48 | + private final TbTenantProfileCache tenantProfileCache; | ||
49 | + private final RpcDao rpcDao; | ||
50 | + | ||
51 | + @Scheduled(initialDelayString = "#{T(org.apache.commons.lang3.RandomUtils).nextLong(0, ${sql.ttl.rpc.checking_interval})}", fixedDelayString = "${sql.ttl.rpc.checking_interval}") | ||
52 | + public void cleanUp() { | ||
53 | + if (ttlTaskExecutionEnabled) { | ||
54 | + PageLink tenantsBatchRequest = new PageLink(10_000, 0); | ||
55 | + PageData<TenantId> tenantsIds; | ||
56 | + do { | ||
57 | + tenantsIds = tenantDao.findTenantsIds(tenantsBatchRequest); | ||
58 | + for (TenantId tenantId : tenantsIds.getData()) { | ||
59 | + if (!partitionService.resolve(ServiceType.TB_CORE, tenantId, tenantId).isMyPartition()) { | ||
60 | + continue; | ||
61 | + } | ||
62 | + | ||
63 | + Optional<DefaultTenantProfileConfiguration> tenantProfileConfiguration = tenantProfileCache.get(tenantId).getProfileConfiguration(); | ||
64 | + if (tenantProfileConfiguration.isEmpty() || tenantProfileConfiguration.get().getRpcTtlDays() == 0) { | ||
65 | + continue; | ||
66 | + } | ||
67 | + | ||
68 | + long ttl = TimeUnit.DAYS.toMillis(tenantProfileConfiguration.get().getRpcTtlDays()); | ||
69 | + long expirationTime = System.currentTimeMillis() - ttl; | ||
70 | + | ||
71 | + long totalRemoved = rpcDao.deleteOutdatedRpcByTenantId(tenantId, expirationTime); | ||
72 | + | ||
73 | + if (totalRemoved > 0) { | ||
74 | + log.info("Removed {} outdated rpc(s) for tenant {} older than {}", totalRemoved, tenantId, new Date(expirationTime)); | ||
75 | + } | ||
76 | + } | ||
77 | + | ||
78 | + tenantsBatchRequest = tenantsBatchRequest.nextPageLink(); | ||
79 | + } while (tenantsIds.hasNext()); | ||
80 | + } | ||
81 | + } | ||
82 | + | ||
83 | +} |
@@ -276,6 +276,9 @@ sql: | @@ -276,6 +276,9 @@ sql: | ||
276 | alarms: | 276 | alarms: |
277 | checking_interval: "${SQL_ALARMS_TTL_CHECKING_INTERVAL:7200000}" # Number of milliseconds. The current value corresponds to two hours | 277 | checking_interval: "${SQL_ALARMS_TTL_CHECKING_INTERVAL:7200000}" # Number of milliseconds. The current value corresponds to two hours |
278 | removal_batch_size: "${SQL_ALARMS_TTL_REMOVAL_BATCH_SIZE:3000}" # To delete outdated alarms not all at once but in batches | 278 | removal_batch_size: "${SQL_ALARMS_TTL_REMOVAL_BATCH_SIZE:3000}" # To delete outdated alarms not all at once but in batches |
279 | + rpc: | ||
280 | + enabled: "${SQL_TTL_RPC_ENABLED:true}" | ||
281 | + checking_interval: "${SQL_RPC_TTL_CHECKING_INTERVAL:7200000}" # Number of milliseconds. The current value corresponds to two hours | ||
279 | 282 | ||
280 | # Actor system parameters | 283 | # Actor system parameters |
281 | actors: | 284 | actors: |
@@ -75,13 +75,11 @@ public class X509LwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { | @@ -75,13 +75,11 @@ public class X509LwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { | ||
75 | return device; | 75 | return device; |
76 | } | 76 | } |
77 | 77 | ||
78 | - //TODO: use different endpoints to isolate tests. | ||
79 | - @Ignore() | ||
80 | @Test | 78 | @Test |
81 | public void testConnectAndObserveTelemetry() throws Exception { | 79 | public void testConnectAndObserveTelemetry() throws Exception { |
82 | createDeviceProfile(TRANSPORT_CONFIGURATION); | 80 | createDeviceProfile(TRANSPORT_CONFIGURATION); |
83 | X509ClientCredentials credentials = new X509ClientCredentials(); | 81 | X509ClientCredentials credentials = new X509ClientCredentials(); |
84 | - credentials.setEndpoint(endpoint+1); | 82 | + credentials.setEndpoint(endpoint); |
85 | Device device = createDevice(credentials); | 83 | Device device = createDevice(credentials); |
86 | 84 | ||
87 | SingleEntityFilter sef = new SingleEntityFilter(); | 85 | SingleEntityFilter sef = new SingleEntityFilter(); |
@@ -99,7 +97,7 @@ public class X509LwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { | @@ -99,7 +97,7 @@ public class X509LwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { | ||
99 | wsClient.waitForReply(); | 97 | wsClient.waitForReply(); |
100 | 98 | ||
101 | wsClient.registerWaitForUpdate(); | 99 | wsClient.registerWaitForUpdate(); |
102 | - LwM2MTestClient client = new LwM2MTestClient(executor, endpoint+1); | 100 | + LwM2MTestClient client = new LwM2MTestClient(executor, endpoint); |
103 | Security security = x509(serverUri, 123, clientX509Cert.getEncoded(), clientPrivateKeyFromCert.getEncoded(), serverX509Cert.getEncoded()); | 101 | Security security = x509(serverUri, 123, clientX509Cert.getEncoded(), clientPrivateKeyFromCert.getEncoded(), serverX509Cert.getEncoded()); |
104 | client.init(security, coapConfig); | 102 | client.init(security, coapConfig); |
105 | String msg = wsClient.waitForUpdate(); | 103 | String msg = wsClient.waitForUpdate(); |
@@ -14,7 +14,7 @@ | @@ -14,7 +14,7 @@ | ||
14 | <logger name="org.springframework.boot.test" level="WARN"/> | 14 | <logger name="org.springframework.boot.test" level="WARN"/> |
15 | <logger name="org.apache.cassandra" level="WARN"/> | 15 | <logger name="org.apache.cassandra" level="WARN"/> |
16 | <logger name="org.cassandraunit" level="INFO"/> | 16 | <logger name="org.cassandraunit" level="INFO"/> |
17 | - <logger name="org.eclipse.leshan" level="TRACE"/> | 17 | + <logger name="org.eclipse.leshan" level="INFO"/> |
18 | 18 | ||
19 | 19 | ||
20 | <root level="WARN"> | 20 | <root level="WARN"> |
1 | +/** | ||
2 | + * Copyright © 2016-2021 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.dao.rpc; | ||
17 | + | ||
18 | +import com.google.common.util.concurrent.ListenableFuture; | ||
19 | +import org.thingsboard.server.common.data.id.DeviceId; | ||
20 | +import org.thingsboard.server.common.data.id.RpcId; | ||
21 | +import org.thingsboard.server.common.data.id.TenantId; | ||
22 | +import org.thingsboard.server.common.data.page.PageData; | ||
23 | +import org.thingsboard.server.common.data.page.PageLink; | ||
24 | +import org.thingsboard.server.common.data.rpc.Rpc; | ||
25 | +import org.thingsboard.server.common.data.rpc.RpcStatus; | ||
26 | + | ||
27 | +public interface RpcService { | ||
28 | + Rpc save(Rpc rpc); | ||
29 | + | ||
30 | + void deleteRpc(TenantId tenantId, RpcId id); | ||
31 | + | ||
32 | + void deleteAllRpcByTenantId(TenantId tenantId); | ||
33 | + | ||
34 | + Rpc findById(TenantId tenantId, RpcId id); | ||
35 | + | ||
36 | + ListenableFuture<Rpc> findRpcByIdAsync(TenantId tenantId, RpcId id); | ||
37 | + | ||
38 | + PageData<Rpc> findAllByDeviceIdAndStatus(TenantId tenantId, DeviceId deviceId, RpcStatus rpcStatus, PageLink pageLink); | ||
39 | +} |
@@ -76,6 +76,12 @@ public class DataConstants { | @@ -76,6 +76,12 @@ public class DataConstants { | ||
76 | 76 | ||
77 | public static final String RPC_CALL_FROM_SERVER_TO_DEVICE = "RPC_CALL_FROM_SERVER_TO_DEVICE"; | 77 | public static final String RPC_CALL_FROM_SERVER_TO_DEVICE = "RPC_CALL_FROM_SERVER_TO_DEVICE"; |
78 | 78 | ||
79 | + public static final String RPC_QUEUED = "RPC_QUEUED"; | ||
80 | + public static final String RPC_DELIVERED = "RPC_DELIVERED"; | ||
81 | + public static final String RPC_SUCCESSFUL = "RPC_SUCCESSFUL"; | ||
82 | + public static final String RPC_TIMEOUT = "RPC_TIMEOUT"; | ||
83 | + public static final String RPC_FAILED = "RPC_FAILED"; | ||
84 | + | ||
79 | public static final String DEFAULT_SECRET_KEY = ""; | 85 | public static final String DEFAULT_SECRET_KEY = ""; |
80 | public static final String SECRET_KEY_FIELD_NAME = "secretKey"; | 86 | public static final String SECRET_KEY_FIELD_NAME = "secretKey"; |
81 | public static final String DURATION_MS_FIELD_NAME = "durationMs"; | 87 | public static final String DURATION_MS_FIELD_NAME = "durationMs"; |
@@ -19,5 +19,5 @@ package org.thingsboard.server.common.data; | @@ -19,5 +19,5 @@ package org.thingsboard.server.common.data; | ||
19 | * @author Andrew Shvayka | 19 | * @author Andrew Shvayka |
20 | */ | 20 | */ |
21 | public enum EntityType { | 21 | public enum EntityType { |
22 | - TENANT, CUSTOMER, USER, DASHBOARD, ASSET, DEVICE, ALARM, RULE_CHAIN, RULE_NODE, ENTITY_VIEW, WIDGETS_BUNDLE, WIDGET_TYPE, TENANT_PROFILE, DEVICE_PROFILE, API_USAGE_STATE, TB_RESOURCE, OTA_PACKAGE, EDGE; | 22 | + TENANT, CUSTOMER, USER, DASHBOARD, ASSET, DEVICE, ALARM, RULE_CHAIN, RULE_NODE, ENTITY_VIEW, WIDGETS_BUNDLE, WIDGET_TYPE, TENANT_PROFILE, DEVICE_PROFILE, API_USAGE_STATE, TB_RESOURCE, OTA_PACKAGE, EDGE, RPC; |
23 | } | 23 | } |
@@ -75,6 +75,8 @@ public class EntityIdFactory { | @@ -75,6 +75,8 @@ public class EntityIdFactory { | ||
75 | return new OtaPackageId(uuid); | 75 | return new OtaPackageId(uuid); |
76 | case EDGE: | 76 | case EDGE: |
77 | return new EdgeId(uuid); | 77 | return new EdgeId(uuid); |
78 | + case RPC: | ||
79 | + return new RpcId(uuid); | ||
78 | } | 80 | } |
79 | throw new IllegalArgumentException("EntityType " + type + " is not supported!"); | 81 | throw new IllegalArgumentException("EntityType " + type + " is not supported!"); |
80 | } | 82 | } |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data.id; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.annotation.JsonCreator; | ||
19 | +import com.fasterxml.jackson.annotation.JsonIgnore; | ||
20 | +import com.fasterxml.jackson.annotation.JsonProperty; | ||
21 | +import org.thingsboard.server.common.data.EntityType; | ||
22 | + | ||
23 | +import java.util.UUID; | ||
24 | + | ||
25 | +public final class RpcId extends UUIDBased implements EntityId { | ||
26 | + | ||
27 | + private static final long serialVersionUID = 1L; | ||
28 | + | ||
29 | + @JsonCreator | ||
30 | + public RpcId(@JsonProperty("id") UUID id) { | ||
31 | + super(id); | ||
32 | + } | ||
33 | + | ||
34 | + @JsonIgnore | ||
35 | + @Override | ||
36 | + public EntityType getEntityType() { | ||
37 | + return EntityType.RPC; | ||
38 | + } | ||
39 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data.rpc; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.databind.JsonNode; | ||
19 | +import lombok.Data; | ||
20 | +import lombok.EqualsAndHashCode; | ||
21 | +import org.thingsboard.server.common.data.BaseData; | ||
22 | +import org.thingsboard.server.common.data.HasTenantId; | ||
23 | +import org.thingsboard.server.common.data.id.DeviceId; | ||
24 | +import org.thingsboard.server.common.data.id.RpcId; | ||
25 | +import org.thingsboard.server.common.data.id.TenantId; | ||
26 | + | ||
27 | +@Data | ||
28 | +@EqualsAndHashCode(callSuper = true) | ||
29 | +public class Rpc extends BaseData<RpcId> implements HasTenantId { | ||
30 | + private TenantId tenantId; | ||
31 | + private DeviceId deviceId; | ||
32 | + private long expirationTime; | ||
33 | + private JsonNode request; | ||
34 | + private JsonNode response; | ||
35 | + private RpcStatus status; | ||
36 | + | ||
37 | + public Rpc() { | ||
38 | + super(); | ||
39 | + } | ||
40 | + | ||
41 | + public Rpc(RpcId id) { | ||
42 | + super(id); | ||
43 | + } | ||
44 | + | ||
45 | + public Rpc(Rpc rpc) { | ||
46 | + super(rpc); | ||
47 | + this.tenantId = rpc.getTenantId(); | ||
48 | + this.deviceId = rpc.getDeviceId(); | ||
49 | + this.expirationTime = rpc.getExpirationTime(); | ||
50 | + this.request = rpc.getRequest(); | ||
51 | + this.response = rpc.getResponse(); | ||
52 | + this.status = rpc.getStatus(); | ||
53 | + } | ||
54 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data.rpc; | ||
17 | + | ||
18 | +public enum RpcStatus { | ||
19 | + QUEUED, DELIVERED, SUCCESSFUL, TIMEOUT, FAILED | ||
20 | +} |
@@ -56,6 +56,7 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura | @@ -56,6 +56,7 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura | ||
56 | 56 | ||
57 | private int defaultStorageTtlDays; | 57 | private int defaultStorageTtlDays; |
58 | private int alarmsTtlDays; | 58 | private int alarmsTtlDays; |
59 | + private int rpcTtlDays; | ||
59 | 60 | ||
60 | private double warnThreshold; | 61 | private double warnThreshold; |
61 | 62 |
@@ -34,5 +34,6 @@ public class ToDeviceRpcRequest implements Serializable { | @@ -34,5 +34,6 @@ public class ToDeviceRpcRequest implements Serializable { | ||
34 | private final boolean oneway; | 34 | private final boolean oneway; |
35 | private final long expirationTime; | 35 | private final long expirationTime; |
36 | private final ToDeviceRpcRequestBody body; | 36 | private final ToDeviceRpcRequestBody body; |
37 | + private final boolean persisted; | ||
37 | } | 38 | } |
38 | 39 |
@@ -318,6 +318,9 @@ message SubscribeToRPCMsg { | @@ -318,6 +318,9 @@ message SubscribeToRPCMsg { | ||
318 | SessionType sessionType = 2; | 318 | SessionType sessionType = 2; |
319 | } | 319 | } |
320 | 320 | ||
321 | +message SendPendingRPCMsg { | ||
322 | +} | ||
323 | + | ||
321 | message ToDeviceRpcRequestMsg { | 324 | message ToDeviceRpcRequestMsg { |
322 | int32 requestId = 1; | 325 | int32 requestId = 1; |
323 | string methodName = 2; | 326 | string methodName = 2; |
@@ -325,6 +328,8 @@ message ToDeviceRpcRequestMsg { | @@ -325,6 +328,8 @@ message ToDeviceRpcRequestMsg { | ||
325 | int64 expirationTime = 4; | 328 | int64 expirationTime = 4; |
326 | int64 requestIdMSB = 5; | 329 | int64 requestIdMSB = 5; |
327 | int64 requestIdLSB = 6; | 330 | int64 requestIdLSB = 6; |
331 | + bool oneway = 7; | ||
332 | + bool persisted = 8; | ||
328 | } | 333 | } |
329 | 334 | ||
330 | message ToDeviceRpcResponseMsg { | 335 | message ToDeviceRpcResponseMsg { |
@@ -332,6 +337,13 @@ message ToDeviceRpcResponseMsg { | @@ -332,6 +337,13 @@ message ToDeviceRpcResponseMsg { | ||
332 | string payload = 2; | 337 | string payload = 2; |
333 | } | 338 | } |
334 | 339 | ||
340 | +message ToDevicePersistedRpcResponseMsg { | ||
341 | + int32 requestId = 1; | ||
342 | + int64 requestIdMSB = 2; | ||
343 | + int64 requestIdLSB = 3; | ||
344 | + string status = 4; | ||
345 | +} | ||
346 | + | ||
335 | message ToServerRpcRequestMsg { | 347 | message ToServerRpcRequestMsg { |
336 | int32 requestId = 1; | 348 | int32 requestId = 1; |
337 | string methodName = 2; | 349 | string methodName = 2; |
@@ -435,6 +447,8 @@ message TransportToDeviceActorMsg { | @@ -435,6 +447,8 @@ message TransportToDeviceActorMsg { | ||
435 | SubscriptionInfoProto subscriptionInfo = 7; | 447 | SubscriptionInfoProto subscriptionInfo = 7; |
436 | ClaimDeviceMsg claimDevice = 8; | 448 | ClaimDeviceMsg claimDevice = 8; |
437 | ProvisionDeviceRequestMsg provisionDevice = 9; | 449 | ProvisionDeviceRequestMsg provisionDevice = 9; |
450 | + ToDevicePersistedRpcResponseMsg persistedRpcResponseMsg = 10; | ||
451 | + SendPendingRPCMsg sendPendingRPC = 11; | ||
438 | } | 452 | } |
439 | 453 | ||
440 | message TransportToRuleEngineMsg { | 454 | message TransportToRuleEngineMsg { |
common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java
@@ -44,6 +44,7 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportC | @@ -44,6 +44,7 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportC | ||
44 | import org.thingsboard.server.common.data.device.profile.JsonTransportPayloadConfiguration; | 44 | import org.thingsboard.server.common.data.device.profile.JsonTransportPayloadConfiguration; |
45 | import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; | 45 | import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; |
46 | import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; | 46 | import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; |
47 | +import org.thingsboard.server.common.data.rpc.RpcStatus; | ||
47 | import org.thingsboard.server.common.data.security.DeviceTokenCredentials; | 48 | import org.thingsboard.server.common.data.security.DeviceTokenCredentials; |
48 | import org.thingsboard.server.common.msg.session.FeatureType; | 49 | import org.thingsboard.server.common.msg.session.FeatureType; |
49 | import org.thingsboard.server.common.msg.session.SessionMsgType; | 50 | import org.thingsboard.server.common.msg.session.SessionMsgType; |
@@ -332,14 +333,14 @@ public class CoapTransportResource extends AbstractCoapTransportResource { | @@ -332,14 +333,14 @@ public class CoapTransportResource extends AbstractCoapTransportResource { | ||
332 | break; | 333 | break; |
333 | case TO_SERVER_RPC_REQUEST: | 334 | case TO_SERVER_RPC_REQUEST: |
334 | transportService.registerSyncSession(sessionInfo, getCoapSessionListener(exchange, coapTransportAdaptor, | 335 | transportService.registerSyncSession(sessionInfo, getCoapSessionListener(exchange, coapTransportAdaptor, |
335 | - transportConfigurationContainer.getRpcRequestDynamicMessageBuilder()), timeout); | 336 | + transportConfigurationContainer.getRpcRequestDynamicMessageBuilder(), sessionInfo), timeout); |
336 | transportService.process(sessionInfo, | 337 | transportService.process(sessionInfo, |
337 | coapTransportAdaptor.convertToServerRpcRequest(sessionId, request), | 338 | coapTransportAdaptor.convertToServerRpcRequest(sessionId, request), |
338 | new CoapNoOpCallback(exchange)); | 339 | new CoapNoOpCallback(exchange)); |
339 | break; | 340 | break; |
340 | case GET_ATTRIBUTES_REQUEST: | 341 | case GET_ATTRIBUTES_REQUEST: |
341 | transportService.registerSyncSession(sessionInfo, getCoapSessionListener(exchange, coapTransportAdaptor, | 342 | transportService.registerSyncSession(sessionInfo, getCoapSessionListener(exchange, coapTransportAdaptor, |
342 | - transportConfigurationContainer.getRpcRequestDynamicMessageBuilder()), timeout); | 343 | + transportConfigurationContainer.getRpcRequestDynamicMessageBuilder(), sessionInfo), timeout); |
343 | transportService.process(sessionInfo, | 344 | transportService.process(sessionInfo, |
344 | coapTransportAdaptor.convertToGetAttributes(sessionId, request), | 345 | coapTransportAdaptor.convertToGetAttributes(sessionId, request), |
345 | new CoapNoOpCallback(exchange)); | 346 | new CoapNoOpCallback(exchange)); |
@@ -362,12 +363,12 @@ public class CoapTransportResource extends AbstractCoapTransportResource { | @@ -362,12 +363,12 @@ public class CoapTransportResource extends AbstractCoapTransportResource { | ||
362 | 363 | ||
363 | private void registerAsyncCoapSession(CoapExchange exchange, TransportProtos.SessionInfoProto sessionInfo, CoapTransportAdaptor coapTransportAdaptor, DynamicMessage.Builder rpcRequestDynamicMessageBuilder, String token) { | 364 | private void registerAsyncCoapSession(CoapExchange exchange, TransportProtos.SessionInfoProto sessionInfo, CoapTransportAdaptor coapTransportAdaptor, DynamicMessage.Builder rpcRequestDynamicMessageBuilder, String token) { |
364 | tokenToSessionInfoMap.putIfAbsent(token, sessionInfo); | 365 | tokenToSessionInfoMap.putIfAbsent(token, sessionInfo); |
365 | - transportService.registerAsyncSession(sessionInfo, getCoapSessionListener(exchange, coapTransportAdaptor, rpcRequestDynamicMessageBuilder)); | 366 | + transportService.registerAsyncSession(sessionInfo, getCoapSessionListener(exchange, coapTransportAdaptor, rpcRequestDynamicMessageBuilder, sessionInfo)); |
366 | transportService.process(sessionInfo, getSessionEventMsg(TransportProtos.SessionEvent.OPEN), null); | 367 | transportService.process(sessionInfo, getSessionEventMsg(TransportProtos.SessionEvent.OPEN), null); |
367 | } | 368 | } |
368 | 369 | ||
369 | - private CoapSessionListener getCoapSessionListener(CoapExchange exchange, CoapTransportAdaptor coapTransportAdaptor, DynamicMessage.Builder rpcRequestDynamicMessageBuilder) { | ||
370 | - return new CoapSessionListener(this, exchange, coapTransportAdaptor, rpcRequestDynamicMessageBuilder); | 370 | + private CoapSessionListener getCoapSessionListener(CoapExchange exchange, CoapTransportAdaptor coapTransportAdaptor, DynamicMessage.Builder rpcRequestDynamicMessageBuilder, TransportProtos.SessionInfoProto sessionInfo) { |
371 | + return new CoapSessionListener(this, exchange, coapTransportAdaptor, rpcRequestDynamicMessageBuilder, sessionInfo); | ||
371 | } | 372 | } |
372 | 373 | ||
373 | private String getTokenFromRequest(Request request) { | 374 | private String getTokenFromRequest(Request request) { |
@@ -455,12 +456,14 @@ public class CoapTransportResource extends AbstractCoapTransportResource { | @@ -455,12 +456,14 @@ public class CoapTransportResource extends AbstractCoapTransportResource { | ||
455 | private final CoapExchange exchange; | 456 | private final CoapExchange exchange; |
456 | private final CoapTransportAdaptor coapTransportAdaptor; | 457 | private final CoapTransportAdaptor coapTransportAdaptor; |
457 | private final DynamicMessage.Builder rpcRequestDynamicMessageBuilder; | 458 | private final DynamicMessage.Builder rpcRequestDynamicMessageBuilder; |
459 | + private final TransportProtos.SessionInfoProto sessionInfo; | ||
458 | 460 | ||
459 | - CoapSessionListener(CoapTransportResource coapTransportResource, CoapExchange exchange, CoapTransportAdaptor coapTransportAdaptor, DynamicMessage.Builder rpcRequestDynamicMessageBuilder) { | 461 | + CoapSessionListener(CoapTransportResource coapTransportResource, CoapExchange exchange, CoapTransportAdaptor coapTransportAdaptor, DynamicMessage.Builder rpcRequestDynamicMessageBuilder, TransportProtos.SessionInfoProto sessionInfo) { |
460 | this.coapTransportResource = coapTransportResource; | 462 | this.coapTransportResource = coapTransportResource; |
461 | this.exchange = exchange; | 463 | this.exchange = exchange; |
462 | this.coapTransportAdaptor = coapTransportAdaptor; | 464 | this.coapTransportAdaptor = coapTransportAdaptor; |
463 | this.rpcRequestDynamicMessageBuilder = rpcRequestDynamicMessageBuilder; | 465 | this.rpcRequestDynamicMessageBuilder = rpcRequestDynamicMessageBuilder; |
466 | + this.sessionInfo = sessionInfo; | ||
464 | } | 467 | } |
465 | 468 | ||
466 | @Override | 469 | @Override |
@@ -503,11 +506,31 @@ public class CoapTransportResource extends AbstractCoapTransportResource { | @@ -503,11 +506,31 @@ public class CoapTransportResource extends AbstractCoapTransportResource { | ||
503 | 506 | ||
504 | @Override | 507 | @Override |
505 | public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg msg) { | 508 | public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg msg) { |
509 | + boolean successful; | ||
506 | try { | 510 | try { |
507 | exchange.respond(coapTransportAdaptor.convertToPublish(isConRequest(), msg, rpcRequestDynamicMessageBuilder)); | 511 | exchange.respond(coapTransportAdaptor.convertToPublish(isConRequest(), msg, rpcRequestDynamicMessageBuilder)); |
512 | + successful = true; | ||
508 | } catch (AdaptorException e) { | 513 | } catch (AdaptorException e) { |
509 | log.trace("Failed to reply due to error", e); | 514 | log.trace("Failed to reply due to error", e); |
510 | exchange.respond(CoAP.ResponseCode.INTERNAL_SERVER_ERROR); | 515 | exchange.respond(CoAP.ResponseCode.INTERNAL_SERVER_ERROR); |
516 | + successful = false; | ||
517 | + } | ||
518 | + if (msg.getPersisted()) { | ||
519 | + RpcStatus status; | ||
520 | + if (!successful) { | ||
521 | + status = RpcStatus.FAILED; | ||
522 | + } else if (msg.getOneway()) { | ||
523 | + status = RpcStatus.SUCCESSFUL; | ||
524 | + } else { | ||
525 | + status = RpcStatus.DELIVERED; | ||
526 | + } | ||
527 | + TransportProtos.ToDevicePersistedRpcResponseMsg responseMsg = TransportProtos.ToDevicePersistedRpcResponseMsg.newBuilder() | ||
528 | + .setRequestId(msg.getRequestId()) | ||
529 | + .setRequestIdLSB(msg.getRequestIdLSB()) | ||
530 | + .setRequestIdMSB(msg.getRequestIdMSB()) | ||
531 | + .setStatus(status.name()) | ||
532 | + .build(); | ||
533 | + coapTransportResource.transportService.process(sessionInfo, responseMsg, TransportServiceCallback.EMPTY); | ||
511 | } | 534 | } |
512 | } | 535 | } |
513 | 536 |
@@ -18,11 +18,12 @@ package org.thingsboard.server.transport.coap; | @@ -18,11 +18,12 @@ package org.thingsboard.server.transport.coap; | ||
18 | import lombok.extern.slf4j.Slf4j; | 18 | import lombok.extern.slf4j.Slf4j; |
19 | import org.eclipse.californium.core.CoapResource; | 19 | import org.eclipse.californium.core.CoapResource; |
20 | import org.eclipse.californium.core.CoapServer; | 20 | import org.eclipse.californium.core.CoapServer; |
21 | +import org.eclipse.californium.core.network.config.NetworkConfig; | ||
21 | import org.springframework.beans.factory.annotation.Autowired; | 22 | import org.springframework.beans.factory.annotation.Autowired; |
22 | import org.springframework.stereotype.Service; | 23 | import org.springframework.stereotype.Service; |
23 | -import org.thingsboard.server.common.data.TbTransportService; | ||
24 | import org.thingsboard.server.coapserver.CoapServerService; | 24 | import org.thingsboard.server.coapserver.CoapServerService; |
25 | import org.thingsboard.server.coapserver.TbCoapServerComponent; | 25 | import org.thingsboard.server.coapserver.TbCoapServerComponent; |
26 | +import org.thingsboard.server.common.data.TbTransportService; | ||
26 | import org.thingsboard.server.common.data.ota.OtaPackageType; | 27 | import org.thingsboard.server.common.data.ota.OtaPackageType; |
27 | import org.thingsboard.server.transport.coap.efento.CoapEfentoTransportResource; | 28 | import org.thingsboard.server.transport.coap.efento.CoapEfentoTransportResource; |
28 | 29 | ||
@@ -30,6 +31,8 @@ import javax.annotation.PostConstruct; | @@ -30,6 +31,8 @@ import javax.annotation.PostConstruct; | ||
30 | import javax.annotation.PreDestroy; | 31 | import javax.annotation.PreDestroy; |
31 | import java.net.UnknownHostException; | 32 | import java.net.UnknownHostException; |
32 | 33 | ||
34 | +import static org.eclipse.californium.core.network.config.NetworkConfigDefaults.DEFAULT_BLOCKWISE_STATUS_LIFETIME; | ||
35 | + | ||
33 | @Service("CoapTransportService") | 36 | @Service("CoapTransportService") |
34 | @TbCoapServerComponent | 37 | @TbCoapServerComponent |
35 | @Slf4j | 38 | @Slf4j |
@@ -52,6 +55,14 @@ public class CoapTransportService implements TbTransportService { | @@ -52,6 +55,14 @@ public class CoapTransportService implements TbTransportService { | ||
52 | public void init() throws UnknownHostException { | 55 | public void init() throws UnknownHostException { |
53 | log.info("Starting CoAP transport..."); | 56 | log.info("Starting CoAP transport..."); |
54 | coapServer = coapServerService.getCoapServer(); | 57 | coapServer = coapServerService.getCoapServer(); |
58 | + coapServer.getConfig().setBoolean(NetworkConfig.Keys.BLOCKWISE_STRICT_BLOCK2_OPTION, true); | ||
59 | + coapServer.getConfig().setBoolean(NetworkConfig.Keys.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true); | ||
60 | + coapServer.getConfig().setLong(NetworkConfig.Keys.BLOCKWISE_STATUS_LIFETIME, DEFAULT_BLOCKWISE_STATUS_LIFETIME); | ||
61 | + coapServer.getConfig().setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE, 256 * 1024 * 1024); | ||
62 | + coapServer.getConfig().setString(NetworkConfig.Keys.RESPONSE_MATCHING, "RELAXED"); | ||
63 | + coapServer.getConfig().setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE, 1024); | ||
64 | + coapServer.getConfig().setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE, 1024); | ||
65 | + coapServer.getConfig().setInt(NetworkConfig.Keys.MAX_RETRANSMIT, 10); | ||
55 | CoapResource api = new CoapResource(API); | 66 | CoapResource api = new CoapResource(API); |
56 | api.add(new CoapTransportResource(coapTransportContext, coapServerService, V1)); | 67 | api.add(new CoapTransportResource(coapTransportContext, coapServerService, V1)); |
57 | 68 |
@@ -24,6 +24,7 @@ import org.eclipse.californium.core.observe.ObserveRelation; | @@ -24,6 +24,7 @@ import org.eclipse.californium.core.observe.ObserveRelation; | ||
24 | import org.eclipse.californium.core.server.resources.CoapExchange; | 24 | import org.eclipse.californium.core.server.resources.CoapExchange; |
25 | import org.eclipse.californium.core.server.resources.Resource; | 25 | import org.eclipse.californium.core.server.resources.Resource; |
26 | import org.eclipse.californium.core.server.resources.ResourceObserver; | 26 | import org.eclipse.californium.core.server.resources.ResourceObserver; |
27 | +import org.thingsboard.common.util.ThingsBoardExecutors; | ||
27 | import org.thingsboard.server.common.data.DeviceTransportType; | 28 | import org.thingsboard.server.common.data.DeviceTransportType; |
28 | import org.thingsboard.server.common.data.StringUtils; | 29 | import org.thingsboard.server.common.data.StringUtils; |
29 | import org.thingsboard.server.common.data.ota.OtaPackageType; | 30 | import org.thingsboard.server.common.data.ota.OtaPackageType; |
@@ -34,6 +35,7 @@ import org.thingsboard.server.gen.transport.TransportProtos; | @@ -34,6 +35,7 @@ import org.thingsboard.server.gen.transport.TransportProtos; | ||
34 | import java.util.List; | 35 | import java.util.List; |
35 | import java.util.Optional; | 36 | import java.util.Optional; |
36 | import java.util.UUID; | 37 | import java.util.UUID; |
38 | +import java.util.concurrent.ExecutorService; | ||
37 | 39 | ||
38 | @Slf4j | 40 | @Slf4j |
39 | public class OtaPackageTransportResource extends AbstractCoapTransportResource { | 41 | public class OtaPackageTransportResource extends AbstractCoapTransportResource { |
@@ -43,9 +45,9 @@ public class OtaPackageTransportResource extends AbstractCoapTransportResource { | @@ -43,9 +45,9 @@ public class OtaPackageTransportResource extends AbstractCoapTransportResource { | ||
43 | 45 | ||
44 | public OtaPackageTransportResource(CoapTransportContext ctx, OtaPackageType otaPackageType) { | 46 | public OtaPackageTransportResource(CoapTransportContext ctx, OtaPackageType otaPackageType) { |
45 | super(ctx, otaPackageType.getKeyPrefix()); | 47 | super(ctx, otaPackageType.getKeyPrefix()); |
46 | - this.setObservable(true); | ||
47 | - this.addObserver(new OtaPackageTransportResource.CoapResourceObserver()); | ||
48 | this.otaPackageType = otaPackageType; | 48 | this.otaPackageType = otaPackageType; |
49 | + | ||
50 | + this.setObservable(true); | ||
49 | } | 51 | } |
50 | 52 | ||
51 | @Override | 53 | @Override |
@@ -138,43 +140,10 @@ public class OtaPackageTransportResource extends AbstractCoapTransportResource { | @@ -138,43 +140,10 @@ public class OtaPackageTransportResource extends AbstractCoapTransportResource { | ||
138 | response.setPayload(data); | 140 | response.setPayload(data); |
139 | if (exchange.getRequestOptions().getBlock2() != null) { | 141 | if (exchange.getRequestOptions().getBlock2() != null) { |
140 | int chunkSize = exchange.getRequestOptions().getBlock2().getSzx(); | 142 | int chunkSize = exchange.getRequestOptions().getBlock2().getSzx(); |
141 | - boolean lastFlag = data.length > chunkSize; | ||
142 | - response.getOptions().setUriPath(exchange.getRequestOptions().getUriPathString()); | 143 | + boolean lastFlag = data.length <= chunkSize; |
143 | response.getOptions().setBlock2(chunkSize, lastFlag, 0); | 144 | response.getOptions().setBlock2(chunkSize, lastFlag, 0); |
144 | } | 145 | } |
145 | - exchange.respond(response); | ||
146 | - } | ||
147 | - } | ||
148 | - | ||
149 | - public class CoapResourceObserver implements ResourceObserver { | ||
150 | - @Override | ||
151 | - public void changedName(String old) { | ||
152 | - | ||
153 | - } | ||
154 | - | ||
155 | - @Override | ||
156 | - public void changedPath(String old) { | ||
157 | - | ||
158 | - } | ||
159 | - | ||
160 | - @Override | ||
161 | - public void addedChild(Resource child) { | ||
162 | - | ||
163 | - } | ||
164 | - | ||
165 | - @Override | ||
166 | - public void removedChild(Resource child) { | ||
167 | - | ||
168 | - } | ||
169 | - | ||
170 | - @Override | ||
171 | - public void addedObserveRelation(ObserveRelation relation) { | ||
172 | - | ||
173 | - } | ||
174 | - | ||
175 | - @Override | ||
176 | - public void removedObserveRelation(ObserveRelation relation) { | ||
177 | - | 146 | + transportContext.getExecutor().submit(() -> exchange.respond(response)); |
178 | } | 147 | } |
179 | } | 148 | } |
180 | 149 |
@@ -17,6 +17,7 @@ package org.thingsboard.server.transport.http; | @@ -17,6 +17,7 @@ package org.thingsboard.server.transport.http; | ||
17 | 17 | ||
18 | import com.google.gson.JsonObject; | 18 | import com.google.gson.JsonObject; |
19 | import com.google.gson.JsonParser; | 19 | import com.google.gson.JsonParser; |
20 | +import lombok.RequiredArgsConstructor; | ||
20 | import lombok.extern.slf4j.Slf4j; | 21 | import lombok.extern.slf4j.Slf4j; |
21 | import org.springframework.beans.factory.annotation.Autowired; | 22 | import org.springframework.beans.factory.annotation.Autowired; |
22 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | 23 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
@@ -34,9 +35,10 @@ import org.springframework.web.bind.annotation.RequestParam; | @@ -34,9 +35,10 @@ import org.springframework.web.bind.annotation.RequestParam; | ||
34 | import org.springframework.web.bind.annotation.RestController; | 35 | import org.springframework.web.bind.annotation.RestController; |
35 | import org.springframework.web.context.request.async.DeferredResult; | 36 | import org.springframework.web.context.request.async.DeferredResult; |
36 | import org.thingsboard.server.common.data.DeviceTransportType; | 37 | import org.thingsboard.server.common.data.DeviceTransportType; |
37 | -import org.thingsboard.server.common.data.ota.OtaPackageType; | ||
38 | import org.thingsboard.server.common.data.TbTransportService; | 38 | import org.thingsboard.server.common.data.TbTransportService; |
39 | import org.thingsboard.server.common.data.id.DeviceId; | 39 | import org.thingsboard.server.common.data.id.DeviceId; |
40 | +import org.thingsboard.server.common.data.ota.OtaPackageType; | ||
41 | +import org.thingsboard.server.common.data.rpc.RpcStatus; | ||
40 | import org.thingsboard.server.common.transport.SessionMsgListener; | 42 | import org.thingsboard.server.common.transport.SessionMsgListener; |
41 | import org.thingsboard.server.common.transport.TransportContext; | 43 | import org.thingsboard.server.common.transport.TransportContext; |
42 | import org.thingsboard.server.common.transport.TransportService; | 44 | import org.thingsboard.server.common.transport.TransportService; |
@@ -95,7 +97,9 @@ public class DeviceApiController implements TbTransportService { | @@ -95,7 +97,9 @@ public class DeviceApiController implements TbTransportService { | ||
95 | request.addAllSharedAttributeNames(sharedKeySet); | 97 | request.addAllSharedAttributeNames(sharedKeySet); |
96 | } | 98 | } |
97 | TransportService transportService = transportContext.getTransportService(); | 99 | TransportService transportService = transportContext.getTransportService(); |
98 | - transportService.registerSyncSession(sessionInfo, new HttpSessionListener(responseWriter), transportContext.getDefaultTimeout()); | 100 | + transportService.registerSyncSession(sessionInfo, |
101 | + new HttpSessionListener(responseWriter, transportContext.getTransportService(), sessionInfo), | ||
102 | + transportContext.getDefaultTimeout()); | ||
99 | transportService.process(sessionInfo, request.build(), new SessionCloseOnErrorCallback(transportService, sessionInfo)); | 103 | transportService.process(sessionInfo, request.build(), new SessionCloseOnErrorCallback(transportService, sessionInfo)); |
100 | })); | 104 | })); |
101 | return responseWriter; | 105 | return responseWriter; |
@@ -151,7 +155,8 @@ public class DeviceApiController implements TbTransportService { | @@ -151,7 +155,8 @@ public class DeviceApiController implements TbTransportService { | ||
151 | transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(), | 155 | transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(), |
152 | new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { | 156 | new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { |
153 | TransportService transportService = transportContext.getTransportService(); | 157 | TransportService transportService = transportContext.getTransportService(); |
154 | - transportService.registerSyncSession(sessionInfo, new HttpSessionListener(responseWriter), | 158 | + transportService.registerSyncSession(sessionInfo, |
159 | + new HttpSessionListener(responseWriter, transportContext.getTransportService(), sessionInfo), | ||
155 | timeout == 0 ? transportContext.getDefaultTimeout() : timeout); | 160 | timeout == 0 ? transportContext.getDefaultTimeout() : timeout); |
156 | transportService.process(sessionInfo, SubscribeToRPCMsg.getDefaultInstance(), | 161 | transportService.process(sessionInfo, SubscribeToRPCMsg.getDefaultInstance(), |
157 | new SessionCloseOnErrorCallback(transportService, sessionInfo)); | 162 | new SessionCloseOnErrorCallback(transportService, sessionInfo)); |
@@ -181,7 +186,9 @@ public class DeviceApiController implements TbTransportService { | @@ -181,7 +186,9 @@ public class DeviceApiController implements TbTransportService { | ||
181 | new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { | 186 | new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { |
182 | JsonObject request = new JsonParser().parse(json).getAsJsonObject(); | 187 | JsonObject request = new JsonParser().parse(json).getAsJsonObject(); |
183 | TransportService transportService = transportContext.getTransportService(); | 188 | TransportService transportService = transportContext.getTransportService(); |
184 | - transportService.registerSyncSession(sessionInfo, new HttpSessionListener(responseWriter), transportContext.getDefaultTimeout()); | 189 | + transportService.registerSyncSession(sessionInfo, |
190 | + new HttpSessionListener(responseWriter, transportContext.getTransportService(), sessionInfo), | ||
191 | + transportContext.getDefaultTimeout()); | ||
185 | transportService.process(sessionInfo, ToServerRpcRequestMsg.newBuilder().setRequestId(0) | 192 | transportService.process(sessionInfo, ToServerRpcRequestMsg.newBuilder().setRequestId(0) |
186 | .setMethodName(request.get("method").getAsString()) | 193 | .setMethodName(request.get("method").getAsString()) |
187 | .setParams(request.get("params").toString()).build(), | 194 | .setParams(request.get("params").toString()).build(), |
@@ -198,7 +205,8 @@ public class DeviceApiController implements TbTransportService { | @@ -198,7 +205,8 @@ public class DeviceApiController implements TbTransportService { | ||
198 | transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(), | 205 | transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(), |
199 | new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { | 206 | new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { |
200 | TransportService transportService = transportContext.getTransportService(); | 207 | TransportService transportService = transportContext.getTransportService(); |
201 | - transportService.registerSyncSession(sessionInfo, new HttpSessionListener(responseWriter), | 208 | + transportService.registerSyncSession(sessionInfo, |
209 | + new HttpSessionListener(responseWriter, transportContext.getTransportService(), sessionInfo), | ||
202 | timeout == 0 ? transportContext.getDefaultTimeout() : timeout); | 210 | timeout == 0 ? transportContext.getDefaultTimeout() : timeout); |
203 | transportService.process(sessionInfo, SubscribeToAttributeUpdatesMsg.getDefaultInstance(), | 211 | transportService.process(sessionInfo, SubscribeToAttributeUpdatesMsg.getDefaultInstance(), |
204 | new SessionCloseOnErrorCallback(transportService, sessionInfo)); | 212 | new SessionCloseOnErrorCallback(transportService, sessionInfo)); |
@@ -372,13 +380,12 @@ public class DeviceApiController implements TbTransportService { | @@ -372,13 +380,12 @@ public class DeviceApiController implements TbTransportService { | ||
372 | } | 380 | } |
373 | } | 381 | } |
374 | 382 | ||
383 | + @RequiredArgsConstructor | ||
375 | private static class HttpSessionListener implements SessionMsgListener { | 384 | private static class HttpSessionListener implements SessionMsgListener { |
376 | 385 | ||
377 | private final DeferredResult<ResponseEntity> responseWriter; | 386 | private final DeferredResult<ResponseEntity> responseWriter; |
378 | - | ||
379 | - HttpSessionListener(DeferredResult<ResponseEntity> responseWriter) { | ||
380 | - this.responseWriter = responseWriter; | ||
381 | - } | 387 | + private final TransportService transportService; |
388 | + private final SessionInfoProto sessionInfo; | ||
382 | 389 | ||
383 | @Override | 390 | @Override |
384 | public void onGetAttributesResponse(GetAttributeResponseMsg msg) { | 391 | public void onGetAttributesResponse(GetAttributeResponseMsg msg) { |
@@ -399,6 +406,21 @@ public class DeviceApiController implements TbTransportService { | @@ -399,6 +406,21 @@ public class DeviceApiController implements TbTransportService { | ||
399 | @Override | 406 | @Override |
400 | public void onToDeviceRpcRequest(ToDeviceRpcRequestMsg msg) { | 407 | public void onToDeviceRpcRequest(ToDeviceRpcRequestMsg msg) { |
401 | responseWriter.setResult(new ResponseEntity<>(JsonConverter.toJson(msg, true).toString(), HttpStatus.OK)); | 408 | responseWriter.setResult(new ResponseEntity<>(JsonConverter.toJson(msg, true).toString(), HttpStatus.OK)); |
409 | + if (msg.getPersisted()) { | ||
410 | + RpcStatus status; | ||
411 | + if (msg.getOneway()) { | ||
412 | + status = RpcStatus.SUCCESSFUL; | ||
413 | + } else { | ||
414 | + status = RpcStatus.DELIVERED; | ||
415 | + } | ||
416 | + TransportProtos.ToDevicePersistedRpcResponseMsg responseMsg = TransportProtos.ToDevicePersistedRpcResponseMsg.newBuilder() | ||
417 | + .setRequestId(msg.getRequestId()) | ||
418 | + .setRequestIdLSB(msg.getRequestIdLSB()) | ||
419 | + .setRequestIdMSB(msg.getRequestIdMSB()) | ||
420 | + .setStatus(status.name()) | ||
421 | + .build(); | ||
422 | + transportService.process(sessionInfo, responseMsg, TransportServiceCallback.EMPTY); | ||
423 | + } | ||
402 | } | 424 | } |
403 | 425 | ||
404 | @Override | 426 | @Override |
@@ -29,12 +29,11 @@ import org.springframework.stereotype.Service; | @@ -29,12 +29,11 @@ import org.springframework.stereotype.Service; | ||
29 | import org.thingsboard.common.util.JacksonUtil; | 29 | import org.thingsboard.common.util.JacksonUtil; |
30 | import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfiguration; | 30 | import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfiguration; |
31 | import org.thingsboard.server.gen.transport.TransportProtos; | 31 | import org.thingsboard.server.gen.transport.TransportProtos; |
32 | -import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; | ||
33 | import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; | 32 | import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; |
33 | +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; | ||
34 | import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener; | 34 | import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener; |
35 | import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; | 35 | import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; |
36 | import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; | 36 | import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; |
37 | -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; | ||
38 | 37 | ||
39 | import java.io.IOException; | 38 | import java.io.IOException; |
40 | import java.security.GeneralSecurityException; | 39 | import java.security.GeneralSecurityException; |
@@ -46,6 +45,7 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.L | @@ -46,6 +45,7 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.L | ||
46 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; | 45 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; |
47 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY; | 46 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY; |
48 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getBootstrapParametersFromThingsboard; | 47 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getBootstrapParametersFromThingsboard; |
48 | +import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.BOOTSTRAP; | ||
49 | 49 | ||
50 | @Slf4j | 50 | @Slf4j |
51 | @Service("LwM2MBootstrapSecurityStore") | 51 | @Service("LwM2MBootstrapSecurityStore") |
@@ -68,7 +68,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { | @@ -68,7 +68,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { | ||
68 | 68 | ||
69 | @Override | 69 | @Override |
70 | public Iterator<SecurityInfo> getAllByEndpoint(String endPoint) { | 70 | public Iterator<SecurityInfo> getAllByEndpoint(String endPoint) { |
71 | - TbLwM2MSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfoByCredentialsId(endPoint, LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP); | 71 | + TbLwM2MSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfoByCredentialsId(endPoint, BOOTSTRAP); |
72 | if (store.getBootstrapCredentialConfig() != null && store.getSecurityMode() != null) { | 72 | if (store.getBootstrapCredentialConfig() != null && store.getSecurityMode() != null) { |
73 | /* add value to store from BootstrapJson */ | 73 | /* add value to store from BootstrapJson */ |
74 | this.setBootstrapConfigScurityInfo(store); | 74 | this.setBootstrapConfigScurityInfo(store); |
@@ -92,7 +92,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { | @@ -92,7 +92,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { | ||
92 | 92 | ||
93 | @Override | 93 | @Override |
94 | public SecurityInfo getByIdentity(String identity) { | 94 | public SecurityInfo getByIdentity(String identity) { |
95 | - TbLwM2MSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfoByCredentialsId(identity, LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP); | 95 | + TbLwM2MSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfoByCredentialsId(identity, BOOTSTRAP); |
96 | if (store.getBootstrapCredentialConfig() != null && store.getSecurityMode() != null) { | 96 | if (store.getBootstrapCredentialConfig() != null && store.getSecurityMode() != null) { |
97 | /* add value to store from BootstrapJson */ | 97 | /* add value to store from BootstrapJson */ |
98 | this.setBootstrapConfigScurityInfo(store); | 98 | this.setBootstrapConfigScurityInfo(store); |
@@ -155,7 +155,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { | @@ -155,7 +155,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { | ||
155 | LwM2MServerBootstrap profileLwm2mServer = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getLwm2mServer()), LwM2MServerBootstrap.class); | 155 | LwM2MServerBootstrap profileLwm2mServer = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getLwm2mServer()), LwM2MServerBootstrap.class); |
156 | UUID sessionUUiD = UUID.randomUUID(); | 156 | UUID sessionUUiD = UUID.randomUUID(); |
157 | TransportProtos.SessionInfoProto sessionInfo = helper.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits()); | 157 | TransportProtos.SessionInfoProto sessionInfo = helper.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits()); |
158 | - context.getTransportService().registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(null, null, null, sessionInfo)); | 158 | + context.getTransportService().registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(null, null, null, sessionInfo, context.getTransportService())); |
159 | if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap, lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer)) { | 159 | if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap, lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer)) { |
160 | lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap); | 160 | lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap); |
161 | lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer); | 161 | lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer); |
@@ -142,7 +142,7 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { | @@ -142,7 +142,7 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig { | ||
142 | URI uri = null; | 142 | URI uri = null; |
143 | try { | 143 | try { |
144 | uri = Resources.getResource(keyStorePathFile).toURI(); | 144 | uri = Resources.getResource(keyStorePathFile).toURI(); |
145 | - log.error("URI: {}", uri); | 145 | + log.info("URI: {}", uri); |
146 | File keyStoreFile = new File(uri); | 146 | File keyStoreFile = new File(uri); |
147 | InputStream inKeyStore = new FileInputStream(keyStoreFile); | 147 | InputStream inKeyStore = new FileInputStream(keyStoreFile); |
148 | keyStoreValue = KeyStore.getInstance(keyStoreType); | 148 | keyStoreValue = KeyStore.getInstance(keyStoreType); |
@@ -33,7 +33,7 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; | @@ -33,7 +33,7 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; | ||
33 | import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; | 33 | import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; |
34 | import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials; | 34 | import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials; |
35 | import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; | 35 | import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; |
36 | -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; | 36 | +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer; |
37 | 37 | ||
38 | import java.io.IOException; | 38 | import java.io.IOException; |
39 | import java.security.GeneralSecurityException; | 39 | import java.security.GeneralSecurityException; |
@@ -45,6 +45,7 @@ import static org.eclipse.leshan.core.SecurityMode.NO_SEC; | @@ -45,6 +45,7 @@ import static org.eclipse.leshan.core.SecurityMode.NO_SEC; | ||
45 | import static org.eclipse.leshan.core.SecurityMode.PSK; | 45 | import static org.eclipse.leshan.core.SecurityMode.PSK; |
46 | import static org.eclipse.leshan.core.SecurityMode.RPK; | 46 | import static org.eclipse.leshan.core.SecurityMode.RPK; |
47 | import static org.eclipse.leshan.core.SecurityMode.X509; | 47 | import static org.eclipse.leshan.core.SecurityMode.X509; |
48 | +import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.BOOTSTRAP; | ||
48 | 49 | ||
49 | @Slf4j | 50 | @Slf4j |
50 | @Component | 51 | @Component |
@@ -55,13 +56,15 @@ public class LwM2mCredentialsSecurityInfoValidator { | @@ -55,13 +56,15 @@ public class LwM2mCredentialsSecurityInfoValidator { | ||
55 | private final LwM2mTransportContext context; | 56 | private final LwM2mTransportContext context; |
56 | private final LwM2MTransportServerConfig config; | 57 | private final LwM2MTransportServerConfig config; |
57 | 58 | ||
58 | - public TbLwM2MSecurityInfo getEndpointSecurityInfoByCredentialsId(String credentialsId, LwM2mTransportUtil.LwM2mTypeServer keyValue) { | 59 | + public TbLwM2MSecurityInfo getEndpointSecurityInfoByCredentialsId(String credentialsId, LwM2mTypeServer keyValue) { |
59 | CountDownLatch latch = new CountDownLatch(1); | 60 | CountDownLatch latch = new CountDownLatch(1); |
60 | final TbLwM2MSecurityInfo[] resultSecurityStore = new TbLwM2MSecurityInfo[1]; | 61 | final TbLwM2MSecurityInfo[] resultSecurityStore = new TbLwM2MSecurityInfo[1]; |
62 | + log.trace("Validating credentials [{}]", credentialsId); | ||
61 | context.getTransportService().process(ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(credentialsId).build(), | 63 | context.getTransportService().process(ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(credentialsId).build(), |
62 | new TransportServiceCallback<>() { | 64 | new TransportServiceCallback<>() { |
63 | @Override | 65 | @Override |
64 | public void onSuccess(ValidateDeviceCredentialsResponse msg) { | 66 | public void onSuccess(ValidateDeviceCredentialsResponse msg) { |
67 | + log.trace("Validated credentials: [{}] [{}]", credentialsId, msg); | ||
65 | String credentialsBody = msg.getCredentials(); | 68 | String credentialsBody = msg.getCredentials(); |
66 | resultSecurityStore[0] = createSecurityInfo(credentialsId, credentialsBody, keyValue); | 69 | resultSecurityStore[0] = createSecurityInfo(credentialsId, credentialsBody, keyValue); |
67 | resultSecurityStore[0].setMsg(msg); | 70 | resultSecurityStore[0].setMsg(msg); |
@@ -91,11 +94,11 @@ public class LwM2mCredentialsSecurityInfoValidator { | @@ -91,11 +94,11 @@ public class LwM2mCredentialsSecurityInfoValidator { | ||
91 | * @param keyValue - | 94 | * @param keyValue - |
92 | * @return SecurityInfo | 95 | * @return SecurityInfo |
93 | */ | 96 | */ |
94 | - private TbLwM2MSecurityInfo createSecurityInfo(String endpoint, String jsonStr, LwM2mTransportUtil.LwM2mTypeServer keyValue) { | 97 | + private TbLwM2MSecurityInfo createSecurityInfo(String endpoint, String jsonStr, LwM2mTypeServer keyValue) { |
95 | TbLwM2MSecurityInfo result = new TbLwM2MSecurityInfo(); | 98 | TbLwM2MSecurityInfo result = new TbLwM2MSecurityInfo(); |
96 | LwM2MCredentials credentials = JacksonUtil.fromString(jsonStr, LwM2MCredentials.class); | 99 | LwM2MCredentials credentials = JacksonUtil.fromString(jsonStr, LwM2MCredentials.class); |
97 | if (credentials != null) { | 100 | if (credentials != null) { |
98 | - if (keyValue.equals(LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP)) { | 101 | + if (keyValue.equals(BOOTSTRAP)) { |
99 | result.setBootstrapCredentialConfig(credentials.getBootstrap()); | 102 | result.setBootstrapCredentialConfig(credentials.getBootstrap()); |
100 | if (LwM2MSecurityMode.PSK.equals(credentials.getClient().getSecurityConfigClientMode())) { | 103 | if (LwM2MSecurityMode.PSK.equals(credentials.getClient().getSecurityConfigClientMode())) { |
101 | PSKClientCredentials pskClientConfig = (PSKClientCredentials) credentials.getClient(); | 104 | PSKClientCredentials pskClientConfig = (PSKClientCredentials) credentials.getClient(); |
@@ -42,9 +42,8 @@ import org.thingsboard.server.common.transport.util.SslUtil; | @@ -42,9 +42,8 @@ import org.thingsboard.server.common.transport.util.SslUtil; | ||
42 | import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; | 42 | import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; |
43 | import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; | 43 | import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; |
44 | import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials; | 44 | import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials; |
45 | -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; | ||
46 | -import org.thingsboard.server.transport.lwm2m.server.store.TbEditableSecurityStore; | ||
47 | import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; | 45 | import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; |
46 | +import org.thingsboard.server.transport.lwm2m.server.store.TbMainSecurityStore; | ||
48 | 47 | ||
49 | import javax.annotation.PostConstruct; | 48 | import javax.annotation.PostConstruct; |
50 | import javax.security.auth.x500.X500Principal; | 49 | import javax.security.auth.x500.X500Principal; |
@@ -57,6 +56,8 @@ import java.security.cert.X509Certificate; | @@ -57,6 +56,8 @@ import java.security.cert.X509Certificate; | ||
57 | import java.util.Arrays; | 56 | import java.util.Arrays; |
58 | import java.util.List; | 57 | import java.util.List; |
59 | 58 | ||
59 | +import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.CLIENT; | ||
60 | + | ||
60 | @Slf4j | 61 | @Slf4j |
61 | @Component | 62 | @Component |
62 | @TbLwM2mTransportComponent | 63 | @TbLwM2mTransportComponent |
@@ -66,7 +67,7 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer | @@ -66,7 +67,7 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer | ||
66 | private final TbLwM2MDtlsSessionStore sessionStorage; | 67 | private final TbLwM2MDtlsSessionStore sessionStorage; |
67 | private final LwM2MTransportServerConfig config; | 68 | private final LwM2MTransportServerConfig config; |
68 | private final LwM2mCredentialsSecurityInfoValidator securityInfoValidator; | 69 | private final LwM2mCredentialsSecurityInfoValidator securityInfoValidator; |
69 | - private final TbEditableSecurityStore securityStore; | 70 | + private final TbMainSecurityStore securityStore; |
70 | 71 | ||
71 | @SuppressWarnings("deprecation") | 72 | @SuppressWarnings("deprecation") |
72 | private StaticCertificateVerifier staticCertificateVerifier; | 73 | private StaticCertificateVerifier staticCertificateVerifier; |
@@ -117,7 +118,7 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer | @@ -117,7 +118,7 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer | ||
117 | 118 | ||
118 | String strCert = SslUtil.getCertificateString(cert); | 119 | String strCert = SslUtil.getCertificateString(cert); |
119 | String sha3Hash = EncryptionUtil.getSha3Hash(strCert); | 120 | String sha3Hash = EncryptionUtil.getSha3Hash(strCert); |
120 | - TbLwM2MSecurityInfo securityInfo = securityInfoValidator.getEndpointSecurityInfoByCredentialsId(sha3Hash, LwM2mTransportUtil.LwM2mTypeServer.CLIENT); | 121 | + TbLwM2MSecurityInfo securityInfo = securityInfoValidator.getEndpointSecurityInfoByCredentialsId(sha3Hash, CLIENT); |
121 | ValidateDeviceCredentialsResponse msg = securityInfo != null ? securityInfo.getMsg() : null; | 122 | ValidateDeviceCredentialsResponse msg = securityInfo != null ? securityInfo.getMsg() : null; |
122 | if (msg != null && org.thingsboard.server.common.data.StringUtils.isNotEmpty(msg.getCredentials())) { | 123 | if (msg != null && org.thingsboard.server.common.data.StringUtils.isNotEmpty(msg.getCredentials())) { |
123 | LwM2MCredentials credentials = JacksonUtil.fromString(msg.getCredentials(), LwM2MCredentials.class); | 124 | LwM2MCredentials credentials = JacksonUtil.fromString(msg.getCredentials(), LwM2MCredentials.class); |
@@ -133,7 +134,7 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer | @@ -133,7 +134,7 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer | ||
133 | if (msg.hasDeviceInfo() && deviceProfile != null) { | 134 | if (msg.hasDeviceInfo() && deviceProfile != null) { |
134 | sessionStorage.put(endpoint, new TbX509DtlsSessionInfo(cert.getSubjectX500Principal().getName(), msg)); | 135 | sessionStorage.put(endpoint, new TbX509DtlsSessionInfo(cert.getSubjectX500Principal().getName(), msg)); |
135 | try { | 136 | try { |
136 | - securityStore.put(securityInfo); | 137 | + securityStore.putX509(securityInfo); |
137 | } catch (NonUniqueSecurityInfoException e) { | 138 | } catch (NonUniqueSecurityInfoException e) { |
138 | log.trace("Failed to add security info: {}", securityInfo, e); | 139 | log.trace("Failed to add security info: {}", securityInfo, e); |
139 | } | 140 | } |
@@ -65,7 +65,7 @@ import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE | @@ -65,7 +65,7 @@ import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE | ||
65 | import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256; | 65 | import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256; |
66 | import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CCM_8; | 66 | import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CCM_8; |
67 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mNetworkConfig.getCoapConfig; | 67 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mNetworkConfig.getCoapConfig; |
68 | -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FIRMWARE_UPDATE_COAP_RECOURSE; | 68 | +import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FIRMWARE_UPDATE_COAP_RECOURSE; |
69 | 69 | ||
70 | @Slf4j | 70 | @Slf4j |
71 | @Component | 71 | @Component |
@@ -23,7 +23,10 @@ import org.jetbrains.annotations.NotNull; | @@ -23,7 +23,10 @@ import org.jetbrains.annotations.NotNull; | ||
23 | import org.thingsboard.server.common.data.Device; | 23 | import org.thingsboard.server.common.data.Device; |
24 | import org.thingsboard.server.common.data.DeviceProfile; | 24 | import org.thingsboard.server.common.data.DeviceProfile; |
25 | import org.thingsboard.server.common.data.ResourceType; | 25 | import org.thingsboard.server.common.data.ResourceType; |
26 | +import org.thingsboard.server.common.data.rpc.RpcStatus; | ||
26 | import org.thingsboard.server.common.transport.SessionMsgListener; | 27 | import org.thingsboard.server.common.transport.SessionMsgListener; |
28 | +import org.thingsboard.server.common.transport.TransportService; | ||
29 | +import org.thingsboard.server.common.transport.TransportServiceCallback; | ||
27 | import org.thingsboard.server.gen.transport.TransportProtos; | 30 | import org.thingsboard.server.gen.transport.TransportProtos; |
28 | import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; | 31 | import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; |
29 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; | 32 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; |
@@ -45,6 +48,7 @@ public class LwM2mSessionMsgListener implements GenericFutureListener<Future<? s | @@ -45,6 +48,7 @@ public class LwM2mSessionMsgListener implements GenericFutureListener<Future<? s | ||
45 | private final LwM2MAttributesService attributesService; | 48 | private final LwM2MAttributesService attributesService; |
46 | private final LwM2MRpcRequestHandler rpcHandler; | 49 | private final LwM2MRpcRequestHandler rpcHandler; |
47 | private final TransportProtos.SessionInfoProto sessionInfo; | 50 | private final TransportProtos.SessionInfoProto sessionInfo; |
51 | + private final TransportService transportService; | ||
48 | 52 | ||
49 | @Override | 53 | @Override |
50 | public void onGetAttributesResponse(GetAttributeResponseMsg getAttributesResponse) { | 54 | public void onGetAttributesResponse(GetAttributeResponseMsg getAttributesResponse) { |
@@ -78,7 +82,22 @@ public class LwM2mSessionMsgListener implements GenericFutureListener<Future<? s | @@ -78,7 +82,22 @@ public class LwM2mSessionMsgListener implements GenericFutureListener<Future<? s | ||
78 | 82 | ||
79 | @Override | 83 | @Override |
80 | public void onToDeviceRpcRequest(ToDeviceRpcRequestMsg toDeviceRequest) { | 84 | public void onToDeviceRpcRequest(ToDeviceRpcRequestMsg toDeviceRequest) { |
81 | - this.rpcHandler.onToDeviceRpcRequest(toDeviceRequest,this.sessionInfo); | 85 | + this.rpcHandler.onToDeviceRpcRequest(toDeviceRequest, this.sessionInfo); |
86 | + if (toDeviceRequest.getPersisted()) { | ||
87 | + RpcStatus status; | ||
88 | + if (toDeviceRequest.getOneway()) { | ||
89 | + status = RpcStatus.SUCCESSFUL; | ||
90 | + } else { | ||
91 | + status = RpcStatus.DELIVERED; | ||
92 | + } | ||
93 | + TransportProtos.ToDevicePersistedRpcResponseMsg responseMsg = TransportProtos.ToDevicePersistedRpcResponseMsg.newBuilder() | ||
94 | + .setRequestId(toDeviceRequest.getRequestId()) | ||
95 | + .setRequestIdLSB(toDeviceRequest.getRequestIdLSB()) | ||
96 | + .setRequestIdMSB(toDeviceRequest.getRequestIdMSB()) | ||
97 | + .setStatus(status.name()) | ||
98 | + .build(); | ||
99 | + transportService.process(sessionInfo, responseMsg, TransportServiceCallback.EMPTY); | ||
100 | + } | ||
82 | } | 101 | } |
83 | 102 | ||
84 | @Override | 103 | @Override |
@@ -25,16 +25,14 @@ import org.eclipse.californium.core.server.resources.CoapExchange; | @@ -25,16 +25,14 @@ import org.eclipse.californium.core.server.resources.CoapExchange; | ||
25 | import org.eclipse.californium.core.server.resources.Resource; | 25 | import org.eclipse.californium.core.server.resources.Resource; |
26 | import org.eclipse.californium.core.server.resources.ResourceObserver; | 26 | import org.eclipse.californium.core.server.resources.ResourceObserver; |
27 | import org.thingsboard.server.cache.ota.OtaPackageDataCache; | 27 | import org.thingsboard.server.cache.ota.OtaPackageDataCache; |
28 | -import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler; | ||
29 | -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; | ||
30 | 28 | ||
31 | import java.util.UUID; | 29 | import java.util.UUID; |
32 | import java.util.concurrent.ConcurrentHashMap; | 30 | import java.util.concurrent.ConcurrentHashMap; |
33 | import java.util.concurrent.ConcurrentMap; | 31 | import java.util.concurrent.ConcurrentMap; |
34 | import java.util.concurrent.atomic.AtomicInteger; | 32 | import java.util.concurrent.atomic.AtomicInteger; |
35 | 33 | ||
36 | -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FIRMWARE_UPDATE_COAP_RECOURSE; | ||
37 | -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SOFTWARE_UPDATE_COAP_RECOURSE; | 34 | +import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FIRMWARE_UPDATE_COAP_RECOURSE; |
35 | +import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SOFTWARE_UPDATE_COAP_RECOURSE; | ||
38 | 36 | ||
39 | @Slf4j | 37 | @Slf4j |
40 | public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource { | 38 | public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource { |
@@ -143,7 +141,7 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource { | @@ -143,7 +141,7 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource { | ||
143 | response.setPayload(fwData); | 141 | response.setPayload(fwData); |
144 | if (exchange.getRequestOptions().getBlock2() != null) { | 142 | if (exchange.getRequestOptions().getBlock2() != null) { |
145 | int chunkSize = exchange.getRequestOptions().getBlock2().getSzx(); | 143 | int chunkSize = exchange.getRequestOptions().getBlock2().getSzx(); |
146 | - boolean lastFlag = fwData.length > chunkSize; | 144 | + boolean lastFlag = fwData.length <= chunkSize; |
147 | response.getOptions().setBlock2(chunkSize, lastFlag, 0); | 145 | response.getOptions().setBlock2(chunkSize, lastFlag, 0); |
148 | log.warn("92) with blokc2 Send currentId: [{}], length: [{}], chunkSize [{}], moreFlag [{}]", currentId.toString(), fwData.length, chunkSize, lastFlag); | 146 | log.warn("92) with blokc2 Send currentId: [{}], length: [{}], chunkSize [{}], moreFlag [{}]", currentId.toString(), fwData.length, chunkSize, lastFlag); |
149 | } | 147 | } |
@@ -43,13 +43,13 @@ import org.thingsboard.server.common.data.DeviceTransportType; | @@ -43,13 +43,13 @@ import org.thingsboard.server.common.data.DeviceTransportType; | ||
43 | import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfiguration; | 43 | import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfiguration; |
44 | import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; | 44 | import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; |
45 | import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; | 45 | import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; |
46 | -import org.thingsboard.server.common.data.ota.OtaPackageKey; | ||
47 | -import org.thingsboard.server.common.data.ota.OtaPackageType; | ||
48 | -import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus; | ||
49 | -import org.thingsboard.server.common.data.ota.OtaPackageUtil; | ||
50 | import org.thingsboard.server.common.transport.TransportServiceCallback; | 46 | import org.thingsboard.server.common.transport.TransportServiceCallback; |
51 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; | 47 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; |
52 | import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue; | 48 | import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue; |
49 | +import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateResult; | ||
50 | +import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateState; | ||
51 | +import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateResult; | ||
52 | +import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateState; | ||
53 | import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler; | 53 | import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler; |
54 | 54 | ||
55 | import java.util.ArrayList; | 55 | import java.util.ArrayList; |
@@ -77,277 +77,20 @@ import static org.eclipse.leshan.core.model.ResourceModel.Type.STRING; | @@ -77,277 +77,20 @@ import static org.eclipse.leshan.core.model.ResourceModel.Type.STRING; | ||
77 | import static org.eclipse.leshan.core.model.ResourceModel.Type.TIME; | 77 | import static org.eclipse.leshan.core.model.ResourceModel.Type.TIME; |
78 | import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY; | 78 | import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY; |
79 | import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; | 79 | import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; |
80 | -import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADED; | ||
81 | -import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADING; | ||
82 | -import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.FAILED; | ||
83 | -import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATED; | ||
84 | -import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATING; | ||
85 | -import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.VERIFIED; | 80 | +import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_RESULT_ID; |
81 | +import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_STATE_ID; | ||
82 | +import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SW_RESULT_ID; | ||
83 | +import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SW_UPDATE_STATE_ID; | ||
86 | 84 | ||
87 | @Slf4j | 85 | @Slf4j |
88 | public class LwM2mTransportUtil { | 86 | public class LwM2mTransportUtil { |
89 | 87 | ||
90 | - public static final String EVENT_AWAKE = "AWAKE"; | ||
91 | - public static final String RESPONSE_REQUEST_CHANNEL = "RESP_REQ"; | ||
92 | - public static final String RESPONSE_CHANNEL = "RESP"; | ||
93 | - public static final String OBSERVE_CHANNEL = "OBSERVE"; | ||
94 | - | ||
95 | - public static final String TRANSPORT_DEFAULT_LWM2M_VERSION = "1.0"; | ||
96 | - public static final String CLIENT_LWM2M_SETTINGS = "clientLwM2mSettings"; | ||
97 | - public static final String BOOTSTRAP = "bootstrap"; | ||
98 | - public static final String SERVERS = "servers"; | ||
99 | - public static final String LWM2M_SERVER = "lwm2mServer"; | ||
100 | - public static final String BOOTSTRAP_SERVER = "bootstrapServer"; | ||
101 | - public static final String OBSERVE_ATTRIBUTE_TELEMETRY = "observeAttr"; | ||
102 | - public static final String ATTRIBUTE = "attribute"; | ||
103 | - public static final String TELEMETRY = "telemetry"; | ||
104 | - public static final String KEY_NAME = "keyName"; | ||
105 | - public static final String OBSERVE_LWM2M = "observe"; | ||
106 | - public static final String ATTRIBUTE_LWM2M = "attributeLwm2m"; | ||
107 | - | ||
108 | - private static final String REQUEST = "/request"; | ||
109 | - private static final String ATTRIBUTES = "/" + ATTRIBUTE; | ||
110 | - public static final String TELEMETRIES = "/" + TELEMETRY; | ||
111 | - public static final String ATTRIBUTES_REQUEST = ATTRIBUTES + REQUEST; | ||
112 | - public static final String DEVICE_ATTRIBUTES_REQUEST = ATTRIBUTES_REQUEST + "/"; | ||
113 | - | ||
114 | - public static final long DEFAULT_TIMEOUT = 2 * 60 * 1000L; // 2min in ms | 88 | + public static final String LWM2M_VERSION_DEFAULT = "1.0"; |
115 | 89 | ||
116 | public static final String LOG_LWM2M_TELEMETRY = "logLwm2m"; | 90 | public static final String LOG_LWM2M_TELEMETRY = "logLwm2m"; |
117 | public static final String LOG_LWM2M_INFO = "info"; | 91 | public static final String LOG_LWM2M_INFO = "info"; |
118 | public static final String LOG_LWM2M_ERROR = "error"; | 92 | public static final String LOG_LWM2M_ERROR = "error"; |
119 | public static final String LOG_LWM2M_WARN = "warn"; | 93 | public static final String LOG_LWM2M_WARN = "warn"; |
120 | - public static final String LOG_LWM2M_VALUE = "value"; | ||
121 | - | ||
122 | - public static final String CLIENT_NOT_AUTHORIZED = "Client not authorized"; | ||
123 | - public static final String LWM2M_VERSION_DEFAULT = "1.0"; | ||
124 | - | ||
125 | - // Firmware | ||
126 | - public static final String FIRMWARE_UPDATE_COAP_RECOURSE = "tbfw"; | ||
127 | - public static final String FW_UPDATE = "Firmware update"; | ||
128 | - public static final Integer FW_5_ID = 5; | ||
129 | - public static final Integer FW_19_ID = 19; | ||
130 | - | ||
131 | - // Package W | ||
132 | - public static final String FW_PACKAGE_5_ID = "/5/0/0"; | ||
133 | - public static final String FW_PACKAGE_19_ID = "/19/0/0"; | ||
134 | - // Package URI | ||
135 | - public static final String FW_PACKAGE_URI_ID = "/5/0/1"; | ||
136 | - // State R | ||
137 | - public static final String FW_STATE_ID = "/5/0/3"; | ||
138 | - // Update Result R | ||
139 | - public static final String FW_RESULT_ID = "/5/0/5"; | ||
140 | - | ||
141 | - public static final String FW_DELIVERY_METHOD = "/5/0/9"; | ||
142 | - | ||
143 | - // PkgName R | ||
144 | - public static final String FW_NAME_ID = "/5/0/6"; | ||
145 | - // PkgVersion R | ||
146 | - public static final String FW_5_VER_ID = "/5/0/7"; | ||
147 | - | ||
148 | - /** | ||
149 | - * Quectel@Hi15RM1-HLB_V1.0@BC68JAR01A10,V150R100C20B300SP7,V150R100C20B300SP7@8 | ||
150 | - * BC68JAR01A10 | ||
151 | - * # Request prodct type number | ||
152 | - * ATI | ||
153 | - * Quectel | ||
154 | - * BC68 | ||
155 | - * Revision:BC68JAR01A10 | ||
156 | - */ | ||
157 | - public static final String FW_3_VER_ID = "/3/0/3"; | ||
158 | - // Update E | ||
159 | - public static final String FW_UPDATE_ID = "/5/0/2"; | ||
160 | - | ||
161 | - // Software | ||
162 | - public static final String SOFTWARE_UPDATE_COAP_RECOURSE = "softwareUpdateCoapRecourse"; | ||
163 | - public static final String SW_UPDATE = "Software update"; | ||
164 | - public static final Integer SW_ID = 9; | ||
165 | - // Package W | ||
166 | - public static final String SW_PACKAGE_ID = "/9/0/2"; | ||
167 | - // Package URI | ||
168 | - public static final String SW_PACKAGE_URI_ID = "/9/0/3"; | ||
169 | - // Update State R | ||
170 | - public static final String SW_UPDATE_STATE_ID = "/9/0/7"; | ||
171 | - // Update Result R | ||
172 | - public static final String SW_RESULT_ID = "/9/0/9"; | ||
173 | - // PkgName R | ||
174 | - public static final String SW_NAME_ID = "/9/0/0"; | ||
175 | - // PkgVersion R | ||
176 | - public static final String SW_VER_ID = "/9/0/1"; | ||
177 | - // Install E | ||
178 | - public static final String SW_INSTALL_ID = "/9/0/4"; | ||
179 | - // Uninstall E | ||
180 | - public static final String SW_UN_INSTALL_ID = "/9/0/6"; | ||
181 | - | ||
182 | - public enum LwM2mTypeServer { | ||
183 | - BOOTSTRAP(0, "bootstrap"), | ||
184 | - CLIENT(1, "client"); | ||
185 | - | ||
186 | - public int code; | ||
187 | - public String type; | ||
188 | - | ||
189 | - LwM2mTypeServer(int code, String type) { | ||
190 | - this.code = code; | ||
191 | - this.type = type; | ||
192 | - } | ||
193 | - | ||
194 | - public static LwM2mTypeServer fromLwM2mTypeServer(String type) { | ||
195 | - for (LwM2mTypeServer sm : LwM2mTypeServer.values()) { | ||
196 | - if (sm.type.equals(type)) { | ||
197 | - return sm; | ||
198 | - } | ||
199 | - } | ||
200 | - throw new IllegalArgumentException(String.format("Unsupported typeServer type : %d", type)); | ||
201 | - } | ||
202 | - } | ||
203 | - | ||
204 | - public static Optional<OtaPackageUpdateStatus> toOtaPackageUpdateStatus(UpdateResultFw updateResultFw) { | ||
205 | - switch (updateResultFw) { | ||
206 | - case INITIAL: | ||
207 | - return Optional.empty(); | ||
208 | - case UPDATE_SUCCESSFULLY: | ||
209 | - return Optional.of(UPDATED); | ||
210 | - case NOT_ENOUGH: | ||
211 | - case OUT_OFF_MEMORY: | ||
212 | - case CONNECTION_LOST: | ||
213 | - case INTEGRITY_CHECK_FAILURE: | ||
214 | - case UNSUPPORTED_TYPE: | ||
215 | - case INVALID_URI: | ||
216 | - case UPDATE_FAILED: | ||
217 | - case UNSUPPORTED_PROTOCOL: | ||
218 | - return Optional.of(FAILED); | ||
219 | - default: | ||
220 | - throw new CodecException("Invalid value stateFw %s for FirmwareUpdateStatus.", updateResultFw.name()); | ||
221 | - } | ||
222 | - } | ||
223 | - | ||
224 | - public static Optional<OtaPackageUpdateStatus> toOtaPackageUpdateStatus(UpdateStateFw updateStateFw) { | ||
225 | - switch (updateStateFw) { | ||
226 | - case IDLE: | ||
227 | - return Optional.empty(); | ||
228 | - case DOWNLOADING: | ||
229 | - return Optional.of(DOWNLOADING); | ||
230 | - case DOWNLOADED: | ||
231 | - return Optional.of(DOWNLOADED); | ||
232 | - case UPDATING: | ||
233 | - return Optional.of(UPDATING); | ||
234 | - default: | ||
235 | - throw new CodecException("Invalid value stateFw %d for FirmwareUpdateStatus.", updateStateFw); | ||
236 | - } | ||
237 | - } | ||
238 | - | ||
239 | - /** | ||
240 | - * SW Update State R | ||
241 | - * 0: INITIAL Before downloading. (see 5.1.2.1) | ||
242 | - * 1: DOWNLOAD STARTED The downloading process has started and is on-going. (see 5.1.2.2) | ||
243 | - * 2: DOWNLOADED The package has been completely downloaded (see 5.1.2.3) | ||
244 | - * 3: DELIVERED In that state, the package has been correctly downloaded and is ready to be installed. (see 5.1.2.4) | ||
245 | - * If executing the Install Resource failed, the state remains at DELIVERED. | ||
246 | - * If executing the Install Resource was successful, the state changes from DELIVERED to INSTALLED. | ||
247 | - * After executing the UnInstall Resource, the state changes to INITIAL. | ||
248 | - * 4: INSTALLED | ||
249 | - */ | ||
250 | - public enum UpdateStateSw { | ||
251 | - INITIAL(0, "Initial"), | ||
252 | - DOWNLOAD_STARTED(1, "DownloadStarted"), | ||
253 | - DOWNLOADED(2, "Downloaded"), | ||
254 | - DELIVERED(3, "Delivered"), | ||
255 | - INSTALLED(4, "Installed"); | ||
256 | - | ||
257 | - public int code; | ||
258 | - public String type; | ||
259 | - | ||
260 | - UpdateStateSw(int code, String type) { | ||
261 | - this.code = code; | ||
262 | - this.type = type; | ||
263 | - } | ||
264 | - | ||
265 | - public static UpdateStateSw fromUpdateStateSwByType(String type) { | ||
266 | - for (UpdateStateSw to : UpdateStateSw.values()) { | ||
267 | - if (to.type.equals(type)) { | ||
268 | - return to; | ||
269 | - } | ||
270 | - } | ||
271 | - throw new IllegalArgumentException(String.format("Unsupported SW State type : %s", type)); | ||
272 | - } | ||
273 | - | ||
274 | - public static UpdateStateSw fromUpdateStateSwByCode(int code) { | ||
275 | - for (UpdateStateSw to : UpdateStateSw.values()) { | ||
276 | - if (to.code == code) { | ||
277 | - return to; | ||
278 | - } | ||
279 | - } | ||
280 | - throw new IllegalArgumentException(String.format("Unsupported SW State type : %s", code)); | ||
281 | - } | ||
282 | - } | ||
283 | - | ||
284 | - /** | ||
285 | - * SW Update Result | ||
286 | - * Contains the result of downloading or installing/uninstalling the software | ||
287 | - * 0: Initial value. | ||
288 | - * - Prior to download any new package in the Device, Update Result MUST be reset to this initial value. | ||
289 | - * - One side effect of executing the Uninstall resource is to reset Update Result to this initial value "0". | ||
290 | - * 1: Downloading. | ||
291 | - * - The package downloading process is on-going. | ||
292 | - * 2: Software successfully installed. | ||
293 | - * 3: Successfully Downloaded and package integrity verified | ||
294 | - * (( 4-49, for expansion, of other scenarios)) | ||
295 | - * ** Failed | ||
296 | - * 50: Not enough storage for the new software package. | ||
297 | - * 51: Out of memory during downloading process. | ||
298 | - * 52: Connection lost during downloading process. | ||
299 | - * 53: Package integrity check failure. | ||
300 | - * 54: Unsupported package type. | ||
301 | - * 56: Invalid URI | ||
302 | - * 57: Device defined update error | ||
303 | - * 58: Software installation failure | ||
304 | - * 59: Uninstallation Failure during forUpdate(arg=0) | ||
305 | - * 60-200 : (for expansion, selection to be in blocks depending on new introduction of features) | ||
306 | - * This Resource MAY be reported by sending Observe operation. | ||
307 | - */ | ||
308 | - public enum UpdateResultSw { | ||
309 | - INITIAL(0, "Initial value", false), | ||
310 | - DOWNLOADING(1, "Downloading", false), | ||
311 | - SUCCESSFULLY_INSTALLED(2, "Software successfully installed", false), | ||
312 | - SUCCESSFULLY_DOWNLOADED_VERIFIED(3, "Successfully Downloaded and package integrity verified", false), | ||
313 | - NOT_ENOUGH_STORAGE(50, "Not enough storage for the new software package", true), | ||
314 | - OUT_OFF_MEMORY(51, "Out of memory during downloading process", true), | ||
315 | - CONNECTION_LOST(52, "Connection lost during downloading process", false), | ||
316 | - PACKAGE_CHECK_FAILURE(53, "Package integrity check failure.", false), | ||
317 | - UNSUPPORTED_PACKAGE_TYPE(54, "Unsupported package type", false), | ||
318 | - INVALID_URI(56, "Invalid URI", true), | ||
319 | - UPDATE_ERROR(57, "Device defined update error", true), | ||
320 | - INSTALL_FAILURE(58, "Software installation failure", true), | ||
321 | - UN_INSTALL_FAILURE(59, "Uninstallation Failure during forUpdate(arg=0)", true); | ||
322 | - | ||
323 | - public int code; | ||
324 | - public String type; | ||
325 | - public boolean isAgain; | ||
326 | - | ||
327 | - UpdateResultSw(int code, String type, boolean isAgain) { | ||
328 | - this.code = code; | ||
329 | - this.type = type; | ||
330 | - this.isAgain = isAgain; | ||
331 | - } | ||
332 | - | ||
333 | - public static UpdateResultSw fromUpdateResultSwByType(String type) { | ||
334 | - for (UpdateResultSw to : UpdateResultSw.values()) { | ||
335 | - if (to.type.equals(type)) { | ||
336 | - return to; | ||
337 | - } | ||
338 | - } | ||
339 | - throw new IllegalArgumentException(String.format("Unsupported SW Update Result type : %s", type)); | ||
340 | - } | ||
341 | - | ||
342 | - public static UpdateResultSw fromUpdateResultSwByCode(int code) { | ||
343 | - for (UpdateResultSw to : UpdateResultSw.values()) { | ||
344 | - if (to.code == code) { | ||
345 | - return to; | ||
346 | - } | ||
347 | - } | ||
348 | - throw new IllegalArgumentException(String.format("Unsupported SW Update Result code : %s", code)); | ||
349 | - } | ||
350 | - } | ||
351 | 94 | ||
352 | public enum LwM2MClientStrategy { | 95 | public enum LwM2MClientStrategy { |
353 | CLIENT_STRATEGY_1(1, "Read only resources marked as observation"), | 96 | CLIENT_STRATEGY_1(1, "Read only resources marked as observation"), |
@@ -380,45 +123,7 @@ public class LwM2mTransportUtil { | @@ -380,45 +123,7 @@ public class LwM2mTransportUtil { | ||
380 | } | 123 | } |
381 | } | 124 | } |
382 | 125 | ||
383 | - /** | ||
384 | - * FirmwareUpdateStatus { | ||
385 | - * DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING, UPDATED, FAILED | ||
386 | - */ | ||
387 | - public static OtaPackageUpdateStatus EqualsSwSateToFirmwareUpdateStatus(UpdateStateSw updateStateSw, UpdateResultSw updateResultSw) { | ||
388 | - switch (updateResultSw) { | ||
389 | - case INITIAL: | ||
390 | - switch (updateStateSw) { | ||
391 | - case INITIAL: | ||
392 | - case DOWNLOAD_STARTED: | ||
393 | - return DOWNLOADING; | ||
394 | - case DOWNLOADED: | ||
395 | - return DOWNLOADED; | ||
396 | - case DELIVERED: | ||
397 | - return VERIFIED; | ||
398 | - } | ||
399 | - case DOWNLOADING: | ||
400 | - return DOWNLOADING; | ||
401 | - case SUCCESSFULLY_INSTALLED: | ||
402 | - return UPDATED; | ||
403 | - case SUCCESSFULLY_DOWNLOADED_VERIFIED: | ||
404 | - return VERIFIED; | ||
405 | - case NOT_ENOUGH_STORAGE: | ||
406 | - case OUT_OFF_MEMORY: | ||
407 | - case CONNECTION_LOST: | ||
408 | - case PACKAGE_CHECK_FAILURE: | ||
409 | - case UNSUPPORTED_PACKAGE_TYPE: | ||
410 | - case INVALID_URI: | ||
411 | - case UPDATE_ERROR: | ||
412 | - case INSTALL_FAILURE: | ||
413 | - case UN_INSTALL_FAILURE: | ||
414 | - return FAILED; | ||
415 | - default: | ||
416 | - throw new CodecException("Invalid value stateFw %s %s for FirmwareUpdateStatus.", updateStateSw.name(), updateResultSw.name()); | ||
417 | - } | ||
418 | - } | ||
419 | - | ||
420 | - | ||
421 | - public static boolean equalsResourceValue(Object valueOld, Object valueNew, ResourceModel.Type type, LwM2mPath | 126 | + public static boolean equalsResourceValue(Object valueOld, Object valueNew, ResourceModel.Type type, LwM2mPath |
422 | resourcePath) throws CodecException { | 127 | resourcePath) throws CodecException { |
423 | switch (type) { | 128 | switch (type) { |
424 | case BOOLEAN: | 129 | case BOOLEAN: |
@@ -443,19 +148,19 @@ public class LwM2mTransportUtil { | @@ -443,19 +148,19 @@ public class LwM2mTransportUtil { | ||
443 | if (path != null) { | 148 | if (path != null) { |
444 | if (FW_STATE_ID.equals(path)) { | 149 | if (FW_STATE_ID.equals(path)) { |
445 | lwM2mOtaConvert.setCurrentType(STRING); | 150 | lwM2mOtaConvert.setCurrentType(STRING); |
446 | - lwM2mOtaConvert.setValue(UpdateStateFw.fromStateFwByCode(((Long) value).intValue()).type); | 151 | + lwM2mOtaConvert.setValue(FirmwareUpdateState.fromStateFwByCode(((Long) value).intValue()).type); |
447 | return lwM2mOtaConvert; | 152 | return lwM2mOtaConvert; |
448 | } else if (FW_RESULT_ID.equals(path)) { | 153 | } else if (FW_RESULT_ID.equals(path)) { |
449 | lwM2mOtaConvert.setCurrentType(STRING); | 154 | lwM2mOtaConvert.setCurrentType(STRING); |
450 | - lwM2mOtaConvert.setValue(UpdateResultFw.fromUpdateResultFwByCode(((Long) value).intValue()).getType()); | 155 | + lwM2mOtaConvert.setValue(FirmwareUpdateResult.fromUpdateResultFwByCode(((Long) value).intValue()).getType()); |
451 | return lwM2mOtaConvert; | 156 | return lwM2mOtaConvert; |
452 | } else if (SW_UPDATE_STATE_ID.equals(path)) { | 157 | } else if (SW_UPDATE_STATE_ID.equals(path)) { |
453 | lwM2mOtaConvert.setCurrentType(STRING); | 158 | lwM2mOtaConvert.setCurrentType(STRING); |
454 | - lwM2mOtaConvert.setValue(UpdateStateSw.fromUpdateStateSwByCode(((Long) value).intValue()).type); | 159 | + lwM2mOtaConvert.setValue(SoftwareUpdateState.fromUpdateStateSwByCode(((Long) value).intValue()).type); |
455 | return lwM2mOtaConvert; | 160 | return lwM2mOtaConvert; |
456 | } else if (SW_RESULT_ID.equals(path)) { | 161 | } else if (SW_RESULT_ID.equals(path)) { |
457 | lwM2mOtaConvert.setCurrentType(STRING); | 162 | lwM2mOtaConvert.setCurrentType(STRING); |
458 | - lwM2mOtaConvert.setValue(UpdateResultSw.fromUpdateResultSwByCode(((Long) value).intValue()).type); | 163 | + lwM2mOtaConvert.setValue(SoftwareUpdateResult.fromUpdateResultSwByCode(((Long) value).intValue()).type); |
459 | return lwM2mOtaConvert; | 164 | return lwM2mOtaConvert; |
460 | } | 165 | } |
461 | } | 166 | } |
@@ -477,18 +182,6 @@ public class LwM2mTransportUtil { | @@ -477,18 +182,6 @@ public class LwM2mTransportUtil { | ||
477 | return null; | 182 | return null; |
478 | } | 183 | } |
479 | 184 | ||
480 | -// public static LwM2mClientProfile getNewProfileParameters(JsonObject profilesConfigData, TenantId tenantId) { | ||
481 | -// LwM2mClientProfile lwM2MClientProfile = new LwM2mClientProfile(); | ||
482 | -// lwM2MClientProfile.setTenantId(tenantId); | ||
483 | -// lwM2MClientProfile.setPostClientLwM2mSettings(profilesConfigData.get(CLIENT_LWM2M_SETTINGS).getAsJsonObject()); | ||
484 | -// lwM2MClientProfile.setPostKeyNameProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(KEY_NAME).getAsJsonObject()); | ||
485 | -// lwM2MClientProfile.setPostAttributeProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE).getAsJsonArray()); | ||
486 | -// lwM2MClientProfile.setPostTelemetryProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(TELEMETRY).getAsJsonArray()); | ||
487 | -// lwM2MClientProfile.setPostObserveProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(OBSERVE_LWM2M).getAsJsonArray()); | ||
488 | -// lwM2MClientProfile.setPostAttributeLwm2mProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE_LWM2M).getAsJsonObject()); | ||
489 | -// return lwM2MClientProfile; | ||
490 | -// } | ||
491 | - | ||
492 | public static Lwm2mDeviceProfileTransportConfiguration toLwM2MClientProfile(DeviceProfile deviceProfile) { | 185 | public static Lwm2mDeviceProfileTransportConfiguration toLwM2MClientProfile(DeviceProfile deviceProfile) { |
493 | DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); | 186 | DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); |
494 | if (transportConfiguration.getType().equals(DeviceTransportType.LWM2M)) { | 187 | if (transportConfiguration.getType().equals(DeviceTransportType.LWM2M)) { |
@@ -603,7 +296,6 @@ public class LwM2mTransportUtil { | @@ -603,7 +296,6 @@ public class LwM2mTransportUtil { | ||
603 | if (keyArray.length > 1 && keyArray[1].split(LWM2M_SEPARATOR_KEY).length == 2) { | 296 | if (keyArray.length > 1 && keyArray[1].split(LWM2M_SEPARATOR_KEY).length == 2) { |
604 | return pathIdVer; | 297 | return pathIdVer; |
605 | } else { | 298 | } else { |
606 | - LwM2mPath pathObjId = new LwM2mPath(pathIdVer); | ||
607 | return convertObjectIdToVersionedId(pathIdVer, registration); | 299 | return convertObjectIdToVersionedId(pathIdVer, registration); |
608 | } | 300 | } |
609 | } | 301 | } |
@@ -743,19 +435,6 @@ public class LwM2mTransportUtil { | @@ -743,19 +435,6 @@ public class LwM2mTransportUtil { | ||
743 | } | 435 | } |
744 | } | 436 | } |
745 | 437 | ||
746 | - public static boolean isFwSwWords(String pathName) { | ||
747 | - return OtaPackageUtil.getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.VERSION).equals(pathName) | ||
748 | - || OtaPackageUtil.getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.TITLE).equals(pathName) | ||
749 | - || OtaPackageUtil.getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.CHECKSUM).equals(pathName) | ||
750 | - || OtaPackageUtil.getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.CHECKSUM_ALGORITHM).equals(pathName) | ||
751 | - || OtaPackageUtil.getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.SIZE).equals(pathName) | ||
752 | - || OtaPackageUtil.getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.VERSION).equals(pathName) | ||
753 | - || OtaPackageUtil.getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.TITLE).equals(pathName) | ||
754 | - || OtaPackageUtil.getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.CHECKSUM).equals(pathName) | ||
755 | - || OtaPackageUtil.getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.CHECKSUM_ALGORITHM).equals(pathName) | ||
756 | - || OtaPackageUtil.getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.SIZE).equals(pathName); | ||
757 | - } | ||
758 | - | ||
759 | /** | 438 | /** |
760 | * @param lwM2MClient - | 439 | * @param lwM2MClient - |
761 | * @param path - | 440 | * @param path - |
@@ -33,12 +33,10 @@ import org.eclipse.leshan.server.security.SecurityInfo; | @@ -33,12 +33,10 @@ import org.eclipse.leshan.server.security.SecurityInfo; | ||
33 | import org.thingsboard.server.common.data.Device; | 33 | import org.thingsboard.server.common.data.Device; |
34 | import org.thingsboard.server.common.data.DeviceProfile; | 34 | import org.thingsboard.server.common.data.DeviceProfile; |
35 | import org.thingsboard.server.common.data.id.TenantId; | 35 | import org.thingsboard.server.common.data.id.TenantId; |
36 | -import org.thingsboard.server.common.data.ota.OtaPackageType; | ||
37 | import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; | 36 | import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; |
38 | import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; | 37 | import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; |
39 | import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; | 38 | import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; |
40 | import org.thingsboard.server.transport.lwm2m.server.LwM2mQueuedRequest; | 39 | import org.thingsboard.server.transport.lwm2m.server.LwM2mQueuedRequest; |
41 | -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; | ||
42 | 40 | ||
43 | import java.util.Collection; | 41 | import java.util.Collection; |
44 | import java.util.Map; | 42 | import java.util.Map; |
@@ -53,7 +51,7 @@ import java.util.concurrent.locks.ReentrantLock; | @@ -53,7 +51,7 @@ import java.util.concurrent.locks.ReentrantLock; | ||
53 | import java.util.stream.Collectors; | 51 | import java.util.stream.Collectors; |
54 | 52 | ||
55 | import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; | 53 | import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; |
56 | -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.TRANSPORT_DEFAULT_LWM2M_VERSION; | 54 | +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LWM2M_VERSION_DEFAULT; |
57 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId; | 55 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId; |
58 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.equalsResourceTypeGetSimpleName; | 56 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.equalsResourceTypeGetSimpleName; |
59 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId; | 57 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId; |
@@ -307,7 +305,7 @@ public class LwM2mClient implements Cloneable { | @@ -307,7 +305,7 @@ public class LwM2mClient implements Cloneable { | ||
307 | LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(path)); | 305 | LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(path)); |
308 | String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); | 306 | String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); |
309 | String verRez = getVerFromPathIdVerOrId(path); | 307 | String verRez = getVerFromPathIdVerOrId(path); |
310 | - return verRez == null ? TRANSPORT_DEFAULT_LWM2M_VERSION.equals(verSupportedObject) : verRez.equals(verSupportedObject); | 308 | + return verRez == null ? LWM2M_VERSION_DEFAULT.equals(verSupportedObject) : verRez.equals(verSupportedObject); |
311 | } | 309 | } |
312 | 310 | ||
313 | /** | 311 | /** |
@@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server.client; | @@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server.client; | ||
17 | 17 | ||
18 | import lombok.RequiredArgsConstructor; | 18 | import lombok.RequiredArgsConstructor; |
19 | import lombok.extern.slf4j.Slf4j; | 19 | import lombok.extern.slf4j.Slf4j; |
20 | +import org.eclipse.leshan.core.SecurityMode; | ||
20 | import org.eclipse.leshan.core.model.ResourceModel; | 21 | import org.eclipse.leshan.core.model.ResourceModel; |
21 | import org.eclipse.leshan.core.node.LwM2mPath; | 22 | import org.eclipse.leshan.core.node.LwM2mPath; |
22 | import org.eclipse.leshan.server.registration.Registration; | 23 | import org.eclipse.leshan.server.registration.Registration; |
@@ -30,7 +31,7 @@ import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; | @@ -30,7 +31,7 @@ import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; | ||
30 | import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; | 31 | import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; |
31 | import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; | 32 | import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; |
32 | import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; | 33 | import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; |
33 | -import org.thingsboard.server.transport.lwm2m.server.store.TbEditableSecurityStore; | 34 | +import org.thingsboard.server.transport.lwm2m.server.store.TbMainSecurityStore; |
34 | 35 | ||
35 | import java.util.Arrays; | 36 | import java.util.Arrays; |
36 | import java.util.Collection; | 37 | import java.util.Collection; |
@@ -54,7 +55,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { | @@ -54,7 +55,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { | ||
54 | 55 | ||
55 | private final LwM2mTransportContext context; | 56 | private final LwM2mTransportContext context; |
56 | private final LwM2MTransportServerConfig config; | 57 | private final LwM2MTransportServerConfig config; |
57 | - private final TbEditableSecurityStore securityStore; | 58 | + private final TbMainSecurityStore securityStore; |
58 | private final Map<String, LwM2mClient> lwM2mClientsByEndpoint = new ConcurrentHashMap<>(); | 59 | private final Map<String, LwM2mClient> lwM2mClientsByEndpoint = new ConcurrentHashMap<>(); |
59 | private final Map<String, LwM2mClient> lwM2mClientsByRegistrationId = new ConcurrentHashMap<>(); | 60 | private final Map<String, LwM2mClient> lwM2mClientsByRegistrationId = new ConcurrentHashMap<>(); |
60 | private final Map<UUID, Lwm2mDeviceProfileTransportConfiguration> profiles = new ConcurrentHashMap<>(); | 61 | private final Map<UUID, Lwm2mDeviceProfileTransportConfiguration> profiles = new ConcurrentHashMap<>(); |
@@ -75,6 +76,9 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { | @@ -75,6 +76,9 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { | ||
75 | oldSession = lwM2MClient.getSession(); | 76 | oldSession = lwM2MClient.getSession(); |
76 | TbLwM2MSecurityInfo securityInfo = securityStore.getTbLwM2MSecurityInfoByEndpoint(lwM2MClient.getEndpoint()); | 77 | TbLwM2MSecurityInfo securityInfo = securityStore.getTbLwM2MSecurityInfoByEndpoint(lwM2MClient.getEndpoint()); |
77 | if (securityInfo.getSecurityMode() != null) { | 78 | if (securityInfo.getSecurityMode() != null) { |
79 | + if (SecurityMode.X509.equals(securityInfo.getSecurityMode())) { | ||
80 | + securityStore.registerX509(registration.getEndpoint(), registration.getId()); | ||
81 | + } | ||
78 | if (securityInfo.getDeviceProfile() != null) { | 82 | if (securityInfo.getDeviceProfile() != null) { |
79 | profileUpdate(securityInfo.getDeviceProfile()); | 83 | profileUpdate(securityInfo.getDeviceProfile()); |
80 | if (securityInfo.getSecurityInfo() != null) { | 84 | if (securityInfo.getSecurityInfo() != null) { |
@@ -124,7 +128,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { | @@ -124,7 +128,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { | ||
124 | if (currentRegistration.getId().equals(registration.getId())) { | 128 | if (currentRegistration.getId().equals(registration.getId())) { |
125 | lwM2MClient.setState(LwM2MClientState.UNREGISTERED); | 129 | lwM2MClient.setState(LwM2MClientState.UNREGISTERED); |
126 | lwM2mClientsByEndpoint.remove(lwM2MClient.getEndpoint()); | 130 | lwM2mClientsByEndpoint.remove(lwM2MClient.getEndpoint()); |
127 | - this.securityStore.remove(lwM2MClient.getEndpoint()); | 131 | + this.securityStore.remove(lwM2MClient.getEndpoint(), registration.getId()); |
128 | UUID profileId = lwM2MClient.getProfileId(); | 132 | UUID profileId = lwM2MClient.getProfileId(); |
129 | if (profileId != null) { | 133 | if (profileId != null) { |
130 | Optional<LwM2mClient> otherClients = lwM2mClientsByRegistrationId.values().stream().filter(e -> e.getProfileId().equals(profileId)).findFirst(); | 134 | Optional<LwM2mClient> otherClients = lwM2mClientsByRegistrationId.values().stream().filter(e -> e.getProfileId().equals(profileId)).findFirst(); |
@@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server.ota; | @@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server.ota; | ||
17 | 17 | ||
18 | import lombok.RequiredArgsConstructor; | 18 | import lombok.RequiredArgsConstructor; |
19 | import lombok.extern.slf4j.Slf4j; | 19 | import lombok.extern.slf4j.Slf4j; |
20 | +import org.eclipse.leshan.core.node.codec.CodecException; | ||
20 | import org.eclipse.leshan.core.request.ContentFormat; | 21 | import org.eclipse.leshan.core.request.ContentFormat; |
21 | import org.springframework.beans.factory.annotation.Autowired; | 22 | import org.springframework.beans.factory.annotation.Autowired; |
22 | import org.springframework.context.annotation.Lazy; | 23 | import org.springframework.context.annotation.Lazy; |
@@ -24,6 +25,7 @@ import org.springframework.stereotype.Service; | @@ -24,6 +25,7 @@ import org.springframework.stereotype.Service; | ||
24 | import org.thingsboard.common.util.DonAsynchron; | 25 | import org.thingsboard.common.util.DonAsynchron; |
25 | import org.thingsboard.server.cache.ota.OtaPackageDataCache; | 26 | import org.thingsboard.server.cache.ota.OtaPackageDataCache; |
26 | import org.thingsboard.server.common.data.StringUtils; | 27 | import org.thingsboard.server.common.data.StringUtils; |
28 | +import org.thingsboard.server.common.data.device.data.lwm2m.OtherConfiguration; | ||
27 | import org.thingsboard.server.common.data.ota.OtaPackageKey; | 29 | import org.thingsboard.server.common.data.ota.OtaPackageKey; |
28 | import org.thingsboard.server.common.data.ota.OtaPackageType; | 30 | import org.thingsboard.server.common.data.ota.OtaPackageType; |
29 | import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus; | 31 | import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus; |
@@ -32,11 +34,7 @@ import org.thingsboard.server.common.transport.TransportServiceCallback; | @@ -32,11 +34,7 @@ import org.thingsboard.server.common.transport.TransportServiceCallback; | ||
32 | import org.thingsboard.server.gen.transport.TransportProtos; | 34 | import org.thingsboard.server.gen.transport.TransportProtos; |
33 | import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; | 35 | import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; |
34 | import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; | 36 | import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; |
35 | -import org.thingsboard.server.transport.lwm2m.server.LwM2MFirmwareUpdateStrategy; | ||
36 | import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; | 37 | import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; |
37 | -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; | ||
38 | -import org.thingsboard.server.transport.lwm2m.server.UpdateResultFw; | ||
39 | -import org.thingsboard.server.transport.lwm2m.server.UpdateStateFw; | ||
40 | import org.thingsboard.server.transport.lwm2m.server.attributes.LwM2MAttributesService; | 38 | import org.thingsboard.server.transport.lwm2m.server.attributes.LwM2MAttributesService; |
41 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; | 39 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; |
42 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; | 40 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; |
@@ -47,6 +45,13 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MExecuteRequ | @@ -47,6 +45,13 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MExecuteRequ | ||
47 | import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteReplaceRequest; | 45 | import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteReplaceRequest; |
48 | import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteResponseCallback; | 46 | import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteResponseCallback; |
49 | import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; | 47 | import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; |
48 | +import org.thingsboard.server.transport.lwm2m.server.ota.firmware.LwM2MFirmwareUpdateStrategy; | ||
49 | +import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareDeliveryMethod; | ||
50 | +import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateResult; | ||
51 | +import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateState; | ||
52 | +import org.thingsboard.server.transport.lwm2m.server.ota.software.LwM2MSoftwareUpdateStrategy; | ||
53 | +import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateResult; | ||
54 | +import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateState; | ||
50 | import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; | 55 | import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; |
51 | 56 | ||
52 | import javax.annotation.PostConstruct; | 57 | import javax.annotation.PostConstruct; |
@@ -59,8 +64,13 @@ import java.util.UUID; | @@ -59,8 +64,13 @@ import java.util.UUID; | ||
59 | import java.util.concurrent.ConcurrentHashMap; | 64 | import java.util.concurrent.ConcurrentHashMap; |
60 | 65 | ||
61 | import static org.thingsboard.server.common.data.ota.OtaPackageKey.STATE; | 66 | import static org.thingsboard.server.common.data.ota.OtaPackageKey.STATE; |
67 | +import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADED; | ||
68 | +import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADING; | ||
69 | +import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.FAILED; | ||
70 | +import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATED; | ||
71 | +import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATING; | ||
72 | +import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.VERIFIED; | ||
62 | import static org.thingsboard.server.common.data.ota.OtaPackageUtil.getAttributeKey; | 73 | import static org.thingsboard.server.common.data.ota.OtaPackageUtil.getAttributeKey; |
63 | -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FIRMWARE_UPDATE_COAP_RECOURSE; | ||
64 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY; | 74 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY; |
65 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId; | 75 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId; |
66 | 76 | ||
@@ -77,13 +87,30 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | @@ -77,13 +87,30 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | ||
77 | public static final String SOFTWARE_TITLE = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.TITLE); | 87 | public static final String SOFTWARE_TITLE = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.TITLE); |
78 | public static final String SOFTWARE_URL = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.URL); | 88 | public static final String SOFTWARE_URL = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.URL); |
79 | 89 | ||
90 | + public static final String FIRMWARE_UPDATE_COAP_RECOURSE = "tbfw"; | ||
91 | + public static final String SOFTWARE_UPDATE_COAP_RECOURSE = "tbsw"; | ||
80 | private static final String FW_PACKAGE_5_ID = "/5/0/0"; | 92 | private static final String FW_PACKAGE_5_ID = "/5/0/0"; |
81 | private static final String FW_URL_ID = "/5/0/1"; | 93 | private static final String FW_URL_ID = "/5/0/1"; |
82 | private static final String FW_EXECUTE_ID = "/5/0/2"; | 94 | private static final String FW_EXECUTE_ID = "/5/0/2"; |
83 | - private static final String FW_NAME_ID = "/5/0/6"; | ||
84 | - private static final String FW_VER_ID = "/5/0/7"; | 95 | + public static final String FW_STATE_ID = "/5/0/3"; |
96 | + public static final String FW_RESULT_ID = "/5/0/5"; | ||
97 | + public static final String FW_NAME_ID = "/5/0/6"; | ||
98 | + public static final String FW_5_VER_ID = "/5/0/7"; | ||
99 | + /** | ||
100 | + * Quectel@Hi15RM1-HLB_V1.0@BC68JAR01A10,V150R100C20B300SP7,V150R100C20B300SP7@8 | ||
101 | + * Revision:BC68JAR01A10 | ||
102 | + */ | ||
103 | + public static final String FW_3_VER_ID = "/3/0/3"; | ||
104 | + public static final String FW_DELIVERY_METHOD = "/5/0/9"; | ||
105 | + | ||
85 | private static final String SW_NAME_ID = "/9/0/0"; | 106 | private static final String SW_NAME_ID = "/9/0/0"; |
86 | private static final String SW_VER_ID = "/9/0/1"; | 107 | private static final String SW_VER_ID = "/9/0/1"; |
108 | + public static final String SW_PACKAGE_ID = "/9/0/2"; | ||
109 | + public static final String SW_PACKAGE_URI_ID = "/9/0/3"; | ||
110 | + public static final String SW_INSTALL_ID = "/9/0/4"; | ||
111 | + public static final String SW_UPDATE_STATE_ID = "/9/0/7"; | ||
112 | + public static final String SW_RESULT_ID = "/9/0/9"; | ||
113 | + public static final String SW_UN_INSTALL_ID = "/9/0/6"; | ||
87 | 114 | ||
88 | private final Map<String, LwM2MClientOtaInfo> fwStates = new ConcurrentHashMap<>(); | 115 | private final Map<String, LwM2MClientOtaInfo> fwStates = new ConcurrentHashMap<>(); |
89 | private final Map<String, LwM2MClientOtaInfo> swStates = new ConcurrentHashMap<>(); | 116 | private final Map<String, LwM2MClientOtaInfo> swStates = new ConcurrentHashMap<>(); |
@@ -175,6 +202,24 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | @@ -175,6 +202,24 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | ||
175 | } | 202 | } |
176 | 203 | ||
177 | @Override | 204 | @Override |
205 | + public void onCurrentFirmwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration) { | ||
206 | + log.debug("[{}] Current fw strategy: {}", client.getEndpoint(), configuration.getFwUpdateStrategy()); | ||
207 | + LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client); | ||
208 | + fwInfo.setFwStrategy(LwM2MFirmwareUpdateStrategy.fromStrategyFwByCode(configuration.getFwUpdateStrategy())); | ||
209 | + fwInfo.setBaseUrl(configuration.getFwUpdateRecourse()); | ||
210 | + startFirmwareUpdateIfNeeded(client, fwInfo); | ||
211 | + } | ||
212 | + | ||
213 | + @Override | ||
214 | + public void onCurrentSoftwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration) { | ||
215 | + log.debug("[{}] Current sw strategy: {}", client.getEndpoint(), configuration.getSwUpdateStrategy()); | ||
216 | + LwM2MClientOtaInfo swInfo = getOrInitSwInfo(client); | ||
217 | + swInfo.setSwStrategy(LwM2MSoftwareUpdateStrategy.fromStrategySwByCode(configuration.getSwUpdateStrategy())); | ||
218 | + swInfo.setBaseUrl(configuration.getSwUpdateRecourse()); | ||
219 | + startSoftwareUpdateIfNeeded(client, swInfo); | ||
220 | + } | ||
221 | + | ||
222 | + @Override | ||
178 | public void onCurrentFirmwareVersion3Update(LwM2mClient client, String version) { | 223 | public void onCurrentFirmwareVersion3Update(LwM2mClient client, String version) { |
179 | log.debug("[{}] Current fw version: {}", client.getEndpoint(), version); | 224 | log.debug("[{}] Current fw version: {}", client.getEndpoint(), version); |
180 | LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client); | 225 | LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client); |
@@ -192,12 +237,12 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | @@ -192,12 +237,12 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | ||
192 | public void onCurrentFirmwareStateUpdate(LwM2mClient client, Long stateCode) { | 237 | public void onCurrentFirmwareStateUpdate(LwM2mClient client, Long stateCode) { |
193 | log.debug("[{}] Current fw state: {}", client.getEndpoint(), stateCode); | 238 | log.debug("[{}] Current fw state: {}", client.getEndpoint(), stateCode); |
194 | LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client); | 239 | LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client); |
195 | - UpdateStateFw state = UpdateStateFw.fromStateFwByCode(stateCode.intValue()); | ||
196 | - if (UpdateStateFw.DOWNLOADED.equals(state)) { | 240 | + FirmwareUpdateState state = FirmwareUpdateState.fromStateFwByCode(stateCode.intValue()); |
241 | + if (FirmwareUpdateState.DOWNLOADED.equals(state)) { | ||
197 | executeFwUpdate(client); | 242 | executeFwUpdate(client); |
198 | } | 243 | } |
199 | fwInfo.setUpdateState(state); | 244 | fwInfo.setUpdateState(state); |
200 | - Optional<OtaPackageUpdateStatus> status = LwM2mTransportUtil.toOtaPackageUpdateStatus(state); | 245 | + Optional<OtaPackageUpdateStatus> status = this.toOtaPackageUpdateStatus(state); |
201 | status.ifPresent(otaStatus -> sendStateUpdateToTelemetry(client, fwInfo, | 246 | status.ifPresent(otaStatus -> sendStateUpdateToTelemetry(client, fwInfo, |
202 | otaStatus, "Firmware Update State: " + state.name())); | 247 | otaStatus, "Firmware Update State: " + state.name())); |
203 | } | 248 | } |
@@ -206,8 +251,8 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | @@ -206,8 +251,8 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | ||
206 | public void onCurrentFirmwareResultUpdate(LwM2mClient client, Long code) { | 251 | public void onCurrentFirmwareResultUpdate(LwM2mClient client, Long code) { |
207 | log.debug("[{}] Current fw result: {}", client.getEndpoint(), code); | 252 | log.debug("[{}] Current fw result: {}", client.getEndpoint(), code); |
208 | LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client); | 253 | LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client); |
209 | - UpdateResultFw result = UpdateResultFw.fromUpdateResultFwByCode(code.intValue()); | ||
210 | - Optional<OtaPackageUpdateStatus> status = LwM2mTransportUtil.toOtaPackageUpdateStatus(result); | 254 | + FirmwareUpdateResult result = FirmwareUpdateResult.fromUpdateResultFwByCode(code.intValue()); |
255 | + Optional<OtaPackageUpdateStatus> status = this.toOtaPackageUpdateStatus(result); | ||
211 | status.ifPresent(otaStatus -> sendStateUpdateToTelemetry(client, fwInfo, | 256 | status.ifPresent(otaStatus -> sendStateUpdateToTelemetry(client, fwInfo, |
212 | otaStatus, "Firmware Update Result: " + result.name())); | 257 | otaStatus, "Firmware Update Result: " + result.name())); |
213 | if (result.isAgain() && fwInfo.getRetryAttempts() <= 2) { | 258 | if (result.isAgain() && fwInfo.getRetryAttempts() <= 2) { |
@@ -250,6 +295,10 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | @@ -250,6 +295,10 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | ||
250 | } | 295 | } |
251 | } | 296 | } |
252 | 297 | ||
298 | + private void startSoftwareUpdateIfNeeded(LwM2mClient client, LwM2MClientOtaInfo swInfo) { | ||
299 | + | ||
300 | + } | ||
301 | + | ||
253 | private void startFirmwareUpdateUsingUrl(LwM2mClient client, String url) { | 302 | private void startFirmwareUpdateUsingUrl(LwM2mClient client, String url) { |
254 | String targetIdVer = convertObjectIdToVersionedId(FW_URL_ID, client.getRegistration()); | 303 | String targetIdVer = convertObjectIdToVersionedId(FW_URL_ID, client.getRegistration()); |
255 | TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(targetIdVer).value(url).timeout(config.getTimeout()).build(); | 304 | TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(targetIdVer).value(url).timeout(config.getTimeout()).build(); |
@@ -276,10 +325,10 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | @@ -276,10 +325,10 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | ||
276 | if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())) { | 325 | if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())) { |
277 | UUID otaPackageId = new UUID(response.getOtaPackageIdMSB(), response.getOtaPackageIdLSB()); | 326 | UUID otaPackageId = new UUID(response.getOtaPackageIdMSB(), response.getOtaPackageIdLSB()); |
278 | LwM2MFirmwareUpdateStrategy strategy; | 327 | LwM2MFirmwareUpdateStrategy strategy; |
279 | - if (fwInfo.getDeliveryMethod() == null || fwInfo.getDeliveryMethod() == 2) { | ||
280 | - strategy = fwInfo.getStrategy(); | 328 | + if (fwInfo.getDeliveryMethod() == null || fwInfo.getDeliveryMethod() == FirmwareDeliveryMethod.BOTH.code) { |
329 | + strategy = fwInfo.getFwStrategy(); | ||
281 | } else { | 330 | } else { |
282 | - strategy = fwInfo.getDeliveryMethod() == 0 ? LwM2MFirmwareUpdateStrategy.OBJ_5_TEMP_URL : LwM2MFirmwareUpdateStrategy.OBJ_5_BINARY; | 331 | + strategy = fwInfo.getDeliveryMethod() == FirmwareDeliveryMethod.PULL.code ? LwM2MFirmwareUpdateStrategy.OBJ_5_TEMP_URL : LwM2MFirmwareUpdateStrategy.OBJ_5_BINARY; |
283 | } | 332 | } |
284 | switch (strategy) { | 333 | switch (strategy) { |
285 | case OBJ_5_BINARY: | 334 | case OBJ_5_BINARY: |
@@ -328,9 +377,9 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | @@ -328,9 +377,9 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | ||
328 | return Optional.empty(); | 377 | return Optional.empty(); |
329 | } | 378 | } |
330 | 379 | ||
331 | - private LwM2MClientOtaInfo getOrInitFwInfo(LwM2mClient client) { | 380 | + public LwM2MClientOtaInfo getOrInitFwInfo(LwM2mClient client) { |
332 | //TODO: fetch state from the cache or DB. | 381 | //TODO: fetch state from the cache or DB. |
333 | - return fwStates.computeIfAbsent(client.getEndpoint(), endpoint -> { | 382 | + return this.fwStates.computeIfAbsent(client.getEndpoint(), endpoint -> { |
334 | var profile = clientContext.getProfile(client.getProfileId()); | 383 | var profile = clientContext.getProfile(client.getProfileId()); |
335 | return new LwM2MClientOtaInfo(endpoint, OtaPackageType.FIRMWARE, profile.getClientLwM2mSettings().getFwUpdateStrategy(), | 384 | return new LwM2MClientOtaInfo(endpoint, OtaPackageType.FIRMWARE, profile.getClientLwM2mSettings().getFwUpdateStrategy(), |
336 | profile.getClientLwM2mSettings().getFwUpdateRecourse()); | 385 | profile.getClientLwM2mSettings().getFwUpdateRecourse()); |
@@ -357,4 +406,76 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | @@ -357,4 +406,76 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl | ||
357 | helper.sendParametersOnThingsboardTelemetry(result, client.getSession()); | 406 | helper.sendParametersOnThingsboardTelemetry(result, client.getSession()); |
358 | } | 407 | } |
359 | 408 | ||
409 | + private static Optional<OtaPackageUpdateStatus> toOtaPackageUpdateStatus(FirmwareUpdateResult fwUpdateResult) { | ||
410 | + switch (fwUpdateResult) { | ||
411 | + case INITIAL: | ||
412 | + return Optional.empty(); | ||
413 | + case UPDATE_SUCCESSFULLY: | ||
414 | + return Optional.of(UPDATED); | ||
415 | + case NOT_ENOUGH: | ||
416 | + case OUT_OFF_MEMORY: | ||
417 | + case CONNECTION_LOST: | ||
418 | + case INTEGRITY_CHECK_FAILURE: | ||
419 | + case UNSUPPORTED_TYPE: | ||
420 | + case INVALID_URI: | ||
421 | + case UPDATE_FAILED: | ||
422 | + case UNSUPPORTED_PROTOCOL: | ||
423 | + return Optional.of(FAILED); | ||
424 | + default: | ||
425 | + throw new CodecException("Invalid value stateFw %s for FirmwareUpdateStatus.", fwUpdateResult.name()); | ||
426 | + } | ||
427 | + } | ||
428 | + | ||
429 | + private static Optional<OtaPackageUpdateStatus> toOtaPackageUpdateStatus(FirmwareUpdateState firmwareUpdateState) { | ||
430 | + switch (firmwareUpdateState) { | ||
431 | + case IDLE: | ||
432 | + return Optional.empty(); | ||
433 | + case DOWNLOADING: | ||
434 | + return Optional.of(DOWNLOADING); | ||
435 | + case DOWNLOADED: | ||
436 | + return Optional.of(DOWNLOADED); | ||
437 | + case UPDATING: | ||
438 | + return Optional.of(UPDATING); | ||
439 | + default: | ||
440 | + throw new CodecException("Invalid value stateFw %d for FirmwareUpdateStatus.", firmwareUpdateState); | ||
441 | + } | ||
442 | + } | ||
443 | + | ||
444 | + /** | ||
445 | + * FirmwareUpdateStatus { | ||
446 | + * DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING, UPDATED, FAILED | ||
447 | + */ | ||
448 | + public static Optional<OtaPackageUpdateStatus> toSwSateResultUpdateStatus(SoftwareUpdateState softwareUpdateState, SoftwareUpdateResult softwareUpdateResult) { | ||
449 | + switch (softwareUpdateResult) { | ||
450 | + case INITIAL: | ||
451 | + switch (softwareUpdateState) { | ||
452 | + case INITIAL: | ||
453 | + case DOWNLOAD_STARTED: | ||
454 | + return Optional.of(DOWNLOADING); | ||
455 | + case DOWNLOADED: | ||
456 | + return Optional.of(DOWNLOADED); | ||
457 | + case DELIVERED: | ||
458 | + return Optional.of(VERIFIED); | ||
459 | + } | ||
460 | + case DOWNLOADING: | ||
461 | + return Optional.of(DOWNLOADING); | ||
462 | + case SUCCESSFULLY_INSTALLED: | ||
463 | + return Optional.of(UPDATED); | ||
464 | + case SUCCESSFULLY_DOWNLOADED_VERIFIED: | ||
465 | + return Optional.of(VERIFIED); | ||
466 | + case NOT_ENOUGH_STORAGE: | ||
467 | + case OUT_OFF_MEMORY: | ||
468 | + case CONNECTION_LOST: | ||
469 | + case PACKAGE_CHECK_FAILURE: | ||
470 | + case UNSUPPORTED_PACKAGE_TYPE: | ||
471 | + case INVALID_URI: | ||
472 | + case UPDATE_ERROR: | ||
473 | + case INSTALL_FAILURE: | ||
474 | + case UN_INSTALL_FAILURE: | ||
475 | + return Optional.of(FAILED); | ||
476 | + default: | ||
477 | + throw new CodecException("Invalid value stateFw %s %s for FirmwareUpdateStatus.", softwareUpdateState.name(), softwareUpdateResult.name()); | ||
478 | + } | ||
479 | + } | ||
480 | + | ||
360 | } | 481 | } |
@@ -18,9 +18,10 @@ package org.thingsboard.server.transport.lwm2m.server.ota; | @@ -18,9 +18,10 @@ package org.thingsboard.server.transport.lwm2m.server.ota; | ||
18 | import lombok.Data; | 18 | import lombok.Data; |
19 | import org.thingsboard.server.common.data.StringUtils; | 19 | import org.thingsboard.server.common.data.StringUtils; |
20 | import org.thingsboard.server.common.data.ota.OtaPackageType; | 20 | import org.thingsboard.server.common.data.ota.OtaPackageType; |
21 | -import org.thingsboard.server.transport.lwm2m.server.LwM2MFirmwareUpdateStrategy; | ||
22 | -import org.thingsboard.server.transport.lwm2m.server.UpdateStateFw; | ||
23 | -import org.thingsboard.server.transport.lwm2m.server.UpdateResultFw; | 21 | +import org.thingsboard.server.transport.lwm2m.server.ota.firmware.LwM2MFirmwareUpdateStrategy; |
22 | +import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateResult; | ||
23 | +import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateState; | ||
24 | +import org.thingsboard.server.transport.lwm2m.server.ota.software.LwM2MSoftwareUpdateStrategy; | ||
24 | 25 | ||
25 | import java.util.Optional; | 26 | import java.util.Optional; |
26 | 27 | ||
@@ -44,9 +45,10 @@ public class LwM2MClientOtaInfo { | @@ -44,9 +45,10 @@ public class LwM2MClientOtaInfo { | ||
44 | private Integer deliveryMethod; | 45 | private Integer deliveryMethod; |
45 | 46 | ||
46 | //TODO: use value from device if applicable; | 47 | //TODO: use value from device if applicable; |
47 | - private LwM2MFirmwareUpdateStrategy strategy; | ||
48 | - private UpdateStateFw updateState; | ||
49 | - private UpdateResultFw updateResult; | 48 | + private LwM2MFirmwareUpdateStrategy fwStrategy; |
49 | + private LwM2MSoftwareUpdateStrategy swStrategy; | ||
50 | + private FirmwareUpdateState updateState; | ||
51 | + private FirmwareUpdateResult updateResult; | ||
50 | 52 | ||
51 | private String failedPackageId; | 53 | private String failedPackageId; |
52 | private int retryAttempts; | 54 | private int retryAttempts; |
@@ -54,7 +56,7 @@ public class LwM2MClientOtaInfo { | @@ -54,7 +56,7 @@ public class LwM2MClientOtaInfo { | ||
54 | public LwM2MClientOtaInfo(String endpoint, OtaPackageType type, Integer strategyCode, String baseUrl) { | 56 | public LwM2MClientOtaInfo(String endpoint, OtaPackageType type, Integer strategyCode, String baseUrl) { |
55 | this.endpoint = endpoint; | 57 | this.endpoint = endpoint; |
56 | this.type = type; | 58 | this.type = type; |
57 | - this.strategy = LwM2MFirmwareUpdateStrategy.fromStrategyFwByCode(strategyCode); | 59 | + this.fwStrategy = LwM2MFirmwareUpdateStrategy.fromStrategyFwByCode(strategyCode); |
58 | this.baseUrl = baseUrl; | 60 | this.baseUrl = baseUrl; |
59 | } | 61 | } |
60 | 62 | ||
@@ -88,7 +90,7 @@ public class LwM2MClientOtaInfo { | @@ -88,7 +90,7 @@ public class LwM2MClientOtaInfo { | ||
88 | return StringUtils.isNotEmpty(currentName) || StringUtils.isNotEmpty(currentVersion5) || StringUtils.isNotEmpty(currentVersion3); | 90 | return StringUtils.isNotEmpty(currentName) || StringUtils.isNotEmpty(currentVersion5) || StringUtils.isNotEmpty(currentVersion3); |
89 | } | 91 | } |
90 | 92 | ||
91 | - public void setUpdateResult(UpdateResultFw updateResult) { | 93 | + public void setUpdateResult(FirmwareUpdateResult updateResult) { |
92 | this.updateResult = updateResult; | 94 | this.updateResult = updateResult; |
93 | switch (updateResult) { | 95 | switch (updateResult) { |
94 | case INITIAL: | 96 | case INITIAL: |
@@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.transport.lwm2m.server.ota; | 16 | package org.thingsboard.server.transport.lwm2m.server.ota; |
17 | 17 | ||
18 | +import org.thingsboard.server.common.data.device.data.lwm2m.OtherConfiguration; | ||
18 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; | 19 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; |
19 | 20 | ||
20 | import java.util.Optional; | 21 | import java.util.Optional; |
@@ -31,6 +32,10 @@ public interface LwM2MOtaUpdateService { | @@ -31,6 +32,10 @@ public interface LwM2MOtaUpdateService { | ||
31 | 32 | ||
32 | void onCurrentFirmwareNameUpdate(LwM2mClient client, String name); | 33 | void onCurrentFirmwareNameUpdate(LwM2mClient client, String name); |
33 | 34 | ||
35 | + void onCurrentFirmwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration); | ||
36 | + | ||
37 | + void onCurrentSoftwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration); | ||
38 | + | ||
34 | void onCurrentFirmwareVersion3Update(LwM2mClient client, String version); | 39 | void onCurrentFirmwareVersion3Update(LwM2mClient client, String version); |
35 | 40 | ||
36 | void onCurrentFirmwareVersion5Update(LwM2mClient client, String version); | 41 | void onCurrentFirmwareVersion5Update(LwM2mClient client, String version); |
1 | +/** | ||
2 | + * Copyright © 2016-2021 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.lwm2m.server.ota.firmware; | ||
17 | + | ||
18 | +public enum FirmwareDeliveryMethod { | ||
19 | + PULL(0, "Pull only"), | ||
20 | + PUSH(1, "Push only"), | ||
21 | + BOTH(2, "Push or Push"); | ||
22 | + | ||
23 | + public int code; | ||
24 | + public String type; | ||
25 | + | ||
26 | + FirmwareDeliveryMethod(int code, String type) { | ||
27 | + this.code = code; | ||
28 | + this.type = type; | ||
29 | + } | ||
30 | + | ||
31 | + public static FirmwareDeliveryMethod fromStateFwByType(String type) { | ||
32 | + for (FirmwareDeliveryMethod to : FirmwareDeliveryMethod.values()) { | ||
33 | + if (to.type.equals(type)) { | ||
34 | + return to; | ||
35 | + } | ||
36 | + } | ||
37 | + throw new IllegalArgumentException(String.format("Unsupported FW delivery type : %s", type)); | ||
38 | + } | ||
39 | + | ||
40 | + public static FirmwareDeliveryMethod fromStateFwByCode(int code) { | ||
41 | + for (FirmwareDeliveryMethod to : FirmwareDeliveryMethod.values()) { | ||
42 | + if (to.code == code) { | ||
43 | + return to; | ||
44 | + } | ||
45 | + } | ||
46 | + throw new IllegalArgumentException(String.format("Unsupported FW delivery code : %s", code)); | ||
47 | + } | ||
48 | +} |
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/firmware/FirmwareUpdateResult.java
renamed from
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/UpdateResultFw.java
@@ -13,7 +13,7 @@ | @@ -13,7 +13,7 @@ | ||
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | -package org.thingsboard.server.transport.lwm2m.server; | 16 | +package org.thingsboard.server.transport.lwm2m.server.ota.firmware; |
17 | 17 | ||
18 | import lombok.Getter; | 18 | import lombok.Getter; |
19 | 19 | ||
@@ -30,7 +30,7 @@ import lombok.Getter; | @@ -30,7 +30,7 @@ import lombok.Getter; | ||
30 | * 8: Firmware update failed. | 30 | * 8: Firmware update failed. |
31 | * 9: Unsupported protocol. | 31 | * 9: Unsupported protocol. |
32 | */ | 32 | */ |
33 | -public enum UpdateResultFw { | 33 | +public enum FirmwareUpdateResult { |
34 | INITIAL(0, "Initial value", false), | 34 | INITIAL(0, "Initial value", false), |
35 | UPDATE_SUCCESSFULLY(1, "Firmware updated successfully", false), | 35 | UPDATE_SUCCESSFULLY(1, "Firmware updated successfully", false), |
36 | NOT_ENOUGH(2, "Not enough flash memory for the new firmware package", false), | 36 | NOT_ENOUGH(2, "Not enough flash memory for the new firmware package", false), |
@@ -49,14 +49,14 @@ public enum UpdateResultFw { | @@ -49,14 +49,14 @@ public enum UpdateResultFw { | ||
49 | @Getter | 49 | @Getter |
50 | private boolean again; | 50 | private boolean again; |
51 | 51 | ||
52 | - UpdateResultFw(int code, String type, boolean isAgain) { | 52 | + FirmwareUpdateResult(int code, String type, boolean isAgain) { |
53 | this.code = code; | 53 | this.code = code; |
54 | this.type = type; | 54 | this.type = type; |
55 | this.again = isAgain; | 55 | this.again = isAgain; |
56 | } | 56 | } |
57 | 57 | ||
58 | - public static UpdateResultFw fromUpdateResultFwByType(String type) { | ||
59 | - for (UpdateResultFw to : UpdateResultFw.values()) { | 58 | + public static FirmwareUpdateResult fromUpdateResultFwByType(String type) { |
59 | + for (FirmwareUpdateResult to : FirmwareUpdateResult.values()) { | ||
60 | if (to.type.equals(type)) { | 60 | if (to.type.equals(type)) { |
61 | return to; | 61 | return to; |
62 | } | 62 | } |
@@ -64,8 +64,8 @@ public enum UpdateResultFw { | @@ -64,8 +64,8 @@ public enum UpdateResultFw { | ||
64 | throw new IllegalArgumentException(String.format("Unsupported FW Update Result type : %s", type)); | 64 | throw new IllegalArgumentException(String.format("Unsupported FW Update Result type : %s", type)); |
65 | } | 65 | } |
66 | 66 | ||
67 | - public static UpdateResultFw fromUpdateResultFwByCode(int code) { | ||
68 | - for (UpdateResultFw to : UpdateResultFw.values()) { | 67 | + public static FirmwareUpdateResult fromUpdateResultFwByCode(int code) { |
68 | + for (FirmwareUpdateResult to : FirmwareUpdateResult.values()) { | ||
69 | if (to.code == code) { | 69 | if (to.code == code) { |
70 | return to; | 70 | return to; |
71 | } | 71 | } |
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/firmware/FirmwareUpdateState.java
renamed from
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/UpdateStateFw.java
@@ -13,7 +13,7 @@ | @@ -13,7 +13,7 @@ | ||
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | -package org.thingsboard.server.transport.lwm2m.server; | 16 | +package org.thingsboard.server.transport.lwm2m.server.ota.firmware; |
17 | 17 | ||
18 | /** | 18 | /** |
19 | * /** State R | 19 | * /** State R |
@@ -22,7 +22,7 @@ package org.thingsboard.server.transport.lwm2m.server; | @@ -22,7 +22,7 @@ package org.thingsboard.server.transport.lwm2m.server; | ||
22 | * 2: Downloaded | 22 | * 2: Downloaded |
23 | * 3: Updating | 23 | * 3: Updating |
24 | */ | 24 | */ |
25 | -public enum UpdateStateFw { | 25 | +public enum FirmwareUpdateState { |
26 | IDLE(0, "Idle"), | 26 | IDLE(0, "Idle"), |
27 | DOWNLOADING(1, "Downloading"), | 27 | DOWNLOADING(1, "Downloading"), |
28 | DOWNLOADED(2, "Downloaded"), | 28 | DOWNLOADED(2, "Downloaded"), |
@@ -31,13 +31,13 @@ public enum UpdateStateFw { | @@ -31,13 +31,13 @@ public enum UpdateStateFw { | ||
31 | public int code; | 31 | public int code; |
32 | public String type; | 32 | public String type; |
33 | 33 | ||
34 | - UpdateStateFw(int code, String type) { | 34 | + FirmwareUpdateState(int code, String type) { |
35 | this.code = code; | 35 | this.code = code; |
36 | this.type = type; | 36 | this.type = type; |
37 | } | 37 | } |
38 | 38 | ||
39 | - public static UpdateStateFw fromStateFwByType(String type) { | ||
40 | - for (UpdateStateFw to : UpdateStateFw.values()) { | 39 | + public static FirmwareUpdateState fromStateFwByType(String type) { |
40 | + for (FirmwareUpdateState to : FirmwareUpdateState.values()) { | ||
41 | if (to.type.equals(type)) { | 41 | if (to.type.equals(type)) { |
42 | return to; | 42 | return to; |
43 | } | 43 | } |
@@ -45,8 +45,8 @@ public enum UpdateStateFw { | @@ -45,8 +45,8 @@ public enum UpdateStateFw { | ||
45 | throw new IllegalArgumentException(String.format("Unsupported FW State type : %s", type)); | 45 | throw new IllegalArgumentException(String.format("Unsupported FW State type : %s", type)); |
46 | } | 46 | } |
47 | 47 | ||
48 | - public static UpdateStateFw fromStateFwByCode(int code) { | ||
49 | - for (UpdateStateFw to : UpdateStateFw.values()) { | 48 | + public static FirmwareUpdateState fromStateFwByCode(int code) { |
49 | + for (FirmwareUpdateState to : FirmwareUpdateState.values()) { | ||
50 | if (to.code == code) { | 50 | if (to.code == code) { |
51 | return to; | 51 | return to; |
52 | } | 52 | } |
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/firmware/LwM2MFirmwareUpdateStrategy.java
renamed from
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MFirmwareUpdateStrategy.java
@@ -13,7 +13,7 @@ | @@ -13,7 +13,7 @@ | ||
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | -package org.thingsboard.server.transport.lwm2m.server; | 16 | +package org.thingsboard.server.transport.lwm2m.server.ota.firmware; |
17 | 17 | ||
18 | public enum LwM2MFirmwareUpdateStrategy { | 18 | public enum LwM2MFirmwareUpdateStrategy { |
19 | OBJ_5_BINARY(1, "ObjectId 5, Binary"), | 19 | OBJ_5_BINARY(1, "ObjectId 5, Binary"), |
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/software/LwM2MSoftwareUpdateStrategy.java
renamed from
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSoftwareUpdateStrategy.java
@@ -13,7 +13,7 @@ | @@ -13,7 +13,7 @@ | ||
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | -package org.thingsboard.server.transport.lwm2m.server; | 16 | +package org.thingsboard.server.transport.lwm2m.server.ota.software; |
17 | 17 | ||
18 | public enum LwM2MSoftwareUpdateStrategy { | 18 | public enum LwM2MSoftwareUpdateStrategy { |
19 | BINARY(1, "ObjectId 9, Binary"), | 19 | BINARY(1, "ObjectId 9, Binary"), |
1 | +/** | ||
2 | + * Copyright © 2016-2021 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.lwm2m.server.ota.software; | ||
17 | + | ||
18 | +/** | ||
19 | + * SW Update Result | ||
20 | + * Contains the result of downloading or installing/uninstalling the software | ||
21 | + * 0: Initial value. | ||
22 | + * - Prior to download any new package in the Device, Update Result MUST be reset to this initial value. | ||
23 | + * - One side effect of executing the Uninstall resource is to reset Update Result to this initial value "0". | ||
24 | + * 1: Downloading. | ||
25 | + * - The package downloading process is on-going. | ||
26 | + * 2: Software successfully installed. | ||
27 | + * 3: Successfully Downloaded and package integrity verified | ||
28 | + * (( 4-49, for expansion, of other scenarios)) | ||
29 | + * ** Failed | ||
30 | + * 50: Not enough storage for the new software package. | ||
31 | + * 51: Out of memory during downloading process. | ||
32 | + * 52: Connection lost during downloading process. | ||
33 | + * 53: Package integrity check failure. | ||
34 | + * 54: Unsupported package type. | ||
35 | + * 56: Invalid URI | ||
36 | + * 57: Device defined update error | ||
37 | + * 58: Software installation failure | ||
38 | + * 59: Uninstallation Failure during forUpdate(arg=0) | ||
39 | + * 60-200 : (for expansion, selection to be in blocks depending on new introduction of features) | ||
40 | + * This Resource MAY be reported by sending Observe operation. | ||
41 | + */ | ||
42 | +public enum SoftwareUpdateResult { | ||
43 | + INITIAL(0, "Initial value", false), | ||
44 | + DOWNLOADING(1, "Downloading", false), | ||
45 | + SUCCESSFULLY_INSTALLED(2, "Software successfully installed", false), | ||
46 | + SUCCESSFULLY_DOWNLOADED_VERIFIED(3, "Successfully Downloaded and package integrity verified", false), | ||
47 | + NOT_ENOUGH_STORAGE(50, "Not enough storage for the new software package", true), | ||
48 | + OUT_OFF_MEMORY(51, "Out of memory during downloading process", true), | ||
49 | + CONNECTION_LOST(52, "Connection lost during downloading process", false), | ||
50 | + PACKAGE_CHECK_FAILURE(53, "Package integrity check failure.", false), | ||
51 | + UNSUPPORTED_PACKAGE_TYPE(54, "Unsupported package type", false), | ||
52 | + INVALID_URI(56, "Invalid URI", true), | ||
53 | + UPDATE_ERROR(57, "Device defined update error", true), | ||
54 | + INSTALL_FAILURE(58, "Software installation failure", true), | ||
55 | + UN_INSTALL_FAILURE(59, "Uninstallation Failure during forUpdate(arg=0)", true); | ||
56 | + | ||
57 | + public int code; | ||
58 | + public String type; | ||
59 | + public boolean isAgain; | ||
60 | + | ||
61 | + SoftwareUpdateResult(int code, String type, boolean isAgain) { | ||
62 | + this.code = code; | ||
63 | + this.type = type; | ||
64 | + this.isAgain = isAgain; | ||
65 | + } | ||
66 | + | ||
67 | + public static SoftwareUpdateResult fromUpdateResultSwByType(String type) { | ||
68 | + for (SoftwareUpdateResult to : SoftwareUpdateResult.values()) { | ||
69 | + if (to.type.equals(type)) { | ||
70 | + return to; | ||
71 | + } | ||
72 | + } | ||
73 | + throw new IllegalArgumentException(String.format("Unsupported SW Update Result type : %s", type)); | ||
74 | + } | ||
75 | + | ||
76 | + public static SoftwareUpdateResult fromUpdateResultSwByCode(int code) { | ||
77 | + for (SoftwareUpdateResult to : SoftwareUpdateResult.values()) { | ||
78 | + if (to.code == code) { | ||
79 | + return to; | ||
80 | + } | ||
81 | + } | ||
82 | + throw new IllegalArgumentException(String.format("Unsupported SW Update Result code : %s", code)); | ||
83 | + } | ||
84 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 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.lwm2m.server.ota.software; | ||
17 | + | ||
18 | +/** | ||
19 | + * SW Update State R | ||
20 | + * 0: INITIAL Before downloading. (see 5.1.2.1) | ||
21 | + * 1: DOWNLOAD STARTED The downloading process has started and is on-going. (see 5.1.2.2) | ||
22 | + * 2: DOWNLOADED The package has been completely downloaded (see 5.1.2.3) | ||
23 | + * 3: DELIVERED In that state, the package has been correctly downloaded and is ready to be installed. (see 5.1.2.4) | ||
24 | + * If executing the Install Resource failed, the state remains at DELIVERED. | ||
25 | + * If executing the Install Resource was successful, the state changes from DELIVERED to INSTALLED. | ||
26 | + * After executing the UnInstall Resource, the state changes to INITIAL. | ||
27 | + * 4: INSTALLED | ||
28 | + */ | ||
29 | +public enum SoftwareUpdateState { | ||
30 | + INITIAL(0, "Initial"), | ||
31 | + DOWNLOAD_STARTED(1, "DownloadStarted"), | ||
32 | + DOWNLOADED(2, "Downloaded"), | ||
33 | + DELIVERED(3, "Delivered"), | ||
34 | + INSTALLED(4, "Installed"); | ||
35 | + | ||
36 | + public int code; | ||
37 | + public String type; | ||
38 | + | ||
39 | + SoftwareUpdateState(int code, String type) { | ||
40 | + this.code = code; | ||
41 | + this.type = type; | ||
42 | + } | ||
43 | + | ||
44 | + public static SoftwareUpdateState fromUpdateStateSwByType(String type) { | ||
45 | + for (SoftwareUpdateState to : SoftwareUpdateState.values()) { | ||
46 | + if (to.type.equals(type)) { | ||
47 | + return to; | ||
48 | + } | ||
49 | + } | ||
50 | + throw new IllegalArgumentException(String.format("Unsupported SW State type : %s", type)); | ||
51 | + } | ||
52 | + | ||
53 | + public static SoftwareUpdateState fromUpdateStateSwByCode(int code) { | ||
54 | + for (SoftwareUpdateState to : SoftwareUpdateState.values()) { | ||
55 | + if (to.code == code) { | ||
56 | + return to; | ||
57 | + } | ||
58 | + } | ||
59 | + throw new IllegalArgumentException(String.format("Unsupported SW State type : %s", code)); | ||
60 | + } | ||
61 | +} | ||
62 | + |
@@ -16,26 +16,28 @@ | @@ -16,26 +16,28 @@ | ||
16 | package org.thingsboard.server.transport.lwm2m.server.store; | 16 | package org.thingsboard.server.transport.lwm2m.server.store; |
17 | 17 | ||
18 | import lombok.extern.slf4j.Slf4j; | 18 | import lombok.extern.slf4j.Slf4j; |
19 | -import org.eclipse.leshan.server.security.EditableSecurityStore; | ||
20 | import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; | 19 | import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; |
21 | import org.eclipse.leshan.server.security.SecurityInfo; | 20 | import org.eclipse.leshan.server.security.SecurityInfo; |
22 | -import org.eclipse.leshan.server.security.SecurityStore; | ||
23 | -import org.eclipse.leshan.server.security.SecurityStoreListener; | ||
24 | import org.jetbrains.annotations.Nullable; | 21 | import org.jetbrains.annotations.Nullable; |
25 | -import org.springframework.stereotype.Component; | ||
26 | -import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; | ||
27 | import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; | 22 | import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; |
28 | import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; | 23 | import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; |
29 | -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; | ||
30 | -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; | ||
31 | 24 | ||
32 | -import java.util.Collection; | 25 | +import java.util.HashSet; |
26 | +import java.util.Map; | ||
27 | +import java.util.Set; | ||
28 | +import java.util.concurrent.ConcurrentHashMap; | ||
29 | +import java.util.concurrent.ConcurrentMap; | ||
30 | +import java.util.concurrent.locks.Lock; | ||
31 | +import java.util.concurrent.locks.ReentrantLock; | ||
32 | + | ||
33 | +import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.CLIENT; | ||
33 | 34 | ||
34 | @Slf4j | 35 | @Slf4j |
35 | -public class TbLwM2mSecurityStore implements TbEditableSecurityStore { | 36 | +public class TbLwM2mSecurityStore implements TbMainSecurityStore { |
36 | 37 | ||
37 | private final TbEditableSecurityStore securityStore; | 38 | private final TbEditableSecurityStore securityStore; |
38 | private final LwM2mCredentialsSecurityInfoValidator validator; | 39 | private final LwM2mCredentialsSecurityInfoValidator validator; |
40 | + private final ConcurrentMap<String, Set<String>> endpointRegistrations = new ConcurrentHashMap<>(); | ||
39 | 41 | ||
40 | public TbLwM2mSecurityStore(TbEditableSecurityStore securityStore, LwM2mCredentialsSecurityInfoValidator validator) { | 42 | public TbLwM2mSecurityStore(TbEditableSecurityStore securityStore, LwM2mCredentialsSecurityInfoValidator validator) { |
41 | this.securityStore = securityStore; | 43 | this.securityStore = securityStore; |
@@ -67,25 +69,43 @@ public class TbLwM2mSecurityStore implements TbEditableSecurityStore { | @@ -67,25 +69,43 @@ public class TbLwM2mSecurityStore implements TbEditableSecurityStore { | ||
67 | 69 | ||
68 | @Nullable | 70 | @Nullable |
69 | public SecurityInfo fetchAndPutSecurityInfo(String credentialsId) { | 71 | public SecurityInfo fetchAndPutSecurityInfo(String credentialsId) { |
70 | - TbLwM2MSecurityInfo securityInfo = validator.getEndpointSecurityInfoByCredentialsId(credentialsId, LwM2mTransportUtil.LwM2mTypeServer.CLIENT); | ||
71 | - try { | ||
72 | - if (securityInfo != null) { | 72 | + TbLwM2MSecurityInfo securityInfo = validator.getEndpointSecurityInfoByCredentialsId(credentialsId, CLIENT); |
73 | + doPut(securityInfo); | ||
74 | + return securityInfo != null ? securityInfo.getSecurityInfo() : null; | ||
75 | + } | ||
76 | + | ||
77 | + private void doPut(TbLwM2MSecurityInfo securityInfo) { | ||
78 | + if (securityInfo != null) { | ||
79 | + try { | ||
73 | securityStore.put(securityInfo); | 80 | securityStore.put(securityInfo); |
81 | + } catch (NonUniqueSecurityInfoException e) { | ||
82 | + log.trace("Failed to add security info: {}", securityInfo, e); | ||
74 | } | 83 | } |
75 | - } catch (NonUniqueSecurityInfoException e) { | ||
76 | - log.trace("Failed to add security info: {}", securityInfo, e); | ||
77 | } | 84 | } |
78 | - return securityInfo != null ? securityInfo.getSecurityInfo() : null; | ||
79 | } | 85 | } |
80 | 86 | ||
81 | @Override | 87 | @Override |
82 | - public void put(TbLwM2MSecurityInfo tbSecurityInfo) throws NonUniqueSecurityInfoException { | ||
83 | - securityStore.put(tbSecurityInfo); | 88 | + public void putX509(TbLwM2MSecurityInfo securityInfo) throws NonUniqueSecurityInfoException { |
89 | + securityStore.put(securityInfo); | ||
84 | } | 90 | } |
85 | 91 | ||
86 | @Override | 92 | @Override |
87 | - public void remove(String endpoint) { | ||
88 | - //TODO: Make sure we delay removal of security store from endpoint due to reg/unreg race condition. | ||
89 | -// securityStore.remove(endpoint); | 93 | + public void registerX509(String endpoint, String registrationId) { |
94 | + endpointRegistrations.computeIfAbsent(endpoint, ep -> new HashSet<>()).add(registrationId); | ||
95 | + } | ||
96 | + | ||
97 | + @Override | ||
98 | + public void remove(String endpoint, String registrationId) { | ||
99 | + Set<String> epRegistrationIds = endpointRegistrations.get(endpoint); | ||
100 | + boolean shouldRemove; | ||
101 | + if (epRegistrationIds == null) { | ||
102 | + shouldRemove = true; | ||
103 | + } else { | ||
104 | + epRegistrationIds.remove(registrationId); | ||
105 | + shouldRemove = epRegistrationIds.isEmpty(); | ||
106 | + } | ||
107 | + if (shouldRemove) { | ||
108 | + securityStore.remove(endpoint); | ||
109 | + } | ||
90 | } | 110 | } |
91 | } | 111 | } |
@@ -51,7 +51,7 @@ public class TbLwM2mStoreFactory { | @@ -51,7 +51,7 @@ public class TbLwM2mStoreFactory { | ||
51 | } | 51 | } |
52 | 52 | ||
53 | @Bean | 53 | @Bean |
54 | - private TbEditableSecurityStore securityStore() { | 54 | + private TbMainSecurityStore securityStore() { |
55 | return new TbLwM2mSecurityStore(redisConfiguration.isPresent() && useRedis ? | 55 | return new TbLwM2mSecurityStore(redisConfiguration.isPresent() && useRedis ? |
56 | new TbLwM2mRedisSecurityStore(redisConfiguration.get().redisConnectionFactory()) : new TbInMemorySecurityStore(), validator); | 56 | new TbLwM2mRedisSecurityStore(redisConfiguration.get().redisConnectionFactory()) : new TbInMemorySecurityStore(), validator); |
57 | } | 57 | } |
1 | +/** | ||
2 | + * Copyright © 2016-2021 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.lwm2m.server.store; | ||
17 | + | ||
18 | +import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; | ||
19 | +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; | ||
20 | + | ||
21 | +public interface TbMainSecurityStore extends TbSecurityStore { | ||
22 | + | ||
23 | + void putX509(TbLwM2MSecurityInfo tbSecurityInfo) throws NonUniqueSecurityInfoException; | ||
24 | + | ||
25 | + void registerX509(String endpoint, String registrationId); | ||
26 | + | ||
27 | + void remove(String endpoint, String registrationId); | ||
28 | + | ||
29 | +} |
@@ -37,11 +37,12 @@ import org.eclipse.leshan.server.registration.Registration; | @@ -37,11 +37,12 @@ import org.eclipse.leshan.server.registration.Registration; | ||
37 | import org.springframework.context.annotation.Lazy; | 37 | import org.springframework.context.annotation.Lazy; |
38 | import org.springframework.stereotype.Service; | 38 | import org.springframework.stereotype.Service; |
39 | import org.thingsboard.common.util.DonAsynchron; | 39 | import org.thingsboard.common.util.DonAsynchron; |
40 | -import org.thingsboard.common.util.ThingsBoardExecutors; | ||
41 | import org.thingsboard.server.cache.ota.OtaPackageDataCache; | 40 | import org.thingsboard.server.cache.ota.OtaPackageDataCache; |
42 | import org.thingsboard.server.common.data.Device; | 41 | import org.thingsboard.server.common.data.Device; |
43 | import org.thingsboard.server.common.data.DeviceProfile; | 42 | import org.thingsboard.server.common.data.DeviceProfile; |
43 | +import org.thingsboard.server.common.data.StringUtils; | ||
44 | import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes; | 44 | import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes; |
45 | +import org.thingsboard.server.common.data.device.data.lwm2m.OtherConfiguration; | ||
45 | import org.thingsboard.server.common.data.device.data.lwm2m.TelemetryMappingConfiguration; | 46 | import org.thingsboard.server.common.data.device.data.lwm2m.TelemetryMappingConfiguration; |
46 | import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; | 47 | import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; |
47 | import org.thingsboard.server.common.data.ota.OtaPackageUtil; | 48 | import org.thingsboard.server.common.data.ota.OtaPackageUtil; |
@@ -82,6 +83,8 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttrib | @@ -82,6 +83,8 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttrib | ||
82 | import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttributesRequest; | 83 | import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttributesRequest; |
83 | import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; | 84 | import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; |
84 | import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService; | 85 | import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService; |
86 | +import org.thingsboard.server.transport.lwm2m.server.ota.firmware.LwM2MFirmwareUpdateStrategy; | ||
87 | +import org.thingsboard.server.transport.lwm2m.server.ota.software.LwM2MSoftwareUpdateStrategy; | ||
85 | import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2MRpcRequestHandler; | 88 | import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2MRpcRequestHandler; |
86 | import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; | 89 | import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; |
87 | import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; | 90 | import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; |
@@ -100,23 +103,22 @@ import java.util.Set; | @@ -100,23 +103,22 @@ import java.util.Set; | ||
100 | import java.util.UUID; | 103 | import java.util.UUID; |
101 | import java.util.concurrent.ConcurrentHashMap; | 104 | import java.util.concurrent.ConcurrentHashMap; |
102 | import java.util.concurrent.CountDownLatch; | 105 | import java.util.concurrent.CountDownLatch; |
103 | -import java.util.concurrent.ExecutorService; | ||
104 | import java.util.concurrent.TimeUnit; | 106 | import java.util.concurrent.TimeUnit; |
105 | import java.util.stream.Collectors; | 107 | import java.util.stream.Collectors; |
106 | 108 | ||
107 | import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; | 109 | import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; |
108 | -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_3_VER_ID; | ||
109 | -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_5_VER_ID; | ||
110 | -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_DELIVERY_METHOD; | ||
111 | -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_NAME_ID; | ||
112 | -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_RESULT_ID; | ||
113 | -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_STATE_ID; | ||
114 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_ERROR; | 110 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_ERROR; |
115 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; | 111 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; |
116 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_WARN; | 112 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_WARN; |
117 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId; | 113 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId; |
118 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertOtaUpdateValueToString; | 114 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertOtaUpdateValueToString; |
119 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId; | 115 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId; |
116 | +import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_3_VER_ID; | ||
117 | +import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_5_VER_ID; | ||
118 | +import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_DELIVERY_METHOD; | ||
119 | +import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_NAME_ID; | ||
120 | +import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_RESULT_ID; | ||
121 | +import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_STATE_ID; | ||
120 | 122 | ||
121 | 123 | ||
122 | @Slf4j | 124 | @Slf4j |
@@ -130,16 +132,13 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl | @@ -130,16 +132,13 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl | ||
130 | private final LwM2mTransportContext context; | 132 | private final LwM2mTransportContext context; |
131 | private final LwM2MAttributesService attributesService; | 133 | private final LwM2MAttributesService attributesService; |
132 | private final LwM2MOtaUpdateService otaService; | 134 | private final LwM2MOtaUpdateService otaService; |
133 | - public final LwM2MTransportServerConfig config; | 135 | + private final LwM2MTransportServerConfig config; |
134 | private final LwM2MTelemetryLogService logService; | 136 | private final LwM2MTelemetryLogService logService; |
135 | - public final OtaPackageDataCache otaPackageDataCache; | ||
136 | - public final LwM2mTransportServerHelper helper; | 137 | + private final LwM2mTransportServerHelper helper; |
137 | private final TbLwM2MDtlsSessionStore sessionStore; | 138 | private final TbLwM2MDtlsSessionStore sessionStore; |
138 | - public final LwM2mClientContext clientContext; | 139 | + private final LwM2mClientContext clientContext; |
139 | private final LwM2MRpcRequestHandler rpcHandler; | 140 | private final LwM2MRpcRequestHandler rpcHandler; |
140 | - public final LwM2mDownlinkMsgHandler defaultLwM2MDownlinkMsgHandler; | ||
141 | - | ||
142 | - public final Map<String, Integer> firmwareUpdateState; | 141 | + private final LwM2mDownlinkMsgHandler defaultLwM2MDownlinkMsgHandler; |
143 | 142 | ||
144 | public DefaultLwM2MUplinkMsgHandler(TransportService transportService, | 143 | public DefaultLwM2MUplinkMsgHandler(TransportService transportService, |
145 | LwM2MTransportServerConfig config, | 144 | LwM2MTransportServerConfig config, |
@@ -150,7 +149,6 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl | @@ -150,7 +149,6 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl | ||
150 | @Lazy LwM2MAttributesService attributesService, | 149 | @Lazy LwM2MAttributesService attributesService, |
151 | @Lazy LwM2MRpcRequestHandler rpcHandler, | 150 | @Lazy LwM2MRpcRequestHandler rpcHandler, |
152 | @Lazy LwM2mDownlinkMsgHandler defaultLwM2MDownlinkMsgHandler, | 151 | @Lazy LwM2mDownlinkMsgHandler defaultLwM2MDownlinkMsgHandler, |
153 | - OtaPackageDataCache otaPackageDataCache, | ||
154 | LwM2mTransportContext context, TbLwM2MDtlsSessionStore sessionStore) { | 152 | LwM2mTransportContext context, TbLwM2MDtlsSessionStore sessionStore) { |
155 | this.transportService = transportService; | 153 | this.transportService = transportService; |
156 | this.attributesService = attributesService; | 154 | this.attributesService = attributesService; |
@@ -161,9 +159,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl | @@ -161,9 +159,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl | ||
161 | this.logService = logService; | 159 | this.logService = logService; |
162 | this.rpcHandler = rpcHandler; | 160 | this.rpcHandler = rpcHandler; |
163 | this.defaultLwM2MDownlinkMsgHandler = defaultLwM2MDownlinkMsgHandler; | 161 | this.defaultLwM2MDownlinkMsgHandler = defaultLwM2MDownlinkMsgHandler; |
164 | - this.otaPackageDataCache = otaPackageDataCache; | ||
165 | this.context = context; | 162 | this.context = context; |
166 | - this.firmwareUpdateState = new ConcurrentHashMap<>(); | ||
167 | this.sessionStore = sessionStore; | 163 | this.sessionStore = sessionStore; |
168 | } | 164 | } |
169 | 165 | ||
@@ -216,7 +212,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl | @@ -216,7 +212,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl | ||
216 | } | 212 | } |
217 | logService.log(lwM2MClient, LOG_LWM2M_INFO + ": Client registered with registration id: " + registration.getId()); | 213 | logService.log(lwM2MClient, LOG_LWM2M_INFO + ": Client registered with registration id: " + registration.getId()); |
218 | SessionInfoProto sessionInfo = lwM2MClient.getSession(); | 214 | SessionInfoProto sessionInfo = lwM2MClient.getSession(); |
219 | - transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, attributesService, rpcHandler, sessionInfo)); | 215 | + transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, attributesService, rpcHandler, sessionInfo, transportService)); |
220 | log.warn("40) sessionId [{}] Registering rpc subscription after Registration client", new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())); | 216 | log.warn("40) sessionId [{}] Registering rpc subscription after Registration client", new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())); |
221 | TransportProtos.TransportToDeviceActorMsg msg = TransportProtos.TransportToDeviceActorMsg.newBuilder() | 217 | TransportProtos.TransportToDeviceActorMsg msg = TransportProtos.TransportToDeviceActorMsg.newBuilder() |
222 | .setSessionInfo(sessionInfo) | 218 | .setSessionInfo(sessionInfo) |
@@ -780,6 +776,21 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl | @@ -780,6 +776,21 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl | ||
780 | clients.forEach(client -> sendCancelObserveRequest(targetId, client)); | 776 | clients.forEach(client -> sendCancelObserveRequest(targetId, client)); |
781 | } | 777 | } |
782 | } | 778 | } |
779 | + | ||
780 | + // update value in fwInfo | ||
781 | + OtherConfiguration newLwM2mSettings = newProfile.getClientLwM2mSettings(); | ||
782 | + OtherConfiguration oldLwM2mSettings = oldProfile.getClientLwM2mSettings(); | ||
783 | + if (!newLwM2mSettings.getFwUpdateStrategy().equals(oldLwM2mSettings.getFwUpdateStrategy()) | ||
784 | + || (StringUtils.isNotEmpty(newLwM2mSettings.getFwUpdateRecourse()) && | ||
785 | + !newLwM2mSettings.getFwUpdateRecourse().equals(oldLwM2mSettings.getFwUpdateRecourse()))) { | ||
786 | + clients.forEach(lwM2MClient -> otaService.onCurrentFirmwareStrategyUpdate(lwM2MClient, newLwM2mSettings)); | ||
787 | + } | ||
788 | + | ||
789 | + if (!newLwM2mSettings.getSwUpdateStrategy().equals(oldLwM2mSettings.getSwUpdateStrategy()) | ||
790 | + || (StringUtils.isNotEmpty(newLwM2mSettings.getSwUpdateRecourse()) && | ||
791 | + !newLwM2mSettings.getSwUpdateRecourse().equals(oldLwM2mSettings.getSwUpdateRecourse()))) { | ||
792 | + clients.forEach(lwM2MClient -> otaService.onCurrentSoftwareStrategyUpdate(lwM2MClient, newLwM2mSettings)); | ||
793 | + } | ||
783 | } | 794 | } |
784 | } | 795 | } |
785 | 796 | ||
@@ -877,7 +888,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl | @@ -877,7 +888,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl | ||
877 | */ | 888 | */ |
878 | private void reportActivityAndRegister(SessionInfoProto sessionInfo) { | 889 | private void reportActivityAndRegister(SessionInfoProto sessionInfo) { |
879 | if (sessionInfo != null && transportService.reportActivity(sessionInfo) == null) { | 890 | if (sessionInfo != null && transportService.reportActivity(sessionInfo) == null) { |
880 | - transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, attributesService, rpcHandler, sessionInfo)); | 891 | + transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, attributesService, rpcHandler, sessionInfo, transportService)); |
881 | this.reportActivitySubscription(sessionInfo); | 892 | this.reportActivitySubscription(sessionInfo); |
882 | } | 893 | } |
883 | } | 894 | } |
1 | +/** | ||
2 | + * Copyright © 2016-2021 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.lwm2m.server.uplink; | ||
17 | + | ||
18 | +public enum LwM2mTypeServer { | ||
19 | + BOOTSTRAP(0, "bootstrap"), | ||
20 | + CLIENT(1, "client"); | ||
21 | + | ||
22 | + public int code; | ||
23 | + public String type; | ||
24 | + | ||
25 | + LwM2mTypeServer(int code, String type) { | ||
26 | + this.code = code; | ||
27 | + this.type = type; | ||
28 | + } | ||
29 | + | ||
30 | + public static LwM2mTypeServer fromLwM2mTypeServer(String type) { | ||
31 | + for (LwM2mTypeServer sm : LwM2mTypeServer.values()) { | ||
32 | + if (sm.type.equals(type)) { | ||
33 | + return sm; | ||
34 | + } | ||
35 | + } | ||
36 | + throw new IllegalArgumentException(String.format("Unsupported typeServer type : %d", type)); | ||
37 | + } | ||
38 | +} | ||
39 | + |
@@ -17,6 +17,7 @@ package org.thingsboard.server.transport.mqtt; | @@ -17,6 +17,7 @@ package org.thingsboard.server.transport.mqtt; | ||
17 | 17 | ||
18 | import com.fasterxml.jackson.databind.JsonNode; | 18 | import com.fasterxml.jackson.databind.JsonNode; |
19 | import com.google.gson.JsonParseException; | 19 | import com.google.gson.JsonParseException; |
20 | +import io.netty.channel.ChannelFuture; | ||
20 | import io.netty.channel.ChannelHandlerContext; | 21 | import io.netty.channel.ChannelHandlerContext; |
21 | import io.netty.channel.ChannelInboundHandlerAdapter; | 22 | import io.netty.channel.ChannelInboundHandlerAdapter; |
22 | import io.netty.handler.codec.mqtt.MqttConnAckMessage; | 23 | import io.netty.handler.codec.mqtt.MqttConnAckMessage; |
@@ -47,8 +48,9 @@ import org.thingsboard.server.common.data.DeviceProfile; | @@ -47,8 +48,9 @@ import org.thingsboard.server.common.data.DeviceProfile; | ||
47 | import org.thingsboard.server.common.data.DeviceTransportType; | 48 | import org.thingsboard.server.common.data.DeviceTransportType; |
48 | import org.thingsboard.server.common.data.TransportPayloadType; | 49 | import org.thingsboard.server.common.data.TransportPayloadType; |
49 | import org.thingsboard.server.common.data.device.profile.MqttTopics; | 50 | import org.thingsboard.server.common.data.device.profile.MqttTopics; |
50 | -import org.thingsboard.server.common.data.ota.OtaPackageType; | ||
51 | import org.thingsboard.server.common.data.id.OtaPackageId; | 51 | import org.thingsboard.server.common.data.id.OtaPackageId; |
52 | +import org.thingsboard.server.common.data.ota.OtaPackageType; | ||
53 | +import org.thingsboard.server.common.data.rpc.RpcStatus; | ||
52 | import org.thingsboard.server.common.msg.EncryptionUtil; | 54 | import org.thingsboard.server.common.msg.EncryptionUtil; |
53 | import org.thingsboard.server.common.msg.tools.TbRateLimitsException; | 55 | import org.thingsboard.server.common.msg.tools.TbRateLimitsException; |
54 | import org.thingsboard.server.common.transport.SessionMsgListener; | 56 | import org.thingsboard.server.common.transport.SessionMsgListener; |
@@ -813,7 +815,31 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement | @@ -813,7 +815,31 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement | ||
813 | public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg rpcRequest) { | 815 | public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg rpcRequest) { |
814 | log.trace("[{}] Received RPC command to device", sessionId); | 816 | log.trace("[{}] Received RPC command to device", sessionId); |
815 | try { | 817 | try { |
816 | - deviceSessionCtx.getPayloadAdaptor().convertToPublish(deviceSessionCtx, rpcRequest).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); | 818 | + deviceSessionCtx.getPayloadAdaptor().convertToPublish(deviceSessionCtx, rpcRequest) |
819 | + .ifPresent(payload -> { | ||
820 | + ChannelFuture channelFuture = deviceSessionCtx.getChannel().writeAndFlush(payload); | ||
821 | + if (rpcRequest.getPersisted()) { | ||
822 | + channelFuture.addListener(future -> { | ||
823 | + RpcStatus status; | ||
824 | + Throwable t = future.cause(); | ||
825 | + if (t != null) { | ||
826 | + log.error("Failed delivering RPC command to device!", t); | ||
827 | + status = RpcStatus.FAILED; | ||
828 | + } else if (rpcRequest.getOneway()) { | ||
829 | + status = RpcStatus.SUCCESSFUL; | ||
830 | + } else { | ||
831 | + status = RpcStatus.DELIVERED; | ||
832 | + } | ||
833 | + TransportProtos.ToDevicePersistedRpcResponseMsg msg = TransportProtos.ToDevicePersistedRpcResponseMsg.newBuilder() | ||
834 | + .setRequestId(rpcRequest.getRequestId()) | ||
835 | + .setRequestIdLSB(rpcRequest.getRequestIdLSB()) | ||
836 | + .setRequestIdMSB(rpcRequest.getRequestIdMSB()) | ||
837 | + .setStatus(status.name()) | ||
838 | + .build(); | ||
839 | + transportService.process(deviceSessionCtx.getSessionInfo(), msg, TransportServiceCallback.EMPTY); | ||
840 | + }); | ||
841 | + } | ||
842 | + }); | ||
817 | } catch (Exception e) { | 843 | } catch (Exception e) { |
818 | log.trace("[{}] Failed to convert device RPC command to MQTT msg", sessionId, e); | 844 | log.trace("[{}] Failed to convert device RPC command to MQTT msg", sessionId, e); |
819 | } | 845 | } |
@@ -15,9 +15,13 @@ | @@ -15,9 +15,13 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.transport.mqtt.session; | 16 | package org.thingsboard.server.transport.mqtt.session; |
17 | 17 | ||
18 | +import io.netty.channel.ChannelFuture; | ||
18 | import lombok.extern.slf4j.Slf4j; | 19 | import lombok.extern.slf4j.Slf4j; |
19 | import org.thingsboard.server.common.data.DeviceProfile; | 20 | import org.thingsboard.server.common.data.DeviceProfile; |
21 | +import org.thingsboard.server.common.data.rpc.RpcStatus; | ||
20 | import org.thingsboard.server.common.transport.SessionMsgListener; | 22 | import org.thingsboard.server.common.transport.SessionMsgListener; |
23 | +import org.thingsboard.server.common.transport.TransportService; | ||
24 | +import org.thingsboard.server.common.transport.TransportServiceCallback; | ||
21 | import org.thingsboard.server.common.transport.auth.TransportDeviceInfo; | 25 | import org.thingsboard.server.common.transport.auth.TransportDeviceInfo; |
22 | import org.thingsboard.server.gen.transport.TransportProtos; | 26 | import org.thingsboard.server.gen.transport.TransportProtos; |
23 | import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; | 27 | import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; |
@@ -32,9 +36,11 @@ import java.util.concurrent.ConcurrentMap; | @@ -32,9 +36,11 @@ import java.util.concurrent.ConcurrentMap; | ||
32 | public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext implements SessionMsgListener { | 36 | public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext implements SessionMsgListener { |
33 | 37 | ||
34 | private final GatewaySessionHandler parent; | 38 | private final GatewaySessionHandler parent; |
39 | + private final TransportService transportService; | ||
35 | 40 | ||
36 | public GatewayDeviceSessionCtx(GatewaySessionHandler parent, TransportDeviceInfo deviceInfo, | 41 | public GatewayDeviceSessionCtx(GatewaySessionHandler parent, TransportDeviceInfo deviceInfo, |
37 | - DeviceProfile deviceProfile, ConcurrentMap<MqttTopicMatcher, Integer> mqttQoSMap) { | 42 | + DeviceProfile deviceProfile, ConcurrentMap<MqttTopicMatcher, Integer> mqttQoSMap, |
43 | + TransportService transportService) { | ||
38 | super(UUID.randomUUID(), mqttQoSMap); | 44 | super(UUID.randomUUID(), mqttQoSMap); |
39 | this.parent = parent; | 45 | this.parent = parent; |
40 | setSessionInfo(SessionInfoProto.newBuilder() | 46 | setSessionInfo(SessionInfoProto.newBuilder() |
@@ -56,6 +62,7 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple | @@ -56,6 +62,7 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple | ||
56 | .build()); | 62 | .build()); |
57 | setDeviceInfo(deviceInfo); | 63 | setDeviceInfo(deviceInfo); |
58 | setDeviceProfile(deviceProfile); | 64 | setDeviceProfile(deviceProfile); |
65 | + this.transportService = transportService; | ||
59 | } | 66 | } |
60 | 67 | ||
61 | @Override | 68 | @Override |
@@ -89,7 +96,32 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple | @@ -89,7 +96,32 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple | ||
89 | @Override | 96 | @Override |
90 | public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg request) { | 97 | public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg request) { |
91 | try { | 98 | try { |
92 | - parent.getPayloadAdaptor().convertToGatewayPublish(this, getDeviceInfo().getDeviceName(), request).ifPresent(parent::writeAndFlush); | 99 | + parent.getPayloadAdaptor().convertToGatewayPublish(this, getDeviceInfo().getDeviceName(), request).ifPresent( |
100 | + payload -> { | ||
101 | + ChannelFuture channelFuture = parent.writeAndFlush(payload); | ||
102 | + if (request.getPersisted()) { | ||
103 | + channelFuture.addListener(future -> { | ||
104 | + RpcStatus status; | ||
105 | + Throwable t = future.cause(); | ||
106 | + if (t != null) { | ||
107 | + log.error("Failed delivering RPC command to device!", t); | ||
108 | + status = RpcStatus.FAILED; | ||
109 | + } else if (request.getOneway()) { | ||
110 | + status = RpcStatus.SUCCESSFUL; | ||
111 | + } else { | ||
112 | + status = RpcStatus.DELIVERED; | ||
113 | + } | ||
114 | + TransportProtos.ToDevicePersistedRpcResponseMsg msg = TransportProtos.ToDevicePersistedRpcResponseMsg.newBuilder() | ||
115 | + .setRequestId(request.getRequestId()) | ||
116 | + .setRequestIdLSB(request.getRequestIdLSB()) | ||
117 | + .setRequestIdMSB(request.getRequestIdMSB()) | ||
118 | + .setStatus(status.name()) | ||
119 | + .build(); | ||
120 | + transportService.process(getSessionInfo(), msg, TransportServiceCallback.EMPTY); | ||
121 | + }); | ||
122 | + } | ||
123 | + } | ||
124 | + ); | ||
93 | } catch (Exception e) { | 125 | } catch (Exception e) { |
94 | log.trace("[{}] Failed to convert device attributes response to MQTT msg", sessionId, e); | 126 | log.trace("[{}] Failed to convert device attributes response to MQTT msg", sessionId, e); |
95 | } | 127 | } |
@@ -28,6 +28,7 @@ import com.google.gson.JsonSyntaxException; | @@ -28,6 +28,7 @@ import com.google.gson.JsonSyntaxException; | ||
28 | import com.google.protobuf.InvalidProtocolBufferException; | 28 | import com.google.protobuf.InvalidProtocolBufferException; |
29 | import com.google.protobuf.ProtocolStringList; | 29 | import com.google.protobuf.ProtocolStringList; |
30 | import io.netty.buffer.ByteBuf; | 30 | import io.netty.buffer.ByteBuf; |
31 | +import io.netty.channel.ChannelFuture; | ||
31 | import io.netty.channel.ChannelHandlerContext; | 32 | import io.netty.channel.ChannelHandlerContext; |
32 | import io.netty.handler.codec.mqtt.MqttMessage; | 33 | import io.netty.handler.codec.mqtt.MqttMessage; |
33 | import io.netty.handler.codec.mqtt.MqttPublishMessage; | 34 | import io.netty.handler.codec.mqtt.MqttPublishMessage; |
@@ -188,8 +189,8 @@ public class GatewaySessionHandler { | @@ -188,8 +189,8 @@ public class GatewaySessionHandler { | ||
188 | } | 189 | } |
189 | } | 190 | } |
190 | 191 | ||
191 | - void writeAndFlush(MqttMessage mqttMessage) { | ||
192 | - channel.writeAndFlush(mqttMessage); | 192 | + ChannelFuture writeAndFlush(MqttMessage mqttMessage) { |
193 | + return channel.writeAndFlush(mqttMessage); | ||
193 | } | 194 | } |
194 | 195 | ||
195 | int nextMsgId() { | 196 | int nextMsgId() { |
@@ -251,7 +252,7 @@ public class GatewaySessionHandler { | @@ -251,7 +252,7 @@ public class GatewaySessionHandler { | ||
251 | new TransportServiceCallback<GetOrCreateDeviceFromGatewayResponse>() { | 252 | new TransportServiceCallback<GetOrCreateDeviceFromGatewayResponse>() { |
252 | @Override | 253 | @Override |
253 | public void onSuccess(GetOrCreateDeviceFromGatewayResponse msg) { | 254 | public void onSuccess(GetOrCreateDeviceFromGatewayResponse msg) { |
254 | - GatewayDeviceSessionCtx deviceSessionCtx = new GatewayDeviceSessionCtx(GatewaySessionHandler.this, msg.getDeviceInfo(), msg.getDeviceProfile(), mqttQoSMap); | 255 | + GatewayDeviceSessionCtx deviceSessionCtx = new GatewayDeviceSessionCtx(GatewaySessionHandler.this, msg.getDeviceInfo(), msg.getDeviceProfile(), mqttQoSMap, transportService); |
255 | if (devices.putIfAbsent(deviceName, deviceSessionCtx) == null) { | 256 | if (devices.putIfAbsent(deviceName, deviceSessionCtx) == null) { |
256 | log.trace("[{}] First got or created device [{}], type [{}] for the gateway session", sessionId, deviceName, deviceType); | 257 | log.trace("[{}] First got or created device [{}], type [{}] for the gateway session", sessionId, deviceName, deviceType); |
257 | SessionInfoProto deviceSessionInfo = deviceSessionCtx.getSessionInfo(); | 258 | SessionInfoProto deviceSessionInfo = deviceSessionCtx.getSessionInfo(); |
@@ -26,7 +26,9 @@ import org.thingsboard.server.common.data.DeviceProfile; | @@ -26,7 +26,9 @@ import org.thingsboard.server.common.data.DeviceProfile; | ||
26 | import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration; | 26 | import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration; |
27 | import org.thingsboard.server.common.data.device.profile.SnmpDeviceProfileTransportConfiguration; | 27 | import org.thingsboard.server.common.data.device.profile.SnmpDeviceProfileTransportConfiguration; |
28 | import org.thingsboard.server.common.data.id.DeviceId; | 28 | import org.thingsboard.server.common.data.id.DeviceId; |
29 | +import org.thingsboard.server.common.data.rpc.RpcStatus; | ||
29 | import org.thingsboard.server.common.transport.SessionMsgListener; | 30 | import org.thingsboard.server.common.transport.SessionMsgListener; |
31 | +import org.thingsboard.server.common.transport.TransportServiceCallback; | ||
30 | import org.thingsboard.server.common.transport.session.DeviceAwareSessionContext; | 32 | import org.thingsboard.server.common.transport.session.DeviceAwareSessionContext; |
31 | import org.thingsboard.server.gen.transport.TransportProtos; | 33 | import org.thingsboard.server.gen.transport.TransportProtos; |
32 | import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; | 34 | import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; |
@@ -139,6 +141,21 @@ public class DeviceSessionContext extends DeviceAwareSessionContext implements S | @@ -139,6 +141,21 @@ public class DeviceSessionContext extends DeviceAwareSessionContext implements S | ||
139 | @Override | 141 | @Override |
140 | public void onToDeviceRpcRequest(ToDeviceRpcRequestMsg toDeviceRequest) { | 142 | public void onToDeviceRpcRequest(ToDeviceRpcRequestMsg toDeviceRequest) { |
141 | snmpTransportContext.getSnmpTransportService().onToDeviceRpcRequest(this, toDeviceRequest); | 143 | snmpTransportContext.getSnmpTransportService().onToDeviceRpcRequest(this, toDeviceRequest); |
144 | + if (toDeviceRequest.getPersisted()) { | ||
145 | + RpcStatus status; | ||
146 | + if (toDeviceRequest.getOneway()) { | ||
147 | + status = RpcStatus.SUCCESSFUL; | ||
148 | + } else { | ||
149 | + status = RpcStatus.DELIVERED; | ||
150 | + } | ||
151 | + TransportProtos.ToDevicePersistedRpcResponseMsg responseMsg = TransportProtos.ToDevicePersistedRpcResponseMsg.newBuilder() | ||
152 | + .setRequestId(toDeviceRequest.getRequestId()) | ||
153 | + .setRequestIdLSB(toDeviceRequest.getRequestIdLSB()) | ||
154 | + .setRequestIdMSB(toDeviceRequest.getRequestIdMSB()) | ||
155 | + .setStatus(status.name()) | ||
156 | + .build(); | ||
157 | + snmpTransportContext.getTransportService().process(getSessionInfo(), responseMsg, TransportServiceCallback.EMPTY); | ||
158 | + } | ||
142 | } | 159 | } |
143 | 160 | ||
144 | @Override | 161 | @Override |
@@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.DeviceTransportType; | @@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.DeviceTransportType; | ||
20 | import org.thingsboard.server.common.transport.auth.GetOrCreateDeviceFromGatewayResponse; | 20 | import org.thingsboard.server.common.transport.auth.GetOrCreateDeviceFromGatewayResponse; |
21 | import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; | 21 | import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; |
22 | import org.thingsboard.server.common.transport.service.SessionMetaData; | 22 | import org.thingsboard.server.common.transport.service.SessionMetaData; |
23 | +import org.thingsboard.server.gen.transport.TransportProtos; | ||
23 | import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; | 24 | import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; |
24 | import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; | 25 | import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; |
25 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; | 26 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; |
@@ -109,6 +110,8 @@ public interface TransportService { | @@ -109,6 +110,8 @@ public interface TransportService { | ||
109 | 110 | ||
110 | void process(SessionInfoProto sessionInfo, ToServerRpcRequestMsg msg, TransportServiceCallback<Void> callback); | 111 | void process(SessionInfoProto sessionInfo, ToServerRpcRequestMsg msg, TransportServiceCallback<Void> callback); |
111 | 112 | ||
113 | + void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.ToDevicePersistedRpcResponseMsg msg, TransportServiceCallback<Void> callback); | ||
114 | + | ||
112 | void process(SessionInfoProto sessionInfo, SubscriptionInfoProto msg, TransportServiceCallback<Void> callback); | 115 | void process(SessionInfoProto sessionInfo, SubscriptionInfoProto msg, TransportServiceCallback<Void> callback); |
113 | 116 | ||
114 | void process(SessionInfoProto sessionInfo, ClaimDeviceMsg msg, TransportServiceCallback<Void> callback); | 117 | void process(SessionInfoProto sessionInfo, ClaimDeviceMsg msg, TransportServiceCallback<Void> callback); |
@@ -557,6 +557,15 @@ public class DefaultTransportService implements TransportService { | @@ -557,6 +557,15 @@ public class DefaultTransportService implements TransportService { | ||
557 | } | 557 | } |
558 | } | 558 | } |
559 | 559 | ||
560 | + @Override | ||
561 | + public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.ToDevicePersistedRpcResponseMsg msg, TransportServiceCallback<Void> callback) { | ||
562 | + if (checkLimits(sessionInfo, msg, callback)) { | ||
563 | + reportActivityInternal(sessionInfo); | ||
564 | + sendToDeviceActor(sessionInfo, TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo).setPersistedRpcResponseMsg(msg).build(), | ||
565 | + new ApiStatsProxyCallback<>(getTenantId(sessionInfo), getCustomerId(sessionInfo), 1, callback)); | ||
566 | + } | ||
567 | + } | ||
568 | + | ||
560 | private void processTimeout(String requestId) { | 569 | private void processTimeout(String requestId) { |
561 | RpcRequestMetadata data = toServerRpcPendingMap.remove(requestId); | 570 | RpcRequestMetadata data = toServerRpcPendingMap.remove(requestId); |
562 | if (data != null) { | 571 | if (data != null) { |
@@ -507,6 +507,17 @@ public class ModelConstants { | @@ -507,6 +507,17 @@ public class ModelConstants { | ||
507 | public static final String OTA_PACKAGE_ADDITIONAL_INFO_COLUMN = ADDITIONAL_INFO_PROPERTY; | 507 | public static final String OTA_PACKAGE_ADDITIONAL_INFO_COLUMN = ADDITIONAL_INFO_PROPERTY; |
508 | 508 | ||
509 | /** | 509 | /** |
510 | + * Persisted RPC constants. | ||
511 | + */ | ||
512 | + public static final String RPC_TABLE_NAME = "rpc"; | ||
513 | + public static final String RPC_TENANT_ID_COLUMN = TENANT_ID_COLUMN; | ||
514 | + public static final String RPC_DEVICE_ID = "device_id"; | ||
515 | + public static final String RPC_EXPIRATION_TIME = "expiration_time"; | ||
516 | + public static final String RPC_REQUEST = "request"; | ||
517 | + public static final String RPC_RESPONSE = "response"; | ||
518 | + public static final String RPC_STATUS = "status"; | ||
519 | + | ||
520 | + /** | ||
510 | * Edge constants. | 521 | * Edge constants. |
511 | */ | 522 | */ |
512 | public static final String EDGE_COLUMN_FAMILY_NAME = "edge"; | 523 | public static final String EDGE_COLUMN_FAMILY_NAME = "edge"; |
1 | +/** | ||
2 | + * Copyright © 2016-2021 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.dao.model.sql; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.databind.JsonNode; | ||
19 | +import lombok.Data; | ||
20 | +import lombok.EqualsAndHashCode; | ||
21 | +import org.hibernate.annotations.Type; | ||
22 | +import org.hibernate.annotations.TypeDef; | ||
23 | +import org.thingsboard.server.common.data.id.DeviceId; | ||
24 | +import org.thingsboard.server.common.data.id.RpcId; | ||
25 | +import org.thingsboard.server.common.data.id.TenantId; | ||
26 | +import org.thingsboard.server.common.data.rpc.Rpc; | ||
27 | +import org.thingsboard.server.common.data.rpc.RpcStatus; | ||
28 | +import org.thingsboard.server.dao.model.BaseEntity; | ||
29 | +import org.thingsboard.server.dao.model.BaseSqlEntity; | ||
30 | +import org.thingsboard.server.dao.util.mapping.JsonStringType; | ||
31 | + | ||
32 | +import javax.persistence.Column; | ||
33 | +import javax.persistence.Entity; | ||
34 | +import javax.persistence.EnumType; | ||
35 | +import javax.persistence.Enumerated; | ||
36 | +import javax.persistence.Table; | ||
37 | +import java.util.UUID; | ||
38 | + | ||
39 | +import static org.thingsboard.server.dao.model.ModelConstants.RPC_DEVICE_ID; | ||
40 | +import static org.thingsboard.server.dao.model.ModelConstants.RPC_EXPIRATION_TIME; | ||
41 | +import static org.thingsboard.server.dao.model.ModelConstants.RPC_REQUEST; | ||
42 | +import static org.thingsboard.server.dao.model.ModelConstants.RPC_RESPONSE; | ||
43 | +import static org.thingsboard.server.dao.model.ModelConstants.RPC_STATUS; | ||
44 | +import static org.thingsboard.server.dao.model.ModelConstants.RPC_TABLE_NAME; | ||
45 | +import static org.thingsboard.server.dao.model.ModelConstants.RPC_TENANT_ID_COLUMN; | ||
46 | + | ||
47 | +@Data | ||
48 | +@EqualsAndHashCode(callSuper = true) | ||
49 | +@Entity | ||
50 | +@TypeDef(name = "json", typeClass = JsonStringType.class) | ||
51 | +@Table(name = RPC_TABLE_NAME) | ||
52 | +public class RpcEntity extends BaseSqlEntity<Rpc> implements BaseEntity<Rpc> { | ||
53 | + | ||
54 | + @Column(name = RPC_TENANT_ID_COLUMN) | ||
55 | + private UUID tenantId; | ||
56 | + | ||
57 | + @Column(name = RPC_DEVICE_ID) | ||
58 | + private UUID deviceId; | ||
59 | + | ||
60 | + @Column(name = RPC_EXPIRATION_TIME) | ||
61 | + private long expirationTime; | ||
62 | + | ||
63 | + @Type(type = "json") | ||
64 | + @Column(name = RPC_REQUEST) | ||
65 | + private JsonNode request; | ||
66 | + | ||
67 | + @Type(type = "json") | ||
68 | + @Column(name = RPC_RESPONSE) | ||
69 | + private JsonNode response; | ||
70 | + | ||
71 | + @Enumerated(EnumType.STRING) | ||
72 | + @Column(name = RPC_STATUS) | ||
73 | + private RpcStatus status; | ||
74 | + | ||
75 | + public RpcEntity() { | ||
76 | + super(); | ||
77 | + } | ||
78 | + | ||
79 | + public RpcEntity(Rpc rpc) { | ||
80 | + this.setUuid(rpc.getUuidId()); | ||
81 | + this.createdTime = rpc.getCreatedTime(); | ||
82 | + this.tenantId = rpc.getTenantId().getId(); | ||
83 | + this.deviceId = rpc.getDeviceId().getId(); | ||
84 | + this.expirationTime = rpc.getExpirationTime(); | ||
85 | + this.request = rpc.getRequest(); | ||
86 | + this.response = rpc.getResponse(); | ||
87 | + this.status = rpc.getStatus(); | ||
88 | + } | ||
89 | + | ||
90 | + @Override | ||
91 | + public Rpc toData() { | ||
92 | + Rpc rpc = new Rpc(new RpcId(id)); | ||
93 | + rpc.setCreatedTime(createdTime); | ||
94 | + rpc.setTenantId(new TenantId(tenantId)); | ||
95 | + rpc.setDeviceId(new DeviceId(deviceId)); | ||
96 | + rpc.setExpirationTime(expirationTime); | ||
97 | + rpc.setRequest(request); | ||
98 | + rpc.setResponse(response); | ||
99 | + rpc.setStatus(status); | ||
100 | + return rpc; | ||
101 | + } | ||
102 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 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.dao.rpc; | ||
17 | + | ||
18 | +import com.google.common.util.concurrent.ListenableFuture; | ||
19 | +import lombok.RequiredArgsConstructor; | ||
20 | +import lombok.extern.slf4j.Slf4j; | ||
21 | +import org.springframework.stereotype.Service; | ||
22 | +import org.thingsboard.server.common.data.id.DeviceId; | ||
23 | +import org.thingsboard.server.common.data.id.RpcId; | ||
24 | +import org.thingsboard.server.common.data.id.TenantId; | ||
25 | +import org.thingsboard.server.common.data.page.PageData; | ||
26 | +import org.thingsboard.server.common.data.page.PageLink; | ||
27 | +import org.thingsboard.server.common.data.rpc.Rpc; | ||
28 | +import org.thingsboard.server.common.data.rpc.RpcStatus; | ||
29 | +import org.thingsboard.server.dao.service.PaginatedRemover; | ||
30 | + | ||
31 | +import static org.thingsboard.server.dao.service.Validator.validateId; | ||
32 | +import static org.thingsboard.server.dao.service.Validator.validatePageLink; | ||
33 | + | ||
34 | +@Service | ||
35 | +@Slf4j | ||
36 | +@RequiredArgsConstructor | ||
37 | +public class BaseRpcService implements RpcService { | ||
38 | + public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; | ||
39 | + public static final String INCORRECT_RPC_ID = "Incorrect rpcId "; | ||
40 | + | ||
41 | + private final RpcDao rpcDao; | ||
42 | + | ||
43 | + @Override | ||
44 | + public Rpc save(Rpc rpc) { | ||
45 | + log.trace("Executing save, [{}]", rpc); | ||
46 | + return rpcDao.save(rpc.getTenantId(), rpc); | ||
47 | + } | ||
48 | + | ||
49 | + @Override | ||
50 | + public void deleteRpc(TenantId tenantId, RpcId rpcId) { | ||
51 | + log.trace("Executing deleteRpc, tenantId [{}], rpcId [{}]", tenantId, rpcId); | ||
52 | + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); | ||
53 | + validateId(rpcId, INCORRECT_RPC_ID + rpcId); | ||
54 | + rpcDao.removeById(tenantId, rpcId.getId()); | ||
55 | + } | ||
56 | + | ||
57 | + @Override | ||
58 | + public void deleteAllRpcByTenantId(TenantId tenantId) { | ||
59 | + log.trace("Executing deleteAllRpcByTenantId, tenantId [{}]", tenantId); | ||
60 | + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); | ||
61 | + tenantRpcRemover.removeEntities(tenantId, tenantId); | ||
62 | + } | ||
63 | + | ||
64 | + @Override | ||
65 | + public Rpc findById(TenantId tenantId, RpcId rpcId) { | ||
66 | + log.trace("Executing findById, tenantId [{}], rpcId [{}]", tenantId, rpcId); | ||
67 | + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); | ||
68 | + validateId(rpcId, INCORRECT_RPC_ID + rpcId); | ||
69 | + return rpcDao.findById(tenantId, rpcId.getId()); | ||
70 | + } | ||
71 | + | ||
72 | + @Override | ||
73 | + public ListenableFuture<Rpc> findRpcByIdAsync(TenantId tenantId, RpcId rpcId) { | ||
74 | + log.trace("Executing findRpcByIdAsync, tenantId [{}], rpcId: [{}]", tenantId, rpcId); | ||
75 | + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); | ||
76 | + validateId(rpcId, INCORRECT_RPC_ID + rpcId); | ||
77 | + return rpcDao.findByIdAsync(tenantId, rpcId.getId()); | ||
78 | + } | ||
79 | + | ||
80 | + @Override | ||
81 | + public PageData<Rpc> findAllByDeviceIdAndStatus(TenantId tenantId, DeviceId deviceId, RpcStatus rpcStatus, PageLink pageLink) { | ||
82 | + log.trace("Executing findAllByDeviceIdAndStatus, tenantId [{}], deviceId [{}], rpcStatus [{}], pageLink [{}]", tenantId, deviceId, rpcStatus, pageLink); | ||
83 | + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); | ||
84 | + validatePageLink(pageLink); | ||
85 | + return rpcDao.findAllByDeviceId(tenantId, deviceId, rpcStatus, pageLink); | ||
86 | + } | ||
87 | + | ||
88 | + private PaginatedRemover<TenantId, Rpc> tenantRpcRemover = | ||
89 | + new PaginatedRemover<>() { | ||
90 | + @Override | ||
91 | + protected PageData<Rpc> findEntities(TenantId tenantId, TenantId id, PageLink pageLink) { | ||
92 | + return rpcDao.findAllRpcByTenantId(id, pageLink); | ||
93 | + } | ||
94 | + | ||
95 | + @Override | ||
96 | + protected void removeEntity(TenantId tenantId, Rpc entity) { | ||
97 | + deleteRpc(tenantId, entity.getId()); | ||
98 | + } | ||
99 | + }; | ||
100 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 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.dao.rpc; | ||
17 | + | ||
18 | +import org.thingsboard.server.common.data.id.DeviceId; | ||
19 | +import org.thingsboard.server.common.data.id.TenantId; | ||
20 | +import org.thingsboard.server.common.data.page.PageData; | ||
21 | +import org.thingsboard.server.common.data.page.PageLink; | ||
22 | +import org.thingsboard.server.common.data.rpc.Rpc; | ||
23 | +import org.thingsboard.server.common.data.rpc.RpcStatus; | ||
24 | +import org.thingsboard.server.dao.Dao; | ||
25 | + | ||
26 | +public interface RpcDao extends Dao<Rpc> { | ||
27 | + PageData<Rpc> findAllByDeviceId(TenantId tenantId, DeviceId deviceId, RpcStatus rpcStatus, PageLink pageLink); | ||
28 | + | ||
29 | + PageData<Rpc> findAllRpcByTenantId(TenantId tenantId, PageLink pageLink); | ||
30 | + | ||
31 | + Long deleteOutdatedRpcByTenantId(TenantId tenantId, Long expirationTime); | ||
32 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 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.dao.sql.rpc; | ||
17 | + | ||
18 | +import lombok.AllArgsConstructor; | ||
19 | +import lombok.extern.slf4j.Slf4j; | ||
20 | +import org.springframework.data.repository.CrudRepository; | ||
21 | +import org.springframework.stereotype.Component; | ||
22 | +import org.thingsboard.server.common.data.id.DeviceId; | ||
23 | +import org.thingsboard.server.common.data.id.TenantId; | ||
24 | +import org.thingsboard.server.common.data.page.PageData; | ||
25 | +import org.thingsboard.server.common.data.page.PageLink; | ||
26 | +import org.thingsboard.server.common.data.rpc.Rpc; | ||
27 | +import org.thingsboard.server.common.data.rpc.RpcStatus; | ||
28 | +import org.thingsboard.server.dao.DaoUtil; | ||
29 | +import org.thingsboard.server.dao.model.sql.RpcEntity; | ||
30 | +import org.thingsboard.server.dao.rpc.RpcDao; | ||
31 | +import org.thingsboard.server.dao.sql.JpaAbstractDao; | ||
32 | + | ||
33 | +import java.util.UUID; | ||
34 | + | ||
35 | +@Slf4j | ||
36 | +@Component | ||
37 | +@AllArgsConstructor | ||
38 | +public class JpaRpcDao extends JpaAbstractDao<RpcEntity, Rpc> implements RpcDao { | ||
39 | + | ||
40 | + private final RpcRepository rpcRepository; | ||
41 | + | ||
42 | + @Override | ||
43 | + protected Class<RpcEntity> getEntityClass() { | ||
44 | + return RpcEntity.class; | ||
45 | + } | ||
46 | + | ||
47 | + @Override | ||
48 | + protected CrudRepository<RpcEntity, UUID> getCrudRepository() { | ||
49 | + return rpcRepository; | ||
50 | + } | ||
51 | + | ||
52 | + @Override | ||
53 | + public PageData<Rpc> findAllByDeviceId(TenantId tenantId, DeviceId deviceId, RpcStatus rpcStatus, PageLink pageLink) { | ||
54 | + return DaoUtil.toPageData(rpcRepository.findAllByTenantIdAndDeviceIdAndStatus(tenantId.getId(), deviceId.getId(), rpcStatus, DaoUtil.toPageable(pageLink))); | ||
55 | + } | ||
56 | + | ||
57 | + @Override | ||
58 | + public PageData<Rpc> findAllRpcByTenantId(TenantId tenantId, PageLink pageLink) { | ||
59 | + return DaoUtil.toPageData(rpcRepository.findAllByTenantId(tenantId.getId(), DaoUtil.toPageable(pageLink))); | ||
60 | + } | ||
61 | + | ||
62 | + @Override | ||
63 | + public Long deleteOutdatedRpcByTenantId(TenantId tenantId, Long expirationTime) { | ||
64 | + return rpcRepository.deleteOutdatedRpcByTenantId(tenantId.getId(), expirationTime); | ||
65 | + } | ||
66 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 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.dao.sql.rpc; | ||
17 | + | ||
18 | +import org.springframework.data.domain.Page; | ||
19 | +import org.springframework.data.domain.Pageable; | ||
20 | +import org.springframework.data.jpa.repository.Query; | ||
21 | +import org.springframework.data.repository.CrudRepository; | ||
22 | +import org.springframework.data.repository.query.Param; | ||
23 | +import org.thingsboard.server.common.data.rpc.RpcStatus; | ||
24 | +import org.thingsboard.server.dao.model.sql.RpcEntity; | ||
25 | + | ||
26 | +import java.util.UUID; | ||
27 | + | ||
28 | +public interface RpcRepository extends CrudRepository<RpcEntity, UUID> { | ||
29 | + Page<RpcEntity> findAllByTenantIdAndDeviceIdAndStatus(UUID tenantId, UUID deviceId, RpcStatus status, Pageable pageable); | ||
30 | + | ||
31 | + Page<RpcEntity> findAllByTenantId(UUID tenantId, Pageable pageable); | ||
32 | + | ||
33 | + @Query(value = "WITH deleted AS (DELETE FROM rpc WHERE (tenant_id = :tenantId AND created_time < :expirationTime) IS TRUE RETURNING *) SELECT count(*) FROM deleted", | ||
34 | + nativeQuery = true) | ||
35 | + Long deleteOutdatedRpcByTenantId(@Param("tenantId") UUID tenantId, @Param("expirationTime") Long expirationTime); | ||
36 | +} |
@@ -37,6 +37,7 @@ import org.thingsboard.server.dao.entityview.EntityViewService; | @@ -37,6 +37,7 @@ import org.thingsboard.server.dao.entityview.EntityViewService; | ||
37 | import org.thingsboard.server.dao.exception.DataValidationException; | 37 | import org.thingsboard.server.dao.exception.DataValidationException; |
38 | import org.thingsboard.server.dao.ota.OtaPackageService; | 38 | import org.thingsboard.server.dao.ota.OtaPackageService; |
39 | import org.thingsboard.server.dao.resource.ResourceService; | 39 | import org.thingsboard.server.dao.resource.ResourceService; |
40 | +import org.thingsboard.server.dao.rpc.RpcService; | ||
40 | import org.thingsboard.server.dao.rule.RuleChainService; | 41 | import org.thingsboard.server.dao.rule.RuleChainService; |
41 | import org.thingsboard.server.dao.service.DataValidator; | 42 | import org.thingsboard.server.dao.service.DataValidator; |
42 | import org.thingsboard.server.dao.service.PaginatedRemover; | 43 | import org.thingsboard.server.dao.service.PaginatedRemover; |
@@ -96,6 +97,9 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe | @@ -96,6 +97,9 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe | ||
96 | @Autowired | 97 | @Autowired |
97 | private OtaPackageService otaPackageService; | 98 | private OtaPackageService otaPackageService; |
98 | 99 | ||
100 | + @Autowired | ||
101 | + private RpcService rpcService; | ||
102 | + | ||
99 | @Override | 103 | @Override |
100 | public Tenant findTenantById(TenantId tenantId) { | 104 | public Tenant findTenantById(TenantId tenantId) { |
101 | log.trace("Executing findTenantById [{}]", tenantId); | 105 | log.trace("Executing findTenantById [{}]", tenantId); |
@@ -151,6 +155,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe | @@ -151,6 +155,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe | ||
151 | apiUsageStateService.deleteApiUsageStateByTenantId(tenantId); | 155 | apiUsageStateService.deleteApiUsageStateByTenantId(tenantId); |
152 | resourceService.deleteResourcesByTenantId(tenantId); | 156 | resourceService.deleteResourcesByTenantId(tenantId); |
153 | otaPackageService.deleteOtaPackagesByTenantId(tenantId); | 157 | otaPackageService.deleteOtaPackagesByTenantId(tenantId); |
158 | + rpcService.deleteAllRpcByTenantId(tenantId); | ||
154 | tenantDao.removeById(tenantId, tenantId.getId()); | 159 | tenantDao.removeById(tenantId, tenantId.getId()); |
155 | deleteEntityRelations(tenantId, tenantId); | 160 | deleteEntityRelations(tenantId, tenantId); |
156 | } | 161 | } |
@@ -567,3 +567,14 @@ CREATE TABLE IF NOT EXISTS edge_event ( | @@ -567,3 +567,14 @@ CREATE TABLE IF NOT EXISTS edge_event ( | ||
567 | tenant_id uuid, | 567 | tenant_id uuid, |
568 | ts bigint NOT NULL | 568 | ts bigint NOT NULL |
569 | ); | 569 | ); |
570 | + | ||
571 | +CREATE TABLE IF NOT EXISTS rpc ( | ||
572 | + id uuid NOT NULL CONSTRAINT rpc_pkey PRIMARY KEY, | ||
573 | + created_time bigint NOT NULL, | ||
574 | + tenant_id uuid NOT NULL, | ||
575 | + device_id uuid NOT NULL, | ||
576 | + expiration_time bigint NOT NULL, | ||
577 | + request varchar(10000000) NOT NULL, | ||
578 | + response varchar(10000000), | ||
579 | + status varchar(255) NOT NULL | ||
580 | +); |
@@ -46,3 +46,4 @@ CREATE INDEX IF NOT EXISTS idx_attribute_kv_by_key_and_last_update_ts ON attribu | @@ -46,3 +46,4 @@ CREATE INDEX IF NOT EXISTS idx_attribute_kv_by_key_and_last_update_ts ON attribu | ||
46 | 46 | ||
47 | CREATE INDEX IF NOT EXISTS idx_audit_log_tenant_id_and_created_time ON audit_log(tenant_id, created_time); | 47 | CREATE INDEX IF NOT EXISTS idx_audit_log_tenant_id_and_created_time ON audit_log(tenant_id, created_time); |
48 | 48 | ||
49 | +CREATE INDEX IF NOT EXISTS idx_rpc_tenant_id_device_id ON rpc(tenant_id, device_id); |
@@ -605,6 +605,17 @@ CREATE TABLE IF NOT EXISTS edge_event ( | @@ -605,6 +605,17 @@ CREATE TABLE IF NOT EXISTS edge_event ( | ||
605 | ts bigint NOT NULL | 605 | ts bigint NOT NULL |
606 | ); | 606 | ); |
607 | 607 | ||
608 | +CREATE TABLE IF NOT EXISTS rpc ( | ||
609 | + id uuid NOT NULL CONSTRAINT rpc_pkey PRIMARY KEY, | ||
610 | + created_time bigint NOT NULL, | ||
611 | + tenant_id uuid NOT NULL, | ||
612 | + device_id uuid NOT NULL, | ||
613 | + expiration_time bigint NOT NULL, | ||
614 | + request varchar(10000000) NOT NULL, | ||
615 | + response varchar(10000000), | ||
616 | + status varchar(255) NOT NULL | ||
617 | +); | ||
618 | + | ||
608 | CREATE OR REPLACE PROCEDURE cleanup_events_by_ttl(IN ttl bigint, IN debug_ttl bigint, INOUT deleted bigint) | 619 | CREATE OR REPLACE PROCEDURE cleanup_events_by_ttl(IN ttl bigint, IN debug_ttl bigint, INOUT deleted bigint) |
609 | LANGUAGE plpgsql AS | 620 | LANGUAGE plpgsql AS |
610 | $$ | 621 | $$ |
@@ -36,4 +36,5 @@ DROP TABLE IF EXISTS resource; | @@ -36,4 +36,5 @@ DROP TABLE IF EXISTS resource; | ||
36 | DROP TABLE IF EXISTS ota_package; | 36 | DROP TABLE IF EXISTS ota_package; |
37 | DROP TABLE IF EXISTS edge; | 37 | DROP TABLE IF EXISTS edge; |
38 | DROP TABLE IF EXISTS edge_event; | 38 | DROP TABLE IF EXISTS edge_event; |
39 | +DROP TABLE IF EXISTS rpc; | ||
39 | DROP FUNCTION IF EXISTS to_uuid; | 40 | DROP FUNCTION IF EXISTS to_uuid; |
@@ -37,3 +37,4 @@ DROP TABLE IF EXISTS resource; | @@ -37,3 +37,4 @@ DROP TABLE IF EXISTS resource; | ||
37 | DROP TABLE IF EXISTS firmware; | 37 | DROP TABLE IF EXISTS firmware; |
38 | DROP TABLE IF EXISTS edge; | 38 | DROP TABLE IF EXISTS edge; |
39 | DROP TABLE IF EXISTS edge_event; | 39 | DROP TABLE IF EXISTS edge_event; |
40 | +DROP TABLE IF EXISTS rpc; |
@@ -35,6 +35,7 @@ public final class RuleEngineDeviceRpcRequest { | @@ -35,6 +35,7 @@ public final class RuleEngineDeviceRpcRequest { | ||
35 | private final UUID requestUUID; | 35 | private final UUID requestUUID; |
36 | private final String originServiceId; | 36 | private final String originServiceId; |
37 | private final boolean oneway; | 37 | private final boolean oneway; |
38 | + private final boolean persisted; | ||
38 | private final String method; | 39 | private final String method; |
39 | private final String body; | 40 | private final String body; |
40 | private final long expirationTime; | 41 | private final long expirationTime; |
@@ -33,8 +33,8 @@ import org.thingsboard.server.common.msg.session.SessionMsgType; | @@ -33,8 +33,8 @@ import org.thingsboard.server.common.msg.session.SessionMsgType; | ||
33 | type = ComponentType.FILTER, | 33 | type = ComponentType.FILTER, |
34 | name = "message type switch", | 34 | name = "message type switch", |
35 | configClazz = EmptyNodeConfiguration.class, | 35 | configClazz = EmptyNodeConfiguration.class, |
36 | - relationTypes = {"Post attributes", "Post telemetry", "RPC Request from Device", "RPC Request to Device", "Activity Event", "Inactivity Event", | ||
37 | - "Connect Event", "Disconnect Event", "Entity Created", "Entity Updated", "Entity Deleted", "Entity Assigned", | 36 | + relationTypes = {"Post attributes", "Post telemetry", "RPC Request from Device", "RPC Request to Device", "RPC Queued", "RPC Delivered", "RPC Successful", "RPC Timeout", "RPC Failed", |
37 | + "Activity Event", "Inactivity Event", "Connect Event", "Disconnect Event", "Entity Created", "Entity Updated", "Entity Deleted", "Entity Assigned", | ||
38 | "Entity Unassigned", "Attributes Updated", "Attributes Deleted", "Alarm Acknowledged", "Alarm Cleared", "Other", "Entity Assigned From Tenant", "Entity Assigned To Tenant", | 38 | "Entity Unassigned", "Attributes Updated", "Attributes Deleted", "Alarm Acknowledged", "Alarm Cleared", "Other", "Entity Assigned From Tenant", "Entity Assigned To Tenant", |
39 | "Timeseries Updated", "Timeseries Deleted"}, | 39 | "Timeseries Updated", "Timeseries Deleted"}, |
40 | nodeDescription = "Route incoming messages by Message Type", | 40 | nodeDescription = "Route incoming messages by Message Type", |
@@ -95,6 +95,16 @@ public class TbMsgTypeSwitchNode implements TbNode { | @@ -95,6 +95,16 @@ public class TbMsgTypeSwitchNode implements TbNode { | ||
95 | relationType = "Timeseries Updated"; | 95 | relationType = "Timeseries Updated"; |
96 | } else if (msg.getType().equals(DataConstants.TIMESERIES_DELETED)) { | 96 | } else if (msg.getType().equals(DataConstants.TIMESERIES_DELETED)) { |
97 | relationType = "Timeseries Deleted"; | 97 | relationType = "Timeseries Deleted"; |
98 | + } else if (msg.getType().equals(DataConstants.RPC_QUEUED)) { | ||
99 | + relationType = "RPC Queued"; | ||
100 | + } else if (msg.getType().equals(DataConstants.RPC_DELIVERED)) { | ||
101 | + relationType = "RPC Delivered"; | ||
102 | + } else if (msg.getType().equals(DataConstants.RPC_SUCCESSFUL)) { | ||
103 | + relationType = "RPC Successful"; | ||
104 | + } else if (msg.getType().equals(DataConstants.RPC_TIMEOUT)) { | ||
105 | + relationType = "RPC Timeout"; | ||
106 | + } else if (msg.getType().equals(DataConstants.RPC_FAILED)) { | ||
107 | + relationType = "RPC Failed"; | ||
98 | } else { | 108 | } else { |
99 | relationType = "Other"; | 109 | relationType = "Other"; |
100 | } | 110 | } |
@@ -81,6 +81,9 @@ public class TbSendRPCRequestNode implements TbNode { | @@ -81,6 +81,9 @@ public class TbSendRPCRequestNode implements TbNode { | ||
81 | tmp = msg.getMetaData().getValue("oneway"); | 81 | tmp = msg.getMetaData().getValue("oneway"); |
82 | boolean oneway = !StringUtils.isEmpty(tmp) && Boolean.parseBoolean(tmp); | 82 | boolean oneway = !StringUtils.isEmpty(tmp) && Boolean.parseBoolean(tmp); |
83 | 83 | ||
84 | + tmp = msg.getMetaData().getValue("persisted"); | ||
85 | + boolean persisted = !StringUtils.isEmpty(tmp) && Boolean.parseBoolean(tmp); | ||
86 | + | ||
84 | tmp = msg.getMetaData().getValue("requestUUID"); | 87 | tmp = msg.getMetaData().getValue("requestUUID"); |
85 | UUID requestUUID = !StringUtils.isEmpty(tmp) ? UUID.fromString(tmp) : Uuids.timeBased(); | 88 | UUID requestUUID = !StringUtils.isEmpty(tmp) ? UUID.fromString(tmp) : Uuids.timeBased(); |
86 | tmp = msg.getMetaData().getValue("originServiceId"); | 89 | tmp = msg.getMetaData().getValue("originServiceId"); |
@@ -108,6 +111,7 @@ public class TbSendRPCRequestNode implements TbNode { | @@ -108,6 +111,7 @@ public class TbSendRPCRequestNode implements TbNode { | ||
108 | .originServiceId(originServiceId) | 111 | .originServiceId(originServiceId) |
109 | .expirationTime(expirationTime) | 112 | .expirationTime(expirationTime) |
110 | .restApiCall(restApiCall) | 113 | .restApiCall(restApiCall) |
114 | + .persisted(persisted) | ||
111 | .build(); | 115 | .build(); |
112 | 116 | ||
113 | ctx.getRpcService().sendRpcRequestToDevice(request, ruleEngineDeviceRpcResponse -> { | 117 | ctx.getRpcService().sendRpcRequestToDevice(request, ruleEngineDeviceRpcResponse -> { |
@@ -160,9 +160,9 @@ | @@ -160,9 +160,9 @@ | ||
160 | <!-- <div fxLayout="column">--> | 160 | <!-- <div fxLayout="column">--> |
161 | <!-- <mat-form-field class="mat-block">--> | 161 | <!-- <mat-form-field class="mat-block">--> |
162 | <!-- <mat-label>{{ 'device-profile.lwm2m.client-strategy-label' | translate }}</mat-label>--> | 162 | <!-- <mat-label>{{ 'device-profile.lwm2m.client-strategy-label' | translate }}</mat-label>--> |
163 | -<!-- <mat-select formControlName="clientStrategy"--> | 163 | +<!-- <mat-select formControlName="clientOnlyObserveAfterConnect"--> |
164 | <!-- matTooltip="{{ 'device-profile.lwm2m.client-strategy-tip' | translate:--> | 164 | <!-- matTooltip="{{ 'device-profile.lwm2m.client-strategy-tip' | translate:--> |
165 | -<!-- { count: +lwm2mDeviceProfileFormGroup.get('clientStrategy').value } }}"--> | 165 | +<!-- { count: +lwm2mDeviceProfileFormGroup.get('clientOnlyObserveAfterConnect').value } }}"--> |
166 | <!-- matTooltipPosition="above">--> | 166 | <!-- matTooltipPosition="above">--> |
167 | <!-- <mat-option value=1>{{ 'device-profile.lwm2m.client-strategy-connect' | translate:--> | 167 | <!-- <mat-option value=1>{{ 'device-profile.lwm2m.client-strategy-connect' | translate:--> |
168 | <!-- {count: 1} }}</mat-option>--> | 168 | <!-- {count: 1} }}</mat-option>--> |
@@ -97,7 +97,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -97,7 +97,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
97 | binding: [], | 97 | binding: [], |
98 | bootstrapServer: [null, Validators.required], | 98 | bootstrapServer: [null, Validators.required], |
99 | lwm2mServer: [null, Validators.required], | 99 | lwm2mServer: [null, Validators.required], |
100 | - clientStrategy: [1, []], | 100 | + clientOnlyObserveAfterConnect: [1, []], |
101 | fwUpdateStrategy: [1, []], | 101 | fwUpdateStrategy: [1, []], |
102 | swUpdateStrategy: [1, []], | 102 | swUpdateStrategy: [1, []], |
103 | fwUpdateRecourse: [{value: '', disabled: true}, []], | 103 | fwUpdateRecourse: [{value: '', disabled: true}, []], |
@@ -216,7 +216,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -216,7 +216,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
216 | binding: this.configurationValue.bootstrap.servers.binding, | 216 | binding: this.configurationValue.bootstrap.servers.binding, |
217 | bootstrapServer: this.configurationValue.bootstrap.bootstrapServer, | 217 | bootstrapServer: this.configurationValue.bootstrap.bootstrapServer, |
218 | lwm2mServer: this.configurationValue.bootstrap.lwm2mServer, | 218 | lwm2mServer: this.configurationValue.bootstrap.lwm2mServer, |
219 | - clientStrategy: this.configurationValue.clientLwM2mSettings.clientStrategy, | 219 | + clientOnlyObserveAfterConnect: this.configurationValue.clientLwM2mSettings.clientOnlyObserveAfterConnect, |
220 | fwUpdateStrategy: this.configurationValue.clientLwM2mSettings.fwUpdateStrategy || 1, | 220 | fwUpdateStrategy: this.configurationValue.clientLwM2mSettings.fwUpdateStrategy || 1, |
221 | swUpdateStrategy: this.configurationValue.clientLwM2mSettings.swUpdateStrategy || 1, | 221 | swUpdateStrategy: this.configurationValue.clientLwM2mSettings.swUpdateStrategy || 1, |
222 | fwUpdateRecourse: fwResource, | 222 | fwUpdateRecourse: fwResource, |
@@ -257,7 +257,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -257,7 +257,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
257 | bootstrapServers.defaultMinPeriod = config.defaultMinPeriod; | 257 | bootstrapServers.defaultMinPeriod = config.defaultMinPeriod; |
258 | bootstrapServers.notifIfDisabled = config.notifIfDisabled; | 258 | bootstrapServers.notifIfDisabled = config.notifIfDisabled; |
259 | bootstrapServers.binding = config.binding; | 259 | bootstrapServers.binding = config.binding; |
260 | - this.configurationValue.clientLwM2mSettings.clientStrategy = config.clientStrategy; | 260 | + this.configurationValue.clientLwM2mSettings.clientOnlyObserveAfterConnect = config.clientOnlyObserveAfterConnect; |
261 | this.configurationValue.clientLwM2mSettings.fwUpdateStrategy = config.fwUpdateStrategy; | 261 | this.configurationValue.clientLwM2mSettings.fwUpdateStrategy = config.fwUpdateStrategy; |
262 | this.configurationValue.clientLwM2mSettings.swUpdateStrategy = config.swUpdateStrategy; | 262 | this.configurationValue.clientLwM2mSettings.swUpdateStrategy = config.swUpdateStrategy; |
263 | this.configurationValue.clientLwM2mSettings.fwUpdateRecourse = config.fwUpdateRecourse; | 263 | this.configurationValue.clientLwM2mSettings.fwUpdateRecourse = config.fwUpdateRecourse; |
@@ -168,7 +168,7 @@ export interface Lwm2mProfileConfigModels { | @@ -168,7 +168,7 @@ export interface Lwm2mProfileConfigModels { | ||
168 | } | 168 | } |
169 | 169 | ||
170 | export interface ClientLwM2mSettings { | 170 | export interface ClientLwM2mSettings { |
171 | - clientStrategy: string; | 171 | + clientOnlyObserveAfterConnect: number; |
172 | fwUpdateStrategy: number; | 172 | fwUpdateStrategy: number; |
173 | swUpdateStrategy: number; | 173 | swUpdateStrategy: number; |
174 | fwUpdateRecourse: string; | 174 | fwUpdateRecourse: string; |
@@ -240,7 +240,7 @@ export function getDefaultProfileConfig(hostname?: any): Lwm2mProfileConfigModel | @@ -240,7 +240,7 @@ export function getDefaultProfileConfig(hostname?: any): Lwm2mProfileConfigModel | ||
240 | 240 | ||
241 | function getDefaultProfileClientLwM2mSettingsConfig(): ClientLwM2mSettings { | 241 | function getDefaultProfileClientLwM2mSettingsConfig(): ClientLwM2mSettings { |
242 | return { | 242 | return { |
243 | - clientStrategy: '1', | 243 | + clientOnlyObserveAfterConnect: 1, |
244 | fwUpdateStrategy: 1, | 244 | fwUpdateStrategy: 1, |
245 | swUpdateStrategy: 1, | 245 | swUpdateStrategy: 1, |
246 | fwUpdateRecourse: DEFAULT_FW_UPDATE_RESOURCE, | 246 | fwUpdateRecourse: DEFAULT_FW_UPDATE_RESOURCE, |
@@ -197,6 +197,18 @@ | @@ -197,6 +197,18 @@ | ||
197 | </mat-error> | 197 | </mat-error> |
198 | </mat-form-field> | 198 | </mat-form-field> |
199 | <mat-form-field class="mat-block"> | 199 | <mat-form-field class="mat-block"> |
200 | + <mat-label translate>tenant-profile.rpc-ttl-days</mat-label> | ||
201 | + <input matInput required min="0" step="1" | ||
202 | + formControlName="rpcTtlDays" | ||
203 | + type="number"> | ||
204 | + <mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('rpcTtlDays').hasError('required')"> | ||
205 | + {{ 'tenant-profile.rpc-ttl-days-required' | translate}} | ||
206 | + </mat-error> | ||
207 | + <mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('rpcTtlDays').hasError('min')"> | ||
208 | + {{ 'tenant-profile.rpc-ttl-days-days-range' | translate}} | ||
209 | + </mat-error> | ||
210 | + </mat-form-field> | ||
211 | + <mat-form-field class="mat-block"> | ||
200 | <mat-label translate>tenant-profile.max-rule-node-executions-per-message</mat-label> | 212 | <mat-label translate>tenant-profile.max-rule-node-executions-per-message</mat-label> |
201 | <input matInput required min="0" step="1" | 213 | <input matInput required min="0" step="1" |
202 | formControlName="maxRuleNodeExecutionsPerMessage" | 214 | formControlName="maxRuleNodeExecutionsPerMessage" |
@@ -77,7 +77,8 @@ export class DefaultTenantProfileConfigurationComponent implements ControlValueA | @@ -77,7 +77,8 @@ export class DefaultTenantProfileConfigurationComponent implements ControlValueA | ||
77 | maxSms: [null, [Validators.required, Validators.min(0)]], | 77 | maxSms: [null, [Validators.required, Validators.min(0)]], |
78 | maxCreatedAlarms: [null, [Validators.required, Validators.min(0)]], | 78 | maxCreatedAlarms: [null, [Validators.required, Validators.min(0)]], |
79 | defaultStorageTtlDays: [null, [Validators.required, Validators.min(0)]], | 79 | defaultStorageTtlDays: [null, [Validators.required, Validators.min(0)]], |
80 | - alarmsTtlDays: [null, [Validators.required, Validators.min(0)]] | 80 | + alarmsTtlDays: [null, [Validators.required, Validators.min(0)]], |
81 | + rpcTtlDays: [null, [Validators.required, Validators.min(0)]] | ||
81 | }); | 82 | }); |
82 | this.defaultTenantProfileConfigurationFormGroup.valueChanges.subscribe(() => { | 83 | this.defaultTenantProfileConfigurationFormGroup.valueChanges.subscribe(() => { |
83 | this.updateModel(); | 84 | this.updateModel(); |
@@ -352,7 +352,12 @@ export enum MessageType { | @@ -352,7 +352,12 @@ export enum MessageType { | ||
352 | ATTRIBUTES_UPDATED = 'ATTRIBUTES_UPDATED', | 352 | ATTRIBUTES_UPDATED = 'ATTRIBUTES_UPDATED', |
353 | ATTRIBUTES_DELETED = 'ATTRIBUTES_DELETED', | 353 | ATTRIBUTES_DELETED = 'ATTRIBUTES_DELETED', |
354 | TIMESERIES_UPDATED = 'TIMESERIES_UPDATED', | 354 | TIMESERIES_UPDATED = 'TIMESERIES_UPDATED', |
355 | - TIMESERIES_DELETED = 'TIMESERIES_DELETED' | 355 | + TIMESERIES_DELETED = 'TIMESERIES_DELETED', |
356 | + RPC_QUEUED = 'RPC_QUEUED', | ||
357 | + RPC_DELIVERED = 'RPC_DELIVERED', | ||
358 | + RPC_SUCCESSFUL = 'RPC_SUCCESSFUL', | ||
359 | + RPC_TIMEOUT = 'RPC_TIMEOUT', | ||
360 | + RPC_FAILED = 'RPC_FAILED' | ||
356 | } | 361 | } |
357 | 362 | ||
358 | export const messageTypeNames = new Map<MessageType, string>( | 363 | export const messageTypeNames = new Map<MessageType, string>( |
@@ -373,7 +378,12 @@ export const messageTypeNames = new Map<MessageType, string>( | @@ -373,7 +378,12 @@ export const messageTypeNames = new Map<MessageType, string>( | ||
373 | [MessageType.ATTRIBUTES_UPDATED, 'Attributes Updated'], | 378 | [MessageType.ATTRIBUTES_UPDATED, 'Attributes Updated'], |
374 | [MessageType.ATTRIBUTES_DELETED, 'Attributes Deleted'], | 379 | [MessageType.ATTRIBUTES_DELETED, 'Attributes Deleted'], |
375 | [MessageType.TIMESERIES_UPDATED, 'Timeseries Updated'], | 380 | [MessageType.TIMESERIES_UPDATED, 'Timeseries Updated'], |
376 | - [MessageType.TIMESERIES_DELETED, 'Timeseries Deleted'] | 381 | + [MessageType.TIMESERIES_DELETED, 'Timeseries Deleted'], |
382 | + [MessageType.RPC_QUEUED, 'RPC Queued'], | ||
383 | + [MessageType.RPC_DELIVERED, 'RPC Delivered'], | ||
384 | + [MessageType.RPC_SUCCESSFUL, 'RPC Successful'], | ||
385 | + [MessageType.RPC_TIMEOUT, 'RPC Timeout'], | ||
386 | + [MessageType.RPC_FAILED, 'RPC Failed'] | ||
377 | ] | 387 | ] |
378 | ); | 388 | ); |
379 | 389 |
@@ -53,6 +53,7 @@ export interface DefaultTenantProfileConfiguration { | @@ -53,6 +53,7 @@ export interface DefaultTenantProfileConfiguration { | ||
53 | 53 | ||
54 | defaultStorageTtlDays: number; | 54 | defaultStorageTtlDays: number; |
55 | alarmsTtlDays: number; | 55 | alarmsTtlDays: number; |
56 | + rpcTtlDays: number; | ||
56 | } | 57 | } |
57 | 58 | ||
58 | export type TenantProfileConfigurations = DefaultTenantProfileConfiguration; | 59 | export type TenantProfileConfigurations = DefaultTenantProfileConfiguration; |
@@ -85,7 +86,8 @@ export function createTenantProfileConfiguration(type: TenantProfileType): Tenan | @@ -85,7 +86,8 @@ export function createTenantProfileConfiguration(type: TenantProfileType): Tenan | ||
85 | maxSms: 0, | 86 | maxSms: 0, |
86 | maxCreatedAlarms: 0, | 87 | maxCreatedAlarms: 0, |
87 | defaultStorageTtlDays: 0, | 88 | defaultStorageTtlDays: 0, |
88 | - alarmsTtlDays: 0 | 89 | + alarmsTtlDays: 0, |
90 | + rpcTtlDays: 0 | ||
89 | }; | 91 | }; |
90 | configuration = {...defaultConfiguration, type: TenantProfileType.DEFAULT}; | 92 | configuration = {...defaultConfiguration, type: TenantProfileType.DEFAULT}; |
91 | break; | 93 | break; |
@@ -2638,6 +2638,9 @@ | @@ -2638,6 +2638,9 @@ | ||
2638 | "alarms-ttl-days": "Alarms TTL days (0 - unlimited)", | 2638 | "alarms-ttl-days": "Alarms TTL days (0 - unlimited)", |
2639 | "alarms-ttl-days-required": "Alarms TTL days required", | 2639 | "alarms-ttl-days-required": "Alarms TTL days required", |
2640 | "alarms-ttl-days-days-range": "Alarms TTL days can't be negative", | 2640 | "alarms-ttl-days-days-range": "Alarms TTL days can't be negative", |
2641 | + "rpc-ttl-days": "RPC TTL days (0 - unlimited)", | ||
2642 | + "rpc-ttl-days-required": "RPC TTL days required", | ||
2643 | + "rpc-ttl-days-days-range": "RPC TTL days can't be negative", | ||
2641 | "max-rule-node-executions-per-message": "Maximum number of rule node executions per message (0 - unlimited)", | 2644 | "max-rule-node-executions-per-message": "Maximum number of rule node executions per message (0 - unlimited)", |
2642 | "max-rule-node-executions-per-message-required": "Maximum number of rule node executions per message is required.", | 2645 | "max-rule-node-executions-per-message-required": "Maximum number of rule node executions per message is required.", |
2643 | "max-rule-node-executions-per-message-range": "Maximum number of rule node executions per message can't be negative", | 2646 | "max-rule-node-executions-per-message-range": "Maximum number of rule node executions per message can't be negative", |