Commit 7ec6923451f6a2240f5e69af95b64e956b80fb1f

Authored by Andrew Shvayka
Committed by GitHub
2 parents 290074ff 0e6df2a3

Merge pull request #4824 from YevhenBondarenko/feature/lwm2m-client-store

fetch all clients after startUp
... ... @@ -269,7 +269,9 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
269 269 ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(msg.getId());
270 270 if (requestMd != null) {
271 271 log.debug("[{}] RPC request [{}] timeout detected!", deviceId, msg.getId());
272   - systemContext.getTbRpcService().save(tenantId, new RpcId(requestMd.getMsg().getMsg().getId()), RpcStatus.TIMEOUT, null);
  272 + if (requestMd.getMsg().getMsg().isPersisted()) {
  273 + systemContext.getTbRpcService().save(tenantId, new RpcId(requestMd.getMsg().getMsg().getId()), RpcStatus.TIMEOUT, null);
  274 + }
273 275 systemContext.getTbCoreDeviceRpcService().processRpcResponseFromDeviceActor(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(),
274 276 null, requestMd.isSent() ? RpcError.TIMEOUT : RpcError.NO_ACTIVE_CONNECTION));
275 277 }
... ...
... ... @@ -16,34 +16,24 @@
16 16 package org.thingsboard.server.transport.lwm2m.server;
17 17
18 18 import com.fasterxml.jackson.databind.ObjectMapper;
19   -import com.google.gson.JsonObject;
20   -import com.google.gson.JsonParser;
21   -import com.google.gson.JsonSyntaxException;
22 19 import lombok.extern.slf4j.Slf4j;
23 20 import org.apache.commons.lang3.StringUtils;
24 21 import org.eclipse.leshan.core.attributes.Attribute;
25 22 import org.eclipse.leshan.core.attributes.AttributeSet;
26 23 import org.eclipse.leshan.core.model.ObjectModel;
27 24 import org.eclipse.leshan.core.model.ResourceModel;
28   -import org.eclipse.leshan.core.node.LwM2mMultipleResource;
29   -import org.eclipse.leshan.core.node.LwM2mNode;
30   -import org.eclipse.leshan.core.node.LwM2mObject;
31   -import org.eclipse.leshan.core.node.LwM2mObjectInstance;
32 25 import org.eclipse.leshan.core.node.LwM2mPath;
33 26 import org.eclipse.leshan.core.node.LwM2mResource;
34   -import org.eclipse.leshan.core.node.LwM2mSingleResource;
35 27 import org.eclipse.leshan.core.node.codec.CodecException;
36 28 import org.eclipse.leshan.core.request.SimpleDownlinkRequest;
37 29 import org.eclipse.leshan.core.request.WriteAttributesRequest;
38 30 import org.eclipse.leshan.core.util.Hex;
39 31 import org.eclipse.leshan.server.registration.Registration;
40   -import org.nustaq.serialization.FSTConfiguration;
41 32 import org.thingsboard.server.common.data.DeviceProfile;
42 33 import org.thingsboard.server.common.data.DeviceTransportType;
43 34 import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfiguration;
44 35 import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
45 36 import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
46   -import org.thingsboard.server.common.transport.TransportServiceCallback;
47 37 import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion;
48 38 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
49 39 import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue;
... ... @@ -56,10 +46,8 @@ import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMs
56 46 import java.util.ArrayList;
57 47 import java.util.Arrays;
58 48 import java.util.Date;
59   -import java.util.LinkedList;
60 49 import java.util.List;
61 50 import java.util.Map;
62   -import java.util.Optional;
63 51 import java.util.concurrent.ConcurrentHashMap;
64 52
65 53 import static org.eclipse.leshan.core.attributes.Attribute.DIMENSION;
... ...
... ... @@ -23,9 +23,6 @@ import org.eclipse.leshan.core.model.ResourceModel;
23 23 import org.eclipse.leshan.core.node.LwM2mPath;
24 24 import org.eclipse.leshan.core.node.LwM2mResource;
25 25 import org.springframework.stereotype.Service;
26   -import org.thingsboard.server.common.data.ota.OtaPackageKey;
27   -import org.thingsboard.server.common.data.ota.OtaPackageType;
28   -import org.thingsboard.server.common.data.ota.OtaPackageUtil;
29 26 import org.thingsboard.server.common.transport.TransportService;
30 27 import org.thingsboard.server.common.transport.TransportServiceCallback;
31 28 import org.thingsboard.server.gen.transport.TransportProtos;
... ...
... ... @@ -15,6 +15,7 @@
15 15 */
16 16 package org.thingsboard.server.transport.lwm2m.server.client;
17 17
  18 +import lombok.EqualsAndHashCode;
