|
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.'); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||