Commit 6ea39e835e3203bfb4bcc6d6e6f7cf7e4552d16d
1 parent
356d4ff2
Transport Rate Limits are now configurable via Tenant Profile
Showing
30 changed files
with
785 additions
and
211 deletions
... | ... | @@ -92,6 +92,7 @@ public class TenantController extends BaseController { |
92 | 92 | installScripts.createDefaultRuleChains(tenant.getId()); |
93 | 93 | } |
94 | 94 | tenantProfileCache.evict(tenant.getId()); |
95 | + tbClusterService.onTenantChange(tenant, null); | |
95 | 96 | return tenant; |
96 | 97 | } catch (Exception e) { |
97 | 98 | throw handleException(e); |
... | ... | @@ -105,9 +106,10 @@ public class TenantController extends BaseController { |
105 | 106 | checkParameter("tenantId", strTenantId); |
106 | 107 | try { |
107 | 108 | TenantId tenantId = new TenantId(toUUID(strTenantId)); |
108 | - checkTenantId(tenantId, Operation.DELETE); | |
109 | + Tenant tenant = checkTenantId(tenantId, Operation.DELETE); | |
109 | 110 | tenantService.deleteTenant(tenantId); |
110 | 111 | tenantProfileCache.evict(tenantId); |
112 | + tbClusterService.onTenantDelete(tenant, null); | |
111 | 113 | tbClusterService.onEntityStateChange(tenantId, tenantId, ComponentLifecycleEvent.DELETED); |
112 | 114 | } catch (Exception e) { |
113 | 115 | throw handleException(e); | ... | ... |
... | ... | @@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.id.TenantProfileId; |
34 | 34 | import org.thingsboard.server.common.data.page.PageData; |
35 | 35 | import org.thingsboard.server.common.data.page.PageLink; |
36 | 36 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
37 | +import org.thingsboard.server.dao.exception.DataValidationException; | |
37 | 38 | import org.thingsboard.server.queue.util.TbCoreComponent; |
38 | 39 | import org.thingsboard.server.service.security.permission.Operation; |
39 | 40 | import org.thingsboard.server.service.security.permission.Resource; |
... | ... | @@ -96,6 +97,7 @@ public class TenantProfileController extends BaseController { |
96 | 97 | |
97 | 98 | tenantProfile = checkNotNull(tenantProfileService.saveTenantProfile(getTenantId(), tenantProfile)); |
98 | 99 | tenantProfileCache.put(tenantProfile); |
100 | + tbClusterService.onTenantProfileChange(tenantProfile, null); | |
99 | 101 | tbClusterService.onEntityStateChange(TenantId.SYS_TENANT_ID, tenantProfile.getId(), |
100 | 102 | newTenantProfile ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); |
101 | 103 | return tenantProfile; |
... | ... | @@ -111,8 +113,9 @@ public class TenantProfileController extends BaseController { |
111 | 113 | checkParameter("tenantProfileId", strTenantProfileId); |
112 | 114 | try { |
113 | 115 | TenantProfileId tenantProfileId = new TenantProfileId(toUUID(strTenantProfileId)); |
114 | - checkTenantProfileId(tenantProfileId, Operation.DELETE); | |
116 | + TenantProfile profile = checkTenantProfileId(tenantProfileId, Operation.DELETE); | |
115 | 117 | tenantProfileService.deleteTenantProfile(getTenantId(), tenantProfileId); |
118 | + tbClusterService.onTenantProfileDelete(profile, null); | |
116 | 119 | } catch (Exception e) { |
117 | 120 | throw handleException(e); |
118 | 121 | } | ... | ... |
... | ... | @@ -61,7 +61,7 @@ public class DefaultTbDeviceProfileCache implements TbDeviceProfileCache { |
61 | 61 | profile = deviceProfileService.findDeviceProfileById(tenantId, deviceProfileId); |
62 | 62 | if (profile != null) { |
63 | 63 | deviceProfilesMap.put(deviceProfileId, profile); |
64 | - log.info("[{}] Fetch device profile into cache: {}", profile.getId(), profile); | |
64 | + log.debug("[{}] Fetch device profile into cache: {}", profile.getId(), profile); | |
65 | 65 | } |
66 | 66 | } |
67 | 67 | } finally { |
... | ... | @@ -91,7 +91,7 @@ public class DefaultTbDeviceProfileCache implements TbDeviceProfileCache { |
91 | 91 | public void put(DeviceProfile profile) { |
92 | 92 | if (profile.getId() != null) { |
93 | 93 | deviceProfilesMap.put(profile.getId(), profile); |
94 | - log.info("[{}] pushed device profile to cache: {}", profile.getId(), profile); | |
94 | + log.debug("[{}] pushed device profile to cache: {}", profile.getId(), profile); | |
95 | 95 | notifyListeners(profile); |
96 | 96 | } |
97 | 97 | } |
... | ... | @@ -99,7 +99,7 @@ public class DefaultTbDeviceProfileCache implements TbDeviceProfileCache { |
99 | 99 | @Override |
100 | 100 | public void evict(TenantId tenantId, DeviceProfileId profileId) { |
101 | 101 | DeviceProfile oldProfile = deviceProfilesMap.remove(profileId); |
102 | - log.info("[{}] evict device profile from cache: {}", profileId, oldProfile); | |
102 | + log.debug("[{}] evict device profile from cache: {}", profileId, oldProfile); | |
103 | 103 | DeviceProfile newProfile = get(tenantId, profileId); |
104 | 104 | if (newProfile != null) { |
105 | 105 | notifyListeners(newProfile); |
... | ... | @@ -117,6 +117,16 @@ public class DefaultTbDeviceProfileCache implements TbDeviceProfileCache { |
117 | 117 | } |
118 | 118 | |
119 | 119 | @Override |
120 | + public DeviceProfile find(DeviceProfileId deviceProfileId) { | |
121 | + return deviceProfileService.findDeviceProfileById(TenantId.SYS_TENANT_ID, deviceProfileId); | |
122 | + } | |
123 | + | |
124 | + @Override | |
125 | + public DeviceProfile findOrCreateDeviceProfile(TenantId tenantId, String profileName) { | |
126 | + return deviceProfileService.findOrCreateDeviceProfile(tenantId, profileName); | |
127 | + } | |
128 | + | |
129 | + @Override | |
120 | 130 | public void removeListener(TenantId tenantId, EntityId listenerId) { |
121 | 131 | ConcurrentMap<EntityId, Consumer<DeviceProfile>> tenantListeners = listeners.get(tenantId); |
122 | 132 | if (tenantListeners != null) { | ... | ... |
... | ... | @@ -29,4 +29,7 @@ public interface TbDeviceProfileCache extends RuleEngineDeviceProfileCache { |
29 | 29 | |
30 | 30 | void evict(DeviceId id); |
31 | 31 | |
32 | + DeviceProfile find(DeviceProfileId deviceProfileId); | |
33 | + | |
34 | + DeviceProfile findOrCreateDeviceProfile(TenantId tenantId, String deviceType); | |
32 | 35 | } | ... | ... |
... | ... | @@ -23,11 +23,15 @@ import org.springframework.stereotype.Service; |
23 | 23 | import org.thingsboard.rule.engine.api.msg.ToDeviceActorNotificationMsg; |
24 | 24 | import org.thingsboard.server.common.data.DeviceProfile; |
25 | 25 | import org.thingsboard.server.common.data.EntityType; |
26 | +import org.thingsboard.server.common.data.HasName; | |
27 | +import org.thingsboard.server.common.data.Tenant; | |
28 | +import org.thingsboard.server.common.data.TenantProfile; | |
26 | 29 | import org.thingsboard.server.common.data.id.DeviceId; |
27 | 30 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
28 | 31 | import org.thingsboard.server.common.data.id.EntityId; |
29 | 32 | import org.thingsboard.server.common.data.id.RuleChainId; |
30 | 33 | import org.thingsboard.server.common.data.id.TenantId; |
34 | +import org.thingsboard.server.common.data.id.TenantProfileId; | |
31 | 35 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
32 | 36 | import org.thingsboard.server.common.msg.TbMsg; |
33 | 37 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
... | ... | @@ -189,21 +193,51 @@ public class DefaultTbClusterService implements TbClusterService { |
189 | 193 | |
190 | 194 | @Override |
191 | 195 | public void onDeviceProfileChange(DeviceProfile deviceProfile, TbQueueCallback callback) { |
192 | - log.trace("[{}][{}] Processing device profile [{}] change event", deviceProfile.getTenantId(), deviceProfile.getId(), deviceProfile.getName()); | |
193 | - TransportProtos.DeviceProfileUpdateMsg profileUpdateMsg = TransportProtos.DeviceProfileUpdateMsg.newBuilder() | |
194 | - .setData(ByteString.copyFrom(encodingService.encode(deviceProfile))).build(); | |
195 | - ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setDeviceProfileUpdateMsg(profileUpdateMsg).build(); | |
196 | - broadcast(transportMsg); | |
196 | + onEntityChange(deviceProfile.getTenantId(), deviceProfile.getId(), deviceProfile, callback); | |
197 | + } | |
198 | + | |
199 | + @Override | |
200 | + public void onTenantProfileChange(TenantProfile tenantProfile, TbQueueCallback callback) { | |
201 | + onEntityChange(TenantId.SYS_TENANT_ID, tenantProfile.getId(), tenantProfile, callback); | |
202 | + } | |
203 | + | |
204 | + @Override | |
205 | + public void onTenantChange(Tenant tenant, TbQueueCallback callback) { | |
206 | + onEntityChange(TenantId.SYS_TENANT_ID, tenant.getId(), tenant, callback); | |
207 | + } | |
208 | + | |
209 | + @Override | |
210 | + public void onDeviceProfileDelete(DeviceProfile entity, TbQueueCallback callback) { | |
211 | + onEntityDelete(entity.getTenantId(), entity.getId(), entity.getName(), callback); | |
197 | 212 | } |
198 | 213 | |
199 | 214 | @Override |
200 | - public void onDeviceProfileDelete(DeviceProfile deviceProfile, TbQueueCallback callback) { | |
201 | - log.trace("[{}][{}] Processing device profile [{}] delete event", deviceProfile.getTenantId(), deviceProfile.getId(), deviceProfile.getName()); | |
202 | - TransportProtos.DeviceProfileDeleteMsg profileDeleteMsg = TransportProtos.DeviceProfileDeleteMsg.newBuilder() | |
203 | - .setProfileIdMSB(deviceProfile.getId().getId().getMostSignificantBits()) | |
204 | - .setProfileIdLSB(deviceProfile.getId().getId().getLeastSignificantBits()) | |
215 | + public void onTenantProfileDelete(TenantProfile entity, TbQueueCallback callback) { | |
216 | + onEntityDelete(TenantId.SYS_TENANT_ID, entity.getId(), entity.getName(), callback); | |
217 | + } | |
218 | + | |
219 | + @Override | |
220 | + public void onTenantDelete(Tenant entity, TbQueueCallback callback) { | |
221 | + onEntityDelete(TenantId.SYS_TENANT_ID, entity.getId(), entity.getName(), callback); | |
222 | + } | |
223 | + | |
224 | + public <T extends HasName> void onEntityChange(TenantId tenantId, EntityId entityid, T entity, TbQueueCallback callback) { | |
225 | + log.trace("[{}][{}][{}] Processing [{}] change event", tenantId, entityid.getEntityType(), entityid.getId(), entity.getName()); | |
226 | + TransportProtos.EntityUpdateMsg entityUpdateMsg = TransportProtos.EntityUpdateMsg.newBuilder() | |
227 | + .setEntityType(entityid.getEntityType().name()) | |
228 | + .setData(ByteString.copyFrom(encodingService.encode(entity))).build(); | |
229 | + ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setEntityUpdateMsg(entityUpdateMsg).build(); | |
230 | + broadcast(transportMsg); | |
231 | + } | |
232 | + | |
233 | + private void onEntityDelete(TenantId tenantId, EntityId entityId, String name, TbQueueCallback callback) { | |
234 | + log.trace("[{}][{}][{}] Processing [{}] delete event", tenantId, entityId.getEntityType(), entityId.getId(), name); | |
235 | + TransportProtos.EntityDeleteMsg entityDeleteMsg = TransportProtos.EntityDeleteMsg.newBuilder() | |
236 | + .setEntityType(entityId.getEntityType().name()) | |
237 | + .setEntityIdMSB(entityId.getId().getMostSignificantBits()) | |
238 | + .setEntityIdLSB(entityId.getId().getLeastSignificantBits()) | |
205 | 239 | .build(); |
206 | - ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setDeviceProfileDeleteMsg(profileDeleteMsg).build(); | |
240 | + ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setEntityDeleteMsg(entityDeleteMsg).build(); | |
207 | 241 | broadcast(transportMsg); |
208 | 242 | } |
209 | 243 | ... | ... |
... | ... | @@ -17,7 +17,8 @@ package org.thingsboard.server.service.queue; |
17 | 17 | |
18 | 18 | import org.thingsboard.rule.engine.api.msg.ToDeviceActorNotificationMsg; |
19 | 19 | import org.thingsboard.server.common.data.DeviceProfile; |
20 | -import org.thingsboard.server.common.data.id.DeviceProfileId; | |
20 | +import org.thingsboard.server.common.data.Tenant; | |
21 | +import org.thingsboard.server.common.data.TenantProfile; | |
21 | 22 | import org.thingsboard.server.common.data.id.EntityId; |
22 | 23 | import org.thingsboard.server.common.data.id.TenantId; |
23 | 24 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
... | ... | @@ -53,5 +54,13 @@ public interface TbClusterService { |
53 | 54 | |
54 | 55 | void onDeviceProfileChange(DeviceProfile deviceProfile, TbQueueCallback callback); |
55 | 56 | |
56 | - void onDeviceProfileDelete(DeviceProfile deviceProfileId, TbQueueCallback callback); | |
57 | + void onDeviceProfileDelete(DeviceProfile deviceProfile, TbQueueCallback callback); | |
58 | + | |
59 | + void onTenantProfileChange(TenantProfile tenantProfile, TbQueueCallback callback); | |
60 | + | |
61 | + void onTenantProfileDelete(TenantProfile tenantProfile, TbQueueCallback callback); | |
62 | + | |
63 | + void onTenantChange(Tenant tenant, TbQueueCallback callback); | |
64 | + | |
65 | + void onTenantDelete(Tenant tenant, TbQueueCallback callback); | |
57 | 66 | } | ... | ... |
... | ... | @@ -28,6 +28,7 @@ import org.springframework.util.StringUtils; |
28 | 28 | import org.thingsboard.server.common.data.DataConstants; |
29 | 29 | import org.thingsboard.server.common.data.Device; |
30 | 30 | import org.thingsboard.server.common.data.DeviceProfile; |
31 | +import org.thingsboard.server.common.data.EntityType; | |
31 | 32 | import org.thingsboard.server.common.data.TenantProfile; |
32 | 33 | import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; |
33 | 34 | import org.thingsboard.server.common.data.device.credentials.ProvisionDeviceCredentialsData; |
... | ... | @@ -45,21 +46,19 @@ import org.thingsboard.server.common.msg.TbMsgDataType; |
45 | 46 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
46 | 47 | import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; |
47 | 48 | import org.thingsboard.server.dao.device.DeviceCredentialsService; |
48 | -import org.thingsboard.server.dao.device.DeviceProfileService; | |
49 | 49 | import org.thingsboard.server.dao.device.DeviceProvisionService; |
50 | 50 | import org.thingsboard.server.dao.device.DeviceService; |
51 | 51 | import org.thingsboard.server.dao.device.provision.ProvisionRequest; |
52 | 52 | import org.thingsboard.server.dao.device.provision.ProvisionResponse; |
53 | 53 | import org.thingsboard.server.dao.relation.RelationService; |
54 | -import org.thingsboard.server.dao.tenant.TenantProfileService; | |
55 | 54 | import org.thingsboard.server.dao.tenant.TenantService; |
56 | 55 | import org.thingsboard.server.dao.util.mapping.JacksonUtil; |
57 | 56 | import org.thingsboard.server.gen.transport.TransportProtos; |
58 | 57 | import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto; |
59 | 58 | import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg; |
60 | 59 | import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayResponseMsg; |
61 | -import org.thingsboard.server.gen.transport.TransportProtos.GetTenantRoutingInfoRequestMsg; | |
62 | -import org.thingsboard.server.gen.transport.TransportProtos.GetTenantRoutingInfoResponseMsg; | |
60 | +import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg; | |
61 | +import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileResponseMsg; | |
63 | 62 | import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg; |
64 | 63 | import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; |
65 | 64 | import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; |
... | ... | @@ -70,6 +69,7 @@ import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
70 | 69 | import org.thingsboard.server.queue.util.TbCoreComponent; |
71 | 70 | import org.thingsboard.server.dao.device.provision.ProvisionFailedException; |
72 | 71 | import org.thingsboard.server.service.executors.DbCallbackExecutorService; |
72 | +import org.thingsboard.server.service.profile.TbDeviceProfileCache; | |
73 | 73 | import org.thingsboard.server.service.profile.TbTenantProfileCache; |
74 | 74 | import org.thingsboard.server.service.queue.TbClusterService; |
75 | 75 | import org.thingsboard.server.service.state.DeviceStateService; |
... | ... | @@ -90,9 +90,7 @@ public class DefaultTransportApiService implements TransportApiService { |
90 | 90 | |
91 | 91 | private static final ObjectMapper mapper = new ObjectMapper(); |
92 | 92 | |
93 | - //TODO: Constructor dependencies; | |
94 | - private final DeviceProfileService deviceProfileService; | |
95 | - private final TenantService tenantService; | |
93 | + private final TbDeviceProfileCache deviceProfileCache; | |
96 | 94 | private final TbTenantProfileCache tenantProfileCache; |
97 | 95 | private final DeviceService deviceService; |
98 | 96 | private final RelationService relationService; |
... | ... | @@ -103,17 +101,15 @@ public class DefaultTransportApiService implements TransportApiService { |
103 | 101 | private final DataDecodingEncodingService dataDecodingEncodingService; |
104 | 102 | private final DeviceProvisionService deviceProvisionService; |
105 | 103 | |
106 | - | |
107 | 104 | private final ConcurrentMap<String, ReentrantLock> deviceCreationLocks = new ConcurrentHashMap<>(); |
108 | 105 | |
109 | - public DefaultTransportApiService(DeviceProfileService deviceProfileService, TenantService tenantService, | |
106 | + public DefaultTransportApiService(TbDeviceProfileCache deviceProfileCache, | |
110 | 107 | TbTenantProfileCache tenantProfileCache, DeviceService deviceService, |
111 | 108 | RelationService relationService, DeviceCredentialsService deviceCredentialsService, |
112 | 109 | DeviceStateService deviceStateService, DbCallbackExecutorService dbCallbackExecutorService, |
113 | 110 | TbClusterService tbClusterService, DataDecodingEncodingService dataDecodingEncodingService, |
114 | 111 | DeviceProvisionService deviceProvisionService) { |
115 | - this.deviceProfileService = deviceProfileService; | |
116 | - this.tenantService = tenantService; | |
112 | + this.deviceProfileCache = deviceProfileCache; | |
117 | 113 | this.tenantProfileCache = tenantProfileCache; |
118 | 114 | this.deviceService = deviceService; |
119 | 115 | this.relationService = relationService; |
... | ... | @@ -143,11 +139,8 @@ public class DefaultTransportApiService implements TransportApiService { |
143 | 139 | } else if (transportApiRequestMsg.hasGetOrCreateDeviceRequestMsg()) { |
144 | 140 | return Futures.transform(handle(transportApiRequestMsg.getGetOrCreateDeviceRequestMsg()), |
145 | 141 | value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); |
146 | - } else if (transportApiRequestMsg.hasGetTenantRoutingInfoRequestMsg()) { | |
147 | - return Futures.transform(handle(transportApiRequestMsg.getGetTenantRoutingInfoRequestMsg()), | |
148 | - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | |
149 | - } else if (transportApiRequestMsg.hasGetDeviceProfileRequestMsg()) { | |
150 | - return Futures.transform(handle(transportApiRequestMsg.getGetDeviceProfileRequestMsg()), | |
142 | + } else if (transportApiRequestMsg.hasEntityProfileRequestMsg()) { | |
143 | + return Futures.transform(handle(transportApiRequestMsg.getEntityProfileRequestMsg()), | |
151 | 144 | value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); |
152 | 145 | } else if (transportApiRequestMsg.hasProvisionDeviceRequestMsg()) { |
153 | 146 | return Futures.transform(handle(transportApiRequestMsg.getProvisionDeviceRequestMsg()), |
... | ... | @@ -238,7 +231,7 @@ public class DefaultTransportApiService implements TransportApiService { |
238 | 231 | device.setName(requestMsg.getDeviceName()); |
239 | 232 | device.setType(requestMsg.getDeviceType()); |
240 | 233 | device.setCustomerId(gateway.getCustomerId()); |
241 | - DeviceProfile deviceProfile = deviceProfileService.findOrCreateDeviceProfile(gateway.getTenantId(), requestMsg.getDeviceType()); | |
234 | + DeviceProfile deviceProfile = deviceProfileCache.findOrCreateDeviceProfile(gateway.getTenantId(), requestMsg.getDeviceType()); | |
242 | 235 | device.setDeviceProfileId(deviceProfile.getId()); |
243 | 236 | device = deviceService.saveDevice(device); |
244 | 237 | relationService.saveRelationAsync(TenantId.SYS_TENANT_ID, new EntityRelation(gateway.getId(), device.getId(), "Created")); |
... | ... | @@ -258,7 +251,7 @@ public class DefaultTransportApiService implements TransportApiService { |
258 | 251 | } |
259 | 252 | GetOrCreateDeviceFromGatewayResponseMsg.Builder builder = GetOrCreateDeviceFromGatewayResponseMsg.newBuilder() |
260 | 253 | .setDeviceInfo(getDeviceInfoProto(device)); |
261 | - DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId()); | |
254 | + DeviceProfile deviceProfile = deviceProfileCache.get(device.getTenantId(), device.getDeviceProfileId()); | |
262 | 255 | if (deviceProfile != null) { |
263 | 256 | builder.setProfileBody(ByteString.copyFrom(dataDecodingEncodingService.encode(deviceProfile))); |
264 | 257 | } else { |
... | ... | @@ -320,23 +313,21 @@ public class DefaultTransportApiService implements TransportApiService { |
320 | 313 | .build(); |
321 | 314 | } |
322 | 315 | |
323 | - private ListenableFuture<TransportApiResponseMsg> handle(GetTenantRoutingInfoRequestMsg requestMsg) { | |
324 | - TenantId tenantId = new TenantId(new UUID(requestMsg.getTenantIdMSB(), requestMsg.getTenantIdLSB())); | |
325 | - | |
326 | - ListenableFuture<TenantProfile> tenantProfileFuture = Futures.immediateFuture(tenantProfileCache.get(tenantId)); | |
327 | - return Futures.transform(tenantProfileFuture, tenantProfile -> TransportApiResponseMsg.newBuilder() | |
328 | - .setGetTenantRoutingInfoResponseMsg(GetTenantRoutingInfoResponseMsg.newBuilder().setIsolatedTbCore(tenantProfile.isIsolatedTbCore()) | |
329 | - .setIsolatedTbRuleEngine(tenantProfile.isIsolatedTbRuleEngine()).build()).build(), dbCallbackExecutorService); | |
330 | - } | |
331 | - | |
332 | - private ListenableFuture<TransportApiResponseMsg> handle(TransportProtos.GetDeviceProfileRequestMsg requestMsg) { | |
333 | - DeviceProfileId profileId = new DeviceProfileId(new UUID(requestMsg.getProfileIdMSB(), requestMsg.getProfileIdLSB())); | |
334 | - DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(TenantId.SYS_TENANT_ID, profileId); | |
335 | - return Futures.immediateFuture(TransportApiResponseMsg.newBuilder() | |
336 | - .setGetDeviceProfileResponseMsg( | |
337 | - TransportProtos.GetDeviceProfileResponseMsg.newBuilder() | |
338 | - .setData(ByteString.copyFrom(dataDecodingEncodingService.encode(deviceProfile))) | |
339 | - .build()).build()); | |
316 | + private ListenableFuture<TransportApiResponseMsg> handle(GetEntityProfileRequestMsg requestMsg) { | |
317 | + EntityType entityType = EntityType.valueOf(requestMsg.getEntityType()); | |
318 | + UUID entityUuid = new UUID(requestMsg.getEntityIdMSB(), requestMsg.getEntityIdLSB()); | |
319 | + ByteString data; | |
320 | + if (entityType.equals(EntityType.DEVICE_PROFILE)) { | |
321 | + DeviceProfileId deviceProfileId = new DeviceProfileId(entityUuid); | |
322 | + DeviceProfile deviceProfile = deviceProfileCache.find(deviceProfileId); | |
323 | + data = ByteString.copyFrom(dataDecodingEncodingService.encode(deviceProfile)); | |
324 | + } else if (entityType.equals(EntityType.TENANT)) { | |
325 | + TenantProfile tenantProfile = tenantProfileCache.get(new TenantId(entityUuid)); | |
326 | + data = ByteString.copyFrom(dataDecodingEncodingService.encode(tenantProfile)); | |
327 | + } else { | |
328 | + throw new RuntimeException("Invalid entity profile request: " + entityType); | |
329 | + } | |
330 | + return Futures.immediateFuture(TransportApiResponseMsg.newBuilder().setEntityProfileResponseMsg(GetEntityProfileResponseMsg.newBuilder().setData(data).build()).build()); | |
340 | 331 | } |
341 | 332 | |
342 | 333 | private ListenableFuture<TransportApiResponseMsg> getDeviceInfo(DeviceId deviceId, DeviceCredentials credentials) { |
... | ... | @@ -348,7 +339,7 @@ public class DefaultTransportApiService implements TransportApiService { |
348 | 339 | try { |
349 | 340 | ValidateDeviceCredentialsResponseMsg.Builder builder = ValidateDeviceCredentialsResponseMsg.newBuilder(); |
350 | 341 | builder.setDeviceInfo(getDeviceInfoProto(device)); |
351 | - DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId()); | |
342 | + DeviceProfile deviceProfile = deviceProfileCache.get(device.getTenantId(), device.getDeviceProfileId()); | |
352 | 343 | if (deviceProfile != null) { |
353 | 344 | builder.setProfileBody(ByteString.copyFrom(dataDecodingEncodingService.encode(deviceProfile))); |
354 | 345 | } else { | ... | ... |
... | ... | @@ -502,7 +502,7 @@ js: |
502 | 502 | remote: |
503 | 503 | # Maximum allowed JavaScript execution errors before JavaScript will be blacklisted |
504 | 504 | max_errors: "${REMOTE_JS_SANDBOX_MAX_ERRORS:3}" |
505 | - # Maximum time in seconds for black listed function to stay in the list. | |
505 | + # Maximum time in seconds for black listed function to stay in 1:the list. | |
506 | 506 | max_black_list_duration_sec: "${REMOTE_JS_SANDBOX_MAX_BLACKLIST_DURATION_SEC:60}" |
507 | 507 | stats: |
508 | 508 | enabled: "${TB_JS_REMOTE_STATS_ENABLED:false}" |
... | ... | @@ -512,10 +512,6 @@ transport: |
512 | 512 | sessions: |
513 | 513 | inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}" |
514 | 514 | report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:30000}" |
515 | - rate_limits: | |
516 | - enabled: "${TB_TRANSPORT_RATE_LIMITS_ENABLED:false}" | |
517 | - tenant: "${TB_TRANSPORT_RATE_LIMITS_TENANT:1000:1,20000:60}" | |
518 | - device: "${TB_TRANSPORT_RATE_LIMITS_DEVICE:10:1,300:60}" | |
519 | 515 | json: |
520 | 516 | # Cast String data types to Numeric if possible when processing Telemetry/Attributes JSON |
521 | 517 | type_cast_enabled: "${JSON_TYPE_CAST_ENABLED:true}" | ... | ... |
... | ... | @@ -177,32 +177,26 @@ message GetOrCreateDeviceFromGatewayResponseMsg { |
177 | 177 | bytes profileBody = 2; |
178 | 178 | } |
179 | 179 | |
180 | -message GetTenantRoutingInfoRequestMsg { | |
181 | - int64 tenantIdMSB = 1; | |
182 | - int64 tenantIdLSB = 2; | |
183 | -} | |
184 | - | |
185 | -message GetTenantRoutingInfoResponseMsg { | |
186 | - bool isolatedTbCore = 1; | |
187 | - bool isolatedTbRuleEngine = 2; | |
188 | -} | |
189 | - | |
190 | -message GetDeviceProfileRequestMsg { | |
191 | - int64 profileIdMSB = 1; | |
192 | - int64 profileIdLSB = 2; | |
180 | +message GetEntityProfileRequestMsg { | |
181 | + string entityType = 1; | |
182 | + int64 entityIdMSB = 2; | |
183 | + int64 entityIdLSB = 3; | |
193 | 184 | } |
194 | 185 | |
195 | -message GetDeviceProfileResponseMsg { | |
196 | - bytes data = 1; | |
186 | +message GetEntityProfileResponseMsg { | |
187 | + string entityType = 1; | |
188 | + bytes data = 2; | |
197 | 189 | } |
198 | 190 | |
199 | -message DeviceProfileUpdateMsg { | |
200 | - bytes data = 1; | |
191 | +message EntityUpdateMsg { | |
192 | + string entityType = 1; | |
193 | + bytes data = 2; | |
201 | 194 | } |
202 | 195 | |
203 | -message DeviceProfileDeleteMsg { | |
204 | - int64 profileIdMSB = 1; | |
205 | - int64 profileIdLSB = 2; | |
196 | +message EntityDeleteMsg { | |
197 | + string entityType = 1; | |
198 | + int64 entityIdMSB = 2; | |
199 | + int64 entityIdLSB = 3; | |
206 | 200 | } |
207 | 201 | |
208 | 202 | message SessionCloseNotificationProto { |
... | ... | @@ -482,8 +476,7 @@ message TransportApiRequestMsg { |
482 | 476 | ValidateDeviceTokenRequestMsg validateTokenRequestMsg = 1; |
483 | 477 | ValidateDeviceX509CertRequestMsg validateX509CertRequestMsg = 2; |
484 | 478 | GetOrCreateDeviceFromGatewayRequestMsg getOrCreateDeviceRequestMsg = 3; |
485 | - GetTenantRoutingInfoRequestMsg getTenantRoutingInfoRequestMsg = 4; | |
486 | - GetDeviceProfileRequestMsg getDeviceProfileRequestMsg = 5; | |
479 | + GetEntityProfileRequestMsg entityProfileRequestMsg = 4; | |
487 | 480 | ValidateBasicMqttCredRequestMsg validateBasicMqttCredRequestMsg = 6; |
488 | 481 | ProvisionDeviceRequestMsg provisionDeviceRequestMsg = 7; |
489 | 482 | } |
... | ... | @@ -492,9 +485,8 @@ message TransportApiRequestMsg { |
492 | 485 | message TransportApiResponseMsg { |
493 | 486 | ValidateDeviceCredentialsResponseMsg validateCredResponseMsg = 1; |
494 | 487 | GetOrCreateDeviceFromGatewayResponseMsg getOrCreateDeviceResponseMsg = 2; |
495 | - GetTenantRoutingInfoResponseMsg getTenantRoutingInfoResponseMsg = 4; | |
496 | - GetDeviceProfileResponseMsg getDeviceProfileResponseMsg = 5; | |
497 | - ProvisionDeviceResponseMsg provisionDeviceResponseMsg = 6; | |
488 | + GetEntityProfileResponseMsg entityProfileResponseMsg = 3; | |
489 | + ProvisionDeviceResponseMsg provisionDeviceResponseMsg = 4; | |
498 | 490 | } |
499 | 491 | |
500 | 492 | /* Messages that are handled by ThingsBoard Core Service */ |
... | ... | @@ -535,7 +527,8 @@ message ToTransportMsg { |
535 | 527 | AttributeUpdateNotificationMsg attributeUpdateNotification = 5; |
536 | 528 | ToDeviceRpcRequestMsg toDeviceRequest = 6; |
537 | 529 | ToServerRpcResponseMsg toServerResponse = 7; |
538 | - DeviceProfileUpdateMsg deviceProfileUpdateMsg = 8; | |
539 | - DeviceProfileDeleteMsg deviceProfileDeleteMsg = 9; | |
530 | + /* For Tenant, TenantProfile and DeviceProfile */ | |
531 | + EntityUpdateMsg entityUpdateMsg = 8; | |
532 | + EntityDeleteMsg entityDeleteMsg = 9; | |
540 | 533 | ProvisionDeviceResponseMsg provisionResponse = 10; |
541 | 534 | } | ... | ... |
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportDeviceProfileCache.java
renamed from
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportProfileCache.java
... | ... | @@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.id.DeviceProfileId; |
21 | 21 | |
22 | 22 | import java.util.Optional; |
23 | 23 | |
24 | -public interface TransportProfileCache { | |
24 | +public interface TransportDeviceProfileCache { | |
25 | 25 | |
26 | 26 | DeviceProfile getOrCreate(DeviceProfileId id, ByteString profileBody); |
27 | 27 | ... | ... |
... | ... | @@ -20,11 +20,12 @@ import org.thingsboard.server.common.data.DeviceTransportType; |
20 | 20 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
21 | 21 | import org.thingsboard.server.common.transport.auth.GetOrCreateDeviceFromGatewayResponse; |
22 | 22 | import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; |
23 | +import org.thingsboard.server.gen.transport.TransportProtos; | |
23 | 24 | import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; |
24 | 25 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; |
25 | 26 | import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg; |
26 | -import org.thingsboard.server.gen.transport.TransportProtos.GetTenantRoutingInfoRequestMsg; | |
27 | -import org.thingsboard.server.gen.transport.TransportProtos.GetTenantRoutingInfoResponseMsg; | |
27 | +import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg; | |
28 | +import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileResponseMsg; | |
28 | 29 | import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg; |
29 | 30 | import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg; |
30 | 31 | import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg; |
... | ... | @@ -47,7 +48,7 @@ import java.util.concurrent.ScheduledExecutorService; |
47 | 48 | */ |
48 | 49 | public interface TransportService { |
49 | 50 | |
50 | - GetTenantRoutingInfoResponseMsg getRoutingInfo(GetTenantRoutingInfoRequestMsg msg); | |
51 | + GetEntityProfileResponseMsg getRoutingInfo(GetEntityProfileRequestMsg msg); | |
51 | 52 | |
52 | 53 | void process(DeviceTransportType transportType, ValidateDeviceTokenRequestMsg msg, |
53 | 54 | TransportServiceCallback<ValidateDeviceCredentialsResponse> callback); |
... | ... | @@ -64,8 +65,6 @@ public interface TransportService { |
64 | 65 | void process(ProvisionDeviceRequestMsg msg, |
65 | 66 | TransportServiceCallback<ProvisionDeviceResponseMsg> callback); |
66 | 67 | |
67 | - void getDeviceProfile(DeviceProfileId deviceProfileId, TransportServiceCallback<DeviceProfile> callback); | |
68 | - | |
69 | 68 | void onProfileUpdate(DeviceProfile deviceProfile); |
70 | 69 | |
71 | 70 | boolean checkLimits(SessionInfoProto sessionInfo, Object msg, TransportServiceCallback<Void> callback); | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2020 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.transport; | |
17 | + | |
18 | +import com.google.protobuf.ByteString; | |
19 | +import org.thingsboard.server.common.data.TenantProfile; | |
20 | +import org.thingsboard.server.common.data.id.TenantId; | |
21 | +import org.thingsboard.server.common.data.id.TenantProfileId; | |
22 | +import org.thingsboard.server.common.transport.profile.TenantProfileUpdateResult; | |
23 | +import org.thingsboard.server.queue.discovery.TenantRoutingInfo; | |
24 | +import org.thingsboard.server.queue.discovery.TenantRoutingInfoService; | |
25 | + | |
26 | +import java.util.Set; | |
27 | + | |
28 | +public interface TransportTenantProfileCache { | |
29 | + | |
30 | + TenantProfile get(TenantId tenantId); | |
31 | + | |
32 | + TenantProfileUpdateResult put(ByteString profileBody); | |
33 | + | |
34 | + boolean put(TenantId tenantId, TenantProfileId profileId); | |
35 | + | |
36 | + Set<TenantId> remove(TenantProfileId profileId); | |
37 | + | |
38 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2020 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.transport.limits; | |
17 | + | |
18 | +import lombok.extern.slf4j.Slf4j; | |
19 | +import org.springframework.stereotype.Component; | |
20 | +import org.springframework.util.StringUtils; | |
21 | +import org.thingsboard.server.common.msg.tools.TbRateLimits; | |
22 | + | |
23 | +@Slf4j | |
24 | +@Component | |
25 | +public class DefaultTransportRateLimitFactory implements TransportRateLimitFactory { | |
26 | + | |
27 | + private static final DummyTransportRateLimit ALWAYS_TRUE = new DummyTransportRateLimit(); | |
28 | + | |
29 | + @Override | |
30 | + public TransportRateLimit create(TransportRateLimitType type, Object configuration) { | |
31 | + if (!StringUtils.isEmpty(configuration)) { | |
32 | + try { | |
33 | + return new SimpleTransportRateLimit(new TbRateLimits(configuration.toString()), configuration.toString()); | |
34 | + } catch (Exception e) { | |
35 | + log.warn("[{}] Failed to init rate limit with configuration: {}", type, configuration, e); | |
36 | + return ALWAYS_TRUE; | |
37 | + } | |
38 | + } else { | |
39 | + return ALWAYS_TRUE; | |
40 | + } | |
41 | + } | |
42 | + | |
43 | + @Override | |
44 | + public TransportRateLimit createDefault(TransportRateLimitType type) { | |
45 | + return ALWAYS_TRUE; | |
46 | + } | |
47 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2020 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.transport.limits; | |
17 | + | |
18 | +import lombok.extern.slf4j.Slf4j; | |
19 | +import org.springframework.stereotype.Service; | |
20 | +import org.thingsboard.server.common.data.TenantProfile; | |
21 | +import org.thingsboard.server.common.data.TenantProfileData; | |
22 | +import org.thingsboard.server.common.data.id.DeviceId; | |
23 | +import org.thingsboard.server.common.data.id.TenantId; | |
24 | +import org.thingsboard.server.common.transport.TransportTenantProfileCache; | |
25 | +import org.thingsboard.server.common.transport.profile.TenantProfileUpdateResult; | |
26 | + | |
27 | +import java.util.concurrent.ConcurrentHashMap; | |
28 | +import java.util.concurrent.ConcurrentMap; | |
29 | + | |
30 | +@Service | |
31 | +@Slf4j | |
32 | +public class DefaultTransportRateLimitService implements TransportRateLimitService { | |
33 | + | |
34 | + private final ConcurrentMap<TenantId, TransportRateLimit[]> perTenantLimits = new ConcurrentHashMap<>(); | |
35 | + private final ConcurrentMap<DeviceId, TransportRateLimit[]> perDeviceLimits = new ConcurrentHashMap<>(); | |
36 | + | |
37 | + private final TransportRateLimitFactory rateLimitFactory; | |
38 | + private final TransportTenantProfileCache tenantProfileCache; | |
39 | + | |
40 | + public DefaultTransportRateLimitService(TransportRateLimitFactory rateLimitFactory, TransportTenantProfileCache tenantProfileCache) { | |
41 | + this.rateLimitFactory = rateLimitFactory; | |
42 | + this.tenantProfileCache = tenantProfileCache; | |
43 | + } | |
44 | + | |
45 | + @Override | |
46 | + public TransportRateLimit getRateLimit(TenantId tenantId, TransportRateLimitType limitType) { | |
47 | + TransportRateLimit[] limits = perTenantLimits.get(tenantId); | |
48 | + if (limits == null) { | |
49 | + limits = fetchProfileAndInit(tenantId); | |
50 | + perTenantLimits.put(tenantId, limits); | |
51 | + } | |
52 | + return limits[limitType.ordinal()]; | |
53 | + } | |
54 | + | |
55 | + @Override | |
56 | + public TransportRateLimit getRateLimit(TenantId tenantId, DeviceId deviceId, TransportRateLimitType limitType) { | |
57 | + TransportRateLimit[] limits = perDeviceLimits.get(deviceId); | |
58 | + if (limits == null) { | |
59 | + limits = fetchProfileAndInit(tenantId); | |
60 | + perDeviceLimits.put(deviceId, limits); | |
61 | + } | |
62 | + return limits[limitType.ordinal()]; | |
63 | + } | |
64 | + | |
65 | + @Override | |
66 | + public void update(TenantProfileUpdateResult update) { | |
67 | + TransportRateLimit[] newLimits = createTransportRateLimits(update.getProfile()); | |
68 | + for (TenantId tenantId : update.getAffectedTenants()) { | |
69 | + mergeLimits(tenantId, newLimits); | |
70 | + } | |
71 | + } | |
72 | + | |
73 | + @Override | |
74 | + public void update(TenantId tenantId) { | |
75 | + mergeLimits(tenantId, fetchProfileAndInit(tenantId)); | |
76 | + } | |
77 | + | |
78 | + public void mergeLimits(TenantId tenantId, TransportRateLimit[] newRateLimits) { | |
79 | + TransportRateLimit[] oldRateLimits = perTenantLimits.get(tenantId); | |
80 | + if (oldRateLimits == null) { | |
81 | + perTenantLimits.put(tenantId, newRateLimits); | |
82 | + } else { | |
83 | + for (int i = 0; i < TransportRateLimitType.values().length; i++) { | |
84 | + TransportRateLimit newLimit = newRateLimits[i]; | |
85 | + TransportRateLimit oldLimit = oldRateLimits[i]; | |
86 | + if (newLimit != null && (oldLimit == null || !oldLimit.getConfiguration().equals(newLimit.getConfiguration()))) { | |
87 | + oldRateLimits[i] = newLimit; | |
88 | + } | |
89 | + } | |
90 | + } | |
91 | + } | |
92 | + | |
93 | + @Override | |
94 | + public void remove(TenantId tenantId) { | |
95 | + perTenantLimits.remove(tenantId); | |
96 | + } | |
97 | + | |
98 | + @Override | |
99 | + public void remove(DeviceId deviceId) { | |
100 | + perDeviceLimits.remove(deviceId); | |
101 | + } | |
102 | + | |
103 | + private TransportRateLimit[] fetchProfileAndInit(TenantId tenantId) { | |
104 | + return perTenantLimits.computeIfAbsent(tenantId, tmp -> createTransportRateLimits(tenantProfileCache.get(tenantId))); | |
105 | + } | |
106 | + | |
107 | + private TransportRateLimit[] createTransportRateLimits(TenantProfile tenantProfile) { | |
108 | + TenantProfileData profileData = tenantProfile.getProfileData(); | |
109 | + TransportRateLimit[] rateLimits = new TransportRateLimit[TransportRateLimitType.values().length]; | |
110 | + for (TransportRateLimitType type : TransportRateLimitType.values()) { | |
111 | + rateLimits[type.ordinal()] = rateLimitFactory.create(type, profileData.getProperties().get(type.getConfigurationKey())); | |
112 | + } | |
113 | + return rateLimits; | |
114 | + } | |
115 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2020 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.transport.limits; | |
17 | + | |
18 | +public class DummyTransportRateLimit implements TransportRateLimit { | |
19 | + | |
20 | + @Override | |
21 | + public String getConfiguration() { | |
22 | + return ""; | |
23 | + } | |
24 | + | |
25 | + @Override | |
26 | + public boolean tryConsume() { | |
27 | + return true; | |
28 | + } | |
29 | + | |
30 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2020 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.transport.limits; | |
17 | + | |
18 | +import lombok.Getter; | |
19 | +import lombok.RequiredArgsConstructor; | |
20 | +import org.thingsboard.server.common.msg.tools.TbRateLimits; | |
21 | + | |
22 | +@RequiredArgsConstructor | |
23 | +public class SimpleTransportRateLimit implements TransportRateLimit { | |
24 | + | |
25 | + private final TbRateLimits rateLimit; | |
26 | + @Getter | |
27 | + private final String configuration; | |
28 | + | |
29 | + @Override | |
30 | + public boolean tryConsume() { | |
31 | + return rateLimit.tryConsume(); | |
32 | + } | |
33 | + | |
34 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2020 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.transport.limits; | |
17 | + | |
18 | +public interface TransportRateLimit { | |
19 | + | |
20 | + String getConfiguration(); | |
21 | + | |
22 | + boolean tryConsume(); | |
23 | + | |
24 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2020 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.transport.limits; | |
17 | + | |
18 | +public interface TransportRateLimitFactory { | |
19 | + | |
20 | + TransportRateLimit create(TransportRateLimitType type, Object config); | |
21 | + | |
22 | + TransportRateLimit createDefault(TransportRateLimitType type); | |
23 | + | |
24 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2020 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.transport.limits; | |
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.transport.profile.TenantProfileUpdateResult; | |
21 | + | |
22 | +public interface TransportRateLimitService { | |
23 | + | |
24 | + TransportRateLimit getRateLimit(TenantId tenantId, TransportRateLimitType limit); | |
25 | + | |
26 | + TransportRateLimit getRateLimit(TenantId tenantId, DeviceId deviceId, TransportRateLimitType limit); | |
27 | + | |
28 | + void update(TenantProfileUpdateResult update); | |
29 | + | |
30 | + void update(TenantId tenantId); | |
31 | + | |
32 | + void remove(TenantId tenantId); | |
33 | + | |
34 | + void remove(DeviceId deviceId); | |
35 | + | |
36 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2020 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.transport.limits; | |
17 | + | |
18 | +import lombok.Getter; | |
19 | + | |
20 | +public enum TransportRateLimitType { | |
21 | + | |
22 | + TENANT_MAX_MSGS("transport.tenant.max.msg"), | |
23 | + TENANT_MAX_DATA_POINTS("transport.tenant.max.dataPoints"), | |
24 | + DEVICE_MAX_MSGS("transport.device.max.msg"), | |
25 | + DEVICE_MAX_DATA_POINTS("transport.device.max.dataPoints"); | |
26 | + | |
27 | + @Getter | |
28 | + private final String configurationKey; | |
29 | + | |
30 | + TransportRateLimitType(String configurationKey) { | |
31 | + this.configurationKey = configurationKey; | |
32 | + } | |
33 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2020 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.transport.profile; | |
17 | + | |
18 | +import lombok.Data; | |
19 | +import org.thingsboard.server.common.data.TenantProfile; | |
20 | +import org.thingsboard.server.common.data.id.TenantId; | |
21 | + | |
22 | +import java.util.Set; | |
23 | + | |
24 | +@Data | |
25 | +public class TenantProfileUpdateResult { | |
26 | + | |
27 | + private final TenantProfile profile; | |
28 | + private final Set<TenantId> affectedTenants; | |
29 | + | |
30 | +} | ... | ... |
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportDeviceProfileCache.java
renamed from
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportProfileCache.java
... | ... | @@ -21,7 +21,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
21 | 21 | import org.springframework.stereotype.Component; |
22 | 22 | import org.thingsboard.server.common.data.DeviceProfile; |
23 | 23 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
24 | -import org.thingsboard.server.common.transport.TransportProfileCache; | |
24 | +import org.thingsboard.server.common.transport.TransportDeviceProfileCache; | |
25 | 25 | import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; |
26 | 26 | |
27 | 27 | import java.util.Optional; |
... | ... | @@ -31,13 +31,13 @@ import java.util.concurrent.ConcurrentMap; |
31 | 31 | @Slf4j |
32 | 32 | @Component |
33 | 33 | @ConditionalOnExpression("('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true') || '${service.type:null}'=='tb-transport'") |
34 | -public class DefaultTransportProfileCache implements TransportProfileCache { | |
34 | +public class DefaultTransportDeviceProfileCache implements TransportDeviceProfileCache { | |
35 | 35 | |
36 | 36 | private final ConcurrentMap<DeviceProfileId, DeviceProfile> deviceProfiles = new ConcurrentHashMap<>(); |
37 | 37 | |
38 | 38 | private final DataDecodingEncodingService dataDecodingEncodingService; |
39 | 39 | |
40 | - public DefaultTransportProfileCache(DataDecodingEncodingService dataDecodingEncodingService) { | |
40 | + public DefaultTransportDeviceProfileCache(DataDecodingEncodingService dataDecodingEncodingService) { | |
41 | 41 | this.dataDecodingEncodingService = dataDecodingEncodingService; |
42 | 42 | } |
43 | 43 | ... | ... |
... | ... | @@ -29,25 +29,35 @@ import org.thingsboard.common.util.ThingsBoardThreadFactory; |
29 | 29 | import org.thingsboard.server.common.data.DeviceProfile; |
30 | 30 | import org.thingsboard.server.common.data.DeviceTransportType; |
31 | 31 | import org.thingsboard.server.common.data.EntityType; |
32 | +import org.thingsboard.server.common.data.Tenant; | |
32 | 33 | import org.thingsboard.server.common.data.id.DeviceId; |
33 | 34 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
34 | 35 | import org.thingsboard.server.common.data.id.RuleChainId; |
35 | 36 | import org.thingsboard.server.common.data.id.TenantId; |
37 | +import org.thingsboard.server.common.data.id.TenantProfileId; | |
36 | 38 | import org.thingsboard.server.common.msg.TbMsg; |
37 | 39 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
38 | 40 | import org.thingsboard.server.common.msg.queue.ServiceQueue; |
39 | 41 | import org.thingsboard.server.common.msg.queue.ServiceType; |
40 | 42 | import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
41 | 43 | import org.thingsboard.server.common.msg.session.SessionMsgType; |
42 | -import org.thingsboard.server.common.msg.tools.TbRateLimits; | |
43 | 44 | import org.thingsboard.server.common.msg.tools.TbRateLimitsException; |
45 | +import org.thingsboard.server.common.stats.MessagesStats; | |
46 | +import org.thingsboard.server.common.stats.StatsFactory; | |
47 | +import org.thingsboard.server.common.stats.StatsType; | |
44 | 48 | import org.thingsboard.server.common.transport.SessionMsgListener; |
45 | -import org.thingsboard.server.common.transport.TransportProfileCache; | |
49 | +import org.thingsboard.server.common.transport.TransportDeviceProfileCache; | |
46 | 50 | import org.thingsboard.server.common.transport.TransportService; |
47 | 51 | import org.thingsboard.server.common.transport.TransportServiceCallback; |
52 | +import org.thingsboard.server.common.transport.TransportTenantProfileCache; | |
48 | 53 | import org.thingsboard.server.common.transport.auth.GetOrCreateDeviceFromGatewayResponse; |
49 | 54 | import org.thingsboard.server.common.transport.auth.TransportDeviceInfo; |
50 | 55 | import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; |
56 | +import org.thingsboard.server.common.transport.limits.TransportRateLimit; | |
57 | +import org.thingsboard.server.common.transport.limits.TransportRateLimitService; | |
58 | +import org.thingsboard.server.common.transport.limits.TransportRateLimitType; | |
59 | +import org.thingsboard.server.common.transport.profile.TenantProfileUpdateResult; | |
60 | +import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; | |
51 | 61 | import org.thingsboard.server.common.transport.util.JsonUtils; |
52 | 62 | import org.thingsboard.server.gen.transport.TransportProtos; |
53 | 63 | import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg; |
... | ... | @@ -69,15 +79,13 @@ import org.thingsboard.server.queue.discovery.PartitionService; |
69 | 79 | import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
70 | 80 | import org.thingsboard.server.queue.provider.TbQueueProducerProvider; |
71 | 81 | import org.thingsboard.server.queue.provider.TbTransportQueueFactory; |
72 | -import org.thingsboard.server.common.stats.MessagesStats; | |
73 | -import org.thingsboard.server.common.stats.StatsFactory; | |
74 | -import org.thingsboard.server.common.stats.StatsType; | |
75 | 82 | |
76 | 83 | import javax.annotation.PostConstruct; |
77 | 84 | import javax.annotation.PreDestroy; |
78 | 85 | import java.util.Collections; |
79 | 86 | import java.util.List; |
80 | 87 | import java.util.Map; |
88 | +import java.util.Optional; | |
81 | 89 | import java.util.Random; |
82 | 90 | import java.util.UUID; |
83 | 91 | import java.util.concurrent.ConcurrentHashMap; |
... | ... | @@ -98,12 +106,6 @@ import java.util.concurrent.atomic.AtomicInteger; |
98 | 106 | @ConditionalOnExpression("('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true') || '${service.type:null}'=='tb-transport'") |
99 | 107 | public class DefaultTransportService implements TransportService { |
100 | 108 | |
101 | - @Value("${transport.rate_limits.enabled}") | |
102 | - private boolean rateLimitEnabled; | |
103 | - @Value("${transport.rate_limits.tenant}") | |
104 | - private String perTenantLimitsConf; | |
105 | - @Value("${transport.rate_limits.device}") | |
106 | - private String perDevicesLimitsConf; | |
107 | 109 | @Value("${transport.sessions.inactivity_timeout}") |
108 | 110 | private long sessionInactivityTimeout; |
109 | 111 | @Value("${transport.sessions.report_timeout}") |
... | ... | @@ -119,7 +121,10 @@ public class DefaultTransportService implements TransportService { |
119 | 121 | private final PartitionService partitionService; |
120 | 122 | private final TbServiceInfoProvider serviceInfoProvider; |
121 | 123 | private final StatsFactory statsFactory; |
122 | - private final TransportProfileCache transportProfileCache; | |
124 | + private final TransportDeviceProfileCache deviceProfileCache; | |
125 | + private final TransportTenantProfileCache tenantProfileCache; | |
126 | + private final TransportRateLimitService rateLimitService; | |
127 | + private final DataDecodingEncodingService dataDecodingEncodingService; | |
123 | 128 | |
124 | 129 | protected TbQueueRequestTemplate<TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> transportApiRequestTemplate; |
125 | 130 | protected TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> ruleEngineMsgProducer; |
... | ... | @@ -132,14 +137,11 @@ public class DefaultTransportService implements TransportService { |
132 | 137 | |
133 | 138 | protected ScheduledExecutorService schedulerExecutor; |
134 | 139 | protected ExecutorService transportCallbackExecutor; |
140 | + private ExecutorService mainConsumerExecutor; | |
135 | 141 | |
136 | 142 | private final ConcurrentMap<UUID, SessionMetaData> sessions = new ConcurrentHashMap<>(); |
137 | 143 | private final Map<String, RpcRequestMetadata> toServerRpcPendingMap = new ConcurrentHashMap<>(); |
138 | - //TODO 3.2: @ybondarenko Implement cleanup of this maps. | |
139 | - private final ConcurrentMap<TenantId, TbRateLimits> perTenantLimits = new ConcurrentHashMap<>(); | |
140 | - private final ConcurrentMap<DeviceId, TbRateLimits> perDeviceLimits = new ConcurrentHashMap<>(); | |
141 | 144 | |
142 | - private ExecutorService mainConsumerExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("transport-consumer")); | |
143 | 145 | private volatile boolean stopped = false; |
144 | 146 | |
145 | 147 | public DefaultTransportService(TbServiceInfoProvider serviceInfoProvider, |
... | ... | @@ -147,22 +149,22 @@ public class DefaultTransportService implements TransportService { |
147 | 149 | TbQueueProducerProvider producerProvider, |
148 | 150 | PartitionService partitionService, |
149 | 151 | StatsFactory statsFactory, |
150 | - TransportProfileCache transportProfileCache) { | |
152 | + TransportDeviceProfileCache deviceProfileCache, | |
153 | + TransportTenantProfileCache tenantProfileCache, | |
154 | + TransportRateLimitService rateLimitService, DataDecodingEncodingService dataDecodingEncodingService) { | |
151 | 155 | this.serviceInfoProvider = serviceInfoProvider; |
152 | 156 | this.queueProvider = queueProvider; |
153 | 157 | this.producerProvider = producerProvider; |
154 | 158 | this.partitionService = partitionService; |
155 | 159 | this.statsFactory = statsFactory; |
156 | - this.transportProfileCache = transportProfileCache; | |
160 | + this.deviceProfileCache = deviceProfileCache; | |
161 | + this.tenantProfileCache = tenantProfileCache; | |
162 | + this.rateLimitService = rateLimitService; | |
163 | + this.dataDecodingEncodingService = dataDecodingEncodingService; | |
157 | 164 | } |
158 | 165 | |
159 | 166 | @PostConstruct |
160 | 167 | public void init() { |
161 | - if (rateLimitEnabled) { | |
162 | - //Just checking the configuration parameters | |
163 | - new TbRateLimits(perTenantLimitsConf); | |
164 | - new TbRateLimits(perDevicesLimitsConf); | |
165 | - } | |
166 | 168 | this.ruleEngineProducerStats = statsFactory.createMessagesStats(StatsType.RULE_ENGINE.getName() + ".producer"); |
167 | 169 | this.tbCoreProducerStats = statsFactory.createMessagesStats(StatsType.CORE.getName() + ".producer"); |
168 | 170 | this.transportApiStats = statsFactory.createMessagesStats(StatsType.TRANSPORT.getName() + ".producer"); |
... | ... | @@ -177,6 +179,7 @@ public class DefaultTransportService implements TransportService { |
177 | 179 | TopicPartitionInfo tpi = partitionService.getNotificationsTopic(ServiceType.TB_TRANSPORT, serviceInfoProvider.getServiceId()); |
178 | 180 | transportNotificationsConsumer.subscribe(Collections.singleton(tpi)); |
179 | 181 | transportApiRequestTemplate.init(); |
182 | + mainConsumerExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("transport-consumer")); | |
180 | 183 | mainConsumerExecutor.execute(() -> { |
181 | 184 | while (!stopped) { |
182 | 185 | try { |
... | ... | @@ -208,10 +211,6 @@ public class DefaultTransportService implements TransportService { |
208 | 211 | |
209 | 212 | @PreDestroy |
210 | 213 | public void destroy() { |
211 | - if (rateLimitEnabled) { | |
212 | - perTenantLimits.clear(); | |
213 | - perDeviceLimits.clear(); | |
214 | - } | |
215 | 214 | stopped = true; |
216 | 215 | |
217 | 216 | if (transportNotificationsConsumer != null) { |
... | ... | @@ -232,7 +231,7 @@ public class DefaultTransportService implements TransportService { |
232 | 231 | } |
233 | 232 | |
234 | 233 | @Override |
235 | - public ScheduledExecutorService getSchedulerExecutor(){ | |
234 | + public ScheduledExecutorService getSchedulerExecutor() { | |
236 | 235 | return this.schedulerExecutor; |
237 | 236 | } |
238 | 237 | |
... | ... | @@ -242,12 +241,12 @@ public class DefaultTransportService implements TransportService { |
242 | 241 | } |
243 | 242 | |
244 | 243 | @Override |
245 | - public TransportProtos.GetTenantRoutingInfoResponseMsg getRoutingInfo(TransportProtos.GetTenantRoutingInfoRequestMsg msg) { | |
244 | + public TransportProtos.GetEntityProfileResponseMsg getRoutingInfo(TransportProtos.GetEntityProfileRequestMsg msg) { | |
246 | 245 | TbProtoQueueMsg<TransportProtos.TransportApiRequestMsg> protoMsg = |
247 | - new TbProtoQueueMsg<>(UUID.randomUUID(), TransportProtos.TransportApiRequestMsg.newBuilder().setGetTenantRoutingInfoRequestMsg(msg).build()); | |
246 | + new TbProtoQueueMsg<>(UUID.randomUUID(), TransportProtos.TransportApiRequestMsg.newBuilder().setEntityProfileRequestMsg(msg).build()); | |
248 | 247 | try { |
249 | 248 | TbProtoQueueMsg<TransportApiResponseMsg> response = transportApiRequestTemplate.send(protoMsg).get(); |
250 | - return response.getValue().getGetTenantRoutingInfoResponseMsg(); | |
249 | + return response.getValue().getEntityProfileResponseMsg(); | |
251 | 250 | } catch (InterruptedException | ExecutionException e) { |
252 | 251 | throw new RuntimeException(e); |
253 | 252 | } |
... | ... | @@ -289,7 +288,7 @@ public class DefaultTransportService implements TransportService { |
289 | 288 | result.deviceInfo(tdi); |
290 | 289 | ByteString profileBody = msg.getProfileBody(); |
291 | 290 | if (profileBody != null && !profileBody.isEmpty()) { |
292 | - DeviceProfile profile = transportProfileCache.getOrCreate(tdi.getDeviceProfileId(), profileBody); | |
291 | + DeviceProfile profile = deviceProfileCache.getOrCreate(tdi.getDeviceProfileId(), profileBody); | |
293 | 292 | if (transportType != DeviceTransportType.DEFAULT |
294 | 293 | && profile != null && profile.getTransportType() != DeviceTransportType.DEFAULT && profile.getTransportType() != transportType) { |
295 | 294 | log.debug("[{}] Device profile [{}] has different transport type: {}, expected: {}", tdi.getDeviceId(), tdi.getDeviceProfileId(), profile.getTransportType(), transportType); |
... | ... | @@ -315,7 +314,7 @@ public class DefaultTransportService implements TransportService { |
315 | 314 | result.deviceInfo(tdi); |
316 | 315 | ByteString profileBody = msg.getProfileBody(); |
317 | 316 | if (profileBody != null && !profileBody.isEmpty()) { |
318 | - result.deviceProfile(transportProfileCache.getOrCreate(tdi.getDeviceProfileId(), profileBody)); | |
317 | + result.deviceProfile(deviceProfileCache.getOrCreate(tdi.getDeviceProfileId(), profileBody)); | |
319 | 318 | } |
320 | 319 | } |
321 | 320 | return result.build(); |
... | ... | @@ -339,8 +338,8 @@ public class DefaultTransportService implements TransportService { |
339 | 338 | log.trace("Processing msg: {}", requestMsg); |
340 | 339 | TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>(UUID.randomUUID(), TransportApiRequestMsg.newBuilder().setProvisionDeviceRequestMsg(requestMsg).build()); |
341 | 340 | ListenableFuture<ProvisionDeviceResponseMsg> response = Futures.transform(transportApiRequestTemplate.send(protoMsg), tmp -> |
342 | - tmp.getValue().getProvisionDeviceResponseMsg() | |
343 | - , MoreExecutors.directExecutor()); | |
341 | + tmp.getValue().getProvisionDeviceResponseMsg() | |
342 | + , MoreExecutors.directExecutor()); | |
344 | 343 | AsyncCallbackTemplate.withCallback(response, callback::onSuccess, callback::onError, transportCallbackExecutor); |
345 | 344 | } |
346 | 345 | |
... | ... | @@ -580,12 +579,11 @@ public class DefaultTransportService implements TransportService { |
580 | 579 | if (log.isTraceEnabled()) { |
581 | 580 | log.trace("[{}] Processing msg: {}", toSessionId(sessionInfo), msg); |
582 | 581 | } |
583 | - if (!rateLimitEnabled) { | |
584 | - return true; | |
585 | - } | |
586 | 582 | TenantId tenantId = new TenantId(new UUID(sessionInfo.getTenantIdMSB(), sessionInfo.getTenantIdLSB())); |
587 | - TbRateLimits rateLimits = perTenantLimits.computeIfAbsent(tenantId, id -> new TbRateLimits(perTenantLimitsConf)); | |
588 | - if (!rateLimits.tryConsume()) { | |
583 | + | |
584 | + TransportRateLimit tenantRateLimit = rateLimitService.getRateLimit(tenantId, TransportRateLimitType.TENANT_MAX_MSGS); | |
585 | + | |
586 | + if (!tenantRateLimit.tryConsume()) { | |
589 | 587 | if (callback != null) { |
590 | 588 | callback.onError(new TbRateLimitsException(EntityType.TENANT)); |
591 | 589 | } |
... | ... | @@ -595,8 +593,8 @@ public class DefaultTransportService implements TransportService { |
595 | 593 | return false; |
596 | 594 | } |
597 | 595 | DeviceId deviceId = new DeviceId(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); |
598 | - rateLimits = perDeviceLimits.computeIfAbsent(deviceId, id -> new TbRateLimits(perDevicesLimitsConf)); | |
599 | - if (!rateLimits.tryConsume()) { | |
596 | + TransportRateLimit deviceRateLimit = rateLimitService.getRateLimit(tenantId, deviceId, TransportRateLimitType.DEVICE_MAX_MSGS); | |
597 | + if (!deviceRateLimit.tryConsume()) { | |
600 | 598 | if (callback != null) { |
601 | 599 | callback.onError(new TbRateLimitsException(EntityType.DEVICE)); |
602 | 600 | } |
... | ... | @@ -637,16 +635,40 @@ public class DefaultTransportService implements TransportService { |
637 | 635 | deregisterSession(md.getSessionInfo()); |
638 | 636 | } |
639 | 637 | } else { |
640 | - if (toSessionMsg.hasDeviceProfileUpdateMsg()) { | |
641 | - DeviceProfile deviceProfile = transportProfileCache.put(toSessionMsg.getDeviceProfileUpdateMsg().getData()); | |
642 | - if (deviceProfile != null) { | |
643 | - onProfileUpdate(deviceProfile); | |
638 | + if (toSessionMsg.hasEntityUpdateMsg()) { | |
639 | + TransportProtos.EntityUpdateMsg msg = toSessionMsg.getEntityUpdateMsg(); | |
640 | + EntityType entityType = EntityType.valueOf(msg.getEntityType()); | |
641 | + if (EntityType.DEVICE_PROFILE.equals(entityType)) { | |
642 | + DeviceProfile deviceProfile = deviceProfileCache.put(msg.getData()); | |
643 | + if (deviceProfile != null) { | |
644 | + onProfileUpdate(deviceProfile); | |
645 | + } | |
646 | + } else if (EntityType.TENANT_PROFILE.equals(entityType)) { | |
647 | + TenantProfileUpdateResult update = tenantProfileCache.put(msg.getData()); | |
648 | + rateLimitService.update(update); | |
649 | + } else if (EntityType.TENANT.equals(entityType)) { | |
650 | + Optional<Tenant> profileOpt = dataDecodingEncodingService.decode(msg.getData().toByteArray()); | |
651 | + if (profileOpt.isPresent()) { | |
652 | + Tenant tenant = profileOpt.get(); | |
653 | + boolean updated = tenantProfileCache.put(tenant.getId(), tenant.getTenantProfileId()); | |
654 | + if (updated) { | |
655 | + rateLimitService.update(tenant.getId()); | |
656 | + } | |
657 | + } | |
658 | + } | |
659 | + } else if (toSessionMsg.hasEntityDeleteMsg()) { | |
660 | + TransportProtos.EntityDeleteMsg msg = toSessionMsg.getEntityDeleteMsg(); | |
661 | + EntityType entityType = EntityType.valueOf(msg.getEntityType()); | |
662 | + UUID entityUuid = new UUID(msg.getEntityIdMSB(), msg.getEntityIdLSB()); | |
663 | + if (EntityType.DEVICE_PROFILE.equals(entityType)) { | |
664 | + deviceProfileCache.evict(new DeviceProfileId(new UUID(msg.getEntityIdMSB(), msg.getEntityIdLSB()))); | |
665 | + } else if (EntityType.TENANT_PROFILE.equals(entityType)) { | |
666 | + tenantProfileCache.remove(new TenantProfileId(entityUuid)); | |
667 | + } else if (EntityType.TENANT.equals(entityType)) { | |
668 | + rateLimitService.remove(new TenantId(entityUuid)); | |
669 | + } else if (EntityType.DEVICE.equals(entityType)) { | |
670 | + rateLimitService.remove(new DeviceId(entityUuid)); | |
644 | 671 | } |
645 | - } else if (toSessionMsg.hasDeviceProfileDeleteMsg()) { | |
646 | - transportProfileCache.evict(new DeviceProfileId(new UUID( | |
647 | - toSessionMsg.getDeviceProfileDeleteMsg().getProfileIdMSB(), | |
648 | - toSessionMsg.getDeviceProfileDeleteMsg().getProfileIdLSB() | |
649 | - ))); | |
650 | 672 | } else { |
651 | 673 | //TODO: should we notify the device actor about missed session? |
652 | 674 | log.debug("[{}] Missing session.", sessionId); |
... | ... | @@ -655,38 +677,6 @@ public class DefaultTransportService implements TransportService { |
655 | 677 | } |
656 | 678 | |
657 | 679 | @Override |
658 | - public void getDeviceProfile(DeviceProfileId deviceProfileId, TransportServiceCallback<DeviceProfile> callback) { | |
659 | - DeviceProfile deviceProfile = transportProfileCache.get(deviceProfileId); | |
660 | - if (deviceProfile != null) { | |
661 | - callback.onSuccess(deviceProfile); | |
662 | - } else { | |
663 | - log.trace("Processing device profile request: [{}]", deviceProfileId); | |
664 | - TransportProtos.GetDeviceProfileRequestMsg msg = TransportProtos.GetDeviceProfileRequestMsg.newBuilder() | |
665 | - .setProfileIdMSB(deviceProfileId.getId().getMostSignificantBits()) | |
666 | - .setProfileIdLSB(deviceProfileId.getId().getLeastSignificantBits()) | |
667 | - .build(); | |
668 | - TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>(UUID.randomUUID(), | |
669 | - TransportApiRequestMsg.newBuilder().setGetDeviceProfileRequestMsg(msg).build()); | |
670 | - AsyncCallbackTemplate.withCallback(transportApiRequestTemplate.send(protoMsg), | |
671 | - response -> { | |
672 | - ByteString devProfileBody = response.getValue().getGetDeviceProfileResponseMsg().getData(); | |
673 | - if (devProfileBody != null && !devProfileBody.isEmpty()) { | |
674 | - DeviceProfile profile = transportProfileCache.put(devProfileBody); | |
675 | - if (profile != null) { | |
676 | - callback.onSuccess(profile); | |
677 | - } else { | |
678 | - log.warn("Failed to decode device profile: {}", devProfileBody); | |
679 | - callback.onError(new IllegalArgumentException("Failed to decode device profile!")); | |
680 | - } | |
681 | - } else { | |
682 | - log.warn("Failed to find device profile: [{}]", deviceProfileId); | |
683 | - callback.onError(new IllegalArgumentException("Failed to find device profile!")); | |
684 | - } | |
685 | - }, callback::onError, transportCallbackExecutor); | |
686 | - } | |
687 | - } | |
688 | - | |
689 | - @Override | |
690 | 680 | public void onProfileUpdate(DeviceProfile deviceProfile) { |
691 | 681 | long deviceProfileIdMSB = deviceProfile.getId().getId().getMostSignificantBits(); |
692 | 682 | long deviceProfileIdLSB = deviceProfile.getId().getId().getLeastSignificantBits(); |
... | ... | @@ -750,7 +740,7 @@ public class DefaultTransportService implements TransportService { |
750 | 740 | |
751 | 741 | private RuleChainId resolveRuleChainId(TransportProtos.SessionInfoProto sessionInfo) { |
752 | 742 | DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); |
753 | - DeviceProfile deviceProfile = transportProfileCache.get(deviceProfileId); | |
743 | + DeviceProfile deviceProfile = deviceProfileCache.get(deviceProfileId); | |
754 | 744 | RuleChainId ruleChainId; |
755 | 745 | if (deviceProfile == null) { |
756 | 746 | log.warn("[{}] Device profile is null!", deviceProfileId); |
... | ... | @@ -779,7 +769,7 @@ public class DefaultTransportService implements TransportService { |
779 | 769 | } |
780 | 770 | } |
781 | 771 | |
782 | - private class StatsCallback implements TbQueueCallback { | |
772 | + private static class StatsCallback implements TbQueueCallback { | |
783 | 773 | private final TbQueueCallback callback; |
784 | 774 | private final MessagesStats stats; |
785 | 775 | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2020 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.transport.service; | |
17 | + | |
18 | +import com.google.protobuf.ByteString; | |
19 | +import lombok.extern.slf4j.Slf4j; | |
20 | +import org.springframework.beans.factory.annotation.Autowired; | |
21 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | |
22 | +import org.springframework.context.annotation.Lazy; | |
23 | +import org.springframework.stereotype.Component; | |
24 | +import org.thingsboard.server.common.data.DeviceProfile; | |
25 | +import org.thingsboard.server.common.data.EntityType; | |
26 | +import org.thingsboard.server.common.data.TenantProfile; | |
27 | +import org.thingsboard.server.common.data.id.TenantId; | |
28 | +import org.thingsboard.server.common.data.id.TenantProfileId; | |
29 | +import org.thingsboard.server.common.transport.TransportService; | |
30 | +import org.thingsboard.server.common.transport.TransportTenantProfileCache; | |
31 | +import org.thingsboard.server.common.transport.profile.TenantProfileUpdateResult; | |
32 | +import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; | |
33 | +import org.thingsboard.server.gen.transport.TransportProtos; | |
34 | +import org.thingsboard.server.queue.discovery.TenantRoutingInfo; | |
35 | +import org.thingsboard.server.queue.discovery.TenantRoutingInfoService; | |
36 | + | |
37 | +import java.util.Collections; | |
38 | +import java.util.Optional; | |
39 | +import java.util.Set; | |
40 | +import java.util.concurrent.ConcurrentHashMap; | |
41 | +import java.util.concurrent.ConcurrentMap; | |
42 | +import java.util.concurrent.locks.Lock; | |
43 | +import java.util.concurrent.locks.ReentrantLock; | |
44 | + | |
45 | +@Component | |
46 | +@ConditionalOnExpression("('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true') || '${service.type:null}'=='tb-transport'") | |
47 | +@Slf4j | |
48 | +public class DefaultTransportTenantProfileCache implements TransportTenantProfileCache { | |
49 | + | |
50 | + private final Lock tenantProfileFetchLock = new ReentrantLock(); | |
51 | + private final ConcurrentMap<TenantProfileId, TenantProfile> profiles = new ConcurrentHashMap<>(); | |
52 | + private final ConcurrentMap<TenantId, TenantProfileId> tenantIds = new ConcurrentHashMap<>(); | |
53 | + private final ConcurrentMap<TenantProfileId, Set<TenantId>> tenantProfileIds = new ConcurrentHashMap<>(); | |
54 | + private final DataDecodingEncodingService dataDecodingEncodingService; | |
55 | + | |
56 | + private TransportService transportService; | |
57 | + | |
58 | + @Lazy | |
59 | + @Autowired | |
60 | + public void setTransportService(TransportService transportService) { | |
61 | + this.transportService = transportService; | |
62 | + } | |
63 | + | |
64 | + public DefaultTransportTenantProfileCache(DataDecodingEncodingService dataDecodingEncodingService) { | |
65 | + this.dataDecodingEncodingService = dataDecodingEncodingService; | |
66 | + } | |
67 | + | |
68 | + @Override | |
69 | + public TenantProfile get(TenantId tenantId) { | |
70 | + return getTenantProfile(tenantId); | |
71 | + } | |
72 | + | |
73 | + @Override | |
74 | + public TenantProfileUpdateResult put(ByteString profileBody) { | |
75 | + Optional<TenantProfile> profileOpt = dataDecodingEncodingService.decode(profileBody.toByteArray()); | |
76 | + if (profileOpt.isPresent()) { | |
77 | + TenantProfile newProfile = profileOpt.get(); | |
78 | + log.trace("[{}] put: {}", newProfile.getId(), newProfile); | |
79 | + return new TenantProfileUpdateResult(newProfile, tenantProfileIds.get(newProfile.getId())); | |
80 | + } else { | |
81 | + log.warn("Failed to decode profile: {}", profileBody.toString()); | |
82 | + return new TenantProfileUpdateResult(null, Collections.emptySet()); | |
83 | + } | |
84 | + } | |
85 | + | |
86 | + @Override | |
87 | + public boolean put(TenantId tenantId, TenantProfileId profileId) { | |
88 | + log.trace("[{}] put: {}", tenantId, profileId); | |
89 | + TenantProfileId oldProfileId = tenantIds.get(tenantId); | |
90 | + if (oldProfileId != null && !oldProfileId.equals(profileId)) { | |
91 | + tenantProfileIds.computeIfAbsent(oldProfileId, id -> ConcurrentHashMap.newKeySet()).remove(tenantId); | |
92 | + tenantIds.put(tenantId, profileId); | |
93 | + tenantProfileIds.computeIfAbsent(profileId, id -> ConcurrentHashMap.newKeySet()).add(tenantId); | |
94 | + return true; | |
95 | + } else { | |
96 | + return false; | |
97 | + } | |
98 | + } | |
99 | + | |
100 | + @Override | |
101 | + public Set<TenantId> remove(TenantProfileId profileId) { | |
102 | + Set<TenantId> tenants = tenantProfileIds.remove(profileId); | |
103 | + if (tenants != null) { | |
104 | + tenants.forEach(tenantIds::remove); | |
105 | + } | |
106 | + profiles.remove(profileId); | |
107 | + return tenants; | |
108 | + } | |
109 | + | |
110 | + private TenantProfile getTenantProfile(TenantId tenantId) { | |
111 | + TenantProfile profile = null; | |
112 | + TenantProfileId tenantProfileId = tenantIds.get(tenantId); | |
113 | + if (tenantProfileId != null) { | |
114 | + profile = profiles.get(tenantProfileId); | |
115 | + } | |
116 | + if (profile == null) { | |
117 | + tenantProfileFetchLock.lock(); | |
118 | + try { | |
119 | + tenantProfileId = tenantIds.get(tenantId); | |
120 | + if (tenantProfileId != null) { | |
121 | + profile = profiles.get(tenantProfileId); | |
122 | + } | |
123 | + if (profile == null) { | |
124 | + TransportProtos.GetEntityProfileRequestMsg msg = TransportProtos.GetEntityProfileRequestMsg.newBuilder() | |
125 | + .setEntityType(EntityType.TENANT.name()) | |
126 | + .setEntityIdMSB(tenantId.getId().getMostSignificantBits()) | |
127 | + .setEntityIdLSB(tenantId.getId().getLeastSignificantBits()) | |
128 | + .build(); | |
129 | + TransportProtos.GetEntityProfileResponseMsg routingInfo = transportService.getRoutingInfo(msg); | |
130 | + Optional<TenantProfile> profileOpt = dataDecodingEncodingService.decode(routingInfo.getData().toByteArray()); | |
131 | + if (profileOpt.isPresent()) { | |
132 | + profile = profileOpt.get(); | |
133 | + TenantProfile existingProfile = profiles.get(profile.getId()); | |
134 | + if (existingProfile != null) { | |
135 | + profile = existingProfile; | |
136 | + } else { | |
137 | + profiles.put(profile.getId(), profile); | |
138 | + } | |
139 | + tenantProfileIds.computeIfAbsent(profile.getId(), id -> ConcurrentHashMap.newKeySet()).add(tenantId); | |
140 | + tenantIds.put(tenantId, profile.getId()); | |
141 | + } else { | |
142 | + log.warn("[{}] Can't decode tenant profile: {}", tenantId, routingInfo.getData()); | |
143 | + throw new RuntimeException("Can't decode tenant profile!"); | |
144 | + } | |
145 | + } | |
146 | + } finally { | |
147 | + tenantProfileFetchLock.unlock(); | |
148 | + } | |
149 | + } | |
150 | + return profile; | |
151 | + } | |
152 | + | |
153 | + | |
154 | +} | ... | ... |
... | ... | @@ -16,14 +16,11 @@ |
16 | 16 | package org.thingsboard.server.common.transport.service; |
17 | 17 | |
18 | 18 | import lombok.extern.slf4j.Slf4j; |
19 | -import org.springframework.beans.factory.annotation.Autowired; | |
20 | 19 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
21 | -import org.springframework.context.annotation.Lazy; | |
22 | 20 | import org.springframework.stereotype.Service; |
21 | +import org.thingsboard.server.common.data.TenantProfile; | |
23 | 22 | import org.thingsboard.server.common.data.id.TenantId; |
24 | -import org.thingsboard.server.common.transport.TransportService; | |
25 | -import org.thingsboard.server.gen.transport.TransportProtos.GetTenantRoutingInfoRequestMsg; | |
26 | -import org.thingsboard.server.gen.transport.TransportProtos.GetTenantRoutingInfoResponseMsg; | |
23 | +import org.thingsboard.server.common.transport.TransportTenantProfileCache; | |
27 | 24 | import org.thingsboard.server.queue.discovery.TenantRoutingInfo; |
28 | 25 | import org.thingsboard.server.queue.discovery.TenantRoutingInfoService; |
29 | 26 | |
... | ... | @@ -32,21 +29,16 @@ import org.thingsboard.server.queue.discovery.TenantRoutingInfoService; |
32 | 29 | @ConditionalOnExpression("'${service.type:null}'=='tb-transport'") |
33 | 30 | public class TransportTenantRoutingInfoService implements TenantRoutingInfoService { |
34 | 31 | |
35 | - private TransportService transportService; | |
32 | + private TransportTenantProfileCache tenantProfileCache; | |
36 | 33 | |
37 | - @Lazy | |
38 | - @Autowired | |
39 | - public void setTransportService(TransportService transportService) { | |
40 | - this.transportService = transportService; | |
34 | + public TransportTenantRoutingInfoService(TransportTenantProfileCache tenantProfileCache) { | |
35 | + this.tenantProfileCache = tenantProfileCache; | |
41 | 36 | } |
42 | 37 | |
43 | 38 | @Override |
44 | 39 | public TenantRoutingInfo getRoutingInfo(TenantId tenantId) { |
45 | - GetTenantRoutingInfoRequestMsg msg = GetTenantRoutingInfoRequestMsg.newBuilder() | |
46 | - .setTenantIdMSB(tenantId.getId().getMostSignificantBits()) | |
47 | - .setTenantIdLSB(tenantId.getId().getLeastSignificantBits()) | |
48 | - .build(); | |
49 | - GetTenantRoutingInfoResponseMsg routingInfo = transportService.getRoutingInfo(msg); | |
50 | - return new TenantRoutingInfo(tenantId, routingInfo.getIsolatedTbCore(), routingInfo.getIsolatedTbRuleEngine()); | |
40 | + TenantProfile profile = tenantProfileCache.get(tenantId); | |
41 | + return new TenantRoutingInfo(tenantId, profile.isIsolatedTbCore(), profile.isIsolatedTbRuleEngine()); | |
51 | 42 | } |
43 | + | |
52 | 44 | } | ... | ... |
... | ... | @@ -49,10 +49,6 @@ transport: |
49 | 49 | sessions: |
50 | 50 | inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}" |
51 | 51 | report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:30000}" |
52 | - rate_limits: | |
53 | - enabled: "${TB_TRANSPORT_RATE_LIMITS_ENABLED:false}" | |
54 | - tenant: "${TB_TRANSPORT_RATE_LIMITS_TENANT:1000:1,20000:60}" | |
55 | - device: "${TB_TRANSPORT_RATE_LIMITS_DEVICE:10:1,300:60}" | |
56 | 52 | json: |
57 | 53 | # Cast String data types to Numeric if possible when processing Telemetry/Attributes JSON |
58 | 54 | type_cast_enabled: "${JSON_TYPE_CAST_ENABLED:true}" | ... | ... |
... | ... | @@ -42,10 +42,6 @@ transport: |
42 | 42 | sessions: |
43 | 43 | inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}" |
44 | 44 | report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:30000}" |
45 | - rate_limits: | |
46 | - enabled: "${TB_TRANSPORT_RATE_LIMITS_ENABLED:false}" | |
47 | - tenant: "${TB_TRANSPORT_RATE_LIMITS_TENANT:1000:1,20000:60}" | |
48 | - device: "${TB_TRANSPORT_RATE_LIMITS_DEVICE:10:1,300:60}" | |
49 | 45 | json: |
50 | 46 | # Cast String data types to Numeric if possible when processing Telemetry/Attributes JSON |
51 | 47 | type_cast_enabled: "${JSON_TYPE_CAST_ENABLED:true}" | ... | ... |
... | ... | @@ -71,10 +71,6 @@ transport: |
71 | 71 | sessions: |
72 | 72 | inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}" |
73 | 73 | report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:30000}" |
74 | - rate_limits: | |
75 | - enabled: "${TB_TRANSPORT_RATE_LIMITS_ENABLED:false}" | |
76 | - tenant: "${TB_TRANSPORT_RATE_LIMITS_TENANT:1000:1,20000:60}" | |
77 | - device: "${TB_TRANSPORT_RATE_LIMITS_DEVICE:10:1,300:60}" | |
78 | 74 | json: |
79 | 75 | # Cast String data types to Numeric if possible when processing Telemetry/Attributes JSON |
80 | 76 | type_cast_enabled: "${JSON_TYPE_CAST_ENABLED:true}" | ... | ... |