18 19 import lombok.Getter;
19 20 import lombok.Setter;
20 21 import lombok.extern.slf4j.Slf4j;
... ... @@ -60,6 +61,7 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.f
60 61 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getVerFromPathIdVerOrId;
61 62
62 63 @Slf4j
  64 +@EqualsAndHashCode(of = {"endpoint"})
63 65 public class LwM2mClient implements Serializable {
64 66
65 67 private static final long serialVersionUID = 8793482946289222623L;
... ...
... ... @@ -32,6 +32,7 @@ import org.thingsboard.server.common.transport.TransportDeviceProfileCache;
32 32 import org.thingsboard.server.common.transport.TransportServiceCallback;
33 33 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
34 34 import org.thingsboard.server.gen.transport.TransportProtos;
  35 +import org.thingsboard.server.queue.util.AfterStartUp;
35 36 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
36 37 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
37 38 import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo;
... ... @@ -81,6 +82,17 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
81 82 private final Map<String, LwM2mClient> lwM2mClientsByRegistrationId = new ConcurrentHashMap<>();
82 83 private final Map<UUID, Lwm2mDeviceProfileTransportConfiguration> profiles = new ConcurrentHashMap<>();
83 84
  85 + @AfterStartUp
  86 + public void init() {
  87 + String nodeId = context.getNodeId();
  88 + Set<LwM2mClient> fetchedClients = clientStore.getAll();
  89 + log.debug("Fetched clients from store: {}", fetchedClients);
  90 + fetchedClients.forEach(client -> {
  91 + lwM2mClientsByEndpoint.put(client.getEndpoint(), client);
  92 + updateFetchedClient(nodeId, client);
  93 + });
  94 + }
  95 +
84 96 @Override
85 97 public LwM2mClient getClientByEndpoint(String endpoint) {
86 98 return lwM2mClientsByEndpoint.computeIfAbsent(endpoint, ep -> {
... ... @@ -91,23 +103,27 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
91 103 client = new LwM2mClient(nodeId, ep);
92 104 } else {
93 105 log.debug("[{}] fetched client from store: {}", endpoint, client);
94   - boolean updated = false;
95   - if (client.getRegistration() != null) {
96   - lwM2mClientsByRegistrationId.put(client.getRegistration().getId(), client);
97   - }
98   - if (client.getSession() != null) {
99   - client.refreshSessionId(nodeId);
100   - sessionManager.register(client.getSession());
101   - updated = true;
102   - }
103   - if (updated) {
104   - clientStore.put(client);
105   - }
  106 + updateFetchedClient(nodeId, client);
106 107 }
107 108 return client;
108 109 });
109 110 }
110 111
  112 + private void updateFetchedClient(String nodeId, LwM2mClient client) {
  113 + boolean updated = false;
  114 + if (client.getRegistration() != null) {
  115 + lwM2mClientsByRegistrationId.put(client.getRegistration().getId(), client);
  116 + }
  117 + if (client.getSession() != null) {
  118 + client.refreshSessionId(nodeId);
  119 + sessionManager.register(client.getSession());
  120 + updated = true;
  121 + }
  122 + if (updated) {
  123 + clientStore.put(client);
  124 + }
  125 + }
  126 +
