|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 45 KiB |
@ -0,0 +1,20 @@ |
|||
{ |
|||
"widgetsBundle": { |
|||
"alias": "high_performance_scada_oil_gas", |
|||
"title": "High-performance SCADA oil & gas", |
|||
"image": "tb-image:aHBfc2NhZGFfb2lsX2dhc19zeXN0ZW1fYnVuZGxlX2ltYWdlLnBuZw==:IkhpZ2gtcGVyZm9ybWFuY2UgU0NBREEgb2lsICYgZ2FzIiBzeXN0ZW0gYnVuZGxlIGltYWdl:SU1BR0U=;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAMAAAB+IdObAAAAflBMVEXe3t7b29vf398AAADf39/e3t7e3t7////Gxsapqam5ubnR0NDj4+Otra2hoaHS0tLi4uK4uLjx8fGYmJikpKSdnZ2VlZWWlpbU1NS1tbWnp6eKioqysrLLy8uampra2tqvr6/X19eRkZF+fn7Dw8N1dXW/vr6FhYViYmJwcHCzXr36AAAABnRSTlPvIK8Av79l/pT7AAAI0UlEQVR42uza23LaMBSF4Z5msbyFpOFMAXcg0HT6/i/YGqvdNhBiYXtipf0v7CRX+UaSbWQ+fP745QNS79PHzx8+ps8A8JvxCe+idzCtwpC8Fwj+Q4bWvw0R7oQiJIbTAxAvwOmAIsFgiodYXxxPODecMYmGeD4fAOQoGtCYxEIMgcMQJbEQD5wlCvEYRLEQoig/wCBkMIgiIYKyE+claTBzKxJClO0AegDI8x0GUTREz5NTbvJUR0RwzjjAn1GpQlgcDif4nfiDAZAqBAIc8nBjNyY3ef6MQRR/HzlI7ZI7lCfHaIg5oA5Bu5bZzZaIKh6Cha9BHFq2HN2sb4gjra84rHAreCDKcjUr+n4b8n1WtHKW0LqDSGGwyFFmaOBMLGRv57uM4+moSWNONvuF7RrC8vhsBTBSEJwBEdfXUXRfux+RADIiJM4OSIIQVs8sHUmOiKlBSgd8pGS/2M8zrhutkemY2XyZ7TuGeKlBXHAJ4qN1q9mP+4ofs5WTXq5agipkqePzYLP7kBkiioIQIRrAifouSggCOsN0IaIQxyorJiOrb4uy5StrZFG2WVnTF8QZkAh5NjW4ebbKxqPo1pPdk2paQ7xHaGsAWMTMreXW7ibTUYum3DxtXBcQHRA5H6PmVjbqpKxLCEE9FUliEP49Uc9FNjGIBIdCwHSnFm8cwKQg9PqPXxgEr3ZkB4zp+tgBxNSWif7cDAJx3542nLa4+NrtkugAItefR3TxN4x2tthN1uPQ6G7jP01W2dyxszu7BXELAkIQk7Gh433I0ZaJ6fZZi8RtCEiPagN/aHS4hNSN2rAhwpch1qLasCEEX4JYCuIy4lbfXn+M36ycGHQMEby02K0aG27QbSbjadM7Bzfzhe0YAtYg6oAASGU7iLi8IaoD9OlAJBAUog5AkoHI1cBQHVEQu3nabyacNlsi2W6ebdkhRBe6QtQBIjKxDV4rzB0NtE4goiSFSI131SBf9ChEP+qKwV3IIF+9GWgsIRUHPNFDPUC8oJItDq7iePvX7U0hgmokIALt7b9L9yAEFENo6YwIL34TIk2IQPu796ulOrXC3q/29pethhDvoYV3PBzU3GoIEVRypr73W/TmcysaUjiqe7+hVCBE6OwIkPrfLTqvzxEpHApRSSojEiDBcXv/2qPv2kPoURQcNYhKBH3XHmJQFhw1COSsTAMixUEddQhcKSH6rj3EAlDHBaSUpDEiBCqOS0iQ0KPbeppa6riGBAn6rD3kynENKSWCfmsP4YXjGlJIHoYcs4t+ekQUARF1XENUQjyUrEcXrYmIYiDquIao5Fd797rcJgxEAbjX1UogBBRfErupm16mff8XbO2RWYuDqyCBx+30/EiMmTb6ugtSgYwtJcW2Q0hbUSSJkJ04ECJZO0rJRkE2hJkF4l4EYUMp0Qh5IswMEEPGvQDClAZ5RoglzAwQJpFch3DqRLK/WWsZEslVCFMqRE+4H5ILCSWWDf+OYQu0hDhGCDNh8iEFhRIbvhCCS5HYEiG1IUguRIZn+Cok55crqwm3R/IgRlrq/J3ZXLZW1u2exwnPCmRDROJj4PGB5Io8T3i+LA/CNJQUXFBRyf4syGEM0hFkvoqIpCJyFhxzttaeILNBRGKJ2BEVFsbupktcMwZpHEFyIc7RQGL8Y4GOxZHUW7KIjy3k8yE4NsvGT/bE4kjuraoFBS7kF4GQXR/fNcaRYcqGbJSKH+05EBwbnoUr3EVToxUGF/JLVETmePcCdco0ggv5hSDM67Wxds1MEEcTs79VaxkcWsU+6yg7sbVwIZ8PKQhi5UU2hFmpCeffnIpMg0z9+bYch9SWJEtBmC3z6UtuRar1D30lP9YVQXIgfPXNEcfEK9mdL0ezC868jS+KSJaoiBDYMmX1Fu/9iJvgiNeN9z06yoLEHb4iZPN6a3UugWpacbSstN98pvkgPPqWh4gkBdKVZ4falgKpWbXavzzQghXBhzNRPqWxjo1UbwXCx+1GmmshCD4uC39gSmP5MdccQI46aa5lWotDDUqcm9pYYxClW2muBSoy/kh5Ukm+6VO++Hm8d/jjpf3p9ydD4g6BiGQ6pPPnWqmCHOyyQ3UzQRi3QghKOAHSBPPIEhBLkqIigIhkIoR3/ajbAeTpEvKFZ28tcQhEJNMghWbuIY0uw5m91rqHMAslB1KEDoSgxMV/sOmUuoAoHa61tuoColTH+RDH6BBIIBayiToeVAhRtRaHLlUIUQ8mG2LAARCQRHuLH9UAIlO5nwp1K5CjhLMh4AAISKIV2akAwuW5DnLyrTmAqEMuhMEBEJDEIPsygPgRw7cA0la5FQEHQFDCsStyoxBuL9cqTQhRXT5EHAhBSfy0ZcsBpJHp4wgYh9Q2C+IcOBCCEhO/iyCQmi8ndN2vHEOI+pAFMehACEpc/MqiQJp2DNI2A4jNg6ADISjh+JVFgWjlcxKx8tEDSJcFYXQgBCU2slgEiPzPkHvWrBCDDoSghJMgzWnzGuSQBbEVRSDTJXoA2fbNFKzn6wFklQMxa0qBUGGi04hAlEBgc67WKigNQuYFV60bfcpOha3V9mtgfUrjPZxVkVQIT3xkQ2b2VqvRVHRzSHRGtFuFkUVWG7k2nwLhFEj8SvbTHxyqHd27o2UrktZbrhtxlP0/fqMgmyILYigJEl/JM0iai3bbNuBgyoLwUhByq1JdpNXBZv3UBpvPUo+bV4QpkvWu7BkffsAh8bWntN2B6I4hRHa1b5ibx9WmYK/qx87UrR6ZWW+0JclNWivpSjaz75oPD+L4+sFPxzIJ3q4i+Xepv5yXJKuCIFkQHAtLrP9yTpEKkXBX6YfDLsJIgcBf+bG8mo9YstTMD4HD7JO6mk80iKGFkt9aUyD3VRForSkQlyiZHYJn0EmQxN5aAIIjmQi5n4oMIX9tRUaer66vZkunfCafe4LISKAU8cLcU2tV3Odj+cJ85z7mBpL/H+x41/kPubf8Mx+s++od/RN58+98iPbb13//x2i/ev/67S8YXTU9MiU8PgAAAABJRU5ErkJggg==", |
|||
"scada": true, |
|||
"description": "Bundle with high-performance SCADA symbols for oil and gas system", |
|||
"order": 9405, |
|||
"name": "High-performance SCADA oil & gas" |
|||
}, |
|||
"widgetTypeFqns": [ |
|||
"hp_drilling_rig", |
|||
"hp_hook", |
|||
"hp_rotor", |
|||
"hp_preventer", |
|||
"hp_drill", |
|||
"hp_drilling_line", |
|||
"hp_platform" |
|||
] |
|||
} |
|||
@ -0,0 +1,291 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.transport.coap.security; |
|||
|
|||
import com.fasterxml.jackson.core.type.TypeReference; |
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.eclipse.californium.core.CoapResponse; |
|||
import org.eclipse.californium.core.coap.CoAP; |
|||
import org.junit.Assert; |
|||
import org.springframework.test.context.TestPropertySource; |
|||
import org.thingsboard.common.util.JacksonUtil; |
|||
import org.thingsboard.server.common.data.CoapDeviceType; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.DeviceProfile; |
|||
import org.thingsboard.server.common.data.SaveDeviceWithCredentialsRequest; |
|||
import org.thingsboard.server.common.data.TransportPayloadType; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.DeviceProfileId; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentials; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentialsType; |
|||
import org.thingsboard.server.common.msg.session.FeatureType; |
|||
import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest; |
|||
import org.thingsboard.server.transport.coap.x509.CertPrivateKey; |
|||
import org.thingsboard.server.transport.coap.x509.CoapClientX509Test; |
|||
import org.thingsboard.server.transport.coap.CoapTestConfigProperties; |
|||
|
|||
import java.io.IOException; |
|||
import java.io.InputStream; |
|||
import java.net.ServerSocket; |
|||
import java.security.GeneralSecurityException; |
|||
import java.security.KeyStore; |
|||
import java.security.PrivateKey; |
|||
import java.security.cert.X509Certificate; |
|||
import java.util.ArrayList; |
|||
import java.util.HashSet; |
|||
import java.util.Iterator; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.Set; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
import static org.awaitility.Awaitility.await; |
|||
import static org.junit.Assert.assertEquals; |
|||
import static org.junit.Assert.assertNotNull; |
|||
import static org.junit.Assert.assertTrue; |
|||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
|||
|
|||
@Slf4j |
|||
@TestPropertySource(properties = { |
|||
"coap.enabled=true", |
|||
"coap.dtls.enabled=true", |
|||
"coap.dtls.credentials.pem.cert_file=coap/credentials/server/cert.pem", |
|||
"device.connectivity.coaps.enabled=true", |
|||
"service.integrations.supported=ALL", |
|||
"transport.coap.enabled=true", |
|||
}) |
|||
public abstract class AbstractCoapSecurityIntegrationTest extends AbstractCoapIntegrationTest { |
|||
private static final String COAPS_BASE_URL = "coaps://localhost:5684/api/v1/"; |
|||
protected final String CREDENTIALS_PATH = "coap/credentials/"; |
|||
protected final String CREDENTIALS_PATH_CLIENT = CREDENTIALS_PATH + "client/"; |
|||
protected final String CREDENTIALS_PATH_CLIENT_CERT_PEM = CREDENTIALS_PATH_CLIENT + "cert.pem"; |
|||
protected final String CREDENTIALS_PATH_CLIENT_KEY_PEM = CREDENTIALS_PATH_CLIENT + "key.pem"; |
|||
protected final X509Certificate clientX509CertTrustNo; // client certificate signed by intermediate, rootCA with a good CN ("host name")
|
|||
protected final PrivateKey clientPrivateKeyFromCertTrustNo; |
|||
|
|||
protected static final String CLIENT_JKS_FOR_TEST = "coapclientTest"; |
|||
protected static final String CLIENT_STORE_PWD = "client_ks_password"; |
|||
protected static final String CLIENT_ALIAS_CERT_TRUST_NO = "client_alias_trust_no"; |
|||
|
|||
protected AbstractCoapSecurityIntegrationTest() { |
|||
|
|||
try { |
|||
// Get certificates from key store
|
|||
char[] clientKeyStorePwd = CLIENT_STORE_PWD.toCharArray(); |
|||
KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); |
|||
try (InputStream clientKeyStoreFile = |
|||
this.getClass().getClassLoader(). |
|||
getResourceAsStream(CREDENTIALS_PATH + CLIENT_JKS_FOR_TEST + ".jks")) { |
|||
clientKeyStore.load(clientKeyStoreFile, clientKeyStorePwd); |
|||
} |
|||
// No trust
|
|||
clientPrivateKeyFromCertTrustNo = (PrivateKey) clientKeyStore.getKey(CLIENT_ALIAS_CERT_TRUST_NO, clientKeyStorePwd); |
|||
clientX509CertTrustNo = (X509Certificate) clientKeyStore.getCertificate(CLIENT_ALIAS_CERT_TRUST_NO); |
|||
} catch (GeneralSecurityException | IOException e) { |
|||
throw new RuntimeException(e); |
|||
} |
|||
} |
|||
|
|||
protected Device createDeviceWithX509(String deviceName, DeviceProfileId deviceProfileId, X509Certificate clientX509Cert) throws Exception { |
|||
Device device = new Device(); |
|||
device.setName(deviceName); |
|||
device.setType(deviceName); |
|||
device.setDeviceProfileId(deviceProfileId); |
|||
|
|||
DeviceCredentials deviceCredentials = new DeviceCredentials(); |
|||
deviceCredentials.setCredentialsType(DeviceCredentialsType.X509_CERTIFICATE); |
|||
String pemFormatCert = CertPrivateKey.convertCertToPEM(clientX509Cert); |
|||
deviceCredentials.setCredentialsValue(pemFormatCert); |
|||
|
|||
SaveDeviceWithCredentialsRequest saveRequest = new SaveDeviceWithCredentialsRequest(device, deviceCredentials); |
|||
Device deviceX509 = readResponse(doPost("/api/device-with-credentials", saveRequest) |
|||
.andExpect(status().isOk()), Device.class); |
|||
DeviceCredentials savedDeviceCredentials = |
|||
doGet("/api/device/" + deviceX509.getId().getId() + "/credentials", DeviceCredentials.class); |
|||
Assert.assertNotNull(savedDeviceCredentials); |
|||
Assert.assertNotNull(savedDeviceCredentials.getId()); |
|||
Assert.assertEquals(deviceX509.getId(), savedDeviceCredentials.getDeviceId()); |
|||
Assert.assertEquals(DeviceCredentialsType.X509_CERTIFICATE, savedDeviceCredentials.getCredentialsType()); |
|||
accessToken = savedDeviceCredentials.getCredentialsId(); |
|||
assertNotNull(accessToken); |
|||
return deviceX509; |
|||
} |
|||
|
|||
protected void clientX509FromJksUpdateAttributesTest() throws Exception { |
|||
CertPrivateKey certPrivateKey = new CertPrivateKey(clientX509CertTrustNo, clientPrivateKeyFromCertTrustNo); |
|||
CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder() |
|||
.coapDeviceType(CoapDeviceType.DEFAULT) |
|||
.transportPayloadType(TransportPayloadType.JSON) |
|||
.build(); |
|||
DeviceProfile deviceProfile = createCoapDeviceProfile(configProperties); |
|||
assertNotNull(deviceProfile); |
|||
CoapClientX509Test clientX509 = clientX509UpdateTest(FeatureType.ATTRIBUTES, certPrivateKey, |
|||
"CoapX509TrustNo_" + FeatureType.ATTRIBUTES.name(), deviceProfile.getId(), null); |
|||
clientX509.disconnect(); |
|||
} |
|||
|
|||
protected void clientX509FromPathUpdateFeatureTypeTest(FeatureType featureType) throws Exception { |
|||
CertPrivateKey certPrivateKey = new CertPrivateKey(CREDENTIALS_PATH_CLIENT_CERT_PEM, CREDENTIALS_PATH_CLIENT_KEY_PEM); |
|||
CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder() |
|||
.coapDeviceType(CoapDeviceType.DEFAULT) |
|||
.transportPayloadType(TransportPayloadType.JSON) |
|||
.build(); |
|||
DeviceProfile deviceProfile = createCoapDeviceProfile(configProperties); |
|||
assertNotNull(deviceProfile); |
|||
CoapClientX509Test clientX509 = clientX509UpdateTest(featureType, certPrivateKey, |
|||
"CoapX509TrustNo_" + featureType.name(), deviceProfile.getId(), null); |
|||
clientX509.disconnect(); |
|||
} |
|||
protected void twoClientWithSamePortX509FromPathConnectTest() throws Exception { |
|||
CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder() |
|||
.coapDeviceType(CoapDeviceType.DEFAULT) |
|||
.transportPayloadType(TransportPayloadType.JSON) |
|||
.build(); |
|||
DeviceProfile deviceProfile = createCoapDeviceProfile(configProperties); |
|||
CertPrivateKey certPrivateKey = new CertPrivateKey(CREDENTIALS_PATH_CLIENT_CERT_PEM, CREDENTIALS_PATH_CLIENT_KEY_PEM); |
|||
CertPrivateKey certPrivateKey_01 = new CertPrivateKey(CREDENTIALS_PATH_CLIENT + "cert_01.pem", |
|||
CREDENTIALS_PATH_CLIENT + "key_01.pem"); |
|||
Integer fixedPort = getFreePort(); |
|||
CoapClientX509Test clientX509 = clientX509UpdateTest(FeatureType.ATTRIBUTES, certPrivateKey, |
|||
"CoapX509TrustNo_" + FeatureType.TELEMETRY.name(), deviceProfile.getId(), fixedPort); |
|||
clientX509.disconnect(); |
|||
await("Need to make port " + fixedPort + " free") |
|||
.atMost(40, TimeUnit.SECONDS) |
|||
.until(() -> isPortAvailable(fixedPort)); |
|||
CoapClientX509Test clientX509_01 = clientX509UpdateTest(FeatureType.ATTRIBUTES, certPrivateKey_01, |
|||
"CoapX509TrustNo_" + FeatureType.TELEMETRY.name() + "_01", deviceProfile.getId(), |
|||
fixedPort, PAYLOAD_VALUES_STR_01); |
|||
clientX509_01.disconnect(); |
|||
} |
|||
|
|||
private CoapClientX509Test clientX509UpdateTest(FeatureType featureType, CertPrivateKey certPrivateKey, |
|||
String deviceName, DeviceProfileId deviceProfileId, Integer fixedPort) throws Exception { |
|||
return clientX509UpdateTest(featureType, certPrivateKey, deviceName, deviceProfileId, fixedPort, null); |
|||
} |
|||
|
|||
private CoapClientX509Test clientX509UpdateTest(FeatureType featureType, CertPrivateKey certPrivateKey, |
|||
String deviceName, DeviceProfileId deviceProfileId, Integer fixedPort, String payload) throws Exception { |
|||
String payloadValuesStr = payload == null ? PAYLOAD_VALUES_STR : payload; |
|||
Device deviceX509 = createDeviceWithX509(deviceName, deviceProfileId, certPrivateKey.getCert()); |
|||
CoapClientX509Test clientX509 = new CoapClientX509Test(certPrivateKey, featureType, COAPS_BASE_URL, fixedPort); |
|||
CoapResponse coapResponseX509 = clientX509.postMethod(payloadValuesStr); |
|||
assertNotNull(coapResponseX509); |
|||
assertEquals(CoAP.ResponseCode.CREATED, coapResponseX509.getCode()); |
|||
|
|||
if (FeatureType.ATTRIBUTES.equals(featureType)) { |
|||
DeviceId deviceId = deviceX509.getId(); |
|||
JsonNode expectedNode = JacksonUtil.toJsonNode(payloadValuesStr); |
|||
List<String> expectedKeys = getKeysFromNode(expectedNode); |
|||
List<String> actualKeys = getActualKeysList(deviceId, expectedKeys, "attributes/CLIENT_SCOPE"); |
|||
assertNotNull(actualKeys); |
|||
|
|||
Set<String> actualKeySet = new HashSet<>(actualKeys); |
|||
Set<String> expectedKeySet = new HashSet<>(expectedKeys); |
|||
assertEquals(expectedKeySet, actualKeySet); |
|||
|
|||
String getAttributesValuesUrl = getAttributesValuesUrl(deviceId, actualKeySet, "attributes/CLIENT_SCOPE"); |
|||
List<Map<String, Object>> actualValues = doGetAsyncTyped(getAttributesValuesUrl, new TypeReference<>() { |
|||
}); |
|||
assertValuesList(actualValues, expectedNode); |
|||
} |
|||
return clientX509; |
|||
} |
|||
|
|||
private List<String> getActualKeysList(DeviceId deviceId, List<String> expectedKeys, String apiSuffix) throws Exception { |
|||
long start = System.currentTimeMillis(); |
|||
long end = System.currentTimeMillis() + 5000; |
|||
|
|||
List<String> actualKeys = null; |
|||
while (start <= end) { |
|||
actualKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + deviceId + "/keys/" + apiSuffix, new TypeReference<>() { |
|||
}); |
|||
if (actualKeys.size() == expectedKeys.size()) { |
|||
break; |
|||
} |
|||
Thread.sleep(100); |
|||
start += 100; |
|||
} |
|||
return actualKeys; |
|||
} |
|||
|
|||
private String getAttributesValuesUrl(DeviceId deviceId, Set<String> actualKeySet, String apiSuffix) { |
|||
return "/api/plugins/telemetry/DEVICE/" + deviceId + "/values/" + apiSuffix + "?keys=" + String.join(",", actualKeySet); |
|||
} |
|||
|
|||
private List getKeysFromNode(JsonNode jNode) { |
|||
List<String> jKeys = new ArrayList<>(); |
|||
Iterator<String> fieldNames = jNode.fieldNames(); |
|||
while (fieldNames.hasNext()) { |
|||
jKeys.add(fieldNames.next()); |
|||
} |
|||
return jKeys; |
|||
} |
|||
|
|||
protected void assertValuesList(List<Map<String, Object>> actualValues, JsonNode expectedValues) { |
|||
assertTrue(actualValues.size() > 0); |
|||
assertEquals(expectedValues.size(), actualValues.size()); |
|||
for (Map<String, Object> map : actualValues) { |
|||
String key = (String) map.get("key"); |
|||
Object actualValue = map.get("value"); |
|||
assertTrue(expectedValues.has(key)); |
|||
JsonNode expectedValue = expectedValues.get(key); |
|||
assertExpectedActualValue(expectedValue, actualValue); |
|||
} |
|||
} |
|||
|
|||
protected void assertExpectedActualValue(JsonNode expectedValue, Object actualValue) { |
|||
switch (expectedValue.getNodeType()) { |
|||
case STRING: |
|||
assertEquals(expectedValue.asText(), actualValue); |
|||
break; |
|||
case NUMBER: |
|||
if (expectedValue.isInt()) { |
|||
assertEquals(expectedValue.asInt(), actualValue); |
|||
} else if (expectedValue.isLong()) { |
|||
assertEquals(expectedValue.asLong(), actualValue); |
|||
} else if (expectedValue.isFloat() || expectedValue.isDouble()) { |
|||
assertEquals(expectedValue.asDouble(), actualValue); |
|||
} |
|||
break; |
|||
case BOOLEAN: |
|||
assertEquals(expectedValue.asBoolean(), actualValue); |
|||
break; |
|||
case ARRAY: |
|||
case OBJECT: |
|||
expectedValue.toString().equals(JacksonUtil.toString(actualValue)); |
|||
break; |
|||
default: |
|||
break; |
|||
} |
|||
} |
|||
|
|||
private static int getFreePort() throws IOException { |
|||
try (ServerSocket socket = new ServerSocket(0)) { |
|||
return socket.getLocalPort(); |
|||
} |
|||
} |
|||
|
|||
private static boolean isPortAvailable(int port) { |
|||
try (ServerSocket serverSocket = new ServerSocket(port)) { |
|||
serverSocket.setReuseAddress(true); |
|||
return true; |
|||
} catch (IOException e) { |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,44 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.transport.coap.security.sql; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.junit.Before; |
|||
import org.junit.Test; |
|||
import org.springframework.test.context.TestPropertySource; |
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
import org.thingsboard.server.transport.coap.security.AbstractCoapSecurityIntegrationTest; |
|||
|
|||
@Slf4j |
|||
@DaoSqlTest |
|||
@TestPropertySource(properties = { |
|||
"coap.dtls.credentials.type=KEYSTORE", |
|||
"coap.dtls.credentials.keystore.store_file=coap/credentials/coapserverTest.jks", |
|||
"coap.dtls.credentials.keystore.key_password=server_ks_password", |
|||
"coap.dtls.credentials.keystore.key_alias=server", |
|||
}) |
|||
public class CoapClientX509SecurityJksIntegrationTest extends AbstractCoapSecurityIntegrationTest { |
|||
|
|||
@Before |
|||
public void beforeTest() throws Exception { |
|||
processBeforeTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testX509NoTrustFromJksConnectCoapSuccessUpdateAttributesSuccess() throws Exception { |
|||
clientX509FromJksUpdateAttributesTest(); |
|||
} |
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.transport.coap.security.sql; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.junit.Before; |
|||
import org.junit.Test; |
|||
import org.thingsboard.server.common.msg.session.FeatureType; |
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
import org.thingsboard.server.transport.coap.security.AbstractCoapSecurityIntegrationTest; |
|||
|
|||
@Slf4j |
|||
@DaoSqlTest |
|||
public class CoapClientX509SecurityPemIntegrationTest extends AbstractCoapSecurityIntegrationTest { |
|||
@Before |
|||
public void beforeTest() throws Exception { |
|||
processBeforeTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testX509NoTrustFromPathConnectCoapSuccessUpdateAttributesSuccess() throws Exception { |
|||
clientX509FromPathUpdateFeatureTypeTest(FeatureType.ATTRIBUTES); |
|||
} |
|||
@Test |
|||
public void testX509NoTrustFromPathConnectCoapSuccessUpdateTelemetrySuccess() throws Exception { |
|||
clientX509FromPathUpdateFeatureTypeTest(FeatureType.TELEMETRY); |
|||
} @Test |
|||
public void testTwoDevicesWithSamePortX509NoTrustFromPathConnectCoapSuccess() throws Exception { |
|||
twoClientWithSamePortX509FromPathConnectTest(); |
|||
} |
|||
} |
|||
@ -0,0 +1,82 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.transport.coap.x509; |
|||
|
|||
import org.apache.commons.io.FileUtils; |
|||
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey; |
|||
import org.thingsboard.common.util.SslUtil; |
|||
import java.io.File; |
|||
import java.io.IOException; |
|||
import java.security.KeyFactory; |
|||
import java.security.PrivateKey; |
|||
import java.security.cert.X509Certificate; |
|||
import java.security.interfaces.ECPrivateKey; |
|||
import java.security.spec.PKCS8EncodedKeySpec; |
|||
import java.util.Base64; |
|||
import java.util.List; |
|||
|
|||
public class CertPrivateKey { |
|||
private final X509Certificate cert; |
|||
private PrivateKey privateKey; |
|||
|
|||
public CertPrivateKey(String certFilePathPem, String keyFilePathPem) throws Exception { |
|||
List<X509Certificate> certs = SslUtil.readCertFile(fileRead(certFilePathPem)); |
|||
this.cert = certs.get(0); |
|||
this.privateKey = SslUtil.readPrivateKey(fileRead(keyFilePathPem), null); |
|||
if (this.privateKey instanceof BCECPrivateKey) { |
|||
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(this.privateKey.getEncoded()); |
|||
KeyFactory keyFactory = KeyFactory.getInstance("EC"); |
|||
this.privateKey = keyFactory.generatePrivate(keySpec); |
|||
} |
|||
if (!(this.privateKey instanceof ECPrivateKey)) { |
|||
throw new RuntimeException("Private key generation must be of type java.security.interfaces.ECPrivateKey, which is used in the standard Java API!"); |
|||
} |
|||
} |
|||
|
|||
public CertPrivateKey(X509Certificate cert, PrivateKey privateKey) { |
|||
this.cert = cert; |
|||
this.privateKey = privateKey; |
|||
} |
|||
|
|||
public X509Certificate getCert() { |
|||
return this.cert; |
|||
} |
|||
|
|||
public PrivateKey getPrivateKey() { |
|||
return this.privateKey; |
|||
} |
|||
|
|||
private String fileRead(String fileName) throws IOException { |
|||
ClassLoader classLoader = getClass().getClassLoader(); |
|||
File file = new File(classLoader.getResource(fileName).getFile()); |
|||
return FileUtils.readFileToString(file, "UTF-8"); |
|||
} |
|||
|
|||
public static String convertCertToPEM(X509Certificate certificate) throws Exception { |
|||
StringBuilder pemBuilder = new StringBuilder(); |
|||
pemBuilder.append("-----BEGIN CERTIFICATE-----\n"); |
|||
// Copy cert to Base64
|
|||
String base64EncodedCert = Base64.getEncoder().encodeToString(certificate.getEncoded()); |
|||
int index = 0; |
|||
while (index < base64EncodedCert.length()) { |
|||
pemBuilder.append(base64EncodedCert, index, Math.min(index + 64, base64EncodedCert.length())); |
|||
pemBuilder.append("\n"); |
|||
index += 64; |
|||
} |
|||
pemBuilder.append("-----END CERTIFICATE-----\n"); |
|||
return pemBuilder.toString(); |
|||
} |
|||
} |
|||
@ -0,0 +1,239 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.transport.coap.x509; |
|||
|
|||
import lombok.Getter; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.eclipse.californium.core.CoapClient; |
|||
import org.eclipse.californium.core.CoapHandler; |
|||
import org.eclipse.californium.core.CoapObserveRelation; |
|||
import org.eclipse.californium.core.CoapResponse; |
|||
import org.eclipse.californium.core.coap.CoAP; |
|||
import org.eclipse.californium.core.coap.MediaTypeRegistry; |
|||
import org.eclipse.californium.core.coap.Request; |
|||
import org.eclipse.californium.core.config.CoapConfig; |
|||
import org.eclipse.californium.core.network.CoapEndpoint; |
|||
import org.eclipse.californium.elements.config.Configuration; |
|||
import org.eclipse.californium.elements.config.ValueException; |
|||
import org.eclipse.californium.elements.exception.ConnectorException; |
|||
import org.eclipse.californium.scandium.DTLSConnector; |
|||
import org.eclipse.californium.scandium.config.DtlsConfig.SignatureAndHashAlgorithmsDefinition; |
|||
import org.eclipse.californium.scandium.config.DtlsConnectorConfig; |
|||
import org.eclipse.californium.scandium.dtls.CertificateType; |
|||
import org.eclipse.californium.scandium.dtls.SignatureAndHashAlgorithm; |
|||
import org.eclipse.californium.scandium.dtls.SignatureAndHashAlgorithm.HashAlgorithm; |
|||
import org.eclipse.californium.scandium.dtls.SignatureAndHashAlgorithm.SignatureAlgorithm; |
|||
import org.eclipse.californium.scandium.dtls.cipher.CipherSuite; |
|||
import org.eclipse.californium.scandium.dtls.x509.CertificateProvider; |
|||
import org.eclipse.californium.scandium.dtls.x509.SingleCertificateProvider; |
|||
import org.thingsboard.server.common.msg.session.FeatureType; |
|||
import org.thingsboard.server.transport.coap.CoapTestCallback; |
|||
|
|||
import java.io.IOException; |
|||
import java.net.InetSocketAddress; |
|||
import java.security.cert.X509Certificate; |
|||
import java.util.Arrays; |
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
import static java.util.concurrent.TimeUnit.MILLISECONDS; |
|||
import static org.eclipse.californium.core.config.CoapConfig.DEFAULT_BLOCKWISE_STATUS_LIFETIME_IN_SECONDS; |
|||
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_AUTO_HANDSHAKE_TIMEOUT; |
|||
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_CIPHER_SUITES; |
|||
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_MAX_FRAGMENTED_HANDSHAKE_MESSAGE_LENGTH; |
|||
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_MAX_PENDING_HANDSHAKE_RESULT_JOBS; |
|||
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_MAX_RETRANSMISSIONS; |
|||
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_MAX_RETRANSMISSION_TIMEOUT; |
|||
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECEIVE_BUFFER_SIZE; |
|||
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CIPHER_SUITES_ONLY; |
|||
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RETRANSMISSION_TIMEOUT; |
|||
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_ROLE; |
|||
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_SIGNATURE_AND_HASH_ALGORITHMS; |
|||
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_USE_HELLO_VERIFY_REQUEST; |
|||
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_USE_MULTI_HANDSHAKE_MESSAGE_RECORDS; |
|||
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_VERIFY_SERVER_CERTIFICATES_SUBJECT; |
|||
import static org.eclipse.californium.scandium.config.DtlsConfig.DtlsRole.CLIENT_ONLY; |
|||
import static org.eclipse.californium.scandium.config.DtlsConfig.MODULE; |
|||
import static org.eclipse.californium.scandium.dtls.SignatureAndHashAlgorithm.SHA256_WITH_ECDSA; |
|||
import static org.eclipse.californium.scandium.dtls.SignatureAndHashAlgorithm.SHA256_WITH_RSA; |
|||
import static org.eclipse.californium.scandium.dtls.SignatureAndHashAlgorithm.SHA384_WITH_ECDSA; |
|||
|
|||
@Slf4j |
|||
public class CoapClientX509Test { |
|||
|
|||
private static final long CLIENT_REQUEST_TIMEOUT = 60000L; |
|||
|
|||
private final CoapClient clientX509; |
|||
private final DTLSConnector dtlsConnector; |
|||
private final Configuration config; |
|||
private final CertPrivateKey certPrivateKey; |
|||
private final String coapsBaseUrl; |
|||
|
|||
@Getter |
|||
private CoAP.Type type = CoAP.Type.CON; |
|||
|
|||
public CoapClientX509Test(CertPrivateKey certPrivateKey, FeatureType featureType, String coapsBaseUrl, Integer fixedPort) { |
|||
this.certPrivateKey = certPrivateKey; |
|||
this.coapsBaseUrl = coapsBaseUrl; |
|||
this.config = createConfiguration(); |
|||
this.dtlsConnector = createDTLSConnector(fixedPort); |
|||
this.clientX509 = createClient(getFeatureTokenUrl(featureType)); |
|||
} |
|||
public void disconnect() { |
|||
if (clientX509 != null) { |
|||
clientX509.shutdown(); |
|||
} |
|||
} |
|||
|
|||
public CoapResponse postMethod(String requestBody) throws ConnectorException, IOException { |
|||
return this.postMethod(requestBody.getBytes()); |
|||
} |
|||
|
|||
public CoapResponse postMethod(byte[] requestBodyBytes) throws ConnectorException, IOException { |
|||
return clientX509.setTimeout(CLIENT_REQUEST_TIMEOUT).post(requestBodyBytes, MediaTypeRegistry.APPLICATION_JSON); |
|||
} |
|||
|
|||
public void postMethod(CoapHandler handler, String payload, int format) { |
|||
clientX509.setTimeout(CLIENT_REQUEST_TIMEOUT).post(handler, payload, format); |
|||
} |
|||
|
|||
public void postMethod(CoapHandler handler, byte[] payload) { |
|||
clientX509.setTimeout(CLIENT_REQUEST_TIMEOUT).post(handler, payload, MediaTypeRegistry.APPLICATION_JSON); |
|||
} |
|||
public void postMethod(CoapHandler handler, byte[] payload, int format) { |
|||
clientX509.setTimeout(CLIENT_REQUEST_TIMEOUT).post(handler, payload, format); |
|||
} |
|||
|
|||
public CoapResponse getMethod() throws ConnectorException, IOException { |
|||
return clientX509.setTimeout(CLIENT_REQUEST_TIMEOUT).get(); |
|||
} |
|||
|
|||
public CoapObserveRelation getObserveRelation(CoapTestCallback callback) { |
|||
return getObserveRelation(callback, true); |
|||
} |
|||
|
|||
public CoapObserveRelation getObserveRelation(CoapTestCallback callback, boolean confirmable) { |
|||
Request request = Request.newGet().setObserve(); |
|||
request.setType(confirmable ? CoAP.Type.CON : CoAP.Type.NON); |
|||
return clientX509.observe(request, callback); |
|||
} |
|||
|
|||
public void setURI(String featureTokenUrl) { |
|||
if (clientX509 == null) { |
|||
throw new RuntimeException("Failed to connect! CoapClient is not initialized!"); |
|||
} |
|||
clientX509.setURI(featureTokenUrl); |
|||
} |
|||
|
|||
public void setURI(String accessToken, FeatureType featureType) { |
|||
if (featureType == null) { |
|||
featureType = FeatureType.ATTRIBUTES; |
|||
} |
|||
setURI(getFeatureTokenUrl(accessToken, featureType)); |
|||
} |
|||
|
|||
public void useCONs() { |
|||
if (clientX509 == null) { |
|||
throw new RuntimeException("Failed to connect! CoapClient is not initialized!"); |
|||
} |
|||
type = CoAP.Type.CON; |
|||
clientX509.useCONs(); |
|||
} |
|||
|
|||
public void useNONs() { |
|||
if (clientX509 == null) { |
|||
throw new RuntimeException("Failed to connect! CoapClient is not initialized!"); |
|||
} |
|||
type = CoAP.Type.NON; |
|||
clientX509.useNONs(); |
|||
} |
|||
|
|||
private Configuration createConfiguration() { |
|||
Configuration clientCoapConfig = new Configuration(); |
|||
clientCoapConfig.set(CoapConfig.BLOCKWISE_STRICT_BLOCK2_OPTION, true); |
|||
clientCoapConfig.set(CoapConfig.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true); |
|||
clientCoapConfig.set(CoapConfig.BLOCKWISE_STATUS_LIFETIME, DEFAULT_BLOCKWISE_STATUS_LIFETIME_IN_SECONDS, TimeUnit.SECONDS); |
|||
clientCoapConfig.set(CoapConfig.MAX_RESOURCE_BODY_SIZE, 256 * 1024 * 1024); |
|||
clientCoapConfig.set(CoapConfig.RESPONSE_MATCHING, CoapConfig.MatcherMode.RELAXED); |
|||
clientCoapConfig.set(CoapConfig.PREFERRED_BLOCK_SIZE, 1024); |
|||
clientCoapConfig.set(CoapConfig.MAX_MESSAGE_SIZE, 1024); |
|||
clientCoapConfig.set(DTLS_ROLE, CLIENT_ONLY); |
|||
clientCoapConfig.set(DTLS_MAX_RETRANSMISSIONS, 2); |
|||
clientCoapConfig.set(DTLS_RETRANSMISSION_TIMEOUT, 5000, MILLISECONDS); |
|||
clientCoapConfig.set(DTLS_MAX_RETRANSMISSION_TIMEOUT, 60000, TimeUnit.MILLISECONDS); |
|||
clientCoapConfig.set(DTLS_USE_HELLO_VERIFY_REQUEST, false); |
|||
clientCoapConfig.set(DTLS_VERIFY_SERVER_CERTIFICATES_SUBJECT, false); |
|||
clientCoapConfig.set(DTLS_MAX_FRAGMENTED_HANDSHAKE_MESSAGE_LENGTH, 22490); |
|||
clientCoapConfig.set(DTLS_AUTO_HANDSHAKE_TIMEOUT, 100000, TimeUnit.MILLISECONDS); |
|||
clientCoapConfig.set(DTLS_MAX_PENDING_HANDSHAKE_RESULT_JOBS, 64); |
|||
clientCoapConfig.set(DTLS_USE_MULTI_HANDSHAKE_MESSAGE_RECORDS, false); |
|||
clientCoapConfig.set(DTLS_RECEIVE_BUFFER_SIZE, 8192); |
|||
clientCoapConfig.setTransient(DTLS_RECOMMENDED_CIPHER_SUITES_ONLY); |
|||
SignatureAndHashAlgorithmsDefinition algorithmsDefinition = new SignatureAndHashAlgorithmsDefinition(MODULE + "SIGNATURE_AND_HASH_ALGORITHMS", "List of DTLS signature- and hash-algorithms.\nValues e.g SHA256withECDSA or ED25519."); |
|||
SignatureAndHashAlgorithm SHA384_WITH_RSA = new SignatureAndHashAlgorithm(HashAlgorithm.SHA384, |
|||
SignatureAlgorithm.RSA); |
|||
List<SignatureAndHashAlgorithm> algorithms = null; |
|||
try { |
|||
algorithms = algorithmsDefinition.checkValue(Arrays.asList(SHA256_WITH_ECDSA, SHA256_WITH_RSA, SHA384_WITH_ECDSA, SHA384_WITH_RSA)); |
|||
} catch (ValueException e) { |
|||
throw new RuntimeException(e); |
|||
} |
|||
clientCoapConfig.setTransient(DTLS_SIGNATURE_AND_HASH_ALGORITHMS); |
|||
clientCoapConfig.set(DTLS_SIGNATURE_AND_HASH_ALGORITHMS, algorithms); |
|||
clientCoapConfig.setTransient(DTLS_CIPHER_SUITES); |
|||
clientCoapConfig.set(DTLS_CIPHER_SUITES, Arrays.asList(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)); |
|||
clientCoapConfig.setTransient(DTLS_VERIFY_SERVER_CERTIFICATES_SUBJECT); |
|||
clientCoapConfig.set(DTLS_VERIFY_SERVER_CERTIFICATES_SUBJECT, false); |
|||
return clientCoapConfig; |
|||
} |
|||
|
|||
private DTLSConnector createDTLSConnector(Integer fixedPort) { |
|||
try { |
|||
// Create DTLS config client
|
|||
DtlsConnectorConfig.Builder configBuilder = new DtlsConnectorConfig.Builder(this.config); |
|||
configBuilder.setAdvancedCertificateVerifier(new TbAdvancedCertificateVerifier()); |
|||
X509Certificate[] certificateChainClient = new X509Certificate[]{this.certPrivateKey.getCert()}; |
|||
CertificateProvider certificateProvider = new SingleCertificateProvider(this.certPrivateKey.getPrivateKey(), certificateChainClient, Collections.singletonList(CertificateType.X_509)); |
|||
configBuilder.setCertificateIdentityProvider(certificateProvider); |
|||
if (fixedPort != null) { |
|||
InetSocketAddress localAddress = new InetSocketAddress("0.0.0.0", fixedPort); |
|||
configBuilder.setAddress(localAddress); |
|||
configBuilder.setReuseAddress(true); |
|||
} |
|||
return new DTLSConnector(configBuilder.build()); |
|||
} catch (Exception e) { |
|||
throw new RuntimeException("", e); |
|||
} |
|||
} |
|||
|
|||
private CoapClient createClient(String featureTokenUrl) { |
|||
CoapClient client = new CoapClient(featureTokenUrl); |
|||
CoapEndpoint.Builder builder = new CoapEndpoint.Builder(); |
|||
builder.setConnector(dtlsConnector); |
|||
client.setEndpoint(builder.build()); |
|||
return client; |
|||
} |
|||
|
|||
public String getFeatureTokenUrl(FeatureType featureType) { |
|||
return this.coapsBaseUrl + featureType.name().toLowerCase(); |
|||
} |
|||
|
|||
public String getFeatureTokenUrl(String token, FeatureType featureType) { |
|||
return this.coapsBaseUrl + token + "/" + featureType.name().toLowerCase(); |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,129 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.transport.coap.x509; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.eclipse.californium.scandium.dtls.AlertMessage; |
|||
import org.eclipse.californium.scandium.dtls.AlertMessage.AlertDescription; |
|||
import org.eclipse.californium.scandium.dtls.AlertMessage.AlertLevel; |
|||
import org.eclipse.californium.scandium.dtls.CertificateMessage; |
|||
import org.eclipse.californium.scandium.dtls.CertificateType; |
|||
import org.eclipse.californium.scandium.dtls.CertificateVerificationResult; |
|||
import org.eclipse.californium.scandium.dtls.ConnectionId; |
|||
import org.eclipse.californium.scandium.dtls.HandshakeException; |
|||
import org.eclipse.californium.scandium.dtls.HandshakeResultHandler; |
|||
import org.eclipse.californium.scandium.dtls.x509.NewAdvancedCertificateVerifier; |
|||
import org.eclipse.californium.scandium.util.ServerNames; |
|||
|
|||
import javax.security.auth.x500.X500Principal; |
|||
import java.net.InetSocketAddress; |
|||
import java.security.PublicKey; |
|||
import java.security.cert.CertPath; |
|||
import java.util.Arrays; |
|||
import java.util.List; |
|||
|
|||
@Slf4j |
|||
public class TbAdvancedCertificateVerifier implements NewAdvancedCertificateVerifier { |
|||
|
|||
private HandshakeResultHandler resultHandler; |
|||
/** |
|||
* Get the list of supported certificate types in order of preference. |
|||
* |
|||
* @return the list of supported certificate types. |
|||
* @since 3.0 (renamed from getSupportedCertificateType) |
|||
*/ |
|||
@Override |
|||
public List<CertificateType> getSupportedCertificateTypes() { |
|||
return Arrays.asList(CertificateType.X_509, CertificateType.RAW_PUBLIC_KEY); |
|||
} |
|||
|
|||
/** |
|||
* Validates the certificate provided by the the peer as part of the |
|||
* certificate message. |
|||
* <p> |
|||
* If a x509 certificate chain is provided in the certificate message, |
|||
* validate the chain and key usage. If a RawPublicKey certificate is |
|||
* provided, check, if this public key is trusted. |
|||
* |
|||
* @param cid connection ID |
|||
* @param serverName indicated server names. May be {@code null}, if not |
|||
* available or SNI is not enabled. |
|||
* @param remotePeer socket address of remote peer |
|||
* @param clientUsage indicator to check certificate usage. {@code true}, |
|||
* check key usage for client, {@code false} for server. |
|||
* @param verifySubject {@code true} to verify the certificate's subjects, |
|||
* {@code false}, if not. |
|||
* @param truncateCertificatePath {@code true} truncate certificate path at |
|||
* a trusted certificate before validation. |
|||
* @param message certificate message to be validated |
|||
* @return certificate verification result, or {@code null}, if result is |
|||
* provided asynchronous. |
|||
* @since 3.0 (removed DTLSSession session, added remotePeer and |
|||
* verifySubject) |
|||
*/ |
|||
@Override |
|||
public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName, InetSocketAddress remotePeer, |
|||
boolean clientUsage, boolean verifySubject, boolean truncateCertificatePath, |
|||
CertificateMessage message) { |
|||
CertPath certChain = message.getCertificateChain(); |
|||
CertificateVerificationResult result; |
|||
|
|||
if (certChain == null) { |
|||
PublicKey publicKey = message.getPublicKey(); |
|||
result = new CertificateVerificationResult(cid, publicKey, null); |
|||
} else { |
|||
if (message.getCertificateChain().getCertificates().isEmpty()) { |
|||
result = new CertificateVerificationResult(cid, new HandshakeException("Empty certificate chain", |
|||
new AlertMessage(AlertLevel.FATAL, AlertDescription.BAD_CERTIFICATE)), null); |
|||
} else { |
|||
result = new CertificateVerificationResult(cid, certChain, null); |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
/** |
|||
* Return an list of certificate authorities which are trusted |
|||
* for authenticating peers. |
|||
* |
|||
* @return a non-null (possibly empty) list of accepted CA issuers. |
|||
*/ |
|||
@Override |
|||
public List<X500Principal> getAcceptedIssuers() { |
|||
log.trace("getAcceptedIssuers: return null"); |
|||
return null; |
|||
} |
|||
|
|||
/** |
|||
* Set the handler for asynchronous handshake results. |
|||
* <p> |
|||
* Called during initialization of the {link DTLSConnector}. Synchronous |
|||
* implementations may just ignore this using an empty implementation. |
|||
* |
|||
* @param resultHandler handler for asynchronous master secret results. This |
|||
* handler MUST NOT be called from the thread calling |
|||
* {@link #verifyCertificate(ConnectionId, ServerNames, InetSocketAddress, boolean, boolean, boolean, CertificateMessage)}, |
|||
* instead just return the result there. |
|||
*/ |
|||
@Override |
|||
public void setResultHandler(HandshakeResultHandler resultHandler) { |
|||
if (this.resultHandler != null && resultHandler != null && this.resultHandler != resultHandler) { |
|||
throw new IllegalStateException("handshake result handler already set!"); |
|||
} |
|||
this.resultHandler = resultHandler; |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
-----BEGIN CERTIFICATE----- |
|||
MIIB/TCCAaOgAwIBAgIIVNrVgKT9OE8wCgYIKoZIzj0EAwIwWjEOMAwGA1UEAxMF |
|||
Y2YtY2ExFDASBgNVBAsTC0NhbGlmb3JuaXVtMRQwEgYDVQQKEwtFY2xpcHNlIElv |
|||
VDEPMA0GA1UEBxMGT3R0YXdhMQswCQYDVQQGEwJDQTAeFw0yMzEwMjYwODA4MjJa |
|||
Fw0yNTEwMjUwODA4MjJaMF4xEjAQBgNVBAMTCWNmLWNsaWVudDEUMBIGA1UECxML |
|||
Q2FsaWZvcm5pdW0xFDASBgNVBAoTC0VjbGlwc2UgSW9UMQ8wDQYDVQQHEwZPdHRh |
|||
d2ExCzAJBgNVBAYTAkNBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEQxYO5/M5 |
|||
ie6+3QPOaAy5MD6CkFILZwIb2rOBCX/EWPaocX1H+eynUnaEEbmqxeN6rnI/pH19 |
|||
j4PtsegfHLrzzaNPME0wHQYDVR0OBBYEFKwEDLTJ+5cQoZfbjWN1vJ2ssgK+MAsG |
|||
A1UdDwQEAwIHgDAfBgNVHSMEGDAWgBSxVzoI1TL87++hsUb9vQwqODzgUTAKBggq |
|||
hkjOPQQDAgNIADBFAiA2KCOw3n2AK9Vm8u2u1bQREIEs3tKAU7eFjpNFn929NwIh |
|||
AInhBGoEwS2Xlu5bdZSfWnujoRrEQiIiQpStmLxVcIsH |
|||
-----END CERTIFICATE----- |
|||
@ -0,0 +1,14 @@ |
|||
-----BEGIN CERTIFICATE----- |
|||
MIICIzCCAcmgAwIBAgIUZZCGYm65c9vU0Xfvd/pAnLVDouUwCgYIKoZIzj0EAwIw |
|||
ZzELMAkGA1UEBhMCVUExDTALBgNVBAgMBEtpeXYxDTALBgNVBAcMBEtpeXYxFDAS |
|||
BgNVBAoMC1RoaW5nc2JvYXJkMRIwEAYDVQQLDAlkZXZlbG9wZXIxEDAOBgNVBAMM |
|||
B2NlcnRfMDEwHhcNMjQxMjE4MTU1NjE1WhcNMjUxMjE4MTU1NjE1WjBnMQswCQYD |
|||
VQQGEwJVQTENMAsGA1UECAwES2l5djENMAsGA1UEBwwES2l5djEUMBIGA1UECgwL |
|||
VGhpbmdzYm9hcmQxEjAQBgNVBAsMCWRldmVsb3BlcjEQMA4GA1UEAwwHY2VydF8w |
|||
MTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABNU1tE6o/QpqJJqpy+m+UoPuQe5g |
|||
eTgS4M3x0iQS6pzNEJBhzbnOp/BysGMB4wKiAWTRuKdH/gcRXDBTjLd/d7ijUzBR |
|||
MB0GA1UdDgQWBBSiao1iNWYzlsrSbxYqbda116HG1jAfBgNVHSMEGDAWgBSiao1i |
|||
NWYzlsrSbxYqbda116HG1jAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gA |
|||
MEUCIB2aCM/nvDqic9NkoSX/71GwksLiAKiFNkt2BZQykrcHAiEAr2h5IMdkyurN |
|||
Jy/idx2y44CP0tMq/3QV0QLCQFJIi6s= |
|||
-----END CERTIFICATE----- |
|||
@ -0,0 +1,4 @@ |
|||
-----BEGIN PRIVATE KEY----- |
|||
MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCDn0+4CuLeX7xwBs0ts |
|||
UUEDB3+HRwRKdIPeJlIbKuvvEQ== |
|||
-----END PRIVATE KEY----- |
|||
@ -0,0 +1,8 @@ |
|||
-----BEGIN EC PARAMETERS----- |
|||
BggqhkjOPQMBBw== |
|||
-----END EC PARAMETERS----- |
|||
-----BEGIN EC PRIVATE KEY----- |
|||
MHcCAQEEIJldU1MBuJUJnNHa9Ob5NGlXc/Os6put9eh1TlIbuScnoAoGCCqGSM49 |
|||
AwEHoUQDQgAE1TW0Tqj9CmokmqnL6b5Sg+5B7mB5OBLgzfHSJBLqnM0QkGHNuc6n |
|||
8HKwYwHjAqIBZNG4p0f+BxFcMFOMt393uA== |
|||
-----END EC PRIVATE KEY----- |
|||
@ -0,0 +1,35 @@ |
|||
-----BEGIN CERTIFICATE----- |
|||
MIIBaDCCAQ2gAwIBAgIUCY+goBAOhowBs7BHs/qXdAX8XFgwCgYIKoZIzj0EAwIw |
|||
ETEPMA0GA1UEAwwGUm9vdENBMB4XDTI0MTIxOTEzNTY1OFoXDTM0MTIxNzEzNTY1 |
|||
OFowETEPMA0GA1UEAwwGU2VydmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE |
|||
/qief3Kjnz0FpkQVaKRqJq3kHmCqqs+y1EGYLEZZAqLFvxmv7xoL6muG4Mj8tzqk |
|||
Ll94JJuz97hG1FiEZsq7O6NDMEEwCwYDVR0PBAQDAgWgMBMGA1UdJQQMMAoGCCsG |
|||
AQUFBwMBMB0GA1UdDgQWBBTK/UPsN0I2ErVPILWKMRV6TSeAmTAKBggqhkjOPQQD |
|||
AgNJADBGAiEA8EhlOwvTbwGlxo55UIOJp9LBbCp0BEIWojlu8PzOVSsCIQDlV24S |
|||
3BUJVCuMRujO5lTfJLxaSKkOEIgRANwIGi88WA== |
|||
-----END CERTIFICATE----- |
|||
-----BEGIN CERTIFICATE----- |
|||
MIIBGzCBwgIUP/PGQOKa5EyvsIXNgvv9PNietyEwCgYIKoZIzj0EAwMwEDEOMAwG |
|||
A1UEAwwFVFJVU1QwHhcNMjQxMjE5MTM1NjU4WhcNMzQxMjE3MTM1NjU4WjARMQ8w |
|||
DQYDVQQDDAZSb290Q0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAT+qJ5/cqOf |
|||
PQWmRBVopGomreQeYKqqz7LUQZgsRlkCosW/Ga/vGgvqa4bgyPy3OqQuX3gkm7P3 |
|||
uEbUWIRmyrs7MAoGCCqGSM49BAMDA0gAMEUCIQD2DY3UDXbzaIBKrsCtohKlEunH |
|||
ip9LkSeYfSKCnfm23gIgA8AEJdunpRmPkilxgy6wZSLLROqDpGDnhnyv8dsR8cc= |
|||
-----END CERTIFICATE----- |
|||
-----BEGIN CERTIFICATE----- |
|||
MIIBLTCB1AIUcsuauXAqvIS2RQcNPYysETJUAvwwCgYIKoZIzj0EAwMwIzEhMB8G |
|||
A1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTI0MTIxOTEzNTY1OFoX |
|||
DTM0MTIxNzEzNTY1OFowEDEOMAwGA1UEAwwFVFJVU1QwWTATBgcqhkjOPQIBBggq |
|||
hkjOPQMBBwNCAAT+qJ5/cqOfPQWmRBVopGomreQeYKqqz7LUQZgsRlkCosW/Ga/v |
|||
Ggvqa4bgyPy3OqQuX3gkm7P3uEbUWIRmyrs7MAoGCCqGSM49BAMDA0gAMEUCIQCM |
|||
DV8sfoArfWiXAUF2LNS3kkHD7sgb91jr2+poEHgBBgIgXf9VeJp3K5jHX6lJwtE8 |
|||
nd+jW7T9nhTc/5njHg7xons= |
|||
-----END CERTIFICATE----- |
|||
-----BEGIN EC PARAMETERS----- |
|||
BggqhkjOPQMBBw== |
|||
-----END EC PARAMETERS----- |
|||
-----BEGIN EC PRIVATE KEY----- |
|||
MHcCAQEEIB+Z69so6HqCCWo5VOFxGsLXOlTWIYijOtzt+SeNGrgPoAoGCCqGSM49 |
|||
AwEHoUQDQgAE/qief3Kjnz0FpkQVaKRqJq3kHmCqqs+y1EGYLEZZAqLFvxmv7xoL |
|||
6muG4Mj8tzqkLl94JJuz97hG1FiEZsq7Ow== |
|||
-----END EC PRIVATE KEY----- |
|||
@ -1,137 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.azure.servicebus; |
|||
|
|||
import com.microsoft.azure.servicebus.management.ManagementClient; |
|||
import com.microsoft.azure.servicebus.management.QueueDescription; |
|||
import com.microsoft.azure.servicebus.primitives.ConnectionStringBuilder; |
|||
import com.microsoft.azure.servicebus.primitives.MessagingEntityAlreadyExistsException; |
|||
import com.microsoft.azure.servicebus.primitives.ServiceBusException; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.util.PropertyUtils; |
|||
|
|||
import java.io.IOException; |
|||
import java.time.Duration; |
|||
import java.util.Map; |
|||
import java.util.Set; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
|
|||
@Slf4j |
|||
@Deprecated(forRemoval = true, since = "3.9") // for removal in 4.0
|
|||
public class TbServiceBusAdmin implements TbQueueAdmin { |
|||
private final String MAX_SIZE = "maxSizeInMb"; |
|||
private final String MESSAGE_TIME_TO_LIVE = "messageTimeToLiveInSec"; |
|||
private final String LOCK_DURATION = "lockDurationInSec"; |
|||
|
|||
private final Map<String, String> queueConfigs; |
|||
private final Set<String> queues = ConcurrentHashMap.newKeySet(); |
|||
|
|||
private final ManagementClient client; |
|||
|
|||
public TbServiceBusAdmin(TbServiceBusSettings serviceBusSettings, Map<String, String> queueConfigs) { |
|||
this.queueConfigs = queueConfigs; |
|||
|
|||
ConnectionStringBuilder builder = new ConnectionStringBuilder( |
|||
serviceBusSettings.getNamespaceName(), |
|||
"queues", |
|||
serviceBusSettings.getSasKeyName(), |
|||
serviceBusSettings.getSasKey()); |
|||
|
|||
client = new ManagementClient(builder); |
|||
|
|||
try { |
|||
client.getQueues().forEach(queueDescription -> queues.add(queueDescription.getPath())); |
|||
} catch (ServiceBusException | InterruptedException e) { |
|||
log.error("Failed to get queues.", e); |
|||
throw new RuntimeException("Failed to get queues.", e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void createTopicIfNotExists(String topic, String properties) { |
|||
if (queues.contains(topic)) { |
|||
return; |
|||
} |
|||
|
|||
try { |
|||
QueueDescription queueDescription = new QueueDescription(topic); |
|||
queueDescription.setRequiresDuplicateDetection(false); |
|||
setQueueConfigs(queueDescription, PropertyUtils.getProps(queueConfigs, properties)); |
|||
|
|||
client.createQueue(queueDescription); |
|||
queues.add(topic); |
|||
} catch (ServiceBusException | InterruptedException e) { |
|||
if (e instanceof MessagingEntityAlreadyExistsException) { |
|||
queues.add(topic); |
|||
log.info("[{}] queue already exists.", topic); |
|||
} else { |
|||
log.error("Failed to create queue: [{}]", topic, e); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void deleteTopic(String topic) { |
|||
if (queues.contains(topic)) { |
|||
doDelete(topic); |
|||
} else { |
|||
try { |
|||
if (client.getQueue(topic) != null) { |
|||
doDelete(topic); |
|||
} else { |
|||
log.warn("Azure Service Bus Queue [{}] is not exist.", topic); |
|||
} |
|||
} catch (ServiceBusException | InterruptedException e) { |
|||
log.error("Failed to delete Azure Service Bus queue [{}]", topic, e); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private void doDelete(String topic) { |
|||
try { |
|||
client.deleteTopic(topic); |
|||
} catch (ServiceBusException | InterruptedException e) { |
|||
log.error("Failed to delete Azure Service Bus queue [{}]", topic, e); |
|||
} |
|||
} |
|||
|
|||
private void setQueueConfigs(QueueDescription queueDescription, Map<String, String> queueConfigs) { |
|||
queueConfigs.forEach((confKey, confValue) -> { |
|||
switch (confKey) { |
|||
case MAX_SIZE: |
|||
queueDescription.setMaxSizeInMB(Long.parseLong(confValue)); |
|||
break; |
|||
case MESSAGE_TIME_TO_LIVE: |
|||
queueDescription.setDefaultMessageTimeToLive(Duration.ofSeconds(Long.parseLong(confValue))); |
|||
break; |
|||
case LOCK_DURATION: |
|||
queueDescription.setLockDuration(Duration.ofSeconds(Long.parseLong(confValue))); |
|||
break; |
|||
default: |
|||
log.error("Unknown config: [{}]", confKey); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public void destroy() { |
|||
try { |
|||
client.close(); |
|||
} catch (IOException e) { |
|||
log.error("Failed to close ManagementClient."); |
|||
} |
|||
} |
|||
} |
|||
@ -1,175 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.azure.servicebus; |
|||
|
|||
import com.google.gson.Gson; |
|||
import com.google.protobuf.InvalidProtocolBufferException; |
|||
import com.microsoft.azure.servicebus.TransactionContext; |
|||
import com.microsoft.azure.servicebus.primitives.ConnectionStringBuilder; |
|||
import com.microsoft.azure.servicebus.primitives.CoreMessageReceiver; |
|||
import com.microsoft.azure.servicebus.primitives.MessageWithDeliveryTag; |
|||
import com.microsoft.azure.servicebus.primitives.MessagingEntityType; |
|||
import com.microsoft.azure.servicebus.primitives.MessagingFactory; |
|||
import com.microsoft.azure.servicebus.primitives.SettleModePair; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.qpid.proton.amqp.messaging.Data; |
|||
import org.apache.qpid.proton.amqp.transport.ReceiverSettleMode; |
|||
import org.apache.qpid.proton.amqp.transport.SenderSettleMode; |
|||
import org.springframework.util.CollectionUtils; |
|||
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueMsg; |
|||
import org.thingsboard.server.queue.TbQueueMsgDecoder; |
|||
import org.thingsboard.server.queue.common.AbstractTbQueueConsumerTemplate; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueMsg; |
|||
|
|||
import java.time.Duration; |
|||
import java.util.Collection; |
|||
import java.util.Collections; |
|||
import java.util.HashSet; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.Set; |
|||
import java.util.concurrent.CompletableFuture; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.concurrent.ExecutionException; |
|||
import java.util.stream.Collectors; |
|||
import java.util.stream.Stream; |
|||
|
|||
@Slf4j |
|||
public class TbServiceBusConsumerTemplate<T extends TbQueueMsg> extends AbstractTbQueueConsumerTemplate<MessageWithDeliveryTag, T> { |
|||
private final TbQueueAdmin admin; |
|||
private final TbQueueMsgDecoder<T> decoder; |
|||
private final TbServiceBusSettings serviceBusSettings; |
|||
|
|||
private final Gson gson = new Gson(); |
|||
|
|||
private Set<CoreMessageReceiver> receivers; |
|||
private final Map<CoreMessageReceiver, Collection<MessageWithDeliveryTag>> pendingMessages = new ConcurrentHashMap<>(); |
|||
private volatile int messagesPerQueue; |
|||
|
|||
public TbServiceBusConsumerTemplate(TbQueueAdmin admin, TbServiceBusSettings serviceBusSettings, String topic, TbQueueMsgDecoder<T> decoder) { |
|||
super(topic); |
|||
this.admin = admin; |
|||
this.decoder = decoder; |
|||
this.serviceBusSettings = serviceBusSettings; |
|||
} |
|||
|
|||
@Override |
|||
protected List<MessageWithDeliveryTag> doPoll(long durationInMillis) { |
|||
List<CompletableFuture<Collection<MessageWithDeliveryTag>>> messageFutures = |
|||
receivers.stream() |
|||
.map(receiver -> receiver |
|||
.receiveAsync(messagesPerQueue, Duration.ofMillis(durationInMillis)) |
|||
.whenComplete((messages, err) -> { |
|||
if (!CollectionUtils.isEmpty(messages)) { |
|||
pendingMessages.put(receiver, messages); |
|||
} else if (err != null) { |
|||
log.error("Failed to receive messages.", err); |
|||
} |
|||
})) |
|||
.collect(Collectors.toList()); |
|||
try { |
|||
return fromList(messageFutures) |
|||
.get() |
|||
.stream() |
|||
.flatMap(messages -> CollectionUtils.isEmpty(messages) ? Stream.empty() : messages.stream()) |
|||
.collect(Collectors.toList()); |
|||
} catch (InterruptedException | ExecutionException e) { |
|||
if (stopped) { |
|||
log.info("[{}] Service Bus consumer is stopped.", getTopic()); |
|||
} else { |
|||
log.error("Failed to receive messages", e); |
|||
} |
|||
return Collections.emptyList(); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
protected void doSubscribe(List<String> topicNames) { |
|||
createReceivers(); |
|||
messagesPerQueue = receivers.size() / Math.max(partitions.size(), 1); |
|||
} |
|||
|
|||
@Override |
|||
protected void doCommit() { |
|||
pendingMessages.forEach((receiver, msgs) -> |
|||
msgs.forEach(msg -> receiver.completeMessageAsync(msg.getDeliveryTag(), TransactionContext.NULL_TXN))); |
|||
pendingMessages.clear(); |
|||
} |
|||
|
|||
@Override |
|||
protected void doUnsubscribe() { |
|||
receivers.forEach(CoreMessageReceiver::closeAsync); |
|||
} |
|||
|
|||
private void createReceivers() { |
|||
List<CompletableFuture<CoreMessageReceiver>> receiverFutures = partitions.stream() |
|||
.map(TopicPartitionInfo::getFullTopicName) |
|||
.map(queue -> { |
|||
MessagingFactory factory; |
|||
try { |
|||
factory = MessagingFactory.createFromConnectionStringBuilder(createConnection(queue)); |
|||
} catch (InterruptedException | ExecutionException e) { |
|||
log.error("Failed to create factory for the queue [{}]", queue); |
|||
throw new RuntimeException("Failed to create the factory", e); |
|||
} |
|||
|
|||
return CoreMessageReceiver.create(factory, queue, queue, 0, |
|||
new SettleModePair(SenderSettleMode.UNSETTLED, ReceiverSettleMode.SECOND), |
|||
MessagingEntityType.QUEUE); |
|||
}).collect(Collectors.toList()); |
|||
|
|||
try { |
|||
receivers = new HashSet<>(fromList(receiverFutures).get()); |
|||
} catch (InterruptedException | ExecutionException e) { |
|||
if (stopped) { |
|||
log.info("[{}] Service Bus consumer is stopped.", getTopic()); |
|||
} else { |
|||
log.error("Failed to create receivers", e); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private ConnectionStringBuilder createConnection(String queue) { |
|||
admin.createTopicIfNotExists(queue); |
|||
return new ConnectionStringBuilder( |
|||
serviceBusSettings.getNamespaceName(), |
|||
queue, |
|||
serviceBusSettings.getSasKeyName(), |
|||
serviceBusSettings.getSasKey()); |
|||
} |
|||
|
|||
private <V> CompletableFuture<List<V>> fromList(List<CompletableFuture<V>> futures) { |
|||
@SuppressWarnings("unchecked") |
|||
CompletableFuture<Collection<V>>[] arrayFuture = new CompletableFuture[futures.size()]; |
|||
futures.toArray(arrayFuture); |
|||
|
|||
return CompletableFuture |
|||
.allOf(arrayFuture) |
|||
.thenApply(v -> futures |
|||
.stream() |
|||
.map(CompletableFuture::join) |
|||
.collect(Collectors.toList())); |
|||
} |
|||
|
|||
@Override |
|||
protected T decode(MessageWithDeliveryTag data) throws InvalidProtocolBufferException { |
|||
DefaultTbQueueMsg msg = gson.fromJson(new String(((Data) data.getMessage().getBody()).getValue().getArray()), DefaultTbQueueMsg.class); |
|||
return decoder.decode(msg); |
|||
} |
|||
|
|||
} |
|||
@ -1,110 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.azure.servicebus; |
|||
|
|||
import com.google.gson.Gson; |
|||
import com.microsoft.azure.servicebus.IMessage; |
|||
import com.microsoft.azure.servicebus.Message; |
|||
import com.microsoft.azure.servicebus.QueueClient; |
|||
import com.microsoft.azure.servicebus.ReceiveMode; |
|||
import com.microsoft.azure.servicebus.primitives.ConnectionStringBuilder; |
|||
import com.microsoft.azure.servicebus.primitives.ServiceBusException; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueCallback; |
|||
import org.thingsboard.server.queue.TbQueueMsg; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueMsg; |
|||
|
|||
import java.util.Map; |
|||
import java.util.concurrent.CompletableFuture; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.concurrent.ExecutorService; |
|||
import java.util.concurrent.Executors; |
|||
|
|||
@Slf4j |
|||
public class TbServiceBusProducerTemplate<T extends TbQueueMsg> implements TbQueueProducer<T> { |
|||
private final String defaultTopic; |
|||
private final Gson gson = new Gson(); |
|||
private final TbQueueAdmin admin; |
|||
private final TbServiceBusSettings serviceBusSettings; |
|||
private final Map<String, QueueClient> clients = new ConcurrentHashMap<>(); |
|||
private final ExecutorService executorService; |
|||
|
|||
public TbServiceBusProducerTemplate(TbQueueAdmin admin, TbServiceBusSettings serviceBusSettings, String defaultTopic) { |
|||
this.admin = admin; |
|||
this.defaultTopic = defaultTopic; |
|||
this.serviceBusSettings = serviceBusSettings; |
|||
executorService = Executors.newCachedThreadPool(); |
|||
} |
|||
|
|||
@Override |
|||
public void init() { |
|||
|
|||
} |
|||
|
|||
@Override |
|||
public String getDefaultTopic() { |
|||
return defaultTopic; |
|||
} |
|||
|
|||
@Override |
|||
public void send(TopicPartitionInfo tpi, T msg, TbQueueCallback callback) { |
|||
IMessage message = new Message(gson.toJson(new DefaultTbQueueMsg(msg))); |
|||
CompletableFuture<Void> future = getClient(tpi.getFullTopicName()).sendAsync(message); |
|||
future.whenCompleteAsync((success, err) -> { |
|||
if (err != null) { |
|||
callback.onFailure(err); |
|||
} else { |
|||
callback.onSuccess(null); |
|||
} |
|||
}, executorService); |
|||
} |
|||
|
|||
@Override |
|||
public void stop() { |
|||
clients.forEach((t, client) -> { |
|||
try { |
|||
client.close(); |
|||
} catch (ServiceBusException e) { |
|||
log.error("Failed to close QueueClient.", e); |
|||
} |
|||
}); |
|||
|
|||
if (executorService != null) { |
|||
executorService.shutdownNow(); |
|||
} |
|||
} |
|||
|
|||
private QueueClient getClient(String topic) { |
|||
return clients.computeIfAbsent(topic, k -> { |
|||
admin.createTopicIfNotExists(topic); |
|||
ConnectionStringBuilder builder = |
|||
new ConnectionStringBuilder( |
|||
serviceBusSettings.getNamespaceName(), |
|||
topic, |
|||
serviceBusSettings.getSasKeyName(), |
|||
serviceBusSettings.getSasKey()); |
|||
try { |
|||
return new QueueClient(builder, ReceiveMode.PEEKLOCK); |
|||
} catch (InterruptedException | ServiceBusException e) { |
|||
log.error("Failed to create new client for the Queue: [{}]", topic, e); |
|||
throw new RuntimeException("Failed to create new client for the Queue", e); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
@ -1,72 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.azure.servicebus; |
|||
|
|||
import jakarta.annotation.PostConstruct; |
|||
import lombok.Getter; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.queue.util.PropertyUtils; |
|||
|
|||
import java.util.Map; |
|||
|
|||
@Component |
|||
@ConditionalOnExpression("'${queue.type:null}'=='service-bus'") |
|||
public class TbServiceBusQueueConfigs { |
|||
|
|||
@Value("${queue.service-bus.queue-properties.core:}") |
|||
private String coreProperties; |
|||
@Value("${queue.service-bus.queue-properties.rule-engine:}") |
|||
private String ruleEngineProperties; |
|||
@Value("${queue.service-bus.queue-properties.transport-api:}") |
|||
private String transportApiProperties; |
|||
@Value("${queue.service-bus.queue-properties.notifications:}") |
|||
private String notificationsProperties; |
|||
@Value("${queue.service-bus.queue-properties.js-executor:}") |
|||
private String jsExecutorProperties; |
|||
@Value("${queue.service-bus.queue-properties.version-control:}") |
|||
private String vcProperties; |
|||
@Value("${queue.service-bus.queue-properties.edge:}") |
|||
private String edgeProperties; |
|||
|
|||
@Getter |
|||
private Map<String, String> coreConfigs; |
|||
@Getter |
|||
private Map<String, String> ruleEngineConfigs; |
|||
@Getter |
|||
private Map<String, String> transportApiConfigs; |
|||
@Getter |
|||
private Map<String, String> notificationsConfigs; |
|||
@Getter |
|||
private Map<String, String> jsExecutorConfigs; |
|||
@Getter |
|||
private Map<String, String> vcConfigs; |
|||
@Getter |
|||
private Map<String, String> edgeConfigs; |
|||
|
|||
@PostConstruct |
|||
private void init() { |
|||
coreConfigs = PropertyUtils.getProps(coreProperties); |
|||
ruleEngineConfigs = PropertyUtils.getProps(ruleEngineProperties); |
|||
transportApiConfigs = PropertyUtils.getProps(transportApiProperties); |
|||
notificationsConfigs = PropertyUtils.getProps(notificationsProperties); |
|||
jsExecutorConfigs = PropertyUtils.getProps(jsExecutorProperties); |
|||
vcConfigs = PropertyUtils.getProps(vcProperties); |
|||
edgeConfigs = PropertyUtils.getProps(edgeProperties); |
|||
} |
|||
|
|||
} |
|||
@ -1,37 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.azure.servicebus; |
|||
|
|||
import lombok.Data; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
@Slf4j |
|||
@ConditionalOnExpression("'${queue.type:null}'=='service-bus'") |
|||
@Component |
|||
@Data |
|||
public class TbServiceBusSettings { |
|||
@Value("${queue.service_bus.namespace_name}") |
|||
private String namespaceName; |
|||
@Value("${queue.service_bus.sas_key_name}") |
|||
private String sasKeyName; |
|||
@Value("${queue.service_bus.sas_key}") |
|||
private String sasKey; |
|||
@Value("${queue.service_bus.max_messages}") |
|||
private int maxMessages; |
|||
} |
|||
@ -1,317 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.provider; |
|||
|
|||
import com.google.protobuf.util.JsonFormat; |
|||
import jakarta.annotation.PreDestroy; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.queue.Queue; |
|||
import org.thingsboard.server.common.msg.queue.ServiceType; |
|||
import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsRequest; |
|||
import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsResponse; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeEventNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueConsumer; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.TbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; |
|||
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|||
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
|||
import org.thingsboard.server.queue.discovery.TopicService; |
|||
import org.thingsboard.server.queue.settings.TbQueueCoreSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueEdgeSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueVersionControlSettings; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsAdmin; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsConsumerTemplate; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsProducerTemplate; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsQueueAttributes; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsSettings; |
|||
|
|||
import java.nio.charset.StandardCharsets; |
|||
|
|||
@Component |
|||
@ConditionalOnExpression("'${queue.type:null}'=='aws-sqs' && '${service.type:null}'=='monolith'") |
|||
public class AwsSqsMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngineQueueFactory, TbVersionControlQueueFactory { |
|||
|
|||
private final TopicService topicService; |
|||
private final TbQueueCoreSettings coreSettings; |
|||
private final TbServiceInfoProvider serviceInfoProvider; |
|||
private final TbQueueRuleEngineSettings ruleEngineSettings; |
|||
private final TbQueueTransportApiSettings transportApiSettings; |
|||
private final TbQueueTransportNotificationSettings transportNotificationSettings; |
|||
private final TbAwsSqsSettings sqsSettings; |
|||
private final TbQueueVersionControlSettings vcSettings; |
|||
private final TbQueueEdgeSettings edgeSettings; |
|||
private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; |
|||
|
|||
private final TbQueueAdmin coreAdmin; |
|||
private final TbQueueAdmin ruleEngineAdmin; |
|||
private final TbQueueAdmin jsExecutorAdmin; |
|||
private final TbQueueAdmin transportApiAdmin; |
|||
private final TbQueueAdmin notificationAdmin; |
|||
private final TbQueueAdmin otaAdmin; |
|||
private final TbQueueAdmin vcAdmin; |
|||
private final TbQueueAdmin edgeAdmin; |
|||
|
|||
public AwsSqsMonolithQueueFactory(TopicService topicService, TbQueueCoreSettings coreSettings, |
|||
TbQueueRuleEngineSettings ruleEngineSettings, |
|||
TbServiceInfoProvider serviceInfoProvider, |
|||
TbQueueTransportApiSettings transportApiSettings, |
|||
TbQueueTransportNotificationSettings transportNotificationSettings, |
|||
TbAwsSqsSettings sqsSettings, |
|||
TbQueueVersionControlSettings vcSettings, |
|||
TbQueueEdgeSettings edgeSettings, |
|||
TbAwsSqsQueueAttributes sqsQueueAttributes, |
|||
TbQueueRemoteJsInvokeSettings jsInvokeSettings) { |
|||
this.topicService = topicService; |
|||
this.coreSettings = coreSettings; |
|||
this.serviceInfoProvider = serviceInfoProvider; |
|||
this.ruleEngineSettings = ruleEngineSettings; |
|||
this.transportApiSettings = transportApiSettings; |
|||
this.transportNotificationSettings = transportNotificationSettings; |
|||
this.sqsSettings = sqsSettings; |
|||
this.vcSettings = vcSettings; |
|||
this.edgeSettings = edgeSettings; |
|||
this.jsInvokeSettings = jsInvokeSettings; |
|||
|
|||
this.coreAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getCoreAttributes()); |
|||
this.ruleEngineAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getRuleEngineAttributes()); |
|||
this.jsExecutorAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getJsExecutorAttributes()); |
|||
this.transportApiAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getTransportApiAttributes()); |
|||
this.notificationAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getNotificationsAttributes()); |
|||
this.otaAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getOtaAttributes()); |
|||
this.vcAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getVcAttributes()); |
|||
this.edgeAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getEdgeAttributes()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToTransportMsg>> createTransportNotificationsMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(notificationAdmin, sqsSettings, topicService.buildTopicName(transportNotificationSettings.getNotificationsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> createRuleEngineMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(ruleEngineAdmin, sqsSettings, topicService.buildTopicName(ruleEngineSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> createRuleEngineNotificationsMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(notificationAdmin, sqsSettings, topicService.buildTopicName(ruleEngineSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> createTbCoreMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> createTbCoreNotificationsMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(notificationAdmin, sqsSettings, |
|||
topicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToVersionControlServiceMsg>> createToVersionControlMsgConsumer() { |
|||
return new TbAwsSqsConsumerTemplate<>(vcAdmin, sqsSettings, topicService.buildTopicName(vcSettings.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToVersionControlServiceMsg.parseFrom(msg.getData()), msg.getHeaders()) |
|||
); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineMsg>> createToRuleEngineMsgConsumer(Queue configuration) { |
|||
return new TbAwsSqsConsumerTemplate<>(ruleEngineAdmin, sqsSettings, topicService.buildTopicName(configuration.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> createToRuleEngineNotificationsMsgConsumer() { |
|||
return new TbAwsSqsConsumerTemplate<>(notificationAdmin, sqsSettings, |
|||
topicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToCoreMsg>> createToCoreMsgConsumer() { |
|||
return new TbAwsSqsConsumerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToCoreNotificationMsg>> createToCoreNotificationsMsgConsumer() { |
|||
return new TbAwsSqsConsumerTemplate<>(notificationAdmin, sqsSettings, |
|||
topicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<TransportApiRequestMsg>> createTransportApiRequestConsumer() { |
|||
return new TbAwsSqsConsumerTemplate<>(transportApiAdmin, sqsSettings, topicService.buildTopicName(transportApiSettings.getRequestsTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiRequestMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<TransportApiResponseMsg>> createTransportApiResponseProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(transportApiAdmin, sqsSettings, topicService.buildTopicName(transportApiSettings.getResponsesTopic())); |
|||
} |
|||
|
|||
@Override |
|||
@Bean |
|||
public TbQueueRequestTemplate<TbProtoJsQueueMsg<RemoteJsRequest>, TbProtoQueueMsg<RemoteJsResponse>> createRemoteJsRequestTemplate() { |
|||
TbQueueProducer<TbProtoJsQueueMsg<RemoteJsRequest>> producer = new TbAwsSqsProducerTemplate<>(jsExecutorAdmin, sqsSettings, jsInvokeSettings.getRequestTopic()); |
|||
TbQueueConsumer<TbProtoQueueMsg<RemoteJsResponse>> consumer = new TbAwsSqsConsumerTemplate<>(jsExecutorAdmin, sqsSettings, |
|||
jsInvokeSettings.getResponseTopic() + "_" + serviceInfoProvider.getServiceId(), |
|||
msg -> { |
|||
RemoteJsResponse.Builder builder = RemoteJsResponse.newBuilder(); |
|||
JsonFormat.parser().ignoringUnknownFields().merge(new String(msg.getData(), StandardCharsets.UTF_8), builder); |
|||
return new TbProtoQueueMsg<>(msg.getKey(), builder.build(), msg.getHeaders()); |
|||
}); |
|||
|
|||
DefaultTbQueueRequestTemplate.DefaultTbQueueRequestTemplateBuilder |
|||
<TbProtoJsQueueMsg<RemoteJsRequest>, TbProtoQueueMsg<RemoteJsResponse>> builder = DefaultTbQueueRequestTemplate.builder(); |
|||
builder.queueAdmin(jsExecutorAdmin); |
|||
builder.requestTemplate(producer); |
|||
builder.responseTemplate(consumer); |
|||
builder.maxPendingRequests(jsInvokeSettings.getMaxPendingRequests()); |
|||
builder.maxRequestTimeout(jsInvokeSettings.getMaxRequestsTimeout()); |
|||
builder.pollInterval(jsInvokeSettings.getResponsePollInterval()); |
|||
return builder.build(); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgConsumer() { |
|||
return new TbAwsSqsConsumerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgConsumer() { |
|||
return new TbAwsSqsConsumerTemplate<>(otaAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getOtaPackageTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToOtaPackageStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(otaAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getOtaPackageTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToVersionControlServiceMsg>> createVersionControlMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(vcAdmin, sqsSettings, topicService.buildTopicName(vcSettings.getTopic())); |
|||
} |
|||
|
|||
public TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperMsgConsumer() { |
|||
return new TbAwsSqsConsumerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToHousekeeperServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperReprocessingMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getHousekeeperReprocessingTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperReprocessingMsgConsumer() { |
|||
return new TbAwsSqsConsumerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getHousekeeperReprocessingTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToHousekeeperServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToEdgeMsg>> createEdgeMsgConsumer() { |
|||
return new TbAwsSqsConsumerTemplate<>(edgeAdmin, sqsSettings, topicService.buildTopicName(edgeSettings.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToEdgeMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeMsg>> createEdgeMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(edgeAdmin, sqsSettings, topicService.buildTopicName(edgeSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createToEdgeNotificationsMsgConsumer() { |
|||
return new TbAwsSqsConsumerTemplate<>(notificationAdmin, sqsSettings, |
|||
topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToEdgeNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(notificationAdmin, sqsSettings, |
|||
topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> createEdgeEventMsgProducer() { |
|||
return null; |
|||
} |
|||
|
|||
@PreDestroy |
|||
private void destroy() { |
|||
if (coreAdmin != null) { |
|||
coreAdmin.destroy(); |
|||
} |
|||
if (ruleEngineAdmin != null) { |
|||
ruleEngineAdmin.destroy(); |
|||
} |
|||
if (jsExecutorAdmin != null) { |
|||
jsExecutorAdmin.destroy(); |
|||
} |
|||
if (transportApiAdmin != null) { |
|||
transportApiAdmin.destroy(); |
|||
} |
|||
if (notificationAdmin != null) { |
|||
notificationAdmin.destroy(); |
|||
} |
|||
if (otaAdmin != null) { |
|||
otaAdmin.destroy(); |
|||
} |
|||
if (vcAdmin != null) { |
|||
vcAdmin.destroy(); |
|||
} |
|||
if (edgeAdmin != null) { |
|||
edgeAdmin.destroy(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,291 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.provider; |
|||
|
|||
import com.google.protobuf.util.JsonFormat; |
|||
import jakarta.annotation.PreDestroy; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.msg.queue.ServiceType; |
|||
import org.thingsboard.server.gen.js.JsInvokeProtos; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueConsumer; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.TbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; |
|||
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|||
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
|||
import org.thingsboard.server.queue.discovery.TopicService; |
|||
import org.thingsboard.server.queue.settings.TbQueueCoreSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueEdgeSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueVersionControlSettings; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsAdmin; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsConsumerTemplate; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsProducerTemplate; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsQueueAttributes; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsSettings; |
|||
|
|||
import java.nio.charset.StandardCharsets; |
|||
|
|||
@Component |
|||
@ConditionalOnExpression("'${queue.type:null}'=='aws-sqs' && '${service.type:null}'=='tb-core'") |
|||
public class AwsSqsTbCoreQueueFactory implements TbCoreQueueFactory { |
|||
|
|||
private final TbAwsSqsSettings sqsSettings; |
|||
private final TbQueueRuleEngineSettings ruleEngineSettings; |
|||
private final TbQueueCoreSettings coreSettings; |
|||
private final TbQueueTransportApiSettings transportApiSettings; |
|||
private final TopicService topicService; |
|||
private final TbServiceInfoProvider serviceInfoProvider; |
|||
private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; |
|||
private final TbQueueTransportNotificationSettings transportNotificationSettings; |
|||
private final TbQueueVersionControlSettings vcSettings; |
|||
private final TbQueueEdgeSettings edgeSettings; |
|||
|
|||
private final TbQueueAdmin coreAdmin; |
|||
private final TbQueueAdmin ruleEngineAdmin; |
|||
private final TbQueueAdmin jsExecutorAdmin; |
|||
private final TbQueueAdmin transportApiAdmin; |
|||
private final TbQueueAdmin notificationAdmin; |
|||
private final TbQueueAdmin otaAdmin; |
|||
private final TbQueueAdmin vcAdmin; |
|||
private final TbQueueAdmin edgeAdmin; |
|||
|
|||
public AwsSqsTbCoreQueueFactory(TbAwsSqsSettings sqsSettings, |
|||
TbQueueCoreSettings coreSettings, |
|||
TbQueueTransportApiSettings transportApiSettings, |
|||
TbQueueRuleEngineSettings ruleEngineSettings, |
|||
TopicService topicService, |
|||
TbQueueVersionControlSettings vcSettings, |
|||
TbQueueEdgeSettings edgeSettings, |
|||
TbServiceInfoProvider serviceInfoProvider, |
|||
TbQueueRemoteJsInvokeSettings jsInvokeSettings, |
|||
TbAwsSqsQueueAttributes sqsQueueAttributes, |
|||
TbQueueTransportNotificationSettings transportNotificationSettings) { |
|||
this.sqsSettings = sqsSettings; |
|||
this.coreSettings = coreSettings; |
|||
this.transportApiSettings = transportApiSettings; |
|||
this.ruleEngineSettings = ruleEngineSettings; |
|||
this.edgeSettings = edgeSettings; |
|||
this.topicService = topicService; |
|||
this.serviceInfoProvider = serviceInfoProvider; |
|||
this.jsInvokeSettings = jsInvokeSettings; |
|||
this.transportNotificationSettings = transportNotificationSettings; |
|||
this.vcSettings = vcSettings; |
|||
|
|||
this.coreAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getCoreAttributes()); |
|||
this.ruleEngineAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getRuleEngineAttributes()); |
|||
this.jsExecutorAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getJsExecutorAttributes()); |
|||
this.transportApiAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getTransportApiAttributes()); |
|||
this.notificationAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getNotificationsAttributes()); |
|||
this.otaAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getOtaAttributes()); |
|||
this.vcAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getVcAttributes()); |
|||
this.edgeAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getEdgeAttributes()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToTransportMsg>> createTransportNotificationsMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(notificationAdmin, sqsSettings, topicService.buildTopicName(transportNotificationSettings.getNotificationsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> createRuleEngineMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> createRuleEngineNotificationsMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(notificationAdmin, sqsSettings, topicService.buildTopicName(ruleEngineSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> createTbCoreMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> createTbCoreNotificationsMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(notificationAdmin, sqsSettings, |
|||
topicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToCoreMsg>> createToCoreMsgConsumer() { |
|||
return new TbAwsSqsConsumerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToCoreNotificationMsg>> createToCoreNotificationsMsgConsumer() { |
|||
return new TbAwsSqsConsumerTemplate<>(notificationAdmin, sqsSettings, |
|||
topicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<TransportApiRequestMsg>> createTransportApiRequestConsumer() { |
|||
return new TbAwsSqsConsumerTemplate<>(transportApiAdmin, sqsSettings, topicService.buildTopicName(transportApiSettings.getRequestsTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiRequestMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<TransportApiResponseMsg>> createTransportApiResponseProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(transportApiAdmin, sqsSettings, topicService.buildTopicName(transportApiSettings.getResponsesTopic())); |
|||
} |
|||
|
|||
@Override |
|||
@Bean |
|||
public TbQueueRequestTemplate<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>, TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> createRemoteJsRequestTemplate() { |
|||
TbQueueProducer<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>> producer = new TbAwsSqsProducerTemplate<>(jsExecutorAdmin, sqsSettings, jsInvokeSettings.getRequestTopic()); |
|||
TbQueueConsumer<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> consumer = new TbAwsSqsConsumerTemplate<>(jsExecutorAdmin, sqsSettings, |
|||
jsInvokeSettings.getResponseTopic() + "_" + serviceInfoProvider.getServiceId(), |
|||
msg -> { |
|||
JsInvokeProtos.RemoteJsResponse.Builder builder = JsInvokeProtos.RemoteJsResponse.newBuilder(); |
|||
JsonFormat.parser().ignoringUnknownFields().merge(new String(msg.getData(), StandardCharsets.UTF_8), builder); |
|||
return new TbProtoQueueMsg<>(msg.getKey(), builder.build(), msg.getHeaders()); |
|||
}); |
|||
|
|||
DefaultTbQueueRequestTemplate.DefaultTbQueueRequestTemplateBuilder |
|||
<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>, TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> builder = DefaultTbQueueRequestTemplate.builder(); |
|||
builder.queueAdmin(jsExecutorAdmin); |
|||
builder.requestTemplate(producer); |
|||
builder.responseTemplate(consumer); |
|||
builder.maxPendingRequests(jsInvokeSettings.getMaxPendingRequests()); |
|||
builder.maxRequestTimeout(jsInvokeSettings.getMaxRequestsTimeout()); |
|||
builder.pollInterval(jsInvokeSettings.getResponsePollInterval()); |
|||
return builder.build(); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgConsumer() { |
|||
return new TbAwsSqsConsumerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgConsumer() { |
|||
return new TbAwsSqsConsumerTemplate<>(otaAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getOtaPackageTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToOtaPackageStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(otaAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getOtaPackageTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToVersionControlServiceMsg>> createVersionControlMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(vcAdmin, sqsSettings, topicService.buildTopicName(vcSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperMsgConsumer() { |
|||
return new TbAwsSqsConsumerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToHousekeeperServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperReprocessingMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getHousekeeperReprocessingTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperReprocessingMsgConsumer() { |
|||
return new TbAwsSqsConsumerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getHousekeeperReprocessingTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToHousekeeperServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToEdgeMsg>> createEdgeMsgConsumer() { |
|||
return new TbAwsSqsConsumerTemplate<>(edgeAdmin, sqsSettings, topicService.buildTopicName(edgeSettings.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToEdgeMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeMsg>> createEdgeMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(edgeAdmin, sqsSettings, topicService.buildTopicName(edgeSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createToEdgeNotificationsMsgConsumer() { |
|||
return new TbAwsSqsConsumerTemplate<>(notificationAdmin, sqsSettings, |
|||
topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToEdgeNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(notificationAdmin, sqsSettings, |
|||
topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName()); |
|||
} |
|||
|
|||
@PreDestroy |
|||
private void destroy() { |
|||
if (coreAdmin != null) { |
|||
coreAdmin.destroy(); |
|||
} |
|||
if (ruleEngineAdmin != null) { |
|||
ruleEngineAdmin.destroy(); |
|||
} |
|||
if (jsExecutorAdmin != null) { |
|||
jsExecutorAdmin.destroy(); |
|||
} |
|||
if (transportApiAdmin != null) { |
|||
transportApiAdmin.destroy(); |
|||
} |
|||
if (notificationAdmin != null) { |
|||
notificationAdmin.destroy(); |
|||
} |
|||
if (otaAdmin != null) { |
|||
otaAdmin.destroy(); |
|||
} |
|||
if (vcAdmin != null) { |
|||
vcAdmin.destroy(); |
|||
} |
|||
if (edgeAdmin != null) { |
|||
edgeAdmin.destroy(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,208 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.provider; |
|||
|
|||
import com.google.protobuf.util.JsonFormat; |
|||
import jakarta.annotation.PreDestroy; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.queue.Queue; |
|||
import org.thingsboard.server.common.msg.queue.ServiceType; |
|||
import org.thingsboard.server.gen.js.JsInvokeProtos; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueConsumer; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.TbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; |
|||
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|||
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
|||
import org.thingsboard.server.queue.discovery.TopicService; |
|||
import org.thingsboard.server.queue.settings.TbQueueCoreSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueEdgeSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsAdmin; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsConsumerTemplate; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsProducerTemplate; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsQueueAttributes; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsSettings; |
|||
|
|||
import java.nio.charset.StandardCharsets; |
|||
|
|||
@Component |
|||
@ConditionalOnExpression("'${queue.type:null}'=='aws-sqs' && '${service.type:null}'=='tb-rule-engine'") |
|||
public class AwsSqsTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory { |
|||
|
|||
private final TopicService topicService; |
|||
private final TbQueueCoreSettings coreSettings; |
|||
private final TbServiceInfoProvider serviceInfoProvider; |
|||
private final TbQueueRuleEngineSettings ruleEngineSettings; |
|||
private final TbAwsSqsSettings sqsSettings; |
|||
private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; |
|||
private final TbQueueTransportNotificationSettings transportNotificationSettings; |
|||
private final TbQueueEdgeSettings edgeSettings; |
|||
|
|||
private final TbQueueAdmin coreAdmin; |
|||
private final TbQueueAdmin ruleEngineAdmin; |
|||
private final TbQueueAdmin jsExecutorAdmin; |
|||
private final TbQueueAdmin notificationAdmin; |
|||
private final TbQueueAdmin otaAdmin; |
|||
private final TbQueueAdmin edgeAdmin; |
|||
|
|||
public AwsSqsTbRuleEngineQueueFactory(TopicService topicService, TbQueueCoreSettings coreSettings, |
|||
TbQueueRuleEngineSettings ruleEngineSettings, |
|||
TbServiceInfoProvider serviceInfoProvider, |
|||
TbAwsSqsSettings sqsSettings, |
|||
TbAwsSqsQueueAttributes sqsQueueAttributes, |
|||
TbQueueRemoteJsInvokeSettings jsInvokeSettings, |
|||
TbQueueTransportNotificationSettings transportNotificationSettings, |
|||
TbQueueEdgeSettings edgeSettings) { |
|||
this.topicService = topicService; |
|||
this.coreSettings = coreSettings; |
|||
this.serviceInfoProvider = serviceInfoProvider; |
|||
this.ruleEngineSettings = ruleEngineSettings; |
|||
this.sqsSettings = sqsSettings; |
|||
this.jsInvokeSettings = jsInvokeSettings; |
|||
this.transportNotificationSettings = transportNotificationSettings; |
|||
this.edgeSettings = edgeSettings; |
|||
|
|||
this.coreAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getCoreAttributes()); |
|||
this.ruleEngineAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getRuleEngineAttributes()); |
|||
this.jsExecutorAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getJsExecutorAttributes()); |
|||
this.notificationAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getNotificationsAttributes()); |
|||
this.otaAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getOtaAttributes()); |
|||
this.edgeAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getEdgeAttributes()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToTransportMsg>> createTransportNotificationsMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(notificationAdmin, sqsSettings, topicService.buildTopicName(transportNotificationSettings.getNotificationsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> createRuleEngineMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(ruleEngineAdmin, sqsSettings, topicService.buildTopicName(ruleEngineSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> createRuleEngineNotificationsMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(notificationAdmin, sqsSettings, topicService.buildTopicName(ruleEngineSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> createTbCoreMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> createTbCoreNotificationsMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(notificationAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeMsg>> createEdgeMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(edgeAdmin, sqsSettings, topicService.buildTopicName(edgeSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(notificationAdmin, sqsSettings, topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineMsg>> createToRuleEngineMsgConsumer(Queue configuration) { |
|||
return new TbAwsSqsConsumerTemplate<>(ruleEngineAdmin, sqsSettings, topicService.buildTopicName(configuration.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> createToRuleEngineNotificationsMsgConsumer() { |
|||
return new TbAwsSqsConsumerTemplate<>(notificationAdmin, sqsSettings, |
|||
topicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
@Bean |
|||
public TbQueueRequestTemplate<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>, TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> createRemoteJsRequestTemplate() { |
|||
TbQueueProducer<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>> producer = new TbAwsSqsProducerTemplate<>(jsExecutorAdmin, sqsSettings, jsInvokeSettings.getRequestTopic()); |
|||
TbQueueConsumer<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> consumer = new TbAwsSqsConsumerTemplate<>(jsExecutorAdmin, sqsSettings, |
|||
jsInvokeSettings.getResponseTopic() + "_" + serviceInfoProvider.getServiceId(), |
|||
msg -> { |
|||
JsInvokeProtos.RemoteJsResponse.Builder builder = JsInvokeProtos.RemoteJsResponse.newBuilder(); |
|||
JsonFormat.parser().ignoringUnknownFields().merge(new String(msg.getData(), StandardCharsets.UTF_8), builder); |
|||
return new TbProtoQueueMsg<>(msg.getKey(), builder.build(), msg.getHeaders()); |
|||
}); |
|||
|
|||
DefaultTbQueueRequestTemplate.DefaultTbQueueRequestTemplateBuilder |
|||
<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>, TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> builder = DefaultTbQueueRequestTemplate.builder(); |
|||
builder.queueAdmin(jsExecutorAdmin); |
|||
builder.requestTemplate(producer); |
|||
builder.responseTemplate(consumer); |
|||
builder.maxPendingRequests(jsInvokeSettings.getMaxPendingRequests()); |
|||
builder.maxRequestTimeout(jsInvokeSettings.getMaxRequestsTimeout()); |
|||
builder.pollInterval(jsInvokeSettings.getResponsePollInterval()); |
|||
return builder.build(); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(otaAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getOtaPackageTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic())); |
|||
} |
|||
|
|||
@PreDestroy |
|||
private void destroy() { |
|||
if (coreAdmin != null) { |
|||
coreAdmin.destroy(); |
|||
} |
|||
if (ruleEngineAdmin != null) { |
|||
ruleEngineAdmin.destroy(); |
|||
} |
|||
if (jsExecutorAdmin != null) { |
|||
jsExecutorAdmin.destroy(); |
|||
} |
|||
if (notificationAdmin != null) { |
|||
notificationAdmin.destroy(); |
|||
} |
|||
if (otaAdmin != null) { |
|||
otaAdmin.destroy(); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -1,98 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.provider; |
|||
|
|||
import jakarta.annotation.PreDestroy; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.gen.transport.TransportProtos; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueConsumer; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|||
import org.thingsboard.server.queue.discovery.TopicService; |
|||
import org.thingsboard.server.queue.settings.TbQueueCoreSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueVersionControlSettings; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsAdmin; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsConsumerTemplate; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsProducerTemplate; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsQueueAttributes; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsSettings; |
|||
|
|||
@Component |
|||
@ConditionalOnExpression("'${queue.type:null}'=='aws-sqs' && '${service.type:null}'=='tb-vc-executor'") |
|||
public class AwsSqsTbVersionControlQueueFactory implements TbVersionControlQueueFactory { |
|||
|
|||
private final TbAwsSqsSettings sqsSettings; |
|||
private final TbQueueCoreSettings coreSettings; |
|||
private final TbQueueVersionControlSettings vcSettings; |
|||
private final TopicService topicService; |
|||
|
|||
private final TbQueueAdmin coreAdmin; |
|||
private final TbQueueAdmin notificationAdmin; |
|||
private final TbQueueAdmin vcAdmin; |
|||
|
|||
public AwsSqsTbVersionControlQueueFactory(TbAwsSqsSettings sqsSettings, |
|||
TbQueueCoreSettings coreSettings, |
|||
TbQueueVersionControlSettings vcSettings, |
|||
TbAwsSqsQueueAttributes sqsQueueAttributes, |
|||
TopicService topicService |
|||
) { |
|||
this.sqsSettings = sqsSettings; |
|||
this.coreSettings = coreSettings; |
|||
this.vcSettings = vcSettings; |
|||
this.topicService = topicService; |
|||
|
|||
this.coreAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getCoreAttributes()); |
|||
this.notificationAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getNotificationsAttributes()); |
|||
this.vcAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getVcAttributes()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToCoreNotificationMsg>> createTbCoreNotificationsMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(notificationAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<TransportProtos.ToVersionControlServiceMsg>> createToVersionControlMsgConsumer() { |
|||
return new TbAwsSqsConsumerTemplate<>(vcAdmin, sqsSettings, topicService.buildTopicName(vcSettings.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportProtos.ToVersionControlServiceMsg.parseFrom(msg.getData()), msg.getHeaders()) |
|||
); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToHousekeeperServiceMsg>> createHousekeeperMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic())); |
|||
} |
|||
|
|||
@PreDestroy |
|||
private void destroy() { |
|||
if (coreAdmin != null) { |
|||
coreAdmin.destroy(); |
|||
} |
|||
if (notificationAdmin != null) { |
|||
notificationAdmin.destroy(); |
|||
} |
|||
if (vcAdmin != null) { |
|||
vcAdmin.destroy(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,153 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.provider; |
|||
|
|||
import jakarta.annotation.PreDestroy; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.gen.transport.TransportProtos; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueConsumer; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.TbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|||
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
|||
import org.thingsboard.server.queue.discovery.TopicService; |
|||
import org.thingsboard.server.queue.settings.TbQueueCoreSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsAdmin; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsConsumerTemplate; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsProducerTemplate; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsQueueAttributes; |
|||
import org.thingsboard.server.queue.sqs.TbAwsSqsSettings; |
|||
|
|||
@Component |
|||
@ConditionalOnExpression("'${queue.type:null}'=='aws-sqs' && (('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true') || '${service.type:null}'=='tb-transport')") |
|||
@Slf4j |
|||
public class AwsSqsTransportQueueFactory implements TbTransportQueueFactory { |
|||
private final TbQueueTransportApiSettings transportApiSettings; |
|||
private final TbQueueTransportNotificationSettings transportNotificationSettings; |
|||
private final TbAwsSqsSettings sqsSettings; |
|||
private final TbQueueCoreSettings coreSettings; |
|||
private final TbServiceInfoProvider serviceInfoProvider; |
|||
private final TbQueueRuleEngineSettings ruleEngineSettings; |
|||
private final TopicService topicService; |
|||
|
|||
private final TbQueueAdmin coreAdmin; |
|||
private final TbQueueAdmin transportApiAdmin; |
|||
private final TbQueueAdmin notificationAdmin; |
|||
private final TbQueueAdmin ruleEngineAdmin; |
|||
|
|||
public AwsSqsTransportQueueFactory(TbQueueTransportApiSettings transportApiSettings, |
|||
TbQueueTransportNotificationSettings transportNotificationSettings, |
|||
TbAwsSqsSettings sqsSettings, |
|||
TbServiceInfoProvider serviceInfoProvider, |
|||
TbQueueCoreSettings coreSettings, |
|||
TbAwsSqsQueueAttributes sqsQueueAttributes, |
|||
TbQueueRuleEngineSettings ruleEngineSettings, |
|||
TopicService topicService) { |
|||
this.transportApiSettings = transportApiSettings; |
|||
this.transportNotificationSettings = transportNotificationSettings; |
|||
this.sqsSettings = sqsSettings; |
|||
this.serviceInfoProvider = serviceInfoProvider; |
|||
this.coreSettings = coreSettings; |
|||
this.ruleEngineSettings = ruleEngineSettings; |
|||
this.topicService = topicService; |
|||
|
|||
this.coreAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getCoreAttributes()); |
|||
this.transportApiAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getTransportApiAttributes()); |
|||
this.notificationAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getNotificationsAttributes()); |
|||
this.ruleEngineAdmin = new TbAwsSqsAdmin(sqsSettings, sqsQueueAttributes.getRuleEngineAttributes()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueRequestTemplate<TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> createTransportApiRequestTemplate() { |
|||
TbQueueProducer<TbProtoQueueMsg<TransportApiRequestMsg>> producerTemplate = |
|||
new TbAwsSqsProducerTemplate<>(transportApiAdmin, sqsSettings, topicService.buildTopicName(transportApiSettings.getRequestsTopic())); |
|||
|
|||
TbQueueConsumer<TbProtoQueueMsg<TransportApiResponseMsg>> consumerTemplate = |
|||
new TbAwsSqsConsumerTemplate<>(transportApiAdmin, sqsSettings, |
|||
topicService.buildTopicName(transportApiSettings.getResponsesTopic() + "_" + serviceInfoProvider.getServiceId()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiResponseMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
|
|||
DefaultTbQueueRequestTemplate.DefaultTbQueueRequestTemplateBuilder |
|||
<TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> templateBuilder = DefaultTbQueueRequestTemplate.builder(); |
|||
templateBuilder.queueAdmin(transportApiAdmin); |
|||
templateBuilder.requestTemplate(producerTemplate); |
|||
templateBuilder.responseTemplate(consumerTemplate); |
|||
templateBuilder.maxPendingRequests(transportApiSettings.getMaxPendingRequests()); |
|||
templateBuilder.maxRequestTimeout(transportApiSettings.getMaxRequestsTimeout()); |
|||
templateBuilder.pollInterval(transportApiSettings.getResponsePollInterval()); |
|||
return templateBuilder.build(); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> createRuleEngineMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(ruleEngineAdmin, sqsSettings, topicService.buildTopicName(ruleEngineSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> createTbCoreMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> createTbCoreNotificationsMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(notificationAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToTransportMsg>> createTransportNotificationsConsumer() { |
|||
return new TbAwsSqsConsumerTemplate<>(notificationAdmin, sqsSettings, topicService.buildTopicName(transportNotificationSettings.getNotificationsTopic() + "_" + serviceInfoProvider.getServiceId()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToTransportMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToHousekeeperServiceMsg>> createHousekeeperMsgProducer() { |
|||
return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic())); |
|||
} |
|||
|
|||
@PreDestroy |
|||
private void destroy() { |
|||
if (coreAdmin != null) { |
|||
coreAdmin.destroy(); |
|||
} |
|||
if (transportApiAdmin != null) { |
|||
transportApiAdmin.destroy(); |
|||
} |
|||
if (notificationAdmin != null) { |
|||
notificationAdmin.destroy(); |
|||
} |
|||
if (ruleEngineAdmin != null) { |
|||
ruleEngineAdmin.destroy(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,315 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.provider; |
|||
|
|||
import com.google.protobuf.util.JsonFormat; |
|||
import jakarta.annotation.PreDestroy; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.queue.Queue; |
|||
import org.thingsboard.server.common.msg.queue.ServiceType; |
|||
import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsRequest; |
|||
import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsResponse; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeEventNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueConsumer; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.TbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; |
|||
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|||
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
|||
import org.thingsboard.server.queue.discovery.TopicService; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubAdmin; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubConsumerTemplate; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubProducerTemplate; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubSettings; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubSubscriptionSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueCoreSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueEdgeSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueVersionControlSettings; |
|||
|
|||
import java.nio.charset.StandardCharsets; |
|||
|
|||
@Component |
|||
@ConditionalOnExpression("'${queue.type:null}'=='pubsub' && '${service.type:null}'=='monolith'") |
|||
public class PubSubMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngineQueueFactory, TbVersionControlQueueFactory { |
|||
|
|||
private final TbPubSubSettings pubSubSettings; |
|||
private final TbQueueCoreSettings coreSettings; |
|||
private final TbQueueRuleEngineSettings ruleEngineSettings; |
|||
private final TbQueueTransportApiSettings transportApiSettings; |
|||
private final TbQueueTransportNotificationSettings transportNotificationSettings; |
|||
private final TopicService topicService; |
|||
private final TbServiceInfoProvider serviceInfoProvider; |
|||
private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; |
|||
private final TbQueueVersionControlSettings vcSettings; |
|||
private final TbQueueEdgeSettings edgeSettings; |
|||
|
|||
private final TbQueueAdmin coreAdmin; |
|||
private final TbQueueAdmin ruleEngineAdmin; |
|||
private final TbQueueAdmin jsExecutorAdmin; |
|||
private final TbQueueAdmin transportApiAdmin; |
|||
private final TbQueueAdmin notificationAdmin; |
|||
private final TbQueueAdmin vcAdmin; |
|||
private final TbQueueAdmin edgeAdmin; |
|||
|
|||
public PubSubMonolithQueueFactory(TbPubSubSettings pubSubSettings, |
|||
TbQueueCoreSettings coreSettings, |
|||
TbQueueRuleEngineSettings ruleEngineSettings, |
|||
TbQueueTransportApiSettings transportApiSettings, |
|||
TbQueueTransportNotificationSettings transportNotificationSettings, |
|||
TopicService topicService, |
|||
TbServiceInfoProvider serviceInfoProvider, |
|||
TbPubSubSubscriptionSettings pubSubSubscriptionSettings, |
|||
TbQueueRemoteJsInvokeSettings jsInvokeSettings, |
|||
TbQueueVersionControlSettings vcSettings, |
|||
TbQueueEdgeSettings edgeSettings) { |
|||
this.pubSubSettings = pubSubSettings; |
|||
this.coreSettings = coreSettings; |
|||
this.ruleEngineSettings = ruleEngineSettings; |
|||
this.transportApiSettings = transportApiSettings; |
|||
this.transportNotificationSettings = transportNotificationSettings; |
|||
this.topicService = topicService; |
|||
this.serviceInfoProvider = serviceInfoProvider; |
|||
this.vcSettings = vcSettings; |
|||
this.edgeSettings = edgeSettings; |
|||
|
|||
this.coreAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getCoreSettings()); |
|||
this.ruleEngineAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getRuleEngineSettings()); |
|||
this.jsExecutorAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getJsExecutorSettings()); |
|||
this.transportApiAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getTransportApiSettings()); |
|||
this.notificationAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getNotificationsSettings()); |
|||
this.vcAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getVcSettings()); |
|||
this.edgeAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getEdgeSettings()); |
|||
|
|||
this.jsInvokeSettings = jsInvokeSettings; |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToTransportMsg>> createTransportNotificationsMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, topicService.buildTopicName(transportNotificationSettings.getNotificationsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> createRuleEngineMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(ruleEngineAdmin, pubSubSettings, topicService.buildTopicName(ruleEngineSettings.getTopic())); |
|||
|
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> createRuleEngineNotificationsMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, topicService.buildTopicName(ruleEngineSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> createTbCoreMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> createTbCoreNotificationsMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToVersionControlServiceMsg>> createToVersionControlMsgConsumer() { |
|||
return new TbPubSubConsumerTemplate<>(vcAdmin, pubSubSettings, topicService.buildTopicName(vcSettings.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToVersionControlServiceMsg.parseFrom(msg.getData()), msg.getHeaders()) |
|||
); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineMsg>> createToRuleEngineMsgConsumer(Queue configuration) { |
|||
return new TbPubSubConsumerTemplate<>(ruleEngineAdmin, pubSubSettings, topicService.buildTopicName(configuration.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> createToRuleEngineNotificationsMsgConsumer() { |
|||
return new TbPubSubConsumerTemplate<>(notificationAdmin, pubSubSettings, |
|||
topicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToCoreMsg>> createToCoreMsgConsumer() { |
|||
return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToCoreNotificationMsg>> createToCoreNotificationsMsgConsumer() { |
|||
return new TbPubSubConsumerTemplate<>(notificationAdmin, pubSubSettings, |
|||
topicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<TransportApiRequestMsg>> createTransportApiRequestConsumer() { |
|||
return new TbPubSubConsumerTemplate<>(transportApiAdmin, pubSubSettings, topicService.buildTopicName(transportApiSettings.getRequestsTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiRequestMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<TransportApiResponseMsg>> createTransportApiResponseProducer() { |
|||
return new TbPubSubProducerTemplate<>(transportApiAdmin, pubSubSettings, topicService.buildTopicName(transportApiSettings.getResponsesTopic())); |
|||
} |
|||
|
|||
@Override |
|||
@Bean |
|||
public TbQueueRequestTemplate<TbProtoJsQueueMsg<RemoteJsRequest>, TbProtoQueueMsg<RemoteJsResponse>> createRemoteJsRequestTemplate() { |
|||
TbQueueProducer<TbProtoJsQueueMsg<RemoteJsRequest>> producer = new TbPubSubProducerTemplate<>(jsExecutorAdmin, pubSubSettings, jsInvokeSettings.getRequestTopic()); |
|||
TbQueueConsumer<TbProtoQueueMsg<RemoteJsResponse>> consumer = new TbPubSubConsumerTemplate<>(jsExecutorAdmin, pubSubSettings, |
|||
jsInvokeSettings.getResponseTopic() + "." + serviceInfoProvider.getServiceId(), |
|||
msg -> { |
|||
RemoteJsResponse.Builder builder = RemoteJsResponse.newBuilder(); |
|||
JsonFormat.parser().ignoringUnknownFields().merge(new String(msg.getData(), StandardCharsets.UTF_8), builder); |
|||
return new TbProtoQueueMsg<>(msg.getKey(), builder.build(), msg.getHeaders()); |
|||
}); |
|||
|
|||
DefaultTbQueueRequestTemplate.DefaultTbQueueRequestTemplateBuilder |
|||
<TbProtoJsQueueMsg<RemoteJsRequest>, TbProtoQueueMsg<RemoteJsResponse>> builder = DefaultTbQueueRequestTemplate.builder(); |
|||
builder.queueAdmin(jsExecutorAdmin); |
|||
builder.requestTemplate(producer); |
|||
builder.responseTemplate(consumer); |
|||
builder.maxPendingRequests(jsInvokeSettings.getMaxPendingRequests()); |
|||
builder.maxRequestTimeout(jsInvokeSettings.getMaxRequestsTimeout()); |
|||
builder.pollInterval(jsInvokeSettings.getResponsePollInterval()); |
|||
return builder.build(); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgConsumer() { |
|||
return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgConsumer() { |
|||
return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getOtaPackageTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToOtaPackageStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getOtaPackageTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToVersionControlServiceMsg>> createVersionControlMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(vcAdmin, pubSubSettings, topicService.buildTopicName(vcSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperMsgConsumer() { |
|||
return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToHousekeeperServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperReprocessingMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getHousekeeperReprocessingTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperReprocessingMsgConsumer() { |
|||
return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getHousekeeperReprocessingTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToHousekeeperServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeMsg>> createEdgeMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(edgeAdmin, pubSubSettings, topicService.buildTopicName(edgeSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToEdgeMsg>> createEdgeMsgConsumer() { |
|||
return new TbPubSubConsumerTemplate<>(edgeAdmin, pubSubSettings, topicService.buildTopicName(edgeSettings.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToEdgeMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createToEdgeNotificationsMsgConsumer() { |
|||
return new TbPubSubConsumerTemplate<>(notificationAdmin, pubSubSettings, |
|||
topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToEdgeNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, |
|||
topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> createEdgeEventMsgProducer() { |
|||
return null; |
|||
} |
|||
|
|||
@PreDestroy |
|||
private void destroy() { |
|||
if (coreAdmin != null) { |
|||
coreAdmin.destroy(); |
|||
} |
|||
if (ruleEngineAdmin != null) { |
|||
ruleEngineAdmin.destroy(); |
|||
} |
|||
if (jsExecutorAdmin != null) { |
|||
jsExecutorAdmin.destroy(); |
|||
} |
|||
if (transportApiAdmin != null) { |
|||
transportApiAdmin.destroy(); |
|||
} |
|||
if (notificationAdmin != null) { |
|||
notificationAdmin.destroy(); |
|||
} |
|||
if (vcAdmin != null) { |
|||
vcAdmin.destroy(); |
|||
} |
|||
if (edgeAdmin != null) { |
|||
edgeAdmin.destroy(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,278 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.provider; |
|||
|
|||
import com.google.protobuf.util.JsonFormat; |
|||
import jakarta.annotation.PreDestroy; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.msg.queue.ServiceType; |
|||
import org.thingsboard.server.gen.js.JsInvokeProtos; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueConsumer; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.TbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; |
|||
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|||
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
|||
import org.thingsboard.server.queue.discovery.TopicService; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubAdmin; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubConsumerTemplate; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubProducerTemplate; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubSettings; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubSubscriptionSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueCoreSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueEdgeSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; |
|||
|
|||
import java.nio.charset.StandardCharsets; |
|||
|
|||
@Component |
|||
@ConditionalOnExpression("'${queue.type:null}'=='pubsub' && '${service.type:null}'=='tb-core'") |
|||
public class PubSubTbCoreQueueFactory implements TbCoreQueueFactory { |
|||
|
|||
private final TbPubSubSettings pubSubSettings; |
|||
private final TbQueueCoreSettings coreSettings; |
|||
private final TbQueueTransportApiSettings transportApiSettings; |
|||
private final TopicService topicService; |
|||
private final TbServiceInfoProvider serviceInfoProvider; |
|||
private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; |
|||
private final TbQueueTransportNotificationSettings transportNotificationSettings; |
|||
private final TbQueueRuleEngineSettings ruleEngineSettings; |
|||
private final TbQueueEdgeSettings edgeSettings; |
|||
|
|||
private final TbQueueAdmin coreAdmin; |
|||
private final TbQueueAdmin jsExecutorAdmin; |
|||
private final TbQueueAdmin transportApiAdmin; |
|||
private final TbQueueAdmin notificationAdmin; |
|||
private final TbQueueAdmin ruleEngineAdmin; |
|||
private final TbQueueAdmin edgeAdmin; |
|||
|
|||
public PubSubTbCoreQueueFactory(TbPubSubSettings pubSubSettings, |
|||
TbQueueCoreSettings coreSettings, |
|||
TbQueueTransportApiSettings transportApiSettings, |
|||
TopicService topicService, |
|||
TbServiceInfoProvider serviceInfoProvider, |
|||
TbQueueRemoteJsInvokeSettings jsInvokeSettings, |
|||
TbQueueTransportNotificationSettings transportNotificationSettings, |
|||
TbQueueRuleEngineSettings ruleEngineSettings, |
|||
TbQueueEdgeSettings edgeSettings, |
|||
TbPubSubSubscriptionSettings pubSubSubscriptionSettings) { |
|||
this.pubSubSettings = pubSubSettings; |
|||
this.coreSettings = coreSettings; |
|||
this.transportApiSettings = transportApiSettings; |
|||
this.topicService = topicService; |
|||
this.serviceInfoProvider = serviceInfoProvider; |
|||
this.jsInvokeSettings = jsInvokeSettings; |
|||
this.transportNotificationSettings = transportNotificationSettings; |
|||
this.ruleEngineSettings = ruleEngineSettings; |
|||
this.edgeSettings = edgeSettings; |
|||
|
|||
this.coreAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getCoreSettings()); |
|||
this.jsExecutorAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getJsExecutorSettings()); |
|||
this.transportApiAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getTransportApiSettings()); |
|||
this.notificationAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getNotificationsSettings()); |
|||
this.ruleEngineAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getRuleEngineSettings()); |
|||
this.edgeAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getEdgeSettings()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToTransportMsg>> createTransportNotificationsMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, topicService.buildTopicName(transportNotificationSettings.getNotificationsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> createRuleEngineMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> createRuleEngineNotificationsMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, topicService.buildTopicName(ruleEngineSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> createTbCoreMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> createTbCoreNotificationsMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, |
|||
topicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToCoreMsg>> createToCoreMsgConsumer() { |
|||
return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToCoreNotificationMsg>> createToCoreNotificationsMsgConsumer() { |
|||
return new TbPubSubConsumerTemplate<>(notificationAdmin, pubSubSettings, |
|||
topicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<TransportApiRequestMsg>> createTransportApiRequestConsumer() { |
|||
return new TbPubSubConsumerTemplate<>(transportApiAdmin, pubSubSettings, topicService.buildTopicName(transportApiSettings.getRequestsTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiRequestMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<TransportApiResponseMsg>> createTransportApiResponseProducer() { |
|||
return new TbPubSubProducerTemplate<>(transportApiAdmin, pubSubSettings, topicService.buildTopicName(transportApiSettings.getResponsesTopic())); |
|||
} |
|||
|
|||
@Override |
|||
@Bean |
|||
public TbQueueRequestTemplate<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>, TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> createRemoteJsRequestTemplate() { |
|||
TbQueueProducer<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>> producer = new TbPubSubProducerTemplate<>(jsExecutorAdmin, pubSubSettings, jsInvokeSettings.getRequestTopic()); |
|||
TbQueueConsumer<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> consumer = new TbPubSubConsumerTemplate<>(jsExecutorAdmin, pubSubSettings, |
|||
jsInvokeSettings.getResponseTopic() + "." + serviceInfoProvider.getServiceId(), |
|||
msg -> { |
|||
JsInvokeProtos.RemoteJsResponse.Builder builder = JsInvokeProtos.RemoteJsResponse.newBuilder(); |
|||
JsonFormat.parser().ignoringUnknownFields().merge(new String(msg.getData(), StandardCharsets.UTF_8), builder); |
|||
return new TbProtoQueueMsg<>(msg.getKey(), builder.build(), msg.getHeaders()); |
|||
}); |
|||
|
|||
DefaultTbQueueRequestTemplate.DefaultTbQueueRequestTemplateBuilder |
|||
<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>, TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> builder = DefaultTbQueueRequestTemplate.builder(); |
|||
builder.queueAdmin(jsExecutorAdmin); |
|||
builder.requestTemplate(producer); |
|||
builder.responseTemplate(consumer); |
|||
builder.maxPendingRequests(jsInvokeSettings.getMaxPendingRequests()); |
|||
builder.maxRequestTimeout(jsInvokeSettings.getMaxRequestsTimeout()); |
|||
builder.pollInterval(jsInvokeSettings.getResponsePollInterval()); |
|||
return builder.build(); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgConsumer() { |
|||
return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgConsumer() { |
|||
return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getOtaPackageTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToOtaPackageStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getOtaPackageTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToVersionControlServiceMsg>> createVersionControlMsgProducer() { |
|||
//TODO: version-control
|
|||
return null; |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperMsgConsumer() { |
|||
return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToHousekeeperServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperReprocessingMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getHousekeeperReprocessingTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperReprocessingMsgConsumer() { |
|||
return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getHousekeeperReprocessingTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToHousekeeperServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToEdgeMsg>> createEdgeMsgConsumer() { |
|||
return new TbPubSubConsumerTemplate<>(edgeAdmin, pubSubSettings, topicService.buildTopicName(edgeSettings.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToEdgeMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeMsg>> createEdgeMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(edgeAdmin, pubSubSettings, topicService.buildTopicName(edgeSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createToEdgeNotificationsMsgConsumer() { |
|||
return new TbPubSubConsumerTemplate<>(notificationAdmin, pubSubSettings, |
|||
topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToEdgeNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, |
|||
topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName()); |
|||
} |
|||
|
|||
@PreDestroy |
|||
private void destroy() { |
|||
if (coreAdmin != null) { |
|||
coreAdmin.destroy(); |
|||
} |
|||
if (jsExecutorAdmin != null) { |
|||
jsExecutorAdmin.destroy(); |
|||
} |
|||
if (transportApiAdmin != null) { |
|||
transportApiAdmin.destroy(); |
|||
} |
|||
if (notificationAdmin != null) { |
|||
notificationAdmin.destroy(); |
|||
} |
|||
if (ruleEngineAdmin != null) { |
|||
ruleEngineAdmin.destroy(); |
|||
} |
|||
if (edgeAdmin != null) { |
|||
edgeAdmin.destroy(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,209 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.provider; |
|||
|
|||
import com.google.protobuf.util.JsonFormat; |
|||
import jakarta.annotation.PreDestroy; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.queue.Queue; |
|||
import org.thingsboard.server.common.msg.queue.ServiceType; |
|||
import org.thingsboard.server.gen.js.JsInvokeProtos; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeEventNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueConsumer; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.TbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; |
|||
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|||
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
|||
import org.thingsboard.server.queue.discovery.TopicService; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubAdmin; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubConsumerTemplate; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubProducerTemplate; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubSettings; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubSubscriptionSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueCoreSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueEdgeSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; |
|||
|
|||
import java.nio.charset.StandardCharsets; |
|||
|
|||
@Component |
|||
@ConditionalOnExpression("'${queue.type:null}'=='pubsub' && '${service.type:null}'=='tb-rule-engine'") |
|||
public class PubSubTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory { |
|||
|
|||
private final TbPubSubSettings pubSubSettings; |
|||
private final TbQueueCoreSettings coreSettings; |
|||
private final TbQueueRuleEngineSettings ruleEngineSettings; |
|||
private final TopicService topicService; |
|||
private final TbServiceInfoProvider serviceInfoProvider; |
|||
private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; |
|||
private final TbQueueTransportNotificationSettings transportNotificationSettings; |
|||
private final TbQueueEdgeSettings edgeSettings; |
|||
|
|||
private final TbQueueAdmin coreAdmin; |
|||
private final TbQueueAdmin ruleEngineAdmin; |
|||
private final TbQueueAdmin jsExecutorAdmin; |
|||
private final TbQueueAdmin notificationAdmin; |
|||
private final TbQueueAdmin edgeAdmin; |
|||
|
|||
public PubSubTbRuleEngineQueueFactory(TbPubSubSettings pubSubSettings, |
|||
TbQueueCoreSettings coreSettings, |
|||
TbQueueRuleEngineSettings ruleEngineSettings, |
|||
TopicService topicService, |
|||
TbServiceInfoProvider serviceInfoProvider, |
|||
TbQueueRemoteJsInvokeSettings jsInvokeSettings, |
|||
TbQueueTransportNotificationSettings transportNotificationSettings, |
|||
TbPubSubSubscriptionSettings pubSubSubscriptionSettings, |
|||
TbQueueEdgeSettings edgeSettings) { |
|||
this.pubSubSettings = pubSubSettings; |
|||
this.coreSettings = coreSettings; |
|||
this.ruleEngineSettings = ruleEngineSettings; |
|||
this.topicService = topicService; |
|||
this.serviceInfoProvider = serviceInfoProvider; |
|||
this.jsInvokeSettings = jsInvokeSettings; |
|||
this.transportNotificationSettings = transportNotificationSettings; |
|||
this.edgeSettings = edgeSettings; |
|||
|
|||
this.coreAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getCoreSettings()); |
|||
this.ruleEngineAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getRuleEngineSettings()); |
|||
this.jsExecutorAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getJsExecutorSettings()); |
|||
this.notificationAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getNotificationsSettings()); |
|||
this.edgeAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getEdgeSettings()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToTransportMsg>> createTransportNotificationsMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, topicService.buildTopicName(transportNotificationSettings.getNotificationsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> createRuleEngineMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(ruleEngineAdmin, pubSubSettings, topicService.buildTopicName(ruleEngineSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> createRuleEngineNotificationsMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, topicService.buildTopicName(ruleEngineSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> createTbCoreMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> createTbCoreNotificationsMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeMsg>> createEdgeMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(edgeAdmin, pubSubSettings, topicService.buildTopicName(edgeSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> createEdgeEventMsgProducer() { |
|||
return null; |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineMsg>> createToRuleEngineMsgConsumer(Queue configuration) { |
|||
return new TbPubSubConsumerTemplate<>(ruleEngineAdmin, pubSubSettings, topicService.buildTopicName(configuration.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> createToRuleEngineNotificationsMsgConsumer() { |
|||
return new TbPubSubConsumerTemplate<>(notificationAdmin, pubSubSettings, |
|||
topicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
@Bean |
|||
public TbQueueRequestTemplate<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>, TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> createRemoteJsRequestTemplate() { |
|||
TbQueueProducer<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>> producer = new TbPubSubProducerTemplate<>(jsExecutorAdmin, pubSubSettings, jsInvokeSettings.getRequestTopic()); |
|||
TbQueueConsumer<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> consumer = new TbPubSubConsumerTemplate<>(jsExecutorAdmin, pubSubSettings, |
|||
jsInvokeSettings.getResponseTopic() + "." + serviceInfoProvider.getServiceId(), |
|||
msg -> { |
|||
JsInvokeProtos.RemoteJsResponse.Builder builder = JsInvokeProtos.RemoteJsResponse.newBuilder(); |
|||
JsonFormat.parser().ignoringUnknownFields().merge(new String(msg.getData(), StandardCharsets.UTF_8), builder); |
|||
return new TbProtoQueueMsg<>(msg.getKey(), builder.build(), msg.getHeaders()); |
|||
}); |
|||
|
|||
DefaultTbQueueRequestTemplate.DefaultTbQueueRequestTemplateBuilder |
|||
<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>, TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> builder = DefaultTbQueueRequestTemplate.builder(); |
|||
builder.queueAdmin(jsExecutorAdmin); |
|||
builder.requestTemplate(producer); |
|||
builder.responseTemplate(consumer); |
|||
builder.maxPendingRequests(jsInvokeSettings.getMaxPendingRequests()); |
|||
builder.maxRequestTimeout(jsInvokeSettings.getMaxRequestsTimeout()); |
|||
builder.pollInterval(jsInvokeSettings.getResponsePollInterval()); |
|||
return builder.build(); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getOtaPackageTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic())); |
|||
} |
|||
|
|||
@PreDestroy |
|||
private void destroy() { |
|||
if (coreAdmin != null) { |
|||
coreAdmin.destroy(); |
|||
} |
|||
if (ruleEngineAdmin != null) { |
|||
ruleEngineAdmin.destroy(); |
|||
} |
|||
if (jsExecutorAdmin != null) { |
|||
jsExecutorAdmin.destroy(); |
|||
} |
|||
if (notificationAdmin != null) { |
|||
notificationAdmin.destroy(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,98 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.provider; |
|||
|
|||
import jakarta.annotation.PreDestroy; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.gen.transport.TransportProtos; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueConsumer; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|||
import org.thingsboard.server.queue.discovery.TopicService; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubAdmin; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubConsumerTemplate; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubProducerTemplate; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubSettings; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubSubscriptionSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueCoreSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueVersionControlSettings; |
|||
|
|||
@Component |
|||
@ConditionalOnExpression("'${queue.type:null}'=='pubsub' && '${service.type:null}'=='tb-vc-executor'") |
|||
public class PubSubTbVersionControlQueueFactory implements TbVersionControlQueueFactory { |
|||
|
|||
private final TbPubSubSettings pubSubSettings; |
|||
private final TbQueueCoreSettings coreSettings; |
|||
private final TbQueueVersionControlSettings vcSettings; |
|||
private final TopicService topicService; |
|||
|
|||
private final TbQueueAdmin coreAdmin; |
|||
private final TbQueueAdmin notificationAdmin; |
|||
private final TbQueueAdmin vcAdmin; |
|||
|
|||
public PubSubTbVersionControlQueueFactory(TbPubSubSettings pubSubSettings, |
|||
TbQueueCoreSettings coreSettings, |
|||
TbQueueVersionControlSettings vcSettings, |
|||
TbPubSubSubscriptionSettings pubSubSubscriptionSettings, |
|||
TopicService topicService |
|||
) { |
|||
this.pubSubSettings = pubSubSettings; |
|||
this.coreSettings = coreSettings; |
|||
this.vcSettings = vcSettings; |
|||
this.topicService = topicService; |
|||
|
|||
this.coreAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getCoreSettings()); |
|||
this.notificationAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getNotificationsSettings()); |
|||
this.vcAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getVcSettings()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToCoreNotificationMsg>> createTbCoreNotificationsMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<TransportProtos.ToVersionControlServiceMsg>> createToVersionControlMsgConsumer() { |
|||
return new TbPubSubConsumerTemplate<>(vcAdmin, pubSubSettings, topicService.buildTopicName(vcSettings.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportProtos.ToVersionControlServiceMsg.parseFrom(msg.getData()), msg.getHeaders()) |
|||
); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToHousekeeperServiceMsg>> createHousekeeperMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic())); |
|||
} |
|||
|
|||
@PreDestroy |
|||
private void destroy() { |
|||
if (coreAdmin != null) { |
|||
coreAdmin.destroy(); |
|||
} |
|||
if (notificationAdmin != null) { |
|||
notificationAdmin.destroy(); |
|||
} |
|||
if (vcAdmin != null) { |
|||
vcAdmin.destroy(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,153 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.provider; |
|||
|
|||
import jakarta.annotation.PreDestroy; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueConsumer; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.TbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|||
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
|||
import org.thingsboard.server.queue.discovery.TopicService; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubAdmin; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubConsumerTemplate; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubProducerTemplate; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubSettings; |
|||
import org.thingsboard.server.queue.pubsub.TbPubSubSubscriptionSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueCoreSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; |
|||
|
|||
@Component |
|||
@ConditionalOnExpression("'${queue.type:null}'=='pubsub' && (('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true') || '${service.type:null}'=='tb-transport')") |
|||
@Slf4j |
|||
public class PubSubTransportQueueFactory implements TbTransportQueueFactory { |
|||
|
|||
private final TbPubSubSettings pubSubSettings; |
|||
private final TbServiceInfoProvider serviceInfoProvider; |
|||
private final TbQueueCoreSettings coreSettings; |
|||
private final TbQueueRuleEngineSettings ruleEngineSettings; |
|||
private final TbQueueTransportApiSettings transportApiSettings; |
|||
private final TbQueueTransportNotificationSettings transportNotificationSettings; |
|||
private final TopicService topicService; |
|||
|
|||
private final TbQueueAdmin coreAdmin; |
|||
private final TbQueueAdmin ruleEngineAdmin; |
|||
private final TbQueueAdmin transportApiAdmin; |
|||
private final TbQueueAdmin notificationAdmin; |
|||
|
|||
public PubSubTransportQueueFactory(TbPubSubSettings pubSubSettings, |
|||
TbServiceInfoProvider serviceInfoProvider, |
|||
TbQueueCoreSettings coreSettings, |
|||
TbQueueRuleEngineSettings ruleEngineSettings, |
|||
TbQueueTransportApiSettings transportApiSettings, |
|||
TbQueueTransportNotificationSettings transportNotificationSettings, |
|||
TbPubSubSubscriptionSettings pubSubSubscriptionSettings, |
|||
TopicService topicService) { |
|||
this.pubSubSettings = pubSubSettings; |
|||
this.serviceInfoProvider = serviceInfoProvider; |
|||
this.coreSettings = coreSettings; |
|||
this.ruleEngineSettings = ruleEngineSettings; |
|||
this.transportApiSettings = transportApiSettings; |
|||
this.transportNotificationSettings = transportNotificationSettings; |
|||
this.topicService = topicService; |
|||
|
|||
this.coreAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getCoreSettings()); |
|||
this.ruleEngineAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getRuleEngineSettings()); |
|||
this.transportApiAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getTransportApiSettings()); |
|||
this.notificationAdmin = new TbPubSubAdmin(pubSubSettings, pubSubSubscriptionSettings.getNotificationsSettings()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueRequestTemplate<TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> createTransportApiRequestTemplate() { |
|||
TbQueueProducer<TbProtoQueueMsg<TransportApiRequestMsg>> producer = new TbPubSubProducerTemplate<>(transportApiAdmin, pubSubSettings, topicService.buildTopicName(transportApiSettings.getRequestsTopic())); |
|||
TbQueueConsumer<TbProtoQueueMsg<TransportApiResponseMsg>> consumer = new TbPubSubConsumerTemplate<>(transportApiAdmin, pubSubSettings, |
|||
topicService.buildTopicName(transportApiSettings.getResponsesTopic() + "." + serviceInfoProvider.getServiceId()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiResponseMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
|
|||
DefaultTbQueueRequestTemplate.DefaultTbQueueRequestTemplateBuilder |
|||
<TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> templateBuilder = DefaultTbQueueRequestTemplate.builder(); |
|||
templateBuilder.queueAdmin(transportApiAdmin); |
|||
templateBuilder.requestTemplate(producer); |
|||
templateBuilder.responseTemplate(consumer); |
|||
templateBuilder.maxPendingRequests(transportApiSettings.getMaxPendingRequests()); |
|||
templateBuilder.maxRequestTimeout(transportApiSettings.getMaxRequestsTimeout()); |
|||
templateBuilder.pollInterval(transportApiSettings.getResponsePollInterval()); |
|||
return templateBuilder.build(); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> createRuleEngineMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(ruleEngineAdmin, pubSubSettings, topicService.buildTopicName(ruleEngineSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> createTbCoreMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> createTbCoreNotificationsMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToTransportMsg>> createTransportNotificationsConsumer() { |
|||
return new TbPubSubConsumerTemplate<>(notificationAdmin, pubSubSettings, |
|||
topicService.buildTopicName(transportNotificationSettings.getNotificationsTopic() + "." + serviceInfoProvider.getServiceId()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToTransportMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperMsgProducer() { |
|||
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic())); |
|||
} |
|||
|
|||
@PreDestroy |
|||
private void destroy() { |
|||
if (coreAdmin != null) { |
|||
coreAdmin.destroy(); |
|||
} |
|||
if (ruleEngineAdmin != null) { |
|||
ruleEngineAdmin.destroy(); |
|||
} |
|||
if (transportApiAdmin != null) { |
|||
transportApiAdmin.destroy(); |
|||
} |
|||
if (notificationAdmin != null) { |
|||
notificationAdmin.destroy(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,313 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.provider; |
|||
|
|||
import com.google.protobuf.util.JsonFormat; |
|||
import jakarta.annotation.PreDestroy; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.queue.Queue; |
|||
import org.thingsboard.server.common.msg.queue.ServiceType; |
|||
import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsRequest; |
|||
import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsResponse; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeEventNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueConsumer; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.TbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; |
|||
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|||
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
|||
import org.thingsboard.server.queue.discovery.TopicService; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqAdmin; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqConsumerTemplate; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqProducerTemplate; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqQueueArguments; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueCoreSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueEdgeSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueVersionControlSettings; |
|||
|
|||
import java.nio.charset.StandardCharsets; |
|||
|
|||
@Component |
|||
@ConditionalOnExpression("'${queue.type:null}'=='rabbitmq' && '${service.type:null}'=='monolith'") |
|||
public class RabbitMqMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngineQueueFactory, TbVersionControlQueueFactory { |
|||
|
|||
private final TopicService topicService; |
|||
private final TbQueueCoreSettings coreSettings; |
|||
private final TbServiceInfoProvider serviceInfoProvider; |
|||
private final TbQueueRuleEngineSettings ruleEngineSettings; |
|||
private final TbQueueTransportApiSettings transportApiSettings; |
|||
private final TbQueueTransportNotificationSettings transportNotificationSettings; |
|||
private final TbRabbitMqSettings rabbitMqSettings; |
|||
private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; |
|||
private final TbQueueVersionControlSettings vcSettings; |
|||
private final TbQueueEdgeSettings edgeSettings; |
|||
|
|||
private final TbQueueAdmin coreAdmin; |
|||
private final TbQueueAdmin ruleEngineAdmin; |
|||
private final TbQueueAdmin jsExecutorAdmin; |
|||
private final TbQueueAdmin transportApiAdmin; |
|||
private final TbQueueAdmin notificationAdmin; |
|||
private final TbQueueAdmin vcAdmin; |
|||
private final TbQueueAdmin edgeAdmin; |
|||
|
|||
public RabbitMqMonolithQueueFactory(TopicService topicService, TbQueueCoreSettings coreSettings, |
|||
TbQueueRuleEngineSettings ruleEngineSettings, |
|||
TbServiceInfoProvider serviceInfoProvider, |
|||
TbQueueTransportApiSettings transportApiSettings, |
|||
TbQueueTransportNotificationSettings transportNotificationSettings, |
|||
TbRabbitMqSettings rabbitMqSettings, |
|||
TbRabbitMqQueueArguments queueArguments, |
|||
TbQueueRemoteJsInvokeSettings jsInvokeSettings, |
|||
TbQueueVersionControlSettings vcSettings, |
|||
TbQueueEdgeSettings edgeSettings) { |
|||
this.topicService = topicService; |
|||
this.coreSettings = coreSettings; |
|||
this.serviceInfoProvider = serviceInfoProvider; |
|||
this.ruleEngineSettings = ruleEngineSettings; |
|||
this.transportApiSettings = transportApiSettings; |
|||
this.transportNotificationSettings = transportNotificationSettings; |
|||
this.rabbitMqSettings = rabbitMqSettings; |
|||
this.jsInvokeSettings = jsInvokeSettings; |
|||
this.vcSettings = vcSettings; |
|||
this.edgeSettings = edgeSettings; |
|||
|
|||
this.coreAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getCoreArgs()); |
|||
this.ruleEngineAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getRuleEngineArgs()); |
|||
this.jsExecutorAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getJsExecutorArgs()); |
|||
this.transportApiAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getTransportApiArgs()); |
|||
this.notificationAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getNotificationsArgs()); |
|||
this.vcAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getVcArgs()); |
|||
this.edgeAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getEdgeArgs()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToTransportMsg>> createTransportNotificationsMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(notificationAdmin, rabbitMqSettings, topicService.buildTopicName(transportNotificationSettings.getNotificationsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> createRuleEngineMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(ruleEngineAdmin, rabbitMqSettings, topicService.buildTopicName(ruleEngineSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> createRuleEngineNotificationsMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(notificationAdmin, rabbitMqSettings, topicService.buildTopicName(ruleEngineSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> createTbCoreMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> createTbCoreNotificationsMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(notificationAdmin, rabbitMqSettings, |
|||
topicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToVersionControlServiceMsg>> createToVersionControlMsgConsumer() { |
|||
return new TbRabbitMqConsumerTemplate<>(vcAdmin, rabbitMqSettings, topicService.buildTopicName(vcSettings.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToVersionControlServiceMsg.parseFrom(msg.getData()), msg.getHeaders()) |
|||
); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineMsg>> createToRuleEngineMsgConsumer(Queue configuration) { |
|||
return new TbRabbitMqConsumerTemplate<>(ruleEngineAdmin, rabbitMqSettings, topicService.buildTopicName(configuration.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> createToRuleEngineNotificationsMsgConsumer() { |
|||
return new TbRabbitMqConsumerTemplate<>(notificationAdmin, rabbitMqSettings, |
|||
topicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToCoreMsg>> createToCoreMsgConsumer() { |
|||
return new TbRabbitMqConsumerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToCoreNotificationMsg>> createToCoreNotificationsMsgConsumer() { |
|||
return new TbRabbitMqConsumerTemplate<>(notificationAdmin, rabbitMqSettings, |
|||
topicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<TransportApiRequestMsg>> createTransportApiRequestConsumer() { |
|||
return new TbRabbitMqConsumerTemplate<>(transportApiAdmin, rabbitMqSettings, topicService.buildTopicName(transportApiSettings.getRequestsTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiRequestMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<TransportApiResponseMsg>> createTransportApiResponseProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(transportApiAdmin, rabbitMqSettings, topicService.buildTopicName(transportApiSettings.getResponsesTopic())); |
|||
} |
|||
|
|||
@Override |
|||
@Bean |
|||
public TbQueueRequestTemplate<TbProtoJsQueueMsg<RemoteJsRequest>, TbProtoQueueMsg<RemoteJsResponse>> createRemoteJsRequestTemplate() { |
|||
TbQueueProducer<TbProtoJsQueueMsg<RemoteJsRequest>> producer = new TbRabbitMqProducerTemplate<>(jsExecutorAdmin, rabbitMqSettings, jsInvokeSettings.getRequestTopic()); |
|||
TbQueueConsumer<TbProtoQueueMsg<RemoteJsResponse>> consumer = new TbRabbitMqConsumerTemplate<>(jsExecutorAdmin, rabbitMqSettings, |
|||
jsInvokeSettings.getResponseTopic() + "." + serviceInfoProvider.getServiceId(), |
|||
msg -> { |
|||
RemoteJsResponse.Builder builder = RemoteJsResponse.newBuilder(); |
|||
JsonFormat.parser().ignoringUnknownFields().merge(new String(msg.getData(), StandardCharsets.UTF_8), builder); |
|||
return new TbProtoQueueMsg<>(msg.getKey(), builder.build(), msg.getHeaders()); |
|||
}); |
|||
|
|||
DefaultTbQueueRequestTemplate.DefaultTbQueueRequestTemplateBuilder |
|||
<TbProtoJsQueueMsg<RemoteJsRequest>, TbProtoQueueMsg<RemoteJsResponse>> builder = DefaultTbQueueRequestTemplate.builder(); |
|||
builder.queueAdmin(jsExecutorAdmin); |
|||
builder.requestTemplate(producer); |
|||
builder.responseTemplate(consumer); |
|||
builder.maxPendingRequests(jsInvokeSettings.getMaxPendingRequests()); |
|||
builder.maxRequestTimeout(jsInvokeSettings.getMaxRequestsTimeout()); |
|||
builder.pollInterval(jsInvokeSettings.getResponsePollInterval()); |
|||
return builder.build(); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgConsumer() { |
|||
return new TbRabbitMqConsumerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgConsumer() { |
|||
return new TbRabbitMqConsumerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getOtaPackageTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToOtaPackageStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getOtaPackageTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToVersionControlServiceMsg>> createVersionControlMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(vcAdmin, rabbitMqSettings, topicService.buildTopicName(vcSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperMsgConsumer() { |
|||
return new TbRabbitMqConsumerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToHousekeeperServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperReprocessingMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getHousekeeperReprocessingTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperReprocessingMsgConsumer() { |
|||
return new TbRabbitMqConsumerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getHousekeeperReprocessingTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToHousekeeperServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToEdgeMsg>> createEdgeMsgConsumer() { |
|||
return new TbRabbitMqConsumerTemplate<>(edgeAdmin, rabbitMqSettings, topicService.buildTopicName(edgeSettings.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToEdgeMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeMsg>> createEdgeMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(edgeAdmin, rabbitMqSettings, topicService.buildTopicName(edgeSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createToEdgeNotificationsMsgConsumer() { |
|||
return new TbRabbitMqConsumerTemplate<>(notificationAdmin, rabbitMqSettings, |
|||
topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToEdgeNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(notificationAdmin, rabbitMqSettings, |
|||
topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> createEdgeEventMsgProducer() { |
|||
return null; |
|||
} |
|||
|
|||
@PreDestroy |
|||
private void destroy() { |
|||
if (coreAdmin != null) { |
|||
coreAdmin.destroy(); |
|||
} |
|||
if (ruleEngineAdmin != null) { |
|||
ruleEngineAdmin.destroy(); |
|||
} |
|||
if (jsExecutorAdmin != null) { |
|||
jsExecutorAdmin.destroy(); |
|||
} |
|||
if (transportApiAdmin != null) { |
|||
transportApiAdmin.destroy(); |
|||
} |
|||
if (notificationAdmin != null) { |
|||
notificationAdmin.destroy(); |
|||
} |
|||
if (vcAdmin != null) { |
|||
vcAdmin.destroy(); |
|||
} |
|||
if (edgeAdmin != null) { |
|||
edgeAdmin.destroy(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,278 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.provider; |
|||
|
|||
import com.google.protobuf.util.JsonFormat; |
|||
import jakarta.annotation.PreDestroy; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.msg.queue.ServiceType; |
|||
import org.thingsboard.server.gen.js.JsInvokeProtos; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueConsumer; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.TbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; |
|||
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|||
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
|||
import org.thingsboard.server.queue.discovery.TopicService; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqAdmin; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqConsumerTemplate; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqProducerTemplate; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqQueueArguments; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueCoreSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueEdgeSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; |
|||
|
|||
import java.nio.charset.StandardCharsets; |
|||
|
|||
@Component |
|||
@ConditionalOnExpression("'${queue.type:null}'=='rabbitmq' && '${service.type:null}'=='tb-core'") |
|||
public class RabbitMqTbCoreQueueFactory implements TbCoreQueueFactory { |
|||
|
|||
private final TbRabbitMqSettings rabbitMqSettings; |
|||
private final TbQueueRuleEngineSettings ruleEngineSettings; |
|||
private final TbQueueCoreSettings coreSettings; |
|||
private final TbQueueTransportApiSettings transportApiSettings; |
|||
private final TopicService topicService; |
|||
private final TbServiceInfoProvider serviceInfoProvider; |
|||
private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; |
|||
private final TbQueueTransportNotificationSettings transportNotificationSettings; |
|||
private final TbQueueEdgeSettings edgeSettings; |
|||
|
|||
private final TbQueueAdmin coreAdmin; |
|||
private final TbQueueAdmin ruleEngineAdmin; |
|||
private final TbQueueAdmin jsExecutorAdmin; |
|||
private final TbQueueAdmin transportApiAdmin; |
|||
private final TbQueueAdmin notificationAdmin; |
|||
private final TbQueueAdmin edgeAdmin; |
|||
|
|||
public RabbitMqTbCoreQueueFactory(TbRabbitMqSettings rabbitMqSettings, |
|||
TbQueueCoreSettings coreSettings, |
|||
TbQueueTransportApiSettings transportApiSettings, |
|||
TbQueueRuleEngineSettings ruleEngineSettings, |
|||
TopicService topicService, |
|||
TbServiceInfoProvider serviceInfoProvider, |
|||
TbQueueRemoteJsInvokeSettings jsInvokeSettings, |
|||
TbQueueTransportNotificationSettings transportNotificationSettings, |
|||
TbQueueEdgeSettings edgeSettings, |
|||
TbRabbitMqQueueArguments queueArguments) { |
|||
this.rabbitMqSettings = rabbitMqSettings; |
|||
this.coreSettings = coreSettings; |
|||
this.transportApiSettings = transportApiSettings; |
|||
this.ruleEngineSettings = ruleEngineSettings; |
|||
this.topicService = topicService; |
|||
this.serviceInfoProvider = serviceInfoProvider; |
|||
this.jsInvokeSettings = jsInvokeSettings; |
|||
this.transportNotificationSettings = transportNotificationSettings; |
|||
this.edgeSettings = edgeSettings; |
|||
|
|||
this.coreAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getCoreArgs()); |
|||
this.ruleEngineAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getRuleEngineArgs()); |
|||
this.jsExecutorAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getJsExecutorArgs()); |
|||
this.transportApiAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getTransportApiArgs()); |
|||
this.notificationAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getNotificationsArgs()); |
|||
this.edgeAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getEdgeArgs()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToTransportMsg>> createTransportNotificationsMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(notificationAdmin, rabbitMqSettings, topicService.buildTopicName(transportNotificationSettings.getNotificationsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> createRuleEngineMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> createRuleEngineNotificationsMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(notificationAdmin, rabbitMqSettings, topicService.buildTopicName(ruleEngineSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> createTbCoreMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> createTbCoreNotificationsMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(notificationAdmin, rabbitMqSettings, |
|||
topicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToCoreMsg>> createToCoreMsgConsumer() { |
|||
return new TbRabbitMqConsumerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToCoreNotificationMsg>> createToCoreNotificationsMsgConsumer() { |
|||
return new TbRabbitMqConsumerTemplate<>(notificationAdmin, rabbitMqSettings, |
|||
topicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeMsg>> createEdgeMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(edgeAdmin, rabbitMqSettings, topicService.buildTopicName(edgeSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToEdgeMsg>> createEdgeMsgConsumer() { |
|||
return new TbRabbitMqConsumerTemplate<>(edgeAdmin, rabbitMqSettings, topicService.buildTopicName(edgeSettings.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToEdgeMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createToEdgeNotificationsMsgConsumer() { |
|||
return new TbRabbitMqConsumerTemplate<>(notificationAdmin, rabbitMqSettings, |
|||
topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToEdgeNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(notificationAdmin, rabbitMqSettings, |
|||
topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<TransportApiRequestMsg>> createTransportApiRequestConsumer() { |
|||
return new TbRabbitMqConsumerTemplate<>(transportApiAdmin, rabbitMqSettings, topicService.buildTopicName(transportApiSettings.getRequestsTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiRequestMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<TransportApiResponseMsg>> createTransportApiResponseProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(transportApiAdmin, rabbitMqSettings, topicService.buildTopicName(transportApiSettings.getResponsesTopic())); |
|||
} |
|||
|
|||
@Override |
|||
@Bean |
|||
public TbQueueRequestTemplate<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>, TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> createRemoteJsRequestTemplate() { |
|||
TbQueueProducer<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>> producer = new TbRabbitMqProducerTemplate<>(jsExecutorAdmin, rabbitMqSettings, jsInvokeSettings.getRequestTopic()); |
|||
TbQueueConsumer<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> consumer = new TbRabbitMqConsumerTemplate<>(jsExecutorAdmin, rabbitMqSettings, |
|||
jsInvokeSettings.getResponseTopic() + "." + serviceInfoProvider.getServiceId(), |
|||
msg -> { |
|||
JsInvokeProtos.RemoteJsResponse.Builder builder = JsInvokeProtos.RemoteJsResponse.newBuilder(); |
|||
JsonFormat.parser().ignoringUnknownFields().merge(new String(msg.getData(), StandardCharsets.UTF_8), builder); |
|||
return new TbProtoQueueMsg<>(msg.getKey(), builder.build(), msg.getHeaders()); |
|||
}); |
|||
|
|||
DefaultTbQueueRequestTemplate.DefaultTbQueueRequestTemplateBuilder |
|||
<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>, TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> builder = DefaultTbQueueRequestTemplate.builder(); |
|||
builder.queueAdmin(jsExecutorAdmin); |
|||
builder.requestTemplate(producer); |
|||
builder.responseTemplate(consumer); |
|||
builder.maxPendingRequests(jsInvokeSettings.getMaxPendingRequests()); |
|||
builder.maxRequestTimeout(jsInvokeSettings.getMaxRequestsTimeout()); |
|||
builder.pollInterval(jsInvokeSettings.getResponsePollInterval()); |
|||
return builder.build(); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToVersionControlServiceMsg>> createVersionControlMsgProducer() { |
|||
//TODO: version-control
|
|||
return null; |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgConsumer() { |
|||
return new TbRabbitMqConsumerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgConsumer() { |
|||
return new TbRabbitMqConsumerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getOtaPackageTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToOtaPackageStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getOtaPackageTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperMsgConsumer() { |
|||
return new TbRabbitMqConsumerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToHousekeeperServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperReprocessingMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getHousekeeperReprocessingTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperReprocessingMsgConsumer() { |
|||
return new TbRabbitMqConsumerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getHousekeeperReprocessingTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToHousekeeperServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@PreDestroy |
|||
private void destroy() { |
|||
if (coreAdmin != null) { |
|||
coreAdmin.destroy(); |
|||
} |
|||
if (ruleEngineAdmin != null) { |
|||
ruleEngineAdmin.destroy(); |
|||
} |
|||
if (jsExecutorAdmin != null) { |
|||
jsExecutorAdmin.destroy(); |
|||
} |
|||
if (transportApiAdmin != null) { |
|||
transportApiAdmin.destroy(); |
|||
} |
|||
if (notificationAdmin != null) { |
|||
notificationAdmin.destroy(); |
|||
} |
|||
if (edgeAdmin != null) { |
|||
edgeAdmin.destroy(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,202 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.provider; |
|||
|
|||
import com.google.protobuf.util.JsonFormat; |
|||
import jakarta.annotation.PreDestroy; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.queue.Queue; |
|||
import org.thingsboard.server.common.msg.queue.ServiceType; |
|||
import org.thingsboard.server.gen.js.JsInvokeProtos; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueConsumer; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.TbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; |
|||
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|||
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
|||
import org.thingsboard.server.queue.discovery.TopicService; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqAdmin; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqConsumerTemplate; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqProducerTemplate; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqQueueArguments; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueCoreSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueEdgeSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; |
|||
|
|||
import java.nio.charset.StandardCharsets; |
|||
|
|||
@Component |
|||
@ConditionalOnExpression("'${queue.type:null}'=='rabbitmq' && '${service.type:null}'=='tb-rule-engine'") |
|||
public class RabbitMqTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory { |
|||
|
|||
private final TopicService topicService; |
|||
private final TbQueueCoreSettings coreSettings; |
|||
private final TbServiceInfoProvider serviceInfoProvider; |
|||
private final TbQueueRuleEngineSettings ruleEngineSettings; |
|||
private final TbRabbitMqSettings rabbitMqSettings; |
|||
private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; |
|||
private final TbQueueTransportNotificationSettings transportNotificationSettings; |
|||
private final TbQueueEdgeSettings edgeSettings; |
|||
|
|||
private final TbQueueAdmin coreAdmin; |
|||
private final TbQueueAdmin ruleEngineAdmin; |
|||
private final TbQueueAdmin jsExecutorAdmin; |
|||
private final TbQueueAdmin notificationAdmin; |
|||
private final TbQueueAdmin edgeAdmin; |
|||
|
|||
public RabbitMqTbRuleEngineQueueFactory(TopicService topicService, TbQueueCoreSettings coreSettings, |
|||
TbQueueRuleEngineSettings ruleEngineSettings, |
|||
TbServiceInfoProvider serviceInfoProvider, |
|||
TbRabbitMqSettings rabbitMqSettings, |
|||
TbQueueRemoteJsInvokeSettings jsInvokeSettings, |
|||
TbQueueTransportNotificationSettings transportNotificationSettings, |
|||
TbQueueEdgeSettings edgeSettings, |
|||
TbRabbitMqQueueArguments queueArguments) { |
|||
this.topicService = topicService; |
|||
this.coreSettings = coreSettings; |
|||
this.serviceInfoProvider = serviceInfoProvider; |
|||
this.ruleEngineSettings = ruleEngineSettings; |
|||
this.rabbitMqSettings = rabbitMqSettings; |
|||
this.jsInvokeSettings = jsInvokeSettings; |
|||
this.transportNotificationSettings = transportNotificationSettings; |
|||
this.edgeSettings = edgeSettings; |
|||
|
|||
this.coreAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getCoreArgs()); |
|||
this.ruleEngineAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getRuleEngineArgs()); |
|||
this.jsExecutorAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getJsExecutorArgs()); |
|||
this.notificationAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getNotificationsArgs()); |
|||
this.edgeAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getEdgeArgs()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToTransportMsg>> createTransportNotificationsMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(notificationAdmin, rabbitMqSettings, topicService.buildTopicName(transportNotificationSettings.getNotificationsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> createRuleEngineMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(ruleEngineAdmin, rabbitMqSettings, topicService.buildTopicName(ruleEngineSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> createRuleEngineNotificationsMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(notificationAdmin, rabbitMqSettings, topicService.buildTopicName(ruleEngineSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> createTbCoreMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> createTbCoreNotificationsMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(notificationAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeMsg>> createEdgeMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(edgeAdmin, rabbitMqSettings, topicService.buildTopicName(edgeSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(notificationAdmin, rabbitMqSettings, topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineMsg>> createToRuleEngineMsgConsumer(Queue configuration) { |
|||
return new TbRabbitMqConsumerTemplate<>(ruleEngineAdmin, rabbitMqSettings, topicService.buildTopicName(configuration.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> createToRuleEngineNotificationsMsgConsumer() { |
|||
return new TbRabbitMqConsumerTemplate<>(notificationAdmin, rabbitMqSettings, |
|||
topicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
@Bean |
|||
public TbQueueRequestTemplate<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>, TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> createRemoteJsRequestTemplate() { |
|||
TbQueueProducer<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>> producer = new TbRabbitMqProducerTemplate<>(jsExecutorAdmin, rabbitMqSettings, jsInvokeSettings.getRequestTopic()); |
|||
TbQueueConsumer<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> consumer = new TbRabbitMqConsumerTemplate<>(jsExecutorAdmin, rabbitMqSettings, |
|||
jsInvokeSettings.getResponseTopic() + "." + serviceInfoProvider.getServiceId(), |
|||
msg -> { |
|||
JsInvokeProtos.RemoteJsResponse.Builder builder = JsInvokeProtos.RemoteJsResponse.newBuilder(); |
|||
JsonFormat.parser().ignoringUnknownFields().merge(new String(msg.getData(), StandardCharsets.UTF_8), builder); |
|||
return new TbProtoQueueMsg<>(msg.getKey(), builder.build(), msg.getHeaders()); |
|||
}); |
|||
|
|||
DefaultTbQueueRequestTemplate.DefaultTbQueueRequestTemplateBuilder |
|||
<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>, TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> builder = DefaultTbQueueRequestTemplate.builder(); |
|||
builder.queueAdmin(jsExecutorAdmin); |
|||
builder.requestTemplate(producer); |
|||
builder.responseTemplate(consumer); |
|||
builder.maxPendingRequests(jsInvokeSettings.getMaxPendingRequests()); |
|||
builder.maxRequestTimeout(jsInvokeSettings.getMaxRequestsTimeout()); |
|||
builder.pollInterval(jsInvokeSettings.getResponsePollInterval()); |
|||
return builder.build(); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getOtaPackageTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic())); |
|||
} |
|||
|
|||
@PreDestroy |
|||
private void destroy() { |
|||
if (coreAdmin != null) { |
|||
coreAdmin.destroy(); |
|||
} |
|||
if (ruleEngineAdmin != null) { |
|||
ruleEngineAdmin.destroy(); |
|||
} |
|||
if (jsExecutorAdmin != null) { |
|||
jsExecutorAdmin.destroy(); |
|||
} |
|||
if (notificationAdmin != null) { |
|||
notificationAdmin.destroy(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,98 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.provider; |
|||
|
|||
import jakarta.annotation.PreDestroy; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.gen.transport.TransportProtos; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueConsumer; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|||
import org.thingsboard.server.queue.discovery.TopicService; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqAdmin; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqConsumerTemplate; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqProducerTemplate; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqQueueArguments; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueCoreSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueVersionControlSettings; |
|||
|
|||
@Component |
|||
@ConditionalOnExpression("'${queue.type:null}'=='rabbitmq' && '${service.type:null}'=='tb-vc-executor'") |
|||
public class RabbitMqTbVersionControlQueueFactory implements TbVersionControlQueueFactory { |
|||
|
|||
private final TbRabbitMqSettings rabbitMqSettings; |
|||
private final TbQueueCoreSettings coreSettings; |
|||
private final TbQueueVersionControlSettings vcSettings; |
|||
private final TopicService topicService; |
|||
|
|||
private final TbQueueAdmin coreAdmin; |
|||
private final TbQueueAdmin notificationAdmin; |
|||
private final TbQueueAdmin vcAdmin; |
|||
|
|||
public RabbitMqTbVersionControlQueueFactory(TbRabbitMqSettings rabbitMqSettings, |
|||
TbQueueCoreSettings coreSettings, |
|||
TbQueueVersionControlSettings vcSettings, |
|||
TbRabbitMqQueueArguments queueArguments, |
|||
TopicService topicService |
|||
) { |
|||
this.rabbitMqSettings = rabbitMqSettings; |
|||
this.coreSettings = coreSettings; |
|||
this.vcSettings = vcSettings; |
|||
this.topicService = topicService; |
|||
|
|||
this.coreAdmin = new TbRabbitMqAdmin(this.rabbitMqSettings, queueArguments.getCoreArgs()); |
|||
this.notificationAdmin = new TbRabbitMqAdmin(this.rabbitMqSettings, queueArguments.getNotificationsArgs()); |
|||
this.vcAdmin = new TbRabbitMqAdmin(this.rabbitMqSettings, queueArguments.getVcArgs()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToCoreNotificationMsg>> createTbCoreNotificationsMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(notificationAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<TransportProtos.ToVersionControlServiceMsg>> createToVersionControlMsgConsumer() { |
|||
return new TbRabbitMqConsumerTemplate<>(vcAdmin, rabbitMqSettings, topicService.buildTopicName(vcSettings.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportProtos.ToVersionControlServiceMsg.parseFrom(msg.getData()), msg.getHeaders()) |
|||
); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToHousekeeperServiceMsg>> createHousekeeperMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic())); |
|||
} |
|||
|
|||
@PreDestroy |
|||
private void destroy() { |
|||
if (coreAdmin != null) { |
|||
coreAdmin.destroy(); |
|||
} |
|||
if (notificationAdmin != null) { |
|||
notificationAdmin.destroy(); |
|||
} |
|||
if (vcAdmin != null) { |
|||
vcAdmin.destroy(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,154 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.provider; |
|||
|
|||
import jakarta.annotation.PreDestroy; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueConsumer; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.TbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|||
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
|||
import org.thingsboard.server.queue.discovery.TopicService; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqAdmin; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqConsumerTemplate; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqProducerTemplate; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqQueueArguments; |
|||
import org.thingsboard.server.queue.rabbitmq.TbRabbitMqSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueCoreSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; |
|||
|
|||
@Component |
|||
@ConditionalOnExpression("'${queue.type:null}'=='rabbitmq' && (('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true') || '${service.type:null}'=='tb-transport')") |
|||
@Slf4j |
|||
public class RabbitMqTransportQueueFactory implements TbTransportQueueFactory { |
|||
private final TbQueueTransportApiSettings transportApiSettings; |
|||
private final TbQueueTransportNotificationSettings transportNotificationSettings; |
|||
private final TbRabbitMqSettings rabbitMqSettings; |
|||
private final TbServiceInfoProvider serviceInfoProvider; |
|||
private final TbQueueCoreSettings coreSettings; |
|||
private final TbQueueRuleEngineSettings ruleEngineSettings; |
|||
private final TopicService topicService; |
|||
|
|||
private final TbQueueAdmin coreAdmin; |
|||
private final TbQueueAdmin ruleEngineAdmin; |
|||
private final TbQueueAdmin transportApiAdmin; |
|||
private final TbQueueAdmin notificationAdmin; |
|||
|
|||
public RabbitMqTransportQueueFactory(TbQueueTransportApiSettings transportApiSettings, |
|||
TbQueueTransportNotificationSettings transportNotificationSettings, |
|||
TbRabbitMqSettings rabbitMqSettings, |
|||
TbServiceInfoProvider serviceInfoProvider, |
|||
TbQueueCoreSettings coreSettings, |
|||
TbQueueRuleEngineSettings ruleEngineSettings, |
|||
TbRabbitMqQueueArguments queueArguments, |
|||
TopicService topicService) { |
|||
this.transportApiSettings = transportApiSettings; |
|||
this.transportNotificationSettings = transportNotificationSettings; |
|||
this.rabbitMqSettings = rabbitMqSettings; |
|||
this.serviceInfoProvider = serviceInfoProvider; |
|||
this.coreSettings = coreSettings; |
|||
this.ruleEngineSettings = ruleEngineSettings; |
|||
this.topicService = topicService; |
|||
|
|||
this.coreAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getCoreArgs()); |
|||
this.ruleEngineAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getRuleEngineArgs()); |
|||
this.transportApiAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getTransportApiArgs()); |
|||
this.notificationAdmin = new TbRabbitMqAdmin(rabbitMqSettings, queueArguments.getNotificationsArgs()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueRequestTemplate<TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> createTransportApiRequestTemplate() { |
|||
TbQueueProducer<TbProtoQueueMsg<TransportApiRequestMsg>> producerTemplate = |
|||
new TbRabbitMqProducerTemplate<>(transportApiAdmin, rabbitMqSettings, topicService.buildTopicName(transportApiSettings.getRequestsTopic())); |
|||
|
|||
TbQueueConsumer<TbProtoQueueMsg<TransportApiResponseMsg>> consumerTemplate = |
|||
new TbRabbitMqConsumerTemplate<>(transportApiAdmin, rabbitMqSettings, |
|||
topicService.buildTopicName(transportApiSettings.getResponsesTopic() + "." + serviceInfoProvider.getServiceId()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiResponseMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
|
|||
DefaultTbQueueRequestTemplate.DefaultTbQueueRequestTemplateBuilder |
|||
<TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> templateBuilder = DefaultTbQueueRequestTemplate.builder(); |
|||
templateBuilder.queueAdmin(transportApiAdmin); |
|||
templateBuilder.requestTemplate(producerTemplate); |
|||
templateBuilder.responseTemplate(consumerTemplate); |
|||
templateBuilder.maxPendingRequests(transportApiSettings.getMaxPendingRequests()); |
|||
templateBuilder.maxRequestTimeout(transportApiSettings.getMaxRequestsTimeout()); |
|||
templateBuilder.pollInterval(transportApiSettings.getResponsePollInterval()); |
|||
return templateBuilder.build(); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> createRuleEngineMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(ruleEngineAdmin, rabbitMqSettings, topicService.buildTopicName(ruleEngineSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> createTbCoreMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> createTbCoreNotificationsMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(notificationAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToTransportMsg>> createTransportNotificationsConsumer() { |
|||
return new TbRabbitMqConsumerTemplate<>(notificationAdmin, rabbitMqSettings, topicService.buildTopicName(transportNotificationSettings.getNotificationsTopic() + "." + serviceInfoProvider.getServiceId()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToTransportMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperMsgProducer() { |
|||
return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic())); |
|||
} |
|||
|
|||
@PreDestroy |
|||
private void destroy() { |
|||
if (coreAdmin != null) { |
|||
coreAdmin.destroy(); |
|||
} |
|||
if (ruleEngineAdmin != null) { |
|||
ruleEngineAdmin.destroy(); |
|||
} |
|||
if (transportApiAdmin != null) { |
|||
transportApiAdmin.destroy(); |
|||
} |
|||
if (notificationAdmin != null) { |
|||
notificationAdmin.destroy(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,312 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.provider; |
|||
|
|||
import com.google.protobuf.util.JsonFormat; |
|||
import jakarta.annotation.PreDestroy; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.queue.Queue; |
|||
import org.thingsboard.server.common.msg.queue.ServiceType; |
|||
import org.thingsboard.server.gen.js.JsInvokeProtos; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeEventNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueConsumer; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.TbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusAdmin; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusConsumerTemplate; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusProducerTemplate; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusQueueConfigs; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusSettings; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; |
|||
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|||
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
|||
import org.thingsboard.server.queue.discovery.TopicService; |
|||
import org.thingsboard.server.queue.settings.TbQueueCoreSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueEdgeSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueVersionControlSettings; |
|||
|
|||
import java.nio.charset.StandardCharsets; |
|||
|
|||
@Component |
|||
@ConditionalOnExpression("'${queue.type:null}'=='service-bus' && '${service.type:null}'=='monolith'") |
|||
public class ServiceBusMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngineQueueFactory, TbVersionControlQueueFactory { |
|||
|
|||
private final TopicService topicService; |
|||
private final TbQueueCoreSettings coreSettings; |
|||
private final TbServiceInfoProvider serviceInfoProvider; |
|||
private final TbQueueRuleEngineSettings ruleEngineSettings; |
|||
private final TbQueueTransportApiSettings transportApiSettings; |
|||
private final TbQueueTransportNotificationSettings transportNotificationSettings; |
|||
private final TbServiceBusSettings serviceBusSettings; |
|||
private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; |
|||
private final TbQueueVersionControlSettings vcSettings; |
|||
private final TbQueueEdgeSettings edgeSettings; |
|||
|
|||
private final TbQueueAdmin coreAdmin; |
|||
private final TbQueueAdmin ruleEngineAdmin; |
|||
private final TbQueueAdmin jsExecutorAdmin; |
|||
private final TbQueueAdmin transportApiAdmin; |
|||
private final TbQueueAdmin notificationAdmin; |
|||
private final TbQueueAdmin vcAdmin; |
|||
private final TbQueueAdmin edgeAdmin; |
|||
|
|||
public ServiceBusMonolithQueueFactory(TopicService topicService, TbQueueCoreSettings coreSettings, |
|||
TbQueueRuleEngineSettings ruleEngineSettings, |
|||
TbServiceInfoProvider serviceInfoProvider, |
|||
TbQueueTransportApiSettings transportApiSettings, |
|||
TbQueueTransportNotificationSettings transportNotificationSettings, |
|||
TbServiceBusSettings serviceBusSettings, |
|||
TbQueueRemoteJsInvokeSettings jsInvokeSettings, |
|||
TbQueueVersionControlSettings vcSettings, |
|||
TbQueueEdgeSettings edgeSettings, |
|||
TbServiceBusQueueConfigs serviceBusQueueConfigs) { |
|||
this.topicService = topicService; |
|||
this.coreSettings = coreSettings; |
|||
this.serviceInfoProvider = serviceInfoProvider; |
|||
this.ruleEngineSettings = ruleEngineSettings; |
|||
this.transportApiSettings = transportApiSettings; |
|||
this.transportNotificationSettings = transportNotificationSettings; |
|||
this.serviceBusSettings = serviceBusSettings; |
|||
this.jsInvokeSettings = jsInvokeSettings; |
|||
this.vcSettings = vcSettings; |
|||
this.edgeSettings = edgeSettings; |
|||
|
|||
this.coreAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getCoreConfigs()); |
|||
this.ruleEngineAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getRuleEngineConfigs()); |
|||
this.jsExecutorAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getJsExecutorConfigs()); |
|||
this.transportApiAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getTransportApiConfigs()); |
|||
this.notificationAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getNotificationsConfigs()); |
|||
this.vcAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getVcConfigs()); |
|||
this.edgeAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getEdgeConfigs()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToTransportMsg>> createTransportNotificationsMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(notificationAdmin, serviceBusSettings, topicService.buildTopicName(transportNotificationSettings.getNotificationsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> createRuleEngineMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(ruleEngineAdmin, serviceBusSettings, topicService.buildTopicName(ruleEngineSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> createRuleEngineNotificationsMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(notificationAdmin, serviceBusSettings, topicService.buildTopicName(ruleEngineSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> createTbCoreMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> createTbCoreNotificationsMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(notificationAdmin, serviceBusSettings, |
|||
topicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToVersionControlServiceMsg>> createToVersionControlMsgConsumer() { |
|||
return new TbServiceBusConsumerTemplate<>(vcAdmin, serviceBusSettings, topicService.buildTopicName(vcSettings.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToVersionControlServiceMsg.parseFrom(msg.getData()), msg.getHeaders()) |
|||
); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineMsg>> createToRuleEngineMsgConsumer(Queue configuration) { |
|||
return new TbServiceBusConsumerTemplate<>(ruleEngineAdmin, serviceBusSettings, configuration.getTopic(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> createToRuleEngineNotificationsMsgConsumer() { |
|||
return new TbServiceBusConsumerTemplate<>(notificationAdmin, serviceBusSettings, |
|||
topicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToCoreMsg>> createToCoreMsgConsumer() { |
|||
return new TbServiceBusConsumerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToCoreNotificationMsg>> createToCoreNotificationsMsgConsumer() { |
|||
return new TbServiceBusConsumerTemplate<>(notificationAdmin, serviceBusSettings, |
|||
topicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<TransportApiRequestMsg>> createTransportApiRequestConsumer() { |
|||
return new TbServiceBusConsumerTemplate<>(transportApiAdmin, serviceBusSettings, topicService.buildTopicName(transportApiSettings.getRequestsTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiRequestMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<TransportApiResponseMsg>> createTransportApiResponseProducer() { |
|||
return new TbServiceBusProducerTemplate<>(transportApiAdmin, serviceBusSettings, topicService.buildTopicName(transportApiSettings.getResponsesTopic())); |
|||
} |
|||
|
|||
@Override |
|||
@Bean |
|||
public TbQueueRequestTemplate<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>, TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> createRemoteJsRequestTemplate() { |
|||
TbQueueProducer<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>> producer = new TbServiceBusProducerTemplate<>(jsExecutorAdmin, serviceBusSettings, jsInvokeSettings.getRequestTopic()); |
|||
TbQueueConsumer<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> consumer = new TbServiceBusConsumerTemplate<>(jsExecutorAdmin, serviceBusSettings, |
|||
jsInvokeSettings.getResponseTopic() + "." + serviceInfoProvider.getServiceId(), |
|||
msg -> { |
|||
JsInvokeProtos.RemoteJsResponse.Builder builder = JsInvokeProtos.RemoteJsResponse.newBuilder(); |
|||
JsonFormat.parser().ignoringUnknownFields().merge(new String(msg.getData(), StandardCharsets.UTF_8), builder); |
|||
return new TbProtoQueueMsg<>(msg.getKey(), builder.build(), msg.getHeaders()); |
|||
}); |
|||
|
|||
DefaultTbQueueRequestTemplate.DefaultTbQueueRequestTemplateBuilder |
|||
<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>, TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> builder = DefaultTbQueueRequestTemplate.builder(); |
|||
builder.queueAdmin(jsExecutorAdmin); |
|||
builder.requestTemplate(producer); |
|||
builder.responseTemplate(consumer); |
|||
builder.maxPendingRequests(jsInvokeSettings.getMaxPendingRequests()); |
|||
builder.maxRequestTimeout(jsInvokeSettings.getMaxRequestsTimeout()); |
|||
builder.pollInterval(jsInvokeSettings.getResponsePollInterval()); |
|||
return builder.build(); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgConsumer() { |
|||
return new TbServiceBusConsumerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgConsumer() { |
|||
return new TbServiceBusConsumerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getOtaPackageTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToOtaPackageStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getOtaPackageTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToVersionControlServiceMsg>> createVersionControlMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(vcAdmin, serviceBusSettings, topicService.buildTopicName(vcSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperMsgConsumer() { |
|||
return new TbServiceBusConsumerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToHousekeeperServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperReprocessingMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getHousekeeperReprocessingTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperReprocessingMsgConsumer() { |
|||
return new TbServiceBusConsumerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getHousekeeperReprocessingTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToHousekeeperServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToEdgeMsg>> createEdgeMsgConsumer() { |
|||
return new TbServiceBusConsumerTemplate<>(edgeAdmin, serviceBusSettings, topicService.buildTopicName(edgeSettings.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToEdgeMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeMsg>> createEdgeMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(edgeAdmin, serviceBusSettings, topicService.buildTopicName(edgeSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createToEdgeNotificationsMsgConsumer() { |
|||
return new TbServiceBusConsumerTemplate<>(notificationAdmin, serviceBusSettings, |
|||
topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToEdgeNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(notificationAdmin, serviceBusSettings, |
|||
topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> createEdgeEventMsgProducer() { |
|||
return null; |
|||
} |
|||
|
|||
@PreDestroy |
|||
private void destroy() { |
|||
if (coreAdmin != null) { |
|||
coreAdmin.destroy(); |
|||
} |
|||
if (ruleEngineAdmin != null) { |
|||
ruleEngineAdmin.destroy(); |
|||
} |
|||
if (jsExecutorAdmin != null) { |
|||
jsExecutorAdmin.destroy(); |
|||
} |
|||
if (transportApiAdmin != null) { |
|||
transportApiAdmin.destroy(); |
|||
} |
|||
if (notificationAdmin != null) { |
|||
notificationAdmin.destroy(); |
|||
} |
|||
if (vcAdmin != null) { |
|||
vcAdmin.destroy(); |
|||
} |
|||
if (edgeAdmin != null) { |
|||
edgeAdmin.destroy(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,278 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.provider; |
|||
|
|||
import com.google.protobuf.util.JsonFormat; |
|||
import jakarta.annotation.PreDestroy; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.msg.queue.ServiceType; |
|||
import org.thingsboard.server.gen.js.JsInvokeProtos; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueConsumer; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.TbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusAdmin; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusConsumerTemplate; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusProducerTemplate; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusQueueConfigs; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusSettings; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; |
|||
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|||
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
|||
import org.thingsboard.server.queue.discovery.TopicService; |
|||
import org.thingsboard.server.queue.settings.TbQueueCoreSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueEdgeSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; |
|||
|
|||
import java.nio.charset.StandardCharsets; |
|||
|
|||
@Component |
|||
@ConditionalOnExpression("'${queue.type:null}'=='service-bus' && '${service.type:null}'=='tb-core'") |
|||
public class ServiceBusTbCoreQueueFactory implements TbCoreQueueFactory { |
|||
|
|||
private final TbServiceBusSettings serviceBusSettings; |
|||
private final TbQueueRuleEngineSettings ruleEngineSettings; |
|||
private final TbQueueCoreSettings coreSettings; |
|||
private final TbQueueTransportApiSettings transportApiSettings; |
|||
private final TopicService topicService; |
|||
private final TbServiceInfoProvider serviceInfoProvider; |
|||
private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; |
|||
private final TbQueueTransportNotificationSettings transportNotificationSettings; |
|||
private final TbQueueEdgeSettings edgeSettings; |
|||
|
|||
private final TbQueueAdmin coreAdmin; |
|||
private final TbQueueAdmin ruleEngineAdmin; |
|||
private final TbQueueAdmin jsExecutorAdmin; |
|||
private final TbQueueAdmin transportApiAdmin; |
|||
private final TbQueueAdmin notificationAdmin; |
|||
private final TbQueueAdmin edgeAdmin; |
|||
|
|||
public ServiceBusTbCoreQueueFactory(TbServiceBusSettings serviceBusSettings, |
|||
TbQueueCoreSettings coreSettings, |
|||
TbQueueTransportApiSettings transportApiSettings, |
|||
TbQueueRuleEngineSettings ruleEngineSettings, |
|||
TopicService topicService, |
|||
TbServiceInfoProvider serviceInfoProvider, |
|||
TbQueueRemoteJsInvokeSettings jsInvokeSettings, |
|||
TbQueueTransportNotificationSettings transportNotificationSettings, |
|||
TbQueueEdgeSettings edgeSettings, |
|||
TbServiceBusQueueConfigs serviceBusQueueConfigs) { |
|||
this.serviceBusSettings = serviceBusSettings; |
|||
this.coreSettings = coreSettings; |
|||
this.transportApiSettings = transportApiSettings; |
|||
this.ruleEngineSettings = ruleEngineSettings; |
|||
this.topicService = topicService; |
|||
this.serviceInfoProvider = serviceInfoProvider; |
|||
this.jsInvokeSettings = jsInvokeSettings; |
|||
this.transportNotificationSettings = transportNotificationSettings; |
|||
this.edgeSettings = edgeSettings; |
|||
|
|||
this.coreAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getCoreConfigs()); |
|||
this.ruleEngineAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getRuleEngineConfigs()); |
|||
this.jsExecutorAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getJsExecutorConfigs()); |
|||
this.transportApiAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getTransportApiConfigs()); |
|||
this.notificationAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getNotificationsConfigs()); |
|||
this.edgeAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getEdgeConfigs()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToTransportMsg>> createTransportNotificationsMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(notificationAdmin, serviceBusSettings, topicService.buildTopicName(transportNotificationSettings.getNotificationsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> createRuleEngineMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> createRuleEngineNotificationsMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(notificationAdmin, serviceBusSettings, topicService.buildTopicName(ruleEngineSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> createTbCoreMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> createTbCoreNotificationsMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(notificationAdmin, serviceBusSettings, |
|||
topicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToCoreMsg>> createToCoreMsgConsumer() { |
|||
return new TbServiceBusConsumerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToCoreNotificationMsg>> createToCoreNotificationsMsgConsumer() { |
|||
return new TbServiceBusConsumerTemplate<>(notificationAdmin, serviceBusSettings, |
|||
topicService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<TransportApiRequestMsg>> createTransportApiRequestConsumer() { |
|||
return new TbServiceBusConsumerTemplate<>(transportApiAdmin, serviceBusSettings, topicService.buildTopicName(transportApiSettings.getRequestsTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiRequestMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<TransportApiResponseMsg>> createTransportApiResponseProducer() { |
|||
return new TbServiceBusProducerTemplate<>(transportApiAdmin, serviceBusSettings, topicService.buildTopicName(transportApiSettings.getResponsesTopic())); |
|||
} |
|||
|
|||
@Override |
|||
@Bean |
|||
public TbQueueRequestTemplate<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>, TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> createRemoteJsRequestTemplate() { |
|||
TbQueueProducer<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>> producer = new TbServiceBusProducerTemplate<>(jsExecutorAdmin, serviceBusSettings, jsInvokeSettings.getRequestTopic()); |
|||
TbQueueConsumer<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> consumer = new TbServiceBusConsumerTemplate<>(jsExecutorAdmin, serviceBusSettings, |
|||
jsInvokeSettings.getResponseTopic() + "." + serviceInfoProvider.getServiceId(), |
|||
msg -> { |
|||
JsInvokeProtos.RemoteJsResponse.Builder builder = JsInvokeProtos.RemoteJsResponse.newBuilder(); |
|||
JsonFormat.parser().ignoringUnknownFields().merge(new String(msg.getData(), StandardCharsets.UTF_8), builder); |
|||
return new TbProtoQueueMsg<>(msg.getKey(), builder.build(), msg.getHeaders()); |
|||
}); |
|||
|
|||
DefaultTbQueueRequestTemplate.DefaultTbQueueRequestTemplateBuilder |
|||
<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>, TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> builder = DefaultTbQueueRequestTemplate.builder(); |
|||
builder.queueAdmin(jsExecutorAdmin); |
|||
builder.requestTemplate(producer); |
|||
builder.responseTemplate(consumer); |
|||
builder.maxPendingRequests(jsInvokeSettings.getMaxPendingRequests()); |
|||
builder.maxRequestTimeout(jsInvokeSettings.getMaxRequestsTimeout()); |
|||
builder.pollInterval(jsInvokeSettings.getResponsePollInterval()); |
|||
return builder.build(); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgConsumer() { |
|||
return new TbServiceBusConsumerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgConsumer() { |
|||
return new TbServiceBusConsumerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getOtaPackageTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToOtaPackageStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getOtaPackageTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToVersionControlServiceMsg>> createVersionControlMsgProducer() { |
|||
//TODO: version-control
|
|||
return null; |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperMsgConsumer() { |
|||
return new TbServiceBusConsumerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToHousekeeperServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperReprocessingMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getHousekeeperReprocessingTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperReprocessingMsgConsumer() { |
|||
return new TbServiceBusConsumerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getHousekeeperReprocessingTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToHousekeeperServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToEdgeMsg>> createEdgeMsgConsumer() { |
|||
return new TbServiceBusConsumerTemplate<>(edgeAdmin, serviceBusSettings, topicService.buildTopicName(edgeSettings.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToEdgeMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeMsg>> createEdgeMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(edgeAdmin, serviceBusSettings, topicService.buildTopicName(edgeSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createToEdgeNotificationsMsgConsumer() { |
|||
return new TbServiceBusConsumerTemplate<>(notificationAdmin, serviceBusSettings, |
|||
topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToEdgeNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(notificationAdmin, serviceBusSettings, |
|||
topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName()); |
|||
} |
|||
|
|||
@PreDestroy |
|||
private void destroy() { |
|||
if (coreAdmin != null) { |
|||
coreAdmin.destroy(); |
|||
} |
|||
if (ruleEngineAdmin != null) { |
|||
ruleEngineAdmin.destroy(); |
|||
} |
|||
if (jsExecutorAdmin != null) { |
|||
jsExecutorAdmin.destroy(); |
|||
} |
|||
if (transportApiAdmin != null) { |
|||
transportApiAdmin.destroy(); |
|||
} |
|||
if (notificationAdmin != null) { |
|||
notificationAdmin.destroy(); |
|||
} |
|||
if (edgeAdmin != null) { |
|||
edgeAdmin.destroy(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,202 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.provider; |
|||
|
|||
import com.google.protobuf.util.JsonFormat; |
|||
import jakarta.annotation.PreDestroy; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.queue.Queue; |
|||
import org.thingsboard.server.common.msg.queue.ServiceType; |
|||
import org.thingsboard.server.gen.js.JsInvokeProtos; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueConsumer; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.TbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusAdmin; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusConsumerTemplate; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusProducerTemplate; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusQueueConfigs; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusSettings; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; |
|||
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|||
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
|||
import org.thingsboard.server.queue.discovery.TopicService; |
|||
import org.thingsboard.server.queue.settings.TbQueueCoreSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueEdgeSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRemoteJsInvokeSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; |
|||
|
|||
import java.nio.charset.StandardCharsets; |
|||
|
|||
@Component |
|||
@ConditionalOnExpression("'${queue.type:null}'=='service-bus' && '${service.type:null}'=='tb-rule-engine'") |
|||
public class ServiceBusTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory { |
|||
|
|||
private final TopicService topicService; |
|||
private final TbQueueCoreSettings coreSettings; |
|||
private final TbServiceInfoProvider serviceInfoProvider; |
|||
private final TbQueueRuleEngineSettings ruleEngineSettings; |
|||
private final TbServiceBusSettings serviceBusSettings; |
|||
private final TbQueueRemoteJsInvokeSettings jsInvokeSettings; |
|||
private final TbQueueTransportNotificationSettings transportNotificationSettings; |
|||
private final TbQueueEdgeSettings edgeSettings; |
|||
|
|||
private final TbQueueAdmin coreAdmin; |
|||
private final TbQueueAdmin ruleEngineAdmin; |
|||
private final TbQueueAdmin jsExecutorAdmin; |
|||
private final TbQueueAdmin notificationAdmin; |
|||
private final TbQueueAdmin edgeAdmin; |
|||
|
|||
public ServiceBusTbRuleEngineQueueFactory(TopicService topicService, TbQueueCoreSettings coreSettings, |
|||
TbQueueRuleEngineSettings ruleEngineSettings, |
|||
TbServiceInfoProvider serviceInfoProvider, |
|||
TbServiceBusSettings serviceBusSettings, |
|||
TbQueueRemoteJsInvokeSettings jsInvokeSettings, |
|||
TbQueueTransportNotificationSettings transportNotificationSettings, |
|||
TbQueueEdgeSettings edgeSettings, |
|||
TbServiceBusQueueConfigs serviceBusQueueConfigs) { |
|||
this.topicService = topicService; |
|||
this.coreSettings = coreSettings; |
|||
this.serviceInfoProvider = serviceInfoProvider; |
|||
this.ruleEngineSettings = ruleEngineSettings; |
|||
this.serviceBusSettings = serviceBusSettings; |
|||
this.jsInvokeSettings = jsInvokeSettings; |
|||
this.transportNotificationSettings = transportNotificationSettings; |
|||
this.edgeSettings = edgeSettings; |
|||
|
|||
this.coreAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getCoreConfigs()); |
|||
this.ruleEngineAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getRuleEngineConfigs()); |
|||
this.jsExecutorAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getJsExecutorConfigs()); |
|||
this.notificationAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getNotificationsConfigs()); |
|||
this.edgeAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getEdgeConfigs()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToTransportMsg>> createTransportNotificationsMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(notificationAdmin, serviceBusSettings, topicService.buildTopicName(transportNotificationSettings.getNotificationsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> createRuleEngineMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(ruleEngineAdmin, serviceBusSettings, topicService.buildTopicName(ruleEngineSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> createRuleEngineNotificationsMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(notificationAdmin, serviceBusSettings, topicService.buildTopicName(ruleEngineSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> createTbCoreMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> createTbCoreNotificationsMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(notificationAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeMsg>> createEdgeMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(edgeAdmin, serviceBusSettings, topicService.buildTopicName(edgeSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToEdgeNotificationMsg>> createEdgeNotificationsMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(notificationAdmin, serviceBusSettings, topicService.getEdgeNotificationsTopic(serviceInfoProvider.getServiceId()).getFullTopicName()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineMsg>> createToRuleEngineMsgConsumer(Queue configuration) { |
|||
return new TbServiceBusConsumerTemplate<>(ruleEngineAdmin, serviceBusSettings, topicService.buildTopicName(configuration.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineNotificationMsg>> createToRuleEngineNotificationsMsgConsumer() { |
|||
return new TbServiceBusConsumerTemplate<>(notificationAdmin, serviceBusSettings, |
|||
topicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineNotificationMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
@Bean |
|||
public TbQueueRequestTemplate<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>, TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> createRemoteJsRequestTemplate() { |
|||
TbQueueProducer<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>> producer = new TbServiceBusProducerTemplate<>(jsExecutorAdmin, serviceBusSettings, jsInvokeSettings.getRequestTopic()); |
|||
TbQueueConsumer<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> consumer = new TbServiceBusConsumerTemplate<>(jsExecutorAdmin, serviceBusSettings, |
|||
jsInvokeSettings.getResponseTopic() + "." + serviceInfoProvider.getServiceId(), |
|||
msg -> { |
|||
JsInvokeProtos.RemoteJsResponse.Builder builder = JsInvokeProtos.RemoteJsResponse.newBuilder(); |
|||
JsonFormat.parser().ignoringUnknownFields().merge(new String(msg.getData(), StandardCharsets.UTF_8), builder); |
|||
return new TbProtoQueueMsg<>(msg.getKey(), builder.build(), msg.getHeaders()); |
|||
}); |
|||
|
|||
DefaultTbQueueRequestTemplate.DefaultTbQueueRequestTemplateBuilder |
|||
<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>, TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> builder = DefaultTbQueueRequestTemplate.builder(); |
|||
builder.queueAdmin(jsExecutorAdmin); |
|||
builder.requestTemplate(producer); |
|||
builder.responseTemplate(consumer); |
|||
builder.maxPendingRequests(jsInvokeSettings.getMaxPendingRequests()); |
|||
builder.maxRequestTimeout(jsInvokeSettings.getMaxRequestsTimeout()); |
|||
builder.pollInterval(jsInvokeSettings.getResponsePollInterval()); |
|||
return builder.build(); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getOtaPackageTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic())); |
|||
} |
|||
|
|||
@PreDestroy |
|||
private void destroy() { |
|||
if (coreAdmin != null) { |
|||
coreAdmin.destroy(); |
|||
} |
|||
if (ruleEngineAdmin != null) { |
|||
ruleEngineAdmin.destroy(); |
|||
} |
|||
if (jsExecutorAdmin != null) { |
|||
jsExecutorAdmin.destroy(); |
|||
} |
|||
if (notificationAdmin != null) { |
|||
notificationAdmin.destroy(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,98 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.provider; |
|||
|
|||
import jakarta.annotation.PreDestroy; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.gen.transport.TransportProtos; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueConsumer; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusAdmin; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusConsumerTemplate; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusProducerTemplate; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusQueueConfigs; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusSettings; |
|||
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|||
import org.thingsboard.server.queue.discovery.TopicService; |
|||
import org.thingsboard.server.queue.settings.TbQueueCoreSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueVersionControlSettings; |
|||
|
|||
@Component |
|||
@ConditionalOnExpression("'${queue.type:null}'=='service-bus' && '${service.type:null}'=='tb-vc-executor'") |
|||
public class ServiceBusTbVersionControlQueueFactory implements TbVersionControlQueueFactory { |
|||
|
|||
private final TbServiceBusSettings serviceBusSettings; |
|||
private final TbQueueCoreSettings coreSettings; |
|||
private final TbQueueVersionControlSettings vcSettings; |
|||
private final TopicService topicService; |
|||
|
|||
private final TbQueueAdmin coreAdmin; |
|||
private final TbQueueAdmin notificationAdmin; |
|||
private final TbQueueAdmin vcAdmin; |
|||
|
|||
public ServiceBusTbVersionControlQueueFactory(TbServiceBusSettings serviceBusSettings, |
|||
TbQueueCoreSettings coreSettings, |
|||
TbQueueVersionControlSettings vcSettings, |
|||
TbServiceBusQueueConfigs serviceBusQueueConfigs, |
|||
TopicService topicService |
|||
) { |
|||
this.serviceBusSettings = serviceBusSettings; |
|||
this.coreSettings = coreSettings; |
|||
this.vcSettings = vcSettings; |
|||
this.topicService = topicService; |
|||
|
|||
this.coreAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getCoreConfigs()); |
|||
this.notificationAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getNotificationsConfigs()); |
|||
this.vcAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getVcConfigs()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToCoreNotificationMsg>> createTbCoreNotificationsMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(notificationAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<TransportProtos.ToVersionControlServiceMsg>> createToVersionControlMsgConsumer() { |
|||
return new TbServiceBusConsumerTemplate<>(vcAdmin, serviceBusSettings, topicService.buildTopicName(vcSettings.getTopic()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportProtos.ToVersionControlServiceMsg.parseFrom(msg.getData()), msg.getHeaders()) |
|||
); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToHousekeeperServiceMsg>> createHousekeeperMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic())); |
|||
} |
|||
|
|||
@PreDestroy |
|||
private void destroy() { |
|||
if (coreAdmin != null) { |
|||
coreAdmin.destroy(); |
|||
} |
|||
if (notificationAdmin != null) { |
|||
notificationAdmin.destroy(); |
|||
} |
|||
if (vcAdmin != null) { |
|||
vcAdmin.destroy(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,155 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.provider; |
|||
|
|||
import jakarta.annotation.PreDestroy; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueConsumer; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.TbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusAdmin; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusConsumerTemplate; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusProducerTemplate; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusQueueConfigs; |
|||
import org.thingsboard.server.queue.azure.servicebus.TbServiceBusSettings; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|||
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
|||
import org.thingsboard.server.queue.discovery.TopicService; |
|||
import org.thingsboard.server.queue.settings.TbQueueCoreSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportApiSettings; |
|||
import org.thingsboard.server.queue.settings.TbQueueTransportNotificationSettings; |
|||
|
|||
@Component |
|||
@ConditionalOnExpression("'${queue.type:null}'=='service-bus' && (('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true') || '${service.type:null}'=='tb-transport')") |
|||
@Slf4j |
|||
public class ServiceBusTransportQueueFactory implements TbTransportQueueFactory { |
|||
private final TbQueueTransportApiSettings transportApiSettings; |
|||
private final TbQueueTransportNotificationSettings transportNotificationSettings; |
|||
private final TbServiceBusSettings serviceBusSettings; |
|||
private final TbServiceInfoProvider serviceInfoProvider; |
|||
private final TbQueueCoreSettings coreSettings; |
|||
private final TbQueueRuleEngineSettings ruleEngineSettings; |
|||
private final TopicService topicService; |
|||
|
|||
private final TbQueueAdmin coreAdmin; |
|||
private final TbQueueAdmin transportApiAdmin; |
|||
private final TbQueueAdmin notificationAdmin; |
|||
private final TbQueueAdmin ruleEngineAdmin; |
|||
|
|||
public ServiceBusTransportQueueFactory(TbQueueTransportApiSettings transportApiSettings, |
|||
TbQueueTransportNotificationSettings transportNotificationSettings, |
|||
TbServiceBusSettings serviceBusSettings, |
|||
TbQueueRuleEngineSettings ruleEngineSettings, |
|||
TbServiceInfoProvider serviceInfoProvider, |
|||
TbQueueCoreSettings coreSettings, |
|||
TbServiceBusQueueConfigs serviceBusQueueConfigs, |
|||
TopicService topicService) { |
|||
this.transportApiSettings = transportApiSettings; |
|||
this.transportNotificationSettings = transportNotificationSettings; |
|||
this.serviceBusSettings = serviceBusSettings; |
|||
this.serviceInfoProvider = serviceInfoProvider; |
|||
this.coreSettings = coreSettings; |
|||
this.ruleEngineSettings = ruleEngineSettings; |
|||
this.topicService = topicService; |
|||
|
|||
this.coreAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getCoreConfigs()); |
|||
this.transportApiAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getTransportApiConfigs()); |
|||
this.notificationAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getNotificationsConfigs()); |
|||
this.ruleEngineAdmin = new TbServiceBusAdmin(serviceBusSettings, serviceBusQueueConfigs.getRuleEngineConfigs()); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueRequestTemplate<TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> createTransportApiRequestTemplate() { |
|||
TbQueueProducer<TbProtoQueueMsg<TransportApiRequestMsg>> producerTemplate = |
|||
new TbServiceBusProducerTemplate<>(transportApiAdmin, serviceBusSettings, topicService.buildTopicName(transportApiSettings.getRequestsTopic())); |
|||
|
|||
TbQueueConsumer<TbProtoQueueMsg<TransportApiResponseMsg>> consumerTemplate = |
|||
new TbServiceBusConsumerTemplate<>(transportApiAdmin, serviceBusSettings, |
|||
topicService.buildTopicName(transportApiSettings.getResponsesTopic() + "." + serviceInfoProvider.getServiceId()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiResponseMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
|
|||
DefaultTbQueueRequestTemplate.DefaultTbQueueRequestTemplateBuilder |
|||
<TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> templateBuilder = DefaultTbQueueRequestTemplate.builder(); |
|||
templateBuilder.queueAdmin(transportApiAdmin); |
|||
templateBuilder.requestTemplate(producerTemplate); |
|||
templateBuilder.responseTemplate(consumerTemplate); |
|||
templateBuilder.maxPendingRequests(transportApiSettings.getMaxPendingRequests()); |
|||
templateBuilder.maxRequestTimeout(transportApiSettings.getMaxRequestsTimeout()); |
|||
templateBuilder.pollInterval(transportApiSettings.getResponsePollInterval()); |
|||
return templateBuilder.build(); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> createRuleEngineMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(ruleEngineAdmin, serviceBusSettings, topicService.buildTopicName(ruleEngineSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> createTbCoreMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToCoreNotificationMsg>> createTbCoreNotificationsMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(notificationAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueConsumer<TbProtoQueueMsg<ToTransportMsg>> createTransportNotificationsConsumer() { |
|||
return new TbServiceBusConsumerTemplate<>(notificationAdmin, serviceBusSettings, |
|||
topicService.buildTopicName(transportNotificationSettings.getNotificationsTopic() + "." + serviceInfoProvider.getServiceId()), |
|||
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToTransportMsg.parseFrom(msg.getData()), msg.getHeaders())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> createToUsageStatsServiceMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); |
|||
} |
|||
|
|||
@Override |
|||
public TbQueueProducer<TbProtoQueueMsg<ToHousekeeperServiceMsg>> createHousekeeperMsgProducer() { |
|||
return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getHousekeeperTopic())); |
|||
} |
|||
|
|||
@PreDestroy |
|||
private void destroy() { |
|||
if (coreAdmin != null) { |
|||
coreAdmin.destroy(); |
|||
} |
|||
if (transportApiAdmin != null) { |
|||
transportApiAdmin.destroy(); |
|||
} |
|||
if (notificationAdmin != null) { |
|||
notificationAdmin.destroy(); |
|||
} |
|||
if (ruleEngineAdmin != null) { |
|||
ruleEngineAdmin.destroy(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,232 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.pubsub; |
|||
|
|||
import com.google.api.gax.rpc.AlreadyExistsException; |
|||
import com.google.cloud.pubsub.v1.SubscriptionAdminClient; |
|||
import com.google.cloud.pubsub.v1.SubscriptionAdminSettings; |
|||
import com.google.cloud.pubsub.v1.TopicAdminClient; |
|||
import com.google.cloud.pubsub.v1.TopicAdminSettings; |
|||
import com.google.protobuf.Duration; |
|||
import com.google.pubsub.v1.ListSubscriptionsRequest; |
|||
import com.google.pubsub.v1.ListTopicsRequest; |
|||
import com.google.pubsub.v1.ProjectName; |
|||
import com.google.pubsub.v1.ProjectSubscriptionName; |
|||
import com.google.pubsub.v1.Subscription; |
|||
import com.google.pubsub.v1.Topic; |
|||
import com.google.pubsub.v1.TopicName; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
|
|||
import java.io.IOException; |
|||
import java.util.Map; |
|||
import java.util.Set; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
|
|||
@Slf4j |
|||
@Deprecated(forRemoval = true, since = "3.9") // for removal in 4.0
|
|||
public class TbPubSubAdmin implements TbQueueAdmin { |
|||
private static final String ACK_DEADLINE = "ackDeadlineInSec"; |
|||
private static final String MESSAGE_RETENTION = "messageRetentionInSec"; |
|||
|
|||
private final TopicAdminClient topicAdminClient; |
|||
private final SubscriptionAdminClient subscriptionAdminClient; |
|||
|
|||
private final TbPubSubSettings pubSubSettings; |
|||
private final Set<String> topicSet = ConcurrentHashMap.newKeySet(); |
|||
private final Set<String> subscriptionSet = ConcurrentHashMap.newKeySet(); |
|||
private final Map<String, String> subscriptionProperties; |
|||
|
|||
public TbPubSubAdmin(TbPubSubSettings pubSubSettings, Map<String, String> subscriptionSettings) { |
|||
this.pubSubSettings = pubSubSettings; |
|||
this.subscriptionProperties = subscriptionSettings; |
|||
|
|||
TopicAdminSettings topicAdminSettings; |
|||
try { |
|||
topicAdminSettings = TopicAdminSettings.newBuilder().setCredentialsProvider(pubSubSettings.getCredentialsProvider()).build(); |
|||
} catch (IOException e) { |
|||
log.error("Failed to create TopicAdminSettings"); |
|||
throw new RuntimeException("Failed to create TopicAdminSettings."); |
|||
} |
|||
|
|||
SubscriptionAdminSettings subscriptionAdminSettings; |
|||
try { |
|||
subscriptionAdminSettings = SubscriptionAdminSettings.newBuilder().setCredentialsProvider(pubSubSettings.getCredentialsProvider()).build(); |
|||
} catch (IOException e) { |
|||
log.error("Failed to create SubscriptionAdminSettings"); |
|||
throw new RuntimeException("Failed to create SubscriptionAdminSettings."); |
|||
} |
|||
|
|||
try { |
|||
topicAdminClient = TopicAdminClient.create(topicAdminSettings); |
|||
|
|||
ListTopicsRequest listTopicsRequest = |
|||
ListTopicsRequest.newBuilder().setProject(ProjectName.format(pubSubSettings.getProjectId())).build(); |
|||
TopicAdminClient.ListTopicsPagedResponse response = topicAdminClient.listTopics(listTopicsRequest); |
|||
for (Topic topic : response.iterateAll()) { |
|||
topicSet.add(topic.getName()); |
|||
} |
|||
} catch (IOException e) { |
|||
log.error("Failed to get topics.", e); |
|||
throw new RuntimeException("Failed to get topics.", e); |
|||
} |
|||
|
|||
try { |
|||
subscriptionAdminClient = SubscriptionAdminClient.create(subscriptionAdminSettings); |
|||
|
|||
ListSubscriptionsRequest listSubscriptionsRequest = |
|||
ListSubscriptionsRequest.newBuilder() |
|||
.setProject(ProjectName.of(pubSubSettings.getProjectId()).toString()) |
|||
.build(); |
|||
SubscriptionAdminClient.ListSubscriptionsPagedResponse response = |
|||
subscriptionAdminClient.listSubscriptions(listSubscriptionsRequest); |
|||
|
|||
for (Subscription subscription : response.iterateAll()) { |
|||
subscriptionSet.add(subscription.getName()); |
|||
} |
|||
} catch (IOException e) { |
|||
log.error("Failed to get subscriptions.", e); |
|||
throw new RuntimeException("Failed to get subscriptions.", e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void createTopicIfNotExists(String partition, String properties) { |
|||
TopicName topicName = TopicName.newBuilder() |
|||
.setTopic(partition) |
|||
.setProject(pubSubSettings.getProjectId()) |
|||
.build(); |
|||
|
|||
if (topicSet.contains(topicName.toString())) { |
|||
createSubscriptionIfNotExists(partition, topicName); |
|||
return; |
|||
} |
|||
|
|||
ListTopicsRequest listTopicsRequest = |
|||
ListTopicsRequest.newBuilder().setProject(ProjectName.format(pubSubSettings.getProjectId())).build(); |
|||
TopicAdminClient.ListTopicsPagedResponse response = topicAdminClient.listTopics(listTopicsRequest); |
|||
for (Topic topic : response.iterateAll()) { |
|||
if (topic.getName().contains(topicName.toString())) { |
|||
topicSet.add(topic.getName()); |
|||
createSubscriptionIfNotExists(partition, topicName); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
try { |
|||
topicAdminClient.createTopic(topicName); |
|||
log.info("Created new topic: [{}]", topicName.toString()); |
|||
} catch (AlreadyExistsException e) { |
|||
log.info("[{}] Topic already exist.", topicName.toString()); |
|||
} finally { |
|||
topicSet.add(topicName.toString()); |
|||
} |
|||
createSubscriptionIfNotExists(partition, topicName); |
|||
} |
|||
|
|||
@Override |
|||
public void deleteTopic(String topic) { |
|||
TopicName topicName = TopicName.newBuilder() |
|||
.setTopic(topic) |
|||
.setProject(pubSubSettings.getProjectId()) |
|||
.build(); |
|||
|
|||
ProjectSubscriptionName subscriptionName = |
|||
ProjectSubscriptionName.of(pubSubSettings.getProjectId(), topic); |
|||
|
|||
if (topicSet.contains(topicName.toString())) { |
|||
topicAdminClient.deleteTopic(topicName); |
|||
} else { |
|||
if (topicAdminClient.getTopic(topicName) != null) { |
|||
topicAdminClient.deleteTopic(topicName); |
|||
} else { |
|||
log.warn("PubSub topic [{}] does not exist.", topic); |
|||
} |
|||
} |
|||
|
|||
if (subscriptionSet.contains(subscriptionName.toString())) { |
|||
subscriptionAdminClient.deleteSubscription(subscriptionName); |
|||
} else { |
|||
if (subscriptionAdminClient.getSubscription(subscriptionName) != null) { |
|||
subscriptionAdminClient.deleteSubscription(subscriptionName); |
|||
} else { |
|||
log.warn("PubSub subscription [{}] does not exist.", topic); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private void createSubscriptionIfNotExists(String partition, TopicName topicName) { |
|||
ProjectSubscriptionName subscriptionName = |
|||
ProjectSubscriptionName.of(pubSubSettings.getProjectId(), partition); |
|||
|
|||
if (subscriptionSet.contains(subscriptionName.toString())) { |
|||
return; |
|||
} |
|||
|
|||
ListSubscriptionsRequest listSubscriptionsRequest = |
|||
ListSubscriptionsRequest.newBuilder().setProject(ProjectName.of(pubSubSettings.getProjectId()).toString()).build(); |
|||
SubscriptionAdminClient.ListSubscriptionsPagedResponse response = subscriptionAdminClient.listSubscriptions(listSubscriptionsRequest); |
|||
for (Subscription subscription : response.iterateAll()) { |
|||
if (subscription.getName().equals(subscriptionName.toString())) { |
|||
subscriptionSet.add(subscription.getName()); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
Subscription.Builder subscriptionBuilder = Subscription |
|||
.newBuilder() |
|||
.setName(subscriptionName.toString()) |
|||
.setTopic(topicName.toString()); |
|||
|
|||
setAckDeadline(subscriptionBuilder); |
|||
setMessageRetention(subscriptionBuilder); |
|||
|
|||
try { |
|||
subscriptionAdminClient.createSubscription(subscriptionBuilder.build()); |
|||
log.info("Created new subscription: [{}]", subscriptionName.toString()); |
|||
} catch (AlreadyExistsException e) { |
|||
log.info("[{}] Subscription already exist.", subscriptionName.toString()); |
|||
} finally { |
|||
subscriptionSet.add(subscriptionName.toString()); |
|||
} |
|||
} |
|||
|
|||
private void setAckDeadline(Subscription.Builder builder) { |
|||
if (subscriptionProperties.containsKey(ACK_DEADLINE)) { |
|||
builder.setAckDeadlineSeconds(Integer.parseInt(subscriptionProperties.get(ACK_DEADLINE))); |
|||
} |
|||
} |
|||
|
|||
private void setMessageRetention(Subscription.Builder builder) { |
|||
if (subscriptionProperties.containsKey(MESSAGE_RETENTION)) { |
|||
Duration duration = Duration |
|||
.newBuilder() |
|||
.setSeconds(Long.parseLong(subscriptionProperties.get(MESSAGE_RETENTION))) |
|||
.build(); |
|||
builder.setMessageRetentionDuration(duration); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void destroy() { |
|||
if (topicAdminClient != null) { |
|||
topicAdminClient.close(); |
|||
} |
|||
if (subscriptionAdminClient != null) { |
|||
subscriptionAdminClient.close(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,175 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.pubsub; |
|||
|
|||
import com.google.api.core.ApiFuture; |
|||
import com.google.api.core.ApiFutures; |
|||
import com.google.cloud.pubsub.v1.stub.GrpcSubscriberStub; |
|||
import com.google.cloud.pubsub.v1.stub.SubscriberStub; |
|||
import com.google.cloud.pubsub.v1.stub.SubscriberStubSettings; |
|||
import com.google.gson.Gson; |
|||
import com.google.protobuf.InvalidProtocolBufferException; |
|||
import com.google.pubsub.v1.AcknowledgeRequest; |
|||
import com.google.pubsub.v1.ProjectSubscriptionName; |
|||
import com.google.pubsub.v1.PubsubMessage; |
|||
import com.google.pubsub.v1.PullRequest; |
|||
import com.google.pubsub.v1.PullResponse; |
|||
import com.google.pubsub.v1.ReceivedMessage; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.util.CollectionUtils; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueMsg; |
|||
import org.thingsboard.server.queue.TbQueueMsgDecoder; |
|||
import org.thingsboard.server.queue.common.AbstractParallelTbQueueConsumerTemplate; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueMsg; |
|||
|
|||
import java.io.IOException; |
|||
import java.util.ArrayList; |
|||
import java.util.Collections; |
|||
import java.util.LinkedHashSet; |
|||
import java.util.List; |
|||
import java.util.Objects; |
|||
import java.util.Set; |
|||
import java.util.concurrent.CopyOnWriteArrayList; |
|||
import java.util.concurrent.ExecutionException; |
|||
import java.util.stream.Collectors; |
|||
|
|||
@Slf4j |
|||
public class TbPubSubConsumerTemplate<T extends TbQueueMsg> extends AbstractParallelTbQueueConsumerTemplate<PubsubMessage, T> { |
|||
|
|||
private final Gson gson = new Gson(); |
|||
private final TbQueueAdmin admin; |
|||
private final String topic; |
|||
private final TbQueueMsgDecoder<T> decoder; |
|||
private final TbPubSubSettings pubSubSettings; |
|||
|
|||
private volatile Set<String> subscriptionNames; |
|||
private final List<AcknowledgeRequest> acknowledgeRequests = new CopyOnWriteArrayList<>(); |
|||
|
|||
private final SubscriberStub subscriber; |
|||
private volatile int messagesPerTopic; |
|||
|
|||
public TbPubSubConsumerTemplate(TbQueueAdmin admin, TbPubSubSettings pubSubSettings, String topic, TbQueueMsgDecoder<T> decoder) { |
|||
super(topic); |
|||
this.admin = admin; |
|||
this.pubSubSettings = pubSubSettings; |
|||
this.topic = topic; |
|||
this.decoder = decoder; |
|||
try { |
|||
SubscriberStubSettings subscriberStubSettings = |
|||
SubscriberStubSettings.newBuilder() |
|||
.setCredentialsProvider(pubSubSettings.getCredentialsProvider()) |
|||
.setTransportChannelProvider( |
|||
SubscriberStubSettings.defaultGrpcTransportProviderBuilder() |
|||
.setMaxInboundMessageSize(pubSubSettings.getMaxMsgSize()) |
|||
.build()) |
|||
.setExecutorProvider(pubSubSettings.getExecutorProvider()) |
|||
.build(); |
|||
this.subscriber = GrpcSubscriberStub.create(subscriberStubSettings); |
|||
} catch (IOException e) { |
|||
log.error("Failed to create subscriber.", e); |
|||
throw new RuntimeException("Failed to create subscriber.", e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
protected List<PubsubMessage> doPoll(long durationInMillis) { |
|||
try { |
|||
List<ReceivedMessage> messages = receiveMessages(); |
|||
if (!messages.isEmpty()) { |
|||
return messages.stream().map(ReceivedMessage::getMessage).collect(Collectors.toList()); |
|||
} |
|||
} catch (ExecutionException | InterruptedException e) { |
|||
if (stopped) { |
|||
log.info("[{}] Pub/Sub consumer is stopped.", topic); |
|||
} else { |
|||
log.error("Failed to receive messages", e); |
|||
} |
|||
} |
|||
return Collections.emptyList(); |
|||
} |
|||
|
|||
@Override |
|||
protected void doSubscribe(List<String> topicNames) { |
|||
subscriptionNames = new LinkedHashSet<>(topicNames); |
|||
subscriptionNames.forEach(admin::createTopicIfNotExists); |
|||
initNewExecutor(subscriptionNames.size() + 1); |
|||
messagesPerTopic = pubSubSettings.getMaxMessages() / Math.max(subscriptionNames.size(), 1); |
|||
} |
|||
|
|||
@Override |
|||
protected void doCommit() { |
|||
acknowledgeRequests.forEach(subscriber.acknowledgeCallable()::futureCall); |
|||
acknowledgeRequests.clear(); |
|||
} |
|||
|
|||
@Override |
|||
protected void doUnsubscribe() { |
|||
if (subscriber != null) { |
|||
subscriber.close(); |
|||
} |
|||
shutdownExecutor(); |
|||
} |
|||
|
|||
private List<ReceivedMessage> receiveMessages() throws ExecutionException, InterruptedException { |
|||
List<ApiFuture<List<ReceivedMessage>>> result = subscriptionNames.stream().map(subscriptionId -> { |
|||
String subscriptionName = ProjectSubscriptionName.format(pubSubSettings.getProjectId(), subscriptionId); |
|||
PullRequest pullRequest = |
|||
PullRequest.newBuilder() |
|||
.setMaxMessages(messagesPerTopic) |
|||
// .setReturnImmediately(false) // return immediately if messages are not available
|
|||
.setSubscription(subscriptionName) |
|||
.build(); |
|||
|
|||
ApiFuture<PullResponse> pullResponseApiFuture = subscriber.pullCallable().futureCall(pullRequest); |
|||
|
|||
return ApiFutures.transform(pullResponseApiFuture, pullResponse -> { |
|||
if (pullResponse != null && !pullResponse.getReceivedMessagesList().isEmpty()) { |
|||
List<String> ackIds = new ArrayList<>(); |
|||
for (ReceivedMessage message : pullResponse.getReceivedMessagesList()) { |
|||
ackIds.add(message.getAckId()); |
|||
} |
|||
AcknowledgeRequest acknowledgeRequest = |
|||
AcknowledgeRequest.newBuilder() |
|||
.setSubscription(subscriptionName) |
|||
.addAllAckIds(ackIds) |
|||
.build(); |
|||
|
|||
acknowledgeRequests.add(acknowledgeRequest); |
|||
return pullResponse.getReceivedMessagesList(); |
|||
} |
|||
return null; |
|||
}, consumerExecutor); |
|||
|
|||
}).collect(Collectors.toList()); |
|||
|
|||
ApiFuture<List<ReceivedMessage>> transform = ApiFutures.transform(ApiFutures.allAsList(result), listMessages -> { |
|||
if (!CollectionUtils.isEmpty(listMessages)) { |
|||
return listMessages.stream().filter(Objects::nonNull).flatMap(List::stream).collect(Collectors.toList()); |
|||
} |
|||
return Collections.emptyList(); |
|||
}, consumerExecutor); |
|||
|
|||
return transform.get(); |
|||
} |
|||
|
|||
@Override |
|||
public T decode(PubsubMessage message) throws InvalidProtocolBufferException { |
|||
DefaultTbQueueMsg msg = gson.fromJson(message.getData().toStringUtf8(), DefaultTbQueueMsg.class); |
|||
return decoder.decode(msg); |
|||
} |
|||
|
|||
} |
|||
@ -1,137 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.pubsub; |
|||
|
|||
import com.google.api.core.ApiFuture; |
|||
import com.google.api.core.ApiFutureCallback; |
|||
import com.google.api.core.ApiFutures; |
|||
import com.google.cloud.pubsub.v1.Publisher; |
|||
import com.google.gson.Gson; |
|||
import com.google.protobuf.ByteString; |
|||
import com.google.pubsub.v1.ProjectTopicName; |
|||
import com.google.pubsub.v1.PubsubMessage; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueCallback; |
|||
import org.thingsboard.server.queue.TbQueueMsg; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueMsg; |
|||
|
|||
import java.io.IOException; |
|||
import java.util.Map; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.concurrent.ExecutorService; |
|||
import java.util.concurrent.Executors; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
@Slf4j |
|||
public class TbPubSubProducerTemplate<T extends TbQueueMsg> implements TbQueueProducer<T> { |
|||
|
|||
private final Gson gson = new Gson(); |
|||
|
|||
private final String defaultTopic; |
|||
private final TbQueueAdmin admin; |
|||
private final TbPubSubSettings pubSubSettings; |
|||
|
|||
private final Map<String, Publisher> publisherMap = new ConcurrentHashMap<>(); |
|||
|
|||
private final ExecutorService pubExecutor = Executors.newCachedThreadPool(); |
|||
|
|||
public TbPubSubProducerTemplate(TbQueueAdmin admin, TbPubSubSettings pubSubSettings, String defaultTopic) { |
|||
this.defaultTopic = defaultTopic; |
|||
this.admin = admin; |
|||
this.pubSubSettings = pubSubSettings; |
|||
} |
|||
|
|||
@Override |
|||
public void init() { |
|||
|
|||
} |
|||
|
|||
@Override |
|||
public String getDefaultTopic() { |
|||
return defaultTopic; |
|||
} |
|||
|
|||
@Override |
|||
public void send(TopicPartitionInfo tpi, T msg, TbQueueCallback callback) { |
|||
PubsubMessage.Builder pubsubMessageBuilder = PubsubMessage.newBuilder(); |
|||
pubsubMessageBuilder.setData(getMsg(msg)); |
|||
|
|||
Publisher publisher = getOrCreatePublisher(tpi.getFullTopicName()); |
|||
ApiFuture<String> future = publisher.publish(pubsubMessageBuilder.build()); |
|||
|
|||
ApiFutures.addCallback(future, new ApiFutureCallback<String>() { |
|||
public void onSuccess(String messageId) { |
|||
if (callback != null) { |
|||
callback.onSuccess(null); |
|||
} |
|||
} |
|||
|
|||
public void onFailure(Throwable t) { |
|||
if (callback != null) { |
|||
callback.onFailure(t); |
|||
} |
|||
} |
|||
}, pubExecutor); |
|||
} |
|||
|
|||
@Override |
|||
public void stop() { |
|||
publisherMap.forEach((k, v) -> { |
|||
if (v != null) { |
|||
try { |
|||
v.shutdown(); |
|||
v.awaitTermination(1, TimeUnit.SECONDS); |
|||
} catch (Exception e) { |
|||
log.error("Failed to shutdown PubSub client during destroy()", e); |
|||
} |
|||
} |
|||
}); |
|||
|
|||
if (pubExecutor != null) { |
|||
pubExecutor.shutdownNow(); |
|||
} |
|||
} |
|||
|
|||
private ByteString getMsg(T msg) { |
|||
String json = gson.toJson(new DefaultTbQueueMsg(msg)); |
|||
return ByteString.copyFrom(json.getBytes()); |
|||
} |
|||
|
|||
private Publisher getOrCreatePublisher(String topic) { |
|||
if (publisherMap.containsKey(topic)) { |
|||
return publisherMap.get(topic); |
|||
} else { |
|||
try { |
|||
admin.createTopicIfNotExists(topic); |
|||
ProjectTopicName topicName = ProjectTopicName.of(pubSubSettings.getProjectId(), topic); |
|||
Publisher publisher = Publisher.newBuilder(topicName) |
|||
.setCredentialsProvider(pubSubSettings.getCredentialsProvider()) |
|||
.setExecutorProvider(pubSubSettings.getExecutorProvider()) |
|||
.build(); |
|||
publisherMap.put(topic, publisher); |
|||
return publisher; |
|||
} catch (IOException e) { |
|||
log.error("Failed to create Publisher for the topic [{}].", topic, e); |
|||
throw new RuntimeException("Failed to create Publisher for the topic.", e); |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
} |
|||
@ -1,82 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.pubsub; |
|||
|
|||
import com.google.api.gax.core.CredentialsProvider; |
|||
import com.google.api.gax.core.FixedCredentialsProvider; |
|||
import com.google.api.gax.core.FixedExecutorProvider; |
|||
import com.google.auth.oauth2.ServiceAccountCredentials; |
|||
import jakarta.annotation.PostConstruct; |
|||
import jakarta.annotation.PreDestroy; |
|||
import lombok.Data; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.common.util.ThingsBoardExecutors; |
|||
|
|||
import java.io.ByteArrayInputStream; |
|||
import java.io.IOException; |
|||
|
|||
@Slf4j |
|||
@ConditionalOnExpression("'${queue.type:null}'=='pubsub'") |
|||
@Component |
|||
@Data |
|||
public class TbPubSubSettings { |
|||
|
|||
@Value("${queue.pubsub.project_id}") |
|||
private String projectId; |
|||
|
|||
@Value("${queue.pubsub.service_account}") |
|||
private String serviceAccount; |
|||
|
|||
@Value("${queue.pubsub.max_msg_size}") |
|||
private int maxMsgSize; |
|||
|
|||
@Value("${queue.pubsub.max_messages}") |
|||
private int maxMessages; |
|||
|
|||
@Value("${queue.pubsub.executor_thread_pool_size:0}") |
|||
private int threadPoolSize; |
|||
|
|||
/** |
|||
* Refers to com.google.cloud.pubsub.v1.Publisher default executor configuration |
|||
*/ |
|||
private static final int THREADS_PER_CPU = 5; |
|||
|
|||
private FixedExecutorProvider executorProvider; |
|||
|
|||
private CredentialsProvider credentialsProvider; |
|||
|
|||
@PostConstruct |
|||
private void init() throws IOException { |
|||
ServiceAccountCredentials credentials = ServiceAccountCredentials.fromStream( |
|||
new ByteArrayInputStream(serviceAccount.getBytes())); |
|||
credentialsProvider = FixedCredentialsProvider.create(credentials); |
|||
if (threadPoolSize == 0) { |
|||
threadPoolSize = THREADS_PER_CPU * Runtime.getRuntime().availableProcessors(); |
|||
} |
|||
executorProvider = FixedExecutorProvider |
|||
.create(ThingsBoardExecutors.newScheduledThreadPool(threadPoolSize, "pubsub-queue-executor")); |
|||
} |
|||
|
|||
@PreDestroy |
|||
private void destroy() { |
|||
if (executorProvider != null) { |
|||
executorProvider.getExecutor().shutdownNow(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,72 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.pubsub; |
|||
|
|||
import jakarta.annotation.PostConstruct; |
|||
import lombok.Getter; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.queue.util.PropertyUtils; |
|||
|
|||
import java.util.Map; |
|||
|
|||
@Component |
|||
@ConditionalOnExpression("'${queue.type:null}'=='pubsub'") |
|||
public class TbPubSubSubscriptionSettings { |
|||
|
|||
@Value("${queue.pubsub.queue-properties.core:}") |
|||
private String coreProperties; |
|||
@Value("${queue.pubsub.queue-properties.rule-engine:}") |
|||
private String ruleEngineProperties; |
|||
@Value("${queue.pubsub.queue-properties.transport-api:}") |
|||
private String transportApiProperties; |
|||
@Value("${queue.pubsub.queue-properties.notifications:}") |
|||
private String notificationsProperties; |
|||
@Value("${queue.pubsub.queue-properties.js-executor:}") |
|||
private String jsExecutorProperties; |
|||
@Value("${queue.pubsub.queue-properties.version-control:}") |
|||
private String vcProperties; |
|||
@Value("${queue.pubsub.queue-properties.edge:}") |
|||
private String edgeProperties; |
|||
|
|||
@Getter |
|||
private Map<String, String> coreSettings; |
|||
@Getter |
|||
private Map<String, String> ruleEngineSettings; |
|||
@Getter |
|||
private Map<String, String> transportApiSettings; |
|||
@Getter |
|||
private Map<String, String> notificationsSettings; |
|||
@Getter |
|||
private Map<String, String> jsExecutorSettings; |
|||
@Getter |
|||
private Map<String, String> vcSettings; |
|||
@Getter |
|||
private Map<String, String> edgeSettings; |
|||
|
|||
@PostConstruct |
|||
private void init() { |
|||
coreSettings = PropertyUtils.getProps(coreProperties); |
|||
ruleEngineSettings = PropertyUtils.getProps(ruleEngineProperties); |
|||
transportApiSettings = PropertyUtils.getProps(transportApiProperties); |
|||
notificationsSettings = PropertyUtils.getProps(notificationsProperties); |
|||
jsExecutorSettings = PropertyUtils.getProps(jsExecutorProperties); |
|||
vcSettings = PropertyUtils.getProps(vcProperties); |
|||
edgeSettings = PropertyUtils.getProps(edgeProperties); |
|||
} |
|||
|
|||
} |
|||
@ -1,95 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.rabbitmq; |
|||
|
|||
import com.rabbitmq.client.Channel; |
|||
import com.rabbitmq.client.Connection; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
|
|||
import java.io.IOException; |
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
import java.util.concurrent.TimeoutException; |
|||
|
|||
@Slf4j |
|||
@Deprecated(forRemoval = true, since = "3.9") // for removal in 4.0
|
|||
public class TbRabbitMqAdmin implements TbQueueAdmin { |
|||
|
|||
private final Channel channel; |
|||
private final Connection connection; |
|||
private final Map<String, Object> arguments; |
|||
|
|||
public TbRabbitMqAdmin(TbRabbitMqSettings rabbitMqSettings, Map<String, Object> arguments) { |
|||
this.arguments = arguments; |
|||
|
|||
try { |
|||
connection = rabbitMqSettings.getConnectionFactory().newConnection(); |
|||
} catch (IOException | TimeoutException e) { |
|||
log.error("Failed to create connection.", e); |
|||
throw new RuntimeException("Failed to create connection.", e); |
|||
} |
|||
|
|||
try { |
|||
channel = connection.createChannel(); |
|||
} catch (IOException e) { |
|||
log.error("Failed to create chanel.", e); |
|||
throw new RuntimeException("Failed to create chanel.", e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void createTopicIfNotExists(String topic, String properties) { |
|||
Map<String, Object> arguments = this.arguments; |
|||
if (StringUtils.isNotBlank(properties)) { |
|||
arguments = new HashMap<>(arguments); |
|||
arguments.putAll(TbRabbitMqQueueArguments.getArgs(properties)); |
|||
} |
|||
try { |
|||
channel.queueDeclare(topic, false, false, false, arguments); |
|||
} catch (IOException e) { |
|||
log.error("Failed to bind queue: [{}]", topic, e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void deleteTopic(String topic) { |
|||
try { |
|||
channel.queueDelete(topic); |
|||
} catch (IOException e) { |
|||
log.error("Failed to delete RabbitMq queue [{}].", topic); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void destroy() { |
|||
if (channel != null) { |
|||
try { |
|||
channel.close(); |
|||
} catch (IOException | TimeoutException e) { |
|||
log.error("Failed to close Chanel.", e); |
|||
} |
|||
} |
|||
if (connection != null) { |
|||
try { |
|||
connection.close(); |
|||
} catch (IOException e) { |
|||
log.error("Failed to close Connection.", e); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,144 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.rabbitmq; |
|||
|
|||
import com.google.gson.Gson; |
|||
import com.google.protobuf.InvalidProtocolBufferException; |
|||
import com.rabbitmq.client.Channel; |
|||
import com.rabbitmq.client.Connection; |
|||
import com.rabbitmq.client.GetResponse; |
|||
import java.util.ArrayList; |
|||
import java.util.Collection; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueMsg; |
|||
import org.thingsboard.server.queue.TbQueueMsgDecoder; |
|||
import org.thingsboard.server.queue.common.AbstractTbQueueConsumerTemplate; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueMsg; |
|||
|
|||
import java.io.IOException; |
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
import java.util.Set; |
|||
import java.util.concurrent.TimeoutException; |
|||
import java.util.stream.Collectors; |
|||
|
|||
@Slf4j |
|||
public class TbRabbitMqConsumerTemplate<T extends TbQueueMsg> extends AbstractTbQueueConsumerTemplate<GetResponse, T> { |
|||
|
|||
private final Gson gson = new Gson(); |
|||
private final TbQueueAdmin admin; |
|||
private final TbQueueMsgDecoder<T> decoder; |
|||
private final Channel channel; |
|||
private final Connection connection; |
|||
private final int maxPollMessages; |
|||
|
|||
private volatile Set<String> queues; |
|||
|
|||
public TbRabbitMqConsumerTemplate(TbQueueAdmin admin, TbRabbitMqSettings rabbitMqSettings, String topic, TbQueueMsgDecoder<T> decoder) { |
|||
super(topic); |
|||
this.admin = admin; |
|||
this.decoder = decoder; |
|||
this.maxPollMessages = rabbitMqSettings.getMaxPollMessages(); |
|||
try { |
|||
connection = rabbitMqSettings.getConnectionFactory().newConnection(); |
|||
} catch (IOException | TimeoutException e) { |
|||
log.error("Failed to create connection.", e); |
|||
throw new RuntimeException("Failed to create connection.", e); |
|||
} |
|||
try { |
|||
channel = connection.createChannel(); |
|||
} catch (IOException e) { |
|||
log.error("Failed to create chanel.", e); |
|||
throw new RuntimeException("Failed to create chanel.", e); |
|||
} |
|||
stopped = false; |
|||
} |
|||
|
|||
@Override |
|||
protected List<GetResponse> doPoll(long durationInMillis) { |
|||
List<GetResponse> result = queues.stream() |
|||
.map(queue -> { |
|||
List<GetResponse> messages = new ArrayList<>(); |
|||
for (int i = 0; i < maxPollMessages; i++) { |
|||
GetResponse response = doQueuePoll(queue); |
|||
if (response == null) { |
|||
break; |
|||
} |
|||
messages.add(response); |
|||
} |
|||
return messages; |
|||
}) |
|||
.filter(r -> !r.isEmpty()) |
|||
.flatMap(Collection::stream) |
|||
.collect(Collectors.toList()); |
|||
if (result.size() > 0) { |
|||
return result; |
|||
} else { |
|||
return Collections.emptyList(); |
|||
} |
|||
} |
|||
|
|||
protected GetResponse doQueuePoll(String queue) { |
|||
try { |
|||
return channel.basicGet(queue, false); |
|||
} catch (IOException e) { |
|||
log.error("Failed to get messages from queue: [{}]", queue); |
|||
throw new RuntimeException("Failed to get messages from queue.", e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
protected void doSubscribe(List<String> topicNames) { |
|||
queues = partitions.stream() |
|||
.map(TopicPartitionInfo::getFullTopicName) |
|||
.collect(Collectors.toSet()); |
|||
queues.forEach(admin::createTopicIfNotExists); |
|||
} |
|||
|
|||
@Override |
|||
protected void doCommit() { |
|||
try { |
|||
channel.basicAck(0, true); |
|||
} catch (IOException e) { |
|||
log.error("Failed to ack messages.", e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
protected void doUnsubscribe() { |
|||
if (channel != null) { |
|||
try { |
|||
channel.close(); |
|||
} catch (IOException | TimeoutException e) { |
|||
log.error("Failed to close the channel."); |
|||
} |
|||
} |
|||
if (connection != null) { |
|||
try { |
|||
connection.close(); |
|||
} catch (IOException e) { |
|||
log.error("Failed to close the connection."); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public T decode(GetResponse message) throws InvalidProtocolBufferException { |
|||
DefaultTbQueueMsg msg = gson.fromJson(new String(message.getBody()), DefaultTbQueueMsg.class); |
|||
return decoder.decode(msg); |
|||
} |
|||
} |
|||
@ -1,125 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.rabbitmq; |
|||
|
|||
import com.google.common.util.concurrent.ListeningExecutorService; |
|||
import com.google.common.util.concurrent.MoreExecutors; |
|||
import com.google.gson.Gson; |
|||
import com.rabbitmq.client.AMQP; |
|||
import com.rabbitmq.client.Channel; |
|||
import com.rabbitmq.client.Connection; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueCallback; |
|||
import org.thingsboard.server.queue.TbQueueMsg; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueMsg; |
|||
|
|||
import java.io.IOException; |
|||
import java.util.Set; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.concurrent.Executors; |
|||
import java.util.concurrent.TimeoutException; |
|||
|
|||
@Slf4j |
|||
public class TbRabbitMqProducerTemplate<T extends TbQueueMsg> implements TbQueueProducer<T> { |
|||
private final String defaultTopic; |
|||
private final Gson gson = new Gson(); |
|||
private final TbQueueAdmin admin; |
|||
private final TbRabbitMqSettings rabbitMqSettings; |
|||
private final ListeningExecutorService producerExecutor; |
|||
private final Channel channel; |
|||
private final Connection connection; |
|||
|
|||
private final Set<TopicPartitionInfo> topics = ConcurrentHashMap.newKeySet(); |
|||
|
|||
public TbRabbitMqProducerTemplate(TbQueueAdmin admin, TbRabbitMqSettings rabbitMqSettings, String defaultTopic) { |
|||
this.admin = admin; |
|||
this.defaultTopic = defaultTopic; |
|||
this.rabbitMqSettings = rabbitMqSettings; |
|||
producerExecutor = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool()); |
|||
try { |
|||
connection = rabbitMqSettings.getConnectionFactory().newConnection(); |
|||
} catch (IOException | TimeoutException e) { |
|||
log.error("Failed to create connection.", e); |
|||
throw new RuntimeException("Failed to create connection.", e); |
|||
} |
|||
|
|||
try { |
|||
channel = connection.createChannel(); |
|||
} catch (IOException e) { |
|||
log.error("Failed to create chanel.", e); |
|||
throw new RuntimeException("Failed to create chanel.", e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void init() { |
|||
|
|||
} |
|||
|
|||
@Override |
|||
public String getDefaultTopic() { |
|||
return defaultTopic; |
|||
} |
|||
|
|||
@Override |
|||
public void send(TopicPartitionInfo tpi, T msg, TbQueueCallback callback) { |
|||
createTopicIfNotExist(tpi); |
|||
AMQP.BasicProperties properties = new AMQP.BasicProperties(); |
|||
try { |
|||
channel.basicPublish(rabbitMqSettings.getExchangeName(), tpi.getFullTopicName(), properties, gson.toJson(new DefaultTbQueueMsg(msg)).getBytes()); |
|||
if (callback != null) { |
|||
callback.onSuccess(null); |
|||
} |
|||
} catch (IOException e) { |
|||
log.error("Failed publish message: [{}].", msg, e); |
|||
if (callback != null) { |
|||
callback.onFailure(e); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void stop() { |
|||
if (producerExecutor != null) { |
|||
producerExecutor.shutdownNow(); |
|||
} |
|||
if (channel != null) { |
|||
try { |
|||
channel.close(); |
|||
} catch (IOException | TimeoutException e) { |
|||
log.error("Failed to close the channel."); |
|||
} |
|||
} |
|||
if (connection != null) { |
|||
try { |
|||
connection.close(); |
|||
} catch (IOException e) { |
|||
log.error("Failed to close the connection."); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private void createTopicIfNotExist(TopicPartitionInfo tpi) { |
|||
if (topics.contains(tpi)) { |
|||
return; |
|||
} |
|||
admin.createTopicIfNotExists(tpi.getFullTopicName()); |
|||
topics.add(tpi); |
|||
} |
|||
} |
|||
@ -1,111 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.rabbitmq; |
|||
|
|||
import jakarta.annotation.PostConstruct; |
|||
import lombok.Getter; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.StringUtils; |
|||
|
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
import java.util.regex.Pattern; |
|||
|
|||
@Component |
|||
@ConditionalOnExpression("'${queue.type:null}'=='rabbitmq'") |
|||
public class TbRabbitMqQueueArguments { |
|||
@Value("${queue.rabbitmq.queue-properties.core:}") |
|||
private String coreProperties; |
|||
@Value("${queue.rabbitmq.queue-properties.rule-engine:}") |
|||
private String ruleEngineProperties; |
|||
@Value("${queue.rabbitmq.queue-properties.transport-api:}") |
|||
private String transportApiProperties; |
|||
@Value("${queue.rabbitmq.queue-properties.notifications:}") |
|||
private String notificationsProperties; |
|||
@Value("${queue.rabbitmq.queue-properties.js-executor:}") |
|||
private String jsExecutorProperties; |
|||
@Value("${queue.rabbitmq.queue-properties.version-control:}") |
|||
private String vcProperties; |
|||
@Value("${queue.rabbitmq.queue-properties.edge:}") |
|||
private String edgeProperties; |
|||
|
|||
@Getter |
|||
private Map<String, Object> coreArgs; |
|||
@Getter |
|||
private Map<String, Object> ruleEngineArgs; |
|||
@Getter |
|||
private Map<String, Object> transportApiArgs; |
|||
@Getter |
|||
private Map<String, Object> notificationsArgs; |
|||
@Getter |
|||
private Map<String, Object> jsExecutorArgs; |
|||
@Getter |
|||
private Map<String, Object> vcArgs; |
|||
@Getter |
|||
private Map<String, Object> edgeArgs; |
|||
|
|||
@PostConstruct |
|||
private void init() { |
|||
coreArgs = getArgs(coreProperties); |
|||
ruleEngineArgs = getArgs(ruleEngineProperties); |
|||
transportApiArgs = getArgs(transportApiProperties); |
|||
notificationsArgs = getArgs(notificationsProperties); |
|||
jsExecutorArgs = getArgs(jsExecutorProperties); |
|||
vcArgs = getArgs(vcProperties); |
|||
edgeArgs = getArgs(edgeProperties); |
|||
} |
|||
|
|||
public static Map<String, Object> getArgs(String properties) { |
|||
Map<String, Object> configs = new HashMap<>(); |
|||
if (StringUtils.isNotEmpty(properties)) { |
|||
for (String property : properties.split(";")) { |
|||
int delimiterPosition = property.indexOf(":"); |
|||
String key = property.substring(0, delimiterPosition); |
|||
String strValue = property.substring(delimiterPosition + 1); |
|||
configs.put(key, getObjectValue(strValue)); |
|||
} |
|||
} |
|||
return configs; |
|||
} |
|||
|
|||
private static Object getObjectValue(String str) { |
|||
if (str.equalsIgnoreCase("true") || str.equalsIgnoreCase("false")) { |
|||
return Boolean.valueOf(str); |
|||
} else if (isNumeric(str)) { |
|||
return getNumericValue(str); |
|||
} |
|||
return str; |
|||
} |
|||
|
|||
private static Object getNumericValue(String str) { |
|||
if (str.contains(".")) { |
|||
return Double.valueOf(str); |
|||
} else { |
|||
return Long.valueOf(str); |
|||
} |
|||
} |
|||
|
|||
private static final Pattern PATTERN = Pattern.compile("-?\\d+(\\.\\d+)?"); |
|||
|
|||
private static boolean isNumeric(String strNum) { |
|||
if (strNum == null) { |
|||
return false; |
|||
} |
|||
return PATTERN.matcher(strNum).matches(); |
|||
} |
|||
} |
|||
@ -1,66 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.rabbitmq; |
|||
|
|||
import com.rabbitmq.client.ConnectionFactory; |
|||
import jakarta.annotation.PostConstruct; |
|||
import lombok.Data; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
@Slf4j |
|||
@ConditionalOnExpression("'${queue.type:null}'=='rabbitmq'") |
|||
@Component |
|||
@Data |
|||
public class TbRabbitMqSettings { |
|||
@Value("${queue.rabbitmq.exchange_name:}") |
|||
private String exchangeName; |
|||
@Value("${queue.rabbitmq.host:}") |
|||
private String host; |
|||
@Value("${queue.rabbitmq.port:}") |
|||
private int port; |
|||
@Value("${queue.rabbitmq.virtual_host:}") |
|||
private String virtualHost; |
|||
@Value("${queue.rabbitmq.username:}") |
|||
private String username; |
|||
@Value("${queue.rabbitmq.password:}") |
|||
private String password; |
|||
@Value("${queue.rabbitmq.automatic_recovery_enabled:}") |
|||
private boolean automaticRecoveryEnabled; |
|||
@Value("${queue.rabbitmq.connection_timeout:}") |
|||
private int connectionTimeout; |
|||
@Value("${queue.rabbitmq.handshake_timeout:}") |
|||
private int handshakeTimeout; |
|||
@Value("${queue.rabbitmq.max_poll_messages:1}") |
|||
private int maxPollMessages; |
|||
|
|||
private ConnectionFactory connectionFactory; |
|||
|
|||
@PostConstruct |
|||
private void init() { |
|||
connectionFactory = new ConnectionFactory(); |
|||
connectionFactory.setHost(host); |
|||
connectionFactory.setPort(port); |
|||
connectionFactory.setVirtualHost(virtualHost); |
|||
connectionFactory.setUsername(username); |
|||
connectionFactory.setPassword(password); |
|||
connectionFactory.setAutomaticRecoveryEnabled(automaticRecoveryEnabled); |
|||
connectionFactory.setConnectionTimeout(connectionTimeout); |
|||
connectionFactory.setHandshakeTimeout(handshakeTimeout); |
|||
} |
|||
} |
|||
@ -1,118 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.sqs; |
|||
|
|||
import com.amazonaws.auth.AWSCredentials; |
|||
import com.amazonaws.auth.AWSCredentialsProvider; |
|||
import com.amazonaws.auth.AWSStaticCredentialsProvider; |
|||
import com.amazonaws.auth.BasicAWSCredentials; |
|||
import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; |
|||
import com.amazonaws.services.sqs.AmazonSQS; |
|||
import com.amazonaws.services.sqs.AmazonSQSClientBuilder; |
|||
import com.amazonaws.services.sqs.model.CreateQueueRequest; |
|||
import com.amazonaws.services.sqs.model.GetQueueUrlResult; |
|||
import lombok.Getter; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.common.util.ThingsBoardExecutors; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.util.PropertyUtils; |
|||
|
|||
import java.util.Map; |
|||
import java.util.concurrent.ExecutorService; |
|||
import java.util.function.Function; |
|||
import java.util.stream.Collectors; |
|||
|
|||
@Slf4j |
|||
@Deprecated(forRemoval = true, since = "3.9") // for removal in 4.0
|
|||
public class TbAwsSqsAdmin implements TbQueueAdmin { |
|||
|
|||
private final Map<String, String> attributes; |
|||
private final AmazonSQS sqsClient; |
|||
private final Map<String, String> queues; |
|||
@Getter |
|||
private final ExecutorService producerExecutor; |
|||
|
|||
public TbAwsSqsAdmin(TbAwsSqsSettings sqsSettings, Map<String, String> attributes) { |
|||
this.attributes = attributes; |
|||
|
|||
AWSCredentialsProvider credentialsProvider; |
|||
if (sqsSettings.getUseDefaultCredentialProviderChain()) { |
|||
credentialsProvider = new DefaultAWSCredentialsProviderChain(); |
|||
} else { |
|||
AWSCredentials awsCredentials = new BasicAWSCredentials(sqsSettings.getAccessKeyId(), sqsSettings.getSecretAccessKey()); |
|||
credentialsProvider = new AWSStaticCredentialsProvider(awsCredentials); |
|||
} |
|||
producerExecutor = ThingsBoardExecutors.newWorkStealingPool(sqsSettings.getThreadPoolSize(), "aws-sqs-queue-executor"); |
|||
|
|||
sqsClient = AmazonSQSClientBuilder.standard() |
|||
.withCredentials(credentialsProvider) |
|||
.withRegion(sqsSettings.getRegion()) |
|||
.build(); |
|||
|
|||
queues = sqsClient |
|||
.listQueues() |
|||
.getQueueUrls() |
|||
.stream() |
|||
.map(this::getQueueNameFromUrl) |
|||
.collect(Collectors.toMap(this::convertTopicToQueueName, Function.identity())); |
|||
} |
|||
|
|||
@Override |
|||
public void createTopicIfNotExists(String topic, String properties) { |
|||
String queueName = convertTopicToQueueName(topic); |
|||
if (queues.containsKey(queueName)) { |
|||
return; |
|||
} |
|||
Map<String, String> attributes = PropertyUtils.getProps(this.attributes, properties, TbAwsSqsQueueAttributes::toConfigs); |
|||
final CreateQueueRequest createQueueRequest = new CreateQueueRequest(queueName).withAttributes(attributes); |
|||
String queueUrl = sqsClient.createQueue(createQueueRequest).getQueueUrl(); |
|||
queues.put(getQueueNameFromUrl(queueUrl), queueUrl); |
|||
} |
|||
|
|||
private String convertTopicToQueueName(String topic) { |
|||
return topic.replaceAll("\\.", "_") + ".fifo"; |
|||
} |
|||
|
|||
@Override |
|||
public void deleteTopic(String topic) { |
|||
String queueName = convertTopicToQueueName(topic); |
|||
if (queues.containsKey(queueName)) { |
|||
sqsClient.deleteQueue(queues.get(queueName)); |
|||
} else { |
|||
GetQueueUrlResult queueUrl = sqsClient.getQueueUrl(queueName); |
|||
if (queueUrl != null) { |
|||
sqsClient.deleteQueue(queueUrl.getQueueUrl()); |
|||
} else { |
|||
log.warn("Aws SQS queue [{}] does not exist!", queueName); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private String getQueueNameFromUrl(String queueUrl) { |
|||
int delimiterIndex = queueUrl.lastIndexOf("/"); |
|||
return queueUrl.substring(delimiterIndex + 1); |
|||
} |
|||
|
|||
@Override |
|||
public void destroy() { |
|||
if (sqsClient != null) { |
|||
sqsClient.shutdown(); |
|||
} |
|||
if (producerExecutor != null) { |
|||
producerExecutor.shutdownNow(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,188 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.sqs; |
|||
|
|||
import com.amazonaws.auth.AWSCredentials; |
|||
import com.amazonaws.auth.AWSCredentialsProvider; |
|||
import com.amazonaws.auth.AWSStaticCredentialsProvider; |
|||
import com.amazonaws.auth.BasicAWSCredentials; |
|||
import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; |
|||
import com.amazonaws.services.sqs.AmazonSQS; |
|||
import com.amazonaws.services.sqs.AmazonSQSClientBuilder; |
|||
import com.amazonaws.services.sqs.model.DeleteMessageBatchRequestEntry; |
|||
import com.amazonaws.services.sqs.model.Message; |
|||
import com.amazonaws.services.sqs.model.ReceiveMessageRequest; |
|||
import com.google.common.util.concurrent.Futures; |
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import com.google.gson.Gson; |
|||
import com.google.protobuf.InvalidProtocolBufferException; |
|||
import lombok.Data; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.util.CollectionUtils; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueMsg; |
|||
import org.thingsboard.server.queue.TbQueueMsgDecoder; |
|||
import org.thingsboard.server.queue.common.AbstractParallelTbQueueConsumerTemplate; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueMsg; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
import java.util.Objects; |
|||
import java.util.Set; |
|||
import java.util.concurrent.CopyOnWriteArrayList; |
|||
import java.util.concurrent.ExecutionException; |
|||
import java.util.concurrent.TimeUnit; |
|||
import java.util.stream.Collectors; |
|||
import java.util.stream.Stream; |
|||
|
|||
@Slf4j |
|||
public class TbAwsSqsConsumerTemplate<T extends TbQueueMsg> extends AbstractParallelTbQueueConsumerTemplate<Message, T> { |
|||
|
|||
private static final int MAX_NUM_MSGS = 10; |
|||
|
|||
private final Gson gson = new Gson(); |
|||
private final TbQueueAdmin admin; |
|||
private final AmazonSQS sqsClient; |
|||
private final TbQueueMsgDecoder<T> decoder; |
|||
private final TbAwsSqsSettings sqsSettings; |
|||
|
|||
private final List<AwsSqsMsgWrapper> pendingMessages = new CopyOnWriteArrayList<>(); |
|||
private volatile Set<String> queueUrls; |
|||
|
|||
public TbAwsSqsConsumerTemplate(TbQueueAdmin admin, TbAwsSqsSettings sqsSettings, String topic, TbQueueMsgDecoder<T> decoder) { |
|||
super(topic); |
|||
this.admin = admin; |
|||
this.decoder = decoder; |
|||
this.sqsSettings = sqsSettings; |
|||
|
|||
AWSCredentialsProvider credentialsProvider; |
|||
if (sqsSettings.getUseDefaultCredentialProviderChain()) { |
|||
credentialsProvider = new DefaultAWSCredentialsProviderChain(); |
|||
} else { |
|||
AWSCredentials awsCredentials = new BasicAWSCredentials(sqsSettings.getAccessKeyId(), sqsSettings.getSecretAccessKey()); |
|||
credentialsProvider = new AWSStaticCredentialsProvider(awsCredentials); |
|||
} |
|||
|
|||
sqsClient = AmazonSQSClientBuilder.standard() |
|||
.withCredentials(credentialsProvider) |
|||
.withRegion(sqsSettings.getRegion()) |
|||
.build(); |
|||
|
|||
} |
|||
|
|||
@Override |
|||
protected void doSubscribe(List<String> topicNames) { |
|||
queueUrls = topicNames.stream().map(this::getQueueUrl).collect(Collectors.toSet()); |
|||
initNewExecutor(queueUrls.size() * sqsSettings.getThreadsPerTopic() + 1); |
|||
} |
|||
|
|||
@Override |
|||
protected List<Message> doPoll(long durationInMillis) { |
|||
int duration = (int) TimeUnit.MILLISECONDS.toSeconds(durationInMillis); |
|||
List<ListenableFuture<List<Message>>> futureList = queueUrls |
|||
.stream() |
|||
.map(url -> poll(url, duration)) |
|||
.collect(Collectors.toList()); |
|||
ListenableFuture<List<List<Message>>> futureResult = Futures.allAsList(futureList); |
|||
try { |
|||
return futureResult.get().stream() |
|||
.flatMap(List::stream) |
|||
.filter(Objects::nonNull) |
|||
.collect(Collectors.toList()); |
|||
} catch (InterruptedException | ExecutionException e) { |
|||
if (stopped) { |
|||
log.info("[{}] Aws SQS consumer is stopped.", getTopic()); |
|||
} else { |
|||
log.error("Failed to pool messages.", e); |
|||
} |
|||
return Collections.emptyList(); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public T decode(Message message) throws InvalidProtocolBufferException { |
|||
DefaultTbQueueMsg msg = gson.fromJson(message.getBody(), DefaultTbQueueMsg.class); |
|||
return decoder.decode(msg); |
|||
} |
|||
|
|||
@Override |
|||
protected void doCommit() { |
|||
pendingMessages.forEach(msg -> |
|||
consumerExecutor.submit(() -> { |
|||
List<DeleteMessageBatchRequestEntry> entries = msg.getMessages() |
|||
.stream() |
|||
.map(message -> new DeleteMessageBatchRequestEntry(message.getMessageId(), message.getReceiptHandle())) |
|||
.collect(Collectors.toList()); |
|||
sqsClient.deleteMessageBatch(msg.getUrl(), entries); |
|||
})); |
|||
pendingMessages.clear(); |
|||
} |
|||
|
|||
@Override |
|||
protected void doUnsubscribe() { |
|||
stopped = true; |
|||
if (sqsClient != null) { |
|||
sqsClient.shutdown(); |
|||
} |
|||
shutdownExecutor(); |
|||
} |
|||
|
|||
private ListenableFuture<List<Message>> poll(String url, int waitTimeSeconds) { |
|||
List<ListenableFuture<List<Message>>> result = new ArrayList<>(); |
|||
|
|||
for (int i = 0; i < sqsSettings.getThreadsPerTopic(); i++) { |
|||
result.add(consumerExecutor.submit(() -> { |
|||
ReceiveMessageRequest request = new ReceiveMessageRequest(); |
|||
request |
|||
.withWaitTimeSeconds(waitTimeSeconds) |
|||
.withQueueUrl(url) |
|||
.withMaxNumberOfMessages(MAX_NUM_MSGS); |
|||
return sqsClient.receiveMessage(request).getMessages(); |
|||
})); |
|||
} |
|||
return Futures.transform(Futures.allAsList(result), list -> { |
|||
if (!CollectionUtils.isEmpty(list)) { |
|||
return list.stream() |
|||
.flatMap(messageList -> { |
|||
if (!messageList.isEmpty()) { |
|||
this.pendingMessages.add(new AwsSqsMsgWrapper(url, messageList)); |
|||
return messageList.stream(); |
|||
} |
|||
return Stream.empty(); |
|||
}) |
|||
.collect(Collectors.toList()); |
|||
} |
|||
return Collections.emptyList(); |
|||
}, consumerExecutor); |
|||
} |
|||
|
|||
@Data |
|||
private static class AwsSqsMsgWrapper { |
|||
private final String url; |
|||
private final List<Message> messages; |
|||
|
|||
public AwsSqsMsgWrapper(String url, List<Message> messages) { |
|||
this.url = url; |
|||
this.messages = messages; |
|||
} |
|||
} |
|||
|
|||
private String getQueueUrl(String topic) { |
|||
admin.createTopicIfNotExists(topic); |
|||
return sqsClient.getQueueUrl(topic.replaceAll("\\.", "_") + ".fifo").getQueueUrl(); |
|||
} |
|||
} |
|||
@ -1,117 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.sqs; |
|||
|
|||
import com.amazonaws.auth.AWSCredentials; |
|||
import com.amazonaws.auth.AWSCredentialsProvider; |
|||
import com.amazonaws.auth.AWSStaticCredentialsProvider; |
|||
import com.amazonaws.auth.BasicAWSCredentials; |
|||
import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; |
|||
import com.amazonaws.handlers.AsyncHandler; |
|||
import com.amazonaws.services.sqs.AmazonSQSAsync; |
|||
import com.amazonaws.services.sqs.AmazonSQSAsyncClientBuilder; |
|||
import com.amazonaws.services.sqs.model.SendMessageRequest; |
|||
import com.amazonaws.services.sqs.model.SendMessageResult; |
|||
import com.google.gson.Gson; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueCallback; |
|||
import org.thingsboard.server.queue.TbQueueMsg; |
|||
import org.thingsboard.server.queue.TbQueueProducer; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueMsg; |
|||
|
|||
import java.util.Map; |
|||
import java.util.UUID; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
|
|||
@Slf4j |
|||
public class TbAwsSqsProducerTemplate<T extends TbQueueMsg> implements TbQueueProducer<T> { |
|||
private final String defaultTopic; |
|||
private final AmazonSQSAsync sqsClient; |
|||
private final Gson gson = new Gson(); |
|||
private final Map<String, String> queueUrlMap = new ConcurrentHashMap<>(); |
|||
private final TbAwsSqsAdmin admin; |
|||
|
|||
public TbAwsSqsProducerTemplate(TbQueueAdmin admin, TbAwsSqsSettings sqsSettings, String defaultTopic) { |
|||
this.admin = (TbAwsSqsAdmin) admin; |
|||
this.defaultTopic = defaultTopic; |
|||
|
|||
AWSCredentialsProvider credentialsProvider; |
|||
if (sqsSettings.getUseDefaultCredentialProviderChain()) { |
|||
credentialsProvider = new DefaultAWSCredentialsProviderChain(); |
|||
} else { |
|||
AWSCredentials awsCredentials = new BasicAWSCredentials(sqsSettings.getAccessKeyId(), sqsSettings.getSecretAccessKey()); |
|||
credentialsProvider = new AWSStaticCredentialsProvider(awsCredentials); |
|||
} |
|||
|
|||
sqsClient = AmazonSQSAsyncClientBuilder.standard() |
|||
.withCredentials(credentialsProvider) |
|||
.withRegion(sqsSettings.getRegion()) |
|||
.withExecutorFactory(this.admin::getProducerExecutor) |
|||
.build(); |
|||
} |
|||
|
|||
@Override |
|||
public void init() { |
|||
|
|||
} |
|||
|
|||
@Override |
|||
public String getDefaultTopic() { |
|||
return defaultTopic; |
|||
} |
|||
|
|||
@Override |
|||
public void send(TopicPartitionInfo tpi, T msg, TbQueueCallback callback) { |
|||
SendMessageRequest sendMsgRequest = new SendMessageRequest(); |
|||
sendMsgRequest.withQueueUrl(getQueueUrl(tpi.getFullTopicName())); |
|||
sendMsgRequest.withMessageBody(gson.toJson(new DefaultTbQueueMsg(msg))); |
|||
|
|||
String sqsMsgId = UUID.randomUUID().toString(); |
|||
sendMsgRequest.withMessageGroupId(sqsMsgId); |
|||
sendMsgRequest.withMessageDeduplicationId(sqsMsgId); |
|||
|
|||
sqsClient.sendMessageAsync(sendMsgRequest, new AsyncHandler<SendMessageRequest, SendMessageResult>() { |
|||
@Override public void onError(Exception e) { |
|||
if (callback != null) { |
|||
callback.onFailure(e); |
|||
} |
|||
} |
|||
|
|||
@Override public void onSuccess(SendMessageRequest request, |
|||
SendMessageResult sendMessageResult) { |
|||
if (callback != null) { |
|||
callback.onSuccess(new AwsSqsTbQueueMsgMetadata(sendMessageResult.getSdkHttpMetadata())); |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
|
|||
@Override |
|||
public void stop() { |
|||
if (sqsClient != null) { |
|||
sqsClient.shutdown(); |
|||
} |
|||
} |
|||
|
|||
private String getQueueUrl(String topic) { |
|||
return queueUrlMap.computeIfAbsent(topic, k -> { |
|||
admin.createTopicIfNotExists(topic); |
|||
return sqsClient.getQueueUrl(topic.replaceAll("\\.", "_") + ".fifo").getQueueUrl(); |
|||
}); |
|||
} |
|||
} |
|||
@ -1,105 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.sqs; |
|||
|
|||
import com.amazonaws.services.sqs.model.QueueAttributeName; |
|||
import jakarta.annotation.PostConstruct; |
|||
import lombok.Getter; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.server.common.data.StringUtils; |
|||
|
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
@Component |
|||
@ConditionalOnExpression("'${queue.type:null}'=='aws-sqs'") |
|||
public class TbAwsSqsQueueAttributes { |
|||
@Value("${queue.aws-sqs.queue-properties.core:}") |
|||
private String coreProperties; |
|||
@Value("${queue.aws-sqs.queue-properties.rule-engine:}") |
|||
private String ruleEngineProperties; |
|||
@Value("${queue.aws-sqs.queue-properties.transport-api:}") |
|||
private String transportApiProperties; |
|||
@Value("${queue.aws-sqs.queue-properties.notifications:}") |
|||
private String notificationsProperties; |
|||
@Value("${queue.aws-sqs.queue-properties.js-executor:}") |
|||
private String jsExecutorProperties; |
|||
@Value("${queue.aws-sqs.queue-properties.ota-updates:}") |
|||
private String otaProperties; |
|||
@Value("${queue.aws-sqs.queue-properties.version-control:}") |
|||
private String vcProperties; |
|||
@Value("${queue.aws-sqs.queue-properties.edge:}") |
|||
private String edgeProperties; |
|||
|
|||
@Getter |
|||
private Map<String, String> coreAttributes; |
|||
@Getter |
|||
private Map<String, String> ruleEngineAttributes; |
|||
@Getter |
|||
private Map<String, String> transportApiAttributes; |
|||
@Getter |
|||
private Map<String, String> notificationsAttributes; |
|||
@Getter |
|||
private Map<String, String> jsExecutorAttributes; |
|||
@Getter |
|||
private Map<String, String> otaAttributes; |
|||
@Getter |
|||
private Map<String, String> vcAttributes; |
|||
@Getter |
|||
private Map<String, String> edgeAttributes; |
|||
|
|||
private final Map<String, String> defaultAttributes = new HashMap<>(); |
|||
|
|||
@PostConstruct |
|||
private void init() { |
|||
defaultAttributes.put(QueueAttributeName.FifoQueue.toString(), "true"); |
|||
|
|||
coreAttributes = getConfigs(coreProperties); |
|||
ruleEngineAttributes = getConfigs(ruleEngineProperties); |
|||
transportApiAttributes = getConfigs(transportApiProperties); |
|||
notificationsAttributes = getConfigs(notificationsProperties); |
|||
jsExecutorAttributes = getConfigs(jsExecutorProperties); |
|||
otaAttributes = getConfigs(otaProperties); |
|||
vcAttributes = getConfigs(vcProperties); |
|||
edgeAttributes = getConfigs(edgeProperties); |
|||
} |
|||
|
|||
private Map<String, String> getConfigs(String properties) { |
|||
Map<String, String> configs = new HashMap<>(defaultAttributes); |
|||
configs.putAll(toConfigs(properties)); |
|||
return configs; |
|||
} |
|||
|
|||
public static Map<String, String> toConfigs(String properties) { |
|||
Map<String, String> configs = new HashMap<>(); |
|||
if (StringUtils.isNotEmpty(properties)) { |
|||
for (String property : properties.split(";")) { |
|||
int delimiterPosition = property.indexOf(":"); |
|||
String key = property.substring(0, delimiterPosition); |
|||
String value = property.substring(delimiterPosition + 1); |
|||
validateAttributeName(key); |
|||
configs.put(key, value); |
|||
} |
|||
} |
|||
return configs; |
|||
} |
|||
|
|||
private static void validateAttributeName(String key) { |
|||
QueueAttributeName.fromValue(key); |
|||
} |
|||
} |
|||
@ -1,48 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.sqs; |
|||
|
|||
import lombok.Data; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
@Slf4j |
|||
@ConditionalOnExpression("'${queue.type:null}'=='aws-sqs'") |
|||
@Component |
|||
@Data |
|||
public class TbAwsSqsSettings { |
|||
|
|||
@Value("${queue.aws_sqs.use_default_credential_provider_chain}") |
|||
private Boolean useDefaultCredentialProviderChain; |
|||
|
|||
@Value("${queue.aws_sqs.access_key_id}") |
|||
private String accessKeyId; |
|||
|
|||
@Value("${queue.aws_sqs.secret_access_key}") |
|||
private String secretAccessKey; |
|||
|
|||
@Value("${queue.aws_sqs.region}") |
|||
private String region; |
|||
|
|||
@Value("${queue.aws_sqs.threads_per_topic}") |
|||
private int threadsPerTopic; |
|||
|
|||
@Value("${queue.aws_sqs.producer_thread_pool_size:50}") |
|||
private int threadPoolSize; |
|||
|
|||
} |
|||
@ -1,128 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2024 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.queue.rabbitmq; |
|||
|
|||
import static org.assertj.core.api.Assertions.assertThat; |
|||
import static org.mockito.ArgumentMatchers.anyBoolean; |
|||
import static org.mockito.ArgumentMatchers.anyString; |
|||
import static org.mockito.Mockito.times; |
|||
import static org.mockito.Mockito.verify; |
|||
import static org.mockito.Mockito.when; |
|||
|
|||
import com.rabbitmq.client.Channel; |
|||
import com.rabbitmq.client.Connection; |
|||
import com.rabbitmq.client.ConnectionFactory; |
|||
import com.rabbitmq.client.GetResponse; |
|||
import java.nio.charset.StandardCharsets; |
|||
import java.util.Set; |
|||
import java.util.UUID; |
|||
import org.junit.jupiter.api.Test; |
|||
import org.junit.jupiter.api.extension.ExtendWith; |
|||
import org.mockito.Mock; |
|||
import org.mockito.junit.jupiter.MockitoExtension; |
|||
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
|||
import org.thingsboard.server.queue.TbQueueAdmin; |
|||
import org.thingsboard.server.queue.TbQueueMsgDecoder; |
|||
import org.thingsboard.server.queue.common.DefaultTbQueueMsg; |
|||
|
|||
@ExtendWith(MockitoExtension.class) |
|||
class TbRabbitMqConsumerTemplateTest { |
|||
|
|||
private static final String TOPIC = "some-topic"; |
|||
|
|||
@Mock |
|||
private TbQueueAdmin admin; |
|||
|
|||
@Mock |
|||
private ConnectionFactory connectionFactory; |
|||
|
|||
@Mock |
|||
private TbQueueMsgDecoder<DefaultTbQueueMsg> decoder; |
|||
|
|||
@Mock |
|||
private Connection connection; |
|||
|
|||
@Mock |
|||
private Channel channel; |
|||
|
|||
@Mock |
|||
private TopicPartitionInfo partition; |
|||
|
|||
@Mock |
|||
private GetResponse getResponse; |
|||
|
|||
private TbRabbitMqConsumerTemplate<DefaultTbQueueMsg> consumer; |
|||
|
|||
private void setUpConsumerWithMaxPollMessages(int maxPollMessages) throws Exception { |
|||
when(connectionFactory.newConnection()).thenReturn(connection); |
|||
when(connection.createChannel()).thenReturn(channel); |
|||
TbRabbitMqSettings settings = new TbRabbitMqSettings(); |
|||
settings.setMaxPollMessages(maxPollMessages); |
|||
settings.setConnectionFactory(connectionFactory); |
|||
|
|||
consumer = new TbRabbitMqConsumerTemplate<>(admin, settings, TOPIC, decoder); |
|||
when(partition.getFullTopicName()).thenReturn(TOPIC); |
|||
consumer.subscribe(Set.of(partition)); |
|||
} |
|||
|
|||
@Test |
|||
void pollWithMax5PollMessagesReturnsEmptyListIfNoMessages() throws Exception { |
|||
setUpConsumerWithMaxPollMessages(5); |
|||
when(channel.basicGet(anyString(), anyBoolean())).thenReturn(null); |
|||
|
|||
assertThat(consumer.poll(0L)).isEmpty(); |
|||
|
|||
verify(channel).basicGet(anyString(), anyBoolean()); |
|||
} |
|||
|
|||
@Test |
|||
void pollWithMax5PollMessagesReturns5MessagesIfQueueContains5() throws Exception { |
|||
setUpConsumerWithMaxPollMessages(5); |
|||
when(getResponse.getBody()).thenReturn(newMessageBody()); |
|||
when(channel.basicGet(anyString(), anyBoolean())).thenReturn(getResponse); |
|||
|
|||
assertThat(consumer.poll(0L)).hasSize(5); |
|||
|
|||
verify(channel, times(5)).basicGet(anyString(), anyBoolean()); |
|||
} |
|||
|
|||
@Test |
|||
void pollWithMax1PollMessageReturns1MessageIfQueueContainsMore() throws Exception { |
|||
setUpConsumerWithMaxPollMessages(1); |
|||
when(getResponse.getBody()).thenReturn(newMessageBody()); |
|||
when(channel.basicGet(anyString(), anyBoolean())).thenReturn(getResponse); |
|||
|
|||
assertThat(consumer.poll(0L)).hasSize(1); |
|||
|
|||
verify(channel).basicGet(anyString(), anyBoolean()); |
|||
} |
|||
|
|||
@Test |
|||
void pollWithMax3PollMessagesReturns2MessagesIfQueueContains2() throws Exception { |
|||
setUpConsumerWithMaxPollMessages(3); |
|||
when(getResponse.getBody()).thenReturn(newMessageBody()); |
|||
when(channel.basicGet(anyString(), anyBoolean())).thenReturn(getResponse, getResponse, null); |
|||
|
|||
assertThat(consumer.poll(0L)).hasSize(2); |
|||
|
|||
verify(channel, times(3)).basicGet(anyString(), anyBoolean()); |
|||
} |
|||
|
|||
private byte[] newMessageBody() { |
|||
return ("{\"key\": \"" + UUID.randomUUID() + "\"}").getBytes(StandardCharsets.UTF_8); |
|||
} |
|||
|
|||
} |
|||
@ -1,198 +0,0 @@ |
|||
///
|
|||
/// Copyright © 2016-2024 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.
|
|||
///
|
|||
|
|||
import config from 'config'; |
|||
import { _logger } from '../config/logger'; |
|||
import { JsInvokeMessageProcessor } from '../api/jsInvokeMessageProcessor' |
|||
import { IQueue } from './queue.models'; |
|||
import { |
|||
CreateQueueCommand, |
|||
CreateQueueRequest, |
|||
DeleteMessageBatchCommand, |
|||
DeleteMessageBatchRequest, |
|||
DeleteMessageBatchRequestEntry, |
|||
ListQueuesCommand, |
|||
ListQueuesResult, |
|||
ReceiveMessageCommand, |
|||
ReceiveMessageRequest, |
|||
ReceiveMessageResult, |
|||
SendMessageCommand, |
|||
SendMessageRequest, |
|||
SQSClient |
|||
} from '@aws-sdk/client-sqs'; |
|||
import uuid from 'uuid-random'; |
|||
|
|||
export class AwsSqsTemplate implements IQueue { |
|||
|
|||
private logger = _logger(`awsSqsTemplate`); |
|||
private queuePrefix: string = config.get('queue_prefix'); |
|||
private requestTopic: string = this.queuePrefix ? this.queuePrefix + "." + config.get('request_topic') : config.get('request_topic'); |
|||
private accessKeyId: string = config.get('aws_sqs.access_key_id'); |
|||
private secretAccessKey: string = config.get('aws_sqs.secret_access_key'); |
|||
private region: string = config.get('aws_sqs.region'); |
|||
private queueProperties: string = config.get('aws_sqs.queue_properties'); |
|||
private pollInterval = Number(config.get('js.response_poll_interval')); |
|||
|
|||
private sqsClient: SQSClient; |
|||
private requestQueueURL: string |
|||
private queueUrls = new Map<string, string>(); |
|||
private queueAttributes: { [n: string]: string } = { |
|||
FifoQueue: 'true' |
|||
}; |
|||
private timer: NodeJS.Timeout; |
|||
|
|||
name = 'AWS SQS'; |
|||
|
|||
constructor() { |
|||
} |
|||
|
|||
async init() { |
|||
this.sqsClient = new SQSClient({ |
|||
apiVersion: '2012-11-05', |
|||
credentials: { |
|||
accessKeyId: this.accessKeyId, |
|||
secretAccessKey: this.secretAccessKey |
|||
}, |
|||
region: this.region |
|||
}); |
|||
|
|||
const queues = await this.getQueues(); |
|||
|
|||
if (queues.QueueUrls) { |
|||
queues.QueueUrls.forEach(queueUrl => { |
|||
const delimiterPosition = queueUrl.lastIndexOf('/'); |
|||
const queueName = queueUrl.substring(delimiterPosition + 1); |
|||
this.queueUrls.set(queueName, queueUrl); |
|||
}); |
|||
} |
|||
|
|||
this.parseQueueProperties(); |
|||
|
|||
this.requestQueueURL = this.queueUrls.get(AwsSqsTemplate.topicToSqsQueueName(this.requestTopic)) || ''; |
|||
if (!this.requestQueueURL) { |
|||
this.requestQueueURL = await this.createQueue(this.requestTopic); |
|||
} |
|||
|
|||
const messageProcessor = new JsInvokeMessageProcessor(this); |
|||
|
|||
const params: ReceiveMessageRequest = { |
|||
MaxNumberOfMessages: 10, |
|||
QueueUrl: this.requestQueueURL, |
|||
WaitTimeSeconds: Math.ceil(this.pollInterval / 10) |
|||
}; |
|||
this.timer = setTimeout(() => {this.getAndProcessMessage(messageProcessor, params)}, this.pollInterval); |
|||
} |
|||
|
|||
private async getAndProcessMessage(messageProcessor: JsInvokeMessageProcessor, params: ReceiveMessageRequest) { |
|||
const messagesResponse: ReceiveMessageResult = await this.sqsClient.send(new ReceiveMessageCommand(params)); |
|||
const messages = messagesResponse.Messages; |
|||
|
|||
if (messages && messages.length > 0) { |
|||
const entries: DeleteMessageBatchRequestEntry[] = []; |
|||
|
|||
messages.forEach(message => { |
|||
entries.push({ |
|||
Id: message.MessageId, |
|||
ReceiptHandle: message.ReceiptHandle |
|||
}); |
|||
messageProcessor.onJsInvokeMessage(JSON.parse(message.Body || '')); |
|||
}); |
|||
|
|||
const deleteBatch: DeleteMessageBatchRequest = { |
|||
QueueUrl: this.requestQueueURL, |
|||
Entries: entries |
|||
}; |
|||
try { |
|||
await this.sqsClient.send(new DeleteMessageBatchCommand(deleteBatch)) |
|||
} catch (err: any) { |
|||
this.logger.error("Failed to delete messages from queue.", err.message); |
|||
} |
|||
} |
|||
this.timer = setTimeout(() => {this.getAndProcessMessage(messageProcessor, params)}, this.pollInterval); |
|||
} |
|||
|
|||
async send(responseTopic: string, msgKey: string, rawResponse: Buffer, headers: any): Promise<any> { |
|||
let msgBody = JSON.stringify( |
|||
{ |
|||
key: msgKey, |
|||
data: [...rawResponse], |
|||
headers: headers |
|||
}); |
|||
|
|||
let responseQueueUrl = this.queueUrls.get(AwsSqsTemplate.topicToSqsQueueName(responseTopic)); |
|||
|
|||
if (!responseQueueUrl) { |
|||
responseQueueUrl = await this.createQueue(responseTopic); |
|||
this.queueUrls.set(responseTopic, responseQueueUrl); |
|||
} |
|||
|
|||
let msgId = uuid(); |
|||
|
|||
let params: SendMessageRequest = { |
|||
MessageBody: msgBody, |
|||
QueueUrl: responseQueueUrl, |
|||
MessageGroupId: msgId, |
|||
MessageDeduplicationId: msgId |
|||
}; |
|||
|
|||
return this.sqsClient.send(new SendMessageCommand(params)) |
|||
} |
|||
|
|||
private async getQueues(): Promise<ListQueuesResult> { |
|||
return this.sqsClient.send(new ListQueuesCommand({})); |
|||
} |
|||
|
|||
private parseQueueProperties() { |
|||
const props = this.queueProperties.split(';'); |
|||
props.forEach(p => { |
|||
const delimiterPosition = p.indexOf(':'); |
|||
this.queueAttributes[p.substring(0, delimiterPosition)] = p.substring(delimiterPosition + 1); |
|||
}); |
|||
} |
|||
|
|||
private static topicToSqsQueueName(topic: string): string { |
|||
return topic.replace(/\./g, '_') + '.fifo'; |
|||
} |
|||
|
|||
private async createQueue(topic: string): Promise<string> { |
|||
let queueName = AwsSqsTemplate.topicToSqsQueueName(topic); |
|||
let queueParams: CreateQueueRequest = { |
|||
QueueName: queueName, |
|||
Attributes: this.queueAttributes |
|||
}; |
|||
|
|||
const result = await this.sqsClient.send(new CreateQueueCommand(queueParams)); |
|||
return result.QueueUrl || ''; |
|||
} |
|||
|
|||
async destroy(): Promise<void> { |
|||
this.logger.info('Stopping AWS SQS resources...'); |
|||
clearTimeout(this.timer); |
|||
if (this.sqsClient) { |
|||
this.logger.info('Stopping AWS SQS client...'); |
|||
try { |
|||
const _sqsClient = this.sqsClient; |
|||
// @ts-ignore
|
|||
delete this.sqsClient; |
|||
_sqsClient.destroy(); |
|||
this.logger.info('AWS SQS client stopped.'); |
|||
} catch (e: any) { |
|||
this.logger.info('AWS SQS client stop error.'); |
|||
} |
|||
} |
|||
this.logger.info('AWS SQS resources stopped.') |
|||
} |
|||
} |
|||
@ -1,162 +0,0 @@ |
|||
///
|
|||
/// Copyright © 2016-2024 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.
|
|||
///
|
|||
|
|||
import config from 'config'; |
|||
import { _logger } from '../config/logger'; |
|||
import { JsInvokeMessageProcessor } from '../api/jsInvokeMessageProcessor' |
|||
import { PubSub } from '@google-cloud/pubsub'; |
|||
import { IQueue } from './queue.models'; |
|||
import { Message } from '@google-cloud/pubsub/build/src/subscriber'; |
|||
|
|||
export class PubSubTemplate implements IQueue { |
|||
|
|||
private logger = _logger(`pubSubTemplate`); |
|||
private projectId: string = config.get('pubsub.project_id'); |
|||
private credentials = JSON.parse(config.get('pubsub.service_account')); |
|||
private queuePrefix: string = config.get('queue_prefix'); |
|||
private requestTopic: string = this.queuePrefix ? this.queuePrefix + "." + config.get('request_topic') : config.get('request_topic'); |
|||
private queueProperties: string = config.get('pubsub.queue_properties'); |
|||
|
|||
private pubSubClient: PubSub; |
|||
private queueProps: { [n: string]: string } = {}; |
|||
private topics: string[] = []; |
|||
private subscriptions: string[] = []; |
|||
|
|||
name = 'Pub/Sub'; |
|||
|
|||
constructor() { |
|||
} |
|||
|
|||
async init() { |
|||
this.pubSubClient = new PubSub({ |
|||
projectId: this.projectId, |
|||
credentials: this.credentials |
|||
}); |
|||
|
|||
this.parseQueueProperties(); |
|||
|
|||
const topicList = await this.pubSubClient.getTopics(); |
|||
|
|||
if (topicList) { |
|||
topicList[0].forEach(topic => { |
|||
this.topics.push(PubSubTemplate.getName(topic.name)); |
|||
}); |
|||
} |
|||
|
|||
const subscriptionList = await this.pubSubClient.getSubscriptions(); |
|||
|
|||
if (subscriptionList) { |
|||
topicList[0].forEach(sub => { |
|||
this.subscriptions.push(PubSubTemplate.getName(sub.name)); |
|||
}); |
|||
} |
|||
|
|||
if (!(this.subscriptions.includes(this.requestTopic) && this.topics.includes(this.requestTopic))) { |
|||
await this.createTopic(this.requestTopic); |
|||
await this.createSubscription(this.requestTopic); |
|||
} |
|||
|
|||
const subscription = this.pubSubClient.subscription(this.requestTopic); |
|||
|
|||
const messageProcessor = new JsInvokeMessageProcessor(this); |
|||
|
|||
const messageHandler = (message: Message) => { |
|||
messageProcessor.onJsInvokeMessage(JSON.parse(message.data.toString('utf8'))); |
|||
message.ack(); |
|||
}; |
|||
|
|||
subscription.on('message', messageHandler); |
|||
} |
|||
|
|||
async send(responseTopic: string, msgKey: string, rawResponse: Buffer, headers: any): Promise<any> { |
|||
if (!(this.subscriptions.includes(responseTopic) && this.topics.includes(this.requestTopic))) { |
|||
await this.createTopic(this.requestTopic); |
|||
await this.createSubscription(this.requestTopic); |
|||
} |
|||
|
|||
let data = JSON.stringify( |
|||
{ |
|||
key: msgKey, |
|||
data: [...rawResponse], |
|||
headers: headers |
|||
}); |
|||
let dataBuffer = Buffer.from(data); |
|||
return this.pubSubClient.topic(responseTopic).publishMessage({data: dataBuffer}); |
|||
} |
|||
|
|||
private parseQueueProperties() { |
|||
const props = this.queueProperties.split(';'); |
|||
props.forEach(p => { |
|||
const delimiterPosition = p.indexOf(':'); |
|||
this.queueProps[p.substring(0, delimiterPosition)] = p.substring(delimiterPosition + 1); |
|||
}); |
|||
} |
|||
|
|||
private static getName(fullName: string): string { |
|||
const delimiterPosition = fullName.lastIndexOf('/'); |
|||
return fullName.substring(delimiterPosition + 1); |
|||
} |
|||
|
|||
private async createTopic(topic: string) { |
|||
if (!this.topics.includes(topic)) { |
|||
try { |
|||
await this.pubSubClient.createTopic(topic); |
|||
this.logger.info('Created new Pub/Sub topic: %s', topic); |
|||
} catch (e) { |
|||
this.logger.info('Pub/Sub topic already exists'); |
|||
} |
|||
this.topics.push(topic); |
|||
} |
|||
} |
|||
|
|||
private async createSubscription(topic: string) { |
|||
if (!this.subscriptions.includes(topic)) { |
|||
try { |
|||
await this.pubSubClient.createSubscription(topic, topic, { |
|||
topic: topic, |
|||
name: topic, |
|||
ackDeadlineSeconds: Number(this.queueProps['ackDeadlineInSec']), |
|||
messageRetentionDuration: { |
|||
seconds: this.queueProps['messageRetentionInSec'] |
|||
} |
|||
}); |
|||
this.logger.info('Created new Pub/Sub subscription: %s', topic); |
|||
} catch (e) { |
|||
this.logger.info('Pub/Sub subscription already exists.'); |
|||
} |
|||
|
|||
this.subscriptions.push(topic); |
|||
} |
|||
} |
|||
|
|||
async destroy(): Promise<void> { |
|||
this.logger.info('Stopping Pub/Sub resources...'); |
|||
if (this.pubSubClient) { |
|||
this.logger.info('Stopping Pub/Sub client...'); |
|||
try { |
|||
const _pubSubClient = this.pubSubClient; |
|||
// @ts-ignore
|
|||
delete this.pubSubClient; |
|||
await _pubSubClient.close(); |
|||
this.logger.info('Pub/Sub client stopped.'); |
|||
} catch (e) { |
|||
this.logger.info('Pub/Sub client stop error.'); |
|||
} |
|||
} |
|||
this.logger.info('Pub/Sub resources stopped.'); |
|||
} |
|||
} |
|||
|
|||