Merge branch 'rc' of github.com:thingsboard/thingsboard into rc
This commit is contained in:
commit
9e0cf30fb9
@ -177,8 +177,8 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer
|
||||
if (strategy.sendWsUpdate()) {
|
||||
addWsCallback(resultFuture, success -> onTimeSeriesUpdate(tenantId, entityId, request.getEntries()));
|
||||
}
|
||||
if (strategy.saveLatest()) {
|
||||
copyLatestToEntityViews(tenantId, entityId, request.getEntries());
|
||||
if (strategy.saveLatest() && entityId.getEntityType().isOneOf(EntityType.DEVICE, EntityType.ASSET)) {
|
||||
addMainCallback(resultFuture, __ -> copyLatestToEntityViews(tenantId, entityId, request.getEntries()));
|
||||
}
|
||||
return resultFuture;
|
||||
}
|
||||
@ -333,58 +333,56 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer
|
||||
}
|
||||
|
||||
private void copyLatestToEntityViews(TenantId tenantId, EntityId entityId, List<TsKvEntry> ts) {
|
||||
if (EntityType.DEVICE.equals(entityId.getEntityType()) || EntityType.ASSET.equals(entityId.getEntityType())) {
|
||||
Futures.addCallback(this.tbEntityViewService.findEntityViewsByTenantIdAndEntityIdAsync(tenantId, entityId),
|
||||
new FutureCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable List<EntityView> result) {
|
||||
if (result != null && !result.isEmpty()) {
|
||||
Map<String, List<TsKvEntry>> tsMap = new HashMap<>();
|
||||
for (TsKvEntry entry : ts) {
|
||||
tsMap.computeIfAbsent(entry.getKey(), s -> new ArrayList<>()).add(entry);
|
||||
Futures.addCallback(tbEntityViewService.findEntityViewsByTenantIdAndEntityIdAsync(tenantId, entityId),
|
||||
new FutureCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable List<EntityView> result) {
|
||||
if (result != null && !result.isEmpty()) {
|
||||
Map<String, List<TsKvEntry>> tsMap = new HashMap<>();
|
||||
for (TsKvEntry entry : ts) {
|
||||
tsMap.computeIfAbsent(entry.getKey(), s -> new ArrayList<>()).add(entry);
|
||||
}
|
||||
for (EntityView entityView : result) {
|
||||
List<String> keys = entityView.getKeys() != null && entityView.getKeys().getTimeseries() != null ?
|
||||
entityView.getKeys().getTimeseries() : new ArrayList<>(tsMap.keySet());
|
||||
List<TsKvEntry> entityViewLatest = new ArrayList<>();
|
||||
long startTs = entityView.getStartTimeMs();
|
||||
long endTs = entityView.getEndTimeMs() == 0 ? Long.MAX_VALUE : entityView.getEndTimeMs();
|
||||
for (String key : keys) {
|
||||
List<TsKvEntry> entries = tsMap.get(key);
|
||||
if (entries != null) {
|
||||
Optional<TsKvEntry> tsKvEntry = entries.stream()
|
||||
.filter(entry -> entry.getTs() > startTs && entry.getTs() <= endTs)
|
||||
.max(comparingLong(TsKvEntry::getTs));
|
||||
tsKvEntry.ifPresent(entityViewLatest::add);
|
||||
}
|
||||
}
|
||||
for (EntityView entityView : result) {
|
||||
List<String> keys = entityView.getKeys() != null && entityView.getKeys().getTimeseries() != null ?
|
||||
entityView.getKeys().getTimeseries() : new ArrayList<>(tsMap.keySet());
|
||||
List<TsKvEntry> entityViewLatest = new ArrayList<>();
|
||||
long startTs = entityView.getStartTimeMs();
|
||||
long endTs = entityView.getEndTimeMs() == 0 ? Long.MAX_VALUE : entityView.getEndTimeMs();
|
||||
for (String key : keys) {
|
||||
List<TsKvEntry> entries = tsMap.get(key);
|
||||
if (entries != null) {
|
||||
Optional<TsKvEntry> tsKvEntry = entries.stream()
|
||||
.filter(entry -> entry.getTs() > startTs && entry.getTs() <= endTs)
|
||||
.max(comparingLong(TsKvEntry::getTs));
|
||||
tsKvEntry.ifPresent(entityViewLatest::add);
|
||||
}
|
||||
}
|
||||
if (!entityViewLatest.isEmpty()) {
|
||||
saveTimeseries(TimeseriesSaveRequest.builder()
|
||||
.tenantId(tenantId)
|
||||
.entityId(entityView.getId())
|
||||
.entries(entityViewLatest)
|
||||
.strategy(TimeseriesSaveRequest.Strategy.LATEST_AND_WS)
|
||||
.callback(new FutureCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable Void tmp) {}
|
||||
if (!entityViewLatest.isEmpty()) {
|
||||
saveTimeseries(TimeseriesSaveRequest.builder()
|
||||
.tenantId(tenantId)
|
||||
.entityId(entityView.getId())
|
||||
.entries(entityViewLatest)
|
||||
.strategy(TimeseriesSaveRequest.Strategy.LATEST_AND_WS)
|
||||
.callback(new FutureCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable Void tmp) {}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
log.error("[{}][{}] Failed to save entity view latest timeseries: {}", tenantId, entityView.getId(), entityViewLatest, t);
|
||||
}
|
||||
})
|
||||
.build());
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
log.error("[{}][{}] Failed to save entity view latest timeseries: {}", tenantId, entityView.getId(), entityViewLatest, t);
|
||||
}
|
||||
})
|
||||
.build());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
log.error("Error while finding entity views by tenantId and entityId", t);
|
||||
}
|
||||
}, MoreExecutors.directExecutor());
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
log.error("Error while finding entity views by tenantId and entityId", t);
|
||||
}
|
||||
}, MoreExecutors.directExecutor());
|
||||
}
|
||||
|
||||
private void onAttributesUpdate(TenantId tenantId, EntityId entityId, String scope, List<AttributeKvEntry> attributes) {
|
||||
|
||||
@ -1419,6 +1419,8 @@ device:
|
||||
host: "${DEVICE_CONNECTIVITY_COAPS_HOST:}"
|
||||
# Port of coap transport service. If empty, the default port for coaps will be used.
|
||||
port: "${DEVICE_CONNECTIVITY_COAPS_PORT:5684}"
|
||||
# Path to the COAP CA root certificate file
|
||||
pem_cert_file: "${DEVICE_CONNECTIVITY_COAPS_CA_ROOT_CERT:cafile.pem}"
|
||||
|
||||
# Edges parameters
|
||||
edges:
|
||||
|
||||
@ -231,16 +231,19 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest {
|
||||
credentials.getCredentialsId()));
|
||||
|
||||
JsonNode linuxCoapCommands = commands.get(COAP);
|
||||
assertThat(linuxCoapCommands.get(COAP).asText()).isEqualTo(String.format("coap-client -v 6 -m POST coap://localhost:5683/api/v1/%s/telemetry " +
|
||||
"-t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
|
||||
assertThat(linuxCoapCommands.get(COAPS).asText()).isEqualTo(String.format("coap-client-openssl -v 6 -m POST coaps://localhost:5684/api/v1/%s/telemetry" +
|
||||
" -t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
|
||||
assertThat(linuxCoapCommands.get(COAP).asText()).isEqualTo(String.format("coap-client -v 6 -m POST " +
|
||||
"-t \"application/json\" -e \"{temperature:25}\" coap://localhost:5683/api/v1/%s/telemetry", credentials.getCredentialsId()));
|
||||
|
||||
assertThat(linuxCoapCommands.get(COAPS).get(1).asText()).isEqualTo(String.format("coap-client-openssl -v 6 -m POST " +
|
||||
"-R " + CA_ROOT_CERT_PEM + " -t \"application/json\" -e \"{temperature:25}\" coaps://localhost:5684/api/v1/%s/telemetry", credentials.getCredentialsId()));
|
||||
|
||||
JsonNode dockerCoapCommands = commands.get(COAP).get(DOCKER);
|
||||
assertThat(dockerCoapCommands.get(COAP).asText()).isEqualTo(String.format("docker run --rm -it --add-host=host.docker.internal:host-gateway" +
|
||||
" thingsboard/coap-clients coap-client -v 6 -m POST coap://host.docker.internal:5683/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
|
||||
" thingsboard/coap-clients coap-client -v 6 -m POST -t \"application/json\" -e \"{temperature:25}\" coap://host.docker.internal:5683/api/v1/%s/telemetry", credentials.getCredentialsId()));
|
||||
assertThat(dockerCoapCommands.get(COAPS).asText()).isEqualTo(String.format("docker run --rm -it --add-host=host.docker.internal:host-gateway" +
|
||||
" thingsboard/coap-clients coap-client-openssl -v 6 -m POST coaps://host.docker.internal:5684/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
|
||||
" thingsboard/coap-clients " +
|
||||
"/bin/sh -c \"curl -f -S -o " + CA_ROOT_CERT_PEM + " http://localhost:80/api/device-connectivity/coaps/certificate/download && " +
|
||||
"coap-client-openssl -v 6 -m POST -R " + CA_ROOT_CERT_PEM + " -t \"application/json\" -e \"{temperature:25}\" coaps://host.docker.internal:5684/api/v1/%s/telemetry\"", credentials.getCredentialsId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -376,16 +379,19 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest {
|
||||
credentials.getCredentialsId()));
|
||||
|
||||
JsonNode linuxCoapCommands = commands.get(COAP);
|
||||
assertThat(linuxCoapCommands.get(COAP).asText()).isEqualTo(String.format("coap-client -v 6 -m POST coap://[::1]:5683/api/v1/%s/telemetry " +
|
||||
"-t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
|
||||
assertThat(linuxCoapCommands.get(COAPS).asText()).isEqualTo(String.format("coap-client-openssl -v 6 -m POST coaps://[::1]:5684/api/v1/%s/telemetry" +
|
||||
" -t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
|
||||
assertThat(linuxCoapCommands.get(COAP).asText()).isEqualTo(String.format("coap-client -v 6 -m POST " +
|
||||
"-t \"application/json\" -e \"{temperature:25}\" coap://[::1]:5683/api/v1/%s/telemetry", credentials.getCredentialsId()));
|
||||
assertThat(linuxCoapCommands.get(COAPS).get(0).asText()).isEqualTo("curl -f -S -o " + CA_ROOT_CERT_PEM + " http://localhost:80/api/device-connectivity/coaps/certificate/download");
|
||||
assertThat(linuxCoapCommands.get(COAPS).get(1).asText()).isEqualTo(String.format("coap-client-openssl -v 6 -m POST " +
|
||||
"-R " + CA_ROOT_CERT_PEM + " -t \"application/json\" -e \"{temperature:25}\" coaps://[::1]:5684/api/v1/%s/telemetry", credentials.getCredentialsId()));
|
||||
|
||||
JsonNode dockerCoapCommands = commands.get(COAP).get(DOCKER);
|
||||
assertThat(dockerCoapCommands.get(COAP).asText()).isEqualTo(String.format("docker run --rm -it --add-host=host.docker.internal:host-gateway" +
|
||||
" thingsboard/coap-clients coap-client -v 6 -m POST coap://host.docker.internal:5683/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
|
||||
" thingsboard/coap-clients coap-client -v 6 -m POST -t \"application/json\" -e \"{temperature:25}\" coap://host.docker.internal:5683/api/v1/%s/telemetry", credentials.getCredentialsId()));
|
||||
assertThat(dockerCoapCommands.get(COAPS).asText()).isEqualTo(String.format("docker run --rm -it --add-host=host.docker.internal:host-gateway" +
|
||||
" thingsboard/coap-clients coap-client-openssl -v 6 -m POST coaps://host.docker.internal:5684/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
|
||||
" thingsboard/coap-clients " +
|
||||
"/bin/sh -c \"curl -f -S -o " + CA_ROOT_CERT_PEM + " http://localhost:80/api/device-connectivity/coaps/certificate/download && " +
|
||||
"coap-client-openssl -v 6 -m POST -R " + CA_ROOT_CERT_PEM + " -t \"application/json\" -e \"{temperature:25}\" coaps://host.docker.internal:5684/api/v1/%s/telemetry\"", credentials.getCredentialsId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -430,16 +436,19 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest {
|
||||
credentials.getCredentialsId()));
|
||||
|
||||
JsonNode linuxCoapCommands = commands.get(COAP);
|
||||
assertThat(linuxCoapCommands.get(COAP).asText()).isEqualTo(String.format("coap-client -v 6 -m POST coap://[1:1:1:1:1:1:1:1]:5683/api/v1/%s/telemetry " +
|
||||
"-t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
|
||||
assertThat(linuxCoapCommands.get(COAPS).asText()).isEqualTo(String.format("coap-client-openssl -v 6 -m POST coaps://[1:1:1:1:1:1:1:1]:5684/api/v1/%s/telemetry" +
|
||||
" -t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
|
||||
assertThat(linuxCoapCommands.get(COAP).asText()).isEqualTo(String.format("coap-client -v 6 -m POST " +
|
||||
"-t \"application/json\" -e \"{temperature:25}\" coap://[1:1:1:1:1:1:1:1]:5683/api/v1/%s/telemetry", credentials.getCredentialsId()));
|
||||
assertThat(linuxCoapCommands.get(COAPS).get(0).asText()).isEqualTo("curl -f -S -o " + CA_ROOT_CERT_PEM + " http://localhost:80/api/device-connectivity/coaps/certificate/download");
|
||||
assertThat(linuxCoapCommands.get(COAPS).get(1).asText()).isEqualTo(String.format("coap-client-openssl -v 6 -m POST -R " + CA_ROOT_CERT_PEM +
|
||||
" -t \"application/json\" -e \"{temperature:25}\" coaps://[1:1:1:1:1:1:1:1]:5684/api/v1/%s/telemetry", credentials.getCredentialsId()));
|
||||
|
||||
JsonNode dockerCoapCommands = commands.get(COAP).get(DOCKER);
|
||||
assertThat(dockerCoapCommands.get(COAP).asText()).isEqualTo(String.format("docker run --rm -it" +
|
||||
" thingsboard/coap-clients coap-client -v 6 -m POST coap://[1:1:1:1:1:1:1:1]:5683/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
|
||||
" thingsboard/coap-clients coap-client -v 6 -m POST -t \"application/json\" -e \"{temperature:25}\" coap://[1:1:1:1:1:1:1:1]:5683/api/v1/%s/telemetry", credentials.getCredentialsId()));
|
||||
assertThat(dockerCoapCommands.get(COAPS).asText()).isEqualTo(String.format("docker run --rm -it" +
|
||||
" thingsboard/coap-clients coap-client-openssl -v 6 -m POST coaps://[1:1:1:1:1:1:1:1]:5684/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
|
||||
" thingsboard/coap-clients " +
|
||||
"/bin/sh -c \"curl -f -S -o " + CA_ROOT_CERT_PEM + " http://localhost:80/api/device-connectivity/coaps/certificate/download && " +
|
||||
"coap-client-openssl -v 6 -m POST -R " + CA_ROOT_CERT_PEM + " -t \"application/json\" -e \"{temperature:25}\" coaps://[1:1:1:1:1:1:1:1]:5684/api/v1/%s/telemetry\"", credentials.getCredentialsId()));
|
||||
|
||||
}
|
||||
|
||||
@ -552,9 +561,10 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest {
|
||||
assertThat(commands).hasSize(1);
|
||||
|
||||
JsonNode linuxCommands = commands.get(COAP);
|
||||
assertThat(linuxCommands.get(COAP).asText()).isEqualTo(String.format("coap-client -v 6 -m POST coap://localhost:5683/api/v1/%s/telemetry -t json -e \"{temperature:25}\"",
|
||||
assertThat(linuxCommands.get(COAP).asText()).isEqualTo(String.format("coap-client -v 6 -m POST -t \"application/json\" -e \"{temperature:25}\" coap://localhost:5683/api/v1/%s/telemetry",
|
||||
credentials.getCredentialsId()));
|
||||
assertThat(linuxCommands.get(COAPS).asText()).isEqualTo(String.format("coap-client-openssl -v 6 -m POST coaps://localhost:5684/api/v1/%s/telemetry -t json -e \"{temperature:25}\"",
|
||||
assertThat(linuxCommands.get(COAPS).get(0).asText()).isEqualTo("curl -f -S -o " + CA_ROOT_CERT_PEM + " http://localhost:80/api/device-connectivity/coaps/certificate/download");
|
||||
assertThat(linuxCommands.get(COAPS).get(1).asText()).isEqualTo(String.format("coap-client-openssl -v 6 -m POST -R " + CA_ROOT_CERT_PEM + " -t \"application/json\" -e \"{temperature:25}\" coaps://localhost:5684/api/v1/%s/telemetry",
|
||||
credentials.getCredentialsId()));
|
||||
}
|
||||
|
||||
@ -772,16 +782,18 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest {
|
||||
"mosquitto_pub -d -q 1 --cafile " + CA_ROOT_CERT_PEM + " -h host.docker.internal -t v1/devices/me/telemetry -u \"%s\" -m \"{temperature:25}\"\"", credentials.getCredentialsId()));
|
||||
|
||||
JsonNode linuxCoapCommands = commands.get(COAP);
|
||||
assertThat(linuxCoapCommands.get(COAP).asText()).isEqualTo(String.format("coap-client -v 6 -m POST coap://localhost/api/v1/%s/telemetry " +
|
||||
"-t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
|
||||
assertThat(linuxCoapCommands.get(COAPS).asText()).isEqualTo(String.format("coap-client-openssl -v 6 -m POST coaps://localhost/api/v1/%s/telemetry" +
|
||||
" -t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
|
||||
assertThat(linuxCoapCommands.get(COAP).asText()).isEqualTo(String.format("coap-client -v 6 -m POST " +
|
||||
"-t \"application/json\" -e \"{temperature:25}\" coap://localhost/api/v1/%s/telemetry", credentials.getCredentialsId()));
|
||||
assertThat(linuxCoapCommands.get(COAPS).get(0).asText()).isEqualTo("curl -f -S -o " + CA_ROOT_CERT_PEM + " http://localhost:80/api/device-connectivity/coaps/certificate/download");
|
||||
assertThat(linuxCoapCommands.get(COAPS).get(1).asText()).isEqualTo(String.format("coap-client-openssl -v 6 -m POST " +
|
||||
"-R " + CA_ROOT_CERT_PEM + " -t \"application/json\" -e \"{temperature:25}\" coaps://localhost/api/v1/%s/telemetry", credentials.getCredentialsId()));
|
||||
|
||||
JsonNode dockerCoapCommands = commands.get(COAP).get(DOCKER);
|
||||
assertThat(dockerCoapCommands.get(COAP).asText()).isEqualTo(String.format("docker run --rm -it --add-host=host.docker.internal:host-gateway" +
|
||||
" thingsboard/coap-clients coap-client -v 6 -m POST coap://host.docker.internal/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
|
||||
" thingsboard/coap-clients coap-client -v 6 -m POST -t \"application/json\" -e \"{temperature:25}\" coap://host.docker.internal/api/v1/%s/telemetry", credentials.getCredentialsId()));
|
||||
assertThat(dockerCoapCommands.get(COAPS).asText()).isEqualTo(String.format("docker run --rm -it --add-host=host.docker.internal:host-gateway" +
|
||||
" thingsboard/coap-clients coap-client-openssl -v 6 -m POST coaps://host.docker.internal/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
|
||||
" thingsboard/coap-clients /bin/sh -c \"curl -f -S -o " + CA_ROOT_CERT_PEM + " http://localhost:80/api/device-connectivity/coaps/certificate/download && " +
|
||||
"coap-client-openssl -v 6 -m POST -R " + CA_ROOT_CERT_PEM + " -t \"application/json\" -e \"{temperature:25}\" coaps://host.docker.internal/api/v1/%s/telemetry\"", credentials.getCredentialsId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -831,16 +843,18 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest {
|
||||
credentials.getCredentialsId()));
|
||||
|
||||
JsonNode linuxCoapCommands = commands.get(COAP);
|
||||
assertThat(linuxCoapCommands.get(COAP).asText()).isEqualTo(String.format("coap-client -v 6 -m POST coap://test.domain:5683/api/v1/%s/telemetry " +
|
||||
"-t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
|
||||
assertThat(linuxCoapCommands.get(COAPS).asText()).isEqualTo(String.format("coap-client-openssl -v 6 -m POST coaps://test.domain:5684/api/v1/%s/telemetry" +
|
||||
" -t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
|
||||
assertThat(linuxCoapCommands.get(COAP).asText()).isEqualTo(String.format("coap-client -v 6 -m POST " +
|
||||
"-t \"application/json\" -e \"{temperature:25}\" coap://test.domain:5683/api/v1/%s/telemetry", credentials.getCredentialsId()));
|
||||
assertThat(linuxCoapCommands.get(COAPS).get(0).asText()).isEqualTo("curl -f -S -o " + CA_ROOT_CERT_PEM + " http://localhost:80/api/device-connectivity/coaps/certificate/download");
|
||||
assertThat(linuxCoapCommands.get(COAPS).get(1).asText()).isEqualTo(String.format("coap-client-openssl -v 6 -m POST " +
|
||||
"-R "+ CA_ROOT_CERT_PEM + " -t \"application/json\" -e \"{temperature:25}\" coaps://test.domain:5684/api/v1/%s/telemetry", credentials.getCredentialsId()));
|
||||
|
||||
JsonNode dockerCoapCommands = commands.get(COAP).get(DOCKER);
|
||||
assertThat(dockerCoapCommands.get(COAP).asText()).isEqualTo(String.format("docker run --rm -it " +
|
||||
"thingsboard/coap-clients coap-client -v 6 -m POST coap://test.domain:5683/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
|
||||
"thingsboard/coap-clients coap-client -v 6 -m POST -t \"application/json\" -e \"{temperature:25}\" coap://test.domain:5683/api/v1/%s/telemetry", credentials.getCredentialsId()));
|
||||
assertThat(dockerCoapCommands.get(COAPS).asText()).isEqualTo(String.format("docker run --rm -it " +
|
||||
"thingsboard/coap-clients coap-client-openssl -v 6 -m POST coaps://test.domain:5684/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
|
||||
"thingsboard/coap-clients /bin/sh -c \"curl -f -S -o " + CA_ROOT_CERT_PEM + " http://localhost:80/api/device-connectivity/coaps/certificate/download && " +
|
||||
"coap-client-openssl -v 6 -m POST -R " + CA_ROOT_CERT_PEM + " -t \"application/json\" -e \"{temperature:25}\" coaps://test.domain:5684/api/v1/%s/telemetry\"", credentials.getCredentialsId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -917,12 +931,17 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest {
|
||||
assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run --rm -it --add-host=host.docker.internal:host-gateway thingsboard/mosquitto-clients /bin/sh -c \"curl -f -S -o " + CA_ROOT_CERT_PEM + " http://localhost:80/api/device-connectivity/mqtts/certificate/download && mosquitto_pub -d -q 1 --cafile " + CA_ROOT_CERT_PEM + " -h host.docker.internal -t v1/devices/me/telemetry -u \"%s\" -m \"{temperature:25}\"\"", credentials.getCredentialsId()));
|
||||
|
||||
JsonNode coapCommands = commands.get(COAP);
|
||||
assertThat(coapCommands.get(COAP).asText()).isEqualTo(String.format("coap-client -v 6 -m POST coap://localhost/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
|
||||
assertThat(coapCommands.get(COAPS).asText()).isEqualTo(String.format("coap-client-openssl -v 6 -m POST coaps://localhost/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
|
||||
assertThat(coapCommands.get(COAP).asText()).isEqualTo(String.format("coap-client -v 6 -m POST -t \"application/json\" -e \"{temperature:25}\" coap://localhost/api/v1/%s/telemetry", credentials.getCredentialsId()));
|
||||
assertThat(coapCommands.get(COAPS).get(0).asText()).isEqualTo("curl -f -S -o " + CA_ROOT_CERT_PEM + " http://localhost:80/api/device-connectivity/coaps/certificate/download");
|
||||
assertThat(coapCommands.get(COAPS).get(1).asText()).isEqualTo(String.format("coap-client-openssl -v 6 -m POST " +
|
||||
"-R " + CA_ROOT_CERT_PEM + " -t \"application/json\" -e \"{temperature:25}\" coaps://localhost/api/v1/%s/telemetry", credentials.getCredentialsId()));
|
||||
|
||||
JsonNode dockerCoapCommands = coapCommands.get(DOCKER);
|
||||
assertThat(dockerCoapCommands.get(COAP).asText()).isEqualTo(String.format("docker run --rm -it --add-host=host.docker.internal:host-gateway thingsboard/coap-clients coap-client -v 6 -m POST coap://host.docker.internal/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
|
||||
assertThat(dockerCoapCommands.get(COAPS).asText()).isEqualTo(String.format("docker run --rm -it --add-host=host.docker.internal:host-gateway thingsboard/coap-clients coap-client-openssl -v 6 -m POST coaps://host.docker.internal/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", credentials.getCredentialsId()));
|
||||
assertThat(dockerCoapCommands.get(COAP).asText()).isEqualTo(String.format("docker run --rm -it --add-host=host.docker.internal:host-gateway " +
|
||||
"thingsboard/coap-clients coap-client -v 6 -m POST -t \"application/json\" -e \"{temperature:25}\" coap://host.docker.internal/api/v1/%s/telemetry", credentials.getCredentialsId()));
|
||||
assertThat(dockerCoapCommands.get(COAPS).asText()).isEqualTo(String.format("docker run --rm -it --add-host=host.docker.internal:host-gateway " +
|
||||
"thingsboard/coap-clients /bin/sh -c \"curl -f -S -o " + CA_ROOT_CERT_PEM + " http://localhost:80/api/device-connectivity/coaps/certificate/download && " +
|
||||
"coap-client-openssl -v 6 -m POST -R " + CA_ROOT_CERT_PEM + " -t \"application/json\" -e \"{temperature:25}\" coaps://host.docker.internal/api/v1/%s/telemetry\"", credentials.getCredentialsId()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,130 @@
|
||||
/**
|
||||
* Copyright © 2016-2025 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.server.controller;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.thingsboard.common.util.JacksonUtil;
|
||||
import org.thingsboard.server.common.data.AttributeScope;
|
||||
import org.thingsboard.server.common.data.Device;
|
||||
import org.thingsboard.server.common.data.edqs.EdqsSyncRequest;
|
||||
import org.thingsboard.server.common.data.edqs.ToCoreEdqsRequest;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
|
||||
import org.thingsboard.server.common.data.page.PageData;
|
||||
import org.thingsboard.server.common.data.query.DeviceTypeFilter;
|
||||
import org.thingsboard.server.common.data.query.EntityData;
|
||||
import org.thingsboard.server.common.data.query.EntityDataPageLink;
|
||||
import org.thingsboard.server.common.data.query.EntityDataQuery;
|
||||
import org.thingsboard.server.common.data.query.EntityKey;
|
||||
import org.thingsboard.server.common.data.query.EntityKeyType;
|
||||
import org.thingsboard.server.common.data.query.EntityKeyValueType;
|
||||
import org.thingsboard.server.common.data.query.FilterPredicateValue;
|
||||
import org.thingsboard.server.common.data.query.KeyFilter;
|
||||
import org.thingsboard.server.common.data.query.StringFilterPredicate;
|
||||
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
|
||||
@DaoSqlTest
|
||||
@TestPropertySource(properties = {
|
||||
"queue.edqs.sync.enabled=true",
|
||||
"queue.edqs.api.supported=true",
|
||||
"queue.edqs.api.auto_enable=true",
|
||||
"queue.edqs.mode=local"
|
||||
})
|
||||
public class EdqsControllerTest extends AbstractControllerTest {
|
||||
|
||||
@Autowired
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
|
||||
@Before
|
||||
public void beforeEdqsControllerTest() throws Exception {
|
||||
loginTenantAdmin();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEdqsSync() throws Exception {
|
||||
List<Device> devices = new ArrayList<>();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
Device device = new Device();
|
||||
device.setName("Device" + i);
|
||||
device.setType("default");
|
||||
device.setLabel("testLabel" + (int) (Math.random() * 1000));
|
||||
ObjectNode additionalInfo = JacksonUtil.newObjectNode();
|
||||
additionalInfo.put("gateway", true);
|
||||
device.setAdditionalInfo(additionalInfo);
|
||||
devices.add(doPost("/api/device", device, Device.class));
|
||||
Thread.sleep(1);
|
||||
}
|
||||
|
||||
DeviceTypeFilter filter = new DeviceTypeFilter();
|
||||
filter.setDeviceTypes(List.of("default"));
|
||||
filter.setDeviceNameFilter("");
|
||||
|
||||
List<EntityKey> entityFields = Collections.singletonList(new EntityKey(EntityKeyType.ENTITY_FIELD, "name"));
|
||||
|
||||
EntityDataPageLink pageLink = new EntityDataPageLink(10, 0, null, null);
|
||||
EntityDataQuery query = new EntityDataQuery(filter, pageLink, entityFields, null, Collections.singletonList(getGatewayFilter()));
|
||||
await().atMost(TIMEOUT, TimeUnit.SECONDS)
|
||||
.until(() -> doPostWithTypedResponse("/api/entitiesQuery/find", query, new TypeReference<PageData<EntityData>>() {
|
||||
}), result -> result.getTotalElements() == 3);
|
||||
|
||||
// update db
|
||||
Device device1 = devices.get(0);
|
||||
device1.setAdditionalInfo(JacksonUtil.newObjectNode());
|
||||
jdbcTemplate.execute("update device set additional_info = '{}' where id = '" + device1.getId().getId().toString() + "'");
|
||||
|
||||
// do edqs sync
|
||||
loginSysAdmin();
|
||||
ToCoreEdqsRequest syncRequest = new ToCoreEdqsRequest(new EdqsSyncRequest(), null);
|
||||
doPost("/api/edqs/system/request", syncRequest);
|
||||
|
||||
//check sync is finished
|
||||
await().atMost(TIMEOUT, TimeUnit.SECONDS).until(() -> {
|
||||
Optional<AttributeKvEntry> attribute = attributesService.find(TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID, AttributeScope.SERVER_SCOPE, "edqsSyncState").get();
|
||||
return attribute.isPresent() && attribute.get().getJsonValue().isPresent() &&
|
||||
attribute.get().getJsonValue().get().contains("\"status\":\"FINISHED\"");
|
||||
});
|
||||
|
||||
// check if the count is updated
|
||||
loginTenantAdmin();
|
||||
await().atMost(TIMEOUT, TimeUnit.SECONDS).until(() -> doPostWithTypedResponse("/api/entitiesQuery/find", query, new TypeReference<PageData<EntityData>>() {
|
||||
}), result -> result.getTotalElements() == 2);
|
||||
}
|
||||
|
||||
private KeyFilter getGatewayFilter() {
|
||||
KeyFilter additionalInfoFilter = new KeyFilter();
|
||||
additionalInfoFilter.setKey(new EntityKey(EntityKeyType.ENTITY_FIELD, "additionalInfo"));
|
||||
additionalInfoFilter.setValueType(EntityKeyValueType.STRING);
|
||||
StringFilterPredicate predicate = new StringFilterPredicate();
|
||||
predicate.setValue(FilterPredicateValue.fromString("\"gateway\":true"));
|
||||
predicate.setOperation(StringFilterPredicate.StringOperation.CONTAINS);
|
||||
additionalInfoFilter.setPredicate(predicate);
|
||||
return additionalInfoFilter;
|
||||
}
|
||||
}
|
||||
@ -359,6 +359,45 @@ class DefaultTelemetrySubscriptionServiceTest {
|
||||
then(subscriptionManagerService).shouldHaveNoInteractions();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotCopyLatestToEntityViewWhenTimeseriesSaveFailedOnMainEntity() {
|
||||
// GIVEN
|
||||
var entityView = new EntityView(new EntityViewId(UUID.randomUUID()));
|
||||
entityView.setTenantId(tenantId);
|
||||
entityView.setCustomerId(customerId);
|
||||
entityView.setEntityId(entityId);
|
||||
entityView.setKeys(new TelemetryEntityView(sampleTimeseries.stream().map(KvEntry::getKey).toList(), new AttributesEntityView()));
|
||||
|
||||
// mock that there is one entity view
|
||||
lenient().when(tbEntityViewService.findEntityViewsByTenantIdAndEntityIdAsync(tenantId, entityId)).thenReturn(immediateFuture(List.of(entityView)));
|
||||
// mock that save latest call for entity view is successful
|
||||
lenient().when(tsService.saveLatest(tenantId, entityView.getId(), sampleTimeseries)).thenReturn(immediateFuture(TimeseriesSaveResult.of(sampleTimeseries.size(), listOfNNumbers(sampleTimeseries.size()))));
|
||||
// mock TPI for entity view
|
||||
lenient().when(partitionService.resolve(ServiceType.TB_CORE, tenantId, entityView.getId())).thenReturn(tpi);
|
||||
|
||||
var request = TimeseriesSaveRequest.builder()
|
||||
.tenantId(tenantId)
|
||||
.customerId(customerId)
|
||||
.entityId(entityId)
|
||||
.entries(sampleTimeseries)
|
||||
.ttl(sampleTtl)
|
||||
.strategy(new TimeseriesSaveRequest.Strategy(true, true, false, false))
|
||||
.build();
|
||||
|
||||
given(tsService.save(tenantId, entityId, sampleTimeseries, sampleTtl)).willReturn(immediateFailedFuture(new RuntimeException("failed to save data on main entity")));
|
||||
|
||||
// WHEN
|
||||
telemetryService.saveTimeseries(request);
|
||||
|
||||
// THEN
|
||||
// should save only time series for the main entity
|
||||
then(tsService).should().save(tenantId, entityId, sampleTimeseries, sampleTtl);
|
||||
then(tsService).shouldHaveNoMoreInteractions();
|
||||
|
||||
// should not send any WS updates
|
||||
then(subscriptionManagerService).shouldHaveNoInteractions();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("allCombinationsOfFourBooleans")
|
||||
void shouldCallCorrectSaveTimeseriesApiBasedOnBooleanFlagsInTheSaveRequest(boolean saveTimeseries, boolean saveLatest, boolean sendWsUpdate, boolean processCalculatedFields) {
|
||||
|
||||
@ -97,4 +97,5 @@ public enum EntityType {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -35,12 +35,12 @@ public class ApiUsageStateData extends BaseEntityData<ApiUsageStateFields> {
|
||||
|
||||
@Override
|
||||
public String getEntityName() {
|
||||
return getEntityOwnerName();
|
||||
return getOwnerName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntityOwnerName() {
|
||||
return repo.getOwnerName(fields.getEntityId());
|
||||
public String getOwnerName() {
|
||||
return repo.getOwnerEntityName(fields.getEntityId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -98,8 +98,13 @@ public abstract class BaseEntityData<T extends EntityFields> implements EntityDa
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityType getOwnerType() {
|
||||
return customerId != null ? EntityType.CUSTOMER : EntityType.TENANT;
|
||||
public String getOwnerName() {
|
||||
return repo.getOwnerEntityName(isTenantEntity() ? repo.getTenantId() : new CustomerId(getCustomerId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOwnerType() {
|
||||
return isTenantEntity() ? EntityType.TENANT.name() : EntityType.CUSTOMER.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -132,22 +137,21 @@ public abstract class BaseEntityData<T extends EntityFields> implements EntityDa
|
||||
}
|
||||
return switch (name) {
|
||||
case "name" -> getEntityName();
|
||||
case "ownerName" -> getEntityOwnerName();
|
||||
case "ownerType" -> customerId != null ? EntityType.CUSTOMER.name() : EntityType.TENANT.name();
|
||||
case "ownerName" -> getOwnerName();
|
||||
case "ownerType" -> getOwnerType();
|
||||
case "entityType" -> Optional.ofNullable(getEntityType()).map(EntityType::name).orElse("");
|
||||
default -> fields.getAsString(name);
|
||||
};
|
||||
}
|
||||
|
||||
public String getEntityOwnerName() {
|
||||
return repo.getOwnerName(getCustomerId() == null || CustomerId.NULL_UUID.equals(getCustomerId()) ? null :
|
||||
new CustomerId(getCustomerId()));
|
||||
}
|
||||
|
||||
public String getEntityName() {
|
||||
return getFields().getName();
|
||||
}
|
||||
|
||||
private boolean isTenantEntity() {
|
||||
return getCustomerId() == null || CustomerId.NULL_UUID.equals(getCustomerId());
|
||||
}
|
||||
|
||||
private String getRelatedParentId(QueryContext ctx) {
|
||||
return Optional.ofNullable(ctx.getRelatedParentIdMap().get(getId()))
|
||||
.map(UUID::toString)
|
||||
|
||||
@ -54,7 +54,9 @@ public interface EntityData<T extends EntityFields> {
|
||||
|
||||
boolean removeTs(Integer keyId);
|
||||
|
||||
EntityType getOwnerType();
|
||||
String getOwnerName();
|
||||
|
||||
String getOwnerType();
|
||||
|
||||
DataPoint getDataPoint(DataKey key, QueryContext queryContext);
|
||||
|
||||
|
||||
@ -421,14 +421,7 @@ public class TenantRepo {
|
||||
return relations.computeIfAbsent(relationTypeGroup, type -> new RelationsRepo());
|
||||
}
|
||||
|
||||
public String getOwnerName(EntityId ownerId) {
|
||||
if (ownerId == null || (ownerId.getEntityType() == EntityType.CUSTOMER && ownerId.isNullUid())) {
|
||||
return getOwnerEntityName(tenantId);
|
||||
}
|
||||
return getOwnerEntityName(ownerId);
|
||||
}
|
||||
|
||||
private String getOwnerEntityName(EntityId entityId) {
|
||||
public String getOwnerEntityName(EntityId entityId) {
|
||||
EntityType entityType = entityId.getEntityType();
|
||||
return switch (entityType) {
|
||||
case CUSTOMER, TENANT -> {
|
||||
|
||||
@ -67,10 +67,10 @@ import static org.thingsboard.server.common.data.query.ComplexFilterPredicate.Co
|
||||
@Slf4j
|
||||
public class RepositoryUtils {
|
||||
|
||||
public static final Comparator<SortableEntityData> SORT_ASC = Comparator.comparing((SortableEntityData sed) -> Optional.ofNullable(sed.getSortValue()).orElse(""))
|
||||
public static final Comparator<SortableEntityData> SORT_ASC = Comparator.comparing((SortableEntityData sed) -> Optional.ofNullable(sed.getSortValue()).orElse(""), String.CASE_INSENSITIVE_ORDER)
|
||||
.thenComparing(sp -> sp.getId().toString());
|
||||
|
||||
public static final Comparator<SortableEntityData> SORT_DESC = Comparator.comparing((SortableEntityData sed) -> Optional.ofNullable(sed.getSortValue()).orElse(""))
|
||||
public static final Comparator<SortableEntityData> SORT_DESC = Comparator.comparing((SortableEntityData sed) -> Optional.ofNullable(sed.getSortValue()).orElse(""), String.CASE_INSENSITIVE_ORDER)
|
||||
.thenComparing(sp -> sp.getId().toString()).reversed();
|
||||
|
||||
public static EntityType resolveEntityType(EntityFilter entityFilter) {
|
||||
|
||||
@ -26,19 +26,17 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
public class VersionsStore {
|
||||
|
||||
private final Cache<String, Long> versions = Caffeine.newBuilder()
|
||||
.expireAfterWrite(1, TimeUnit.HOURS)
|
||||
.expireAfterWrite(24, TimeUnit.HOURS)
|
||||
.build();
|
||||
|
||||
public boolean isNew(String key, Long version) {
|
||||
AtomicBoolean isNew = new AtomicBoolean(false);
|
||||
versions.asMap().compute(key, (k, prevVersion) -> {
|
||||
if (prevVersion == null || prevVersion < version) {
|
||||
if (prevVersion == null || prevVersion <= version) {
|
||||
isNew.set(true);
|
||||
return version;
|
||||
} else {
|
||||
if (version < prevVersion) {
|
||||
log.info("[{}] Version {} is outdated, the latest is {}", key, version, prevVersion);
|
||||
}
|
||||
log.info("[{}] Version {} is outdated, the latest is {}", key, version, prevVersion);
|
||||
return prevVersion;
|
||||
}
|
||||
});
|
||||
|
||||
@ -41,6 +41,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentialsType;
|
||||
import org.thingsboard.server.dao.settings.AdminSettingsService;
|
||||
import org.thingsboard.server.dao.util.DeviceConnectivityUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URISyntaxException;
|
||||
@ -83,6 +84,8 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService
|
||||
|
||||
@Value("${device.connectivity.mqtts.pem_cert_file:}")
|
||||
private String mqttsPemCertFile;
|
||||
@Value("${device.connectivity.coaps.pem_cert_file:}")
|
||||
private String coapsPemCertFile;
|
||||
|
||||
@Override
|
||||
public JsonNode findDevicePublishTelemetryCommands(String baseUrl, Device device) throws URISyntaxException {
|
||||
@ -133,22 +136,19 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService
|
||||
public Resource getPemCertFile(String protocol) {
|
||||
return certs.computeIfAbsent(protocol, key -> {
|
||||
DeviceConnectivityInfo connectivity = getConnectivity(protocol);
|
||||
if (!MQTTS.equals(protocol) || connectivity == null) {
|
||||
if (connectivity == null) {
|
||||
log.warn("Unknown connectivity protocol: {}", protocol);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(mqttsPemCertFile) && ResourceUtils.resourceExists(this, mqttsPemCertFile)) {
|
||||
try {
|
||||
return getCert(mqttsPemCertFile);
|
||||
} catch (Exception e) {
|
||||
String msg = String.format("Failed to read %s server certificate!", protocol);
|
||||
log.warn(msg);
|
||||
throw new RuntimeException(msg, e);
|
||||
return switch (protocol) {
|
||||
case COAPS -> getCert(coapsPemCertFile);
|
||||
case MQTTS -> getCert(mqttsPemCertFile);
|
||||
default -> {
|
||||
log.warn("Unsupported secure protocol: {}", protocol);
|
||||
yield null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@ -174,7 +174,11 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService
|
||||
return info != null && info.isEnabled();
|
||||
}
|
||||
|
||||
private Resource getCert(String path) throws Exception {
|
||||
private Resource getCert(String path) {
|
||||
if (StringUtils.isBlank(path) || !ResourceUtils.resourceExists(this, path)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
StringBuilder pemContentBuilder = new StringBuilder();
|
||||
|
||||
try (InputStream inStream = ResourceUtils.getInputStream(this, path);
|
||||
@ -197,6 +201,10 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService
|
||||
pemContentBuilder.append("-----END CERTIFICATE-----\n");
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
String msg = String.format("Failed to read %s server certificate!", path);
|
||||
log.warn(msg);
|
||||
throw new RuntimeException(msg, e);
|
||||
}
|
||||
|
||||
return new ByteArrayResource(pemContentBuilder.toString().getBytes(StandardCharsets.UTF_8));
|
||||
@ -311,8 +319,11 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService
|
||||
}
|
||||
|
||||
if (isEnabled(COAPS)) {
|
||||
ArrayNode coapsCommands = coapCommands.putArray(COAPS);
|
||||
Optional.ofNullable(DeviceConnectivityUtil.getCurlPemCertCommand(baseUrl, COAPS))
|
||||
.ifPresent(coapsCommands::add);
|
||||
Optional.ofNullable(getCoapPublishCommand(COAPS, baseUrl, deviceCredentials))
|
||||
.ifPresent(v -> coapCommands.put(COAPS, v));
|
||||
.ifPresent(coapsCommands::add);
|
||||
|
||||
Optional.ofNullable(getDockerCoapPublishCommand(COAPS, baseUrl, deviceCredentials))
|
||||
.ifPresent(v -> dockerCoapCommands.put(COAPS, v));
|
||||
@ -336,7 +347,7 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService
|
||||
DeviceConnectivityInfo properties = getConnectivity(protocol);
|
||||
String host = getHost(baseUrl, properties, protocol);
|
||||
String port = StringUtils.isBlank(properties.getPort()) ? "" : ":" + properties.getPort();
|
||||
return DeviceConnectivityUtil.getDockerCoapPublishCommand(protocol, host, port, deviceCredentials);
|
||||
return DeviceConnectivityUtil.getDockerCoapPublishCommand(protocol, baseUrl, host, port, deviceCredentials);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -199,19 +199,39 @@ public class DeviceConnectivityUtil {
|
||||
switch (deviceCredentials.getCredentialsType()) {
|
||||
case ACCESS_TOKEN:
|
||||
String client = COAPS.equals(protocol) ? "coap-client-openssl" : "coap-client";
|
||||
return String.format("%s -v 6 -m POST %s://%s%s/api/v1/%s/telemetry -t json -e %s",
|
||||
client, protocol, host, port, deviceCredentials.getCredentialsId(), JSON_EXAMPLE_PAYLOAD);
|
||||
String certificate = COAPS.equals(protocol) ? " -R " + CA_ROOT_CERT_PEM : "";
|
||||
return String.format("%s -v 6 -m POST%s -t \"application/json\" -e %s %s://%s%s/api/v1/%s/telemetry",
|
||||
client, certificate, JSON_EXAMPLE_PAYLOAD, protocol, host, port, deviceCredentials.getCredentialsId());
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getDockerCoapPublishCommand(String protocol, String host, String port, DeviceCredentials deviceCredentials) {
|
||||
public static String getDockerCoapPublishCommand(String protocol, String baseUrl, String host, String port, DeviceCredentials deviceCredentials) {
|
||||
String coapCommand = getCoapPublishCommand(protocol, host, port, deviceCredentials);
|
||||
if (coapCommand != null && isLocalhost(host)) {
|
||||
|
||||
if (coapCommand == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
StringBuilder coapDockerCommand = new StringBuilder();
|
||||
coapDockerCommand.append(DOCKER_RUN).append(isLocalhost(host) ? ADD_DOCKER_INTERNAL_HOST : "").append(COAP_IMAGE);
|
||||
|
||||
if (isLocalhost(host)) {
|
||||
coapCommand = coapCommand.replace(host, HOST_DOCKER_INTERNAL);
|
||||
}
|
||||
return coapCommand != null ? String.format("%s%s%s", DOCKER_RUN + (isLocalhost(host) ? ADD_DOCKER_INTERNAL_HOST : ""), COAP_IMAGE, coapCommand) : null;
|
||||
|
||||
if (COAPS.equals(protocol)) {
|
||||
coapDockerCommand.append("/bin/sh -c \"")
|
||||
.append(getCurlPemCertCommand(baseUrl, protocol))
|
||||
.append(" && ")
|
||||
.append(coapCommand)
|
||||
.append("\"");
|
||||
} else {
|
||||
coapDockerCommand.append(coapCommand);
|
||||
}
|
||||
|
||||
return coapDockerCommand.toString();
|
||||
}
|
||||
|
||||
public static String getHost(String baseUrl, DeviceConnectivityInfo properties, String protocol) throws URISyntaxException {
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
<pkg.disabled>false</pkg.disabled>
|
||||
<pkg.process-resources.phase>process-resources</pkg.process-resources.phase>
|
||||
<pkg.package.phase>package</pkg.package.phase>
|
||||
<pkg.name>edqs</pkg.name>
|
||||
<pkg.name>tb-edqs</pkg.name>
|
||||
<pkg.win.dist>${project.build.directory}/windows</pkg.win.dist>
|
||||
<pkg.copyInstallScripts>true</pkg.copyInstallScripts>
|
||||
<pkg.implementationTitle>ThingsBoard Entity Data Query Service</pkg.implementationTitle>
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<main.dir>${basedir}/../..</main.dir>
|
||||
<pkg.name>edqs</pkg.name>
|
||||
<pkg.name>tb-edqs</pkg.name>
|
||||
<docker.name>tb-edqs</docker.name>
|
||||
<pkg.logFolder>/var/log/${pkg.name}</pkg.logFolder>
|
||||
<pkg.installFolder>/usr/share/${pkg.name}</pkg.installFolder>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user