111 127 @Override
112 128 public Optional<TransportProtos.SessionInfoProto> register(LwM2mClient client, Registration registration) throws LwM2MClientStateException {
113 129 TransportProtos.SessionInfoProto oldSession = null;
... ... @@ -282,22 +298,23 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
282 298 @Override
283 299 public Lwm2mDeviceProfileTransportConfiguration getProfile(Registration registration) {
284 300 UUID profileId = getClientByEndpoint(registration.getEndpoint()).getProfileId();
285   - Lwm2mDeviceProfileTransportConfiguration result = doGetAndCache(profileId);
  301 + return doGetAndCache(profileId);
  302 + }
  303 +
  304 + private Lwm2mDeviceProfileTransportConfiguration doGetAndCache(UUID profileId) {
  305 + Lwm2mDeviceProfileTransportConfiguration result = profiles.get(profileId);
286 306 if (result == null) {
287   - log.debug("[{}] Fetching profile [{}]", registration.getEndpoint(), profileId);
  307 + log.debug("Fetching profile [{}]", profileId);
288 308 DeviceProfile deviceProfile = deviceProfileCache.get(new DeviceProfileId(profileId));
289 309 if (deviceProfile != null) {
290   - profileUpdate(deviceProfile);
291   - result = doGetAndCache(profileId);
  310 + result = profileUpdate(deviceProfile);
  311 + } else {
  312 + log.info("Device profile was not found! Most probably device profile [{}] has been removed from the database.", profileId);
292 313 }
293 314 }
294 315 return result;
295 316 }
296 317
297   - private Lwm2mDeviceProfileTransportConfiguration doGetAndCache(UUID profileId) {
298   - return profiles.get(profileId);
299   - }
300   -
301 318 @Override
302 319 public Lwm2mDeviceProfileTransportConfiguration profileUpdate(DeviceProfile deviceProfile) {
303 320 Lwm2mDeviceProfileTransportConfiguration clientProfile = LwM2mTransportUtil.toLwM2MClientProfile(deviceProfile);
... ...
... ... @@ -17,6 +17,9 @@ package org.thingsboard.server.transport.lwm2m.server.store;
17 17
18 18 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
19 19
  20 +import java.util.Collections;
  21 +import java.util.Set;
  22 +
20 23 public class TbDummyLwM2MClientStore implements TbLwM2MClientStore {
21 24 @Override
22 25 public LwM2mClient get(String endpoint) {
... ... @@ -24,6 +27,11 @@ public class TbDummyLwM2MClientStore implements TbLwM2MClientStore {
24 27 }
25 28
26 29 @Override
  30 + public Set<LwM2mClient> getAll() {
  31 + return Collections.emptySet();
  32 + }
  33 +
  34 + @Override
27 35 public void put(LwM2mClient client) {
28 36
29 37 }
... ...
... ... @@ -17,10 +17,14 @@ package org.thingsboard.server.transport.lwm2m.server.store;
17 17
18 18 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
19 19
  20 +import java.util.Set;
  21 +
20 22 public interface TbLwM2MClientStore {
21 23
22 24 LwM2mClient get(String endpoint);
23 25
  26 + Set<LwM2mClient> getAll();
  27 +
24 28 void put(LwM2mClient client);
25 29
26 30 void remove(String endpoint);
... ...
... ... @@ -23,12 +23,9 @@ import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInf
23 23 import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo;
24 24
25 25 import java.util.HashSet;
26   -import java.util.Map;
27 26 import java.util.Set;
28 27 import java.util.concurrent.ConcurrentHashMap;
29 28 import java.util.concurrent.ConcurrentMap;
30   -import java.util.concurrent.locks.Lock;
31   -import java.util.concurrent.locks.ReentrantLock;
32 29
33 30 import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.CLIENT;
34 31
... ...
... ... @@ -16,9 +16,17 @@
16 16 package org.thingsboard.server.transport.lwm2m.server.store;
17 17
18 18 import org.nustaq.serialization.FSTConfiguration;
  19 +import org.springframework.data.redis.connection.RedisClusterConnection;
19 20 import org.springframework.data.redis.connection.RedisConnectionFactory;
  21 +import org.springframework.data.redis.core.Cursor;
  22 +import org.springframework.data.redis.core.ScanOptions;
20 23 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
21 24
  25 +import java.util.ArrayList;
  26 +import java.util.HashSet;
  27 +import java.util.List;
  28 +import java.util.Set;
  29 +
22 30 public class TbRedisLwM2MClientStore implements TbLwM2MClientStore {
23 31
24 32 private static final String CLIENT_EP = "CLIENT#EP#";
... ... @@ -43,6 +51,30 @@ public class TbRedisLwM2MClientStore implements TbLwM2MClientStore {
43 51 }
44 52
45 53 @Override
  54 + public Set<LwM2mClient> getAll() {
  55 + try (var connection = connectionFactory.getConnection()) {
  56 + Set<LwM2mClient> clients = new HashSet<>();
  57 + ScanOptions scanOptions = ScanOptions.scanOptions().count(100).match(CLIENT_EP + "*").build();
  58 + List<Cursor<byte[]>> scans = new ArrayList<>();
  59 + if (connection instanceof RedisClusterConnection) {
  60 + ((RedisClusterConnection) connection).clusterGetNodes().forEach(node -> {
  61 + scans.add(((RedisClusterConnection) connection).scan(node, scanOptions));
  62 + });
  63 + } else {
  64 + scans.add(connection.scan(scanOptions));
  65 + }
  66 +
  67 + scans.forEach(scan -> {
  68 + scan.forEachRemaining(key -> {
  69 + byte[] element = connection.get(key);
  70 + clients.add((LwM2mClient) serializer.asObject(element));
  71 + });
  72 + });
  73 + return clients;
  74 + }
  75 + }
  76 +
  77 + @Override
46 78 public void put(LwM2mClient client) {
47 79 byte[] clientSerialized = serializer.asByteArray(client);
48 80 try (var connection = connectionFactory.getConnection()) {
... ...