From bd06dae340b5e3167e4b2100742ebef10dc6710e Mon Sep 17 00:00:00 2001 From: xiwa Date: Wed, 9 Mar 2022 18:45:37 +0800 Subject: [PATCH 01/16] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=8D=8F=E8=AE=AE?= =?UTF-8?q?=E7=BD=91=E5=85=B3=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 1 + protocol/pom.xml | 43 ++++++++++++ .../cc/iotkit/protocol/DeregisterInfo.java | 17 +++++ .../cc/iotkit/protocol/DeviceBehaviour.java | 46 +++++++++++++ .../cc/iotkit/protocol/DeviceMessage.java | 24 +++++++ .../java/cc/iotkit/protocol/OtaMessage.java | 30 +++++++++ .../java/cc/iotkit/protocol/RegisterInfo.java | 18 +++++ .../main/java/cc/iotkit/protocol/Result.java | 9 +++ .../config/ProtocolConfiguration.java | 24 +++++++ .../protocol/impl/DeviceBehaviourImpl.java | 66 +++++++++++++++++++ protocol/src/main/resources/spring.factories | 1 + .../src/main/resources/spring.factories | 2 +- 12 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 protocol/pom.xml create mode 100644 protocol/src/main/java/cc/iotkit/protocol/DeregisterInfo.java create mode 100644 protocol/src/main/java/cc/iotkit/protocol/DeviceBehaviour.java create mode 100644 protocol/src/main/java/cc/iotkit/protocol/DeviceMessage.java create mode 100644 protocol/src/main/java/cc/iotkit/protocol/OtaMessage.java create mode 100644 protocol/src/main/java/cc/iotkit/protocol/RegisterInfo.java create mode 100644 protocol/src/main/java/cc/iotkit/protocol/Result.java create mode 100644 protocol/src/main/java/cc/iotkit/protocol/config/ProtocolConfiguration.java create mode 100644 protocol/src/main/java/cc/iotkit/protocol/impl/DeviceBehaviourImpl.java create mode 100755 protocol/src/main/resources/spring.factories diff --git a/pom.xml b/pom.xml index f653e772..e2ed65a0 100755 --- a/pom.xml +++ b/pom.xml @@ -11,6 +11,7 @@ manager dao tppa-server + protocol org.springframework.boot diff --git a/protocol/pom.xml b/protocol/pom.xml new file mode 100644 index 00000000..30293718 --- /dev/null +++ b/protocol/pom.xml @@ -0,0 +1,43 @@ + + + + iotkit-parent + cc.iotkit + 0.0.1-SNAPSHOT + + 4.0.0 + + protocol + + + 8 + 8 + + + + + + org.springframework + spring-context-support + + + + org.springframework.boot + spring-boot + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + org.projectlombok + lombok + + + + + \ No newline at end of file diff --git a/protocol/src/main/java/cc/iotkit/protocol/DeregisterInfo.java b/protocol/src/main/java/cc/iotkit/protocol/DeregisterInfo.java new file mode 100644 index 00000000..4e8f03ed --- /dev/null +++ b/protocol/src/main/java/cc/iotkit/protocol/DeregisterInfo.java @@ -0,0 +1,17 @@ +package cc.iotkit.protocol; + +import lombok.Data; + + +/** + * 注销信息 + */ +@Data +public class DeregisterInfo { + + private String productKey; + + private String deviceName; + + private boolean cascade; +} diff --git a/protocol/src/main/java/cc/iotkit/protocol/DeviceBehaviour.java b/protocol/src/main/java/cc/iotkit/protocol/DeviceBehaviour.java new file mode 100644 index 00000000..78a996bb --- /dev/null +++ b/protocol/src/main/java/cc/iotkit/protocol/DeviceBehaviour.java @@ -0,0 +1,46 @@ +package cc.iotkit.protocol; + +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +/** + * 设备行为接口 + */ +public interface DeviceBehaviour { + + /** + * 设备注册 + */ + @PostMapping("/register") + Result register(@RequestBody RegisterInfo info); + + /** + * 设备注销 + */ + @PostMapping("/deregister") + Result deregister(@RequestBody DeregisterInfo info); + + /** + * 设备上线 + */ + @PostMapping("/online") + void online(String productKey, String deviceName); + + /** + * 设备离线 + */ + @PostMapping("/offline") + void offline(String productKey, String deviceName); + + /** + * 设备消息上报 + */ + void messageReport(DeviceMessage msg); + + /** + * OTA消息上报 + */ + void otaProgressReport(OtaMessage msg); + + +} diff --git a/protocol/src/main/java/cc/iotkit/protocol/DeviceMessage.java b/protocol/src/main/java/cc/iotkit/protocol/DeviceMessage.java new file mode 100644 index 00000000..9a8daca5 --- /dev/null +++ b/protocol/src/main/java/cc/iotkit/protocol/DeviceMessage.java @@ -0,0 +1,24 @@ +package cc.iotkit.protocol; + +import lombok.Data; + +/** + * 设备消息 + */ +@Data +public class DeviceMessage { + + public static final String TYPE_REQUEST = "request"; + public static final String TYPE_ACK = "ack"; + + private String productKey; + + private String deviceName; + + private String type; + + private String mid; + + private String content; + +} diff --git a/protocol/src/main/java/cc/iotkit/protocol/OtaMessage.java b/protocol/src/main/java/cc/iotkit/protocol/OtaMessage.java new file mode 100644 index 00000000..65ad1be2 --- /dev/null +++ b/protocol/src/main/java/cc/iotkit/protocol/OtaMessage.java @@ -0,0 +1,30 @@ +package cc.iotkit.protocol; + +import lombok.Data; + +/** + * OTA消息 + */ +@Data +public class OtaMessage { + + private final String TYPE_PROGRESS="progress"; + private final String TYPE_RESULT="result"; + + private final String PROGRESS_DOWNLOADING="downloading"; + private final String PROGRESS_DOWNLOADED="downloaded"; + private final String PROGRESS_UPGRADING="upgrading"; + private final String PROGRESS_UPGRADED="upgraded"; + + private String productKey; + + private String deviceName; + + private String type; + + private String jobId; + + private String progress; + + private String result; +} diff --git a/protocol/src/main/java/cc/iotkit/protocol/RegisterInfo.java b/protocol/src/main/java/cc/iotkit/protocol/RegisterInfo.java new file mode 100644 index 00000000..b4f324fa --- /dev/null +++ b/protocol/src/main/java/cc/iotkit/protocol/RegisterInfo.java @@ -0,0 +1,18 @@ +package cc.iotkit.protocol; + +import lombok.Data; + +import java.util.Map; + +/** + * 注册信息 + */ +@Data +public class RegisterInfo { + + private String productKey; + + private String deviceName; + + private Map label; +} diff --git a/protocol/src/main/java/cc/iotkit/protocol/Result.java b/protocol/src/main/java/cc/iotkit/protocol/Result.java new file mode 100644 index 00000000..a9566b2a --- /dev/null +++ b/protocol/src/main/java/cc/iotkit/protocol/Result.java @@ -0,0 +1,9 @@ +package cc.iotkit.protocol; + +import lombok.Data; + +@Data +public class Result { + + +} diff --git a/protocol/src/main/java/cc/iotkit/protocol/config/ProtocolConfiguration.java b/protocol/src/main/java/cc/iotkit/protocol/config/ProtocolConfiguration.java new file mode 100644 index 00000000..c385afb6 --- /dev/null +++ b/protocol/src/main/java/cc/iotkit/protocol/config/ProtocolConfiguration.java @@ -0,0 +1,24 @@ +package cc.iotkit.protocol.config; + +import cc.iotkit.protocol.DeviceBehaviour; +import cc.iotkit.protocol.impl.DeviceBehaviourImpl; +import feign.Client; +import feign.Contract; +import feign.codec.Decoder; +import feign.codec.Encoder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ProtocolConfiguration { + + @Value("${protocol.server}") + private String protocolServer; + + @Bean + public DeviceBehaviour getDeviceBehaviour(Decoder decoder, Encoder encoder, Client client, Contract contract) { + return new DeviceBehaviourImpl(protocolServer, decoder, encoder, client, contract); + } + +} diff --git a/protocol/src/main/java/cc/iotkit/protocol/impl/DeviceBehaviourImpl.java b/protocol/src/main/java/cc/iotkit/protocol/impl/DeviceBehaviourImpl.java new file mode 100644 index 00000000..91722fba --- /dev/null +++ b/protocol/src/main/java/cc/iotkit/protocol/impl/DeviceBehaviourImpl.java @@ -0,0 +1,66 @@ +package cc.iotkit.protocol.impl; + +import cc.iotkit.protocol.*; +import feign.Client; +import feign.Contract; +import feign.Feign; +import feign.codec.Decoder; +import feign.codec.Encoder; +import org.springframework.cloud.openfeign.FeignClientsConfiguration; +import org.springframework.context.annotation.Import; + +@Import(FeignClientsConfiguration.class) +public class DeviceBehaviourImpl implements DeviceBehaviour { + + private final Feign.Builder builder; + + private final String protocolServer; + + private DeviceBehaviour target; + + public DeviceBehaviourImpl(String protocolServer, Decoder decoder, + Encoder encoder, Client client, Contract contract) { + this.protocolServer = protocolServer; + this.builder = Feign.builder() + .client(client) + .encoder(encoder) + .decoder(decoder) + .contract(contract); + } + + private DeviceBehaviour behaviour() { + if (target == null) { + target = this.builder.target(DeviceBehaviour.class, protocolServer); + } + return target; + } + + @Override + public Result register(RegisterInfo info) { + return behaviour().register(info); + } + + @Override + public Result deregister(DeregisterInfo info) { + return behaviour().deregister(info); + } + + @Override + public void online(String productKey, String deviceName) { + behaviour().online(productKey, deviceName); + } + + @Override + public void offline(String productKey, String deviceName) { + behaviour().offline(productKey, deviceName); + } + + @Override + public void messageReport(DeviceMessage msg) { + + } + + @Override + public void otaProgressReport(OtaMessage msg) { + } +} diff --git a/protocol/src/main/resources/spring.factories b/protocol/src/main/resources/spring.factories new file mode 100755 index 00000000..77623732 --- /dev/null +++ b/protocol/src/main/resources/spring.factories @@ -0,0 +1 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration= cc.iotkit.protocol.config.ProtocolConfiguration \ No newline at end of file diff --git a/rule-engine/src/main/resources/spring.factories b/rule-engine/src/main/resources/spring.factories index 557a2014..f80a18ec 100755 --- a/rule-engine/src/main/resources/spring.factories +++ b/rule-engine/src/main/resources/spring.factories @@ -1 +1 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.danbay.iot.commons.logger.config.LoggerAutoConfiguration \ No newline at end of file +org.springframework.boot.autoconfigure.EnableAutoConfiguration=cc.iotkit.ruleengine.config.RuleConfiguration From 2b0c9aab997df541f919d7ba19b587f668cd1de5 Mon Sep 17 00:00:00 2001 From: xiwa Date: Thu, 10 Mar 2022 19:06:35 +0800 Subject: [PATCH 02/16] =?UTF-8?q?=E5=8D=8F=E8=AE=AE=E7=BD=91=E5=85=B3?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 15 ++- .../gateway-api}/pom.xml | 22 ++--- .../cc/iotkit/protocol/DeregisterInfo.java | 0 .../cc/iotkit/protocol/DeviceBehaviour.java | 40 ++++++++ .../cc/iotkit/protocol/DeviceMessage.java | 0 .../java/cc/iotkit/protocol/OtaMessage.java | 0 .../java/cc/iotkit/protocol/RegisterInfo.java | 0 .../main/java/cc/iotkit/protocol/Result.java | 16 +++ .../client/DeviceBehaviourClient.java | 98 +++++++++++++++++++ protocol-gateway/gateway-server/pom.xml | 33 +++++++ .../java/cc/iotkit/protocol/server/Test1.java | 66 +++++++++++++ .../src/main/resources/spring.factories | 2 +- protocol-gateway/pom.xml | 24 +++++ .../cc/iotkit/protocol/DeviceBehaviour.java | 46 --------- .../main/java/cc/iotkit/protocol/Result.java | 9 -- .../config/ProtocolConfiguration.java | 24 ----- .../protocol/impl/DeviceBehaviourImpl.java | 66 ------------- 17 files changed, 303 insertions(+), 158 deletions(-) rename {protocol => protocol-gateway/gateway-api}/pom.xml (66%) rename {protocol => protocol-gateway/gateway-api}/src/main/java/cc/iotkit/protocol/DeregisterInfo.java (100%) create mode 100644 protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/DeviceBehaviour.java rename {protocol => protocol-gateway/gateway-api}/src/main/java/cc/iotkit/protocol/DeviceMessage.java (100%) rename {protocol => protocol-gateway/gateway-api}/src/main/java/cc/iotkit/protocol/OtaMessage.java (100%) rename {protocol => protocol-gateway/gateway-api}/src/main/java/cc/iotkit/protocol/RegisterInfo.java (100%) create mode 100644 protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/Result.java create mode 100644 protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/client/DeviceBehaviourClient.java create mode 100644 protocol-gateway/gateway-server/pom.xml create mode 100644 protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/Test1.java rename {protocol => protocol-gateway/gateway-server}/src/main/resources/spring.factories (57%) create mode 100644 protocol-gateway/pom.xml delete mode 100644 protocol/src/main/java/cc/iotkit/protocol/DeviceBehaviour.java delete mode 100644 protocol/src/main/java/cc/iotkit/protocol/Result.java delete mode 100644 protocol/src/main/java/cc/iotkit/protocol/config/ProtocolConfiguration.java delete mode 100644 protocol/src/main/java/cc/iotkit/protocol/impl/DeviceBehaviourImpl.java diff --git a/pom.xml b/pom.xml index e2ed65a0..8893c748 100755 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ manager dao tppa-server - protocol + protocol-gateway org.springframework.boot @@ -149,6 +149,13 @@ 1.2.2 + + + org.apache.pulsar + pulsar-client + 2.9.1 + + cc.iotkit model @@ -179,6 +186,12 @@ ${project.version} + + cc.iotkit + gateway-api + ${project.version} + + diff --git a/protocol/pom.xml b/protocol-gateway/gateway-api/pom.xml similarity index 66% rename from protocol/pom.xml rename to protocol-gateway/gateway-api/pom.xml index 30293718..296fb9bd 100644 --- a/protocol/pom.xml +++ b/protocol-gateway/gateway-api/pom.xml @@ -3,13 +3,13 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - iotkit-parent + protocol-gateway cc.iotkit 0.0.1-SNAPSHOT 4.0.0 - protocol + gateway-api 8 @@ -19,18 +19,13 @@ - org.springframework - spring-context-support + com.squareup.okhttp3 + okhttp - org.springframework.boot - spring-boot - - - - org.springframework.cloud - spring-cloud-starter-openfeign + org.apache.pulsar + pulsar-client @@ -38,6 +33,11 @@ lombok + + cc.iotkit + common + + \ No newline at end of file diff --git a/protocol/src/main/java/cc/iotkit/protocol/DeregisterInfo.java b/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/DeregisterInfo.java similarity index 100% rename from protocol/src/main/java/cc/iotkit/protocol/DeregisterInfo.java rename to protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/DeregisterInfo.java diff --git a/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/DeviceBehaviour.java b/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/DeviceBehaviour.java new file mode 100644 index 00000000..81126e37 --- /dev/null +++ b/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/DeviceBehaviour.java @@ -0,0 +1,40 @@ +package cc.iotkit.protocol; + + +/** + * 设备行为接口 + */ +public interface DeviceBehaviour { + + /** + * 设备注册 + */ + Result register(RegisterInfo info); + + /** + * 设备注销 + */ + Result deregister(DeregisterInfo info); + + /** + * 设备上线 + */ + Result online(String productKey, String deviceName); + + /** + * 设备离线 + */ + Result offline(String productKey, String deviceName); + + /** + * 设备消息上报 + */ + void messageReport(DeviceMessage msg); + + /** + * OTA消息上报 + */ + void otaProgressReport(OtaMessage msg); + + +} diff --git a/protocol/src/main/java/cc/iotkit/protocol/DeviceMessage.java b/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/DeviceMessage.java similarity index 100% rename from protocol/src/main/java/cc/iotkit/protocol/DeviceMessage.java rename to protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/DeviceMessage.java diff --git a/protocol/src/main/java/cc/iotkit/protocol/OtaMessage.java b/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/OtaMessage.java similarity index 100% rename from protocol/src/main/java/cc/iotkit/protocol/OtaMessage.java rename to protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/OtaMessage.java diff --git a/protocol/src/main/java/cc/iotkit/protocol/RegisterInfo.java b/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/RegisterInfo.java similarity index 100% rename from protocol/src/main/java/cc/iotkit/protocol/RegisterInfo.java rename to protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/RegisterInfo.java diff --git a/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/Result.java b/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/Result.java new file mode 100644 index 00000000..10479669 --- /dev/null +++ b/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/Result.java @@ -0,0 +1,16 @@ +package cc.iotkit.protocol; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Result { + + private boolean success; + + private String content; + +} diff --git a/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/client/DeviceBehaviourClient.java b/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/client/DeviceBehaviourClient.java new file mode 100644 index 00000000..dc5a5d3f --- /dev/null +++ b/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/client/DeviceBehaviourClient.java @@ -0,0 +1,98 @@ +package cc.iotkit.protocol.client; + +import cc.iotkit.common.utils.JsonUtil; +import cc.iotkit.protocol.*; +import okhttp3.*; +import org.apache.pulsar.client.api.PulsarClient; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class DeviceBehaviourClient implements DeviceBehaviour { + + private final String server; + + private final OkHttpClient httpClient; + + private PulsarClient client; + + public DeviceBehaviourClient(String server) { + this.server = server.replaceAll("/$", ""); + httpClient = new OkHttpClient.Builder() + .connectTimeout(10, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) + .build(); + } + + public Request buildRequest(String url, String method, String type, Map data) { + Request.Builder requestBuilder = new Request.Builder() + .url(url); + + RequestBody requestBody; + if ("json".equals(type)) { + requestBody = RequestBody.create(MediaType.get("application/json; charset=utf-8"), + JsonUtil.toJsonString(data)); + } else { + FormBody.Builder builder = new FormBody.Builder(); + data.forEach((key, val) -> builder.add(key, val.toString())); + requestBody = builder.build(); + } + requestBuilder.method(method.toUpperCase(), requestBody); + return requestBuilder.build(); + } + + private Result invoke(String path, T data) { + Request request = buildRequest(server + path, "post", "form", + (data instanceof Map) ? (Map) data : + JsonUtil.parse(JsonUtil.toJsonString(data), Map.class)); + + Call call = httpClient.newCall(request); + try { + Response response = call.execute(); + if (!response.isSuccessful() || response.body() == null) { + return new Result(false, "接口调用失败"); + } + String content = response.body().string(); + return JsonUtil.parse(content, Result.class); + } catch (Throwable e) { + return new Result(false, "接口调用失败:" + e.getMessage()); + } + } + + + @Override + public Result register(RegisterInfo info) { + return invoke("/register", info); + } + + @Override + public Result deregister(DeregisterInfo info) { + return invoke("/deregister", info); + } + + @Override + public Result online(String productKey, String deviceName) { + Map data = new HashMap<>(); + data.put("productKey", productKey); + data.put("deviceName", deviceName); + return invoke("/online", data); + } + + @Override + public Result offline(String productKey, String deviceName) { + Map data = new HashMap<>(); + data.put("productKey", productKey); + data.put("deviceName", deviceName); + return invoke("/offline", data); + } + + @Override + public void messageReport(DeviceMessage msg) { + + } + + @Override + public void otaProgressReport(OtaMessage msg) { + } +} diff --git a/protocol-gateway/gateway-server/pom.xml b/protocol-gateway/gateway-server/pom.xml new file mode 100644 index 00000000..46cf5cf6 --- /dev/null +++ b/protocol-gateway/gateway-server/pom.xml @@ -0,0 +1,33 @@ + + + + protocol-gateway + cc.iotkit + 0.0.1-SNAPSHOT + + 4.0.0 + + gateway-server + + + 8 + 8 + + + + + + org.apache.pulsar + pulsar-client + + + + cc.iotkit + gateway-api + + + + + \ No newline at end of file diff --git a/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/Test1.java b/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/Test1.java new file mode 100644 index 00000000..9bb4eb98 --- /dev/null +++ b/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/Test1.java @@ -0,0 +1,66 @@ +package cc.iotkit.protocol.server; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.pulsar.client.api.*; +import org.apache.pulsar.client.impl.schema.JSONSchema; +import org.apache.pulsar.common.functions.FunctionConfig; + +import java.util.regex.Pattern; + +public class Test1 { + + public static void main(String[] args) throws PulsarClientException, InterruptedException { +// FunctionConfig functionConfig = new FunctionConfig(); +// functionConfig.setTenant("tenant"); +// functionConfig.setNamespace("namespace"); +// functionConfig.setName("functionName"); +// functionConfig.setRuntime(FunctionConfig.Runtime.JAVA); +// functionConfig.setParallelism(1); +// functionConfig.setClassName("org.apache.pulsar.functions.api.examples.ExclamationFunction"); +// functionConfig.setProcessingGuarantees(FunctionConfig.ProcessingGuarantees.ATLEAST_ONCE); +// functionConfig.setTopicsPattern(sourceTopicPattern); +// functionConfig.setSubName(subscriptionName); +// functionConfig.setAutoAck(true); +// functionConfig.setOutput(sinkTopic); +// admin.functions().createFunction(functionConfig, fileName); + + + PulsarClient client = PulsarClient.builder() + .serviceUrl("pulsar://localhost:6650") + .build(); + + client.newConsumer(JSONSchema.of(Msg.class)) + .topicsPattern(Pattern.compile("persistent://public/default/test.*")) + .subscriptionName("test1") + .consumerName("test1") + .messageListener((MessageListener) (consumer, msg) -> { + Msg m = msg.getValue(); + System.out.printf("=====received:%s,%s%n", m.getIdentifier(), m.getDeviceId()); + }).subscribe(); + + Producer producer = client.newProducer(JSONSchema.of(Msg.class)) + .topic("test1234") + .create(); + + for (int i = 0; i < 1000; i++) { + producer.send(new Msg("test", "xxxx11222333" + i)); + Thread.sleep(500); + } + + + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class Msg { + + private String identifier; + + private String deviceId; + + } + +} diff --git a/protocol/src/main/resources/spring.factories b/protocol-gateway/gateway-server/src/main/resources/spring.factories similarity index 57% rename from protocol/src/main/resources/spring.factories rename to protocol-gateway/gateway-server/src/main/resources/spring.factories index 77623732..ae3134d9 100755 --- a/protocol/src/main/resources/spring.factories +++ b/protocol-gateway/gateway-server/src/main/resources/spring.factories @@ -1 +1 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration= cc.iotkit.protocol.config.ProtocolConfiguration \ No newline at end of file +org.springframework.boot.autoconfigure.EnableAutoConfiguration= cc.iotkit.protocol.config.GatewayConfig \ No newline at end of file diff --git a/protocol-gateway/pom.xml b/protocol-gateway/pom.xml new file mode 100644 index 00000000..e2ef3a51 --- /dev/null +++ b/protocol-gateway/pom.xml @@ -0,0 +1,24 @@ + + + + iotkit-parent + cc.iotkit + 0.0.1-SNAPSHOT + + 4.0.0 + + protocol-gateway + pom + + gateway-api + gateway-server + + + + 8 + 8 + + + \ No newline at end of file diff --git a/protocol/src/main/java/cc/iotkit/protocol/DeviceBehaviour.java b/protocol/src/main/java/cc/iotkit/protocol/DeviceBehaviour.java deleted file mode 100644 index 78a996bb..00000000 --- a/protocol/src/main/java/cc/iotkit/protocol/DeviceBehaviour.java +++ /dev/null @@ -1,46 +0,0 @@ -package cc.iotkit.protocol; - -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; - -/** - * 设备行为接口 - */ -public interface DeviceBehaviour { - - /** - * 设备注册 - */ - @PostMapping("/register") - Result register(@RequestBody RegisterInfo info); - - /** - * 设备注销 - */ - @PostMapping("/deregister") - Result deregister(@RequestBody DeregisterInfo info); - - /** - * 设备上线 - */ - @PostMapping("/online") - void online(String productKey, String deviceName); - - /** - * 设备离线 - */ - @PostMapping("/offline") - void offline(String productKey, String deviceName); - - /** - * 设备消息上报 - */ - void messageReport(DeviceMessage msg); - - /** - * OTA消息上报 - */ - void otaProgressReport(OtaMessage msg); - - -} diff --git a/protocol/src/main/java/cc/iotkit/protocol/Result.java b/protocol/src/main/java/cc/iotkit/protocol/Result.java deleted file mode 100644 index a9566b2a..00000000 --- a/protocol/src/main/java/cc/iotkit/protocol/Result.java +++ /dev/null @@ -1,9 +0,0 @@ -package cc.iotkit.protocol; - -import lombok.Data; - -@Data -public class Result { - - -} diff --git a/protocol/src/main/java/cc/iotkit/protocol/config/ProtocolConfiguration.java b/protocol/src/main/java/cc/iotkit/protocol/config/ProtocolConfiguration.java deleted file mode 100644 index c385afb6..00000000 --- a/protocol/src/main/java/cc/iotkit/protocol/config/ProtocolConfiguration.java +++ /dev/null @@ -1,24 +0,0 @@ -package cc.iotkit.protocol.config; - -import cc.iotkit.protocol.DeviceBehaviour; -import cc.iotkit.protocol.impl.DeviceBehaviourImpl; -import feign.Client; -import feign.Contract; -import feign.codec.Decoder; -import feign.codec.Encoder; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class ProtocolConfiguration { - - @Value("${protocol.server}") - private String protocolServer; - - @Bean - public DeviceBehaviour getDeviceBehaviour(Decoder decoder, Encoder encoder, Client client, Contract contract) { - return new DeviceBehaviourImpl(protocolServer, decoder, encoder, client, contract); - } - -} diff --git a/protocol/src/main/java/cc/iotkit/protocol/impl/DeviceBehaviourImpl.java b/protocol/src/main/java/cc/iotkit/protocol/impl/DeviceBehaviourImpl.java deleted file mode 100644 index 91722fba..00000000 --- a/protocol/src/main/java/cc/iotkit/protocol/impl/DeviceBehaviourImpl.java +++ /dev/null @@ -1,66 +0,0 @@ -package cc.iotkit.protocol.impl; - -import cc.iotkit.protocol.*; -import feign.Client; -import feign.Contract; -import feign.Feign; -import feign.codec.Decoder; -import feign.codec.Encoder; -import org.springframework.cloud.openfeign.FeignClientsConfiguration; -import org.springframework.context.annotation.Import; - -@Import(FeignClientsConfiguration.class) -public class DeviceBehaviourImpl implements DeviceBehaviour { - - private final Feign.Builder builder; - - private final String protocolServer; - - private DeviceBehaviour target; - - public DeviceBehaviourImpl(String protocolServer, Decoder decoder, - Encoder encoder, Client client, Contract contract) { - this.protocolServer = protocolServer; - this.builder = Feign.builder() - .client(client) - .encoder(encoder) - .decoder(decoder) - .contract(contract); - } - - private DeviceBehaviour behaviour() { - if (target == null) { - target = this.builder.target(DeviceBehaviour.class, protocolServer); - } - return target; - } - - @Override - public Result register(RegisterInfo info) { - return behaviour().register(info); - } - - @Override - public Result deregister(DeregisterInfo info) { - return behaviour().deregister(info); - } - - @Override - public void online(String productKey, String deviceName) { - behaviour().online(productKey, deviceName); - } - - @Override - public void offline(String productKey, String deviceName) { - behaviour().offline(productKey, deviceName); - } - - @Override - public void messageReport(DeviceMessage msg) { - - } - - @Override - public void otaProgressReport(OtaMessage msg) { - } -} From 456f7a471b1ee9a4c130c4c86d522b07ce907ec5 Mon Sep 17 00:00:00 2001 From: xiwa Date: Sat, 19 Mar 2022 22:28:28 +0800 Subject: [PATCH 03/16] =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cc/iotkit/common/Constants.java | 10 + communication/component/pom.xml | 16 + communication/mqtt-component/pom.xml | 21 + communication/pom.xml | 15 + .../main/java/cc/iotkit/dao/DeviceCache.java | 39 + .../main/java/cc/iotkit/dao/DeviceDao.java | 62 - .../java/cc/iotkit/dao/DeviceRepository.java | 5 + .../{ProductDao.java => ProductCache.java} | 12 +- .../iotkit/dao/ProtocolGatewayRepository.java | 11 + .../main/java/cc/iotkit/dao/SceneLogDao.java | 22 - .../cc/iotkit/dao/SceneLogRepository.java | 3 + .../main/java/cc/iotkit/dao/TaskLogDao.java | 22 - .../java/cc/iotkit/dao/TaskLogRepository.java | 3 + .../dao/ThingModelMessageRepository.java | 9 + .../cc/iotkit/dao/ThingModelRepository.java | 3 + .../cc/iotkit/dao/UserInfoRepository.java | 7 + .../config/ElasticsearchConfiguration.java | 13 + .../iotkit/dao/config/RepositoryConfig.java | 31 +- device-server/mqtt-auth/pom.xml | 95 -- .../java/cc/iotkit/mqttauth/dao/DaoTool.java | 53 - .../cc/iotkit/mqttauth/dao/DeviceDao.java | 53 - .../cc/iotkit/mqttauth/dao/ProductDao.java | 23 - .../mqttauth/service/DeviceService.java | 82 -- .../cc/iotkit/mqttauth/service/MqttAuth.java | 12 - .../iotkit/mqttauth/service/SysMqttAuth.java | 42 - .../iotkit/mqttauth/service/WxMqttAuth.java | 18 - .../src/main/resources/application-dev.yml | 5 - .../src/main/resources/application.yml | 5 - .../mqtt-auth/src/test/java/SupperUser.java | 23 - .../mqtt-auth/src/test/java/SysMqttAuth.java | 13 - .../mqtt-server/log/error.2022-01-10.0.gz | Bin 2618 -> 0 bytes .../mqtt-server/log/error.2022-01-11.0.gz | Bin 14966 -> 0 bytes .../mqtt-server/log/error.2022-01-12.0.gz | Bin 845 -> 0 bytes .../mqtt-server/log/error.2022-01-13.0.gz | Bin 2177 -> 0 bytes .../mqtt-server/log/info.2022-01-10.0.gz | Bin 14191 -> 0 bytes .../mqtt-server/log/info.2022-01-11.0.gz | Bin 102288 -> 0 bytes .../mqtt-server/log/info.2022-01-12.0.gz | Bin 79144 -> 0 bytes .../mqtt-server/log/info.2022-01-13.0.gz | Bin 36536 -> 0 bytes device-server/mqtt-server/pom.xml | 58 +- .../cc/iotkit/server/config/CacheConfig.java | 43 - .../server/config/GlobalExceptionHandler.java | 42 - .../cc/iotkit/server/config/MqttConfig.java | 147 --- .../java/cc/iotkit/server/dao/BaseDao.java | 55 - .../java/cc/iotkit/server/dao/DaoTool.java | 53 - .../java/cc/iotkit/server/dao/DeviceDao.java | 62 - .../server/dao/DeviceEventRepository.java | 13 - .../iotkit/server/dao/DeviceRepository.java | 9 - .../server/dao/ThingModelRepository.java | 9 - .../server/handler/DisconnectedHandler.java | 63 - .../server/handler/EventReportHandler.java | 49 - .../server/handler/MqttConsumerHandler.java | 162 --- .../cc/iotkit/server/handler/MqttHandler.java | 14 - .../server/handler/PropertyPostHandler.java | 62 - .../server/handler/PropertyReplyHandler.java | 47 - .../server/handler/RegisterHandler.java | 36 - .../server/handler/ServiceReplyHandler.java | 49 - .../cc/iotkit/server/mqtt}/Application.java | 2 +- .../server/mqtt/config/AutobeanConfig.java | 19 + .../mqtt/controller/DeviceController.java | 47 + .../mqtt}/controller/MqttAuthController.java | 39 +- .../mqtt/handler/DisconnectedHandler.java | 41 + .../cc/iotkit/server/mqtt}/model/EmqAcl.java | 2 +- .../server/mqtt}/model/EmqAuthInfo.java | 2 +- .../cc/iotkit/server/mqtt/model/Request.java | 17 + .../cc/iotkit/server/mqtt/model/Response.java | 25 + .../mqtt/service/DeviceAuthService.java} | 40 +- .../server/mqtt/service/MqttManager.java | 256 +++++ .../iotkit/server/service/DeviceService.java | 219 ---- .../cc/iotkit/server/service/IMqttSender.java | 40 - .../server/service/ThingModelService.java | 60 - device-server/pom.xml | 1 - log/error.2022-03-14.0.gz | Bin 0 -> 4041 bytes log/error.2022-03-15.0.gz | Bin 0 -> 20999 bytes log/error.2022-03-16.0.gz | Bin 0 -> 7595 bytes log/error.2022-03-16.01767963764004696.tmp | 900 +++++++++++++++ log/error.2022-03-17.0.gz | Bin 0 -> 20450 bytes log/error.2022-03-18.0.gz | Bin 0 -> 14387 bytes log/info.2022-03-14.0.gz | Bin 0 -> 36764 bytes log/info.2022-03-15.0.gz | Bin 0 -> 43469 bytes log/info.2022-03-16.0.gz | Bin 0 -> 44742 bytes log/info.2022-03-16.01767904371465962.tmp | 1019 +++++++++++++++++ log/info.2022-03-17.0.gz | Bin 0 -> 107296 bytes log/info.2022-03-18.0.gz | Bin 0 -> 93228 bytes manager/pom.xml | 5 + .../java/cc/iotkit/manager/Application.java | 2 +- .../config/KeycloakSecurityConfig.java | 3 +- .../manager/controller/DeviceController.java | 8 +- .../manager/controller/ProductController.java | 9 +- .../controller/ProtocolController.java | 126 ++ .../controller/RuleEngineController.java | 14 +- .../manager/controller/SpaceController.java | 8 +- .../controller/UserInfoController.java | 43 +- .../aligenie/AligenieProductController.java | 10 +- .../controller/api/MessageController.java | 17 +- .../controller/api/SpaceController.java | 8 +- .../manager/service/AligenieService.java | 6 +- .../manager/service/DataOwnerService.java | 20 +- .../iotkit/manager/service/DeviceService.java | 4 +- .../manager/service/KeycloakAdminService.java | 18 +- .../manager/service/PulsarAdminService.java | 51 + .../manager/service/SpaceDeviceService.java | 12 +- .../src/main/resources/application-dev.yml | 10 +- manager/src/main/resources/application.yml | 10 +- model/pom.xml | 7 + .../cc/iotkit/model/device/DeviceInfo.java | 10 +- .../device/message/ThingModelMessage.java | 61 + .../java/cc/iotkit/model/product/Product.java | 2 - .../model/protocol/ProtocolGateway.java | 33 + pom.xml | 42 +- .../java/cc/iotkit/protocol/RegisterInfo.java | 18 - .../{gateway-api => gateway-client}/pom.xml | 7 +- .../cc/iotkit/protocol/DeregisterInfo.java | 0 .../cc/iotkit/protocol/DeviceBehaviour.java | 6 - .../cc/iotkit/protocol/DeviceGateway.java | 23 + .../cc/iotkit/protocol/DeviceMessage.java | 11 +- .../main/java/cc/iotkit/protocol/OtaInfo.java | 7 + .../java/cc/iotkit/protocol/OtaMessage.java | 0 .../java/cc/iotkit/protocol/RegisterInfo.java | 49 + .../main/java/cc/iotkit/protocol/Result.java | 0 .../client/DeviceBehaviourClient.java | 79 +- protocol-gateway/gateway-server/.DS_Store | Bin 0 -> 6148 bytes .../gateway-server/fun-test/.DS_Store | Bin 0 -> 8196 bytes .../gateway-server/fun-test/pom.xml | 71 ++ .../main/java/cc/iotkit/fun/TestFunction.java | 50 + protocol-gateway/gateway-server/pom.xml | 34 +- .../java/cc/iotkit/protocol}/Application.java | 6 +- .../java/cc/iotkit/protocol/server/Test1.java | 56 +- .../java/cc/iotkit/protocol/server/Test3.java | 40 + .../iotkit/protocol/server/TestFunction.java | 88 ++ .../protocol/server/config/ServerConfig.java | 17 + .../controller/DeviceBehaviourController.java | 60 + .../service/DeviceBehaviourService.java | 142 +++ .../server/service/DeviceMessageConsumer.java | 75 ++ .../server/service/GatewayService.java | 98 ++ .../src/main/resources/logback-spring.xml | 6 + protocol-gateway/pom.xml | 4 +- .../protocol-function}/.DS_Store | Bin protocol-gateway/protocol-function/pom.xml | 70 ++ .../protocol/function/DeviceMessage.java | 25 + .../function/MessageDistributionFunction.java | 52 + .../protocol/function/ThingModelMessage.java | 62 + .../function/UplinkTranslateFunction.java | 51 + .../action/DeviceActionExecutor.java | 4 +- .../ruleengine/filter/DeviceCondition.java | 6 +- .../ruleengine/filter/DeviceFilter.java | 6 +- .../iotkit/ruleengine/scene/SceneManager.java | 6 +- .../iotkit/ruleengine/task/TaskManager.java | 6 +- 147 files changed, 4153 insertions(+), 2051 deletions(-) create mode 100644 communication/component/pom.xml create mode 100644 communication/mqtt-component/pom.xml create mode 100644 communication/pom.xml create mode 100755 dao/src/main/java/cc/iotkit/dao/DeviceCache.java delete mode 100755 dao/src/main/java/cc/iotkit/dao/DeviceDao.java rename dao/src/main/java/cc/iotkit/dao/{ProductDao.java => ProductCache.java} (55%) create mode 100755 dao/src/main/java/cc/iotkit/dao/ProtocolGatewayRepository.java delete mode 100755 dao/src/main/java/cc/iotkit/dao/SceneLogDao.java delete mode 100755 dao/src/main/java/cc/iotkit/dao/TaskLogDao.java create mode 100644 dao/src/main/java/cc/iotkit/dao/ThingModelMessageRepository.java create mode 100644 dao/src/main/java/cc/iotkit/dao/config/ElasticsearchConfiguration.java delete mode 100755 device-server/mqtt-auth/pom.xml delete mode 100755 device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/dao/DaoTool.java delete mode 100755 device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/dao/DeviceDao.java delete mode 100755 device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/dao/ProductDao.java delete mode 100755 device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/DeviceService.java delete mode 100755 device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/MqttAuth.java delete mode 100755 device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/SysMqttAuth.java delete mode 100755 device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/WxMqttAuth.java delete mode 100755 device-server/mqtt-auth/src/main/resources/application-dev.yml delete mode 100755 device-server/mqtt-auth/src/main/resources/application.yml delete mode 100755 device-server/mqtt-auth/src/test/java/SupperUser.java delete mode 100755 device-server/mqtt-auth/src/test/java/SysMqttAuth.java delete mode 100755 device-server/mqtt-server/log/error.2022-01-10.0.gz delete mode 100755 device-server/mqtt-server/log/error.2022-01-11.0.gz delete mode 100755 device-server/mqtt-server/log/error.2022-01-12.0.gz delete mode 100755 device-server/mqtt-server/log/error.2022-01-13.0.gz delete mode 100755 device-server/mqtt-server/log/info.2022-01-10.0.gz delete mode 100755 device-server/mqtt-server/log/info.2022-01-11.0.gz delete mode 100755 device-server/mqtt-server/log/info.2022-01-12.0.gz delete mode 100755 device-server/mqtt-server/log/info.2022-01-13.0.gz delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/config/CacheConfig.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/config/GlobalExceptionHandler.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/config/MqttConfig.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/BaseDao.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DaoTool.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DeviceDao.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DeviceEventRepository.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DeviceRepository.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/ThingModelRepository.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/DisconnectedHandler.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/EventReportHandler.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/MqttConsumerHandler.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/MqttHandler.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/PropertyPostHandler.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/PropertyReplyHandler.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/RegisterHandler.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/ServiceReplyHandler.java rename device-server/{mqtt-auth/src/main/java/cc/iotkit/mqttauth => mqtt-server/src/main/java/cc/iotkit/server/mqtt}/Application.java (90%) create mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/config/AutobeanConfig.java create mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/controller/DeviceController.java rename device-server/{mqtt-auth/src/main/java/cc/iotkit/mqttauth => mqtt-server/src/main/java/cc/iotkit/server/mqtt}/controller/MqttAuthController.java (58%) create mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/handler/DisconnectedHandler.java rename device-server/{mqtt-auth/src/main/java/cc/iotkit/mqttauth => mqtt-server/src/main/java/cc/iotkit/server/mqtt}/model/EmqAcl.java (85%) rename device-server/{mqtt-auth/src/main/java/cc/iotkit/mqttauth => mqtt-server/src/main/java/cc/iotkit/server/mqtt}/model/EmqAuthInfo.java (84%) create mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/Request.java create mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/Response.java rename device-server/{mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/DeviceMqttAuth.java => mqtt-server/src/main/java/cc/iotkit/server/mqtt/service/DeviceAuthService.java} (67%) create mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/service/MqttManager.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/service/DeviceService.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/service/IMqttSender.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/service/ThingModelService.java create mode 100755 log/error.2022-03-14.0.gz create mode 100644 log/error.2022-03-15.0.gz create mode 100644 log/error.2022-03-16.0.gz create mode 100644 log/error.2022-03-16.01767963764004696.tmp create mode 100644 log/error.2022-03-17.0.gz create mode 100644 log/error.2022-03-18.0.gz create mode 100755 log/info.2022-03-14.0.gz create mode 100644 log/info.2022-03-15.0.gz create mode 100644 log/info.2022-03-16.0.gz create mode 100644 log/info.2022-03-16.01767904371465962.tmp create mode 100644 log/info.2022-03-17.0.gz create mode 100644 log/info.2022-03-18.0.gz create mode 100644 manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java create mode 100644 manager/src/main/java/cc/iotkit/manager/service/PulsarAdminService.java create mode 100755 model/src/main/java/cc/iotkit/model/device/message/ThingModelMessage.java create mode 100644 model/src/main/java/cc/iotkit/model/protocol/ProtocolGateway.java delete mode 100644 protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/RegisterInfo.java rename protocol-gateway/{gateway-api => gateway-client}/pom.xml (85%) mode change 100644 => 100755 rename protocol-gateway/{gateway-api => gateway-client}/src/main/java/cc/iotkit/protocol/DeregisterInfo.java (100%) mode change 100644 => 100755 rename protocol-gateway/{gateway-api => gateway-client}/src/main/java/cc/iotkit/protocol/DeviceBehaviour.java (86%) mode change 100644 => 100755 create mode 100755 protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeviceGateway.java rename protocol-gateway/{gateway-api => gateway-client}/src/main/java/cc/iotkit/protocol/DeviceMessage.java (62%) mode change 100644 => 100755 create mode 100755 protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/OtaInfo.java rename protocol-gateway/{gateway-api => gateway-client}/src/main/java/cc/iotkit/protocol/OtaMessage.java (100%) mode change 100644 => 100755 create mode 100755 protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/RegisterInfo.java rename protocol-gateway/{gateway-api => gateway-client}/src/main/java/cc/iotkit/protocol/Result.java (100%) mode change 100644 => 100755 rename protocol-gateway/{gateway-api => gateway-client}/src/main/java/cc/iotkit/protocol/client/DeviceBehaviourClient.java (53%) mode change 100644 => 100755 create mode 100755 protocol-gateway/gateway-server/.DS_Store create mode 100755 protocol-gateway/gateway-server/fun-test/.DS_Store create mode 100755 protocol-gateway/gateway-server/fun-test/pom.xml create mode 100755 protocol-gateway/gateway-server/fun-test/src/main/java/cc/iotkit/fun/TestFunction.java mode change 100644 => 100755 protocol-gateway/gateway-server/pom.xml rename {device-server/mqtt-server/src/main/java/cc/iotkit/server => protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol}/Application.java (64%) mode change 100644 => 100755 protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/Test1.java create mode 100755 protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/Test3.java create mode 100644 protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/TestFunction.java create mode 100755 protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/config/ServerConfig.java create mode 100755 protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/controller/DeviceBehaviourController.java create mode 100755 protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/service/DeviceBehaviourService.java create mode 100755 protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/service/DeviceMessageConsumer.java create mode 100644 protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/service/GatewayService.java rename {device-server/mqtt-auth => protocol-gateway/gateway-server}/src/main/resources/logback-spring.xml (93%) mode change 100644 => 100755 protocol-gateway/pom.xml rename {device-server/mqtt-auth => protocol-gateway/protocol-function}/.DS_Store (100%) mode change 100755 => 100644 create mode 100755 protocol-gateway/protocol-function/pom.xml create mode 100755 protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/DeviceMessage.java create mode 100755 protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/MessageDistributionFunction.java create mode 100755 protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/ThingModelMessage.java create mode 100755 protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/UplinkTranslateFunction.java diff --git a/common/src/main/java/cc/iotkit/common/Constants.java b/common/src/main/java/cc/iotkit/common/Constants.java index f4a1987d..860ab832 100755 --- a/common/src/main/java/cc/iotkit/common/Constants.java +++ b/common/src/main/java/cc/iotkit/common/Constants.java @@ -58,4 +58,14 @@ public interface Constants { */ String PWD_SYSTEM_USER="s123456"; + /** + * 设备原始上报消息的topic + */ + String DEVICE_RAW_MESSAGE_TOPIC="device_raw"; + + /** + * 设备物模型消息的topic + */ + String THING_MODEL_MESSAGE_TOPIC="device_thing"; + } diff --git a/communication/component/pom.xml b/communication/component/pom.xml new file mode 100644 index 00000000..02396859 --- /dev/null +++ b/communication/component/pom.xml @@ -0,0 +1,16 @@ + + + + iotkit-parent + cc.iotkit + 0.0.1-SNAPSHOT + ../../pom.xml + + 4.0.0 + + component + + + \ No newline at end of file diff --git a/communication/mqtt-component/pom.xml b/communication/mqtt-component/pom.xml new file mode 100644 index 00000000..565bb85a --- /dev/null +++ b/communication/mqtt-component/pom.xml @@ -0,0 +1,21 @@ + + + + iotkit-parent + cc.iotkit + 0.0.1-SNAPSHOT + ../../pom.xml + + 4.0.0 + + mqtt-component + + + + + + + + \ No newline at end of file diff --git a/communication/pom.xml b/communication/pom.xml new file mode 100644 index 00000000..a25ff27e --- /dev/null +++ b/communication/pom.xml @@ -0,0 +1,15 @@ + + + + iotkit-parent + cc.iotkit + 0.0.1-SNAPSHOT + + 4.0.0 + + communication + + + \ No newline at end of file diff --git a/dao/src/main/java/cc/iotkit/dao/DeviceCache.java b/dao/src/main/java/cc/iotkit/dao/DeviceCache.java new file mode 100755 index 00000000..524487e4 --- /dev/null +++ b/dao/src/main/java/cc/iotkit/dao/DeviceCache.java @@ -0,0 +1,39 @@ +package cc.iotkit.dao; + +import cc.iotkit.common.Constants; +import cc.iotkit.model.device.DeviceInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.stereotype.Repository; + +import static org.springframework.data.mongodb.core.query.Criteria.where; +import static org.springframework.data.mongodb.core.query.Query.query; + +@Repository +public class DeviceCache extends BaseDao { + + @Autowired + private DeviceRepository deviceRepository; + + @Autowired + public DeviceCache(MongoTemplate mongoTemplate) { + super(mongoTemplate, DeviceInfo.class); + } + + @Cacheable(value = Constants.DEVICE_CACHE, key = "#pk+'_'+#dn") + public DeviceInfo findByProductKeyAndDeviceName(String pk, String dn) { + return deviceRepository.findByProductKeyAndDeviceName(pk, dn); + } + + @Cacheable(value = Constants.DEVICE_CACHE, key = "#deviceId") + public DeviceInfo findByDeviceId(String deviceId) { + return deviceRepository.findByDeviceId(deviceId); + } + + @Cacheable(value = Constants.DEVICE_CACHE, key = "#deviceId") + public DeviceInfo get(String deviceId) { + return deviceRepository.findById(deviceId).orElse(new DeviceInfo()); + } +} diff --git a/dao/src/main/java/cc/iotkit/dao/DeviceDao.java b/dao/src/main/java/cc/iotkit/dao/DeviceDao.java deleted file mode 100755 index 1d34e2b9..00000000 --- a/dao/src/main/java/cc/iotkit/dao/DeviceDao.java +++ /dev/null @@ -1,62 +0,0 @@ -package cc.iotkit.dao; - -import cc.iotkit.common.Constants; -import cc.iotkit.model.device.DeviceInfo; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.query.Query; -import org.springframework.stereotype.Repository; - -import static org.springframework.data.mongodb.core.query.Criteria.where; -import static org.springframework.data.mongodb.core.query.Query.query; - -@Repository -public class DeviceDao extends BaseDao { - - @Autowired - private DeviceRepository deviceRepository; - - @Autowired - public DeviceDao(MongoTemplate mongoTemplate) { - super(mongoTemplate, DeviceInfo.class); - } - - public void addDevice(DeviceInfo device) { - device.setCreateAt(System.currentTimeMillis()); - mongoTemplate.insert(device); - } - - public void updateDevice(DeviceInfo device) { - if (device.getDeviceId() == null) { - return; - } - mongoTemplate.updateFirst(query(where("deviceId").is(device.getDeviceId())), - DaoTool.update(device), DeviceInfo.class); - } - - public void updateDeviceByPkAndDn(DeviceInfo device) { - if (device.getProductKey() == null || device.getDeviceName() == null) { - return; - } - mongoTemplate.updateFirst(query(where("productKey").is(device.getProductKey()). - and("deviceName").is(device.getDeviceName())), - DaoTool.update(device), DeviceInfo.class); - } - - @Cacheable(value = "deviceInfoCache", key = "#pk+'_'+#dn") - public DeviceInfo getByPkAndDn(String pk, String dn) { - Query query = query(where("productKey").is(pk).and("deviceName").is(dn)); - return mongoTemplate.findOne(query, DeviceInfo.class); - } - - public DeviceInfo getByDeviceId(String deviceId) { - Query query = query(where("deviceId").is(deviceId)); - return mongoTemplate.findOne(query, DeviceInfo.class); - } - - @Cacheable(value = Constants.DEVICE_CACHE, key = "#deviceId") - public DeviceInfo get(String deviceId) { - return deviceRepository.findById(deviceId).orElse(new DeviceInfo()); - } -} diff --git a/dao/src/main/java/cc/iotkit/dao/DeviceRepository.java b/dao/src/main/java/cc/iotkit/dao/DeviceRepository.java index d19b3170..334e0f3d 100755 --- a/dao/src/main/java/cc/iotkit/dao/DeviceRepository.java +++ b/dao/src/main/java/cc/iotkit/dao/DeviceRepository.java @@ -6,4 +6,9 @@ import org.springframework.stereotype.Repository; @Repository public interface DeviceRepository extends MongoRepository { + + DeviceInfo findByProductKeyAndDeviceName(String productKey, String deviceName); + + DeviceInfo findByDeviceId(String deviceId); + } diff --git a/dao/src/main/java/cc/iotkit/dao/ProductDao.java b/dao/src/main/java/cc/iotkit/dao/ProductCache.java similarity index 55% rename from dao/src/main/java/cc/iotkit/dao/ProductDao.java rename to dao/src/main/java/cc/iotkit/dao/ProductCache.java index 18bd810f..db78ee01 100755 --- a/dao/src/main/java/cc/iotkit/dao/ProductDao.java +++ b/dao/src/main/java/cc/iotkit/dao/ProductCache.java @@ -5,25 +5,23 @@ import cc.iotkit.model.product.Product; import cc.iotkit.model.product.ThingModel; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.Cacheable; -import org.springframework.data.domain.Example; import org.springframework.stereotype.Repository; @Repository -public class ProductDao { +public class ProductCache { @Autowired private ProductRepository productRepository; @Autowired private ThingModelRepository thingModelRepository; - @Cacheable(value = Constants.PRODUCT_CACHE, key = "'getProductById'+#pk", unless = "#result == null") - public Product get(String pk) { + @Cacheable(value = Constants.PRODUCT_CACHE, key = "'pk'+#pk", unless = "#result == null") + public Product findById(String pk) { return productRepository.findById(pk).orElse(new Product()); } - @Cacheable(value = Constants.THING_MODEL_CACHE, key = "'getThingModel'+#pk", unless = "#result == null") + @Cacheable(value = Constants.THING_MODEL_CACHE, key = "'pk'+#pk", unless = "#result == null") public ThingModel getThingModel(String pk) { - return thingModelRepository.findOne(Example.of(ThingModel.builder() - .productKey(pk).build())).orElse(new ThingModel()); + return thingModelRepository.findByProductKey(pk); } } diff --git a/dao/src/main/java/cc/iotkit/dao/ProtocolGatewayRepository.java b/dao/src/main/java/cc/iotkit/dao/ProtocolGatewayRepository.java new file mode 100755 index 00000000..d304423c --- /dev/null +++ b/dao/src/main/java/cc/iotkit/dao/ProtocolGatewayRepository.java @@ -0,0 +1,11 @@ +package cc.iotkit.dao; + +import cc.iotkit.model.protocol.ProtocolGateway; +import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ProtocolGatewayRepository extends MongoRepository { + + +} diff --git a/dao/src/main/java/cc/iotkit/dao/SceneLogDao.java b/dao/src/main/java/cc/iotkit/dao/SceneLogDao.java deleted file mode 100755 index c53d722b..00000000 --- a/dao/src/main/java/cc/iotkit/dao/SceneLogDao.java +++ /dev/null @@ -1,22 +0,0 @@ -package cc.iotkit.dao; - -import cc.iotkit.model.rule.SceneLog; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.query.Query; -import org.springframework.stereotype.Repository; - -import static org.springframework.data.mongodb.core.query.Criteria.where; - -@Repository -public class SceneLogDao extends BaseDao { - - @Autowired - public SceneLogDao(MongoTemplate mongoTemplate) { - super(mongoTemplate, SceneLog.class); - } - - public void deleteLogs(String sceneId) { - this.mongoTemplate.remove(Query.query(where("sceneId").is(sceneId)), SceneLog.class); - } -} diff --git a/dao/src/main/java/cc/iotkit/dao/SceneLogRepository.java b/dao/src/main/java/cc/iotkit/dao/SceneLogRepository.java index eee529e8..30216d15 100755 --- a/dao/src/main/java/cc/iotkit/dao/SceneLogRepository.java +++ b/dao/src/main/java/cc/iotkit/dao/SceneLogRepository.java @@ -6,4 +6,7 @@ import org.springframework.stereotype.Repository; @Repository public interface SceneLogRepository extends MongoRepository { + + void deleteBySceneId(String sceneId); + } diff --git a/dao/src/main/java/cc/iotkit/dao/TaskLogDao.java b/dao/src/main/java/cc/iotkit/dao/TaskLogDao.java deleted file mode 100755 index ee780dbc..00000000 --- a/dao/src/main/java/cc/iotkit/dao/TaskLogDao.java +++ /dev/null @@ -1,22 +0,0 @@ -package cc.iotkit.dao; - -import cc.iotkit.model.rule.TaskLog; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.query.Query; -import org.springframework.stereotype.Repository; - -import static org.springframework.data.mongodb.core.query.Criteria.where; - -@Repository -public class TaskLogDao extends BaseDao { - - @Autowired - public TaskLogDao(MongoTemplate mongoTemplate) { - super(mongoTemplate, TaskLog.class); - } - - public void deleteLogs(String taskId) { - this.mongoTemplate.remove(Query.query(where("taskId").is(taskId)), TaskLog.class); - } -} diff --git a/dao/src/main/java/cc/iotkit/dao/TaskLogRepository.java b/dao/src/main/java/cc/iotkit/dao/TaskLogRepository.java index c197c13f..ddbbdc71 100755 --- a/dao/src/main/java/cc/iotkit/dao/TaskLogRepository.java +++ b/dao/src/main/java/cc/iotkit/dao/TaskLogRepository.java @@ -6,4 +6,7 @@ import org.springframework.stereotype.Repository; @Repository public interface TaskLogRepository extends MongoRepository { + + void deleteByTaskId(String taskId); + } diff --git a/dao/src/main/java/cc/iotkit/dao/ThingModelMessageRepository.java b/dao/src/main/java/cc/iotkit/dao/ThingModelMessageRepository.java new file mode 100644 index 00000000..c865fbdd --- /dev/null +++ b/dao/src/main/java/cc/iotkit/dao/ThingModelMessageRepository.java @@ -0,0 +1,9 @@ +package cc.iotkit.dao; + +import cc.iotkit.model.device.message.ThingModelMessage; +import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ThingModelMessageRepository extends ElasticsearchRepository { +} diff --git a/dao/src/main/java/cc/iotkit/dao/ThingModelRepository.java b/dao/src/main/java/cc/iotkit/dao/ThingModelRepository.java index 16612cb5..880adb47 100755 --- a/dao/src/main/java/cc/iotkit/dao/ThingModelRepository.java +++ b/dao/src/main/java/cc/iotkit/dao/ThingModelRepository.java @@ -6,4 +6,7 @@ import org.springframework.stereotype.Repository; @Repository public interface ThingModelRepository extends MongoRepository { + + ThingModel findByProductKey(String productKey); + } diff --git a/dao/src/main/java/cc/iotkit/dao/UserInfoRepository.java b/dao/src/main/java/cc/iotkit/dao/UserInfoRepository.java index e58f2c5c..afeece71 100755 --- a/dao/src/main/java/cc/iotkit/dao/UserInfoRepository.java +++ b/dao/src/main/java/cc/iotkit/dao/UserInfoRepository.java @@ -4,6 +4,13 @@ import cc.iotkit.model.UserInfo; import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface UserInfoRepository extends MongoRepository { + + List findByType(int type); + + List findByTypeAndOwnerId(int type, String ownerId); + } diff --git a/dao/src/main/java/cc/iotkit/dao/config/ElasticsearchConfiguration.java b/dao/src/main/java/cc/iotkit/dao/config/ElasticsearchConfiguration.java new file mode 100644 index 00000000..0e5850e4 --- /dev/null +++ b/dao/src/main/java/cc/iotkit/dao/config/ElasticsearchConfiguration.java @@ -0,0 +1,13 @@ +package cc.iotkit.dao.config; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; +import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories; + +@Configuration +@EnableElasticsearchRepositories(basePackages = "cc.iotkit.dao", includeFilters = +@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = ElasticsearchRepository.class)) +public class ElasticsearchConfiguration { +} diff --git a/dao/src/main/java/cc/iotkit/dao/config/RepositoryConfig.java b/dao/src/main/java/cc/iotkit/dao/config/RepositoryConfig.java index 9d5dc24e..c7a636be 100755 --- a/dao/src/main/java/cc/iotkit/dao/config/RepositoryConfig.java +++ b/dao/src/main/java/cc/iotkit/dao/config/RepositoryConfig.java @@ -1,19 +1,24 @@ package cc.iotkit.dao.config; import org.springframework.beans.factory.BeanFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; +import org.springframework.context.annotation.*; import org.springframework.data.convert.CustomConversions; import org.springframework.data.mongodb.MongoDatabaseFactory; -import org.springframework.data.mongodb.core.convert.DbRefResolver; -import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver; -import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper; -import org.springframework.data.mongodb.core.convert.MappingMongoConverter; +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.convert.*; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; +import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; +import java.util.Collections; + @Configuration -@EnableMongoRepositories(basePackages = "cc.iotkit.dao") +@Import(value = MongoAutoConfiguration.class) +@EnableMongoRepositories(basePackages = "cc.iotkit.dao", includeFilters = @ComponentScan.Filter( + type = FilterType.ASSIGNABLE_TYPE, value = MongoRepository.class)) public class RepositoryConfig { @Bean @@ -28,4 +33,16 @@ public class RepositoryConfig { return mappingMongoConverter; } + @Bean + @ConditionalOnMissingBean({MongoOperations.class}) + MongoTemplate mongoTemplate(MongoDatabaseFactory factory, MongoConverter converter) { + return new MongoTemplate(factory, converter); + } + + @Bean + @Primary + MongoCustomConversions mongoCustomConversions() { + return new MongoCustomConversions(Collections.emptyList()); + } + } diff --git a/device-server/mqtt-auth/pom.xml b/device-server/mqtt-auth/pom.xml deleted file mode 100755 index 4b942648..00000000 --- a/device-server/mqtt-auth/pom.xml +++ /dev/null @@ -1,95 +0,0 @@ - - - - device-server - cc.iotkit - 0.0.1-SNAPSHOT - - 4.0.0 - - mqtt-auth - - - - org.springframework.boot - spring-boot-starter-data-mongodb - - - - org.springframework.boot - spring-boot-starter-web - - - - com.github.ben-manes.caffeine - caffeine - - - - org.projectlombok - lombok - true - - - - org.apache.commons - commons-lang3 - - - - commons-codec - commons-codec - - - - commons-beanutils - commons-beanutils - - - - org.bouncycastle - bcprov-jdk15on - - - - joda-time - joda-time - - - - cc.iotkit - common - - - - cc.iotkit - model - - - junit - junit - test - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - - - - - - \ No newline at end of file diff --git a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/dao/DaoTool.java b/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/dao/DaoTool.java deleted file mode 100755 index 74f8b660..00000000 --- a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/dao/DaoTool.java +++ /dev/null @@ -1,53 +0,0 @@ -package cc.iotkit.mqttauth.dao; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.SneakyThrows; -import org.apache.commons.beanutils.BeanMap; -import org.springframework.data.mongodb.core.query.Update; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -public class DaoTool { - - public static void update(Update update, List props) { - for (Prop pro : props) { - update.set(pro.getName(), pro.getValue()); - } - } - - public static List getProp(String key, Object value) { - List props = new ArrayList<>(); - if (value instanceof Map) { - Set> entrySet = ((Map) value).entrySet(); - for (Map.Entry entry : entrySet) { - props.addAll(getProp(key + "." + entry.getKey(), entry.getValue())); - } - } else if (value != null && !(value instanceof Class)) { - props.add(new Prop(key, value)); - } - return props; - } - - @SneakyThrows - public static Update update(T obj) { - Map pros = new BeanMap(obj); - Update update = new Update(); - for (Map.Entry entry : pros.entrySet()) { - update(update, DaoTool.getProp(entry.getKey().toString(), entry.getValue())); - } - return update; - } - - @Data - @AllArgsConstructor - @NoArgsConstructor - static class Prop { - private String name; - private Object value; - } -} diff --git a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/dao/DeviceDao.java b/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/dao/DeviceDao.java deleted file mode 100755 index c3fbfd5e..00000000 --- a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/dao/DeviceDao.java +++ /dev/null @@ -1,53 +0,0 @@ -package cc.iotkit.mqttauth.dao; - -import cc.iotkit.model.device.DeviceInfo; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.query.Query; -import org.springframework.stereotype.Repository; - -import javax.annotation.Resource; - -import static org.springframework.data.mongodb.core.query.Criteria.where; -import static org.springframework.data.mongodb.core.query.Query.query; - -@Repository -public class DeviceDao { - - @Resource - private MongoTemplate mongoTemplate; - - public void addDevice(DeviceInfo device) { - device.setId(device.getDeviceId()); - device.setCreateAt(System.currentTimeMillis()); - mongoTemplate.insert(device); - } - - public void updateDevice(DeviceInfo device) { - if (device.getDeviceId() == null) { - return; - } - mongoTemplate.updateFirst(query(where("deviceId").is(device.getDeviceId())), - DaoTool.update(device), DeviceInfo.class); - } - - public void updateDeviceByPkAndDn(DeviceInfo device) { - if (device.getProductKey() == null || device.getDeviceName() == null) { - return; - } - mongoTemplate.updateFirst(query(where("productKey").is(device.getProductKey()). - and("deviceName").is(device.getDeviceName())), - DaoTool.update(device), DeviceInfo.class); - } - - @Cacheable(value = "deviceInfoCache", key = "#pk+'_'+#dn") - public DeviceInfo getByPkAndDn(String pk, String dn) { - Query query = query(where("productKey").is(pk).and("deviceName").is(dn)); - return mongoTemplate.findOne(query, DeviceInfo.class); - } - - public DeviceInfo getByDeviceId(String deviceId) { - Query query = query(where("deviceId").is(deviceId)); - return mongoTemplate.findOne(query, DeviceInfo.class); - } -} diff --git a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/dao/ProductDao.java b/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/dao/ProductDao.java deleted file mode 100755 index f1782be6..00000000 --- a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/dao/ProductDao.java +++ /dev/null @@ -1,23 +0,0 @@ -package cc.iotkit.mqttauth.dao; - -import cc.iotkit.model.product.Product; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.query.Query; -import org.springframework.stereotype.Repository; - -import javax.annotation.Resource; - -import static org.springframework.data.mongodb.core.query.Criteria.where; -import static org.springframework.data.mongodb.core.query.Query.query; - -@Repository -public class ProductDao { - - @Resource - private MongoTemplate mongoTemplate; - - public Product getProduct(String pk) { - Query query = query(where("code").is(pk)); - return mongoTemplate.findOne(query, Product.class); - } -} diff --git a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/DeviceService.java b/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/DeviceService.java deleted file mode 100755 index fdb563ef..00000000 --- a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/DeviceService.java +++ /dev/null @@ -1,82 +0,0 @@ -package cc.iotkit.mqttauth.service; - -import cc.iotkit.common.exception.BizException; -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.model.product.Product; -import cc.iotkit.mqttauth.dao.DeviceDao; -import cc.iotkit.mqttauth.dao.ProductDao; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.RandomUtils; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -@Slf4j -@Service -public class DeviceService { - - @Autowired - private DeviceDao deviceDao; - @Autowired - private ProductDao productDao; - - public DeviceInfo register(DeviceInfo device) { - - String pk = device.getProductKey(); - Product product = productDao.getProduct(pk); - if (product == null) { - throw new BizException("Product does not exist"); - } - String uid = product.getUid(); - - DeviceInfo deviceInfo = deviceDao.getByPkAndDn(pk, device.getDeviceName()); - if (deviceInfo != null) { - device.setDeviceId(deviceInfo.getDeviceId()); - device.setUid(uid); - deviceDao.updateDevice(device); - log.info("device register update:{}", JsonUtil.toJsonString(device)); - return device; - } - - device.setUid(uid); - device.setDeviceId(newDeviceId(device.getDeviceName())); - deviceDao.addDevice(device); - log.info("device registered:{}", JsonUtil.toJsonString(device)); - return device; - } - - public DeviceInfo getByPkAndDn(String pk, String dn) { - return deviceDao.getByPkAndDn(pk, dn); - } - - public void online(String pk, String dn) { - DeviceInfo device = new DeviceInfo(); - device.setProductKey(pk); - device.setDeviceName(dn); - - device.getState().setOnline(true); - device.getState().setOnlineTime(System.currentTimeMillis()); - deviceDao.updateDeviceByPkAndDn(device); - } - - /** - * 1-13位 时间戳 - * 14-29位 deviceNae,去除非字母和数字,不足16位补0,超过16位的mac取后16位,共16位 - * 30-31位 mac长度,共2位 - * 32位 随机一个0-f字符 - */ - public static String newDeviceId(String deviceNae) { - int maxDnLen = 16; - String dn = deviceNae.replaceAll("[^0-9A-Za-z]", ""); - if (dn.length() > maxDnLen) { - dn = dn.substring(dn.length() - maxDnLen); - } else { - dn = (dn + "00000000000000000000").substring(0, maxDnLen); - } - String len = StringUtils.leftPad(deviceNae.length() + "", 2, '0'); - String rnd = Integer.toHexString(RandomUtils.nextInt(0, 16)); - return (System.currentTimeMillis() + "0" + dn + len + rnd).toLowerCase(); - } - -} diff --git a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/MqttAuth.java b/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/MqttAuth.java deleted file mode 100755 index 708dddca..00000000 --- a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/MqttAuth.java +++ /dev/null @@ -1,12 +0,0 @@ -package cc.iotkit.mqttauth.service; - -import cc.iotkit.mqttauth.model.EmqAcl; -import cc.iotkit.mqttauth.model.EmqAuthInfo; - -public interface MqttAuth { - - void auth(EmqAuthInfo auth); - - void acl(EmqAcl acl); - -} diff --git a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/SysMqttAuth.java b/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/SysMqttAuth.java deleted file mode 100755 index 450eadf8..00000000 --- a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/SysMqttAuth.java +++ /dev/null @@ -1,42 +0,0 @@ -package cc.iotkit.mqttauth.service; - -import cc.iotkit.common.Constants; -import cc.iotkit.common.utils.CodecUtil; -import cc.iotkit.mqttauth.model.EmqAcl; -import cc.iotkit.mqttauth.model.EmqAuthInfo; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Component; - -@Slf4j -@Component("SysMqttAuth") -public class SysMqttAuth implements MqttAuth { - @Override - public void auth(EmqAuthInfo auth) { - try { - //password= aes(sy_username,ACCOUNT_SECRET) - String uid = auth.getUsername(); - String codes = CodecUtil.aesDecryptHex(auth.getPassword(), Constants.ACCOUNT_SECRET); - if (StringUtils.isBlank(codes)) { - throw new RuntimeException("mqtt auth failed,pwd error."); - } - //解出来的用户id与username是否一致 - String[] parts = codes.split("_"); - if (parts.length < 2 || !uid.equals(parts[1])) { - throw new RuntimeException("mqtt auth failed,pw validate error."); - } - } catch (Throwable e) { - log.error("sys user mqtt failed.", e); - throw new RuntimeException("mqtt auth failed:" + e.getMessage()); - } - } - - @Override - public void acl(EmqAcl acl) { - //平台用户可订阅以所有设备 -// String topic = acl.getTopic(); -// if (!topic.startsWith("/app/")) { -// throw new RuntimeException("acl failed."); -// } - } -} diff --git a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/WxMqttAuth.java b/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/WxMqttAuth.java deleted file mode 100755 index 63e5ecad..00000000 --- a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/WxMqttAuth.java +++ /dev/null @@ -1,18 +0,0 @@ -package cc.iotkit.mqttauth.service; - -import cc.iotkit.mqttauth.model.EmqAcl; -import cc.iotkit.mqttauth.model.EmqAuthInfo; -import org.springframework.stereotype.Component; - -@Component("WxMqttAuth") -public class WxMqttAuth implements MqttAuth { - @Override - public void auth(EmqAuthInfo auth) { - - } - - @Override - public void acl(EmqAcl acl) { - - } -} diff --git a/device-server/mqtt-auth/src/main/resources/application-dev.yml b/device-server/mqtt-auth/src/main/resources/application-dev.yml deleted file mode 100755 index c7d60c0a..00000000 --- a/device-server/mqtt-auth/src/main/resources/application-dev.yml +++ /dev/null @@ -1,5 +0,0 @@ -spring: - data: - mongodb: - uri: mongodb://填写mongodb地址/admin - database: iotkit diff --git a/device-server/mqtt-auth/src/main/resources/application.yml b/device-server/mqtt-auth/src/main/resources/application.yml deleted file mode 100755 index c7d60c0a..00000000 --- a/device-server/mqtt-auth/src/main/resources/application.yml +++ /dev/null @@ -1,5 +0,0 @@ -spring: - data: - mongodb: - uri: mongodb://填写mongodb地址/admin - database: iotkit diff --git a/device-server/mqtt-auth/src/test/java/SupperUser.java b/device-server/mqtt-auth/src/test/java/SupperUser.java deleted file mode 100755 index 83f16234..00000000 --- a/device-server/mqtt-auth/src/test/java/SupperUser.java +++ /dev/null @@ -1,23 +0,0 @@ -import cc.iotkit.common.Constants; -import cc.iotkit.common.utils.CodecUtil; -import cc.iotkit.mqttauth.controller.MqttAuthController; -import org.junit.Assert; -import org.junit.Test; - -public class SupperUser { - - @Test - public void createSuperuser() throws Exception { - //mqtt生成超级用户,作为mqtt-server连接mqtt的clientId - String clientId = "mqtt-server-producer-dev"; - System.out.println("clientId:su_" + CodecUtil.aesEncrypt("admin_" + clientId, Constants.MQTT_SECRET)); - } - - @Test - public void isSupperUser() { - String clientId = "su_344A6E61654F567A30536E59646A306659664A75625A374D35484756776D457977374653684B306B414E513D"; -// String clientId = "su_tng1t408QrZDEoM7CxiDueP++4FmXIxS7x35YbpuNf8="; - MqttAuthController authController = new MqttAuthController(); - Assert.assertTrue(authController.isSupperUser(clientId)); - } -} diff --git a/device-server/mqtt-auth/src/test/java/SysMqttAuth.java b/device-server/mqtt-auth/src/test/java/SysMqttAuth.java deleted file mode 100755 index 9f0a73fe..00000000 --- a/device-server/mqtt-auth/src/test/java/SysMqttAuth.java +++ /dev/null @@ -1,13 +0,0 @@ -import cc.iotkit.common.Constants; -import cc.iotkit.common.utils.CodecUtil; -import org.junit.Test; - -public class SysMqttAuth { - - @Test - public void createSyPwd() throws Exception { - System.out.println(CodecUtil.aesEncrypt("sy_gateway_dev", Constants.ACCOUNT_SECRET)); - System.out.println(CodecUtil.aesDecryptHex("4B6272544E59324C596562686173494A696E764E69673D3D", Constants.ACCOUNT_SECRET)); - } - -} diff --git a/device-server/mqtt-server/log/error.2022-01-10.0.gz b/device-server/mqtt-server/log/error.2022-01-10.0.gz deleted file mode 100755 index 33d7414a164003d9a0415fbe033ec2d62015b6aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2618 zcmV-A3dQvwiwFP!000000NtHSuUtnF$Jh8%oCOP`j7$Bh)7=MoVcCunDJI7Df`Lm{x9{D1`(ERtv8K6p?OOBQH=o}3Pc44?;rZbk zKM2>q*KDANb6CLHkM{c~7MAOMzg^E)aC5cn*ZceX`Mz(4A6>IMe1E@wr1wsRZ*ISH z>-Of3zxi}|>(JkQ?KSuM*|%OQyK5dS&-#;QbJ#cYU9;Xa^TmGoWVwHL);#X}^Bb$> zlm5CznHLLk<|Mp@3aC2Cn+$fJ?N5a|QNnKSLodK?P4yIendsq{F*V6T`@>1jcsuh0|DUi+{fN><=G2|LI?z{r>%n zpa1FNw}1ZlcR#uK<@*x`e zs<~ihD%e+6y;by_)3bnKrrY*ERc{@AVD+rUIJAius{U9yqMM;opRH$AS7NSu^r@9< zZ9k1lChnge_9vTn)^BV!kG~M=?Wc?WJV7?^oGw>=b6D>V4|j|0@*z=Nxw6?lf_|}D zp6{qJQDLwcTFbGuhq3tdA~7w((^6+-D6(JCKC=*1U*`|Gn`e|YhaA3y)sAD{i=gID)f z(g+tD!OkW@PME{%~C6M%$TRUrMpn{qO5JJr(MB}tKt6fK(~ z#)E3TC`A&IuR$6|5$7ScHBEFnMG}(dY9o%^8K9M*AVo5gcWjE72;NHSH5uvB2cBLL z@=;nNOOb?RYntsCieRTTxT>jcDn$wsvMFK>7$r-Qgrqf_B4{99Mi^x%f)-R&C5@p- zOS2t>AZf12NRg}8w6xp-FUmv9NS;p-q(y|2)kYFhmD4zeBAy7q+L{WPN|B7@xY~%P z6*;603Q3A2BwMri97hohptPi3laU;kB7uHFP?BcfjKt=lh0aF6C`%DSYBkroCU#1J zMM;WeB(}LGc1DA4YnI;ADUy)b;v=zh8X|HnBC>f&?vPQPqIHcEWIwGrJZ1g9kRnvA5GMpiO!TF_C_&^90$Mnzl;G1Sa8 z(v8jvT}&DPlArS;ZAq zjOn6+k#u+Bh{P3DjQQ?_q?KMq;yRf}=ADO7<+F}xUQmTtmG4dn^5P3pRe)lIN+RR{k>iXM06@Zd@O-ACnUt|5S6(Gt(%Se`M9Pw!@K-3A}g2d*< z`_6^RP1flY8IZVoO-Ne-QA<*!AaTXeLfRgPl1}&*B+b`GFuBZ%l8Yy(S}ZWf3Iv7-VJb z$w)1mA|`DG)Lj9aN|6Dnm{yi%!4(hxzS+=YD&scQ;@jwkC6Ek)Rc5npdfKwxOH)evx?fm%1CTp zd`v-2E9pI01&K=$R4J%gmoRrCMUF^(iWmb*(y1##a)uV4;*g?Z8thT0GtXYqQT>8c zm6K!~MNGQ6D9A-BNRjCZa(Y)ZLd$jI=xAP2r#0!!b6b_wcv>W`#V46J9-O3w#Sw`q zh(+d8pi|P3mV(4}3>$5VDz;U*C8km&BXM0`z?6anP}1w$3R2ZOf5%Y-HCQERd!Qh3 zr9{CY^R*J?p=G41lUU;@V##HelmMh4aa}JZ^Jpt0M$;*hkg9GEjG@So`C5BH0g8ge zbyOdR%-5pQ_!Xq8N*YIzl=)gxl9+gN0yiiGrDPFHoJW-3K8 z64wi4aL9aZTS;DgMq=|vLV7Q!39=MPNNjB+ruTAcNhwhZ5?7KKGH=LbmUJ+^AXT~1 c<0#@hsH%6#Pp3#inl8@zZ$5Wmhs>P-04f;!8~^|S diff --git a/device-server/mqtt-server/log/error.2022-01-11.0.gz b/device-server/mqtt-server/log/error.2022-01-11.0.gz deleted file mode 100755 index 365f8c7c53917a522d9b87eee6b79ebf561adc49..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14966 zcmX|Ic|276`!7+K7G*0-mNCSn?6lak42>)^Q;`ypEwoVftjR=XEM>?(4Kt{V+)C&s z`w}(iri-$SED=LO_&sOt_w~DfP1iBb`Fx(w^SrksbMKE$|NYmS-Tuz+Q{aPDr^X?h zVDB8k?Jr$E8JpHO9ML-RN4{0?$Q8S)cEb0HM;9ba|Dbhmjxvfgl@~IxiZ>_kjxJGd ze)vX;^CR5wB5m&E1x|RvO{vFD%(hOZ87d^@wjG5kHByD{M$u{=4@{B-@tT70g=rS+7J*JNh-r-NjJ zDO2aytCQoibsGD>9>`tVI2bv!G5_}CP}tl|$?Ibq{p}|$R$O^rhy9-Sm^BOy-dJp3 z?J~T*#IiBm&}N5gcUoY~cr6#@2MV!Q=nEV1mXs(FBhrg@htzY5_HMGG_weW=!X=OG zP05*CC#20%bn~w&Ymg zeNsPfDG42Zh}$l4>suOXJAdH)*n@6(hTgLT5nJb>tB*en$o(sStV456cJ6vFx_z{= z>7bS{CY5!BA~9KRJwTatcBa3LKoL7{+(_I2n(-xNcc!>?%yIAZ?Yxfu- z?kR+OOgRx3(Jp$gJZVD80bA@ryT4%M9%8O2q*8iDLCkqOtI-w3aDBR@gew0<3pVXi zMq&RXTT4!CX43jit%^nLQ_qG8z;l~MEA(bI3>S`vnDbhSdes>3@lX(x$q4I<8#R9O z!_S~$CVx+@_ICcU{6LQK&tyY8EhBPDx!A&D;3?O+xYiR>Sh=i@QPd%H+P$96B3D;7 ztbEjAv3DoK3`~&~;NF8!<~3@I+&^%eXspU$$%n)u5h@nelsBOC-zFx+sX&fFz}|$3GAb5h_*2@-lB5C~qsLl(S(4 z^A3B3Ca1E{VqIgEhtWMpQ_x~E!gdOMCegv34pxgN&`jrlvBhNTx-d;SwQwKB|MuL? z+Kt)w8C&dcJ@MSX!f4!dzBskY>5Zg6wLV1HlE?~5MzyB$9XoEX)>mNin&>*0)OIfy zyR!&;mo7&4a6>T;i!CXo*q@1Qm4U@ity+AV-HPLTyq%w2`PV^_RMbOMbS$R)I~%Wk zRHLz5(VjBE}%M}cyT2-Z%W2| zqmRFJuT)O>HuH*Xi+8LJR=uFd($t__T*tm})mGm<=A$Dt>6Y}+S22k0-)Ukp;4>^* zI>$7aLyD#u}Z5K9$U}UE-Y@@6}vGtuC2>YS9m;Q9tlvx~V4L>QE zhet9F59f@b92z`P3O(mipOO>81cn>nZIZ(V^qFlB0zr16bis7dikdt+`=t8H!dB>WO-s|q@; ztDiR7Z`U}yR|wj+LHZPzS2z=dd?s^dI_)>DrVmIqv~D2m`r1g>V&Weun0*oPsIS)t-ROsx;|R6~e7@aI^BRYR z6Jpvt&9ZrKNI6mUgsX`xDc=|U2qh=ktfhNVKL0mGi4obR)#NXie~ixr z7Vt9DBOA-t8`Ikv?~TF}uE~GRq4eM`BEJO{tRT8O8 zPC=y+YbjVB_A(+;HxCR=uT{*o$=zFVG-71zPRe-Kv?2{@o0$oR-sAyLj}?9jLZIhuqy^P zzKfj27Ps8cmAPlh%r{1Egt)nRKS@OVOl}7AiI~0la;aHUFW%STEcVY(Yl^sb)Z_&y zh+d)cch?qi>dz8lGbOt_li~BVz69QTm8Zr3IH8Sfw20S@XoFOgwPDYOw3(ZeKK^#6 zN%XS3byKegJ^k%={@#}vZqA7bxN}N-?Rl5wEiqqLK0a(YaSmG?G2~}Jd;-VPe&_3& z6MGJfOdf)|kjt-lG!WLU^Dzfclh-Dcxz1PM9(t>eo0tTq25<(c9nao-$Ps%!er(q` ze|}{2D2zkx-}Af7q7zF5adVWo*vX~u>~O973=Jr~zp4T_>f-HbOXso0htibWUW7FF zY_6riI8z##3_P&|84<-3-v+`;-C#1?pI4c&MO$Jv>FmCobpT^Bi>*`M8zp6K66|Sd zzqxwu04y8rPKZwhjYo*ZUP$6?I~Blrb1;4@w>%`ntCvM^rxm*2Az!NEfq`{lxfoJ3 zCZ&`$p5%BJL2LI7pJd}t)3dpwDYeR~RlCp)SFGEZ{V@3%Lz~ zSu@N(g^zmWzYYjB$WYc;g`PGbh+%mi=&=ZulZ>rison< z7>~NJwO+(RSUm(~eC+-mXd9=IwlRU_8_D0vDW^7QCI!g56AS;{Pl|1K5GJ@^EfRso z{9MuLP2jD&6K?0RP_8XT8FY!l0GMs{9o0h4*sb*hCd{q;9E#Ew7lEz|?+ysH-AmTk zt;h+G(kEYpmK&vJdM;NQDLMEUqu*!>*j zubsr?F*ALTd^ifXkF}AOY8_35}qSVa(_oS)(GVH=BncIrFfhZR`LwfslrQ9kj%-;-yb)-QSKlPVnY|2^F7FHI&$Jn`#4ecdk zFf)PXm>8UlN)h<-=^MwCCtLoV6~^fK)nzh3q)PEC8B6Jm1HYqU+g6WFuymt}woSo$ zY6Qfi{AfHuIxBi)HP-w186H--gZO&XvnxnF=RvDGkFJ4Wbv?(DJTq ze`T@9lJ5t>-+-*<>+-gS#zTmULMo1AkH%tTHHd8Jl;?!eqDIed%tgh1`li`YVuq^!&ZeR_(M;RKW;It4`>zSAa_ez`>!@q(~hWTmja%vfVN>uY)3+XI3xpZ7(dRjkQcS`*6mwlpkiF{;;>w==)3F%W)0=(3-YuCqBNvgqV`R4fS^ zo&mKdn{AN{E**;pLu3cC9_ zJxkD7oUM;EQ>H=WK2d*o~tAq z9q{=xML>y}o*a*yMkax+w>auI|JM(0qrXXtA`7B+{QjL~b@PPc zSAp_hMO?C`pHXbrv5!)-k<%6XNx`t=WTA;$h`E^1sXbnVi==&r(7oN&$3-mVMgJz) zRg!I2eX5tgB)T(+PS|4a1V4kL_zd>6oMltD)(6n`;oOFOfCx>uJUWxP%U3SHfTaFznm5(3f^1a& z>&R)_DN-G`PPza1+%%fM6CFR9{S7(D&$fif=cCMnf1XmyE*0-Tz6VyTL5t!ppFg90 zi7(Kt-x;=JzXjYRySvJW(p&)u-hq*&n(fJlqwG2Fz&M5fvD@W90MH?Wu}#*-01l$i<8&m{Q?wbT#pWfe%#0Y_{sYCk?g zWjFex)Ar^*`IdAklT$-6dVI~RG|vwwxfS-h48EP=y#<&^S*wP*a><>1guB?TX~QM- z%(Jh^nBvprSxcWx>Ar`c=4wB6HoKa*aob86<6&7-iKFf*W!O9MQoq6WdiMfSW*qOU ziQa<_BN>xGD5k}|9;O~OM|dp)VC>LG@Ko$$<9w;`m--^OruRjf zG^!_@+`$6_1i5BbZMN_lLAu|x9#^`b zeM#fA_WCGtEEf~emV8<{xL?Bji;LDN0>yea5~Z=bxT8!Y=Tnv-Is@fkzd6C9f(2Lf zxxs*A?&~*=ZtRA}5b(D79jG6&pZKYIaAFS&!da-R8xt4|!XO{tQLaC}Sjrsuh5Vtw zHZZ!z{ev8p*2+6%)&Ulq}5^JBZa@|D(5ok@GAJg78jMS(vodLnE8J@L&Yg4 zL}Wf;^Zb)iTkG2*dykrJ6>2$gBSl6%uBd(q#=Ejw$Ev3WUL`_4>NmyDKv5W&&J9uk zEtUZz_pQ4oOR8{NiuaotebTQFYkN?t5pr*UAa1Qco1+{JtI{Q*Aey(m>k$<18-$B( z8aVbEA-!#KFDxi-)^efdy!8==nE zNkV~-uMbKzvo^1pnuPmQsIV0J)qa_p?DvIbPr?8fLIzfpnv-2)Tx|76;1mAA>_$Vf zny^p>~KM+vB^kZ^HVZ3vi((FUO$-Hs)Y)7iJTt=;=c*mPmm>FEPPEix1AaLpv; z*;kaSB(x6(Up8!F|MESkU}$~YjDpSEEw!6wrOl!}`b}WAx!1p17FlV|op8&>7F!A! zSYc!tnGVRwwDq@6BN(~C$VL-(lx5jC9KF2q|HT_b5dZgFNA8O82WV7*M*ir3lhKS# z^x|Q2lYxbKEMMM-cc1lG3aDhlCT=z5P*9A>2CXU&`Fy=+DA>0z-w|er5gzQc@Om-^ zQd9o@zcBFsf0W}%J7}ayKcG7rRE)%*$WElYS5v%xvJuK+EjGQCe$;%sW$%mI$*4=z z!+5QWvQauKJD`!8k7*r7cYoA9Ysp7Iu3<#aYjYt}ql3Rz*J4bI#`#|Fv`TF8OVXPp z_v&K$3*Ve?`=+n}u)OZSH>tnkBhJPX?o$o8`0Cj}{@n#Vszicc2=p(*51sKn{voDI znF-LQKtanYUHO%ZbUf;h-DrI>mpZ_BGaA6+u81XH5HqyXglEhLG^4SDxZKxK zJs0OF*Ub_dHER)$z3pI6`==*=AT7{#moY4Bwb-Aq5BBES^27%dmznn(O-#&0vv{@3 zy!)HN*$nCTiX)SfEUgbovDIOJsXvh>#;%KT;v>kO?oPFSc}MV-e)fB zBxU*`D0K0{S3FuTb$z}Qai;kn4WtK;S%eOeyptEA*(ahmN?dH9if(c z$q@*;%|>`!{-lK~`PyQX*Iy0i$TN1P4o8Hdg=v~PM5Lf1bl2|8yQMd0Ej zOPDs(SR(y7RD`k+iHW_1u-ode(+H)_9FHT|<-SH50|CJg<-g#gQ-)MDs0)p{;zFs^ z%P`=3j((u+_?&O`=&#^{hdQ6^?sP6Bg5tK>Lf6phNkUy6)Y~DDzWxsE?Z@V2j*ptR zYO_S%B=ODzD9y#WW&-B1)vfi5NORK6mfz05uxK6ez)2H1v*UMVwzwdgZ*1Es^jr!Y zY$fCf)jm?j=CPPgY=kQGbkz76oP}|k17lo@Ut{+jW?lfO3eAr}@e)e!swUe?JEldc zy$9Jzm_Km;EE_+XDfuV);!tM5OE*1y9dKWI;Vq7wB(T}TXxm3sSvHMl>HE83fu6Q% z?53-C24DCO{S)w-Abz0o6|HY_7zm?Ax}d)`bXF<@p(M~2CN^gu4?tG%m<8wqJgjF) zNwM=5lVdU0aFWRfQqGi}d}%=`K3~o~LY*GgpeMdWb@>}rTkOeADndl#8S#VxcRESW z2AzodT5%d0xJT}wF#j+x{JP_J_0oeS`L%KbGi-)sO$-8UI9jT{7S}7pv`UWcowaq# zJb*|4dh$oo-VLMrp5z@I<%|Z+rrCtp5K8kG--1sJ4FepOziTQezabPxO z36~Bj*{F^S^QW+;*sQbLNtP7`9UPT6QrHSH5thi3S{J@lo$P8`eZqpmLkCS#Cg%D6 zt}6)#fJWpdj!@%&nwn&nUi$G@qsqPDOyFr&MH)$y$hzjfzP{{=u^Cwx<}bpQwhe>- zu>;Wt+Z=7PV}f9Q@Dk8x>F4Kd5bY2|8c)4xmL8s`EQy%U40!K??iqM)*;+Nm0JH>L z5vKng@zEb@U7GzSA)!r!GEYl9!ozr|tFyD;e1TX34-&^qf~lG!aFL|v z4>Dki^p{T+KVXiBvtSq@`f`T{G|n$8E2q%J;YFYu?)~XMjqKC^8O+B%AQ%x89Bh!Y za=_;SA+l(`doVHpOak#DtNX|wiXw$MQP^>9te8bp6Oa!jL^1dWHxTxWnuuaba9gN{2-0^38(t}E=Y)GR9iyt7r#~+9EB)~8H+#P)+{L=LBJ4@ z!2ys^f)Ff1c%?LB+t6jsrwHHwjs6jaLMi5AATnth9crhK5KgnRk>?3Jt-61Io5l+~ zNd*>5Uesu`vW^c(7|m|8X4te>&cwEa6oKx*=Q(Czogmt5ju}Cawu$-UJ3Do17Z@O0 z_s_6fCJ+F@5RKQ3B6S~a$x#)9l`biH_8A{VAY8E%~0ge$I7 zXAlH~F@VX{O^7+n#YWCU8V9~B_c2%G{Dx7V>7S&tsgVK?fNCkkuG z$sPp-sGRzDPfQiXNL2d`D6z@csn3JyF#}6O4MFM0VfHR1qWvE+)qWtCk0oQzR97gh zAxB^2#P<1SH)6&T7a;ZV0$`_0m&V0@n*H3_T#kF_abpEKDeGQ}K;C2uXbvDtfRyui zW#ur~BAJKJysRD_iiRr8&uk(f{TFd8QX1WGL!cy(Fn3fC?BsP_KL3d$;L|9t3Kjx| z%-}p|qs9^4D}8L5?fzPoxC01)UkLo*fmh-GdkKau+zOmI=T3ccc+YL5*W%G)sf>ES zHH&3l56jxokj%pZO1GM(xcR#MAd74)_Y&Yl;`tT zL5v&V-veRuPMY3gLf)i{0S~t;YW8kbp^-w&{}nB;1XUuAhAFSLprqk!lMZnetN+Ze z_9jhV2QUzyK7A;zeF2eop+>zEtCtDsj7X$o^_-K(Ur$T;_22%WE>wCI=dpEQ^d~>8 z8aQzYSu9pe|fEI==JK4 zxg~>$mAQfTU%69bQ~vAg&4Px3GKFQgM@n9EVuse|;QI!~@b<=>pkeTG{OsV`bZG9lJ)c*5Tb$vQFV%2c{ z*Taom1dMf!wgwuJw`U8*Ib1#@B1jL+kepmw&!qYj<9sGK6fx#Q>hgVQ6P!@Hi6 zck33fH*Hl-V3@O7)~nB0F*1p|!7R-M3e%Po8vzCeWH|%@KMXJAFDL zv&iyvAk9-D!a?@=^cl9pysU7mZmO4nb}p9e)~lr|Y2?-PzQ!c_NRoR`LdYdz_%lQU zxSPR7eng~XAS{>O?+KPj#b!dfz8;`lV-q>o!S=1T1EW>Q`NPUjY00EmMkzS`G>ujv zWwG726nl?1BTdwba#gW~tcxX1etrM2txEzONSzTO<*}mO?nA+l;`?e>H__TeS`aKPAgfL}^T# z#w0wLD9^@9FP60mu>-ZHL}joSs!~^Bd}<|4&K#%6`ZzX*Q8Xe=SWXM3(a&z%a164F zCnfaZPXp&0wK25d3SxU1ZEh>(>C#;7D!p|f?sChbBn1Q<9bvEjvK%b=>oY$>%~2mI zqSi$ekbCQ&Y#rvSSree)ndokT4&$(xWke%Gw0@~oqxw>>Z1#y;RJ&G+Z;sNB0gC-C zs+W0gEs&h>)Kr1rSXTSI0B9sH)K|?GW4Hr6tk2J&b=VQ+CHTg5t?h0rCYpKUqC%%A z-FN%Q0LXl^Tn(@ZWgblRe(Vvm8U@G5HFH|1NWwtUO(zf&n2{s9%!dETIysgMu64Xv zvs(xdThn=Rl_v|d@y80Jt)Siq>OF2ZPxYdg>yt@l;XWzTok`5^e2Ctsq-xMQ=+w+| z<`~s$83%GMxuzUu1{DS?Zo7uVwUHAn0fTDN6zxl$5N{ngMZ1nWf)W&k+!`CSX0yDQ z^Xc41cu!AJ(T;c?bmMo7<09h1sXSmqnwx-xM@lIa$1Dr*iv~Zrl)I&O+#f~kv3}Ya zzN=Wqjq0&toQdu&@YYxZdbZy&Q~qAio#XJ>>)6`T#AhxNGe3;#5nYR%j<4b>Ng#&h zk`glhUSjF76ux&AM2l_6USF7c|nawid z*oqlyQRGO}sO({TT^V%Dsc38KvMZx!D==o7X5wH?3jH8nQW~q zqY(3WO5_NF_C)A{9D~JGHEa9tQM|9b%~~&-{qylw=J?CiwmSh6Pv@APe*-SnOhK3Q zs^LR(*j}!4Ta-`Z2~%5k$pb=g&^ViL*>Md@{QZN+ubViDox!rkI<_{PR!Z<3ID;$c z=BHXOrZ+7l)@%mE6Mdln{E}((^tl{1UM;8S&=q+;oR^cXvqhm)=S=k(aN_7~9eM>H zUThPZzJQ0j%<8{^Ov|>j&&rvKn!%n(ct(4|>ZIOCYc3+qrc#5Y#d@6B2?l``=gkzI zg%LKUsUDt@+-I88_hy@r+l|tUTQ}}YQxL}XKGN^PWwwiAgI!FbZ)ewb0}{%Nc1OnMgg5yC$PMI!XvItLl4R?1JOh zArd@@ec^!?6Am_irjM8`X@?A*KyS3~M8CAyKrp8E2XNUZp1${8IQkgmj4>a#^F;wt>f!5(LLkm3?oxB8dJhVSH{@OR@CXxK z2Js~B7MN(~Fb+o`Xd1HyW;__Iz|vD6$XF~wN9sApLPzywIBwf3)Fv}`bDIB5XUA~_ z%GH95^K7a3uTLPHB>_zOF!*+%?+Q8%b*eu!V4?tNoA~+77tiG!>`-&{3glN`CJQ!NIf48*Zrl>d{xrJx_^DMickw z-$u7e)iw~~e~Q69@W1CJlsAD)1|V7Efk*KM+)tvLWnQlpvTxv!w0G2WR7#B|@G^sE z*zWhGFHf;PBR!hb(Q$)WW&>7;p}n{!M-9wmc5t864q6ZHa^|6O*yy_rbuYR6{T$xi zE%)$aaM+7|(;&2>Bjl;a`cnp*!KZ<+hLV+V1a}(|&mdgN7BNf%Dz+Zv*DASA6;!SO zh47ar1~2;SKiY;<%;!0ch)u)jD6t^1O9o_HAg_aaFHu1_q1_Gfd8F0&rYTp219nf$ zLte-0vDmy<{<^bS*WHHxQ!81W2YgDIJ7z%qiX~Ovkxjau&Tw><%by28dsT6+G<5(g zF1qs@J5^V1ID+hwqf{(jfbN#US2dW}hp*54q7-N~66yVspzjo7Ns9RJaHs`fb4K@Y z)E{6FtSVaO*>w&&VVR5-@Bu2k2+l+3V1s)SSg{JYx6_4JIJn$u70W79QN&g&c9pii z#@yeH>`mU;Fr`A}`(A?FM44IUu($g>Vsg5r^Icag(b$NquLZ& z(0mgK11Yt)T{Q$Y9y-I2X|Uw6ekgDxk(abDkW)wH%Aqi!2Er;7)vVnudxX6Ga_aMkcW1T*E^1hy}|{5TlA-Pol8`dxg@^` zahe@IHM84pG*~|B9mOwVM>QG=T-lydeR=eoP(Y$D2WNO!GUhPxq?#ZiHy+@BmU-8S zmc)zkvV@D>9Ost)JD#R=hcA*q>S%5}tjm8U@d`{mzWVYC4?gL=xrx5~SAoVLW@;cR z|0YCq7?6cZgN%*8b&Zo|j+b=5iAgW4>wAflfffIy74|pUc4p~ zjy?iu@uxI>;v29I-Mp-a+D^FOp(I`_P5QCEtLkGuz`3$~nKv}|rJhiu*xnGu?`Lcx z<_;b;>%rbq`T%k?ILU`-cjmjn&WXlE-9((!vK|o9L?Y#C+;iCbd>&Rkyw}7?k@uje z^$NWW!?xwOA%}!K^-C=`#fzD~72$q3_nhe(GQo)WUz?8(@_ZYn)K-3;bE}2XJg$@!f$x=P4y{&1H*Z&yaXK=?Mm!oAP%>IsrxKe^g zG{{?HsK@V%BgHk>w7LQkA5#RrOuT`BkE`d0&zcgVLC5l-{jJr#t?{Qb3P{LvbeKMH zF>t^KU;br4CY%%mH333(#dpHNN0Q_E5s|pDd~0+bN;v@9$Ll!Y+@R*}{>}L9#9(f8JRpShFWmZp-Go zdcLy?ku7QSLb|OHW!%reQF#CR)@q8;kiRSk^M$@NO<+Q^7BgR(kXx2qSGIx}d^g{@VeRH<7TZ>yK3kA<6Kk zNMo7NIf%1DKN*pc+{+8V6^hIjZH0-%ID^S=aqba(jpyGc_DQ03NHWKE0E$V;U>JOy zVu3^?CQ2AN44oth--;}p5F64LmxK|Q-IfGCq*jiXBuJu~W8iYQk-UQkAgRWm4oW6o zhw5Q41tJH+mrZltH73zcY7Q1+za7>@6y>X3Snnnd?rx~83v!wQRs1~Kz$57S`22pO zAOXU6v6D_x=M4vp-4K2ci8R8yON`N84}@m$C=ZvZ1mD%;IOK9|vL*ZO zEmnJdIi}k}El3W_jN{N*8$)k7D1Vb9aiM!(=c+5F>o@qqKg1L4yHAK9x-|3PEEFrT zy=_LbtCAij%jaXltKA4aL+18v1&`ZpP#w%yjd?=j#M zT4acMlYsZrdC1dgkZqSB>CmsfIN=LCL+7;ZIj$S%7jol}HhvN8uDHb}$H^wmw@Xnp z3@w`6T}=I(ReiQzJGJ4On@o^;^Y`o(U4VpZ%PR5(&!RN{A2xkD{qePUxG+Xr*qpi zs_{qW^9;kK7#ifc;Awc$55~$eBAY}!2C&7=I>-rZ%6)`{`w%@8tqs-)k_Bs(P@PTm zAR*D8pD$btj z`XoD5yYDN4N+$M{r3iR3dzCz(xdI6Mf-~0Et8M)KQU)EIiuriyIM^@x)E4@`L175p z$?TFCed2{;sr*QawGz~FpqCs}Lp;R%-xN>K+}ztHtkLnz6I1LHI@XIHauC5w@0p*0 zC=1D`3SnYI2gaBT95PaZJqN-(70*C&43$r(nBR8z{B#h}ra;?%6|5R_IKg!e=AXxR zcA+j6F?fwWCG2yH4R__HGt{2}zBSu9x#v7PL14>q`{~1#ZN_?l?9B_(oTki2q1(v@ zXFw`gHj&ty&y7{?d=4OI`{D03oiN6sy*9=m_|MMeqQ!hCnvVGq7u&zm1CY+-A_5V- zqi`J>PX_Zzb>Lg^I$8*PaB3F;9in*GH^f-a_<8CIVj{E{?Q8F`hH1VInJ*(^oX39? z-x~gL7`N+BT|%<5x_yi8b&T202DfpA@+ZxGWj)HQzG0{G;9`6ycS z3sHV`mpro8gG(oQnWHO**j;O~<<6)Ky=QT;OdcB$+coeHf188v4>%3!;R(ozM@m#JigAh}$l#1O_q>E$5n$Dk$^H0SQve?HAYV;w(s~QEO82FK!aGb2 zgEq*7uQ@R>vwQOKc{X*p6y#nC!^uSs(ZGLE+QuM7ZM$n&qif;AgM*Gw5X&v?jTH#x z=jaT5$m#zBV@rz(1!K=w4reL^FT`pEIhmwo$@eWf6M0vo*s-z4oWp~EKZi)jzFHWy z&gy>bU6rEg+`kHMnLt1#7G;CRM!IG`G>^M;q-oG|{a-;;=XR}uGLX&2?`GVBxC-+> zH=*a~Fl4?x>Ap24CJhcnz?JUcGQ-@#QJ6~+z>>!TpLS@5Pl8{8vKH z838IHjqfssRKjD%iBO=U!>P1w7;C~@0`d+Hr12k9`#I)7Ia@DL{oIs~Ma0FftXu|@ z*z0HPYZDW~d25b(1}=3eJTBIr24R5nbKgL9NwLT-HG42IX{FGm`~gyZc}2?^>D-Je zx<$lT-T8P_xmMNYr(}qwVJ4!?HOH3|2*9*!U2jpj7BUJ;zAvvnv?2qGJ+Q>34W+GG zH$Qdxwnob%>?hFiR8@ za@)70B@@F)m=fQEZjqH!&o#$v(rEaR#I{+J^`h~39^<Q zW!1tDaAI|+ZAfhMhABHdBZG>V{J%(u7@_FL$JtJ?Hi>W?ke zrobkXJ@>T-cqtyQg{71?wtBLk%aFp?qj|N1b)*f!;t!I6;C1H2H*SeQBpid+pF&hR zyE_dcFr$%_M#_$a_rCcx?~#~et5HS+cLqLJv~1OW=K<$Df~=zO(N4SJhl-FlWRhh- z)6EP-oIHE&8F+iB?fjmC=>~I?#%@xY%QnK6pE@=ozhr(MwQsq1oP zV)lI5@&jQl^s@!2fyhfY;6j-nEr3V~(obw@_eb^cX2_cjn}AAmCtC2y15+Kga|m@w za?j+eqrmG%sXA}OUPhpe?T_*kj(6!aElOLTb>wwjhnCI?RgUHsQbXy=DcO5Wfa^ay{n9v{M+$_{oT| eNzi?7!9LUZCgz=$4ReuYXPe7TyKGl^H~k-oR^}`K diff --git a/device-server/mqtt-server/log/error.2022-01-12.0.gz b/device-server/mqtt-server/log/error.2022-01-12.0.gz deleted file mode 100755 index 312d3325586da305a940a03f55d11e0ebdab92a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 845 zcmV-T1G4-diwFP!000000NqzhYZO5czWXcsZg11Cntn(QAyE{J#^}KZB9qOS4DQaX zJG~*fc~C?_FN&h5;6V@}7Y_;|`fGNRpJDZ`=Ao;ssBv_mx0&gp>YJ*s9xb_)4K5l& z60STKUI~_HLk=%2oLnFRoYkb!XpjrX)=rx>1?Lt!y%U%1)J4){IjgenYSv{dX|dG8 zeeP-qGi6cr+FAGL=p7-%lXg~B>2gLw*~yzEuSni%Wy@)c9gt(p0~ZsRXKl0}4bG=4 z<=n`?Y&T!ciW!7cWUc9?v=b13C&$YwkY)G2_Tg$ zV;$CHZA7)ISYDv{0v$io%CjPz4r$29@aIX@yA+CL5j3}_y60yPmvd%jEuZaW^9K*= zBki+a>GtGI-p-at*$X7CNKuj$KV>x!>y%u{vd(l1KYU7Z%K7#pt+Wa!dttHc6-(2f z#itU`R69kjQdAmA4U7bj6=UQK%4tIZ6y;iyfEb1cAff_;3OMe1s9+x5w@14HLzU8F z{HYmNllb#jLcF?(}az?>~CE`S^PO-ktut`-6vXw%**p{~v{3 z8ZQ$j!Tv{~cN!O1s<@*B&8-vkl#ML;NXG-CNO0u@yI`s49MeH zIC1pBrmD9Eze$EDr!ZM`?9Rx0lp7^OJTM~#T$-=C@^0-8+ctM&{R#F@*SlX$200vC zW9Us?N;5)|*f12+Zj#cxPmq-GLb8NUask{gNCs~_%t%=uNLqT}%>8lN{|qFH49EEx z>H`V1=avaE$sD{dkc5{yW}JfBa7lWJbxAQWHG+iKX&E!FHi5&TL3r+%<#mFTcreVV X8U+p_Dkj`tEdrka#+Z6rQWO9HT`Q4Y diff --git a/device-server/mqtt-server/log/error.2022-01-13.0.gz b/device-server/mqtt-server/log/error.2022-01-13.0.gz deleted file mode 100755 index 56466d0b220073d4cd545a636607ae9580268dd1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2177 zcmV-{2!8h;iwFP!000000L`6Ci(Je)n->d`{4uoSZa2f9J(}@rCmrJh`~~$*i>|$FO7r90zH3f*_{Gz1 zv)h*D`d|ON`O~-8|M~6f|NZsmi*Md;F5B+%=Tyai;7vnfvj4#IG@Yd3hj1Lt^r%1GKFQ2!U3K5>3;lBiUZ@1lFowt`i z8ot&vh;%*xH{I@HbJ}e7&F1W^eYQUPt~`z#7nCuAoHQai&t?%HR0c6i-~q|kOzt@> zl8T8c1xaIMK&qO^^H{_sbcmpJWJ2PaHL3Wll5@QBAjlyZqbU_^5{Klt_L^M4D9|-4 z>x}YZLL^&27i}@Nt(mk7Bh@VSGdKz5ty3lm+I=S^rj-@t0hEb?mbMY8%1Lur#1!q7 zj*`a6fRvb4R-j|D(m|F*dL*t{gXhnvG}Oc+%UOhws)EKjEMkkskl9Jv{zfFOy~Y-s zRFV{-jYwP(8p=af(MZ~B1|-XL_61iAhRm94h>r4NGL1cwGsOay9W+Pzn(?rlLwr)!%0qH2PI85cpIJF8CT2w>JlAODt14K_B6%(+S?VhQ zIm7mV#5Qc{XoJI6Ov>hn#1clMJpEQy&ROS(#IpVM@)nfNl9sj+i6yPq%L7Jea>@g@ zLz=@PK$+(h#iaF)NGu17Ufu>3s-pPiEJ8>;$?#qtqVgaq9vP8Xj#?=1i%!bPIcgn{ zc#c}Vyv=y95R=3@BGqhv^H{`dWenG(y@mWz4hh8=rR8)`9Fb}=jdM6DQ06)E^r0Q) zB~98undcxU8GbvYIh+(J^X!wPD1JaGfO`>xKCmBtp09Vz|x{yUCB&L&|>2Ez6IqeDuq^h*uJQe|~w3lTOLJCX~ znlaQDpCv_TBN9)$LN9NfiXiA*Ga~V{*!J=OlCJz5kg6_5&0!Hsr2uaQ1q2fkQ@sY| zZBU>E#Um3EQ_PC;5S7hLDZD}6$?0cBBsxbZBd71^fK-)foWn_uN&z|w>J1o?xaz(r z4_ReNIkX9h>s$lWD<7*;cuQGiKuTOuJWzQcNUCyBT9B(5mlQz<~uBbX*6$5r<=p)UnU$|_DsT)S_eUU{7) zoqY$Ss)w1)V-X)KBeWUiB`xf+7z~+%q>Ryk#MP^a@}SWol2+CMi7oS-s1zV8&pIM; zUq%kre0n_e_@?I;D^E}Q25-{}!SW6cboMk#hO!AT(VvDmF4hg!;IUzA+15n=6 zbz?yh+K5yYM$cgpsw!fH#x-jOc{$IE?~$Ca8_*LHS3KgV6cFV+AoYmEWf7oKfEN|B z4oHD1tBCS0;^r^QB80@%y@~SuQ+v1q#9PQOnc_SKh_Wm~NL7*jJQnc*V^*ef z%_v`0^x+O6jk~C{Z zB(7QGs1#tUF4rz+ksgUD8{nX5dT0>Wq#flYIRuKevThvR25BBAf#rHn_)%WcvC2~^ zAj)|)*8zzu7mxB5RFqVlACZ7*X`^>QCkzk;9X>}SuD7+&JD@Yp8fJMhL)25Nq|VC9 zdD;eDe(*V{^uJ28 zzxrjjeP%k)>8F<;-hZ%r81KE<+`nocz4aFS@cd`r`QD{@e{Xp`qKh4>C-@SX)J=tAtpWYomekU5UiV#;OnU#xa6|?O> z_|EowK4Bf#P1pY){kRUr&yN5A D)mRob diff --git a/device-server/mqtt-server/log/info.2022-01-10.0.gz b/device-server/mqtt-server/log/info.2022-01-10.0.gz deleted file mode 100755 index 38fc3fce63909f53dc557d07da126f48ede790e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14191 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 Q>sJ)7v>iw>HUixL0TcPQTmS$7 diff --git a/device-server/mqtt-server/log/info.2022-01-11.0.gz b/device-server/mqtt-server/log/info.2022-01-11.0.gz deleted file mode 100755 index 1518b11c0b4614d421443039e8efe44b711ab50c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102288 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 diff --git a/device-server/mqtt-server/log/info.2022-01-12.0.gz b/device-server/mqtt-server/log/info.2022-01-12.0.gz deleted file mode 100755 index 1dea45f4ced4efa159c8ef3b7cfdceb4b816e70f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 79144 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 - - org.springframework.boot - spring-boot-starter-data-mongodb - org.springframework.boot spring-boot-starter-web - - org.springframework.boot - spring-boot-starter-integration - - - org.springframework.integration - spring-integration-mqtt - - - - org.springframework.boot - spring-boot-starter-cache - - - - org.springframework.cloud - spring-cloud-commons - - - - com.github.ben-manes.caffeine - caffeine - - org.projectlombok lombok true - - commons-beanutils - commons-beanutils - - - - org.apache.commons - commons-lang3 - - commons-codec commons-codec - - commons-io - commons-io - - - - com.google.guava - guava - - org.bouncycastle bcprov-jdk15on - joda-time - joda-time + org.eclipse.paho + org.eclipse.paho.client.mqttv3 @@ -96,11 +48,17 @@ cc.iotkit common + cc.iotkit device-api + + cc.iotkit + gateway-client + + diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/config/CacheConfig.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/config/CacheConfig.java deleted file mode 100755 index 137ebb51..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/config/CacheConfig.java +++ /dev/null @@ -1,43 +0,0 @@ -package cc.iotkit.server.config; - -import com.github.benmanes.caffeine.cache.Caffeine; -import com.google.common.collect.Lists; -import org.springframework.cache.CacheManager; -import org.springframework.cache.caffeine.CaffeineCache; -import org.springframework.cache.support.SimpleCacheManager; -import org.springframework.context.annotation.Bean; - -import java.util.concurrent.TimeUnit; - -//@Configuration -//@EnableCaching -public class CacheConfig { - - /** - * 配置本地缓存 - */ - @Bean - public CacheManager cacheManager() { - SimpleCacheManager manager = new SimpleCacheManager(); - manager.setCaches(Lists.newArrayList(new CaffeineCache( - "device_cache", - Caffeine.newBuilder() - .expireAfterWrite(5, TimeUnit.MINUTES) - .build() - ), - new CaffeineCache( - "product_cache", - Caffeine.newBuilder() - .expireAfterWrite(5, TimeUnit.MINUTES) - .build() - ), - new CaffeineCache( - "app_design_cache", - Caffeine.newBuilder() - .expireAfterWrite(5, TimeUnit.MINUTES) - .build() - ))); - return manager; - } - -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/config/GlobalExceptionHandler.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/config/GlobalExceptionHandler.java deleted file mode 100755 index 1c603d32..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/config/GlobalExceptionHandler.java +++ /dev/null @@ -1,42 +0,0 @@ -package cc.iotkit.server.config; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.ResponseBody; - -import javax.servlet.http.HttpServletResponse; - -@Slf4j -@ControllerAdvice -public class GlobalExceptionHandler { - - @ExceptionHandler(Exception.class) - @ResponseBody - public RequestResult handleException(Exception e, HttpServletResponse response) { - log.error("handler exception", e); - if(e.getMessage().contains("Unauthorized")){ - response.setStatus(403); - return new RequestResult("403", "没有权限"); - } - response.setStatus(500); - return new RequestResult("500", e.getMessage()); - } - - @NoArgsConstructor - @AllArgsConstructor - @Data - public static class RequestResult { - - private String code; - - private String message; - - } - -} - - diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/config/MqttConfig.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/config/MqttConfig.java deleted file mode 100755 index c984a60c..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/config/MqttConfig.java +++ /dev/null @@ -1,147 +0,0 @@ -package cc.iotkit.server.config; - -import cc.iotkit.common.Constants; -import cc.iotkit.common.utils.CodecUtil; -import cc.iotkit.server.handler.MqttConsumerHandler; -import lombok.SneakyThrows; -import org.apache.commons.lang3.StringUtils; -import org.eclipse.paho.client.mqttv3.MqttConnectOptions; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.integration.annotation.ServiceActivator; -import org.springframework.integration.channel.DirectChannel; -import org.springframework.integration.core.MessageProducer; -import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory; -import org.springframework.integration.mqtt.core.MqttPahoClientFactory; -import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter; -import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler; -import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.MessageHandler; - -@Configuration -public class MqttConfig { - - /** - * 订阅的bean名称 - */ - public static final String CHANNEL_NAME_IN = "mqttInboundChannel"; - /** - * 发布的bean名称 - */ - public static final String CHANNEL_NAME_OUT = "mqttOutboundChannel"; - - @Value("${mqtt.url}") - private String url; - - @Value(("${spring.profiles.active:}")) - private String env; - - /** - * MQTT连接器选项 - * - * @return {@link MqttConnectOptions} - */ - @Bean - public MqttConnectOptions getMqttConnectOptions() { - MqttConnectOptions options = new MqttConnectOptions(); - // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录, - // 这里设置为true表示每次连接到服务器都以新的身份连接 - options.setCleanSession(true); - // 设置连接的用户名 - options.setUserName("admin"); - // 设置连接的密码 - options.setPassword("password".toCharArray()); - options.setServerURIs(StringUtils.split(url, ",")); - // 设置超时时间 单位为秒 - options.setConnectionTimeout(10); - // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送心跳判断客户端是否在线,但这个方法并没有重连的机制 - options.setKeepAliveInterval(20); - return options; - } - - /** - * MQTT客户端 - * - * @return {@link MqttPahoClientFactory} - */ - @Bean - public MqttPahoClientFactory mqttClientFactory() { - DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory(); - factory.setConnectionOptions(getMqttConnectOptions()); - return factory; - } - - /** - * MQTT信息通道(生产者) - * - * @return {@link MessageChannel} - */ - @Bean(name = CHANNEL_NAME_OUT) - public MessageChannel mqttOutboundChannel() { - return new DirectChannel(); - } - - /** - * MQTT消息处理器(生产者) - * - * @return {@link MessageHandler} - */ - @SneakyThrows - @Bean - @ServiceActivator(inputChannel = CHANNEL_NAME_OUT) - public MessageHandler mqttOutbound() { - String clientId = "mqtt-server-producer-" + env; - clientId = "su_" + CodecUtil.aesEncrypt("admin_" + clientId, Constants.MQTT_SECRET); - MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler( - clientId, - mqttClientFactory()); - messageHandler.setAsync(true); - return messageHandler; - } - - /** - * MQTT消息订阅绑定(消费者) - * - * @return {@link MessageProducer} - */ - @SneakyThrows - @Bean - public MessageProducer inbound() { - // 可以同时消费(订阅)多个Topic - String clientId = "mqtt-server-consumer-" + env; - clientId = "su_" + CodecUtil.aesEncrypt("admin_" + clientId, Constants.MQTT_SECRET); - MqttPahoMessageDrivenChannelAdapter adapter = - new MqttPahoMessageDrivenChannelAdapter( - clientId, mqttClientFactory(), - "/sys/#"); - adapter.setCompletionTimeout(5000); - adapter.setConverter(new DefaultPahoMessageConverter()); - adapter.setQos(1); - // 设置订阅通道 - adapter.setOutputChannel(mqttInboundChannel()); - return adapter; - } - - /** - * MQTT信息通道(消费者) - * - * @return {@link MessageChannel} - */ - @Bean(name = CHANNEL_NAME_IN) - public MessageChannel mqttInboundChannel() { - return new DirectChannel(); - } - - /** - * MQTT消息处理器(消费者) - * - * @return {@link MessageHandler} - */ - @Bean - @ServiceActivator(inputChannel = CHANNEL_NAME_IN) - public MessageHandler handler() { - return new MqttConsumerHandler(); - } -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/BaseDao.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/BaseDao.java deleted file mode 100755 index 53218ee0..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/BaseDao.java +++ /dev/null @@ -1,55 +0,0 @@ -package cc.iotkit.server.dao; - -import org.springframework.data.domain.Sort; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.query.Criteria; -import org.springframework.data.mongodb.core.query.Query; - -import java.util.List; - -import static org.springframework.data.mongodb.core.query.Criteria.where; -import static org.springframework.data.mongodb.core.query.Query.query; - -public class BaseDao { - - protected MongoTemplate mongoTemplate; - - private Class cls; - - public BaseDao(MongoTemplate mongoTemplate, Class cls) { - this.mongoTemplate = mongoTemplate; - this.cls = cls; - } - - public List find(Criteria condition) { - Query query = new Query(); - query.addCriteria(condition); - return mongoTemplate.find(query, cls); - } - - public List find(Criteria condition, long skip, int count, Sort.Order order) { - Query query = new Query(); - query.addCriteria(condition) - .with(Sort.by(order)) - .skip(skip) - .limit(count); - return mongoTemplate.find(query, cls); - } - - public long count(Criteria condition) { - Query query = new Query(); - query.addCriteria(condition); - return mongoTemplate.count(query, cls); - } - - public T save(String id, T entity) { - if (id == null) { - return mongoTemplate.save(entity); - } else { - mongoTemplate.updateFirst(query(where("_id").is(id)), - DaoTool.update(entity), entity.getClass()); - return (T) mongoTemplate.findById(id, entity.getClass()); - } - } - -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DaoTool.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DaoTool.java deleted file mode 100755 index 03fc448e..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DaoTool.java +++ /dev/null @@ -1,53 +0,0 @@ -package cc.iotkit.server.dao; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.SneakyThrows; -import org.apache.commons.beanutils.BeanMap; -import org.springframework.data.mongodb.core.query.Update; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -public class DaoTool { - - public static void update(Update update, List props) { - for (Prop pro : props) { - update.set(pro.getName(), pro.getValue()); - } - } - - public static List getProp(String key, Object value) { - List props = new ArrayList<>(); - if (value instanceof Map) { - Set> entrySet = ((Map) value).entrySet(); - for (Map.Entry entry : entrySet) { - props.addAll(getProp(key + "." + entry.getKey(), entry.getValue())); - } - } else if (value != null && !(value instanceof Class)) { - props.add(new Prop(key, value)); - } - return props; - } - - @SneakyThrows - public static Update update(T obj) { - Map pros = new BeanMap(obj); - Update update = new Update(); - for (Map.Entry entry : pros.entrySet()) { - update(update, DaoTool.getProp(entry.getKey().toString(), entry.getValue())); - } - return update; - } - - @Data - @AllArgsConstructor - @NoArgsConstructor - static class Prop { - private String name; - private Object value; - } -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DeviceDao.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DeviceDao.java deleted file mode 100755 index e553f4d2..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DeviceDao.java +++ /dev/null @@ -1,62 +0,0 @@ -package cc.iotkit.server.dao; - -import cc.iotkit.common.Constants; -import cc.iotkit.model.device.DeviceInfo; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.query.Query; -import org.springframework.stereotype.Repository; - -import static org.springframework.data.mongodb.core.query.Criteria.where; -import static org.springframework.data.mongodb.core.query.Query.query; - -@Repository -public class DeviceDao extends BaseDao { - - @Autowired - private DeviceRepository deviceRepository; - - @Autowired - public DeviceDao(MongoTemplate mongoTemplate) { - super(mongoTemplate, DeviceInfo.class); - } - - public void addDevice(DeviceInfo device) { - device.setCreateAt(System.currentTimeMillis()); - mongoTemplate.insert(device); - } - - public void updateDevice(DeviceInfo device) { - if (device.getDeviceId() == null) { - return; - } - mongoTemplate.updateFirst(query(where("deviceId").is(device.getDeviceId())), - DaoTool.update(device), DeviceInfo.class); - } - - public void updateDeviceByPkAndDn(DeviceInfo device) { - if (device.getProductKey() == null || device.getDeviceName() == null) { - return; - } - mongoTemplate.updateFirst(query(where("productKey").is(device.getProductKey()). - and("deviceName").is(device.getDeviceName())), - DaoTool.update(device), DeviceInfo.class); - } - - @Cacheable(value = "deviceInfoCache", key = "#pk+'_'+#dn") - public DeviceInfo getByPkAndDn(String pk, String dn) { - Query query = query(where("productKey").is(pk).and("deviceName").is(dn)); - return mongoTemplate.findOne(query, DeviceInfo.class); - } - - public DeviceInfo getByDeviceId(String deviceId) { - Query query = query(where("deviceId").is(deviceId)); - return mongoTemplate.findOne(query, DeviceInfo.class); - } - - @Cacheable(value = Constants.DEVICE_CACHE, key = "#deviceId") - public DeviceInfo get(String deviceId) { - return deviceRepository.findById(deviceId).orElse(new DeviceInfo()); - } -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DeviceEventRepository.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DeviceEventRepository.java deleted file mode 100755 index 7b8b9e01..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DeviceEventRepository.java +++ /dev/null @@ -1,13 +0,0 @@ -package cc.iotkit.server.dao; - -import cc.iotkit.model.device.message.DeviceEvent; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.mongodb.repository.MongoRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface DeviceEventRepository extends MongoRepository { - - Page findByDeviceId(String deviceId, Pageable pageable); -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DeviceRepository.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DeviceRepository.java deleted file mode 100755 index 2ee7e611..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/DeviceRepository.java +++ /dev/null @@ -1,9 +0,0 @@ -package cc.iotkit.server.dao; - -import cc.iotkit.model.device.DeviceInfo; -import org.springframework.data.mongodb.repository.MongoRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface DeviceRepository extends MongoRepository { -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/ThingModelRepository.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/ThingModelRepository.java deleted file mode 100755 index a306169e..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/dao/ThingModelRepository.java +++ /dev/null @@ -1,9 +0,0 @@ -package cc.iotkit.server.dao; - -import cc.iotkit.model.product.ThingModel; -import org.springframework.data.mongodb.repository.MongoRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface ThingModelRepository extends MongoRepository { -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/DisconnectedHandler.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/DisconnectedHandler.java deleted file mode 100755 index 31517224..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/DisconnectedHandler.java +++ /dev/null @@ -1,63 +0,0 @@ -package cc.iotkit.server.handler; - -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.server.dao.DeviceRepository; -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.server.service.DeviceService; -import com.fasterxml.jackson.core.type.TypeReference; -import lombok.Data; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Example; -import org.springframework.stereotype.Component; - -import java.util.List; - -@Slf4j -@Component -public class DisconnectedHandler { - - @Autowired - private DeviceService deviceService; - @Autowired - private DeviceRepository deviceRepository; - - public void handler(String msg) { - Disconnected disconnected = JsonUtil.parse(msg, new TypeReference() { - }); - String clientId = disconnected.getClientid(); - String[] parts = clientId.split("_"); - if (parts.length < 2) { - return; - } - String pk = parts[0]; - String dn = parts[1]; - log.info("gateway disconnected, offline,pk:{},dn:{}", pk, dn); - - DeviceInfo example = new DeviceInfo(); - example.setProductKey(pk); - example.setDeviceName(dn); - DeviceInfo device = deviceRepository.findOne(Example.of(example)).orElse(new DeviceInfo()); - if (device.getDeviceId() == null) { - log.error("no device found by pk:{} and dn:{}", pk, dn); - return; - } - deviceService.offline(pk, dn); - - example = new DeviceInfo(); - example.setParentId(device.getDeviceId()); - //子设备下线 - List children = deviceRepository.findAll(Example.of(example)); - children.forEach(c -> deviceService.offline(c.getProductKey(), c.getDeviceName())); - } - - @Data - private static class Disconnected { - private String reason; - private String clientid; - private String username; - private String peername; - private String sockname; - } - -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/EventReportHandler.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/EventReportHandler.java deleted file mode 100755 index fec33d09..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/EventReportHandler.java +++ /dev/null @@ -1,49 +0,0 @@ -package cc.iotkit.server.handler; - -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.server.dao.DeviceEventRepository; -import cc.iotkit.model.device.message.DeviceEvent; -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.model.mq.Request; -import cc.iotkit.model.mq.Response; -import com.fasterxml.jackson.core.type.TypeReference; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.util.Map; -import java.util.regex.Pattern; - -@Component -public class EventReportHandler implements MqttHandler, Response.Empty> { - - private static final Pattern MATCH_REG = Pattern.compile("^/sys/\\w+/\\w+/s/event/[^_/]+$"); - - @Autowired - DeviceEventRepository deviceEventRepository; - - @Override - public boolean compliant(String topic) { - return MATCH_REG.matcher(topic).matches(); - } - - @Override - public Request parse(String msg) { - return JsonUtil.parse(msg, new TypeReference() { - }); - } - - @Override - public Response.Empty handler(String topic, DeviceInfo device, Request request) { - String identifier = topic.substring(topic.indexOf("/event/") + 7); - DeviceEvent event = DeviceEvent.builder() - .deviceId(device.getDeviceId()) - .identifier(identifier) - .request(request) - .type(topic.endsWith("_reply") ? "ack" : "event") - .createAt(System.currentTimeMillis()) - .build(); - deviceEventRepository.save(event); - return Response.empty(); - } - -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/MqttConsumerHandler.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/MqttConsumerHandler.java deleted file mode 100755 index 49a45cc3..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/MqttConsumerHandler.java +++ /dev/null @@ -1,162 +0,0 @@ -package cc.iotkit.server.handler; - -import cc.iotkit.common.Constants; -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.server.dao.DeviceDao; -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.model.mq.Request; -import cc.iotkit.model.mq.Response; -import cc.iotkit.server.service.DeviceService; -import cc.iotkit.server.service.IMqttSender; -import com.fasterxml.jackson.core.type.TypeReference; -import lombok.Data; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageHandler; -import org.springframework.messaging.MessageHeaders; -import org.springframework.messaging.MessagingException; - -import java.util.ArrayList; -import java.util.List; - -@Slf4j -public class MqttConsumerHandler implements MessageHandler, ApplicationContextAware { - - private List mqttHandlers = new ArrayList<>(); - - @Autowired - private DeviceDao deviceDao; - @Autowired - private IMqttSender mqttSender; - @Autowired - private DeviceService deviceService; - @Autowired - private DisconnectedHandler disconnectedHandler; - - @Override - public void handleMessage(Message msg) throws MessagingException { - log.info(JsonUtil.toJsonString(msg)); - MessageHeaders headers = msg.getHeaders(); - String topic = headers.get("mqtt_receivedTopic", String.class); - if (topic == null) { - log.error("message topic is null."); - return; - } - - if (topic.equals("/sys/session/topic/unsubscribed")) { - topicUnsubscribed(msg.getPayload().toString()); - return; - } - - if (topic.equals("/sys/client/disconnected")) { - disconnectedHandler.handler(msg.getPayload().toString()); - return; - } - - String[] parts = topic.split("/"); - if (parts.length < 5) { - log.error("message topic is illegal."); - return; - } - - String pk = parts[2]; - String dn = parts[3]; - DeviceInfo device = deviceDao.getByPkAndDn(pk, dn); - if (device == null) { - log.warn("device not found by pk and dn."); - return; - } - String payload = msg.getPayload().toString(); - - //转发到deviceId对应的topic中给客户端消费 - sendToAppClientTopic(device.getDeviceId(), topic, payload); - - Object result = null; - Request request = new Request<>(); - try { - for (MqttHandler handler : mqttHandlers) { - if (!handler.compliant(topic)) { - continue; - } - request = handler.parse(payload); - result = handler.handler(topic, device, request); - } - } catch (Throwable e) { - log.error("handler mqtt msg error.", e); - reply(device.getDeviceId(), topic, request.getId(), 1, ""); - return; - } - - if (result == null) { - return; - } - - reply(device.getDeviceId(), topic, request.getId(), 0, result); - } - - private void reply(String deviceId, String topic, String id, int code, Object result) { - topic = topic.replace("/s/", "/c/") + "_reply"; - String msg = JsonUtil.toJsonString(new Response<>(id, code, result)); - mqttSender.sendToMqtt(topic, msg); - sendToAppClientTopic(deviceId, topic, msg); - } - - private void topicUnsubscribed(String msg) { - Unsubscribed unsubscribed = JsonUtil.parse(msg, new TypeReference() { - }); - String topic = unsubscribed.getTopic(); - String[] parts = topic.split("/"); - if (parts.length < 4) { - return; - } - - log.info("device offline,pk:{},dn:{}", parts[2], parts[3]); - deviceService.offline(parts[2], parts[3]); - } - - private void sendToAppClientTopic(String deviceId, String topic, String msg) { - //排除服务调用和属性设置消息 - if (topic.contains("/c/service/") || topic.endsWith("/post_reply")) { - return; - } - - //发给app端订阅消息 - distributeMsg(Constants.TOPIC_PREFIX_APP, topic, deviceId, msg); - //发送给第三方接入gateway - distributeMsg(Constants.TOPIC_PREFIX_GATEWAY, topic, deviceId, msg); - } - - /** - * 分发消息 - */ - void distributeMsg(String topicNamePrefix, String topic, String deviceId, String msg) { - /* - /app/xxxdeviceId/event/事件名 - /app/xxxdeviceId/event/property/post - /app/xxxdeviceId/service/服务名_reply - */ - String distTopic = "/" + topicNamePrefix + "/" + deviceId + "/" + - (topic.replaceAll("/sys/.*/s/", "") - .replaceAll("/sys/.*/c/", "")); - log.info("send msg:{},to topic:{}", JsonUtil.toJsonString(msg), distTopic); - //转发到deviceId对应的topic中给客户端消费 - mqttSender.sendToMqtt(distTopic, msg); - } - - @Override - public void setApplicationContext(ApplicationContext context) throws BeansException { - mqttHandlers.addAll(context.getBeansOfType(MqttHandler.class).values()); - } - - @Data - private static class Unsubscribed { - private String clientid; - private String username; - private String topic; - private String peerhost; - } -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/MqttHandler.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/MqttHandler.java deleted file mode 100755 index ff6fc23b..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/MqttHandler.java +++ /dev/null @@ -1,14 +0,0 @@ -package cc.iotkit.server.handler; - -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.model.mq.Request; - -public interface MqttHandler { - - boolean compliant(String topic); - - Request parse(String msg); - - R handler(String topic, DeviceInfo device, Request request); - -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/PropertyPostHandler.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/PropertyPostHandler.java deleted file mode 100755 index 3a1be075..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/PropertyPostHandler.java +++ /dev/null @@ -1,62 +0,0 @@ -package cc.iotkit.server.handler; - -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.server.dao.DeviceEventRepository; -import cc.iotkit.server.dao.DeviceRepository; -import cc.iotkit.model.device.message.DeviceEvent; -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.model.mq.Request; -import cc.iotkit.model.mq.Response; -import com.fasterxml.jackson.core.type.TypeReference; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.util.HashMap; -import java.util.Map; - -@Slf4j -@Component -public class PropertyPostHandler implements MqttHandler, Response.Empty> { - - @Autowired - DeviceRepository deviceRepository; - @Autowired - DeviceEventRepository deviceEventRepository; - - @Override - public boolean compliant(String topic) { - return topic.endsWith("/event/property/post"); - } - - @Override - public Request> parse(String msg) { - return JsonUtil.parse(msg, new TypeReference>>() { - }); - } - - @Override - public Response.Empty handler(String topic, DeviceInfo device, Request> request) { - device.setId(device.getDeviceId()); - if (device.getProperty() == null) { - device.setProperty(new HashMap<>()); - } - Map newProps = request.getParams(); - if (newProps != null && newProps.size() > 0) { - request.getParams().forEach(device.getProperty()::put); - } - - deviceRepository.save(device); - - DeviceEvent event = DeviceEvent.builder() - .deviceId(device.getDeviceId()) - .identifier("propertyPost") - .request(request) - .type("property") - .createAt(System.currentTimeMillis()) - .build(); - deviceEventRepository.save(event); - return Response.empty(); - } - -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/PropertyReplyHandler.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/PropertyReplyHandler.java deleted file mode 100755 index b4cfc4ab..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/PropertyReplyHandler.java +++ /dev/null @@ -1,47 +0,0 @@ -package cc.iotkit.server.handler; - -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.server.dao.DeviceEventRepository; -import cc.iotkit.model.device.message.DeviceEvent; -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.model.mq.Request; -import cc.iotkit.model.mq.Response; -import com.fasterxml.jackson.core.type.TypeReference; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.util.Map; - -@Component -public class PropertyReplyHandler implements MqttHandler, Response.Empty> { - - @Autowired - DeviceEventRepository deviceEventRepository; - - @Override - public boolean compliant(String topic) { - return topic.endsWith("/service/property/set_reply"); - } - - @Override - public Request> parse(String msg) { - return JsonUtil.parse(msg, new TypeReference>>() { - }); - } - - @Override - public Response.Empty handler(String topic, DeviceInfo device, Request> request) { - String identifier = "propertySetReply"; - DeviceEvent event = - DeviceEvent.builder() - .deviceId(device.getDeviceId()) - .identifier(identifier) - .request(request) - .type("ack") - .createAt(System.currentTimeMillis()) - .build(); - deviceEventRepository.save(event); - return null; - } - -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/RegisterHandler.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/RegisterHandler.java deleted file mode 100755 index 22f79da4..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/RegisterHandler.java +++ /dev/null @@ -1,36 +0,0 @@ -package cc.iotkit.server.handler; - -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.model.device.message.DeviceRegister; -import cc.iotkit.model.mq.Request; -import cc.iotkit.server.service.DeviceService; -import com.fasterxml.jackson.core.type.TypeReference; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class RegisterHandler implements MqttHandler { - - @Autowired - private DeviceService deviceService; - - @Override - public boolean compliant(String topic) { - return topic.endsWith("/register"); - } - - @Override - public Request parse(String msg) { - return JsonUtil.parse(msg, new TypeReference>() { - }); - } - - @Override - public DeviceRegister handler(String topic, DeviceInfo device, Request request) { - DeviceRegister regInfo = request.getParams(); - deviceService.register(device.getDeviceId(), regInfo.getProductKey(), - regInfo.getDeviceName(), regInfo.getModel()); - return regInfo; - } -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/ServiceReplyHandler.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/ServiceReplyHandler.java deleted file mode 100755 index 4e3c7c86..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/handler/ServiceReplyHandler.java +++ /dev/null @@ -1,49 +0,0 @@ -package cc.iotkit.server.handler; - -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.server.dao.DeviceEventRepository; -import cc.iotkit.model.device.message.DeviceEvent; -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.model.mq.Request; -import cc.iotkit.model.mq.Response; -import com.fasterxml.jackson.core.type.TypeReference; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.util.Map; -import java.util.regex.Pattern; - -@Component -public class ServiceReplyHandler implements MqttHandler, Response.Empty> { - - private static final Pattern MATCH_REG = Pattern.compile("^/sys/\\w+/\\w+/s/service/[^_/]+_reply$"); - - @Autowired - DeviceEventRepository deviceEventRepository; - - @Override - public boolean compliant(String topic) { - return MATCH_REG.matcher(topic).matches(); - } - - @Override - public Request> parse(String msg) { - return JsonUtil.parse(msg, new TypeReference>>() { - }); - } - - @Override - public Response.Empty handler(String topic, DeviceInfo device, Request> request) { - String identifier = topic.substring(topic.indexOf("/service/") + 9); - DeviceEvent event = DeviceEvent.builder() - .deviceId(device.getDeviceId()) - .identifier(identifier) - .request(request) - .type("ack") - .createAt(System.currentTimeMillis()) - .build(); - deviceEventRepository.save(event); - return null; - } - -} diff --git a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/Application.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/Application.java similarity index 90% rename from device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/Application.java rename to device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/Application.java index 5ab5413a..25c2b9fc 100755 --- a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/Application.java +++ b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/Application.java @@ -1,4 +1,4 @@ -package cc.iotkit.mqttauth; +package cc.iotkit.server.mqtt; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/config/AutobeanConfig.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/config/AutobeanConfig.java new file mode 100755 index 00000000..41fe6042 --- /dev/null +++ b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/config/AutobeanConfig.java @@ -0,0 +1,19 @@ +package cc.iotkit.server.mqtt.config; + +import cc.iotkit.protocol.client.DeviceBehaviourClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class AutobeanConfig { + + @Value("${gateway.server:}") + private String gatewayServer; + + @Bean + public DeviceBehaviourClient getDeviceBehaviourClient() { + return new DeviceBehaviourClient(gatewayServer); + } + +} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/controller/DeviceController.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/controller/DeviceController.java new file mode 100755 index 00000000..e2e1b2b0 --- /dev/null +++ b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/controller/DeviceController.java @@ -0,0 +1,47 @@ +package cc.iotkit.server.mqtt.controller; + +import cc.iotkit.common.utils.JsonUtil; +import cc.iotkit.protocol.DeviceGateway; +import cc.iotkit.protocol.DeviceMessage; +import cc.iotkit.protocol.OtaInfo; +import cc.iotkit.protocol.Result; +import cc.iotkit.server.mqtt.service.MqttManager; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +public class DeviceController implements DeviceGateway { + + @Autowired + private MqttManager mqttManager; + + @Override + public Result sendMessage(DeviceMessage msg) { + try { + MqttMessage mqttMessage = JsonUtil.parse(msg.getContent(), MqttMessage.class); + mqttManager.sendMsg(mqttMessage.getTopic(), mqttMessage.getPayload()); + return new Result(true, ""); + } catch (Throwable e) { + log.error("send message error", e); + return new Result(false, e.getMessage()); + } + } + + @Override + public Result sendOta(OtaInfo ota) { + return null; + } + + @Data + public static class MqttMessage { + + private String topic; + + private String payload; + + } + +} diff --git a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/controller/MqttAuthController.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/controller/MqttAuthController.java similarity index 58% rename from device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/controller/MqttAuthController.java rename to device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/controller/MqttAuthController.java index 3806f20e..3b3c79e5 100755 --- a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/controller/MqttAuthController.java +++ b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/controller/MqttAuthController.java @@ -1,15 +1,12 @@ -package cc.iotkit.mqttauth.controller; +package cc.iotkit.server.mqtt.controller; import cc.iotkit.common.Constants; import cc.iotkit.common.utils.CodecUtil; import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.mqttauth.model.EmqAcl; -import cc.iotkit.mqttauth.model.EmqAuthInfo; -import cc.iotkit.mqttauth.service.DeviceMqttAuth; -import cc.iotkit.mqttauth.service.MqttAuth; -import cc.iotkit.mqttauth.service.SysMqttAuth; -import cc.iotkit.mqttauth.service.WxMqttAuth; +import cc.iotkit.server.mqtt.model.EmqAcl; +import cc.iotkit.server.mqtt.model.EmqAuthInfo; +import cc.iotkit.server.mqtt.service.DeviceAuthService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; @@ -23,11 +20,7 @@ import javax.servlet.http.HttpServletResponse; public class MqttAuthController { @Autowired - private DeviceMqttAuth deviceMqttAuth; - @Autowired - private WxMqttAuth wxMqttAuth; - @Autowired - private SysMqttAuth sysMqttAuth; + private DeviceAuthService deviceAuthService; @PostMapping("/mqtt/auth") public void auth(@RequestBody EmqAuthInfo auth) { @@ -36,27 +29,22 @@ public class MqttAuthController { if (isSupperUser(clientId)) { return; } - MqttAuth mqttAuth = getMqttAuth(clientId); - mqttAuth.auth(auth); + deviceAuthService.auth(auth); } @PostMapping("/mqtt/acl") public void acl(@RequestBody EmqAcl acl) { - log.info("mqtt acl:" + JsonUtil.toJsonString(acl)); + log.info("mqtt acl:{}", JsonUtil.toJsonString(acl)); if (isSupperUser(acl.getClientid())) { return; } - MqttAuth mqttAuth = getMqttAuth(acl.getClientid()); - mqttAuth.acl(acl); + deviceAuthService.acl(acl); + log.info("topic:{}, acl success", acl.getTopic()); } @PostMapping("/mqtt/superuser") public void superuser(@RequestBody EmqAcl acl, HttpServletResponse response) { response.setStatus(HttpServletResponse.SC_BAD_GATEWAY); -// log.info("mqtt superuser:" + JsonUtil.toJsonString(acl)); -// if (!isSupperUser(acl.getClientid())) { -// throw new RuntimeException("superuser check false."); -// } } public boolean isSupperUser(String clientId) { @@ -72,13 +60,4 @@ public class MqttAuthController { } } - private MqttAuth getMqttAuth(String clientId) { - if (clientId.startsWith("wx_")) { - return wxMqttAuth; - } else if (clientId.startsWith("sy_")) { - return sysMqttAuth; - } - return deviceMqttAuth; - } - } diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/handler/DisconnectedHandler.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/handler/DisconnectedHandler.java new file mode 100755 index 00000000..4a9206ef --- /dev/null +++ b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/handler/DisconnectedHandler.java @@ -0,0 +1,41 @@ +package cc.iotkit.server.mqtt.handler; + +import cc.iotkit.common.utils.JsonUtil; +import cc.iotkit.protocol.client.DeviceBehaviourClient; +import com.fasterxml.jackson.core.type.TypeReference; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class DisconnectedHandler { + + @Autowired + private DeviceBehaviourClient behaviourClient; + + public void handler(String msg) { + Disconnected disconnected = JsonUtil.parse(msg, new TypeReference() { + }); + String clientId = disconnected.getClientid(); + String[] parts = clientId.split("_"); + if (parts.length < 2) { + return; + } + String pk = parts[0]; + String dn = parts[1]; + behaviourClient.offline(pk, dn); + log.info("client disconnected, offline,pk:{},dn:{}", pk, dn); + } + + @Data + private static class Disconnected { + private String reason; + private String clientid; + private String username; + private String peername; + private String sockname; + } + +} diff --git a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/model/EmqAcl.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/EmqAcl.java similarity index 85% rename from device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/model/EmqAcl.java rename to device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/EmqAcl.java index 8fd1138f..f4cdbee4 100755 --- a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/model/EmqAcl.java +++ b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/EmqAcl.java @@ -1,4 +1,4 @@ -package cc.iotkit.mqttauth.model; +package cc.iotkit.server.mqtt.model; import lombok.Data; diff --git a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/model/EmqAuthInfo.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/EmqAuthInfo.java similarity index 84% rename from device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/model/EmqAuthInfo.java rename to device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/EmqAuthInfo.java index 2673f1e1..1ca3f4d5 100755 --- a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/model/EmqAuthInfo.java +++ b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/EmqAuthInfo.java @@ -1,4 +1,4 @@ -package cc.iotkit.mqttauth.model; +package cc.iotkit.server.mqtt.model; import lombok.Data; diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/Request.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/Request.java new file mode 100755 index 00000000..1b365b70 --- /dev/null +++ b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/Request.java @@ -0,0 +1,17 @@ +package cc.iotkit.server.mqtt.model; + + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@JsonIgnoreProperties(ignoreUnknown = true) +public class Request { + protected String id; + + protected T params; +} \ No newline at end of file diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/Response.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/Response.java new file mode 100755 index 00000000..5a9d9421 --- /dev/null +++ b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/Response.java @@ -0,0 +1,25 @@ +package cc.iotkit.server.mqtt.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Response { + + private String id; + + private int code; + + private T data; + + public static Empty empty() { + return new Empty(); + } + + @Data + public static class Empty { + } +} diff --git a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/DeviceMqttAuth.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/service/DeviceAuthService.java similarity index 67% rename from device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/DeviceMqttAuth.java rename to device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/service/DeviceAuthService.java index cfffe3ff..f4f30a7d 100755 --- a/device-server/mqtt-auth/src/main/java/cc/iotkit/mqttauth/service/DeviceMqttAuth.java +++ b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/service/DeviceAuthService.java @@ -1,9 +1,12 @@ -package cc.iotkit.mqttauth.service; +package cc.iotkit.server.mqtt.service; import cc.iotkit.common.Constants; -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.mqttauth.model.EmqAcl; -import cc.iotkit.mqttauth.model.EmqAuthInfo; +import cc.iotkit.common.utils.JsonUtil; +import cc.iotkit.protocol.RegisterInfo; +import cc.iotkit.protocol.Result; +import cc.iotkit.protocol.client.DeviceBehaviourClient; +import cc.iotkit.server.mqtt.model.EmqAcl; +import cc.iotkit.server.mqtt.model.EmqAuthInfo; import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang3.StringUtils; @@ -11,14 +14,13 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Slf4j -@Component("DeviceMqttAuth") -public class DeviceMqttAuth implements MqttAuth { +@Component +public class DeviceAuthService { + @Autowired - private DeviceService deviceService; + private DeviceBehaviourClient behaviourClient; - @Override public void auth(EmqAuthInfo auth) { - String clientId = auth.getClientid(); String[] pkDnAndModel = getPkDnAndModel(clientId); @@ -27,25 +29,19 @@ public class DeviceMqttAuth implements MqttAuth { throw new RuntimeException("password is illegal."); } - DeviceInfo device = new DeviceInfo(); - device.setProductKey(pkDnAndModel[0]); - device.setDeviceName(pkDnAndModel[1]); - device.setModel(pkDnAndModel[2]); - deviceService.register(device); + String pk = pkDnAndModel[0]; + String dn = pkDnAndModel[1]; + String model = pkDnAndModel[2]; + + Result result = behaviourClient.register(new RegisterInfo(pk, dn, model)); + log.info("register result:{}", JsonUtil.toJsonString(result)); } - @Override public void acl(EmqAcl acl) { String[] pkDn = getPkDnFromTopic(acl.getTopic()); String pk = pkDn[2]; String dn = pkDn[3]; - DeviceInfo device = deviceService.getByPkAndDn(pk, dn); - if (device == null) { - log.error("the device is not registered,pk:{},dn:{}", pk, dn); - return; - } - - deviceService.online(pk, dn); + behaviourClient.online(pk, dn); } private String[] getPkDnAndModel(String clientId) { diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/service/MqttManager.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/service/MqttManager.java new file mode 100755 index 00000000..f2bf9bee --- /dev/null +++ b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/service/MqttManager.java @@ -0,0 +1,256 @@ +package cc.iotkit.server.mqtt.service; + +import cc.iotkit.common.Constants; +import cc.iotkit.common.utils.CodecUtil; +import cc.iotkit.common.utils.JsonUtil; +import cc.iotkit.protocol.DeviceMessage; +import cc.iotkit.protocol.RegisterInfo; +import cc.iotkit.protocol.client.DeviceBehaviourClient; +import cc.iotkit.server.mqtt.handler.DisconnectedHandler; +import cc.iotkit.server.mqtt.model.Request; +import cc.iotkit.server.mqtt.model.Response; +import com.fasterxml.jackson.core.type.TypeReference; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.eclipse.paho.client.mqttv3.*; +import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.HashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +@Slf4j +@Component +public class MqttManager implements MqttCallback, IMqttMessageListener { + + @Value("${mqtt.url}") + private String url; + + @Value(("${spring.profiles.active:}")) + private String env; + + private MqttClient mqttClient; + + @Autowired + private DisconnectedHandler disconnectedHandler; + @Autowired + private DeviceBehaviourClient behaviourClient; + + public MqttManager() { + ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); + executorService.scheduleWithFixedDelay(this::createClient, 1, 3, TimeUnit.SECONDS); + } + + private MqttConnectOptions getMqttConnectOptions() { + MqttConnectOptions options = new MqttConnectOptions(); + // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录, + // 这里设置为true表示每次连接到服务器都以新的身份连接 + options.setCleanSession(true); + // 设置连接的用户名 + options.setUserName("admin"); + // 设置连接的密码 + options.setPassword("password".toCharArray()); + options.setServerURIs(StringUtils.split(url, ",")); + // 设置超时时间 单位为秒 + options.setConnectionTimeout(10); + // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送心跳判断客户端是否在线,但这个方法并没有重连的机制 + options.setKeepAliveInterval(20); + return options; + } + + @SneakyThrows + private void createClient() { + try { + if (mqttClient == null) { + MemoryPersistence persistence = new MemoryPersistence(); + String clientId = "mqtt-server-consumer-" + env; + clientId = "su_" + CodecUtil.aesEncrypt("admin_" + clientId, Constants.MQTT_SECRET); + mqttClient = new MqttClient(url, clientId, persistence); + mqttClient.setCallback(this); + } + if (mqttClient.isConnected()) { + return; + } + connect(); + } catch (Throwable e) { + log.error("create mqttClient error", e); + } + } + + private void connect() { + try { + log.info("Connecting to broker:{} ", url); + IMqttToken mqttToken = mqttClient.connectWithResult(getMqttConnectOptions()); + if (mqttToken.isComplete()) { + log.info("connect mqtt-broker success"); + } else { + log.error("connect mqtt-broker failed", mqttToken.getException()); + } + IMqttToken response = mqttClient.subscribeWithResponse( + new String[]{"/sys/+/+/s/#", "/sys/session/topic/unsubscribed", "/sys/client/disconnected"}); + if (response.isComplete()) { + log.info("subscribe topics success"); + } else { + log.error("subscribe topics failed", mqttToken.getException()); + } + } catch (Throwable e) { + log.error("connect to mqtt-broker error", e); + } + } + + @SneakyThrows + @Override + public void connectionLost(Throwable e) { + log.error("mqtt connection lost", e); + while (true) { + try { + Thread.sleep(1000); + if (mqttClient.isConnected()) { + mqttClient.disconnect(); + } + connect(); + break; + } catch (Throwable e1) { + log.error("connect error,retry...", e1); + } + } + } + + @Override + public void messageArrived(String topic, MqttMessage mqttMessage) { + handleMessage(topic, mqttMessage); + } + + @Override + public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) { + } + + public void handleMessage(String topic, MqttMessage msg) { + log.info("receive msg,topic:{},msg:{}", topic, JsonUtil.toJsonString(msg)); + if (topic == null) { + log.error("message topic is null."); + return; + } + int code = 0; + String mid = ""; + + try { + String payload = new String(msg.getPayload()); + + //取消订阅 + if (topic.equals("/sys/session/topic/unsubscribed")) { + topicUnsubscribed(payload); + return; + } + + //连接断开 + if (topic.equals("/sys/client/disconnected")) { + disconnectedHandler.handler(payload); + return; + } + + String[] parts = topic.split("/"); + if (parts.length < 5) { + log.error("message topic is illegal."); + return; + } + String productKey = parts[2]; + String deviceName = parts[3]; + + //子设备注册 + if (topic.endsWith("/register")) { + RegisterRequest registerRequest = JsonUtil.parse(payload, RegisterRequest.class); + mid = registerRequest.getId(); + + RegisterInfo registerInfo = RegisterInfo.builder() + .productKey(productKey) + .deviceName(deviceName) + .subDevices(Collections.singletonList(registerRequest.getParams())) + .build(); + behaviourClient.register(registerInfo); + return; + } + + Request request = JsonUtil.parse(payload, Request.class); + mid = request.getId(); + MqtMsg mqtMsg = new MqtMsg(topic, request); + + behaviourClient.messageReport(DeviceMessage.builder() + .productKey(productKey) + .deviceName(deviceName) + .mid(request.getId()) + .content(JsonUtil.toJsonString(mqtMsg)) + .build()); + + } catch (Throwable e) { + log.error("message process error", e); + code = 500; + } finally { + reply(topic, mid, code); + } + + } + + @SneakyThrows + private void reply(String topic, String id, int code) { + //回复消息不需要再回复 + if (topic.endsWith("_reply")) { + return; + } + + topic = topic.replace("/s/", "/c/") + "_reply"; + String msg = JsonUtil.toJsonString(new Response<>(id, code, new HashMap<>())); + mqttClient.publish(topic, new MqttMessage(msg.getBytes())); + } + + private void topicUnsubscribed(String msg) { + Unsubscribed unsubscribed = JsonUtil.parse(msg, new TypeReference() { + }); + String topic = unsubscribed.getTopic(); + String[] parts = topic.split("/"); + if (parts.length < 4) { + return; + } + + log.info("device offline,pk:{},dn:{}", parts[2], parts[3]); + behaviourClient.offline(parts[2], parts[3]); + } + + @SneakyThrows + public void sendMsg(String topic, String msg) { + mqttClient.publish(topic, new MqttMessage(msg.getBytes())); + } + + @Data + private static class Unsubscribed { + private String clientid; + private String username; + private String topic; + private String peerhost; + } + + public static class RegisterRequest extends Request { + + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + private static class MqtMsg { + + private String topic; + + private Object payload; + + } + +} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/service/DeviceService.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/service/DeviceService.java deleted file mode 100755 index fdfc0bea..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/service/DeviceService.java +++ /dev/null @@ -1,219 +0,0 @@ -package cc.iotkit.server.service; - -import cc.iotkit.common.exception.BizException; -import cc.iotkit.common.exception.NotFoundException; -import cc.iotkit.common.exception.OfflineException; -import cc.iotkit.common.utils.DeviceUtil; -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.common.utils.UniqueIdUtil; -import cc.iotkit.deviceapi.IDeviceManager; -import cc.iotkit.deviceapi.IDeviceService; -import cc.iotkit.deviceapi.Service; -import cc.iotkit.model.device.message.DeviceEvent; -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.model.product.ThingModel; -import cc.iotkit.model.mq.Request; -import cc.iotkit.server.dao.DeviceDao; -import cc.iotkit.server.dao.DeviceEventRepository; -import cc.iotkit.server.dao.DeviceRepository; -import cc.iotkit.server.dao.ThingModelRepository; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.RandomUtils; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; - -import java.util.HashMap; -import java.util.Map; - -@Slf4j -@RestController -public class DeviceService implements IDeviceManager, IDeviceService { - - @Autowired - private DeviceDao deviceDao; - @Autowired - private DeviceRepository deviceRepository; - @Autowired - private ThingModelRepository thingModelRepository; - @Autowired - private ThingModelService thingModelService; - @Autowired - private DeviceEventRepository deviceEventRepository; - - @Autowired - private IMqttSender mqttSender; - - private static final String identifier_set = "property/set"; - - @Override - public DeviceInfo register(String parentId, String productKey, String deviceName, String model) { - DeviceInfo device = new DeviceInfo(); - device.setParentId(parentId); - device.setProductKey(productKey); - device.setDeviceName(deviceName); - device.setModel(model); - - DeviceInfo parentDevice = deviceDao.getByDeviceId(parentId); - if (parentDevice == null) { - throw new BizException("Parent device does not exist"); - } - String uid = parentDevice.getUid(); - - DeviceInfo deviceInfo = deviceDao.getByPkAndDn(productKey, deviceName); - if (deviceInfo != null) { - device.setId(deviceInfo.getId()); - device.setDeviceId(deviceInfo.getDeviceId()); - device.setUid(uid); - deviceDao.updateDevice(device); - log.info("device register update:{}", JsonUtil.toJsonString(device)); - return deviceInfo; - } - - String deviceId = newDeviceId(deviceName); - - device.setId(deviceId); - device.setDeviceId(deviceId); - device.setUid(uid); - deviceDao.addDevice(device); - log.info("device registered:{}", JsonUtil.toJsonString(device)); - return device; - } - - @Override - public void unbind(String deviceId) { - log.info("start unbind device,deviceId:{}", deviceId); - - DeviceInfo device = deviceRepository.findById(deviceId) - .orElseThrow(() -> new RuntimeException("no device found by deviceId:" + deviceId)); - - String gatewayId = device.getParentId(); - DeviceInfo gateway = deviceRepository.findById(gatewayId) - .orElseThrow(() -> new RuntimeException("no device found by deviceId:" + deviceId)); - - //数据库解绑 - device.setParentId(""); - deviceRepository.save(device); - - //网关注销 - String topic = "/sys/" + gateway.getProductKey() + "/" + gateway.getDeviceName() + "/c/service/deregister"; - String requestId = UniqueIdUtil.newRequestId(); - Map params = new HashMap<>(); - params.put("productKey", device.getProductKey()); - params.put("deviceName", device.getDeviceName()); - CmdRequest request = new CmdRequest(requestId, params); - String msg = JsonUtil.toJsonString(request); - log.info("start send mqtt msg,topic:{},payload:{}", topic, msg); - mqttSender.sendToMqtt(topic, msg); - } - - @Override - public String invoke(Service service) { - return sendMsg(service); - } - - @Override - public String setProperty(String deviceId, @RequestBody Map properties) { - return sendMsg(deviceId, identifier_set, properties); - } - - @Override - public String invokeService(String deviceId, String identifier, Map properties) { - return sendMsg(deviceId, identifier, properties); - } - - public void offline(String pk, String dn) { - DeviceInfo device = new DeviceInfo(); - device.setProductKey(pk); - device.setDeviceName(dn); - - device.getState().setOnline(false); - device.getState().setOfflineTime(System.currentTimeMillis()); - deviceDao.updateDeviceByPkAndDn(device); - log.info("device offline,pk:{},dn:{}", pk, dn); - } - - public String sendMsg(String deviceId, String service, Map args) { - DeviceInfo device = deviceRepository.findById(deviceId) - .orElseThrow(() -> new NotFoundException("device not found by deviceId")); - - return this.sendMsg(device, service, args); - } - - public String sendMsg(DeviceInfo device, String service, Map args) { - if (device.getState() == null || device.getState().getOnline() != Boolean.TRUE) { - throw new OfflineException("device is offline"); - } - - String pk = device.getProductKey(); - String dn = device.getDeviceName(); - - ThingModel thingModel = thingModelRepository.findById(pk) - .orElseThrow(() -> new NotFoundException("device thingModel not found")); - - String topic = "/sys/" + pk + "/" + dn + "/c/service/" + service; - String requestId = UniqueIdUtil.newRequestId(); - - //参数类型转换 - args = thingModelService.paramsParse(thingModel, service, args); - - CmdRequest request = new CmdRequest(requestId, args); - String msg = JsonUtil.toJsonString(request); - log.info("start send mqtt msg,topic:{},payload:{}", topic, msg); - mqttSender.sendToMqtt(topic, msg); - - //记录下行日志 - DeviceEvent deviceEvent = DeviceEvent.builder() - .deviceId(device.getDeviceId()) - .identifier(service.replace("property/set", "propertySet")) - .type("service") - .request(new Request<>(requestId, args)) - .createAt(System.currentTimeMillis()) - .build(); - deviceEventRepository.save(deviceEvent); - - return requestId; - } - - public String sendMsg(Service service) { - DeviceUtil.PkDn pkDn = DeviceUtil.getPkDn(service.getDevice()); - DeviceInfo deviceInfo = deviceDao.getByPkAndDn(pkDn.getProductKey(), pkDn.getDeviceName()); - if ("set".equals(service.getIdentifier())) { - return sendMsg(deviceInfo.getDeviceId(), identifier_set, service.parseInputData()); - } else { - return sendMsg(deviceInfo.getDeviceId(), service.getIdentifier(), service.parseInputData()); - } - } - - /** - * 1-13位 时间戳 - * 14-29位 deviceNae,去除非字母和数字,不足16位补0,超过16位的mac取后16位,共16位 - * 30-31位 mac长度,共2位 - * 32位 随机一个0-f字符 - */ - private static String newDeviceId(String deviceNae) { - int maxDnLen = 16; - String dn = deviceNae.replaceAll("[^0-9A-Za-z]", ""); - if (dn.length() > maxDnLen) { - dn = dn.substring(dn.length() - maxDnLen); - } else { - dn = (dn + "00000000000000000000").substring(0, maxDnLen); - } - String len = StringUtils.leftPad(deviceNae.length() + "", 2, '0'); - String rnd = Integer.toHexString(RandomUtils.nextInt(0, 16)); - return (System.currentTimeMillis() + "0" + dn + len + rnd).toLowerCase(); - } - - - @Data - @NoArgsConstructor - @AllArgsConstructor - private static class CmdRequest { - private String id; - private Object params; - } -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/service/IMqttSender.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/service/IMqttSender.java deleted file mode 100755 index 9831e409..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/service/IMqttSender.java +++ /dev/null @@ -1,40 +0,0 @@ -package cc.iotkit.server.service; -import cc.iotkit.server.config.MqttConfig; -import org.springframework.integration.annotation.MessagingGateway; -import org.springframework.integration.mqtt.support.MqttHeaders; -import org.springframework.messaging.handler.annotation.Header; -import org.springframework.stereotype.Component; - -@Component -@MessagingGateway(defaultRequestChannel = MqttConfig.CHANNEL_NAME_OUT) -public interface IMqttSender { - - /** - * 发送信息到MQTT服务器 - * - * @param data 发送的文本 - */ - void sendToMqtt(String data); - - /** - * 发送信息到MQTT服务器 - * - * @param topic 主题 - * @param payload 消息主体 - */ - void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, - String payload); - - /** - * 发送信息到MQTT服务器 - * - * @param topic 主题 - * @param qos 对消息处理的几种机制。
0 表示的是订阅者没收到消息不会再次发送,消息会丢失。
- * 1 表示的是会尝试重试,一直到接收到消息,但这种情况可能导致订阅者收到多次重复消息。
- * 2 多了一次去重的动作,确保订阅者收到的消息有一次。 - * @param payload 消息主体 - */ - void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, - @Header(MqttHeaders.QOS) int qos, - String payload); -} \ No newline at end of file diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/service/ThingModelService.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/service/ThingModelService.java deleted file mode 100755 index c0e47c53..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/service/ThingModelService.java +++ /dev/null @@ -1,60 +0,0 @@ -package cc.iotkit.server.service; - -import cc.iotkit.model.product.ThingModel; -import org.springframework.stereotype.Component; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@Component -public class ThingModelService { - - public Map paramsParse(ThingModel thingModel, String identifier, Map params) { - Map parsedParams = new HashMap<>(); - ThingModel.Model model = thingModel.getModel(); - - //属性设置 - if ("property/set".equals(identifier)) { - List properties = model.getProperties(); - if (properties == null) { - return parsedParams; - } - return parseProperties(properties, params); - } else { - //服务调用 - Map services = model.serviceMap(); - ThingModel.Service service = services.get(identifier); - if (service == null) { - return parsedParams; - } - List parameters = service.getInputData(); - return parseParams(parameters, params); - } - } - - private Map parseParams(List parameters, Map params) { - Map parsed = new HashMap<>(); - parameters.forEach((p -> parseField(p.getIdentifier(), p.getDataType(), params, parsed))); - return parsed; - } - - private Map parseProperties(List properties, Map params) { - Map parsed = new HashMap<>(); - properties.forEach((p -> parseField(p.getIdentifier(), p.getDataType(), params, parsed))); - return parsed; - } - - private void parseField(String identifier, ThingModel.DataType dataType, Map params, Map parsed) { - Object val = params.get(identifier); - if (val == null) { - return; - } - Object result = dataType.parse(val); - if (result == null) { - return; - } - parsed.put(identifier, result); - } - -} diff --git a/device-server/pom.xml b/device-server/pom.xml index e5077655..6693a251 100755 --- a/device-server/pom.xml +++ b/device-server/pom.xml @@ -12,7 +12,6 @@ device-server pom - mqtt-auth mqtt-server device-api mqtt-client-simulator diff --git a/log/error.2022-03-14.0.gz b/log/error.2022-03-14.0.gz new file mode 100755 index 0000000000000000000000000000000000000000..395381df7f2a46e41fe5b384775bc534244ca24d GIT binary patch literal 4041 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 a+Vh;*U*DnzJLu<5Sp!K)y%kQdvHk-W8<1fD literal 0 HcmV?d00001 diff --git a/log/error.2022-03-15.0.gz b/log/error.2022-03-15.0.gz new file mode 100644 index 0000000000000000000000000000000000000000..b307f51a54733e2883ab52e5b7d9d5b2e59b4025 GIT binary patch literal 20999 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 literal 0 HcmV?d00001 diff --git a/log/error.2022-03-16.0.gz b/log/error.2022-03-16.0.gz new file mode 100644 index 0000000000000000000000000000000000000000..d5f2d074e9b9013294d288a382b77de2e23b1c6f GIT binary patch literal 7595 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 literal 0 HcmV?d00001 diff --git a/log/error.2022-03-18.0.gz b/log/error.2022-03-18.0.gz new file mode 100644 index 0000000000000000000000000000000000000000..ae23775520f0d58c589998acb988de7da048fdcc GIT binary patch literal 14387 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 AE&u=k literal 0 HcmV?d00001 diff --git a/log/info.2022-03-14.0.gz b/log/info.2022-03-14.0.gz new file mode 100755 index 0000000000000000000000000000000000000000..e1a670e8e3f8fbc5dc1385142ea56cf2ff78b055 GIT binary patch literal 36764 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 literal 0 HcmV?d00001 diff --git a/log/info.2022-03-15.0.gz b/log/info.2022-03-15.0.gz new file mode 100644 index 0000000000000000000000000000000000000000..7053b26e66e542029b948005ce8d2d076718420b GIT binary patch literal 43469 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 DKWz5Y literal 0 HcmV?d00001 diff --git a/log/info.2022-03-16.0.gz b/log/info.2022-03-16.0.gz new file mode 100644 index 0000000000000000000000000000000000000000..f93541e9a69ce1f54311833f079fd2ee2f847ee7 GIT binary patch literal 44742 zcma&NWpo@(lQk$=WHB={Gqc6a%*Sn~f6&b|QpTYj~Iq!CGBA02UdhkBg+Q+n&It|4beZ=0ZSkaWx*vP7= zTufD;>!iVe8yPQ7F~CS3ke4lSb_Y2Z2+ZgRbR z$Msbdr(l<%8X?InR;?_rI7u2FkDylk!Q-q5M5lJsSVC6c`_hCtVSjS9L{?cvKYG%+ zBuoSNoz?2{^=rPLa+EN4!1`-BBzR=`dX| z-OW_h0Mm?J>cA@}e+hCX72%WC(!L{`+0GZ*2Vbo#?wHM&pJNoyeqXtyrMY3>YF)6c zmPS`jU}4%kpM+wePfT9s7IxfS&0l62y_b6?Pz{Kn5VB>!_y?lgH;TnQps*N7 zte8yS&vD46Vz5dU%=T#I(@4s00Po^z<-DKfiWHz#sL@gnD7e>bqza@nQP}66M zKF0xBpOEt1{L3d7qWffy$)um}&a-DgtpV^*S2Xt`df{lWu{9I!=+_MzY+z*G^QZzE z5~>O{?nA#n6o9_asC0z{iOqtAP6KxI*RJo3(L|raVl+NK>h{yS&?owDf$-#Hyxuzb zF$I+Q`P6lW#NC0eG9pQ`3ALqBK|jDR7Sb6`ORfff)o&?5>@BB!w2 z^Q$}>Mv5hTT@NmR3=Kglw((o&44%q|fHs?b@HHVQ1T#HPiX#@M?1q2;u5Tz7>QoTA z(Wa6Wf`?@s>9VSFkzC+%BsQ|*{v$1V60HPLLrLy3fS8{bDhA@$CAe+gDiw`&P!y^a zjUiuGl3_6gAq}r=(M-{mt(*+B7DY+pF~VE+F%zyIbaSSXV|{DA!Y6C)82r`DeG1sH z=6m0Fk@-mIZ!~X~#G^D{#c57aOfcNjB-K5(rdU-nB=jKjF_6*eqLaX?QU@DP7tWWQ znHB4Pwx+d|&8yK`gSXh^&y`lvbJMCA?tRhVs4IMh(~zmc+eR^XBr1>rUk{tMt{Euq z3ejPX{>E_w^YeZ-460xixr|&>Mr>Y30aY1Y4LD(wpEWONHmR9>8=AsTatP2yZ`2*!PQ2O=pwamyD`Lk!VMCM#GB9Yx^Xh{YL*#Mkfshy z*w!`jYJn3$M%+<{?KIL_r4~3sKiL2#SXyj+{E_ynwlIN_)XyX9zF^u;4MnjEtItgm z`^`_sjIrR;(YW|Yo%1^2kK)hDdYQzSSNqf1F@S50^$W>)yYI$~doxh2k)gIicfZxm z)GUyVB6^;R5};q^qa4x!W_VxQM-itHp8-I1Lw&C-@#86k`Wi{-BTkuSfH>+bJ}xv2X?YYx zklYoz4`Gnn0bLWEhb(+Eq&I4_DM*<|cBv2b($t*xbv)(-L7%K2AT}WHbt^T>W&l;2 zx2-E<@m?cZk^zrJQGVY}^Ih?K4d1qudeB`&L6jHwa*?+@7E&JsxKbIvJp24&f?e>>$6S z?6e*0$szyKvhH>s|HqANt=H|RH*Xv<@zJv`Nc6ki_fFxS*PS8HSM`FTpHRzfU=l94 zTjC=uz72NeS1`baSG$rg3=8Th#PO3`j0CqFs-cZ~3$e#B5NWEcBDsVwJGO+S9_=K{}&`0)YiV6Pex~%mU zGx#FW%}Pf&89BbJHP$xzUH;*g4es$&4&|P<5=Shah_62gzNB#7V8{TjK3q1a3Kez< z-hva+?*SnIPf!%%EgG_P1VR7y>-XZ4ABctc!uUvEC14XEk1wRQ2L{Apa}D;l1YTp~ z{Z&&W1Rry^D0y{JNa$ZedcM?)_?qSA?>2KNe3bU|BPdkYtNp?CeQtj;MS((f!ye!D z$AO#~Gbw|BFm*b-ZPt}?J*!BoYkL38bwq<;_BMKXlh_OP?O^%dm`Bmk(KrjA@tIYG zp?qV$n$u26q&v=MhZmwDpKky|9d9$^vdED*Y+Iag&uBJ8P=qwD7tcR3#3W6wwo-pi zUrC^dmJp7it8Vu-`SYFvpO;lst-hpSQHeg;2Jo3EE64CP&+2gttKL& zZ9d@2I_;UoDU&fk=mGx%{CPVh*)hqF=wZdv;zSEGu?VFZO)eh?;b_tN+GCCuaQ0X` zOqrv7?E5CQ2v22P_2bfBD*X=-`W<%76>@(p#Eq1>^NPCAFabfOH(zjv1)Im;zJEig zZzG@N)Z;o+WFA-igp-3h+VMr_o(rayzNC0S)aa%sT~x$|I<7zY^Pt&hjji#Up1W4bi zwE^qzb|u&)%ke5Z1|^>mf3mz~^aBNXRNm(9kE$$>=VF~Ia}ZS4#S@bL( z-&TmXv0L|A8yS|=qhNr6KADiq}&G#XuQ?mzP1;QOZ^B_CtP#A5+Bh5$?&K4rC zJYc(^JYqNH_NM9rt zN!xyc%=K5*56RhrGka%bfnXvW?A7A6Wi6f?eJVm?H)j3TXYB`@j$_p|qd7E{mFQ8c z>H`HQj3e~LH9A;-VE@qcR1yWWy{Ckk=I;&9kypdFBa`nFf2x#-1gdUo7}v&jTD$6&|Jn`$vowbZ_6`DLX(w8kC93+mR}szs72v-XE?4MAx|9b>lks?FLD83M0lR;vg5>jg`NZDf?cbjCxovx zE?Q7{mYt(jx3|QTP-y{T{cFJxurd3nPeqS5KN`7aDdFvxg>&AIR%TXKvgh`S#^#7O zY3t$@x4QULm;#lVnBpgyk9r=f_xaj#1^MaE$tyXDUCksh95fDiKIth9+WXtoqdV&f z>!yg6B_Kl1fB5r(xg8)`YH}gzP6fEu8=Bs|xhFS7lNU2x`UU5gUMvAeoW zCrPS2L0Z!iOrl@Yc()e(otaTjKO^Mpf$^1-Z?Z#>`_J|*WK;O69s+ugAU^Qw{k@0n zJluY9{~IgeW?v^u&J*~m!2uOD_OvIhZv-n%?>oM2l-a{wgmnfhNwbPP41KYRyikUmA1^xb3`+$8X(9`&Kk1c)aj{@Z4fMd| zTtD+bIilhU(I`cWgcg)U#~dkKJ94y)AL!+NWw#Br5D=9RSwC#Wu<(xiiljPM6Rw6T zrI-0TbB{ZeLH9Ogpt;+Dc4(EO2i5Wj-2GQ&BKIjf)YC!txoIx#hX13xs@x3vTjyRO^nwcj!eX`XiM7%tk<75sY zxLH+FE=?%kyU4jGmtf^A+%+simcxVASGKha@@L(P=6)HxyyENsF@mUgMnYS>SxoPd zh%e}ICZC73W}hfxm1dt#&3?!TOui#bX#B*0}qUluoi2HS^3P_`CUaT~{Pts>)|k%2X!<0gUKp2rVV6;!Sedn23`V(my%VwA05L#jAafe?(a* zw|HF10{MWuC>yR&^&F9C$$Jl{zq(;f3BT!%+NvVYA4Iqh0)Tv*a7~uMPBJR?avN!d z)uPpAB!m+_JeUnNoDuF3#FofSmZVM+yeOU%Vy;C%07296`HYt-p8Dt4H_-V! z20(KmLeNmlNt73c9_1pdu^9zPCb1K|8w-=C9MD+Cbc0OB=U~1ZK5X$Y(w!htxf%d& zx}mz@6sy5i0__M5O4#lF(zlJkbd+3ODs@B&+DMov! za)~oBwm?dvdJnN_K1BO*9&O{FshmmLWpf)LY+5+|&PzT`kYxCIS~!P~(I_rp~n-y$4o)x3a21)=8z z=$qL&TcS`oi)y`SZI~y{!p;|RbtIsJqa5!k$s+4`?#owz>5^1+QEUSND*KK#Jw}+wVli^c4}RPt!htpN}VIzu-1P~-v8B<6i@x^ zr4$-JR4OcH{cZ{2C!pC)+n9IP{^V6{5~p`{jm7XT#3z*7<)u0Ml#3Os^cZoG)+)J9 zWh8LM^|ZU9pQb6YS0$EaH}}K?lA~T4czFeAW3G_(95F#+&c64%n<%l!`95Jf%=0DI zegHj)*s1A3?mgnzLXwLb+R-QuA+U-QRtdgs*4d|e=QzO3AZNlLOwEH^qNY>!pw+Q>lSGgVo>9#{drGI7z37Dzek?MD z4ZMtt9fy$kek9_9!t@icYKtru`AdiBpcRgIo7+#KcRXu9 z5)|}H=c%^Pqd4!5-#vG&zD!#(p~)OFGRZ0b8b4VMnT$&Yt^be`Jx-{7dKw2F8gW93Np@A?RN}o zpN+Go1IP!tq;E=?ZsB}w&)BG+tUV;saqn?u3*_rFjj?FTj4e?~!3pbZmNSIEhy^|T zN}2gtNj*m8bd&z$ySTFZ2={8t)`!oSP|nfXbKxM&BxKzN(G}X*v7T8&RL?%lo6RCs zT{Lv)SP~9Y>miphDEg1{t>O%!tNa)m0^!xw9X0#;dxm@SLM}ZUr&GEPOdmtx8Cg%9 z`QpMbjF}6!M5*yewH|}a5DM$Np6Md1c$)NeE7zh`L=Yt?ggxEZ^2U2j_+t}i;0|6?JvneE; zF&a*h>L2apCe6$?cOs;5{fS^r_ z`6BjfKUk%lTa9J;+Tr&GP3=>1^%TVI+Dvpw5xlVLuXMYoXUhFF0c-w0MorRhvK+N} zPxHS!k0Vtat)HwKJ&Cq682U%O;%k)nQE=*J7cgNehSNY zIhO)#5s88Z1=k-w8WVMrG+ow1N=kXveu{rhE)r$TglC+FvhCqZds1UFg+=7((hMQ( zmcr=LEaW~ttw|Ev!!nHt+e(&vD^+rhKU55#P&_On&^}0Is1jSZI#54`Z=+)V-P?6l~ca|b`!pLmKz#7Jym1=FBtr$aO&JJQZl;%OG?{<#(uAgJW@h*8gM6G6!ffciJga+>CBsxGi@&e$`= z76QMnlYQGSh;+xOG+RV)r!~zvs#O5_;%lr_1x=itqnwH+87L|^($;J)Y5-f8NEg8a zVvj8+L^q>cNF43-Mpa-M;!Ik_E#nbSqBMvb;1-j6 zepkglT^pv)tq_mwn*rLHZSgnOj`U$I&e8WX&>duSvm#Em&>G@MX9-Eg@6pfFDgx|4 ziF1@o;;^{}?JTXYB{s&r^zgqjm=sVtkPyg6hq6J#_B2j>>q71~68n|TsEF<^2`C|> zpYpHq;{!@?ZSjWPQFEOrd9?=l{U6T)5A-{4wRs8U73h6KfP9+WRE;)&+W&gDl%H&o zQFkB}$oCJ)0wqijx%&v)bPxD*Xsc?muM;4Gqr)dL2+%d}plXQw2d)c$Ck>2W)q}EBY*tXi06IAQ<6_o?+;>nMs7-B% z+ihFOx^|M`wbwAObO0g6WRXZ!>y&&E6bD3Gudh+h@}2oq+#QNy?Fbs;T6M9rGTY>; zi~1Opu)(Mz-8pA}majXIPKltMVad#rlroWxFruE}kja^U+JJ0u{2K?Vi}DFHfagxB z+C$Ef%e{;!XYyn9bP?`gvlIYoimtj4Z7C>I%?{tBC(1~p|1nD8PZCG`a`dRle*?i& z3&nNx=n^aAKY@T1l+OM_@E;uhW0rVK3A2ave`-{(g8r_LmUY9aGwPZ4fP4+fBBS>I z_Nt-WV}up9I*Po{thOm(h#gZy+}JGs{|VV8HjctH$Mmd!GFqITd4d3l9f~f54&Iis zEuNgApJ~&}wxtSDN&HOl*HcXa#SM&NlLZ79U#*|2Z>=>#vIq4J4*!9xS*mKReg=snQX)CF4KCaWy zln_S8^20$-g25BflyKKG@pF4vdpv8pBU$}KDq`EUF# zFzEnV{6AX|O>@p{=RmP}mR($61O!o-PptFT$xa<#{)f8$bCe5OF;kuvrW^XiT4=p# zVDr)g9NoifjW(*MWe&yuX(yUjp>w*bXe&F+FI20URpQ$nYV3atMlu1?xl@Hywq zS~dxuVI5L|h}2(Mpr1zhPpD@f{Ma1WLoym4 zATP*;KTEEgY^94E}{H)Xz~lGG$%jcfTRzfXI)H-ndR&1Ntamf}8ku z#gyHp>ELePQ*0@lLBGq<41oiSnVVZo(m#0DbFYS9Sf=}kmt}|Yn;(9H`Bh~Wl;8&U z8jU1ZRFgV=Le`s9ZcB_p74MRt;~r;eBnxJ%J4wPdp|=w5ADRim-aQUJ)FzC@yx|2P z10p{%p9;3Z>(mU-%j=Q+qu&yRVQQ~uP~O;WtJDn5&3#IDsx?W{!tm!AO!we1hBu8R z@N+LEeWb)={%FgvNEif1k>W!B8IfaG*VAy<$ZwwSjqUH6np)`{!hs{$c>bmm-d^Bj zQ^}}G6m9YzAh0sEMQw0QuFFsto{sc#X``}VOSK%SI~dJHw#7;AE^xJ zTL7JN@OoCBes|%NWWraA+O_Vn4;4&Lb<9zMivHTB9koyCoilB{mi4(0%snyY)4*8p zmRzTWdYWCcLa$jAwxl2tLwr5ijUnHJuoCnZAiz2tpw*HKaX3@ET;%0~>IEM4%R>7R zF?wY2Hl2Mld`3GonoNJe=F9i9kw!KvWikPjW#Gze-|+(Yh!-NU7S$S_HQGK$J2ZCX5cN2dQn#=#$FI;t0k<~5&KEI zZc1oDOD%e+Y~+e!P6&$nAsOIv(=~N{$SM4+@pA&w!Wu6Xvr4G}whH{LEL)ieTxVt@3Ar)2$3Df4y>abQ$NH(x$~HaQ&Flh1NFLQc5LYE3}~9L2KhBkLEU-uHb~ zZ`oUpTXGhiibCMOTWGc6X|3%rTyxqBgc!R@%|T9n5>AV|8T6V2AaiBhsI6WxLn5}v zU%P(K1&1ove{Dl8a>1HHLm*s!E+sh$^CF1sP5s5}wk{5vg9k_B{_QL{Z`==aKeZJ0^|v zHhGdo=&NDG89CzjpT7v8JMg<^y^rB&E|a27zWT4i7crL{&TOS3&kY`uZx|MZBS^b< zr!vR3oRL8g^ARpQnEW6y!gv55NXB-)#F`ftx5My%{{Hf0bN9J%^o`@Bo5uo~_Kvi) zS%c>x6+eP2p#+hN2@g_exdr#z2Kw4V)yFZ1I`V@W`i>)!aAnb4wMm)^K~C<}tO6Pi zrh2f|kKaWujDg|H%gTWd@>!xba3!?*ix`DkU0(b9gzoc$d-@_C9OFryUMPg$I3e#D zbI@rdES^qs`|t&5l)bIB>9bf0AOd(9T5BD_Wa|Y`=#ekeVN{u_&bFGxKD;yhuxF<7 zs(dx#8!({;bX!LSE(&!>8;ip&4#SIwHPrnYxF2O&O`WQ%q4qW=v-#=@BndeU7%Qc; zHZY;0lAnupztpQ~A6QciyE#qr+lyG`8oPd)PT^AOL?HALXjFeY(Qa?#KGFyi%O;Pb z{CXvAZQ`HCUza_zN0VqKD_<@#v;H}#ugH(tX0xx-%|D8-v}Z?7^7edwos73xhcbIr zV1T`7-^5ANIZW5iIjg|7C9TX?Kf$$09>q=Lk#3V{Z6$>%)ve+X*LObTQDE z7YFmbdxqI>%|EU}5Ai9b8uEHE9E|EkE~~iAYgefukjVWBwpAkHu*1bv%xBP;$(t-0 z>=CQ0KfQ~aq!KOc*@g8~&4oY+J?g@<(Ymj#pERo{qLEI6xp!EE@sxoNa`Q=8t)Um+ z%Rz9~6rOBTDuIj(#rR9y6r?exrT`eF%~W1LM|E>AWZ>7PZ+O8lUDwkg;5 z?og*&&gc@!Qx2x}{P8AHO|UG2q>^wQU_Nt}bNZ*gOh|aU1+2`KDBT8}%DSS)8;!#5 zlR9h8Thn2kmi;2PE}quU-@CAKNj>Xccqei6Yd0+hz;5`P8G5&}KTwQ>jHPEu5lLr` zNH5=FX3Zsofhv7TzCT2ri?KHvjHx5$1s}@$&rk3ue@_Iu*i)p?Z+okM2_j2n2*{$% zw4GNePXrzd2Gbg)f<0nNNdTdaIJjoGePks^6W9@ow!G@*1e$7 z<6N`G*rW*7qNgQi))9bSJ$cSyvQUH?cl~NW$F5CRCVkxn6+*m44-g;u}xWbbnH=1=zx}{1q+@L!%3L!}B zbzc1(;j8x&HB@HZBOzDCB54M_R@KBJg-L54CSumh*qjBBeg2`x@&~#GMj@yIKCgpC z-gLEu;#=PVZQC}ZH;74e5{7C%v~!}8|_ttsI_YB z$FL+%2=zL@<1(ajIm%0}8oVS=eDsPBqQt)x`eA<~OhJ9ap9j;q`W`efV8ACv6Vlmf zB5FRl3!in3tZ69B?N=qcH#f(irUs~_F}T06%p(Tk&=va|)3#E>Mav#Hjsv8XRBX!@ zHy65Uibd=0PUtQlt4W^UC=|4S$?Li|j$h1SS1uTy7kr zrix?E(Wk8q_cw!+>lRPBmoCW)2qC(!bm z%Od@A=p{?bYuv*=4WIG{IQRxTa0R))cJ+pR=}U`|;;~C35NRwBrhMQ1bmH`HJ@f~a z+F10!I(e6Xev0WGj9a{QU_bhX@=7QT4*@i#(A!02`bwRLk3Zngiq+y2RbCBGh2nc- zCiOh^e+r(`mu(lDlFPxvj7oh`zZkN(|R?)0;w631}iv1=DB11IPN`5+?VAh~o%p^6pOY zpV(rtrIp>A9sUEZ2h6xG-U_svj`Z4-{r_F5+#el!9rS%Pxaq+9qS(_UgN@ir?*{{#mgrxm*$QSy?$L#>X=$1$vcr3Gw;go{D$8iFC9J@b&(9-E2xaTlaZ5uda_TU-TP~ z#Z_t6U{|7uUwN4|rrvE0Xr>8QB*p(+{_*Mtc05WrUTsg%ocn%g{PT--EP{O}3(2j~ zN{vMbe%0Pr`!>u_mc{KOW)TXFIl|UD9}2D3s+Sp`Rd!YrtwR5Y7z0&sTaHl`&pl+J zJra2z4st>yE?Xy7`KJeal!3>`*U@_7MxA8jK{qdm%YL_zCEh#s|I`z&@jg$6y*@aV z)5fjLv7Vyg9I9|$K@cSdO&8(MIw))2al}s9WYV$zFkKsCjX9isLeY1%@sm%h6)L=5 zARFVf@gx7MUu`*r`U+9UR6*sesGtF7J5Z_Mb8Nh*yBtB8Za$O5-tBpdjbAlp?K2JL zFGdG{Cv6qY!fTa;TuRd$Zizki#e!?_fE=(>sd57RzHS{n;sO1~FZz;N=P%ZN&8%sR zY<$GTvGJUf=$S`(D6#RatE>_Lw@y&G!4gHo9qMn*AagW)P!Z2TUYvq!7Q-rNEm9&r#yWGNi%WmW#QO7O9d zgf)qcWs)V;zvjWs+S0zq6%KFSk63GVJgqoWn#|4=+3ea&8WJtQGjBB<0$3wCo@OaW;Oj70 z{n+`+!UGD^kRZ~tls>iWwcT;w=KJvt=c%vO;65#LbQ*C?QqSB{MBe7(r;uRiKYf~f z&?PO%(A#=LESy7kq2r<9$UHii7S# z8PMX~@X*&BJ~|dUrut*G8y-O1qv+jG)X#Uvcq8?PpnXtE>}smKM$tPl?c#eWeybKe z+SmZ2EmqStC0wz8eZRkg)>`hDk;#4jclf%u``>9-8L zLpZR16;_wu#065tP$gik0S^0Dd*xgZj@A{LH}2jjj@Dp1+h9(dvm9^G34Axr9(^?B znBFj!O`?isijhFT>KQVd-jGX##IS*Q{YPq|~6u6|ke5=$A1T~u}G z*8<(cQ0|XCGHzs|G9kGkSw79#hNL(RgKQY2nXiWTJo~-(*Ui8(!;p%#>s;`MMX4{J;~8r-0H2352sSW| zZ}u#$NE5WC#;T4EIBoZq$~BNY)V`y3N3t(f`;gvzTo>`VD&QYh4jzx+f68?{xF1n7 z@qFe74u-unScMZ62F0fT584l@}LE z@9S!4!PCsUtNjTk{yWy9)kJ4|oDTsdNdCdM&}89*qj;rUQcmD&r`9T|49#=5o*MpI+hPEW>jKngOLTWM z4g6;?^GX8BOsqGb)gBj(u9(}YS#)k)?VJwj{o+SyYow6D$)5|RxH^p0?;a(4uN)qE zOC344)f&-&dc>bHj+t$;a(5$zfBoU@^yDqYKA4o?m`X**pJj)39YN28~+F>s^4xo;P_Ok;kJc*{MQoX;4CYUdrEEL<0{b0v@?KDZRZM~d9 zZYSnP2xejyij#z}gyY);&j3jssiH5tG{z@_iUmBg(HGkF=;EhDzUn3qZm~%Z zhr+yEXrq`{@^mC$5@oT3CsL-e_O169QVsFx+uwMJIpL3@DR-e1_6`jnf#dJ(FXK%e zj0YyM7t+$nczKrl2mV+kJT9)I_yw7@hR8|Tfr?AKJ}aAd>~8_iui3Z~Q=Rl1#Kkl8 z$C2j&o0unAt+p$?!~HLlJ)|418<>?ND{{No4e9B1Y26xz`Cbz`olixEUR1N}S--R3 z>G&;xD1WfnSAF-0Z&J%8CIQoL?7I0@bJMOZlabc%GHJEOMFy-ta6JyVak%R3KQz)x zj{BWk91na`h$lCV`rC&fIYz@X)oHwT-=8aP3Zl^5_sFGQ)dtx|aBN@JW~Z(!Wf8Mx zf9*>W_w;rN@Xtq-W>i*o-HC-(O%GZ1o-6M)%)MAxB~YwT%L=dB_&-^|{9aeIv&t=5 zTiG%xMatFNSQeqJzS?0yDxfIe2W^0S<1-kZtRsHJM|27dmkES%lX<^ial%5n^V@Ei zJ0z!bJ)tMcD}2Uctm(&z#kH@S>?hDDuE&LreQ%w%J*6uda{T#(-%P{-UdrTk*l%~j zcRj8uX))&T^~DivY5i_PKg}|+rxQu1HnYbUvT_m0kkOypm^IQinnte(?b2o4r@Ngy zsV7^MvpGwmOZ~;MUhu5+(z1re%EDhf$~5BvwDYOtZUdvZ!W+4aEUriK#W9Nb5Fk}S zFkG{qDw!GlmOvJ*~gno6>vmzpNNPNc@PZ zDZMoOw1hS5d6sLXUVK?fqQJW2k9pEr@r9u*#nBZc6Hd6&<=bQq?C>X>`(Z73Xk9L1 zXxEY7KTpx7_WV(P^TYci3iF)zcEMt6)1g^!#JIGGF!y>-&gJ$ihFZa{&~QQA6GEZ- zE8o(H+O3BGrvhIw|4NQYn{QrQwo1Hr2%fFxD6VFi3+3BxIO)Yhmv+s{tDAIJ`_rG} zxBanzbO|VLs5oqj#P`4?Y5qf=(9+U1u zExmGWf**|>h6uz~8zxp*u_c3~DK?%6x&UT?-_uwll6Vn^+noHiC}EY-gHtQKUJ6sr z^W}RB8Q-)np8%!dIkEfO?hHmtzlZCn;p>VzvgR6o17@#IefHNXOB|>W>-LrbMC~uo zprNp{a6suoZkQIlx`HcX)dfda>q&N;iWHXNge{E9G%9GBFvX;Vt;aiy-!U&uhGl`J$@WG`vXW0<=AAneqY8sTEJJT#XN6u6H8(hSaT;)q}fg;yY|nXtDKW)mxNkS z&qLJm!{|vgPC(8v;N^2Fg!7X9J6A?edEZ;mVR7x9gtr;P5T^Awxtvi7_oSwT&uK+5 z^Qhi$Te4RBXwYdacZ1?FDe^|@TC+Kc>x_0Fu^lyweUQ`~TDsy;%#25h<}zTXWYlba zzb0dp^36qFB-5VOUnN-1oWPOPKhebI6yz@GSx7Td4qt)yJBf}j2;Kc+KJDx5t&Z~^ z#{gJ`>R}S|vqR`C?H#z$JH9pfy1kRuGu|*Evkcr4h^(uTz_wHunDs-&=#%(MDRu3}OYo)fYo(emXa>f8xk!z_$7=ek=?gk>|_khLtE!AGROw}BKIY{14=6E$4M)7cPxbTAIS9T zn3XIx#St&>w0TBA1BIW;R&ah`u0*?Jl+uw+Dp)YTd@rzgoQoYdYEFHV@GkRhoyNm= zd&vv`L-LxLAC(l%&=n+u^jHS{tjl?M_n2axSXUSS>Y`4{TygC!;cYRJkC$S{029UN zbP&Px8l9hutYAqoi2I+eky*?u z6UH|gQ^&bS9r+5f+xfc3^q(_stChqo9ygFLg$R4S1Hl_!tCBaYWGfgdVHjK2SYh^S zU4ou1jy*_oJ^+u9qu!4LB`(h1ZUN7ykb#0kNC}N|zurak$&W*S`}XX?P9Zt1%0mRo zu2%Fvr+k$f@Ga3wWSMWrz|SWkAuK#*1%9dHPan* zC(xhki)Y%r#g#h228RijrX7ETeHukP1tOH77@S~maCCi0`3qL9ja9uf*n@65==hB( zxZ;{?F!kWivD=EYjAg}Rsa}84N17-mfCwde5Xa3Q34Yh*YF?L8b`dPsQV-(UQ2+X= zE$v9$VG5b8bO}<%BV*&NTI8LCoGS) zw8leSs|AT+;g}!;a7OGEMo0juxqlp2b!utd@Ey!~fhs~uy~&iS21bwnbXnKB3Wjh9 z%06IC;EHog@H0eHQ82T)PaHpXb}6g^I%FX!+I@e(ClOR{clfkBNDWACquHGa>1a?b zUs|jF3zT(X6GYFLci-N^VwuERQHoHo&1~V%x^}9=Zwq_!5#U@HW#Y8JmxejLMP<=;uAXaWqnW2!ydAXv1JiA)KChDBLI z80Vi^vA}n>Pf zNnKH*x>^HPZbBy~W?VxG83d7pl5wlk$$BAbxTHfQn>SZt2cQVC1Gn!9o+352T!Ui` zEW+@QZ=zgLBo)U<=K$*(o;Lp-FT`sZ+_(QSnwP}$V}|9if@|Ej5Ybga^N7e|pt@|e zp1LwB>p>mAG@5}?cr;9K##??a?^xi$4gW!%+WL2e;xwR4Xdx`JKF@q0Yo6t(g6ljo z%XhsnAPJGZnfg=}cNINn2;p}mbk?9+?2x=zgt5p;li$Zzm)oRV*}Xtnn8;F(1K*Ji zgwLGplu^i455dBM9~`Y4dCV4?)&Ar>1-}j~T$99iv}Kdp%dGKO-SNGLWSHesyM^CQ zen%(;>Ep(_lnhQ4@-l7&^Ag(WkhHZz{~skp)L)y(WD4&3(n$6nWwA6=EX38WQ`N z=uj5jkZ@g2#vZX*B}!EB<_yFyL?4M|M;=2L*!j$Ng)#M{oPs};XE2LH!r=T=)K$A& zL2nD#7l|nd5ywXvazvdj6aq)obk^YIaL0YOW)^+7FbD?E-%rqn;MAbp#miZWs34M& zkJ1Mesqu=V&vgTyN58FdW?P{*i?c-@uooJ%n01$YOI@T`8fFzN>uD;IK-UuFr$g3U zbgQ3b)sUJK{JnI7#O7w|>*$BrjVY(698x{^0pCilmX&_HBf5pYwwnGiUaKu1fDaeD5vj2`>USJt$7Pmo z$#?fKnq^6N(G(qrbw7+!1&dY}0*xBxBQS@e$iuqA*frTr&eVK_Rc*5nwl)i07Df~e zBln+Qpat2E6Gh??e9WiGzvY&p-0ia${t1#hURCF!T;e3?e$X*mqIZl-AO&)XeKt^2 zSepJ}M9u%%TSlB6ze!+{gjc+3)pKRBJwx_#8&Ili#H5GZVH~D#UdfMN%+1hka)K!5 zr0p{>i~q;AYsXL0jo1azKFa!_B3I|5`f{=Rnz?(&qT6JGol}E*-KdOz7_v>iM!L3{ zk@80&XE55TV~%Y3-b7~Z4y@N3Y@~D^B*)rRjmk1gS_~$$P5cd4>3~wJ1>Pb3+@g_g zmIEG_TcQ>5npA5^FYtpe?6-F9?~JtHt91+;jT7iky_U;|a_~KkaR>|b2t!$YKmDZm zrcBa`4f`*4W13$54_q&Nrf+g{+G-jDZ>ySBh*=8vV`H{`%a-;ZuyjX18%L;_lzHn!L`$#sEW#@ z&t9q$=5Ef9Qm+A9DkY;o3?uq^J0H&ZPCGA#O;X=z3oFC{^lnNngNv<;jY2-dH7M%B z8mCNJPU&=@OICn_4qvtv(nQ>VDyz&DXN@R$114;4+`vTeVZ^qJzZb9J9d0ZBqJif6BDX6&G7IKv4p)UunXbq0R z(MHLZ2&+piEvQU!vM3X6N)Bcrw#%+!#{27UaT`HsP12Fm$k?c zLQW9x|8}ik5!|X$tE%sWN(OR5v>7lvo{I-T%;|s{Ti^oDXInqfch18!pWV;Aa;Lvt zl-QIL%}82yP?gv15%D;9{nm!HkO{NdW~YSm0_@TKZR9T6$8^v%yU@9*kBeUdXtecD z6BiWPgFV_y6huE$GixcM8lba2<((GCMJ9`M9x&>F7& z&<-0uZy+^jkgF_YvY#{k<;;n?Ce01!@)QJVz;NM^LuoTu=cxE~X4jzq?L9Z%?yYlf zhpzjb?WNy^+~e|g0U;#$IEd(dJv@QF*Um*V$S+*Wx2DY8A5@3Xdz(6z?dV4MLvXBVjbo*1_&ZdG4i7Y|S zRY)A(YL92WWU!C%ajECFjpf&ABr$S?dm1+N7PJh<=yrsarzfwtmiYSt)=hpT?BVjV z-cIY2U}l{hEMiP-v3SIhjknS1)6N|&x?8h=RMYv`I@59VD65>G*OTpK5e}w~ZOH!o z3(M*&1K5SkLXrwKCxve&X#`(*jlK@`^utJj_G%{&%(^g-m=%}V%y$36=Lm%wampvC zar^IHY*vZVs)IUXIwLC?i0sPfj7roMvIlYNWh+5{+E-8`XckEMPS{dd_pJ+q*@HnK~Xu zW%vxpFv`5y`?~jkG4_tpl?GjyXp#;(R>!vObZpzU?R0D>9ox2T+qRu_Y~9oSeRuAx znYnAtk5twA$3Z_nf_S#4jhd@ME3@ykJ*EH{IvWeGnui!8cdvnj&^ zlk7}3-1L<^?B)jy9FO2;JA^rO8Y4`>R%v4!$S7H`s?R#TOw4CELxSbJ502XCz^dI$x`7 zu$%?F6}cka$+W)ijr!hs-quZeU-n)1 z9I47PdK^xTvPGkX2Pe=&*=33~#$2@ZM6~{yOKw>FA1y%IpnoMA-$LrYv_aVCJ>2B0 z81#$6XBM%1S6Q-V^2wAURnDcqXIj}I&hIRH#ZR5SInBPj*X!Amz%bvgD`(BibJ6_4 zp_hNN`Mu$q4jSM7H(yX_tfR=DPJj0*=GvZlC#V5OHo{70==cQJU-gS=H~oWx&RIz% zq)X^?B>N|pkZAwKYbfSOLUIX285Vn0y+*7Wt{Lc4yITtI^j#lL&-$sEA7A=MZQS=r zFZ2s~?CWeT|ICr6$tEf}jk9eL{jJmEi)}-v%$Ps#{98o9sDb)ecjwf!G46TZyjd3~ zSMjt?NHj^y@y(ll7}GP2i=aQ{$AxCg(AIJ!EuR3Xf>Z%V>A_cRgq)nSx}u#0u0HWF z^Y&3YhiyDNi`)eKiiWZ+vvjCGZi~+UWiRF%#vygyoq1llrfl3de%bKWEV%mcHl2V zVL0AI)E;Ju>XqX5=k$dphV0f4g!#%AONe05aJZ z20e`=@{Ky5VIHG^9pz2J4>ewTulr#w!&{E~|0L;YshH#7THtoZ2F*lz(8#JT_FrHQ z^^--?v}dz>k$;%pD8qY3$mW!ZCpqU|3lCov&Dy>U_ivHc68t@Wdh*yUZg0T?=Q){y z-uU@N_R5fw#|-6jzVCfgtaD58Cx`)t0dW4r<;{ehqhq;K0b{qzYfXW7ZBbKe!)_NQ zvhb~6elgmx-)KKD3kAdFq}+Pm&g#UV`m*_^+t2uUY$`%_)zRmZ{SU{Ry4tdMQ%+)J@prrr)U~HxZ zlYY6tI2)KEm~w)a(JnC}@!t&(^H{o?e;XdFVZo}pJ$bzzi#ag4&P|Z76W?dSMz%tH zZcr)y?sy!i%9*b?J|pY$TPJEA29Yd>dcxh9p0So_<{<~1+_{h-1fNI{gv8F-aP$6p z3n}pOllc(xRr@Sz@a8OcnN_YVT$QEwe*XrON=aPrDoJt|Ri`-^yJlSFxe-8)lyNvO zw~Dhbb;+YBVGMS`3BdHgcTEhKwN`ZcJl{elKi-5-9veKIxKEJW^&B&y+K`=mA zhhBg397oQ=*=k4y|4e95B+1(+gwhO$(yi+q$al!-7)Gd-F^mVtQZ~K*ZjdLvsPt(f zAtKC=1Ho)oPF}Jw+z@%r-csa;r`>tX6g@`=0tXVSkYfAex)5w3>{o(8Z0_y{@7cNf zrjE`ZQ++BMggQrx84`Myt)Z5NiDR)Qrpbf?(g&S360TQU3Z-0AUj%(d8it{qb4N9b ztly&GFtwtEn|5 z&K{o^OkmafHq0XNQJsIj(#g+Y!UGo1@)CWJe)JUU6vSH=2qf5VWUlSZL`9APP)SP^<0=C zn51RxPcgiON(a8zb2$@U@uoPJiy=>39Z)S+K)99%iPmdSYgxK+J%J=+lGgcspkoCe z%oeZGpO>;q8M)sxuugcEm6`D_;?`%EDSOtzI%Wa>mBH3$pMhHQF1kk^ExV<`&SzWn zXPK?+rN}zrI#!Tbpy1?gz7DU@zm-NatS7*F7y%wL>DLmxn2C1Vi+LxWU8wS;YfT5{ zKgiesS1hP0oG5d42T~QT$p&e*QivnR9v4S?`XNmcoJ(-Uei~F-_Y}h0iE{(_n=0R2 zNO5ws-wd;JYO7Wfz1M`cZ=^}!)LR&33YJs`*iMp629jtan_Vvl9?|LZu1K-e?vzs` zR-zE@v?^Jm5J=fFxjI1ttQLJ>mIatvTEhSLzRUSwXP6Qtb{WmwCf1l&POIT4yvm4s z57ur;jG}Bt+Ji^_D5Jv!p<-X~kD*c;b#T@p;wG}Z4;H*Hm+}}NCZTB3;F8DvZAsogO z6p&t3#RLqTj4S*Ucu!jTJ7~vf9q(%(13+6>+V9;2bqF1{-D6W0jeF{3@Jn&wNdZY! zzYzo2V+@|E6Lk{uPV)ECBAo6j$pzKAfGnG_cOL=jSgcLLBgKEwQtTh499Ndt9?|5YfUQ@B>?bbQ; z)X9zuCkI}qC5;GNy+f`AZm5G_u}S(Dq-UF!CX9+wo57r7-w;5bRQ2d=rhx!S`pJrH z$0grP7lQL~L&=Q0djA=)qfkyq)gHLiu&9zqIVPl6<$o}azULYrvVn1PK6edi7@i@+ zFtSB&zlSABn@@~4olZe5M&YMy_5nSjB8i;$Mk5}G`BA^8c;*T-1JC7qorWhw3nt{m z>`P$*U+vQCv`09(Fa~6sa(Ij7kNS&*ULS$gZ&D34=U?`)TQ*O8uqvjGxm&um+s$Xf z;F!D-7yb&1YYNk`+5M{0S;cXFh)#Z7m%;Jzh_CTcUiR!Aj0a&*ZG?(dgsxgWO^y9k zG5JUmzgdOS@aED5$p0;$;kfH z)d%QD4k;}X;+sIqKA~(`yQUr>(|7H0w^U&kgGi(c0<CgLyhaNNqJ=dzS>6n)_*Yjj`Ryqp0O2ad$~%P5afyIHVjRA)+3G2`T?*qUZr7YIz&J1d zpYxKZ(y5Z@WS?5_(f$}9!Zbb>Ny-iX5la9Lh2b*-BK(Gc;X48(1dh)L%6Q_OXH<^^1_j6uf&}_6xi)2g=hcTQAP>zlJt-5W| z#Ffy}B1SSH-QlLhupDPF^e|RY>?sZdo3bwPMu$=O7xfVTzQ;M;(b|BCuP6Z zaCzKTpl?=fV1l7RThCinUU}`Pv+b6n)bK_j%^_x1WG~Br6RM?{G^4fx+sqHfW%ue= zk1ik^nW~(K#Lu6^!Jpnbvqu|^?lxLv8Sm%OI+V+mx2k#Wixsq^pn`)`qE z=bNJ^zB#CFwn(20ng_NPnBJSJ3=P)c!9I><*T0NqFdZLbS(8w4yI}hYOk;`Dl^Gr; zE6k#uo;{g#r~L$518;LHijy8?#+i#^>qrXkxVs4iv7D6eIfCYD9}Oz~Qw#CqabWK1 zYVtix9owr-$on2dgS~yBb-G4>?4xQA-%N+cgNQEdYiR2xDf-~7{w^tXUB@-}vU0~@ zO{km`fuHHx{1C>I7*~;DO1BULT6FaZ9qlfKEN(DkJZuiv_cwSYb&mPDb4W=_1Fi|l zvRu&(I;*|1M;cZe9B$SMYVQp4ZjyCJ*oCmYuz~lJ#MjPUa2F zaueHI4Avvb@)tss+FB34W^Tk9ar@&>E+|5DiJbH7r?Kr@$ZDw)gfbu}>O*6=6PNpE zGA*jcQT>59t9i8N7^}POz*@yzL}av2o`zrzIB9Jf79|Vv#qZ^XW&7>}cq)RGN#K}g zW(tCZ!AF?60l}Ouj?4@6p}QJ?zlmn<1CJ_Uw|teuv{)Trz%I>I5ERASt?h80oRPyK zVq3p02$q1wF%J~AYG?2+*<{4tb8|>a#^jv)u1Hc<#wIM7nN)^2pHMEXAP5~r&rd`- z_r;YEe1^Fqr)*KOFcT}1;-q378JtF1%hifY$di_Fi}*@T|W_KlcXm;nE{6aynk;B zm@12!mFp*Nqg72W_}jx*M9JvWiyU@PTUPe(=mJDsdu7u4+ozNc=~{w+D8&C#QiZf^ zHAW5Z29usrwUL~RsbLl{#c%Pe$I2$q8M9eW}f#TzY`=J%N%q+#a!>Z!HwC`|`wDV(H zSPaM=TEzdIjue2ZiCfO74eC|{I+g^>z*z<7ymjf_m2bG(L`4Ju!2#GYQfoUA-sxB0 zQ6_#A`tPYcmCg5OdQ6MG(jV(_7e7mLgGBT$Hd55LtWH^Hwg1c4P^pa~yL6x!bHvHS z`i{TPY0ZQdWjrjm1;I(oecz(YB4HaD9O{)@>F8LT3J` z%~(6%zoBxinupBDSDX|RG5<+8JteAD7V=sRE^6bi9u{Km?sAYcauoA%0cbM2?f6F~ z%wJVubx%>%jei1&n8rMC7T+d5H&2@FpBUmq_>A_LgYcl-dWy!m9u)+~G4%sPm`Rc# zxPqbG4#GSCX{koQ;~{KR7I&jj0r6jgpaEK1-ywoAQFag_0ZYT&2Nq=p#rxwr1&-n1 zKeD7o0d&DEo3Ag9UXc5%volHt9#J=f&L`joDU1Lc0VozE=4{G?9FD2`KQ9rx zH<{5IBNc#O2ogchL4-{^qzO@*gHOavvkVL%Tdp{&VCA5Jy-H60k5&QV%Vz>KAt>nS)=fMbjimXm7#>5dh^L@HQQF{f^WY5sbi zAdwaTm2+}}M|w$^fC9&zCl*pFxE%)Ry)iW%3o~&d?7g&pe84;!&qARpk?09viKu|cZ^0bk8N#R@%Sau!0h-R- z2NY!n<2WFcZZobeTbfJq&n@-ou~sG(A#eVdMC!bs0D?jfaa51G;{Wnn9J?Cel>A^5 zIYj>&9f*~gq0C$=>zY&Qn~a5-I+0c$%Mmfo4sbf{->D|C^qJ3fbwp7;wz2JLV1S!Z z4d(ywv3YNSa08Ny^NOx#P!j#{W`py**m%E50@4Q+z*w$H)9%@MgjJ`?l$S zokP&YAKdk>;uCBVU$>8GXJ}KI7L#FbZ0&lK@N!G}v~hOG*yQz>vq$9h7vMd>%^9(O z&l3c{%ejKjNr&(MKIqcJhc}1V?*pEoD(`~s^uZjZKq9;#U(#@eLar6&F&3xn#U$8P z$Twdo!^qR|JXRVN>~%*l%y>S_ zwS#COwo7uD{NF~SuxcFth5eMn5{tt5_~ zGAD_dXso?wyo&EaSgzpA-Tv%Ld+Waln8RT;m+BjO7=0g*FnfUl%(Ee~8T=3Q0se){ zJ*I#XrqDUd!Rfk_B6w**X9;sUC-6^cr(_tOc$b4G1rR~BVFveY$=sXAw2X1i|-i{zd78 z;+lm`+)VFl-uef*Nd9U@9L~P!Ni~L$WXt!n?a|ioT3Vf}!GTDp&-Q>M$O!%~D9zP!x3qpr60b<1gVp^;lo|q0TjJ4t4dV z=WGbAIwSQ}?}P@Aj{%SK(4c7}^;v2Vif9NQHbA!4!))0mfr_)iGgBGgB0^&da*BGQ zqimt9lxr#i0oB{b-;bPV-ZFl+E&!E?_L{#;O=qIh7Ge|?KDJWoXGQdAfi0r_*nLT& zi8SZkeBC6tWVjaxUrj%NGRZ4vV;Cui0PN$rKSr9{YakXlyou^{DfF>ly7CKPNa^zH zcuIUk1Hbw~AY4;D&4`EVLWQ1~0Vyuv>RkGt-ml{?QC5RunnbD4qPhPkUREB^$$zPO z$1&LVdX@ScEf?-uH|{xP^7jTXtyJ(=o(=D{LHfGQl_c{#~l zE-9#Pn}wAC``PV*H9P$Yy2QAKOc6tnVpBP37%UE)u*Td`+mIGK;+D|ITCFcoW8|=AWskcFG(pcDKdH1Dsz6I+x!XMC^N#+7HZPl3 z^{EWkkWyc5T*V#9`CXr_-B*-A#c0e0SKAK@4Bih1%j<8MuSTa00ME*80g!>ua#nI` zAP6E)v&BA|$6ZV@0*+(U4i zzlFZ*5r9Hp{q^ABHj7y7wTd`t>#W^W`P&+{a(2PWM)pa$<4Kh9DQ+qh%Wlk zm&WcIfA9AsaE1;bns3d`zZ7*)j&D}j6{wPQQl2V{S6i%=Gfp^nP@YPEKUo!yydP#@ z(C!(T{J#yeW&h_e`^8ATlXW`kJTRVD(&LFV%W$PQhpuAhMPB5g!v{Ett1iz3O+4^y&!?NAIp#mAW~@VPNw6j@ap0kh)vhSnbI0ESME@ zu6K9a$MROi9P6A2Q_9r@sd<7;w{sDGk*yau0l&s0a=p7jiWOp7Dd!mOoEowuZy(#E zr-{9jd6L_Fw3)uu!YQv{SVhCz8pHqpcpLL?ynRDY#)vZ^XsLO`%%+ru@yR(2^D`x6 zsfp5T2EH)Yt!%Tt@IR5|x4#SCMkxc2r2j0V?LzZau<^aoVVxPyON=G3{sjUdYAS>B zH-HeapCql}UjRlAyT?&zgcH5Iqs0L9hv6`Mcg{Ini@{mUbyADrZ$;jVMXP~U2l-5` zPz^IB#P@z{OF&7USQR>WV}?l~pcwWre0F&Xr621??4cmT%Ao$2f@l?baBGW{(;Jkc zVHLU=j2geJkbP4ERWKnV3*vljm=?phQg@>k!;b_KBbnwjDicVp^-+|4<%4kh8%!R_ zJHYVu!{f`q(6Yg ztG(!P>;-yZ&j=wj!XJAt`YSFthPv+a zoC{o;W=#=lO4Y{dMK)9rV=pUcX3RBmNilpmcTg8w7=Gqk3){x=RPt3U=_e&k0$_QPGpSF9dw+hBu9;uSVuNk|-;`AR`H_b69-&eQI1MFWs*Iv@~ znIm=j9e>iu%`&fTx88JT^kO;X(@689?BGOoF@8+S(~HgB!)OX8Iu;w(&e^VfJC-Bk zftzP&*uy64x+}nW5&;|tTJm-Vo6_nb%rzO{gY`r5yyABGLHPH2@k;(SWyBT|Rl?b+ zT^232-5GDn277+h>U7^m@_uw5-?> z=Sb-K<(@q|4J++@zn88`ojfK(g$2W3(ECvH)cVeV#-hRBfa`m5+Z7Y#^VHw2Izwqg zLx+CScmAHML*1XoFn)3Q(4)%UEdC1^4EId<-eHOb>x~qi&J>o@zP>-6AZG8 zmdG%fV3s3NxOsU-(~o4r>seYoz6##igz-Mf5apF`pVSR{OqSQUzCI>D!*lK}&5End zO)^$J!-!Jm)iX}&s#!(zr0xnF{dwwi>#+UOxzSZZ^u9Q~Ql`N*SV!H7UG&8JYR`(K zk^JPO4w-xPiQfDCZMtD2#C&b?Bl3N;Lvyu$BJO=R2JI*EcFk0k+ab)t7u=BQ>G*z& zk2J(fNX-2c(^TPJ_J$A}LQY4R?OtR$Um~VI-4j|N@Q6e{-tpBj9wUbq+`GLQMtXGQ)Fe2N~=f zo8jp+{}z}9d@Vj39`nT%z1Ft|a3P7YBNg}KB{N&$jSX6nbBWL)Y>3TKa5vDZ1!ms9ny;SRztXq zCTWN%e_Pnt&gDbbY=<@wz3MerOm_#TWxuTc?afMXGZm+aA3esWc)k_y#v6**dHzGi z6R4CPKF{--Qsz=@ADp8=T`tVU2JJ8ioHm1~Qt(RP>mCRIPxhFnf3q>^T0e zutu!U;m0nUR%;{iyI*e<^cvH-oGO7gU;P-9*r{>rXNKc8;xe)>F1n_yM=Y%MWkCMKVyMKw<5t+o@@V|^7L(Q0)l&g~cQIoa zBhYlI6#C68+emJSvk7V(PyF*VRsxe3GP_wyr@=pRY8sGSt%1Q-^$;Nr5)dnyq#sqH zd!|wW*O`#ZZGbZSa&}+JPa^obY)THPzQ(#(QI;8Cn~SDZX|`EoQ_;byFTmmB~>+4>=VZl zd-}mWj0Jka3rb|_l8Qb_%|ZeVbX!8rkP|J{VSuT_NUGw@;aeAVv&ygVhhEI)yP;5& zyI!o;RBdGx0S+c;+-3jeB>Xh+gX3=I@hGwTXZFt5=-pR~Dvw2zQr@&_YSAZfYLXn< zEr67|n|&xKE4&w`n(fI8QDw_QeXN|NwTo--mmMn8NBl@mBY zrOU>MES(Vl?$g5MV$r$5=VQ&E?~gBoi?i~_gAp>#>l{3PMs6$O{yg9mAE)C+Ce6mb zdG(*BbI&U)izYD-%b6DH=NA4nvzKI!Y<$%l3*GxZ!&EvFZcYl%NJxsp;Y-6j3B1xf zlzXz7w+Kxf8KN6Jd-P7trsSN$F*U-#?j(|?|&RolHjUIy6P zJ*zu7yko3^yXv2lzdU(9&mlOtKCr>IAU?+F@Vqe|zyuVE=lx?$$;Q@y}=v+2J0`RmB@Q2rB1LoJ>fs!jL3$WEd~AtI7S)IL)DjYOLA z2nXr0ojO4L-V+9R5MytZ&fGoM;9=wpXTqVNz)QLd4frK2U{wW0y?s0E8{wWMtnB`l zWp^F4<(KkBOy6jpLbLuLl60dHtT(oV*M_2x)Yt2-3mQsWom4K>cu1-INtD30bdXKF z0=RMSrh1UgpEfq2NP3}h+R+`&q0o?PaP+YutQ~Exsc6|VEv^OQh>$j`k_(d?Gt`(& zZ7wH8r9vdz9ecBUQRAVdim(RbG%>1KA)}NE5oDG$Gd7l3T4!Qd)ODngUoP_w%K>X6 z-!&I1;x5;XBU_3w#^;b7sa$$ZjDL?s6Z1wZ@71nWoUQMlbE-mltxDw5;gy*bnyG|m zYE#G!NWQan3$P_oI2n%8k4l5K%b&ED&7_7V z8yQYhIsrbFqqIf3XOj#snlM4RdJzF(=!ccb?^RJ74w!J0|F*?oGq++vvmXSBn!<;r zvl%Ky+l12&JZzR+05a099paXLfS8 zpLKcr*tl;MekI>HEFe{dp$xN>NQjpe=Rijv1h2t^+wHy+ z%pC1z?Xm7AL5!7F%JTadjh8fjQmRMG=SI9QTK2FVsd)h8a>2_Gn#KVMD>IGXLv5f? zP`c1k^vIN?j?qV5wAvEq+l&L0tMBw)EAWZ}@T2$b2ji~N`QcZEoyzV5BXB9kjuKyr z_?*e3BAE`t*2I|s6b$^Zw=*9kH5&ASYq8P+N08t?Np(-7lvMO6f7e5wd~lh6sGVR( zMCi4nSC}vPQ9#)z=qrKfWKBH@wx?bwl`7ewx80*YuRDJW3B9ro%Woq-I*B&A9%{IB zzSC3#-GLmsy|} zfa09UUl7l5g#i?(nhQmZ7^-^iTqOF%Es4MEmvuSW11w}@LzccZN|2}xEu&H1S(TfZR}m7r)V4Jc(!|v&uqQ+lht<(=v+U}% zG+ILrcS1{=rl6D_g}KE@9Jp3fXUgYGa?Qsp5szGdOXzcMWon)UVKGHyd1m-=IQcex z5_#|GL;k#NM*%x$7Z=1-!(N5=<^@1->^U}2MhG;euxMj%q5W*IOTXF0A({~>ExPL-yc#cw9o_XeCR->N zM3AeQ%O~pj({gLo#Eqsiz9$t~<@Gee@!+bJaBK0x9xGZ+vdm2UY1AsNKU>d#(2xj- zio7kgFZ>28WQt=>qCvOXxR}T^1s2feAZI>mn^<{wQ3ln5*Wd%rbI@K36hPIs)K`%T z!qzt7A}>K|!)ju9ue&);Se;SR`y7<56|lfDwdnf*z^}M8nyFV{-Ukj65oW4-MlP!+ zsAuFOYg+m6)8gt2%(y`cjyT@=6>vV$V#hbe7S;W_wQrXTyVHCaNHJNfIyj#cw793M z0yy3%<3-bn+`0HD@+xkkPQET>%gCK6T1N-LhIOq>Z{5)|#?z~5!iPU|=UEZG1#QSe z@VM#Bw?8e0KSr<1Y1BLAUz^t-%{In8!a9XO9Z2_c(|0Nla269LWg!OSes-{PzwJJZ z`uQ#n`>#ByWvlg{Uw^FXPHlO!|I{l~p?kM0a#_`nSV;Kh(t!Gy@m)|!dz6+`jp>;C zx3v~VPO{Pkh`-qkNj8$gG_T~{5TP4;9`wql)2_$VDCvcZ+iZ%Hl}dJU|P>ryy|L8?2O+mJp{Lw)!y zUE)ESred^Wj`k=Bq_gN6leP;(H`p;X7gVjV1Xsx$k&%{!%8!NbizNBGSEMiH$$`8_ z$MUCvQ{(TGGAGSMc+Ggwx;`17US}U72`AGs?2kVsSkF&HajXQ_>3zNe1GlV)csY>{ z8Ihu3f2$ev+sC#D(R7CepAbMbOi8Ga7xKdOi;K9{3a}`zXT|8CiyI@Iv^jBk-C~V1 zuyvV8(@^*3hynWstyaV;mmHMoBdAPXDb#ig=Amq`75UT>2OkRI0dCfk( z;7!;GyQ_R2Ae4VJeGWZ^k2c4TKM?q4C{>53db0A?y4N|l z3NQE>?m3Abn=OY$!G|6sK4$_|)Rh(SZDEgeiLJ5}9Tr;LlI&z)9t<0cl$Jgg;yxfq zB}s}=+S5FD@;+4>=NfFLp$qoAH(pT^#1H+B!Yk0+tB(Nsd*mOiyv6KdP+@Y#1iy%P zU_(wq6A~mZ!cbP^?z_y`5*_mvB^Sjrf8ZHKJrgpL#Srs*h%+%zJx0(uXsFa zu3~jxCB{^jE?b+4GD{5Vo0VrE@}L99{6Od7M;fI!c&CujohJ^fK%#Z}+H`eNijSM5 zAPpo$Uk6#bfX)Ik>DKjIRYVoFDA7RrbDDT7Mae?OG*l1lnv_ zRbmbLpwseNPRpX-Nt%Ny{$P`U>C9b*sm^_XY!+|)-Hx)FZ)uJ3 ztn$rTws&p!t#n#_xrMV_MtobiTw`=r)$&8W*b)v#IP`emM)=1(0V*vxG|7Xb2jGXkkC>2?FO&6o`Ko6}Cxf!!_L zPs+j-4FXro*FHs%>xygPx~BFE7@5{FAk`i`?@4Fjr4>L$pxMA@#;N1!xfOep;X>UR;K<*QSK6j#J~$$R<>yo8DU2k1lfAq-x*}{DPVbgt0+u#KwF*E}9d`jpFFks{kIKTEPqOBc>(`M~V9{ z$c_Z|0Mo>^Tu_}H4K(9K)6x|i5IW!@aju>;&@Ie)8H#OVT$**_>#Ad;-LrBQMN4SN zjvujoAtj%nI!oNiRjV2xbiRy2qX)51m891y0Q`7R9mOR{BsWO0$%7lQFLc0I1i>18 zzX7+dDUm29oln4d+99DK;l~P@eclW>0AgE zf`IA=q__MUiH`|!-orQepqOfz=xDHe49@9e8*>O({$E*JJq>LF{S+Mripp%$0#z0)UO1!@&LPXqd;115>iiCE29winy0_)I$dq6 z#>^smU|wYYv0CRL1OIh?Rz`H;l`;G!j?QsnANP{3cV>0bJ^*yt+r2*^8g)}1lkA4< z+ZT1WSX`TS+D=#`Lt7p_L@ht_~OfnuD{@&Fz9r7eRR2KO;K9(1Cqw7}f!fAP7Z)?P z)PUcv*s@@({JI@^{wL+11cY4qe z`0?M6!=`A=Xl7E1z51j`-${P)#S1lBxlmDGH)U|{{=rWy_~s69D5N>n;u8n5Og=Salrti{VFtfa6H+Lbb;SZI^6_P zDH2rbu0B-)zxGp%j4ptlgrG-ng!CB#=8NQ+h5C2DIL~gFwK}GSxSD2x7u)nP5ifG4 z5u=mvJ>CtxifJ>#TprM;Rlwr%a$~?8_vaiOBUB1g8XZ>EbXo$=b`1b8clHPtGBBJO z_Z1lTjlojLRUfohyD-Z0hAih-1|1>QPD+i*-O%fS>Ynb3$CZJC!F_0`XkQxhn^$vj z$=GJvz+(*;)x&`L4&;_;6jqs~c^0K3!sSE*v411%5lcn>vn=@Hqo=sTD|RJG&T5C% z%=Bruwi1$Pj(}?CX^gC7Ti~2meBdJ0a z;I_zY$%0TH%A?ZM#W^z2vzz9dg0HxrgZ_t^{+bOL@HO@F2dD|cTj+L$0$rxIbfD0ZMURuohM#MH zMl7Lcn%z1zOwox9{`ENbDS!B!A~gMdQH~yC%t$qV5UmT81IyG+U4?sE3N8 z9uN{sBzYVcnn?HOSsUP|GcTbZDu_z&=_HWh0bB+VK@nM06!@L=ck(4@i+1Z(f4-3<6_{m3FXTif8`NJS zF_c1RPG4cwnTlO@nFF&H7dPUp)~;ohKOEwEHb`57u?iH4dg(BzBst=H$JLLV)O0rfCH?+}$9_%SiL@FO2Rqs%gv8&9}bThNah-5&v`dsNhW#j0xHg}7~&~;kc(*r5mC01m@^C%_8rjUl}j~{P z&PWD+;Q4sRn(b_-55`s~%e^Mx8JS!chqhN9l>9_Bzy_v# z4zyj0fM>uUJimk3G_1rQu}e#wx8U!A9Q2GpDOK6`k=e*s=@i>kxZR9^S11r`Y4ZGc zHL^VM@e3M&1Zt5Ry}2YT#CquQV=o^xCHRK8FyG~&c~-y^rrw-4r)EJl6uz`pc=bpf zCR>YuM?7EohiE}z|qk`IVt z7?hJdZUvz1DKblz-_URO$G513!iz1OlgU%5e@hqeT&Er|HDj$%X{$9#JDsPlUzD^| zB(KuQWk0AU9BW&>b~SuoJV~Uqe0lpF^o%Z}?aj}AHkn57w6wEMz_YAsMOoX1V~dE5Gzri6*;`Y;GL@Y*0Z(D^x&$81s0P)|gY2z5 zGdg*d_UN#3*cH!+WyL^p?~cZ^MfJe&uj4UkbIO|!e##qTfnKa7?~cUhCgIUB2~Sth z+Fl7yC^gz7g(I8Pysm|O&rk`^aN0%pK^T%*>UDpQYYERE=`_g~$vkc(JOd_^3;vpy zncS@so{Nwh1|(fD*vW;r2#L?Epx5?Fd*xCak5o6-!hC<6alv-XJ=F(&8YDa;IX3*N zD^>RdeOX&Fx!R#+&mtW~(5Gq7;)y3#(?hEp8684;NYg=UG$9QB`zG zYduj@ep8;spOUs^rLC1e-~gHtD2vFgijnZX72o)l=OSg3mNhlyp=Q&Th4c7a%gqBF zNhJkYms>K-Rm#0p4h9v6>E znQxSG8G?*n*wjZZ7D;kOISsVnxv)*idp3=5%0+4WP4t7xxw|s|^GAZZ7`?`5d?n69 zwZA2_=!fxU9BRxfkyynCQ&c<+gg6-)+6Y%GcJN$Ksu&U@m~BQTB1!dRt~E665oa(# z7xLT3imVMNne<2RcQGo-{a%I9!kd z_Ql24E7E|8aQHp5*Hdlpg>sN@ zO6gb{DvCEHA;5TSlbomi_8?UDxdVhbm{EcV+MZ3*H#~=NMPpb!d%{A3D*Xo6F=}As zHqQ8MMH?t$wUsj%_gu%RXdgTA$I}HLb;~7UCBGJF>yePJDc$arR_e~`2v2I?BR&#s z)vAn4X&)lXRBWNNjDks z=#d>L3q6@V6{z#5`kt`&TeT)11P*mkeLdTz64QkF3wn?Ys!?P~xX1wryP6TK*}@?4 zm0+F+wTnPHt;}he6r;hI#`2bOu)g5%#twksuVm?1M_H*sRn}a*5*cgxgdu#7^Mt19 zyX`uv%pqV~7xdk5U!Db5`G0E?pZej_WohCom{})Oi^AIVoI%wDUApgS*7D64PWs&u z+r16eb~T=)RVv4r%!Jc#aDc=#bv*wxEA07(<%PQH%D403oAth8fKs3%YO*Y2Q8m{( z{GS@jMhE3eII3m_7_5G~OV55xH*>C`kX4#+13!{C<83DM$_~V~B07byeKl*hg#3l{`j0rRA818Y5*qf}jo^0n1H8o>dNILD8M}%M-Qj zV2Z5guH^^b&A=var3I%Z^|+!%ibE#TZL;{)=Z43RH<0^A94-$R#twc#a&Ly*R=!O< zo$M~RN2yrp#p|~wFTReeA9qy#yaO8 zp_8Aa=$=<~Kj$aNf3wjKNCsK?6_2JIjPGtv?WG2Yc2ls3(rVMyki!`kHOT5BoM0vT zba&r-l-VZ?qOPX8el(q4@(mz_S>DDp@oX=}ch zO0iDD&LV9V85z_h8qgCNSmEGQu;K1z@XvxA{{uWQZbg`j_AP!-<}4124@EKI`WLTS zBDJ#GK>k@?rC5aN!k>T;YkER-1&v@rq>)U}`+_uhOs|CJy^+>1#>?nxZ)I_hpv05y z&#SNZr>{@l&kx*_Ol%x=v>u=#aY|N_D^gwBh!5}6S9AJjs~qp?vrF7Zjcn#UQ9wsH@-t4Y?X6^! z9G8!>MvKyC7~?ISuS!bA(?_G=$xa-ldzwKq5fnN!HeK z0aNJu#D9u`DQ*0Z5S9D==1O{EUXW*&>}@D3>;r82b*)k~g$_{YfJ5`&ikDx9Sy9|_xY6C*;2}tzFboe8;4>GCINt0>S zS<0>O-n9!zee+k(Qa8mnH&v5Y|2S;qqD~}UQN*nxu-p}qvEUmt1Jhk}ZPPeROA=wQ zoaQ)(nF7pc%HnvJh}+Rsz)dN8I1{_4Ed@uOfP=<6oSheQv1%8SeXECT?T_WBb#|IDMS(PrL|HHc@0l%uQa2{GoDpYq_mKmG@C= zP@_|p*5T)p>_U>7D`e#JVS`lpHj*8t-1opHS)`zCY!?hR^?-@*Z5RVI503 zPDWJ)Nzcsk)0N$}qvFGmM|T1QVco64i6lC+g`1$S^sb+$sFjssb4VFm33kCRb9;Ng zzJ6*ccC}abRZX^Jhji1yX+D#N)=T6yXBXm=?B=^VXr8heGH|@SzJkFt@l|R44sBeVrk~CO3yX8x!v$Tj!Y|y90IlT&y^H}i6H zUD?#)&_j;KOo`%qi^yU6(F>ydfDOOZgXn&=>|jR=3&gE)s3sum{X)0w=T?#7MGIkX zhYKY$hFB}F@Ww_NF3%^an9_?O+oDkq+sqZ{rx%!GF{zE zpO6d29`;34R$}B}R&Wk~FMqxi^Icm>8%Vhb;$+cCYO|sS!r;PFjv+#I(|;|OCIk;9 z?~&TxtxPU9hxCOTH>|_e;AI{+N=%KblApP`g#*sx5~*(Et`e)g3AB>+jkonFR@xFh zZDQU*o#Y4#jq=hW0tk5Vg3{ z^~eCPqh1vT*(IW zZ<>ApLlYQ&@CnD8onX0U2I2r}Wu|xvk`D1@efePE8|UUg(aGNPPyD}mdbQF2ou_+^ zV%d0SL_iP6VqL}Vc74-ZN1svP2B_L8^9W*?@b~9IGvd74LOcqQ!0T0HuZ1Nc=f@tG z@5|5)u!9UoPbLW2Z9q;c$BEOb&+Ad9#`u04z{2RRU?TJ{RKJCIbdE9M6;k(#T>lc( z4Lu=2H#!_2xQJQekhNRs+k*b->_pWmN#1>Uih3PyrO(Uy^F2WrtM7BlekAThyv%77 zwW6Q{1uLb;g@t9rm#Ga2K`+7(21H0WDc)W&lSj7R8q+`$)oVmGyZjk-rM?xwS;teT z$ewjkvT|5;#2eLHZ_+jrB@5ElWPMF$QgLwA__~xV)Q#+oTmPMYcDre2SCuD;{YHX( znLKn6`BoiygDkgPgG$F@>0hYs14i|+-->z-Ugo~nOjm5D-#qI4xm6wFBEC=)vQ8!i z=FRK>)Y z>}$^3stk)0j37TT)}SlMcypW3%3UFa3+X`a8P`TZ9k9fFLPyNB4kc3E;bDGi$kw2e zoo0LIZG5p|9`>_M##H^b>t}m~j&EmN*t8>O#Ly^6y4D?aHRYFg{-?b%XbMg_6C#Tr zSU7x!)G8i^KQ4X*?0$6r>y7de~f&^Ix zJW9Q^Zbe?AL&t<*hi&Y~cmN*~_j&T!Y5u9{24GEh(97tRAE^b;W`5#0HYz}V$GtJV z%=|?QA&u=Mm+8$XU7N3#E|*tuLq>2QR`Hm|tuR zc(gEnv;p*{yK>fHpm=}aia09J5KH{Q$lZW}O{tT%#D>k`fb?vGjsLBru#X^__cPQ( zSnJb3m!&F@J!=IEKpvps#BILbTVo6nTe1FBHX(Fi_xXEK;S9E5T?)1`If7ECb_J`wrTr(3H)G5=MU1w zldCO@zMKrz|G!p*O+Q$o!ShxY}`Ie822 z7Q-KXsu$9IE~j~`QnOH9MzR~~C-j%grH?q@8QY}Zy5g`tE% z%+^uf0A^-|wmC-VvIwk$Zy?lh9|(3lDol{LBA@q8#^Mv}svSR_lVUwvSO<-Ec+ZW- z>8$-=z-v*h7)LgXibs9#a3?ioU^EW?Qt*pHdVAPSww;(4B~a2*#_1h^=puh3icq(j_Q-0@2a zIXfbuax?cxt|fId&~|xum@$~#0A{$|QT;y$kD=@@z~F|G*Wjdc{AK}i(zdWhrnFcLu=}k#3DE=s7 zB+{Xa|4LD87M-QLw$8bD4T`7;amWUNt70{~dx@1D^~7)^Y17T0iA~m;kWzC$Zk>N) z62eq>|0d7rN$SEi#_H*&4alGc%GA_1_v zN6nARp|5Xe5hyQpNAGxUU0Hn(8+XIPU{T~cKvXBLK zxpI5WhOt3g_56~i1@$W^t?jauur0v&s9n9;U-Cs_~#)Z%>)rnE8b5LEz zvi-G_xYZ$zHHCSpSnpe4j4iooero1Svw-+}_E-Q6%+5k9o$bCM;j>*6|#{`Q={+=6l zJAcSS7kTEho==m^jWkO<(^;eIdc1N!R|a_GZc$ zr~5HBBVYYa>G*<@fo~=$)$R8p9Z&bK?15oPep^003jRkDi^-DpD~MLD(>K&h(4+2v zF*IF$=xsVbv?L5UPd%VaT#hx%j;YZC^@3isEh@b*Y>XS!v*($}#F~ZVJY)B{@2)lu zr8XS|j=1s74z5b!mwyT&pU>`XZe*{x;y-MVx#O{2N4^Rhd>!1EbLNK6=bzoPbcZXx z!VX5~gw_O7v147zPpj<_l%ZLP1W&_poYOs3QI$z(yJ}kCLP_LJhT${`(Lx0lFaljR0>szyv5V zd6`9G4@g|T=qlFCNrB1Dki_qO!lY?V1_Y18O;vrn zazkE#LV-$`AxmVR|ACde=tXD(5j6*VkL6DNg~boNZ)=9%;y>|kLa}~6m0C!l_B}t4 zrbwD3%K*gTnIdLD&-2Xe|C0vkC!$DD9_|N9@EFP--@KutI%uhu?oGxelSe`;E8LJ{ zBaFPH&s#Noe#Z&l%|W|^Y)2BPURqx;1{MT}}r z4RoW@#oT2{TV?9#I2LPnbp~PRb{hZi-$v=sMs-57ewB*}!2ZMW+#_ zB@IaU=wr~CT8l0!SJv;rk)1}Ox%Lrlw18b5;FhimNK?#WWw?*;)+C>Cy-5MiUVkjB zQ}K$~)=SuMA%}5(B?qKfxe#@H#=vX7w_@*(={x*7h`04%wh& zmi^b-6?CmJYNl%Rn^fB!Ry|Tk-KPyU-{^ZABA#bQ;{jHLEcez0-(;Q2Yn1oXR$t&D zX43HUe^sUMn-tOS?1#*;Vj#S)^@Ec@k{!^UxEuOz4_fB?1n;{ zwE-WA;;&5IC#&>KM*Wr_l;1NsgjD~G#<8(}`69K{*6A@(0b1kNU7a^+wI|T&zVV*0 z=(u+7VyIMX;T_8vs`v=1_-m1=RBSjm*Wp=!3D23X)U#T0h2-M9`~S>; zAcxVcYQpyaf&b)=|HXgCiAaC=FOR_h&W09as%9GBA5+#=aNUjI)=|7$Mfzh>7nT1k zFY6GM*an+u=}Bs{*~H}aF4B8%;5bBJ9_AAY4~2cVW5>!ZT=VO`*hCDJ7qnET_6VM5 zR*XWI;ZaAq=Yh#SwBkgf(jqcQV=#l^Y!)BpS$2Q(g6%c$BZ+05jP491z2V03caI}( zokIuAk(JW!k@sf#M-Hdo^9+5xjTbrBE19RiMO*i|>T|o9Un%RkJPnfHT_YPoN74(t zJ+ha+sdSzjCxc`q|HxP$R#QEv5;{#`1tnwHoV*QHVVm?41tv{u5SgN+Y3jQsNlJbr z-+?=9$Th8s{E^m5)f2jf-gTb^HH(5q@9>w;;3LtTKEGBqnd2*1$@=XVqJ60Duo<)~ zt?(S$`~Xyaep$|DH)V@*T4IT&y5y=RDbL4rSY{~Ma*oZ~Vu=)-mU&ODk1(Z}H6=*DK^Y+TX-@ymnNo(pH zU3coou}wWf2L5CS&tS$|#$bjxfLkLyW!Twy<6OSJY{i?ZFgD}>t1wVnIBNxsH^ZQa z_ET&KFIJXP2r8C_CgMpUwf4Nspe`|@JvDbaf|B;vBqBrbuiH+ulC}Kj*OdmiBA$sF zurc&sQD8-R+SNuQ^Ym$F?nsE8{zDXXaC{4S`rdfmcW&RkkK3cWehBs1HOKwdswZOp z%s%>NW~zjOVJOle=;Px)@B8|;15OR^=@BGOEq}2@@1YHzsJ=46hVNmv7#AYgLe7!JuFhNTbL6r7CiUlONUBR>_aUMwb zTL_N~S5xKu3O-_rns%V9x|?xl_`QN=X>wS>3>Bbt1n#N$h`==Xcy$q!j1ZR)R{?yI`@(k~D&g#scsC|!<`U{_gUdJ((ct+RqFFoOTmBb+ z@@-JhZ~bjh--#tuk%OW*oNHQ>gN?fjxUa(aUIo}1SKC+&t!UDwSCA+46)?#_vbKlY znie_ggb_Sr$VOsW#uy<#LB-AlcrpAyOL6~?wu%!x_vV;jbY!Rf;}RwGAEKvpHDq3F z85AK3aJNMzzo5oBGT^G;F((OU)w2R8qB;k^3fI` zE&M2YTj5V@=GbThRiBmkKena^nEH*t%GR72Ln+4eebtfIwEV-Z*NoOPc!3!W5#9lw zfc|XsvI38ln^(#_X1G;G`F;hwO{{59)T`(tCHz*14|k%L9v){KY9B^ck+p>4Hwp^X z)V)}&ca9q$0^uIGBpc@TJ21vM^^{h3i{Hiyb5&+x)&#eWRU zM1u`O2=q9*_euMCJKtQX_}Rd%z^Agb!d@lOQtF-EU~`G4i4{jq2acYgkXRne-jKV) zmj`6TOsvhCCRT#Mpp4R4xjF8>+qF!FWvrsE1l54^_@<^OL>K+uONHe(7eJvlQdnIX}_^W@1ef-e3&h#ZEX$osjvUWsZjfb}Sr+l=CTz5|= z@B99fWN7v;Z@fdvxS&ZTb&2qc$v5Zw`~KxXangNcu@V|I*5E+$*xCLx#@^onq*a?r zgl0^kpDc8Lcxkdj>cSn-;C2L15V?+)Quipqa)wRK=e+-MYHxzR99z8VGoYXhnfFMv zk2x+u-dl8{`a%5MKdy5oouu06<)RHUO3+ERcB@+$wdd9jV^6j8h*pi0@Guo5H(`f-;GL4Djgv~r_pY4okCDji zVn4n@4fCcS_PaR9iJqt9b-nSw{+jz0tL*HIQ%Ys6DIs>;{PBI%)8DO?n+!8jX%3FR z_ox?vdx?hHJc(`NAIwT-P&B8}v{Q%eFoIdZ7hkI8=OTZ9oS(?=oX5~kryuas6z9|lPO$)S>h zTRv@0JZnxAxg?skM>vRK+4#H|*TQcC53m9tTsVTRICE2Q_cIYneKKPxpNrD}(XNR)#164=Z52Z)j_e_EeI+-9gv6K!j^NfzfQR5}PV2h^1%e{lRDymB)yhzTZ<(P6Ec&fFRR^J~ z7^rJ+#$vBfPV_@XbY$q*2MJSyw*XjH6q9>jnJ&7rW_D3HKLv76gWDI`U3Mokjy5OZ z4=4a91Xgjs5aKK{+MOP!V(BlttqyFu55ZCj+}x^m<6%M=;%0xyl~g6@FLKpXVxNJN zBdUf zs|;Cijn(m_*9}cs1h~2~-*SWbnGLQGSUfaBZ@ZP2!Bcmb%hv;u?YBF*N-0pJ(nWp0 z>qZrcXa|wfmQOU`O3kudvIc>ega0$g%rR;*GVlaFM1}oAgm=14y=Xf?z!dvR4Pu$; z%Kl&??nf&)YH<{GG_^x+C%`0(MZkh7pGh{ zA2lb_48$3{=jkvA^H0=wy43zpirFxi4WOj1tXJt};CoH=cW`y32FWy8ceqa;uU9G9 zp-ach!0Az-DD_VbxlPShGZT_<3vsbTn&buvAdS(#^}nA@5k;sea%oHpIKQvw5G(!d zt|3R#3rLQQIDHH|yZw@PZvz@2guQ`&MM{HIrv#g8c+LpB8?A@Fh;w+VA|YQ4{(u6eX_g%_d5(!5icC%sFp;5Vls4$i)kqm~8|P z+ISl@d&mt+Zf@QuO01EW%$YpI?uv>ki~3&i${y0&z-Jurw*<3Cy-k1Nt^qi~-1cF? zM<#P;asb9<*|xaBxG(dyCWLDfxvKul1fEeLv~JAF9QJ#zr|hbW5J>}RG(p#5d)N^? zJ$jC@MJjhYe$2w$hL-d`@Symo{ZS6T(>U{SaulaeME!J9HGHPoXP4)mQ^i=10>?B# zY6qe52bfktSlNIV9n+rFjDhGdRQvz zt(8+@1R6sHdEiI6#Pv>D*J6?P%M7jvL?4<1Yx*lJ<(ud8yDc+!8q?a7SBBOVss?iB zQnJ<+3{u?4u#_@0Tg6eB*)BJQu@*3^o!Ym#B)CetEEK#A(&zjPw3tinE5laZ-8QwA zl{C54O5H#~^{;#e+RW9V0l!C}AA#|Q%9=7zC&J0pH6o6ZJy#{(I)aXU&Pyl!$&bh@L@LWte~w5l3wv<+ zHCIP%Wz-X<^0R(BT9c4IOq6rE4wU*JG^3y#!UA+a9YJL6fmZwUMPEvvhyLD6PDsfJ z8ba7x`M_V)idqGxRt&p*mAS9kWm_7CSn!ts88`0)v7ef9CVoQuhxGJy9s%sIq&@4@ z%F8-^p1i2})TY9#Bx;H5`s*5fjkz>2)^tw_Sk0B+r8adm=DeJV^C?U#EH3Cxuj5vt zvi<}YfoEk^Wwt^U!rZxZRA+zAb@>xvo>T=ii_7e&IG-SG5_Zk~^iV5_S#*lB z+E@L;-fjdH$i(5`vY%x`-$2b8zxADy48KQ*C1KBp>n<^K-oG({Lq@Sa zCcN%YcL@SSMd84#mmJ%)sCgSX@ke!Epaq=SsFNZDgT4K9oId9hbk znLvA9GiQ&77Vd)C!L>G9ygndLrAEc@q|ryExlG!@M0Bd_rnzJ+W^gh&4+a`wWD|Pz z0iwsGM;4G-kDXIDb1bP|>Sc<@Un+N*v-g*q?M8H$^?CIZFMQKbYqKp6`~}=I@?ba| z*N8hP?8=kP0*C1DuU#-hVYf&NaY-Srd1<{KZY;=ZQ3U%Od~CUq*0`*~sV{N3 z#}H;2)(`DkGY;Kxg<5>zee|PmJ^Gyp$WCeArpDqP=zK^uqxVc|;2HPEY=4*5iQRwb z^YI~drg$)M*!toF-;HpIC*qCcSwoea&+O;2H>8o&DOC}{ehPVbRCycfa)kW>9vP{O zU(R4(_!zeT1s~#RNa6C4BMcj%>gd;u=NQu?oU!BXD1GcD*0R&-EVR<)%2@I2;-w`z z9iKbol1&yvhSrZgm4Fe>tz{*z7W|%14+k^?6uhoS(a8mQD!x`E91L{e+$zMz3gjRq^?@61*X(T>Ww}GAD>{zbW@6 z=S0~8ej6XQY$`EI^=Q{qS8kLKSYg-~uzy-Idlf}ANoks^N^N$zz^5B}N2n!ng2ANgEKw_aorRLK*y| zGyTn4>jp1(OzZ-+oZFLI=XaU(CA(;c8S2OB=3w2Wk}txXfeve;3)G9YSZRwYX_@- z#m%o-d&Av^rxU(X@Ev<}7ve7trhd3xr*Or@oTFlXfc(w6=%nT3Krx8?Yd3ZTO&}Ca z5ki*=D-w1>vn-i)_avF7XaZH{4^RqCEh~*+TX8xe*OMggE1XnZ{|*t~>&LVVnq&EG zUAcJ>mfAh8Qh#yVSKUaRV4c25-`=Dg%D|U(Qa`Gt3&d{`FSN8xE+Yxa!7$XG#F}+S{#g4 zWk-ibfh7nnPp zZ9vc|WfZg~DQjHq0p_ykz_H%?3#LrqP8dG)nycSxaTX=SS$ld+%`Mg0lD76B|4baW zQH$#;zpgP+eKlcyArV_F{&S-32{`;8=QgW7L8Zmvro-vF&a1OKkP>S?v7iFNtz4-n zantGdEGH|bORl{7nQx(D;q5Ak3*W&>ojP7_}Hx=RBbV zky5tzznax!&vWtbX7#jK%zba}u=;CM&k*B`2pxKUe7IL8q5}iDQd+LQ=tqBXQB9jk liRHtl`E-scRz!#mIo~}gS`2B0YN0o=_x*%ems|)C{{iVm6O{k} literal 0 HcmV?d00001 diff --git a/log/info.2022-03-16.01767904371465962.tmp b/log/info.2022-03-16.01767904371465962.tmp new file mode 100644 index 00000000..d5c5f3f7 --- /dev/null +++ b/log/info.2022-03-16.01767904371465962.tmp @@ -0,0 +1,1019 @@ +2022-03-17 00:22:07.709 INFO 35086 --- [nio-8086-exec-3] o.keycloak.adapters.KeycloakDeployment : Loaded URLs from https://auth.iotkit.cc/realms/iotkit/.well-known/openid-configuration +2022-03-17 00:22:08.815 INFO 35086 --- [nio-8086-exec-3] org.mongodb.driver.connection : Opened connection [connectionId{localValue:5, serverValue:5942935}] to dds-wz9rfynv908bptqw-pub.mongodb.rds.aliyuncs.com:3717 +2022-03-17 00:22:10.444 ERROR 35086 --- [nio-8086-exec-3] c.i.m.config.GlobalExceptionHandler : handler exception + +cc.iotkit.common.exception.BizException: add protocol gateway error + at cc.iotkit.manager.controller.ProtocolController.addGateway(ProtocolController.java:38) + at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) + at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.lang.reflect.Method.invoke(Method.java:498) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) + at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) + at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter.doFilter(KeycloakAuthenticatedActionsFilter.java:57) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter.doFilter(KeycloakSecurityContextRequestFilter.java:61) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:96) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter.successfulAuthentication(KeycloakAuthenticationProcessingFilter.java:214) + at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:233) + at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:327) + at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115) + at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter.doFilter(KeycloakAuthenticatedActionsFilter.java:74) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter.doFilter(KeycloakSecurityContextRequestFilter.java:92) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter.successfulAuthentication(KeycloakAuthenticationProcessingFilter.java:214) + at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:233) + at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:96) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) + at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110) + at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211) + at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183) + at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354) + at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) + at org.keycloak.adapters.tomcat.AbstractAuthenticatedActionsValve.invoke(AbstractAuthenticatedActionsValve.java:67) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540) + at org.keycloak.adapters.tomcat.AbstractKeycloakAuthenticatorValve.invoke(AbstractKeycloakAuthenticatorValve.java:181) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) + at java.lang.Thread.run(Thread.java:748) +Caused by: org.apache.pulsar.client.admin.PulsarAdminException: java.lang.IllegalArgumentException: The URI scheme, of the URI pulsar://192.168.0.112:6650/admin/v3/functions/public/iot/.UplinkTranslateFunction_mqtt-gateway, must be equal (ignoring case) to 'http', 'https', 'ws', or 'wss' + at org.apache.pulsar.client.admin.internal.BaseResource.getApiException(BaseResource.java:247) + at org.apache.pulsar.client.admin.internal.FunctionsImpl$2.failed(FunctionsImpl.java:154) + at org.apache.pulsar.shade.org.glassfish.jersey.client.JerseyInvocation$1.failed(JerseyInvocation.java:882) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.processFailure(ClientRuntime.java:247) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.processFailure(ClientRuntime.java:242) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.lambda$null$6(ClientRuntime.java:184) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors$1.call(Errors.java:248) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors$1.call(Errors.java:244) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:292) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:274) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:244) + at org.apache.pulsar.shade.org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:288) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.lambda$createRunnableForAsyncProcessing$7(ClientRuntime.java:156) + at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) + at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) + at java.util.concurrent.FutureTask.run(FutureTask.java) + at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) + at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) + ... 1 common frames omitted +Caused by: java.lang.IllegalArgumentException: The URI scheme, of the URI pulsar://192.168.0.112:6650/admin/v3/functions/public/iot/.UplinkTranslateFunction_mqtt-gateway, must be equal (ignoring case) to 'http', 'https', 'ws', or 'wss' + at org.apache.pulsar.shade.org.asynchttpclient.uri.Uri.validateSupportedScheme(Uri.java:289) + at org.apache.pulsar.shade.org.asynchttpclient.RequestBuilderBase.computeUri(RequestBuilderBase.java:605) + at org.apache.pulsar.shade.org.asynchttpclient.RequestBuilderBase.build(RequestBuilderBase.java:614) + at org.apache.pulsar.shade.org.asynchttpclient.BoundRequestBuilder.execute(BoundRequestBuilder.java:39) + at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.oneShot(AsyncHttpConnector.java:316) + at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$retryOrTimeOut$2(AsyncHttpConnector.java:236) + at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.retryOperation(AsyncHttpConnector.java:248) + at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.retryOrTimeOut(AsyncHttpConnector.java:236) + at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.apply(AsyncHttpConnector.java:201) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.lambda$null$6(ClientRuntime.java:182) + ... 13 common frames omitted + +2022-03-17 00:23:44.681 INFO 35086 --- [ionShutdownHook] org.quartz.core.QuartzScheduler : Scheduler schedulerFactoryBean_$_NON_CLUSTERED paused. +2022-03-17 00:23:49.731 INFO 35086 --- [ionShutdownHook] .m.i.MqttPahoMessageDrivenChannelAdapter : stopped bean 'inbound'; defined in: 'class path resource [cc/iotkit/ruleengine/config/RuleConfiguration.class]'; from source: 'cc.iotkit.ruleengine.config.RuleConfiguration.inbound()' +2022-03-17 00:23:49.732 INFO 35086 --- [ionShutdownHook] o.s.i.endpoint.EventDrivenConsumer : Removing {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel +2022-03-17 00:23:49.732 INFO 35086 --- [ionShutdownHook] o.s.i.channel.PublishSubscribeChannel : Channel 'application.errorChannel' has 0 subscriber(s). +2022-03-17 00:23:49.732 INFO 35086 --- [ionShutdownHook] o.s.i.endpoint.EventDrivenConsumer : stopped bean '_org.springframework.integration.errorLogger' +2022-03-17 00:23:49.733 INFO 35086 --- [ionShutdownHook] o.s.i.endpoint.EventDrivenConsumer : Removing {message-handler:ruleConfiguration.handler.serviceActivator} as a subscriber to the 'mqttInboundChannel' channel +2022-03-17 00:23:49.733 INFO 35086 --- [ionShutdownHook] o.s.integration.channel.DirectChannel : Channel 'application.mqttInboundChannel' has 0 subscriber(s). +2022-03-17 00:23:49.733 INFO 35086 --- [ionShutdownHook] o.s.i.endpoint.EventDrivenConsumer : stopped bean 'ruleConfiguration.handler.serviceActivator' +2022-03-17 00:23:49.741 INFO 35086 --- [ionShutdownHook] org.quartz.core.QuartzScheduler : Scheduler schedulerFactoryBean_$_NON_CLUSTERED shutting down. +2022-03-17 00:23:49.741 INFO 35086 --- [ionShutdownHook] org.quartz.core.QuartzScheduler : Scheduler schedulerFactoryBean_$_NON_CLUSTERED paused. +2022-03-17 00:23:49.742 INFO 35086 --- [ionShutdownHook] org.quartz.core.QuartzScheduler : Scheduler schedulerFactoryBean_$_NON_CLUSTERED shutdown complete. +2022-03-17 00:23:49.743 INFO 35086 --- [ionShutdownHook] o.s.s.quartz.SchedulerFactoryBean : Shutting down Quartz Scheduler +2022-03-17 00:23:55.525 INFO 35449 --- [ main] cc.iotkit.manager.Application : Starting Application using Java 1.8.0_261 on songjiangangdeMacBook-Pro.local with PID 35449 (/Users/sjg/home/gitee/open-source/iotkit-parent/manager/target/classes started by sjg in /Users/sjg/home/gitee/open-source/iotkit-parent) +2022-03-17 00:23:55.529 DEBUG 35449 --- [ main] cc.iotkit.manager.Application : Running with Spring Boot v2.6.2, Spring v5.3.14 +2022-03-17 00:23:55.529 INFO 35449 --- [ main] cc.iotkit.manager.Application : The following profiles are active: dev +2022-03-17 00:23:56.897 INFO 35449 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode! +2022-03-17 00:23:56.898 INFO 35449 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Elasticsearch repositories in DEFAULT mode. +2022-03-17 00:23:57.180 INFO 35449 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 275 ms. Found 1 Elasticsearch repository interfaces. +2022-03-17 00:23:57.296 INFO 35449 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode! +2022-03-17 00:23:57.296 INFO 35449 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data MongoDB repositories in DEFAULT mode. +2022-03-17 00:23:57.422 INFO 35449 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 125 ms. Found 20 MongoDB repository interfaces. +2022-03-17 00:23:57.690 INFO 35449 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode! +2022-03-17 00:23:57.692 INFO 35449 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Reactive Elasticsearch repositories in DEFAULT mode. +2022-03-17 00:23:57.701 INFO 35449 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 8 ms. Found 0 Reactive Elasticsearch repository interfaces. +2022-03-17 00:23:58.019 INFO 35449 --- [ main] faultConfiguringBeanFactoryPostProcessor : No bean named 'errorChannel' has been explicitly defined. Therefore, a default PublishSubscribeChannel will be created. +2022-03-17 00:23:58.048 INFO 35449 --- [ main] faultConfiguringBeanFactoryPostProcessor : No bean named 'integrationHeaderChannelRegistry' has been explicitly defined. Therefore, a default DefaultHeaderChannelRegistry will be created. +2022-03-17 00:23:58.264 INFO 35449 --- [ main] o.s.cloud.context.scope.GenericScope : BeanFactory id=cfb87af3-c30c-3a03-8b33-421165292980 +2022-03-17 00:23:58.602 INFO 35449 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.integration.config.IntegrationManagementConfiguration' of type [org.springframework.integration.config.IntegrationManagementConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) +2022-03-17 00:23:58.626 INFO 35449 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'integrationChannelResolver' of type [org.springframework.integration.support.channel.BeanFactoryChannelResolver] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) +2022-03-17 00:23:59.221 INFO 35449 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8086 (http) +2022-03-17 00:23:59.237 INFO 35449 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] +2022-03-17 00:23:59.238 INFO 35449 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.56] +2022-03-17 00:23:59.370 INFO 35449 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +2022-03-17 00:23:59.370 INFO 35449 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 3717 ms +2022-03-17 00:23:59.800 INFO 35449 --- [ main] org.mongodb.driver.cluster : Cluster created with settings {hosts=[dds-wz9rfynv908bptqw-pub.mongodb.rds.aliyuncs.com:3717], mode=SINGLE, requiredClusterType=UNKNOWN, serverSelectionTimeout='30000 ms'} +2022-03-17 00:23:59.984 WARN 35449 --- [ main] o.s.data.convert.CustomConversions : Registering converter from class java.time.LocalDateTime to class org.joda.time.LocalDateTime as reading converter although it doesn't convert from a store-supported type! You might want to check your annotation setup at the converter implementation. +2022-03-17 00:24:00.039 INFO 35449 --- [iyuncs.com:3717] org.mongodb.driver.connection : Opened connection [connectionId{localValue:2, serverValue:5943240}] to dds-wz9rfynv908bptqw-pub.mongodb.rds.aliyuncs.com:3717 +2022-03-17 00:24:00.039 INFO 35449 --- [iyuncs.com:3717] org.mongodb.driver.connection : Opened connection [connectionId{localValue:1, serverValue:5943239}] to dds-wz9rfynv908bptqw-pub.mongodb.rds.aliyuncs.com:3717 +2022-03-17 00:24:00.039 INFO 35449 --- [iyuncs.com:3717] org.mongodb.driver.cluster : Monitor thread successfully connected to server with description ServerDescription{address=dds-wz9rfynv908bptqw-pub.mongodb.rds.aliyuncs.com:3717, type=SHARD_ROUTER, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=8, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=72114855} +2022-03-17 00:24:00.128 WARN 35449 --- [ main] o.s.data.convert.CustomConversions : Registering converter from class java.time.LocalDateTime to class org.joda.time.LocalDateTime as reading converter although it doesn't convert from a store-supported type! You might want to check your annotation setup at the converter implementation. +2022-03-17 00:24:02.145 WARN 35449 --- [ main] .m.SimpleElasticsearchPersistentProperty : Unsupported type 'class java.lang.Long' for date property 'occur'. +2022-03-17 00:24:02.148 WARN 35449 --- [ main] .m.SimpleElasticsearchPersistentProperty : Unsupported type 'class java.lang.Long' for date property 'time'. +2022-03-17 00:24:02.310 INFO 35449 --- [pool-3-thread-1] org.mongodb.driver.connection : Opened connection [connectionId{localValue:3, serverValue:5943246}] to dds-wz9rfynv908bptqw-pub.mongodb.rds.aliyuncs.com:3717 +2022-03-17 00:24:02.471 WARN 35449 --- [ main] org.elasticsearch.client.RestClient : request [HEAD http://192.168.0.112:9200/thing_model_messages?ignore_throttled=false&ignore_unavailable=false&expand_wildcards=open%2Cclosed&allow_no_indices=false] returned 1 warnings: [299 Elasticsearch-8.1.0-3700f7679f7d95e36da0b43762189bab189bc53a "[ignore_throttled] parameter is deprecated because frozen indices have been deprecated. Consider cold or frozen tiers in place of frozen indices."] +2022-03-17 00:24:02.871 WARN 35449 --- [ main] .i.n.r.d.DnsServerAddressStreamProviders : Can not find org.apache.pulsar.shade.io.netty.resolver.dns.macos.MacOSDnsServerAddressStreamProvider in the classpath, fallback to system defaults. This may result in incorrect DNS resolutions on MacOS. +2022-03-17 00:24:03.770 INFO 35449 --- [r-client-io-1-1] o.a.pulsar.client.impl.ConnectionPool : [[id: 0xae4892c5, L:/192.168.0.109:54411 - R:/192.168.0.112:6650]] Connected to server +2022-03-17 00:24:04.593 INFO 35449 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Will secure any request with [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@503b5337, org.springframework.security.web.context.SecurityContextPersistenceFilter@65e4eba5, org.springframework.security.web.header.HeaderWriterFilter@56511eda, org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter@6abe62bb, org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter@11c3d22f, org.springframework.security.web.authentication.logout.LogoutFilter@14c1cba6, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@be56353, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@1ae69abe, org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter@29c25bbc, org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter@30704f85, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@265361a, org.springframework.security.web.session.SessionManagementFilter@760f4310, org.springframework.security.web.access.ExceptionTranslationFilter@70c6c6a7, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@5fc3dfc1] +2022-03-17 00:24:04.660 INFO 35449 --- [ main] org.quartz.impl.StdSchedulerFactory : Using default implementation for ThreadExecutor +2022-03-17 00:24:04.682 INFO 35449 --- [ main] org.quartz.core.SchedulerSignalerImpl : Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl +2022-03-17 00:24:04.682 INFO 35449 --- [ main] org.quartz.core.QuartzScheduler : Quartz Scheduler v.2.3.2 created. +2022-03-17 00:24:04.684 INFO 35449 --- [ main] org.quartz.simpl.RAMJobStore : RAMJobStore initialized. +2022-03-17 00:24:04.685 INFO 35449 --- [ main] org.quartz.core.QuartzScheduler : Scheduler meta-data: Quartz Scheduler (v2.3.2) 'schedulerFactoryBean' with instanceId 'NON_CLUSTERED' + Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally. + NOT STARTED. + Currently in standby mode. + Number of jobs executed: 0 + Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads. + Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered. + +2022-03-17 00:24:04.685 INFO 35449 --- [ main] org.quartz.impl.StdSchedulerFactory : Quartz scheduler 'schedulerFactoryBean' initialized from an externally provided properties instance. +2022-03-17 00:24:04.685 INFO 35449 --- [ main] org.quartz.impl.StdSchedulerFactory : Quartz scheduler version: 2.3.2 +2022-03-17 00:24:04.685 INFO 35449 --- [ main] org.quartz.core.QuartzScheduler : JobFactory set to: cc.iotkit.ruleengine.config.JobFactory@331fe6d4 +2022-03-17 00:24:05.310 INFO 35449 --- [pool-4-thread-1] org.mongodb.driver.connection : Opened connection [connectionId{localValue:4, serverValue:5943253}] to dds-wz9rfynv908bptqw-pub.mongodb.rds.aliyuncs.com:3717 +2022-03-17 00:24:05.556 INFO 35449 --- [pool-4-thread-1] cc.iotkit.ruleengine.scene.SceneManager : got scene 460f0805-503f-428a-936c-c5e7278024d5 to init +2022-03-17 00:24:05.653 INFO 35449 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel +2022-03-17 00:24:05.654 INFO 35449 --- [ main] o.s.i.channel.PublishSubscribeChannel : Channel 'application.errorChannel' has 1 subscriber(s). +2022-03-17 00:24:05.654 INFO 35449 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started bean '_org.springframework.integration.errorLogger' +2022-03-17 00:24:05.654 INFO 35449 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {message-handler:ruleConfiguration.handler.serviceActivator} as a subscriber to the 'mqttInboundChannel' channel +2022-03-17 00:24:05.654 INFO 35449 --- [ main] o.s.integration.channel.DirectChannel : Channel 'application.mqttInboundChannel' has 1 subscriber(s). +2022-03-17 00:24:05.654 INFO 35449 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started bean 'ruleConfiguration.handler.serviceActivator' +2022-03-17 00:24:05.670 INFO 35449 --- [pool-4-thread-1] cc.iotkit.ruleengine.scene.SceneManager : got scene bef61d60-f78f-4ab4-a1a8-dc4f1bab4978 to init +2022-03-17 00:24:06.055 INFO 35449 --- [ main] .m.i.MqttPahoMessageDrivenChannelAdapter : started bean 'inbound'; defined in: 'class path resource [cc/iotkit/ruleengine/config/RuleConfiguration.class]'; from source: 'cc.iotkit.ruleengine.config.RuleConfiguration.inbound()' +2022-03-17 00:24:06.073 INFO 35449 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8086 (http) with context path '' +2022-03-17 00:24:06.587 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void +2022-03-17 00:24:06.592 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void +2022-03-17 00:24:06.593 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void +2022-03-17 00:24:06.599 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void +2022-03-17 00:24:06.599 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void +2022-03-17 00:24:06.603 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void +2022-03-17 00:24:06.632 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void +2022-03-17 00:24:06.635 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void +2022-03-17 00:24:06.636 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void +2022-03-17 00:24:06.641 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void +2022-03-17 00:24:06.642 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void +2022-03-17 00:24:06.697 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void +2022-03-17 00:24:06.702 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void +2022-03-17 00:24:06.809 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void +2022-03-17 00:24:06.811 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void +2022-03-17 00:24:06.812 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void +2022-03-17 00:24:06.817 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void +2022-03-17 00:24:06.818 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void +2022-03-17 00:24:06.819 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void +2022-03-17 00:24:06.833 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void +2022-03-17 00:24:06.834 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void +2022-03-17 00:24:06.837 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void +2022-03-17 00:24:06.840 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void +2022-03-17 00:24:06.920 INFO 35449 --- [ main] o.s.s.quartz.SchedulerFactoryBean : Starting Quartz Scheduler now +2022-03-17 00:24:06.920 INFO 35449 --- [ main] org.quartz.core.QuartzScheduler : Scheduler schedulerFactoryBean_$_NON_CLUSTERED started. +2022-03-17 00:24:06.930 INFO 35449 --- [ main] cc.iotkit.manager.Application : Started Application in 12.648 seconds (JVM running for 13.495) +2022-03-17 00:24:14.552 INFO 35449 --- [nio-8086-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' +2022-03-17 00:24:14.553 INFO 35449 --- [nio-8086-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' +2022-03-17 00:24:14.558 INFO 35449 --- [nio-8086-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 5 ms +2022-03-17 00:24:15.726 INFO 35449 --- [nio-8086-exec-1] o.keycloak.adapters.KeycloakDeployment : Loaded URLs from https://auth.iotkit.cc/realms/iotkit/.well-known/openid-configuration +2022-03-17 00:24:16.809 INFO 35449 --- [nio-8086-exec-1] org.mongodb.driver.connection : Opened connection [connectionId{localValue:5, serverValue:5943283}] to dds-wz9rfynv908bptqw-pub.mongodb.rds.aliyuncs.com:3717 +2022-03-17 00:24:19.269 ERROR 35449 --- [nio-8086-exec-1] c.i.m.config.GlobalExceptionHandler : handler exception + +cc.iotkit.common.exception.BizException: add protocol gateway error + at cc.iotkit.manager.controller.ProtocolController.addGateway(ProtocolController.java:38) + at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) + at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.lang.reflect.Method.invoke(Method.java:498) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) + at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) + at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter.doFilter(KeycloakAuthenticatedActionsFilter.java:57) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter.doFilter(KeycloakSecurityContextRequestFilter.java:61) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:96) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter.successfulAuthentication(KeycloakAuthenticationProcessingFilter.java:214) + at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:233) + at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:327) + at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115) + at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter.doFilter(KeycloakAuthenticatedActionsFilter.java:74) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter.doFilter(KeycloakSecurityContextRequestFilter.java:92) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter.successfulAuthentication(KeycloakAuthenticationProcessingFilter.java:214) + at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:233) + at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:96) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) + at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110) + at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211) + at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183) + at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354) + at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) + at org.keycloak.adapters.tomcat.AbstractAuthenticatedActionsValve.invoke(AbstractAuthenticatedActionsValve.java:67) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540) + at org.keycloak.adapters.tomcat.AbstractKeycloakAuthenticatorValve.invoke(AbstractKeycloakAuthenticatorValve.java:181) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) + at java.lang.Thread.run(Thread.java:748) +Caused by: org.apache.pulsar.client.admin.PulsarAdminException: java.util.concurrent.CompletionException: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Remotely closed + at org.apache.pulsar.client.admin.internal.BaseResource.getApiException(BaseResource.java:247) + at org.apache.pulsar.client.admin.internal.FunctionsImpl$2.failed(FunctionsImpl.java:154) + at org.apache.pulsar.shade.org.glassfish.jersey.client.JerseyInvocation$1.failed(JerseyInvocation.java:882) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.processFailure(ClientRuntime.java:247) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.processFailure(ClientRuntime.java:242) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.access$100(ClientRuntime.java:62) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime$2.lambda$failure$1(ClientRuntime.java:178) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors$1.call(Errors.java:248) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors$1.call(Errors.java:244) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:292) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:274) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:244) + at org.apache.pulsar.shade.org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:288) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime$2.failure(ClientRuntime.java:178) + at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$apply$1(AsyncHttpConnector.java:204) + at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:774) + at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:750) + at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:488) + at java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:1990) + at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$retryOperation$4(AsyncHttpConnector.java:263) + at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:774) + at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:750) + at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:488) + at java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:1990) + at org.apache.pulsar.shade.org.asynchttpclient.netty.NettyResponseFuture.abort(NettyResponseFuture.java:273) + at org.apache.pulsar.shade.org.asynchttpclient.netty.request.NettyRequestSender.abort(NettyRequestSender.java:473) + at org.apache.pulsar.shade.org.asynchttpclient.netty.request.NettyRequestSender.handleUnexpectedClosedChannel(NettyRequestSender.java:484) + at org.apache.pulsar.shade.org.asynchttpclient.netty.handler.AsyncHttpClientHandler.channelInactive(AsyncHttpClientHandler.java:145) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) + at org.apache.pulsar.shade.io.netty.handler.stream.ChunkedWriteHandler.channelInactive(ChunkedWriteHandler.java:137) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) + at org.apache.pulsar.shade.io.netty.channel.ChannelInboundHandlerAdapter.channelInactive(ChannelInboundHandlerAdapter.java:81) + at org.apache.pulsar.shade.io.netty.handler.codec.http.HttpContentDecoder.channelInactive(HttpContentDecoder.java:235) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) + at org.apache.pulsar.shade.io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelInactive(CombinedChannelDuplexHandler.java:418) + at org.apache.pulsar.shade.io.netty.handler.codec.ByteToMessageDecoder.channelInputClosed(ByteToMessageDecoder.java:389) + at org.apache.pulsar.shade.io.netty.handler.codec.ByteToMessageDecoder.channelInactive(ByteToMessageDecoder.java:354) + at org.apache.pulsar.shade.io.netty.handler.codec.http.HttpClientCodec$Decoder.channelInactive(HttpClientCodec.java:326) + at org.apache.pulsar.shade.io.netty.channel.CombinedChannelDuplexHandler.channelInactive(CombinedChannelDuplexHandler.java:221) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) + at org.apache.pulsar.shade.io.netty.channel.DefaultChannelPipeline$HeadContext.channelInactive(DefaultChannelPipeline.java:1405) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) + at org.apache.pulsar.shade.io.netty.channel.DefaultChannelPipeline.fireChannelInactive(DefaultChannelPipeline.java:901) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannel$AbstractUnsafe$8.run(AbstractChannel.java:831) + at org.apache.pulsar.shade.io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164) + at org.apache.pulsar.shade.io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:469) + at org.apache.pulsar.shade.io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500) + at org.apache.pulsar.shade.io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986) + at org.apache.pulsar.shade.io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) + at org.apache.pulsar.shade.io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) + ... 1 common frames omitted +Caused by: java.util.concurrent.CompletionException: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Remotely closed + at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:292) + at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:308) + at java.util.concurrent.CompletableFuture.orApply(CompletableFuture.java:1385) + at java.util.concurrent.CompletableFuture$OrApply.tryFire(CompletableFuture.java:1364) + ... 43 common frames omitted +Caused by: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Remotely closed + at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$retryOperation$4(AsyncHttpConnector.java:265) + ... 40 common frames omitted +Caused by: org.apache.pulsar.shade.org.asynchttpclient.exception.RemotelyClosedException: Remotely closed + at org.apache.pulsar.shade.org.asynchttpclient.exception.RemotelyClosedException.INSTANCE(Unknown Source) + +2022-03-17 00:29:56.110 ERROR 35449 --- [nio-8086-exec-5] c.i.m.config.GlobalExceptionHandler : handler exception + +cc.iotkit.common.exception.BizException: add protocol gateway error + at cc.iotkit.manager.controller.ProtocolController.addGateway(ProtocolController.java:38) + at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) + at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.lang.reflect.Method.invoke(Method.java:498) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) + at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) + at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter.doFilter(KeycloakAuthenticatedActionsFilter.java:57) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter.doFilter(KeycloakSecurityContextRequestFilter.java:61) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:96) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter.successfulAuthentication(KeycloakAuthenticationProcessingFilter.java:214) + at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:233) + at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:327) + at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115) + at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter.doFilter(KeycloakAuthenticatedActionsFilter.java:74) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter.doFilter(KeycloakSecurityContextRequestFilter.java:92) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter.successfulAuthentication(KeycloakAuthenticationProcessingFilter.java:214) + at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:233) + at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:96) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) + at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110) + at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211) + at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183) + at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354) + at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) + at org.keycloak.adapters.tomcat.AbstractAuthenticatedActionsValve.invoke(AbstractAuthenticatedActionsValve.java:67) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540) + at org.keycloak.adapters.tomcat.AbstractKeycloakAuthenticatorValve.invoke(AbstractKeycloakAuthenticatorValve.java:181) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) + at java.lang.Thread.run(Thread.java:748) +Caused by: org.apache.pulsar.client.admin.PulsarAdminException: java.util.concurrent.CompletionException: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Remotely closed + at org.apache.pulsar.client.admin.internal.BaseResource.getApiException(BaseResource.java:247) + at org.apache.pulsar.client.admin.internal.FunctionsImpl$2.failed(FunctionsImpl.java:154) + at org.apache.pulsar.shade.org.glassfish.jersey.client.JerseyInvocation$1.failed(JerseyInvocation.java:882) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.processFailure(ClientRuntime.java:247) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.processFailure(ClientRuntime.java:242) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.access$100(ClientRuntime.java:62) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime$2.lambda$failure$1(ClientRuntime.java:178) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors$1.call(Errors.java:248) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors$1.call(Errors.java:244) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:292) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:274) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:244) + at org.apache.pulsar.shade.org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:288) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime$2.failure(ClientRuntime.java:178) + at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$apply$1(AsyncHttpConnector.java:204) + at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:774) + at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:750) + at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:488) + at java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:1990) + at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$retryOperation$4(AsyncHttpConnector.java:263) + at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:774) + at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:750) + at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:488) + at java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:1990) + at org.apache.pulsar.shade.org.asynchttpclient.netty.NettyResponseFuture.abort(NettyResponseFuture.java:273) + at org.apache.pulsar.shade.org.asynchttpclient.netty.request.NettyRequestSender.abort(NettyRequestSender.java:473) + at org.apache.pulsar.shade.org.asynchttpclient.netty.request.NettyRequestSender.handleUnexpectedClosedChannel(NettyRequestSender.java:484) + at org.apache.pulsar.shade.org.asynchttpclient.netty.handler.AsyncHttpClientHandler.channelInactive(AsyncHttpClientHandler.java:145) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) + at org.apache.pulsar.shade.io.netty.handler.stream.ChunkedWriteHandler.channelInactive(ChunkedWriteHandler.java:137) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) + at org.apache.pulsar.shade.io.netty.channel.ChannelInboundHandlerAdapter.channelInactive(ChannelInboundHandlerAdapter.java:81) + at org.apache.pulsar.shade.io.netty.handler.codec.http.HttpContentDecoder.channelInactive(HttpContentDecoder.java:235) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) + at org.apache.pulsar.shade.io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelInactive(CombinedChannelDuplexHandler.java:418) + at org.apache.pulsar.shade.io.netty.handler.codec.ByteToMessageDecoder.channelInputClosed(ByteToMessageDecoder.java:389) + at org.apache.pulsar.shade.io.netty.handler.codec.ByteToMessageDecoder.channelInactive(ByteToMessageDecoder.java:354) + at org.apache.pulsar.shade.io.netty.handler.codec.http.HttpClientCodec$Decoder.channelInactive(HttpClientCodec.java:326) + at org.apache.pulsar.shade.io.netty.channel.CombinedChannelDuplexHandler.channelInactive(CombinedChannelDuplexHandler.java:221) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) + at org.apache.pulsar.shade.io.netty.channel.DefaultChannelPipeline$HeadContext.channelInactive(DefaultChannelPipeline.java:1405) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) + at org.apache.pulsar.shade.io.netty.channel.DefaultChannelPipeline.fireChannelInactive(DefaultChannelPipeline.java:901) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannel$AbstractUnsafe$8.run(AbstractChannel.java:831) + at org.apache.pulsar.shade.io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164) + at org.apache.pulsar.shade.io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:469) + at org.apache.pulsar.shade.io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500) + at org.apache.pulsar.shade.io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986) + at org.apache.pulsar.shade.io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) + at org.apache.pulsar.shade.io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) + ... 1 common frames omitted +Caused by: java.util.concurrent.CompletionException: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Remotely closed + at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:292) + at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:308) + at java.util.concurrent.CompletableFuture.orApply(CompletableFuture.java:1385) + at java.util.concurrent.CompletableFuture$OrApply.tryFire(CompletableFuture.java:1364) + ... 43 common frames omitted +Caused by: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Remotely closed + at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$retryOperation$4(AsyncHttpConnector.java:265) + ... 40 common frames omitted +Caused by: org.apache.pulsar.shade.org.asynchttpclient.exception.RemotelyClosedException: Remotely closed + at org.apache.pulsar.shade.org.asynchttpclient.exception.RemotelyClosedException.INSTANCE(Unknown Source) + +2022-03-17 00:31:07.512 ERROR 35449 --- [nio-8086-exec-6] c.i.m.config.GlobalExceptionHandler : handler exception + +cc.iotkit.common.exception.BizException: add protocol gateway error + at cc.iotkit.manager.controller.ProtocolController.addGateway(ProtocolController.java:38) + at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) + at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.lang.reflect.Method.invoke(Method.java:498) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) + at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) + at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter.doFilter(KeycloakAuthenticatedActionsFilter.java:57) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter.doFilter(KeycloakSecurityContextRequestFilter.java:61) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:96) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter.successfulAuthentication(KeycloakAuthenticationProcessingFilter.java:214) + at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:233) + at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:327) + at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115) + at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter.doFilter(KeycloakAuthenticatedActionsFilter.java:74) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter.doFilter(KeycloakSecurityContextRequestFilter.java:92) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter.successfulAuthentication(KeycloakAuthenticationProcessingFilter.java:214) + at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:233) + at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:96) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) + at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110) + at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211) + at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183) + at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354) + at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) + at org.keycloak.adapters.tomcat.AbstractAuthenticatedActionsValve.invoke(AbstractAuthenticatedActionsValve.java:67) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540) + at org.keycloak.adapters.tomcat.AbstractKeycloakAuthenticatorValve.invoke(AbstractKeycloakAuthenticatorValve.java:181) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) + at java.lang.Thread.run(Thread.java:748) +Caused by: org.apache.pulsar.client.admin.PulsarAdminException: java.util.concurrent.CompletionException: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Remotely closed + at org.apache.pulsar.client.admin.internal.BaseResource.getApiException(BaseResource.java:247) + at org.apache.pulsar.client.admin.internal.FunctionsImpl$2.failed(FunctionsImpl.java:154) + at org.apache.pulsar.shade.org.glassfish.jersey.client.JerseyInvocation$1.failed(JerseyInvocation.java:882) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.processFailure(ClientRuntime.java:247) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.processFailure(ClientRuntime.java:242) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.access$100(ClientRuntime.java:62) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime$2.lambda$failure$1(ClientRuntime.java:178) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors$1.call(Errors.java:248) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors$1.call(Errors.java:244) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:292) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:274) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:244) + at org.apache.pulsar.shade.org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:288) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime$2.failure(ClientRuntime.java:178) + at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$apply$1(AsyncHttpConnector.java:204) + at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:774) + at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:750) + at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:488) + at java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:1990) + at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$retryOperation$4(AsyncHttpConnector.java:263) + at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:774) + at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:750) + at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:488) + at java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:1990) + at org.apache.pulsar.shade.org.asynchttpclient.netty.NettyResponseFuture.abort(NettyResponseFuture.java:273) + at org.apache.pulsar.shade.org.asynchttpclient.netty.request.NettyRequestSender.abort(NettyRequestSender.java:473) + at org.apache.pulsar.shade.org.asynchttpclient.netty.request.NettyRequestSender.handleUnexpectedClosedChannel(NettyRequestSender.java:484) + at org.apache.pulsar.shade.org.asynchttpclient.netty.handler.AsyncHttpClientHandler.channelInactive(AsyncHttpClientHandler.java:145) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) + at org.apache.pulsar.shade.io.netty.handler.stream.ChunkedWriteHandler.channelInactive(ChunkedWriteHandler.java:137) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) + at org.apache.pulsar.shade.io.netty.channel.ChannelInboundHandlerAdapter.channelInactive(ChannelInboundHandlerAdapter.java:81) + at org.apache.pulsar.shade.io.netty.handler.codec.http.HttpContentDecoder.channelInactive(HttpContentDecoder.java:235) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) + at org.apache.pulsar.shade.io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelInactive(CombinedChannelDuplexHandler.java:418) + at org.apache.pulsar.shade.io.netty.handler.codec.ByteToMessageDecoder.channelInputClosed(ByteToMessageDecoder.java:389) + at org.apache.pulsar.shade.io.netty.handler.codec.ByteToMessageDecoder.channelInactive(ByteToMessageDecoder.java:354) + at org.apache.pulsar.shade.io.netty.handler.codec.http.HttpClientCodec$Decoder.channelInactive(HttpClientCodec.java:326) + at org.apache.pulsar.shade.io.netty.channel.CombinedChannelDuplexHandler.channelInactive(CombinedChannelDuplexHandler.java:221) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) + at org.apache.pulsar.shade.io.netty.channel.DefaultChannelPipeline$HeadContext.channelInactive(DefaultChannelPipeline.java:1405) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) + at org.apache.pulsar.shade.io.netty.channel.DefaultChannelPipeline.fireChannelInactive(DefaultChannelPipeline.java:901) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannel$AbstractUnsafe$8.run(AbstractChannel.java:831) + at org.apache.pulsar.shade.io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164) + at org.apache.pulsar.shade.io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:469) + at org.apache.pulsar.shade.io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500) + at org.apache.pulsar.shade.io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986) + at org.apache.pulsar.shade.io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) + at org.apache.pulsar.shade.io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) + ... 1 common frames omitted +Caused by: java.util.concurrent.CompletionException: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Remotely closed + at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:292) + at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:308) + at java.util.concurrent.CompletableFuture.orApply(CompletableFuture.java:1385) + at java.util.concurrent.CompletableFuture$OrApply.tryFire(CompletableFuture.java:1364) + ... 43 common frames omitted +Caused by: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Remotely closed + at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$retryOperation$4(AsyncHttpConnector.java:265) + ... 40 common frames omitted +Caused by: org.apache.pulsar.shade.org.asynchttpclient.exception.RemotelyClosedException: Remotely closed + at org.apache.pulsar.shade.org.asynchttpclient.exception.RemotelyClosedException.INSTANCE(Unknown Source) + +2022-03-17 00:32:01.292 INFO 35449 --- [r-client-io-1-1] org.apache.pulsar.client.impl.ClientCnx : [id: 0xae4892c5, L:/192.168.0.109:54411 ! R:/192.168.0.112:6650] Disconnected +2022-03-17 00:32:14.472 WARN 35449 --- [r-client-io-1-1] o.a.pulsar.client.impl.ConnectionPool : Failed to open connection to 192.168.0.112:6650 : org.apache.pulsar.shade.io.netty.channel.ConnectTimeoutException: connection timed out: /192.168.0.112:6650 +2022-03-17 00:32:14.577 WARN 35449 --- [al-listener-3-1] o.a.p.c.impl.BinaryProtoLookupService : [namespace: public/iot] Could not get connection while getTopicsUnderNamespace -- Will try again in 100 ms +2022-03-17 00:32:24.581 WARN 35449 --- [r-client-io-1-1] o.a.pulsar.client.impl.ConnectionPool : Failed to open connection to 192.168.0.112:6650 : org.apache.pulsar.shade.io.netty.channel.ConnectTimeoutException: connection timed out: /192.168.0.112:6650 +2022-03-17 00:32:24.785 WARN 35449 --- [al-listener-3-1] o.a.p.c.impl.BinaryProtoLookupService : [namespace: public/iot] Could not get connection while getTopicsUnderNamespace -- Will try again in 197 ms +2022-03-17 00:32:34.789 WARN 35449 --- [r-client-io-1-1] o.a.pulsar.client.impl.ConnectionPool : Failed to open connection to 192.168.0.112:6650 : org.apache.pulsar.shade.io.netty.channel.ConnectTimeoutException: connection timed out: /192.168.0.112:6650 +2022-03-17 00:32:35.181 WARN 35449 --- [al-listener-3-1] o.a.p.c.impl.BinaryProtoLookupService : [namespace: public/iot] Could not get connection while getTopicsUnderNamespace -- Will try again in 391 ms +2022-03-17 00:32:45.187 WARN 35449 --- [r-client-io-1-1] o.a.pulsar.client.impl.ConnectionPool : Failed to open connection to 192.168.0.112:6650 : org.apache.pulsar.shade.io.netty.channel.ConnectTimeoutException: connection timed out: /192.168.0.112:6650 +2022-03-17 00:32:45.953 WARN 35449 --- [al-listener-3-1] o.a.p.c.impl.BinaryProtoLookupService : [namespace: public/iot] Could not get connection while getTopicsUnderNamespace -- Will try again in 765 ms +2022-03-17 00:32:55.955 WARN 35449 --- [r-client-io-1-1] o.a.pulsar.client.impl.ConnectionPool : Failed to open connection to 192.168.0.112:6650 : org.apache.pulsar.shade.io.netty.channel.ConnectTimeoutException: connection timed out: /192.168.0.112:6650 +2022-03-17 00:32:57.456 WARN 35449 --- [al-listener-3-1] o.a.p.c.impl.BinaryProtoLookupService : [namespace: public/iot] Could not get connection while getTopicsUnderNamespace -- Will try again in 1498 ms +2022-03-17 00:32:59.602 INFO 35449 --- [r-client-io-1-1] o.a.pulsar.client.impl.ConnectionPool : [[id: 0x745631fb, L:/192.168.0.109:58210 - R:/192.168.0.112:6650]] Connected to server +2022-03-17 00:33:47.330 ERROR 35449 --- [nio-8086-exec-7] c.i.m.config.GlobalExceptionHandler : handler exception + +cc.iotkit.common.exception.BizException: add protocol gateway error + at cc.iotkit.manager.controller.ProtocolController.addGateway(ProtocolController.java:38) + at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) + at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.lang.reflect.Method.invoke(Method.java:498) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) + at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) + at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter.doFilter(KeycloakAuthenticatedActionsFilter.java:57) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter.doFilter(KeycloakSecurityContextRequestFilter.java:61) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:96) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter.successfulAuthentication(KeycloakAuthenticationProcessingFilter.java:214) + at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:233) + at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:327) + at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115) + at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter.doFilter(KeycloakAuthenticatedActionsFilter.java:74) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter.doFilter(KeycloakSecurityContextRequestFilter.java:92) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter.successfulAuthentication(KeycloakAuthenticationProcessingFilter.java:214) + at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:233) + at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:96) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) + at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110) + at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) + at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211) + at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183) + at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354) + at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) + at org.keycloak.adapters.tomcat.AbstractAuthenticatedActionsValve.invoke(AbstractAuthenticatedActionsValve.java:67) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540) + at org.keycloak.adapters.tomcat.AbstractKeycloakAuthenticatorValve.invoke(AbstractKeycloakAuthenticatorValve.java:181) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) + at java.lang.Thread.run(Thread.java:748) +Caused by: org.apache.pulsar.client.admin.PulsarAdminException: java.util.concurrent.CompletionException: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Remotely closed + at org.apache.pulsar.client.admin.internal.BaseResource.getApiException(BaseResource.java:247) + at org.apache.pulsar.client.admin.internal.FunctionsImpl$2.failed(FunctionsImpl.java:154) + at org.apache.pulsar.shade.org.glassfish.jersey.client.JerseyInvocation$1.failed(JerseyInvocation.java:882) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.processFailure(ClientRuntime.java:247) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.processFailure(ClientRuntime.java:242) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.access$100(ClientRuntime.java:62) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime$2.lambda$failure$1(ClientRuntime.java:178) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors$1.call(Errors.java:248) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors$1.call(Errors.java:244) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:292) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:274) + at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:244) + at org.apache.pulsar.shade.org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:288) + at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime$2.failure(ClientRuntime.java:178) + at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$apply$1(AsyncHttpConnector.java:204) + at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:774) + at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:750) + at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:488) + at java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:1990) + at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$retryOperation$4(AsyncHttpConnector.java:263) + at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:774) + at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:750) + at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:488) + at java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:1990) + at org.apache.pulsar.shade.org.asynchttpclient.netty.NettyResponseFuture.abort(NettyResponseFuture.java:273) + at org.apache.pulsar.shade.org.asynchttpclient.netty.request.NettyRequestSender.abort(NettyRequestSender.java:473) + at org.apache.pulsar.shade.org.asynchttpclient.netty.request.NettyRequestSender.handleUnexpectedClosedChannel(NettyRequestSender.java:484) + at org.apache.pulsar.shade.org.asynchttpclient.netty.handler.AsyncHttpClientHandler.channelInactive(AsyncHttpClientHandler.java:145) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) + at org.apache.pulsar.shade.io.netty.handler.stream.ChunkedWriteHandler.channelInactive(ChunkedWriteHandler.java:137) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) + at org.apache.pulsar.shade.io.netty.channel.ChannelInboundHandlerAdapter.channelInactive(ChannelInboundHandlerAdapter.java:81) + at org.apache.pulsar.shade.io.netty.handler.codec.http.HttpContentDecoder.channelInactive(HttpContentDecoder.java:235) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) + at org.apache.pulsar.shade.io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelInactive(CombinedChannelDuplexHandler.java:418) + at org.apache.pulsar.shade.io.netty.handler.codec.ByteToMessageDecoder.channelInputClosed(ByteToMessageDecoder.java:389) + at org.apache.pulsar.shade.io.netty.handler.codec.ByteToMessageDecoder.channelInactive(ByteToMessageDecoder.java:354) + at org.apache.pulsar.shade.io.netty.handler.codec.http.HttpClientCodec$Decoder.channelInactive(HttpClientCodec.java:326) + at org.apache.pulsar.shade.io.netty.channel.CombinedChannelDuplexHandler.channelInactive(CombinedChannelDuplexHandler.java:221) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) + at org.apache.pulsar.shade.io.netty.channel.DefaultChannelPipeline$HeadContext.channelInactive(DefaultChannelPipeline.java:1405) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) + at org.apache.pulsar.shade.io.netty.channel.DefaultChannelPipeline.fireChannelInactive(DefaultChannelPipeline.java:901) + at org.apache.pulsar.shade.io.netty.channel.AbstractChannel$AbstractUnsafe$8.run(AbstractChannel.java:831) + at org.apache.pulsar.shade.io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164) + at org.apache.pulsar.shade.io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:469) + at org.apache.pulsar.shade.io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500) + at org.apache.pulsar.shade.io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986) + at org.apache.pulsar.shade.io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) + at org.apache.pulsar.shade.io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) + ... 1 common frames omitted +Caused by: java.util.concurrent.CompletionException: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Remotely closed + at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:292) + at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:308) + at java.util.concurrent.CompletableFuture.orApply(CompletableFuture.java:1385) + at java.util.concurrent.CompletableFuture$OrApply.tryFire(CompletableFuture.java:1364) + ... 43 common frames omitted +Caused by: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Remotely closed + at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$retryOperation$4(AsyncHttpConnector.java:265) + ... 40 common frames omitted +Caused by: org.apache.pulsar.shade.org.asynchttpclient.exception.RemotelyClosedException: Remotely closed + at org.apache.pulsar.shade.org.asynchttpclient.exception.RemotelyClosedException.INSTANCE(Unknown Source) + +2022-03-17 00:39:21.706 INFO 35449 --- [ionShutdownHook] org.quartz.core.QuartzScheduler : Scheduler schedulerFactoryBean_$_NON_CLUSTERED paused. diff --git a/log/info.2022-03-17.0.gz b/log/info.2022-03-17.0.gz new file mode 100644 index 0000000000000000000000000000000000000000..9e81d1aca3a4b77357d0c80c8731da21425f1f36 GIT binary patch literal 107296 zcmd?QQD4k`6aQA#a1ZJe2WR+~+Aj__A!WTDCYRGS>Y<{38nWQUazkM%{jUIBiG)X|u znYBj&06*Rd-bTgZy>yhfgDu#ESgI^VW!Y%2qTg~!cL!ri&JkgWbg7G22+e)x3l$Fc9kmDa*%|$QO>}456+7+zUEjkYEl?rsM)c>oJVpGp;x{i}==&LaF4Gp_&4)3n znf0tn>^9-m{et3oScp5ya3dw-=7IM6yuh9>gqYVh{+g+H1tVshCuVNy$oZTrnN&keCL-yh)LVzk#`6!I41;-&yv z^r!6}>3Ex({7Ykh5v{Z~9|@fBT})diF=1^USyLC$+}30AG< zej@|V_j+|#HD$rQ>v!OP#S4>U6;F-5R-s+s;Bmzgv_lilR&`}eT+>XFZO??YcN2gU z_q=)GHkAjIm{2qw;O$;}p}AjFEwS>_&!D(pBpI16m_gP+GuEx!jP;*$O(b-zxg_Ic zW_WREI!b+ZY95hOkF8#Xbg>7EYaWNpvPz(k&hUkyH@E7L7#p#jt=A^&%r!gU=y}{& z?4TNyif8Etk-+7m_oLV5c!SbL>`l-{GJnK!CR?*W1o)ONEa(!FrdS<0C%CO#4Aaog zxmvtB^KgMy^&+XCdjy0bXM{)!7>YqT-41h1Koi_A#mK;3-HqdW@>gl2^IyJ0uy(@w zoS&Eu+gk(dxzv`NE23>uxk2>c07QY|sI;%d9WlyV5my~aN!NQ@@Jsj7w~$ROs0mp4 z7H#NZKWwM!GnpfYvD~sI(T0bn zFw?i3u=&k+Iv^JugGJkC!c`rI_A=DEzA|c$kLhcy0nrO9zphdCYpnKgD$ue{1-Ib9 zbE_6RZFo6&8cU6+nOv88+cy?)nOUq^uXMd>JC?N2G*Hi2*v>p?$9lX5@zEUF0MQ1o89P30TD|V=mmT z`rN&%5sapjKY81P)j%xq9tJyCQdZwj;?3PAJ&zwwZ0Gwm=6X^aL+>hnh6(4~c%owK z>O{w$`ibceei!tN;9WSlRFWf1e?!+Fc^M;C8(2#Dae{a~#bjD_fV78`{SK9dGfT)A3aE18na_x)I_4K~94b>!=nE+e2PexTWGTa>E-@16oIYISe`}uZosmcZ8 zN}o>z{y%0q@G0e(^hm8>8KSO_wkD>a{lc$UyGrJ|fF{H>m&=ZUZXhSHWUo z)$jiNr6c}o>16Uf62U=6){JPTcT5(QSgU|llnm9I^VK}E1@1(d%0|E04ZH$}jLlF% zi*LD3asu=N0kscY=ZFkf?s_s&ScL-%mU`xLz)-l6S%LX1G2txjK_>{e2?u>!HcU6itf7^_7DPoBcDX zcwJo~Varo#iS6NG0`p9b2s4Wr7~@g>3yT%|SH?J1O@~#QHaO&j_~H0G87*mdflW$G zs5YfC<1pgjz9n+N4Dhmb@EIL&o%^sVu&iEzIq(_CB?R)!2!|Y`-fq%J@BoaamAr-T z^1jQa(hAlml<&dJ7AgbH42*DjBrp_md72y&_4XldB5pzZ#9U!73nwkvZ<_P)pp+?} zdl(Xk+1$aXeVopRC2!CnW1ahxFVNc7$m^Mb$=e5}%}hhNL%4Rguy#j>G z*x)G}N`YHYX>Z$Wv)TP1T#dfr-4Itr1qeu>o}W2aPMv-$kFt|?>3Awv_pyhv(RBGfkv@jO(t}K1qNy!w7lLb3km>Pg zJ_tT{_LWWS@?+TO7U{GT-voo;;XIn9X9}(6JtgsxxhDb7ToY;v#(a2Da}_DZ5{cFq zaI?ir1%j;Ywo9h~Y%I7p0|Wtf+BrfI*!#$jJIeFyTU}8YoMmE+!hE9J-DCOfY*4n6 zc(qUE7!IsRgUa$e3|0I6c}RSvR&$6%LDn#Eu#BMl1kn{uh7Ed}!LnAj=hV9rh{Q8> ze%(eDX8Q!4zE}=r-dmKA8Ig0<7_Ut;kia1q-OycH?a2hi@lA(~zK}1tl7v{FEE=P} z>2`gQ8$5UF^x}Qxks;EVtiqP-U+_in+h<_lrc?vj7~@{37|=%R9Dr(R`xZo`MWXckLK&y^Kqb@pboafVeqe#A-whFuHEMh{5Dtj7dO*a(JsrT z&Iv(&C3i5vIh}WVUpT(cP94N(Tk;1!DH46_Yiz8~z^BVy?Mox5bIwJ>qv%gB->k9C zz)A{pz-_Up{;{z zBq|vt5;y~N#D)v33^Fozy(5Qrn0Ot6qN-1+vju77P=s%p`r#}|jzIq2vpF*nj9s@i zi?Ics*xtajH>sGv8}`#M^PQa@FN9ZE3-oK@CwJ0bo3F2+;Fa0$X*m&ZJrM}B?BAiN z{a_%y7`@w@$SKUD!+dgk0S-7@Qmx~jmR=f=LXk+zcpN)>hdcM9`g#b)0!CLphF3Lo zwXUz@pQAg2qak1S%ZR*BG*T*4>w~)bkTW(idfbFoS z%J%^Sc{pX?NZfst!%yCgOPBUw+pAcP&cN@ye4sAH!V7N{nCJ#wWXj^F|I$V*Ct$H?MV$tx;Ny!eKTy-uUBTXV6&GmQLSB6rsgPQ_nKA?jr`Z)^}kXq z%7$djCXI>)_jV3=kwjp|qX?Q;2pFiIqq|WQ4^O>656r(}f6UCRb=IF9V5K!_>j*Zt z2~1OVVe}yY`&oVR&zb=79sxbQMi9XTbo!wm?Q{?BIRI5+4&s4G?}|R#fK0s&%A$bt zwOqg8UBY}MJM_55eqHR?j)=zTiAa7k5Si+J1>!;5gTWRGsY=Q64OJ1)SH02Y)V~dq3G2b`pOc4PbCTI76{5KP#EP!D2 zWabW#@n_nFFOE19Sf;Q??pffmVsRPBr_h_D3<)pK$ zjie8K7AObhkqa&k;_ zm!E&Ut!fc|f*^*#)kmYp!1^1_js0$Kr^B%g1Tw(F3s!Rxe07>dNJO1VYQGSgn}%Fu zqF*T8(t=iWza_E{^l{dtPR^{yqn;5l1Iqpy?Iz>*k2FD)9FtBe7| z@p2JMkgApyzhwNH0oRn-h2YEu3|G>QWq_84=^4061+mOi2?%9B)-U#pR%Z?4GkPbc z>I@UTxZ(PZ_1lggKjz7Y*ouGS9grAPcP35)&Q*UrGS+vg8K1EvetQNX|i~@v7 zpG78@)P&C^F=BC*`lQCp}cBYUe>vYr|(TFgD=Ez+UVdco141G3Yd^L=I%C1 zZ;5Z6EIy{_9nj$S!j8SzgC9l*znYStj+TptYxX4|)tZ3w@G|rI9>2DoXH1kCSLrj* zjBGtQ0JUW81CdTvY*52K>9tXC=klCmU!a`6czP|9Y)Tu1a1Rh!tDu1F)7D8H0g zuooC=KdVk7NGx3=Mv(^FT;xrDwXJMroV(vE2-#8c`9#G$4iSC^xV2~~KBeV%#b}3m zk_ZjT69lt4DY96lQzPmt21}}rcYd%$pB<8F3nuq1<2Z*GqG5`z}5A@jDW8y}t= zO`-TBa8vF#%PtT|x;3J+0@{qu&A~b+)TAjeJ(iJIc3VX^hPu#+hDhAVHmIw^jxa7f znw*K)(y>q@pfUZXP7A4TnbW-hY3t_OY!zZrP{*^{NFR=xhn~gNfGXgmod<3k`KJt* zZC5Z4d>`lbDWvg|y;oZerNeTubo>jp85zMe)HjSM9XT^mo{0tko@VWH>Xaw8T7SVF!&+9e#YKPrpvZ2 zpZsOkMA)c=*Y~~&%pI24TmMm)tk56T56VG5+ro8#Ox7xsOvs%<>Z_=_qu(+OLBp*q zv?p_{79=5|e)UEcp&WYAu@C8{0KY3~qije$H!1WKGwc zuE!(D<1qTZZQ&=pIJH0e9UkQJa`-bzEPPO(Oe1r$6rEBdvvM(+LgPfM78Y5i7QPnK z-=>VR4V%*~1qC3?u2K_~F|5GgsSLU{&)1ZS%mVS}(je)~^IDtgZ*#m|+v?wn%@uP} zH4E{W2g1y@P{`B(n>oy;Q3H#6i8xbgtCg|L-_h&ZV#-lLNm z9kutq-fFTvTZpS%3!5oofsJmwmLg67V8XW-dt&G_cAhaKlSj4#cf~JNbMxzrHVn|} z)zgzR%fEY2t!ZXr4+ryxU2kG%l9MFM|U<_YW&oCo{iJ^gBq|P4FU5Uw` z39NU_uSX8Ajx-;#-#S}WhR6ttBwLD^`Pb{w5;=KrC2%wI4_j%UL&_Lhqgo+GPu)7f0m8+p5O)z&AB2E z^x4wb!g3^j#TSTAcXp&@6p8V zv+JI{?WSAtKCwh|a-h2Ej>Y*4&5(#0XD9U6$uu-bOW5Q;s)c}Oy!pc7 zVU@??$s?0Ye88QLqu)B`YrEaE3YcJYUxY) zbqOh6pDVB0UQ97^I~JzUWv}h0o_up>nWtg4JMN4-_cW!(WrZFGoXUql)qA5UbL`e- znkCC~#rTL>_Gir$)I)j|6}Pqqh`89$?{l7blktkC&fgIsXd$>SwI6UDsHye$xvF%B z4}rei8|xDQWoQXItE{J5vs}~*XHu`a3vK%iXAOB}KtlOj&0S`edDIyabWyI*5n&7f zZzA{Xxy-A@%$01dW9PSx%cqQeH4I9%L3|3=Ll1m=t1F(wMt+QG11)XU?|2#u&hXhk zpOt#_WzN#vsfJ2CUpuH5_d0rVYr=f8vM4`FU)PnZxOlRA3y~Bc%C_O}ygRh33n>Vb z29^|%zYOXQlvLGSM~h<2YvIH2ePHUtIptqmUf7lZtctogrDGP}T?Giuwg6rqUD-Dm!}qNA>CKvo-=aJOAxYozOjW*splmSNg#&xt*f*Nem^`|5|3z+m-DnxA#SpR0tM-r%3+$GOdohq-Qrj#v;Z}(;Mj?E3(WU$PjV}uw$j#oYK z4dJ0p4*)Ul43eF5hHEMwmJN0{^-@4t1{GdVOlkoo8$nSIJI@Z}-ADbdF}Cka!H$)1 z#i8q(YP;WT$fG=$=|0S@>8f~6d`p6oyJie)UzBwK`Vu|{q$#Cnnl}4!YggUrr3F}r zzGQc9K;2gaxw0riF&C6HP#JgGGC_WiJ3MVl?b=3>El=BJO&UKzEK1+Kh*+T+Z9Q^? zPGr3-Q)1He84RE|LsU$ngPC-T-7FHNh@UrZn>|B_Tf~S*{|4p}bTfCbj$(nCJDTG)C}>+gVDF%=QsUyb2Pemu;`#wW2Gdmd15yNIlWMP#2`+p zfAD9qtFJ?FsG@yXK8|hLXNM57wGa{x&k0a!@JIHm5uxul^hJ?fHlOT3DUV#u=vtD} z|6S4&+chs9&3U8^mbnf)ljctR#Bt~tuqf%>WjCc`<2OxzbG%G2R(*WM@H?ovZdZTB zjz=~fGf1!O{8E~6h+=4Y^}*rX`xy9KC|`2bh7aiX50Pwl>NxHr&sAQly|*{*;G$A0 zB@Vr(a`08^$Ka2iwXr}Q?J+0=g--D(WNd?Yr|64=LB{Ml$K1N9_kuREzQoP~zMWAR zHet;jorNLa| zw9+5xs^{l=*JFGWy1ja|0?5AsNi@rJ~S-zRf)9dz(+D zU|JwFRr#Jl33WU{zH+^>oyk2*C=v$Nw7A>2UU^<5#`;lz2&$&QSR9$Ji#@AcSJT+E zXoZpyk!B;^0EvRiLg|j5C`^wqk1+4RZ~9il3M>{ zL(n+Tl$6)dRGLt{XoIv@G6_4`CxkPHme7}mw z3r{5I95R9#+xu?#cWkT6y+IQgfF(LhogUbiH8qjSS>}wSg+B%k%tJkTh zt5xlrs~V#>GsBk@Ka1UKAg~@kP<&!q-b8^iSwU5r>?hWwV@>WSPKD)B0*+Bh>;&`> zvtCR5Rda%W{rC6Af3?jyE|>ww%=Zx69Dm=DWf%s-EAi@>Dix_YN z0F0Eg6(x_-A0L1EUsmV(ci=y@OTq5HTC1@Ct1})|uhxG>f#oIWfIM9OI~%|YtN%%s zO7Rifzw#DWQvSy}FFP6ggU71f;y*+B3C#gBTEPn=HO#7#5HUk0vk5M&h{5#M; zviUz1PgVp^{@A8375)3hEd03@WY_;1oJMcGfZ@NR6)E%8%dPxLDZKJOGU}muErFY! zRwX^Mw#SY?b}gYWc(Tv}F_*rd%<}OX#P~71JRZ*fQgrp_^;=#r^aqch*zUCiAf)yE zBr1ejq`6v{zIC~cD;rjCZ{``3VI5sk+?1aZINsb%07|hN|g820_Chz%JSN6S} z2FMdlIAfU_Z1a`~H>$?K54jGP)Z04o;)_g>Lx4U^WX5`puc{D8e-L#vFnrW(YwKV{ zrX5oPr4IH&7Y@DA6G$FzImW0D7@DM}Ey7vigY&dU(an|k5FXwV zdYf!xmli2(_RbuCHKIIdUaZxw-1l01o74HGSr z2Won!WArH9sJV@Hr)_)78kOJVMp`NR&T2nFMz;;Lr{K`&ABGWQLG;k5XF}i{yflpc z>R1A<4g;a4R@iIC!@bfdRxGZHzbL%F*c-46LOem5UmSiaZJm@JW$#|pLG4yky4G04 z)8ZdedTe|wI*JbZYCvgLr-J29k)yVst78}m-ZxUc4U3q`rP9t|o!N88BTMHS)3J~A z3E%gW^@Sy3>pP)@m2W3uOO$fT-^GhE(daUr`?cTxa+Tb!e!{Tc85z#7E-P*@cc|QI z54uVW|1qQ6dqH;%;wLEH@)5y;3*Yc{DE}`pFTi}KkV7PhBONBgCQZicVw_o zZz^>rb2!3GcfNH@;XE;*U*(ptQ*5^8 z-BZap4oGL4gjViEy&gk^afP}=D+em9Q53;w9bl?C&W%BSng$^L&2{9H)#tq=4VWL zp<+NAYEjqpwX;-O2TjLG`N0@wi@hyQk=kJ89=Dt)?4%sP2W$TT{}eRjuBbve}#X)`)WdjYHyQl{=Hq5C=42L8V3{d#la3S;A;>l&dAAkyiu{>Uq zKf;|Mc@}q{XXEJoIqkyF&9&023LskNezy1WaOtSVpg7*>rjsZ z_2@OHUWJ>1&VV0o*%o*4Pc@Z4pYvez)ovtOr=c9}V;w@Fp(Jr8oKTX7di47w98w8X zjvVPnKf*(L%y(|+Zm^cva&OC=w#_=i%C6B?^&Ha8REE+IOga3;)BbEf1So2uIAEN^ zc5uLd(c;A*Bd~@unuvG&vd8CHgAQE+#(!V)f^U}n9Ow8Iifx$S>)E1e|GNNP5$RV< z=3RByx0peW{@=Rb+>`c`}styoqrn}y`Bs4jjA|Xsn9v1Ixix$tIK*aRO?%o|y93x(& zZ!yZQ!B*hjR;lBGvoxDw7g@!!ah_~o5?HUzb$Jnj-+hL}xh_@Jix08aBWg=jd`Lp{ zB3(x_9LcwQ4)<*S@RzYAH^OrCNwA`|>Ur`saZfUR1-|C8T&jTqy-6$$G2L>A#A2b| zVb(wK!8i`+YOiP00H}NLUxRtecH@r@wp3TYb|Ejzbq7z3BZdhE_!VlmDFNcyzDzs?!>eB!de-=x7-=UWG*6PBP>e#u7xgxOU&)e;UHkM) zFlXdGzUiz4m9Y(oj|&T=I2;@L-yjjcAHtq3LzM=J;FsFDo$$&{%{1-xQ$u!q>_Y?s zFNxbIcf5wbAiq~I@uoSCOoqP#p}dTWE-{j!r4ZDqc|C-#V9ESY6PX#28XWVkyP z5PKZeosYHTfRcO+Lx3JU^7!9`D5yvr4Obuq&36HIQVyawElyrKv7(n~Y${(o0asMy zB*iM4g7y?6yw^oeq>#xGKhW<4^b>89Kin;B12+42bR{f{c>OBEH<(r2{+rb*i#MAs zsCKXxT`}?+1*`@KQoAZk4}EyM5BncyewB^jy5MeiubEB7o^ssR+`ygi-G-+YtafY* z_ge8PA6~8ync3rh35lROM}8>YqZYuuI+cqsZun}gmVzjIU$=$i$dQ}( zFaQf6lZq_mmeHA_6iLR$FIIPVX73~asEUjpjnN$(74Bq?Fei1F$!my$uCtjSjtxtN z=P+@_FleJZW{yAl-W<>#gF@XwU6Y*5yn5{Aje1@=5oOrCO}LJeFm*SHbKk$`Jy!4C zCX2gpqY8?C$LYkReaV0`cybY2yzn&AKHondbQkZ+xh2`@Z7=3Wo9ev^(G< z%2}45UIcAj$}zyD7PUIQ?U1T{cB#Jj9JW<54N^LJu`UFefatt$aNm=7e+Cth_#lt8 zky`&)SZEN|)4(e|a?R`YqOTB|ftqX1a2fP;fW3?xUpZSCEOd(>OSeZ~EY+5_ElBF$ zyT)&vDWvHJz{b@t}V3UE1L+HC3BlSxh$wDM& z^b5mKTR1iAk}r0%!TR0QmFLzFEfS?bBWL?^($A+LpRub=6+ZVq#hs(-4)@vQ`06W$ zk%n6=lU6$R^SmeLtd+lb2=fx$m-0g?R~1{exCtfW%X|Gp^RqQxCXmbon#zOg!jo44 z{Z?G_oZtT~4*6mI4;dB@zuLv zIA|yXHED5)YEx^Nl6q*1^HFc4LKlWs`u5qW< zdj-|U`4V5fUw?93RbKjW{1nBId{f0O?Ls0dEW?b&fh*@vk3WhHtaU21TXy~DeDs_L znGj7$ZwIQXKZ+R`r{Wn|6m}J)!c=dfse<@-*rWpGarb5=-At z++OlykB}9`-QwO3M?Q=2GJm2I3&}Jg0MVE=@IxkE_B9e+5|cabSQOX+x7?C$5%x{q@(kijJ|z%k*e$s*7!lfhGNW9u}MA2QPwoA%3_O+*r@Rf zDtuRlsEB481IwPEM><-rj8goGSiO7@egOllTBHf>3D>yx+{0+4D08dy!4Z*(8X+?| zxwgygAa`JQ^8boLz9;>KLex}#|4l*!%lwYs^5{=E zL5sgq@BQvx=iKU?fp(tPucY>x?$GD>aKbsEII7;-i8+Rj9?H3p^m2L|9eRyDu;coW zyDL1^fKs_FLO?S+UbBoZip-|POg~7K&sKcZIHyiRMOQ%o@Y`tWB}tI{iNDcwbA&hg zWj)7PDf=p&dHeqP9VsRnHt#+B6AoF^jhgy1@nZLtr%diDA9Gbz`iEF2|z>EqPzF}%}&|GJ5Za4D%y2t(yc zac@9unIzN5)7@dB_*|!?f|#7h|&_XK!!gx6- zhhw5!b~&ap^{7MWi0?wnAaBK=uepb5VGng2!fZV5SPWO@ooyB#q5j%M+Ky5xl~#K`^RiG=f0GPm zfljG{Xj^@&fTY*nB!~K&E+}Iy66qp3+*l$#&2<0kB~tcnJ43Dpm>UE#Fvg;qiGe16 zdJO^gmVCfWF_8I_wSNot?wuxf2^DiT-=Cdc=~|#sAQ>6&0U0zA_+bWFZ{&jJBG1qV z4jmC0nHf946JwzYvuVr!M*CJAmIE5U2 z5M$cAOLrtsV1$!nKc|xtuw%>N1U1+%F}4@JUClX>By&8=UK?CzUpKMdWxe^01BJiM z$NOTS&LUI;Db1T}m$zj(TdJrSb2^hpkA*YULNiOZD0_OeV4Gz1InmJnHWVRG$Hnau zSANjLD5zH&j2{eKY2V)TB-U|DJ2y_qn$G^NDcQlUr)Qsb9(R^Xn^fl7;km~lPD#qO zvu-@jaB?-z4Rh6>tr_N6M#zM222ll(ryb@g1sgxW zb-~qlhb1G&?C<$pnknL+QYtCw1R1BJBFWavir~VdDZ-WE4}WlsRm+)l<`L25y_>A1 zlkLrD`c(b0sT^>j{wf{gsQjAGjP{y!lC4>~dhU5nH(1B=;C$J4oZI*bGwnn7UM zDT6`v@isiIuQhl?&2V@FWEci?n7pbg`iAxE)`8>92fDq&$ylom#7;Y)dj?com>!C^ zqJBOaW2rQWVt7y`sO}WW7<+yUx72RJBE@hEbTBn|Zdw1*_54oO>H89V-n`Qf7`cei zlrp-99hC)9{`gzibD!9bTQ8IF_3!~65D%_*#lkt(`$Ct;EU6@<+7IIpO2HYPJPlyUapDKi-v<3z1HGzw|^p2BWQ7#AWohRm)Ck7Xwf9Z(< zap{;ZGmOJ@R0zgKFVbXar%#~yaPwI=68NQxd7)~MLr#bfh2NgzdsZbY_B~b89BpcN zlS>)A_UchF%!<9>N!4b7U& z$IQx4KyYjZU85+HUAlPAG&%Mi76jo3Zt+B>dE6CrIQ(uBcLPI%DD$$PX;&=9uBdp5 z<0ErPE530~smzgp#G_N^l4^1ZIgYoQo9j8LMCSPM4?zxUG2PTMe|Fy|rSPtaAFwA# zzLScGUSzruPmN$^!)>+)h{2a6G;$^tN8PDR&dF}S0#IGr#6X#$YOvQKkB_^=!-JgB zqzXMl8l=AKzhBSAoKWHKys_Q;C=L=e(**F>e_J;AUlEUs-w<_}9^~jzrzVBq*)~c+efuny)fk*D~INR;Ql$zy&wEUI3F| z&7+OwoF9re!?K<%m-3dQ{u%xp&3gmWj2{hVK(6{ODcMb~uaD11uHxJve$;t1Fd~^| z3?LVo_+LlQ{l$B@eK*xFT@-mlV*L!b=$>muV7>ylYrfQ|h8W?RXLR^dK{8W=lT`ct z6ayRSb7#|l>@6@~M&kF$h+%{2Se-k4+GeBn=#M9Ko#3wQp{&f%HmQNjS5X#J@9Lyb zR8v?%ERW^D>^x%S>xyT!F<7i`ge^|%=K%{3=+Kjt8TG(0R^L3VDcSy z2jp;`KT}?foGj%GY*+ue18;BmJ&dw#?jI_bg#T8#v^Je#wH2y5F(VUQ%fFEiOBXMG zD?(`Cnb8x3|FeP?QENH0K8gq1m1Bli5VbG|YZ@GVlF=;V=2qxq+aNrJ`mJfrtoN;Q z=ZQrD4X7J$&HJC=V>$OP@F7nEz1DXo2<*r9hW^s+1OxliT{RY)o)QE6*!uUH6O0OZ zv+H&ZCmy0bhCRHcmR+C`cN5Z6X~L_CpI-i!_?%scWt-t|hlC=BHS0UZyh{E>3`?pZ zg(aOkjMdy=lO+a1u7YA217<5EWE>i&5%HWwZG;=1R2z!aNd{icces>w(@oB-U;+AU z-}cPcPmVP;c2L^_9(2Ch2I}Po2XsUC7?23aahx%b4CH|a1AeIp#2VfGJ9_cA5D=r_ z&C9AwER|+l`()>hKXfeZ(p;&_{ z2_$-fTVmVo`s*SN+X3L&S35&9zL?-X8A2$JcJS=NbaD4YQb3_ZKR*}Hw`(!X%$K;F z24U12e_mg}E@kTWS#qQ3%r>noGzczTwguR3Yvo#iXDwc(=&sG+HeWs5*ljWK-tHZ> zzxxsr!xPIb`Z}h#i))VLa7o~Q;vNx3|54#UBErN`UvceQu>$H6wu@X)a^BL0zOw|s zmxcBy%q0I2;ebdYT>T}&F+`5AJhr55p8T5(?0h+HZ8!Y-Z46Q59wl>dthe_QCGb0N ziJQBU7McJ5N(Ly%u@Pra85hh$1RRIF;e!?K?QL`WVGf|wqM@~OZgO2CFeO`xP;<2i zw);uIe!6*$F(vLYauY{uXGMallGm2nQtALICf@|OrPjEx)d-W)W##*`WQ#{oLZf@Q zM~|izXNXtX+2>it@qVq{SE*l;q^;G%UOP&pXWU=jTl8x-U%KgU@zDZtb@VBKcAAQ_+}9hc*qU0eU#YNVRaVRF+-^@*LXMW}MZVeA2jSn5 z>7=c^l&ddt<9wH-NqUkpm{l6H+V>KSUfOV?{3#1-sbtg(hGLYzNcEEN4<-O+e;@%N z{4XY;^oI#Fnr^(2wE3~0G&1t2nHM=vvfLrBs1^3x+;MVA-S!1oT-yjVna%Ar{kL$$ z>R-Z|KcH4}619^VvUxFsrB$R7{+ZCn>;`Am`eav^XC%-|&^uw|84}`4 z18^q8eMyLQ395;=SyDu5Ufwn?Hrz?YIt#1t zPM9V#fcrgb>ePA~%s|~@+LCeG`~nK|aYm?=?jaupa6R-pt(Py#4U#7|A2F^rwt2K^ zBkd$k19$LVqb}fatqav9swy8dvq#8cW&pKAaK>1THjFo=`9DIA4)+haH2`lh?sKN! zW{CbqRedb`M%jV;yu3?D&&x}Om;un@8iwAJ1&a5HVgPDtx%<3;F@5zO%a{=Z#pK@T zbRNUbDH#OskY+*}m{R)S8^%b$RGtQ1<7pvn)zA6riA`v}(~z-~Md@x0R!Ol_2-E*T z+*?M~wQOs<3GVI|EI7g4Ed+OWcXtm?aCdiy0Kwhe-QC?ad^4=9wbwp-@9&&*+r91n znu8iueN@$GjXB%<^!}EHf-8&@M-LLp+~h5e?@D_9#l8LkmiapvL&iL0d^(sWTK}^g zbtP^cGg))5cj&zj?!aS!e=kmvgcm|4j>ewAHt)uWRq{z&q{R831ON+3(LG%wc1W?#mB1i*qa;#5FQ zMxEsCtQgAh!Z`OV9kad9DF*hEF7_cvbxt<`D+D|Sr>PD!(#TYf_CnQWeNyOKluii7 zEn5`qplUf?wA2VfcQG`#l;ak$!t3nZ^4>Vl8*cbvHJW;Xan7Ja>&p$m1ZUD>N7~#v z$slYdFON%4BJA(;2lvsKE+#|R@FbAk5kWD8kn$|lBQ5l>yv2vy+Yy_(AYvr=GLkr9 z>T#Dna+NnUyjz-6$3O2Km1tWTSfaRv!Efwl+9z7=#(vlgBZIqrkB)0va;b}=K3p(9 zpx@ACjZ#o2kZ!X|bS4YWfIcd)?rp_lPa^7B6OE3TQ zBwDI0GUKsOW~f!_MForPv8$hC*blSMpIgf-ZeZ|&=JVoDqW>K!$dlszFQmZsPf|b& zAO)D@$CKQIG;gE;D1{wGqf^F|7U{vZWMf06>0ewQ*2>lyU z5dRk`7}E(BZ5>=0k>+mW?JueoS4uz^^jpJ+X)A$4#kS4PGX^0A(*C9y(DRcl*?J<` zg&Ym@2b)7hTq~iJ4S`2d1diNj9SnQJQxVhEXG?%;4^|fQ=suUqm*2OS;B0G-u%mSC zl-Sp)rgBkn%#xlrV$M&a;CPpZp^GA5e)4#40W}Uf??D_>y5tT**zuM7N^#q9)Tzd8 zwzuxC4n{&wA@{uLR0+OD=@|COyDkp0p*9w^Gto5yi|QpnjL!50j(Z0W*y z?y`R4)*yIC@S#xk>f=2Mc}gqZLfMr{RZYL;nxG1ki%V)g$y^S~TrgVovW?=DUz;DE zpvTqEb%A7hXg|Se@`x! z{JhXH!}_pD!GoS98um?prV$~US4N>AV9bVQ&m3 zZ~kQ8o2{kG-E~~>W}Fi4W7qs4dnnok5;58j0yw=k{nm-cNC>gob9QFiV58$LePCf2nz z%}_#r1AZ?Su%l3XW2Rt2Hj1#)Ms7%YEzw-`9O!|Pgiq?M#3dB zXy7J|o}lTY*|0pD*x9nEGYW=wur{L<$LUQfo4iHVgZNo`6{#(qw1EY}L^0m2Hh0-e z-2tMr(WdL26_|5EK2bw=hm|+H@2g*3S<>AyygHinazXlYS7A_qGh$@+=Oxvdn^L)) zY{H=;4jXyJ*l!YvDxGPIQ(Y@$S19>S z$5~usrl`@N86fNYR21GA!8vl9g&t7{zxl@@$7Mdx{Z8Yaf7Yg69F{k5{Ufa#DJ;(%GXFJ=RF4=l`j z{P&gvHby?A=br|MSlayYZvK1;fEQ!OH)%2+#asb!`T)FvgJM46Me${Sz_9N=M(?{P z-+}=OgbdTF0O9fS{}%mPcRcDE@43RM$RNe9nalGkD>NKLAyqRh1iwYZQ)H?_3uDSF zw59Yu=Ir4o&C>&lA4D&*K5=+BqetRU#;S8Yzx@;Yb#zEs$Uhkn3TODkwUTCFEqtf&aS- zif|~zutmZ_zMHN355f;KMWsse-9oW#=5AB!IP61XsFh`L^Oie23YbP7yQT+!R8ag| zUXl(<0;r(4{Cfq(Y`f4E=6|iBm^QrNCXv-TLIu;E#?<^^^)KK=#_XM^{EZHmpd~J6 zkOXa~I=yRgVQaTx!vaKt(O{Dgcpz494H2tk;1w-u8cYk>L-so!syy*{Q6hNI>0r)S zvCs=nj0eEc?z%jH;$B_stj_#0jj@#(#Y@)^8G%-DAon8v(8U-<>?JUfM0nb#g<^c~xv=fAv zSK~v^CFB)|{lJE<&ew*o&nuXE3QYO+)68?jhuF0O;Awfo1|oqCXEsEjw=jk7iE?2}|F4Qin|TdmwIdyA95vy(n$hM1B>2r^?+g7*GY46)Fz=|V$$t#ljO z)}zpFGrI7YNcbLjY{^KYDOY|q^55h{Z{87B=bpY&`vWTu*0=hrk+dJnXUy^$tU4iN3{m^0Y}E7y^X4AF7=5gAJmke#5r)( z{eLRe^7eARoEV6~>kbs#L%0O5GfsW16Jf{iq3(Ziv0!YABqN2aFVMl!`22$L(jEGB zO9Mg*(O}cE4%~u+)Lc^ap6`C7tFY(~A2T;UVQufsPH^FtBL|YexEsyMzHZ4YMgZ7E zMIry*wIeD#FnfyN;VN+`e>OWo>{!O#lC@F!0qniKoX!5`A0}q>_?l>}mBO^5!b00U z_2k{a*wZ2av?+{mlTkxEQRI`Ox*^bbPZi5sO2Y8HSUHX$gDpY}Pu8QQOPOH?I>@kd zF3oNGikk?ZvGzzdOtm(de5#P;9T4*Q+WR=9$uX+VR-h8^45zlBO|DBtW~qUK$S^U4 zBW*17;IIYoa|d7GYLKdbbt{7t&qUTS{S5vL@i9gt$MXL*VA5H6`_Cm5b^oq};^(gt z3bKDGp^!x1EPvw&Pwww(!x(_4WygWn@q3Wh<{;ihlRO9#xHIpiSChdW>bTLkGX(Ce zSBX2-V*lY-w#e`g$Fg>hZk0_WcZUo<*u(er3s!foEP(uVQ`r zL4iO6f43`(Q3I_6n3Vw$VSWmiItm-#x0c-YZQ*YNtDg!UKeFVYgtfFiww_(*4&`6Q zrEK}h`SM_Kj()V==5oP$d@xCIUlG4#!%=&4hmLaXiS}?T$S6;^IQFGGSO?fgJ5(Ej zC-+PKy#7U5EOr?q>g0vaM+iDm?UYf!h?Kx7QZE<2$oF9_Pv2U)8oO5yXr4#|(Mdmy z0&I00t!HW=?%=p_K77DU#l=01ygt&53hT)E@Ogj~BiM7R#Y@VUbhYjhIgpD@{Dsaj zQZDi7&c12s1go({VDlOY>{=N=JUHvnBQ`XIc8$SXIRJ4T^Gm>4cnk5!o&C9Fqh#L? z`7Mmv$kkB226uWh$2{Jz^!scIoBS!&~qIRf>iocNv*C9Z_y07?! zL`eQZBHDK7`-=AtP|-pQ;X^n6W{U` z2k@2lAN*5roMmftO|@AZmTN~_Ypn*Z+kInB53l^6@p|=!>+LXD0FtFO)gMH}v4E$` z4+3l;&I$K2F4ROt)Ov^oYP>=0w=J1A*}h4*E<8U(5SY=x#0Q0Rw?M39T_)2%xYM^x z0Cy5Jp&%J7Z{7V?CBPA{Q1B%5&yHorIuI>qSU2f^I+pR)4OLJ6t7BP5zCID5qxmq? zB7ydIn>Akol!A3N4CDY?NXouAYT9A|EFl-EFGSTD66g+8f!RL4kIkd#(R2KQbH|AZ zU2M~y-B=VPT*Z90dqQS$G)#=2m@*>O)e#~YMUH^$ozndWEU6p6$Q;{0g>#vsi~vqv zI;z*`BC)WYY+~S@ug&v#;D_6Nf&X}>QJ`rZp0WTzO+5RP*hd@ENjUL}RQ**?*@~8r zq%MXojE!gTM?6#eQ_JN`cmZg~=;Jt&7N#Ptb(tq@bliMW#jz(~*DTITVW+O+EEaVN zc&txCdT zQWYWV16mI5iPy`mKi5f`fbV|}Lg7eUQMujhszPMEiq3AAmk*caXhiDSn2K!J zvRIPCQW7wG%1oKzV0jae;%IELwLMg8Joqc&J*3g0g^7bxGE>jchLrC2W~JcZcv(%N zJ!sqJ(|oZgGgIjptPtkR$T0RN&X3Htv!$d@XI>Id1sH8{X{@1)VpgJJI|@IXW=s4I z1kMv$m_PSHjntGU8F~^f72DTaa0>~GXgbqEx5D<{in}h~!siNxEbv8~nNw@qVynlB z=L*mXGq>jP0*Evw8`lyK8wY#07X1B#FUFmZO$#C9W1X%O_F#CRhoyI0!Aq)Nsg~dV zhYqpTq;4P>*Nr!yExt_@Zzvbt>_e=mds$>zY2lQfJt+P>W<$nu!q?!Q`{4#uL=sF1 zE=VXmY5Y6CZVIGDL4TR)g=#IGOvDo&lcQoonzQ3`RH$X>-9VB|klPlOTy8O(^?J5?`uqi<#H1$ovW_) zFZ6{GrPvpfw?tALIUJB!75f(h-km?-lqk!zJK&X!C+rS0>>gS|%#9|Yo75k%Dqdi~ zh+a8g3ZRxi-a!OXm|}fN1F3Vv?)QaLz;}!9)Jw(2j}x#t?UIHVC4Z(?go|tuOD(;? zJeXhPwPP%?Fxkyqp~I;-Nv>VHEvq!M#~s-RL968)jf7fll&?rIsvC4^tUA;@cVU+g z&zrYWlj^$Z@-73foyD`qHD;|?GjVI&s{w9f7=Jo1S#m&QNgXVVWo}cA4>jij)KWaq z0ct74q?C`qB5BvA5EP*HV&8JV zaKAofu}|HN0o3k>U8U+*=d{cf35Oze4}li9IyC!k3JjXd@jr?wZ!?+)&>|7dF5T-E`1W<*t^5s9s};j0aE z0imb9dT(?LMS1`vxbA3u7p3c;@V#K(QRZ(&6@wDO-<4kxECK!m4~F3n1nWVU z`WbmLOGO1S4>;^e)J_=To7ay0F^6t{^P+P2?M3DOH!mtUsK30ZNKk%xQGM=clGISp zz2`iOsEV>0vD#J(_`VwEKBRp$KQS;67~@aKUr->>V0LYndfVb0Jw;mSofo7_8tHfW z0?#Af2NT{PLVC7;v_FP~Rft|0i{fbVA&RBw`-oux6g$uDdaYQzE<1Ky!V9kWhxZK` zY*F!>W%WIgTgAIuet@cDc#}yz_zvpTz#avxFPcZ_>&Zznsu+7lAoXV3g0dD>e1=MwK1&zCN@<1BUcfEkG zg@P-kJ8oUBQD_{fl>NPfq{)opF|M8Bt}9G+3IhL3sGqcJAGC#nk#t4eVVN#Ikf?o9 zaBxU4e+)udY3>bu$%i>>~~{XLF0pRJUZ6P3B_ho9MQwvISU2aZyk`sM|8xB3PK zGQxA|i)apiBvx8>QkT+0X znrbgh$Fy8+yE&0C)=qEQ$0Xn%eb#wwk024mM$wY{$)ApA6@B)Vq#$@ZI0DRBga2n} z_l)oklDNzsz+p>mgIRl+(ySWRSX`@M59+cD+~t&z!H=HfbGxjCL9hTvk=riy(4~80 zkKDMxsxU`GlRxFiG?pFyrb0>X|P zr|7g5LcJGq*_`U-fWb9qok^wkjMX4# zXuXXO7jm%5@l#R9=_|TCFDognYeR+LiVZ+RBsv!;#KuLHNXki6O=Q^Se5yULfC`|h z40x9m7Tkb%mo%iKnBG}Hx-@n+1zOwX^Y}YLpuA`9O<1oLQD@{hfZF2^hYf*WN?KM@ z6CwfEi7)YUKqL-cVFoAa$m)nn>$GuIvccjv;l&F6_<4KNZ>=3ST7Drat|B>)@SSCH zx09FP`gs>1wR!YP3wVecf<)ieHjUrWy`Iyk8#m3}?;<8W*K1kE==IZJXJl%d)kINh z0}!?KPwmolT2ra7Btdpk{oC-Cb0GXKRD22$ES0)FcE(8Z@#Pe0TFpQ2#pJ4*4QbH? zVPGUSnO5VUGY8^JaregX#8na$a-s`AbKKwJ(O~tJyb`+Vv4LsP+N~RC8qc(+L3IYI zs9x7*_Xk_fWP+ZZ#&&=v*f=nT^?y7RQcFIY*}N(4o(P<$30ypiSQ7lH%IB2ER|T{(|E<2}3tEY2cY@`Y)JajR>31itc8?b) z)J^w(!W64j^JGO<_|~Fl7o!rC_Cy{w9WG*6Qx`yIWZjE@WS^Ybm zQc{__FEBGOGlPeGf;%g+WD&OLB-y6vjdM!`0u_+05m<;sNz4Wvd?Le0AQ1%EFSk z)SsSsst(-hqaC({+L={~Fq0@^kjaETxr>&e9Y7HGI6v9e>cjy1;pN*#dzO!nKn|t( zxDu}CrqQx<6udUcWxRT@?>aOtKSR%?WQXf7mZ&qE1X*=?@9bTc@VEhUc1HrO-#x{n zUVGghUkZg8GPR|dN8pmUHrLl?eIw)GIWV`=rD=~&@a4m1h4)q(ofM)=Hb9E=;OH}_ zzy+9^zynN8Zrv4D$;4EFhZB6E_S~&0?mAmsUC(c@`2 zS&C&yiGYghl9t0rrt}br#wfIer>P)!(4MJ7BIgv?5Ddu|XO@Ilw&v)J%2bdH(yxK^ zc4FMwE?JFrfU0!yex>v3i@!_OEWYfFvp)6V^Qo!m)vj=r#?3{vnpne44!*U%zBh4J} zHLbGlH93cH3M|4-gnVqeMZ%ri1ISCRe6)V-n%vQpyLOo@QY6eNKamNMD{FKkk+V;b?MKcmecW|t#;>)}q( zoO>2VvWE87ig?j1Up_Lp8`wY945qj3uy9Y@v06a=j?_S0*VBwAkFa0eCi^@UP!+JryT{*24do9TG>SbVI2Sx21O(X7 z%m6rN-%6~5e>Id?dFyn>v#e3tp6LSY6G6T?t76&)`oMS2Sl|av$)r~)58o7+-0@f5 zGc<5aU$?L!83ZtUzS_729T}gb$pvM+Ds5G`P5Dzd&*;H3&exZbO~*>gZ$jPPVMU+& zkc`bMw!9&Q;EiCIvob2Q^Xe->MQ84M6QlghR1t4ELEIC&@zbT$Vm9zVER} z35HwM6>GE{!+;o~kE7Abt#-K!7ifZIE4{cRz}{2iD1`~o`;E9FvMejL z)2(847{m+FyQc7h14G#Sgq(!tN$MZKqUr^;?3wfx!|j(`Yc)sHb@X4xC^Z5H1_sQm zke>GAu#AIs9N5k77GSuiDO+-mRxIZ~o4cIT7;?yEe}XP)nkpq%h4a!4**W1?uBq7tBiD-D zVsbhf^(`G}ETvxj3PeBMC>9hN8f$-abI`OFJqinEEkpw+Fw&XQ3CIdQa!ANklC%d7 zTrksd9*!EG0FD}7%N5XMUnWS)$zdJgOa!F?KB$bvbGk<_l1`AS&|p{R-zK;xdnn`X zjyVZ4DBL@IDYLh8bM1xqdhY$80O+2v_SdeKGU^YX zavlvwQrqrt>HLjw(S%Vn6;DYZ8KNW;_(7*eL}C1M2*`eFFqDV*VSU828`3uNS-gMZ zr1qgm|2h!pLpp+5o}yPG`Qh#6D4a%idyBTKBT%D0FV`_Xe6R@; zkU})Yji;&Pyr`5KA=C;C;!rP!y@#Y?uv5ZE3zLZpUlW`2`DIBZXz@>Ja1oM7(pXY> z(pafqCuy^Pxnp3&4k*HPYw__9Yhgw%RLd^WE^8=Z^6jxG;p#Jb# zC9Z*#HB?rP4=dhFg>RNMl)t~aM)e`PB=v?e`p$gpQDy_f!LQmiUi=flF2v=5Zu(4L zOj=$vkP}El<;UT%KUc+*61kpZnnsM#fO6W(52Jy^mWog|x531m6H>ioRU@N&6?#RZ zu@e>g+JatzsauE8nZZ`)@X(VZ&U`kvMZJKkx=_rg!TIz6>VU?A-PL)e1XC}}soQBK z#u~1)OjrvkUDJFQiq91PcK)qs~#^#nv+>)(Ik}p?wOfZfyc`F*%5Se7L3PS4+YgwY_JbPDLHPjDve1ScbS$ z&oCVbmXRX4da!fJUv^>L|G33HQe-7&g$$33&aK%dabO7asj~p^)iCToq%d_S6_7P| zRPcZYdOm;jqqU{%j91jp`NedR&3#J=ZU>WH)B|L0V_7!QP)=A z>gm-IDTHxp%d?j7ke6WJyh@xA@!nyNs_KP`e0c43hej@h50PbOfaAg8x&kP@6g|=p z#YdBJMTS-Fn|Ts9CdnsXJt^VuoG?w!f^w~w2#cECOFjG{)ZiSm&0K3uQ!*NjD>92X6$+*bU*_}a!%iJ2&IR=Ml2~+rJNZ%)?e|R3 zk;Q6&JGt!OiVM4b$!Eek`Bs_chK;&Cj|&pa+iyX8Xkq!juH_In1c$I(6Ocm&Z|>x9 zG`c*HyJ=SF7BPs^X+)WyU5hkeC*Sd1&zRdZl0 zxtoJ1zh;4}8eu~L14kflgM&eoc1PK}VYPVtM|+1oQ2F|AI zk~8?z^Ro^SC#(fr^FU1+vmW%z3rxPGWXz_wlSH?8vb&cCZ!oxh9qN|z%M_yhhB zgQ^1lE(Y!YAqF8(w*Mst1qtZeYNmJk{TDH4f_39f40`+*F$f~+w-|)=CI;F55`!?% z#N+erJue=&Xe0(Mlf8`)=xAX==9~qtd`Z-*98-DRXbm(J!=SQD4d28dmcA!2B3Ci? zUJHO21grap7z7SSZTMj5EvkCnDUGRajX9@36{NnbS(EnwN2i%2hT{Q&ZTA(P=IWdz z8c}w-r)WbNYQn8A!Gt;V8HTg3c@|R~tGQ#l0@Z#FlbCWmEG-B+S^rz9p!Csmt`T=IsD)Jhv^QMExe%z?8z0xJuE9Ri6e$dc zlB-J3b%kIzsAH&hshfY1!76A{1t>xI{clQ;N~$As8DXu$ID$lykzRxCyee);t=piE zl_XoafNAg?GihzPm6TF&aW>VCNz$frRrYj}XTOjY+XF9Tqw??)zr63jC>*U_oU|8D z02yr}Yz7?~!QD~-4;hB4RceLdx<~#7?Xl0C3k-phXM?)J*JoUsgJZuqrCgcaYj(To ztt3i6Q^p^$GQu<`c;O$qXq(bw)wHS1DX)r-!n!BgL*Cc;_4Aqf-V!4OD zvV;PP%3jY~J7KMzn^9{mzo%aD-AxNG2c)noP|Mjd&B@gJVb-eoR+e&dYib|md9rqi z^$Y-EUR=WiJZ>vLmhh)CI?ky-BG)0au6qk71awFcSdwr~*U<`kuSlm$`hV6=R*N(qJ{l#(h1Ombn=QsdTe z)0ts(a;6M`a^tX9d;JhA-%jkfIT&oN%9(AhLapic;|s~rI>~Mtr4IWo<0t(G8ME;l zTv)sCA51dw4d|PXm4N+4zh%8(+)ww%Z7CXv0O`J=zV9C5`8f$JZRwf-$-?vX z;&$^9BcZwKd}raQq$H$zDdb9z{Na`!JG>qDNce(uJZJ3yH;o3>dGm#g+onI}s++Xw zo<+M}t2o|bDcKZPtYsVSvtC4+v61WTr(j`~#MbGoDuTwdx^~RgrprxY50k`VOW*Gm z<9u~rTbr#{`D(PMIU_YmGWgDj6EQ|UVM~zW3UY~JwS1o(ht+?rct@N1-sMtFUKm1z zpBU}Q+|}#ygGf6yh$PLeTZ3&y!U}0llN>`>Sq%>dV*iVWV zCwd>ahNiLHGtE>)sBz?|-T?^Hw6AAb5}2^W5!uvIOVnCYBX&s^3lpqYj{&{)z1Uld zTYAe(5?TCGdHjup*a2z+t+p8}JL*vLq*z2|_MVb_)l7CY-E#Y}c>tr_)Om?j%LQ<{?sY9W@uIbbz z-F9J}bG{6EPOR>~^vE4+(@afA&fLEp_;zSoWy+Qao^NWQBo`ZVj2AGYWS{D)wXo{^ zs5PMhL$pWP&pc42iP3!Q+QRrOb?b~GVD*`6Sk-{0^8@htN}Fedt2aEJ`y&!dz)t~= zD>q0%o!5g6!~Qwe2dtj=f{5fVhtT7RVFB}q6fivm<)(S-OJ?P2nw_R>RTPxeD~hq@ z77LbhaOw=xW$kk80hVgXhxND>zFtrHry}4PMhCC5?F)hJbP(WOkvJrgZ;H``?lYwz ztJQDCsLb$}VkE}_1)=EmTQS0b-WP*+eXAFbFNuL?{r;_dFj>ZkB!P%6KF}6FqmTUR zwdlz%#{2M&XZ&f{`<-=#4I5PF*H4VvGnh*1Tg&#H8x z;R2VDnG~^sd9sOxE%$Mcr1d>puz%t93iqkaeWvx0W?y3n&#ODx#FtrSw&}@@w_i!e z~aj1rgu^%_XBrbIX7J+$CPDi|209i_$qYh(G$`|;W(|no_}OLr9ccRI-O~q` zNG6qpAD~N8exdAYjiB_hlVx)SXP#p0EEuh*xK1#P&{j~;I|^lU3wo~d$=LVNn$W&_ z;riitLHa*Qa4(}b;0|DLdrWpaaGWu}1m`d%iJe?A|WLI|bSDQNpqBHMasJLOtRZdwUV5$wLj)Lrie_B-qn_ zN97D{7Dbtm%%R)74#JrfRQBJe=6T0b1hr@!b)G6GlNBL?dl%&;#qYkkRP{~{OZ)`_ z6DJdY4N-R}vJiQMtcPBp>(Og+PGLoJc`geYr5;&aN|HALrqBy_n}AM&FH=-DYt^#s zB%O&>=ZMqd8<{F5%$`>E@z7*xrSCm7zu*$35g(Hm&%56GNIXl(mBKK%{ zpq(*>xi?GCkuF&|B5*Dzb-7bG*EB(0DCN2qj8y`Yt2HY0^Irw&N5&GD(0lFG@#bM z&zX7nMqwh80cySDN?`*X)nCi-QA2B$cM+uiKVmhB+w0_e6z(lc;OK*c8NDl=^s$z~YUN7j!v@NR2-M$W-!@e@Nf7HoIby zr0FXvchJFv@+=-Bbld-7*FmY- zD8ZhpfxTE$EjENj#8axTlUczIa13OF$}!Kq%hQyd+Jnh~e{5>+dk^=T`s>T1viPYk zWlv!pW963zCeYYa*&JbLp2WTzt3*OmO2Y~!Rl(3IL0q=(?K#v~3>rD>no1ap2E#T$ zvQp;LLv_wW!to@DS=b_G5Wm9CX||Ylh(p^z#%>0Kafmy{NXr;as;af{V&|hThz&i( zp~F>4;YHnt7*XqTQgoAT|BwXZSc*!tm6evr@@7$Po$#Cr;Y15eyDxJiYpA&<5zSHi z6HcJt1)&fuM9WwDb*_0vR;V9~>>~=R!A=HD(p6M7<-baFnb6z{y4VG-W^NOA{TWC+JH^6ESm9Tq5vW^TB?dIZ3iU;kgwtv{ zN3~VTLH>)SQw$)_C|+0LozJFr`Q7^&M?JO0R_4sEnjghLjFrVlc$QOuBWY;zE#lJY zv2VU)IQ2ND8W}?gT~~W#Pg{gFSd_CLhuai&Bm0o-cU{+nz}kpbe!Kuv&3?0PU91A+ z8CBxBeR$dkv{t6uv-xG+x~Pdh;~({wXGHIKTveo7DrK?uw7?>x)?qA2)@d1vpdqlViNZli!AVyLROW9+hp>leVDpE$WUK-Gy2E(wNNuu%Ks6)9s)puK|79iar+gegoueAaZEjCtAEH z{-kwJIz^2zYgXSOh9hKXCdLB6%!UapzLLb=@b^kJFbAS}hOUJy-dVtq(Oo?HYy zz>-s}R|IWW#MGrx=7Idmm$jHLII8rc!bcaeV)lmbg|SWY?xV7XY@Abvm+63W?9jfS zT?tm@1kcHPuyHXck&A42&RHi521!ER3(n-uBUfZK)?X5R)tS z-F8L!fGSFBP<1m%Tqx4Q;1I>fZ=_3McPQLds1$y}b zQK8}%y~dQ^P2nb9CB~8F<@1sA#W#(_poCvV*=1grt*O5bvNNMJIR;+h%v5eU4)P-cbg?2kB>c3yf`Shjga|vw7uNboY!NfV(BvMWmii5UW$yjaM?6t(eK}9T@j?SBk~b_+&VuPQUYw zuVKhHS_8ZL@EHM?A0n|6y*@8>PJJ5O^I}@*Te!8r57uDy2DvxbAhsGf7QogL~& zV;$uYn)!+kThmAUf?C^6>hxMG8Z#g|OZ7OuiQ`r=`jHi{t`GHh1cnizpPIC zYGPUgzcxnPQCX|j3@d1iu~XY((Wf;c3mXUs)OIVB&lhrW4S!Bzp~c-}v5yobr4#|v zcvs>&hBB#Av@uXD_>i6Ew7TxEs7yk^nIToF@vVhLGkJo2;3g~Yrli=(-Z>{N#y~~( zBUAu>)JghVA{bY*^GmR-Kk7?lTfrr5oJqR?S^;#3a@*>vXC#bJl%|_^x1)c${Y?_ZwA6XvO-D@kOzOJ6vQ>8H}^%*Bj}?aZ-z7A##`%g zG3Q&u{M41wQ)c+@p5K^yD8@-ae)R-&bogBU_E}2p%}tPQx??U=Ds{mDlW$?VTbwX_vu$`!I|B{x9)F!II}$g(;Fwn`*Ye&6jE;ux7W`z z+=V&6d+JJjhx)Y>Z%-CXi=zA$3B*h+Qz~eG@8L5KM;YK4(LcBA&-Kkmb=?9M==2D< zam-7a3i*!+)JSjp2iT^k0PZZPd&u`Z1nZ_kexB0iBHi^GF0Ve#N zsNe+jx%>3mA22I#Nmk^)ZhliG{>PF4v(R?^^lNdyR`IKkZXkRu;C>b;hs~tM+mq{NFct zK5vjUzkjm(%5gk+;l1Y-5_8rj=>*C2_f}jHAjFD z@FT1v?zY!OL`+6`q4jQyd4M<0NR6u}8lNPRO=X?KIORG-{d5M%ct;2hV&aP~{otxl zizdhnFRIG6mp}mI>oMJq4Q(irIFAc9w;z`*8pJa~?|aDipD*fYwOc=VzMttz1ZQ5m z0~(efLv{XuthpNMDlId2l(%ugcdz$Ojuh#-)eUnmL~rNJ)`zP1)Ecl^ESl5UumX*2 z;OcE`E$(h#w@EU&Rs0%n_S(Lmjq@GCTg$N~)~Ftz4qj<>}CTLh#`QA_k*ugZ5e;E*T}JqjLLj*DEda^_IMQkefJjWXsnPhQA%EYUAEV zxfIfZjJMHG;rP&;wb)tsw)I2vDr{&i>lZtKZIzXBE}Za1O`1+3Avaj4H@+Z??d7H# zYiq+@fR1$j58tog2{s5nzn(@y#(w zP;N#k@2o4Y8BvN(& z;WlWU3IYp#m2Nokx|P;t0-Bt0aJrXQiiZ_`fgoY|VxGg>a9C}~lv{aGnB+H4aNaYR zC!GRb>Di4S-5Yq&rOSGQjf#5e3|#Nm*YTb)td-?-Io@9{-a*&OF0QCB7d_Cm7@bK6 zul;8dd}m~R*XlNhOwbBP)Xd!uU1_~v@*83XpC6xvD8XwDj}jW72^bXO@?kT*el(<+4c3;e`9l^h+q6u;|BnrLUEV8vbhFlR-L9# z$gNhHQKS;oW*pP>BRf4}el~1P8ifdd6?m%0lEhglOIH~IdVZ$<5HQh>yCd9x+!9=0 zm&zZFfwN)gAxh-zmzLO4dYl^X0;dw}tk9X#D6=0b?;(X;;c(=cq08c!SVRkv>BYHA zh#|XkCb?SijNWYR<;rYcPx9$c3MyD_qktnS~$dcEUsEcq~ zW-Q_?3tBi~5m9Y>WDdYEtNFCk&lD)k^NSJc$My7E#As z)B0*Oc$KbvM^(zu(IQ|6kk=9m34saWvE^VmRA+&d+6Rd(sKY05(d|ky3;53=*aowU z8jFw6xWlDZT&K}zHX2%j%2Z)fo(ya}K|8)s6<8WraB!=V7%&mf(9H|&soX5UZ!HEQ zBbEtF%6u&Q9%-$R`;>9dMYE@6g}y&E;tF^@8Nco3S_X+>A9lJe2E;)KoamKN1*|9O z5nVAxZ#kx+NtRRj!bD)zwh^PeAP9@)ZHh=N_yrgItfMI{@jxvo*jZVv-+OrN-Kgng zmlEyx;z%*z2g>EjD1k++}Gm1-aMY`|;On@8zU#QMxyv{?%6pvu6f z22+DhR-&Q~EVb+`deYjE-nav@#M?+F3l+cjiyeh?8(Ia41zNgNhroIx@0^xWkOHQ5xB!JN0;Dh_&= zh4A-#%Pm4&R66)pqxb9C>~>k+#|M8pH6r!f^lSsk<61YH)HaG;kaqeCi zXa{4c%ouoiK)oB9r|%X`>iq^y8&9*9Nw%$6+1~L=6-MrvNOyWswIp!zU2<5VASzDQ zplUA2L@e{D%fN?azMQa`HdJP7?i=u@*IZBgK2>k9daxzM)AoHT5ycRSz_N}C#z_5Z zmQs}`u@&4q8!3?fU~h4joz}{9C;V)j!Eo!u^+9%@&JHF19d}vsk0xwcX((>hT1CEn zCq7HUQ2uP#bAGaKWS&Xo*(1v##yAZDOe=bzCV+bxjyg;{n%lk&F!DO+2r8C;uq@YR zy= zV-|&6tJ!S|qs~Etw~;V3sc*(t{U-^TH!DZq>hoA5{^&`j^ZX*SO>fdf>MX0~Gilm* zbXtSvtBFK@m6W^At1R|JAOxFBEKk@>#RRr*+{>`w$9t+*{XFcZJ1wy4B^@;FNu_3L zwWZv%^MW{IV;)UvmLf6hKtS)eTGaLQC6Q?x@3STpNIuQouHYIB3urq)hZ(m+&_`%N z_8u{J$)lsf?y#&IPOeyj-ElD7JSy1WGK!SVb_O_dKob)hr^zpqS$Wws6nxV2PHjeF z9Elr^VUh*Sma`2sQf3m1mXVE~0tXTe4!z<62HVk6ZM#R4o^oL~+jg>ptkdA33-j@j zC|9rDPFP34iyjZoRcgdsn*UNi!(OvT3KcVlCXKJ*dIwWA@iPc&L|{2{E+e+4>F@fE zzPgcy`V68=!=K|(5aR-+2)Su_kZC`-ZD%aD0oKCQ=pU=E-%kSQRlCu6emwGsgIA2B zm&=e5(_*GL^lnw5?5OEF<|i_gbKSKfsW8Iq@}I<%@{@itLC!)`zTEx_-qv(;p5ir8 zLj@lMpPDhWnfl=@^3;*^cbxP>vY}z~rPYCRop0?UIp4y_kuo$t4 zdv;6Nrj4a_43fxd!HG?p4@Yid-eIkoe)5(7iO%g#T18g--F&oy@kJRM_IG7Kuy<=M z9T^S<7Z@2*ZOBzW>|D3Jbd>%9HRwQ_k&B>770O1XMGl^fTg=U?E@Nw35?J5fAo}xA zJHZL>ypxg`qwYGH=?@0q7=buH3_vTIe4_6|Qcs4Cn!9By``$C7*>&&`}*eu`9BZt+U zYLVC6)D{cBoEKg**RT4NfvPQ)WP5tL2iMzMeVX;-^2Xj7ofFWT*hcOzo?~Cx`o(m; zJXKwp1m=i=4gON*G6ut=VB+1Kz*Kt%2^R{o`em*DV~*x$e<7MrOq3(_j{a+vUX6}l zC{(z*dAS$g*Ilgd8f})GwYuhUD2E|Mh`?QuJ3lL~#EzQE=@9$3?C_j{+om(#r09-a zIwYu>@|qvd7U{h|le(U+Tw^`M7>jc@<@8){U~^x*QG5yM@HLD>;NoU*zHPU$6`l@z zKYMpy$(|m&Gc>aZ<&$HP@|ehdba!&4@%o;48!F^q0Vl(yY7w1(<^ z=TV50>Muec^J!!l(oDka0HmGPtVl+HWocn;v&@~I8-d9hfY-bnV1U-h?PR+<7nGFU z{l&|xrja_6w{kiK5akbHz^+KjKAEq;=%MKCBqMNX-hO@GYnE~|gb6LKXg0tScMO(K zEG7y{o|R37;o+lV&??+A(ZyJ?8~5Ufn(;~UndCI+fcb~wl;F~=0Z^P3em|5i)Z98+ zH}~XjCwma{Acg@Hr@LsI9#8ED{&Td_!YSp&oZ5S`l3kV|@UzMj6xMc8C9j^muz zOoGZV*_iF!{kJ+AeM$5%YY)0xH~F(3e^%)I*`6=ypp0G{!aU!5>fGr<_dW9NxpU;A zC`aV=OP8a}Ns1NQQYRGxR_gNM3gqiecf9oxe{J7V6lBSnXL1ubro4dl=Wt#W_FvOr z`}v)F0zdjKMa7$HW4`3+#z*Ya8h%`suN{-Ofs-Me!s;&k20I}Bkw=}dPsHV^ZQ$CM znU{w4F_e5<8hg+?GZ$RU*Tl^SEu_>!qBcx3K$?}M?iFwyYHsNu7;qykdK}Dtye?m* z5zV&Yx~V8tg*lJ3?oXe7-L7DXG-x70q)0JOB^NS-=7OV6B)MK!Vw9r;mF3mlFoxD8 z)@QMI-z+nMYBXKb*iA?CNGNYWNe+FedfF1uF_uN#WS{`UNSVcN{e+ z#4f|QabSRUoEAK+T$g)aweMr=zhKp{=SSS$Uj-xkQ0~S@oAA6w9F_k?uByAsk@-zL@8zUhgccB1^r8X zzBhPSssrwe)%{hC)lwr0E{YjH+;J}WM94B(k;2|3(b z4MAa(s{pY4DIRX9WRK)=O=S+C&AzMBAH&AAALj#J# z$Nn^+b0U?dHW8?M_|t$c-p)A_cDXcWh$g`r+1l#q+*P|>BG8j?r$r?1I6IR{&@kK(NYH2C@_F#bP2IaR!6_<4AKpBGxHORuoAKu`GWH>^U;UZ z6qI9|@=Gn2@l$@VzW(<@XG;fXJ_%y3QWu%|q**5WgjnPaG<%NQ|8g@zeqj&jk^-un zMX;d}tKI0V#9wCOPw`uD2gCvprBf_A7$M9QE~PaMzQg3OZrCTd3{50r`(M7 zzP_3mfV&!y$ID)kqc{CUv)^uD@59BHdousw`$NX0s&s?VeCDEH(*%buSSFAH4g_2O z|JT`o&mfNG+!XYytvI+X4fpiIDI7LA3cAru&VbE@zz{1)vXHUepk!9#Bcrj^eQ)7ch}GQy^nC4h zXTSsjRgKAh3vg1RmAvO}A`I*P{heeZycS_;S{_?h^c5cfz7HPo874q#dyG-V*KI$^ zfXHdJU-g*vwvCWNn|F{>Qff)S`+@XPL5j+Y6mPRr%^%a1z+o4-BB=p+5KY!J*^27E z2qJ7%URi%{`0C)TMKSjB6-qYJZE|U??@B2AGaf-YK2oc(~ug z>O|Bwe#4u1cc(ZPnxrS0ZGtNH7t5jJjIr@!-qWi5HAfl*CHU*^YAcw~nCVC|V7V$< z3#}f_+$LU)?QF*IQ};qNeR@;XaBR|eV^y{0I$*zK)?jinB8|*<*Pud37)^Sml$aXJ z7zy!aA}E^UZr}M1{}qsH%MN$#stR5@GG;viN#jDRMn3>|?u;)E`Lp1VD7nz9x>Q?Q z#pG1JxtNjF=j1kI)N$_ao;_``Yx$rh;AiJPVqLpromT}Zi)`q_Zd>l$ksX8iK`ezF z^oS;I{NWulQ`xN$^EU!LNbRjmJ1u*8yr%(sx}0VaN~IhhujE-DksIfEWsazAiHULL z`0M~(mM)zxuW-dGC<4!zOS@qYS7&7;f6HCBG2mvmKfVUtmv#8JPWmTzc3#SkBCoC5 zUpoxv`IiLQ7h<1~z_MY9Ev2WbMIy37g^JEQ#TF(*3(X@aSPex%%jCCUg}YkfNyg#@ zaRtPFmA{lbj3JN9=dKKteU*n!+zw&1OadHpdvBkiR}+@pcMC8oZfSaZ;!&$hH>S5E zoMaOXB@)OneT5&~6)29yFm_02HM(<^bVc~~E=#zjF<@a;Gib~8-rd|^1sIV<+|EG} zS5e(&=80+_f-H`$K(*_xkYINP$O}85y?Rmq$j`ZE&Psn(=f6@ju6);DSsL!&lDcL> z(cca3ZePst=H&miXHDVHe`NT-XP6lJE0_B=kZh3&-`#rTWo0a2{YSa}w?Kb3Wah0eBZD;TnI>^iv&hQNnzaY%j~E9SHw*iT`#%`XjL$(Ew)4EE>S$ z0O#D6{?8fAV#xn>iA!vE|JV}$7#yVnh=1>aOCz{C;C4>=X0RXsV-29kbFq>G+ytxQ zfBcVsTnnlvh;<-)D)mYVi6j;44YX~t?2!MKL4YQB_Zi-<`#{%P`~i1!3qy|(PCA8z z?4|cYKkn_eyY2S;+7Lw>W#1zQ7`_5xKbHIjVjA*VGq7sQnO}*ZL_wI-SxH5N_%lmawp+SfrB&b-w zjnIP(N%VKXs=JoNeDJvrTyep0zL>al8n&|ouE1*Mlw`BUlzx4^7@QHbMLgSYT4*WJ z_sT~ojH0bj-4B%`0T?5&JRD2j)ZffglwVbpd7VNo?5o;Fj}o5GUg2% z&yYMewiH1mAoMfNe$RNuMxksEtqc(Q*>!UaW@#C3btZg=GStZ*@&xsLn)+sT3hU)j zQH^K|eD3aTXZ(1usmWhy!v(Cs=G;iaQz-F4ry9BBUrafFW+jILU&5b!f$DdZv2YSS zpEg|S7Y|zKGF@8MTypWIItme2@IodI@Aq#g3^Mxelsi8`VW#6=rGb@YD1XSV+q-kcc)fetK*QUP2PQ&GA%MGki_1mSK83VJa zgv|LgDL~8W;Nu`7)1f}#NIq&oTKD~g^xjg!H0)p)3)j@3iM2(=3Dms0jU<7~(o35O zk}m?EX~A$*@J4sM`G$D#sRdUW>tWNx)JXU&pGxUU4O(}|xw*(c&}`qFo-w}2KlP#qc7R>1hjkd~L z;)TGitk|M@U}0%uNlWS}xkj%=TV%q>2=E?gqt;1K-RsmRDlCTX3;~^AQfLn!jQg}E$Ta@X$sCYO=ieG4dm%6DxOeB+btMk| zc>a9cYdMyaD*FN&tC%`gj7mfHy#g0jIC%DkEogfT)3eOSJpO$sASr&W`=>~tnrS5t zudxm~CiBxe*lIY>ZP*W7y71lfhRgI#ds%Y2hk^LSF+)DwKvXz}F^hfs#F)$3(vdS= z4J7{h@sT!R^}d8fk?*poWF-vb3?<0rwFdOZOa<3cBDZcC2d9R^38}_Qs#}IzW&eX# z_sFGgi(Cdz>ApJ~HMX0`c}wwMddz0Ix*bOQ(N3dzu&!uBc{7o41wX<}Zy?o*;xNxJ zwmD6I_{|T=FvS|kPZ!#w<-DngQpB^Gd!C4&u6GIr>FpbAOlA23o_O&7s9a?n}muZknWbZvAXhmLI;Q=VubvS>!IbiY=$#nRjOsSl&c_ zf^PIk_k;`bD+Os~y`y?V7dDdE`TqF+Je@UNB%mWXGECpE23IK3qy53MF71v_2S;jo z4aU~oP!p8@EeC-d-o=x%qf?FZ0C>tW9V0tInim)nQF_3;J5E(1T^2;p*#3mGZU#T| zg8o>_fF;oA(ttlxdI6ya4?5;2h1Acl@gIL7a#-+6{zR%rw`I>i@KAf$=5*_I#;jjojFvL3LDBXikw>`1T6L_`)8s z#(}Dg8+L+JJyc`a@UxsA3m#M-glPIq-qg*c9f0nO(#W7Y&y|A^h(Z|DsO37{{!e&6 zuzxg7TdoR#k9U2#xZ8S$j~1#v-JHG8&kro04?Nezd$^~-h;2;+)?!G>xtqsF-X+~g zmtxl;LYe7gAK$=-V8-6*lt&vaWf~$2wCupaItH_Kl1tps2J)z-wNJh;!xMF@Z$WQr zy4uEeGCNACC=YC>F(7H8>Hf~_4PUktNx%`SAkc21+l*e3{QA0gMe9}uY+?_6^Nya> z5)BKbM{+!6EuaY(avCZTcmyd-e#)s2Nem$SfYKC1ouiH>Hp@ zVsOG8cg$?c=p!QYgQa337zDKsz{+DeFS=~R{$b@K6{Y@$Du*2V-q>Ll&>!b$W=8Ky&>O~-TO3QsK1u3jn2 zn;a%1UWC=CVEiOvM-8{n&l{z9@HyLZN(wxG*>~j5pR3^TZ(hFLgUfx$*OVhzvE}kv zg0k!O?U5~PRe<+TjsnkB?W;aSYu(~?xBm__H(1)#q)N4d#u8A-V+X^XQz#%vArusd zH`50>v)fui}RG+(%q6P^}}aAdc6o__^x%&0p7Y*S@-Ww>`gryqx;UylIQ_ zuJT`y!4XdG9C)_SURZljDd^Nl7&d$^S*2DLngGjp(4~IsLkkuLZ)sO-=sb{V^o>9` z-Kcm_AU=Ovenvg9KZHR^))S}_-w2}4ttVY~NuJV{r?iVJ@Ws7ATJp&*aP`$zC85A& zTas<(ukRnUWJ7vqu!DZouE0zKCg?MDrQP>wv!hMm;$J)SCwPkUrwxLiqx=6tG3dJnmDoy|3Ixh0;|$f5dGoyBvO|9Ry6$qchd)k{7sjF+ z!-;)4>(tG?Dtc z9D1+M>H1TFpsQTaJ_eM<9@f~{4TmX7o$X{zdK_In=8gR7Yi9u>z+>E|9wE7T7tT_O#*ydyg4@SnG6^0X+e`v@WO;nH~}^4e<20acx~Yj zzoghR(89ELb4=Hke7~@q)b95KfC3qRcPamF#;PE%~!t5RE^>|UM?Z(4lfAw#OQqGqni=tf8dPir!1DGBb@H+8A?tJTi>n9uilRkRo{f2bwO zMs>ZvALtywoLfwg;qkwB^*vFxbBBRF>VWm2JqdbEM#lpluUhWVu2&e2&TRI z^{p9^)=RPhgGbC;449P0T!xtsr5dvT0}y~$-3AoV+wJ)o!As)k71~T2)Vd3H?lTqJ zB3k}9!e%tD4)Jx8)r`6uHIBT!7a2iFsOHd89kP#j_5RY4Sr^;)np+hq`c4M@Vha?gqR5?MLalP za?47V`>F+|Mss^Rkk(7ebc5p$GmxR!)FlC}o!G-b8$+*x;&z4pI1Ztz2$wi9VJWd6 z{5yI+6{~{cEht%(x``x+mio&F{j^8#8|q1(xE6P2xk=2#&H*CxFRG`JOOVQK%)#*< z=1xYSg57R!KpBtlxkmw4q8WRm>l%9M3DvB;=KQf*RGA&a+8Na=wr2pGU zwT$*Drc=bq$rq)r+BMlNXD+XdmmgqnUIne1llH)$w!WJF;UAE1-^FS?tM5F?@Lip>dXE{fuyWo8`<`LD@&ik{W3G;1IG;s-}Q;s@3<1ed?& z2{Lm334H0<O3Egm(CJ zilG^Oq+7{E>pv)9JT}vmLw&9N9r#n6vjjQT79m$1j_z1T4+5+i{YP%F6XrT-hM+cq z%$%cAKK7EC0!sZfA=cD?0$*xFWSp#*P*3L4ZiO(ov+*Zg4O9{Tmx7)#jePa1lFEovG)w-^K zqGDmT7+`vaZLY9|CR`?A%k)TE+d7Lqb?R%|3p`UxuT0jDp&FY5H_~zQ=}NhbqTblH z=`)VirO>pg7)vZUT2IX3&>Eem>Do`rsaTH8#qbGP%Z{`+VKN-pJ~CsfckHb!085-X zS%IDU-wJZX(+U?j=mKk0iGw)02{@uXBPkINV~&McWPxKNfGKU9gBU1Bm#i50>faqz zOW8OefoOTJUaZG1uM4lwqN!Qeg6a-Meqxz3B^xKHWRMa-A9P{6%{r*Le!PXM;lGl< zV@-w<*g7H&m`i%w@h0VOR1u!`jl(CGiFH;CN1Lq_-xeStAVFg_X817-0}FQlpaK=7 z)B24g?OIlX*^ok&c|4@cG6XwdH@_v{Kn1Cwed2Ln?Q&Xgzc=ieeSs6a?dQxVfRVc= z??cbM!f``L+1U5V#|I7SRGvW=sp|_d4BsPkK>zu4mi;_D=aD((db8&iDWfoeR-DXE zR1aJ3+GD__4MB8yWR23xVD|h;l?60x2vSFT`8G&g=4bGUM1gbjt=?e1I4%tRi;oaT z%;uqb2DAhQUgo;I>w#fTW6=?_|A$h+0UlOIm(mBnyT>g5~OmjS2L7# z&vOQ6?TXyCqEZubcQX{2HrNeVnK1p=pt`gq5Z$16iuBji)r6?H%hTv9gQrppinyi+ znEvaDyK#gj%5Ff9>?>siYMCTQkpT}uZc==l_lMUui9aFD#ev~T>k~01C-8$diHE!7 zrrT~7P_y4|@+VpF4JL@Vr6G2(4|Ldqdd`R@fanOKhy-9=O&Ky|GOeq8+m%bU4cDrK z##O(T7y9e@{Yu5&!o-r-gbA|OOBWjO0Mg8)bjF2s8*Y}9Q)((`3JFSq!mHXWbYT0c zvOW7S3{lv(-+KH?);D!}KkE?(K*F|h{3_z zbQ%MDyjCu#z^K*w65ilwe4Jgx93#WJ(e2HtWJqjfsAQOGx}GbX6zarM!NClZ+nt6FlKl$Q zD0!9<5K_op1NwC+m|_8qX@}Cv`UR#WwUyygmnbID!hH6ZXO9cY5{s}_V>xF!0{@KA zyq+8RxALRs>K>7sQqqzfrRAI1;k$B59+%Y#51?C+a|##Ex(d!nTH9laO!efc+5TY@ zHhM16?4Wd{+Qh=+(~R)KdaMA8Ns{`*B6hbKGr!M4<6WDFMv+aSzV}4;&?v+Qls&4Tfg^UEZBfF8r9$jQXo4mL0Kx~4j@^4a``l28exLH(1HQ z8nkD0f;5U8rP#^^Zp-s^64(rbu(}fb_^8a)EPXY#Qnlzeh46divD)DZmJ|ztV57rn z#Qh3)gQjBBM7aHIqvPw`f`y_A^{j*CdTX`v>6(qqs*<#(v*Q5!EX`?zmu&W!JrnPH z%vi|S1)hrlU+)tErpvym-uF~97o;yk!HbHg7J>|mzC)!0s7Ooa(jGuA42~^v^W&6sO`U2Nymb)3-kZZ0v~me))0dm;8&P~(-aI^(U0&P09@x`COWlr~Xb~ zIt(4>tQK!todzEq*A-Fv>h5Y;$L8xxQ5IKINmqX>MNuL8r{IIRl>Z9(On)k>>T|y& zkQD9HqlI(SEFfs>r-A0j7e-DjEYlTJZVNO{)-1?Vvsz?<4%0~R+1x@L_c6l&v=vF* z@fD@QkBYnm_ZjgOoO$Kn0n+7(2J-B>aQHEI6OYZycTBTnctl^|kwnuS;7?mzc(FV5I zHyEq6Gu=ii*T1TqoTUSu+D7KEg%Gk`wj$giw5;slBfYUcZ)elI9hr&T@ZJlZUKTsN zAKdf2y~iR!(dch~Vgj@DDI-_P;T7UuCTr1mTmKWPTn7N@s)Ip z^2L%r8F;-O7J0*RzHfGE{vMI~-uNkTv@=gX#tp)nO3ON1pggDRf)l<(LLc{7JWW|u z=Ab&w9*5plWcf!m^w|9(IgwZ6cQTwh3-DPW!-vpB+sEf^}v z8TUbAk_oFF17!92SM!Dd%4_g54oc_k_b&2r%`66m8UL5A|c0)++3&v0mi} z7CNe-@yyHw>~kdBWbWXSHbS~nQJ!!kY2pmYg(PLN=~bG|9!#VF>ddGd4NaobkcuNo zsQf)2GE_+*27v#S;CuXdb|5O7c2ku|ypDj|;>x)Bf!mV%{l=u- zC57GLR#WhBI%jdH>G5NKnBkrveO@pS*{5DVFLkDY-T8LurqW@KE{SPOBIdH#+lKmQ zfMz?_%;PBSumUVO*$40Mbv6ei|cJN_Isuw=oiNJ07chPYA z8CW))Qebmnjq}g?1+YbN#p;@D;e!gZ0|HBN`*j7?IadY*(g(n8i?L;77joDEiG%pCNchHgRy+8SVJaIZ0s8!rm1j0H z<}5;=!AAZLK9`AjR^te#)c{VHh&6uFfWb^{hfLHL4AET96yZD=7VnQ4^NG z<;W{{Et9>)8pR+H=5WG6YM4%+Mmbs$pCFHB!OI1XX|&*+O>;#HSBYVg+yjW2y(vSNT@_H#al{ zZ8F=k52;bkW`WXGV4FB5&FIk1&p;TG2t*)i$CA?E{OQ^$ z_=_ZcT9KI}N{KvtF~uJ)?$v~*^*?6FQSj-i44EYI0x8?tEjJ5&ER0*N{iezrqE$U3 zW2WL8&4xJX%=5WlRe_olA*D%1%IQ#+UKVuZK#b~PG#5foKO-CaBv$#?m?T#w3QlF? z8q=aL+$2^Nb1~0v#7Ha^)z)@8g-K}I;v>>#HN^teWmk;yTVcXnNbsRH8&Gh3GXEYwEDv^~&n=0qUj)glldtaNX0C$=-^KC7@2KS0%bLtmMLd!N? zvEOUHeIrt<3#=zS%e5DC%j6r9E370_#SL|>UMr0RZISXBjg~tCU>kucniKJ36l($X z=kr7EC-vv)n6l1R^pnTsl?O=E zRq04DGHfK%RmYh|`>%Ej{jAZAFcoQm7VPN@X|k&uaop-i2Bhi((pF6+R4AE*lc>S& zvaXFvt=YbD+^eMdZAO{r{>7qgZ?>+D{9zDUUO4xwC2tav&ImfKfWS)P$;4Q-_RU-f z1-5i!sg$Yv!xA!?+4p+a#&9EZcgR_6PDV!kVaW>ErSF+E1w+M5xLJggi7eWKJ65!l ziSPxe>y09e%Nm*IkPeo_lc=qhUh;nM$M{!rnE)+XOC*yfCW+=$!~n6$XH^_G%UJ4& zA+)8GgGa`o9wevYH1zoDN4TTZ^x~)qL46vj@vk#8!e2vmC?Q|CQoivA#g0Ra3KRYk z2Z0ayLWrP~7xHBeyCoeZlC&LB%$^7Dw_AWp?M4O+)pVy_<~d-2O+T4P|7~~w&(q~z z1w7r!%9=o0))eD1y73v4N#oi9oi~ECh^U-x*@FvMj z%eu($ia95POxDSTrDE`)=Bb88^~P9ZDTsQGPD`=*WvR z;mmW%Js#Ign!Lce&6Z(qb-{p2yT+fwnU<=en1hTKx?G5dzi5ZgM`3`6oM`r#PWD-~f`K^wvuO&002@SKN5J*;Evv)a; zL(1kDs<`4#2FYn9Eu{RV82PgFH_ zv1Yb(0BvQBWi`8<5%m$5_M0O!&4c<~CXQuz)B85wBD*fTLY_0&z(G_S0s=G2qFGe- zvmNw%AN_(f7U&9&>O9A93zf$Pk(J`5#f@Q4OU`)dNL9qw6+LbBGxIRd^N0&`B>Vj9 z+-}nL*vgG_%pXf7SCZ*q?T9kl)UM3YtS=@rSkhPp(530cPDwMOcr+BeZ2@tKSVm3h z4mz}5aV@I9D^~n$UN0KNu~07VFIpE<|NcRt{yfsQZLQS?jk)uJ2-dS9c5`7QnZgLQ zKjX7%)5-aR1(9Vu;!qme;WrCHOQqR*5!1X%LwnXSW>ANqI^Iqs(>$t}$34@$@IU`i zM$7o`IaujWO8F6qh6Z-ND=-BS3P9xrp;R-XhXKEr5jLb7GYdxpJL^Xm;ZdL2|Hq@+eHFQ={pdTYov34n4`#41G#y{en2M88$r3>bSy~Y?ir9Vt2HB0F zJww&>7I&`W2!Gtwy)jD}V#K2y)4;-k4zb~S2g43wAi=iLG%6>@Pvv~J(D%iRHSYo; z33C_nkav}uPs#`FfsfOX*Qz;ejCA$HDV1csB!p*uos&4rws}fG(Z<~1Bi;vhTv7>g& zwNkO8#z}oSUm(8w${pv9L`FSYjCHCmDVlQEND&2 zufDx39~v92)^XlcVX7$$uZ$9np|GIsB68k5H}u)0cmz!^Q~3IrKZK0Rq1?L5h@A4g zJ5CwZ#U@fX$!g)yAsN@EB65K3v>rw{YfCb!ZDsJxwZC|$LeALIMLo~_b}Z?ME<)Ng zNa@MuX);Mz5BCEd-Dx$clkJuRwGn|1m=dJ+w?>(BFbwtganra!qOI$lqObBpHOLe{!iEhd%Vywb$3ZM zjV8DF77dX?Z=y+Un;x8Dh5eeq#qS1$?OyHM4W~bF84tyUMTziKRo#_3jZ{KQRaPuZl#-83TN31KAC?2$53?w9-;Cqnzhkh|+ zi2A0P;N|e!chw6yR;ZZ@yKgS9u(GM5yLMGg(fO^>S`}86)~m14gw@wX!$cZH@_|*>m>kq5M&-|;2a7Y%bbQCd~wzUG`jM_$?QrRClA~FZP zD3n$kHG%5()Z&*$7H|fE5{1I_tPCq-^YgFrRC>9sVRshlU!4@1?HSjIX=NUa$B2 zVb0pxY#W|DYwnNtCZFp`@0Z}$hHEeTkFuw|yw+ZC{F8i79}iOISB<)wozJzG*qLv$ z+;6?-_^+_9-fx4`TUmJb6Fo`9uzV}ppHEL>Rj${si++_4>8YDpAxje{Vi+{GlJ2?B z6Ab3_4xHG*hGQn~Aq}>gKa}eU;~Q{Yl|$4xiyA1f&>kgay-6ZNvSrU`Bj-b6o&C-? z7GDe=*J0c4uW7mZWQXlM+7r0Kyz2B>iZ*Ax=1w(+-3qshTeVwSFWZbiOfWWAKbbqd z^R(_0?y+CoFQcLwQNPO-+z#`#iLLL#y(Zy}ZSn>373+S^n7;*)UOH}jV<)<;pQ3eT z++lWk9-qHIK0fSqd)yi(-A`Ozc6!jmdcP^|@+@6- zf&9K)sV;K%#(TRSy+rE~Yr7TOZP2bU#;kKIB&edaM{z4O4ELrN++bQS!c&bQ!WQbH zsI7%pRSqw|`C!mC5%H_kM?cULq|(Y`t9)L2g|29ph;MeoK_H!;M^q-L&XG=|wK zY%lc?A{_9x0B$}n4u|KSA!RX1t*Z0(YWD~oA5NW5rYVMx-j1NDFzN@U-SOG~4cxhlxdOD~lPgM+b5UN{apsauFHu|e!VY#Rh6-2T z*|q*!J@j=gljYayO=)fTNShuU%P%a)btTQ^u$|p_O9JXU2Dq)gZ&LG897BP?PfxNf zfnPmJfSU_k5A?unky?n_`^Z(ku^2N*P`C)KX1a@np{HurPX^o*mf*9Mc zxQqjtiu4ZDUmZ6o?)!zqycQP2h#lc@sB&HeeK_002R+vT;UTUzCAZm@YK2yGdbnfe zO11k;Wu|nVxXh=4bZ92rk*-$==Yko>)^bj09N?{W2mC5pGE~*U!{_a`SDkGdry-L* zi8(6^GQgmt=x=j}{EaEvBh(!Fu=Nb!w2rWQhMGfa-{+1Z%zG4OJA*i;9*UbJz!q)e zPra6ZEPvqVju*Q>u8}P^Oyn&rI@si}zR=8?;5gKYdJ#JlyQ`}0nd$_nV4kUrob~}1AhEp) zd`cEjapF9LO2yoSkp)?TQM{Mh&Sj_7qSZf11uBGjdcv~wy!aEdHOwWJ7fe8^QD>S9 zKI|}iOH?IJ`_EJ@+jp{i2JJyTkA6yS%*?jt+PdE)9fs{;b_j?XD@Alhgz z7H+D#Xa#Q*@g-#eqs*e8VQHf@uV0N-Wz7UCj9TsW(;Q}fjvUKTjZo)aG^b}Y+tG{< zD2qv3rFm%;OaV-#ky#Y$Ejyc40Am!|Mnl-xZrJt3I%8B+xSC1ACgm-Aod{h~W&7{M z!FYw%>Q(jf_0b{j%(RoAVJwcB(lf12i*vgo1aI>eWR*_Z=LTO(2BFf%gUso}qOhu8wycSc|Y~eC3#z#=5_-#l>?t&#d)mEW9N3q z#8VH}bx*EOU#JwK4nOR;CE#45=XQH>7vrJ7g^Ax_utrRoai&s-L|(r9&WQDZT;)-j z5x_OK63)jJ`~O(`3b3}8=I_!XZL!kg+7@>wXep&Yad#{3P+S6}1qu{*E$$L1UV=l> z;tqk}4#C~NaPNEH|0})!?|bh3p5JrM*<^EOXJ==VlbM}a+aH|?B#KVd8&agTIFTec zcc=YVj+CoykuRpGwce^cMYd756B`Q2|Dp3*Md{+zu5E-TBio8IfgyXSy{ zPP-j?cYEEXj37jo2Bju;`xPH_xH`*OTfoFSp|HIRoPdc&oJ7YXNBR^r_sW-Keuf0?bCpjf_jZxdV#%VWI+lg*PwPT}M+v&^~Rjvw+dv3f;PH`GZso6Fs58t1;r#^fb z3G`Hh@3&e+X^F!3`5eLtyknR;BY^c%i26^#xs!N~;T3t8gD;E|rOy$V z72Y@1X|2v}%&*Psz#_r#Jdz!oOx5W1@zjCPGWoE9wBi8BcXIUmQN7(j3Or~at!oAH zt?KNq1bRg5Ffg4rY&etnkj43q$1u0WUp?Lm5-$&X2liZYnee>PvZP{^;bG&Oad!By zMU45WT%BOPi;t|E>atvY@2-SMmuw()@?yTroviz5TWch`eK!4rx(~}&Vc7{dVf7W1 z=TUOyr{AAS^LvG_Uv?qHx6^O_B6{$)#Lp#g2g4|jdEJD z@g4fQbg!yLWBu7QtL=l>txDLXd50tYD3{DV$PR^A9WL93&z9%kX>Ci%U^y-?u%{Gs z8*E3g@@30WEJurOG#ei5Y4B@n)y4T$hXT%^#?)Ru(GSk0Czhkz5OjOHUjT>@CE9?Q z$m$=FOU~GW?w#Et1kt`!hF+G@zU)GLgd@?uFOo?^y1QF6&X(Vga*J{sXL5#+I);+^ zn-4~5o^*4Y-|EG;I`WtY=af%Os;?c$)U=H*g>#L7zfB%-ncS|g&niwWrYke*B^wk_ zl>*6>QlK>7Mdo9;%a` zHq~U3KXadm#lB)DTK%RsD6i>oS}8FuF2(t%^t;0?o$!JB&CM{$X7Rurh*#0Yja|;2 zT`m~E%#oM|Om;oTu^%_$c>TuR+2O!jLjBn0v*dAF#VJ9qUcw=!ER_7!mHYm)_Q9h? zudt?D)s5k$f>&9sp44)&tSSSRwCkw_622_JO-p=u-Yu?iQ2on_*P%TdLvJ%n%0evK zI1VRL_!0Y@jxpVCb-h5_Ieo-U>CinM+GJ`Az8oKLt=I}|*u_^Qc)>}9YSY)4AUwx0 zBSzf(rc(re_Dn@rds(?{Ih{m&&d#II7I-M^T+{7n`g(N0QUb-2kBl0O5UVOz2T(8Sj3G^OwNbgr+oF z&xV0ccAlCFKFkHc<)etpFSQHD|#uCHn)(i`Rs{$Li!;Yb|M_j+$LP4I2MpeVuVx zm8|0uYt-17l==WAS;Ze{+Q15T!Z(34d!X^bMe$vOBF~(kx&n`ywjXF$ z;K#mOxY^^!k<*+&c8`Vj{Ghb6JdMo^IOl)s^qt156BsqM5CXi>9Hj|$``Q@uJO-1T$gHs>#?Fu zrBkFJZ>U!ZufGDG6pOiLQflWs%Ty!FJFuYvdG=vz5;Me|2;=gFX|%Ss-k7yH=0G34 zIqDre0$X`&RXW&wk~dv}>___B=^ei7E?qC7C`eZPnWXu6_FxUN#%V8VyH}jd@6TN{ zBu7P9Lp=jc5A6Z# zgO#$>wO!9bY`R(SQiiLf8P|HkH&h!NOlQtd>Sp(ZiVD0oxu(Xru^nfif=sKIxfQ#G zv)>ETiu%@+O&j$uWwd+3c4l4kxJ%c~T-v=mB&tP&kYTj-cySQYU~C%k8&}!5`>d*( z1i_a>2E!)8vkX|llJ7Xp#`3zVa^ckA@N3@SAo8Lcf;hePCR08!yk}XaNoL`lC8BxQD^9}^L$6r0em7aFvPv~b+E`U zp#Dtq6TUA3!aXIAv@m|dm7n?k{c3EaptU0oLiT@PKZ(QeqO*|Q@IieE$OGKH&%y#aktD-l>P~-%yVM4cXt+!|Jc92T*+5e7uLtRE+1HDpGKVd zgfWT~Dc@R&{zxM^#xybl`a-zy)?a3V;P7$%`g{QKaf8q%pOYN#ORS9o$x3_d2Psq_X4)Ff8KIyHMS1EvOZWyh^Yj%52R6A<~c zW`4@zqrX%8+@?xZacMJ{qmZq?e(!)f+aWU5W^T$8@`yWD@57kn{qcL|7kmQd_3-N< z-Va#BXmi+$Kkxo~+i%6ktKVMb-}0UfJCf|fi3ITV&Mdl0puo!|=F3^eorx2>fiz{` zGtLbEJR7^CET;6cAovUxzeQz3WTz_H3t=)WkCX(p%b`6%tIyLRkUS!*o=78AJK|tC zqlg=hYiHd%e%>lqu+Rh>rrE@Fl{K`&%WS}HW4(H1J#3@iNpG@_g}FM#zsjtxWCITI zw@OYjf;L+5UzWhPH5+%PpY^?`pDm&;I{nR9)wgM!TH(=yN49}E?y>P`<#7z7Ldome z`+uP@qgHEJSZyUU;zm9*IvFxjIwkt9xcaS=oK^IP!Jvyy&4?Tc98C04naK;C*Nb{( zNk7e%HZhY@zE>e4ci#_ough1j^6sF;r^U)!;5)UYM>}ODX>zX9?`GL*yll15#W|@r z14s_UZr7(_^!EdOL;CZRTC$%B&^P(r6wuox+sEBr$~MPEbA8l#YoN=H!4DoJU6#fw7(rw8*)>92=c@ykevY72nS{Ty)f~J?(r(@3N@0w(C@0^B zxIc2uwkS>CZ27op0FGx?5PE%lZ>-Iuh}?7^PgL8!@qX-mmB$M7uXFDGPoed~Nj4uh zUFo9~5(7#;Zd{g9evm@OZ!bS<7vM7eUT4t4fbz36U+LRcQbE#B>*0+lC7$7-kwBsw@vpV##c>X%rqM_CKH z?oTLH{CpUV`2_?0Agy*;xHU44s$$S>R=bPEv1Xg2bttvLgP-vke^C|8?Nk3_e#Z6U z^a`I}7K&owNrRdqW+*9mPHO*M7;{z&2`jvyL+^gLskB0thFu;pPFfnZyk%y4ndY0G zcKsx)+3spr%r9R03GyfznM^QZF}n+EW;*a<`)F@=!D6W|U@7`K>sly@N>g8*y4t-k z;~dXgnRPUw;_9@;J&IN2F9KZbSR7hQ)@gOGPR`pR9 zk1{14dnjEpb75A@c2ED*QMbBIPoA2UL~*stg-T{VP<&!nA$uZhz$I+`o$sylAi)$;{+ z@%OCtm**Y#F7#8Dw?l?bv@^Pc&1rzRM3v>qBmupJd`W?|y);U*Tb#s!``<)CQUeAg4Ud777}&(I z4Ce->d1%$leQ9l`mwL3BXCD5Esw4(lgdR-pp546;RrHyHl+ZjIjpP`|>B?e_`H=EcONZ^O)Y za0)h8SdPF(d_~IP@=L@zC=>O{=%Y+qSw9u`cWPOCY4k*nR<2#S6?D)A5yH<+^c9h; zw0ID_XXyRzOKE0j!|Ep|`krSdijBqsAA9X*Fgrb0)w@I!5Be0y#wJ<9yed>5Lz!z8 zOR6Uyzse}6O>yGyrUp8drd1YX3}L{+V?J_5^P>#RQB}JYuJGeoXDHIDT#j!2eC#*; zHSVxE(0ajAk$B^=1lvZgL*zFDT53v*Aeh?AYFk6vkz$IPNg#f^ZmimQ^|tF!Q|~vZ zZt-mK)5PK82_yg5Pzopm(G;<=dwwE(r)lPTZ`CiEpS#*oxx2AF>4F13O!zJ($J(Sj zz=H8fXiP7sOf)K;s(ZI!>3YRu$DF+?YXNhyf_mK49k8*e=J(kOk{)eh{^$mR8uOQp z`yXY0*h@427|ac}S6vlU{o7G6$t|!2ObO7S{G?%9>?z)qOfh-;!ZE)C5wy zppm4R!6sWsb^MH z>31Hx>H9r3SlHqLKNt;UH2KD<0kPR&V|5j{JbK-l*@=r}eCtU5v$Qe*EiW{?S>Pw7 zm>La^3z|xe@@Lst<`ds_V6$53@rE{vFH?a%AI7W#zHjs#n8C}_wkiIK-8#==_#FRu z?St`)00x(@QZ_b=x!7gg4eMTj(7tztY z-x<7Pz~bM>E>B~%PLQu2PTLB~a}O(TpFGA0F1Ab&A}}6oTW6nry(MTy4IP=k~v0M1W%~Y8-lVLG$vnNm2+jquDps}!^niA0CP*~|& z9X_0S%QKqkw@KUBYHEpeaoN9ibpUZtP?4w4rDIUfxL^XKlNhq47^ugNJ9eX*a*cB*nlQ(@>-Gkd5*R>*~(Yc^;dLRlM+(_hsQ_-$cDB>*ZnjI0;vP{6;{5RC_J4 zllF4ja;DsBZCZ`{*ORNW`Mr3+rA$|gflGq$p`U;H8U+?e$n$jngEkJNX^D;?FLhZe zQdap{^1Ec^UB@UCePrNX5Huy87B1HT>? zbqjs{^eDgMg%EUKxpwtSYfB)}Pr{GiKf2#aKb2z5{OG%p+F?iTRPI=Hq8FCO z<50v?X-FzbctgwcN9tWo5PFLb(Z@_SA0EkKgE#sTTpI!vdxkgUvzjRUK>Knxz(Jz7 z&ROPoi)q!n-{W>}t`qT&T$m4r@D$_mhP2<{PzPs9iG5|a9(|#0uU1M3I2D(;G2HbZ5lWpanS|C$3krKz0V`cSj^J(GH$yy7 z?!L^mP}hKf%h2fS1{>=03&AaHy3D4)ItmNA3*DoewP_w`ISa-9S!6>t_j|JCgw>lh z$P%O^LjWp8%a?`J;Ml7-PL8E&w*-G4JiJB|U0jAY|0p&jMF0aLc`@Va`4eC*`YOb} z`ICXQWLrW(l3c9Cn}&#n7Cx1e3iH@JB87xE4)wU7mkqOzJw*GQqXSA_K;O|R;SL7n zj}adM%%(Pkhy^qo2G~YUt{D1``O6}n+~D?ct4A`V>Fw;o={eiemFzc~+Rbz=)$%Yr zOf+d9ryY8d+;(AOLsUk;w;_YiA8G9>WJ31vOutvRlgNF+$72q#dK&Y2!df6G z4$0qn&9+bv8BC=*hYEJ>oDdFBrKZ5q>@J0J}@B0GSJ7KN^^(GpK zJF}eS#qpHN0mQVFF_30|L%DbOi&ssXi}XnAYV|>`9yuCU6I?^(TuPR&P#)t+n2}YQ zFk|S(o~U6R*fQ0R@~2H{+*h0Lyxs#p3vn&R+z2_|bLO6Xdg%XyTvhj6+PI$2n4vTD zA}_R%2*&ejt=3`qRHVZxj^uc=X%^NMD=c`#k9+=+YRZy^#h8%?^5Iqh9lgLx{;RjN zaLx$O_Z5jXK*OJ^|MId4GgIV;VSXq?uBdhg(=usxIm(~Ej5hw}4brplSXc-6m2~M3 z79#?eb70I|=Ir=HRv?CvYu$8~FY zxZGS&q_!D1l9_db{E3YpFCXDzUh1D7%>G#XMrTw?L3_r89fp`1A5g3<$v+iOMFb zOEizFQ^{`NwV^H^rxW}V9YNG)>y7UvoNCLT^<-7I#!(FLc&bPYr*7)fPwP-Mk~(O0 z@n-B5NZQ1l#Bn}=9Nn--wQtF5gYQOa6@cHNOdVihpqW}#WKFiUo3%E$M`*Hq(EmJy z@F8L98L=)|8rn4-X-(`J`!a)lp`O9vIsnOPa#RmEwM@iQv3i^krW6vJtYB6Ds9O!6 z2Qv|!d^KoD_J>`T0n=RM)!^>8$UuEAytc9z9=;PD=a>ESOmLpbuhfvV5BS3EnQ2a& zUC?xOQX^SzI-6$=IYqKVT>_E^sv*=%om0=5N)O=ki_dX(v&#B^V&j&A;;_RFqhqEw zf?xeCY>`)Z>oUAaM&qf&phYS$Nu;VXE-8Oesb!@=A+6s*W*IQW$7kuAHf{1^O#~2X zZt^5_wf&$}pW33M8J}5U$)z!ccL+(Gb*EuLt_$VV@cWXDgoEeR+b-%Hs~yH2TZeR1D?Tc1BNT>YG81AUWHvQBp< zo;5F+DD#`Xw=6qgujnPbn85dF)98trXda%$WKU?sCR}~1|a-7ODOK5WXqQRSZs1g>#mC^79N-d=j$m^yhczl6NIP`6tQ<^|fv ziW%ZB>MVaBMQWctTR468=){lWtZ1XfjZr#!d}4If&SveC>3;HXB6b_Hk8)lII;RmY zM?5Y&L=9>IwdJBTJR*3)zL~4oezG<9cnxId)Z_@=HTRfu$T(ARi**#@CwRgj`%0!v zHu{CoLQ{(3>qqxfvmDNfBjs^>JkNtxYM-JTAO#m{CTi6GjH6;cnA1(E5yBY6ev>#F zbKX`e=n5+peydCd5mgc_ch-1S5EVyI>flU}@ri0`<(ns`gF%u(@CrDVAV1QGwk(Q> zIq~eNq}eVl2IU8$CqP^iUi{>_ta$nuTc<>Ixv`5?t228F>k8d;L6sch8Pl1s$=pHj z+qZSpk2XsZr+eS?nE+*YLAtG&3rUJdVwSMN&(T_DY&=4>V;rjX%>LR-ucq2-{JIIN zhU^l>gH10GOCCzU>%5Y?_Q|@`8U#@AwZAJH`( z*GKzD6~WiziE&2L>%PQ8{(U!n&OG<}Qa%Ur-SzRFeK#^eZ}5Zndv3pD`^vZTUr{<( zj6se~-sGW6CP@BEc*`LOMOhQc$9HNc`E_cKW02cH7(16R_s*)YKDI3VjYv}g z+1z(S|NkI@Vb5>kg0R>Iirs!UVc3{@cqepz--_(sAHpMC<)yD`<;wjjCbvo>ZzlJ{~BqCQ5wJ4 zbCb@Jw2$f>5%EF|cdd$D+GlaQ(n4$ggWBZzzu&E&p-F^j)B700j~KLH;i_H`HZ~E| zDGx%3m7mkCez%k~{Iq##g8v@sKUnGP7yh?fuO9dH+%;G`nOqghL;q3 zCqwnpqCfQRKd%Enml~=T_j4JS_DjBYUQQ#_U-vVXuaWkw>vCEP$z3|`8|=XBp1Y{F;`36(9ahK~&#`|)I2d%#{aLeRIF*vkAk%hDcN6V45j z;q{Nm1&6^N_niKTqnrmvi52^j zullO?V~rIUeeZ;{ZIGsEhy|50g!X6CoZd{Qt2x~E0EhLH#@&+GV?-|WX(wx%UQT1B`m6ZB=V_K zX^dx-GRxAo&N&r{)eZAFSEHHb4JY@zQV8?0(ddi`$eqN=LT+R+$wl(V=t_{XD_`g1-klO-9b`^+S6ecyrv)O1j?c8vmZ4U z8Yv79uVAJlT+p3r{fyq0$&^t!2l0h37yh@3Gt6v#gJnC9U5&P8zU3d)*8(*18-PSd z!Ne9-#jnxZ7;3V(KhXC0=m}~Lls@Gt+^<^=r=KZ2@2kd{t~uQLq1<7&Gi}3obbq&B z760>+Y|DP~Co8{}tFbDmEJU54`#G826S4NHg2=>1?e39L?{)vqMfoAoDcH?7f{o&B zHN0o%9;&fBNGkwN&$f&by`1DV015nY(IUQ>P%KaE&FmHYfqK|=+YU*(9 z`MR0#5Bv^$e0=nIZ!G4=Q|NQjDsR{$81@O#7toQ*ni=sk9I}{PUuC)N@l>w!zRK#R zUaTu@&3_O?wwV6xHoe)(E%9ZE5lDJk%4IBgQz|(3Tjg{Lf%!SY7*E;ee_Oz~sM5V| zSD2Ahm{HjkJZdybWU7*MDsGxxuNCex*C?0NslptobR(}zpY}zf|LeY!ws!F|aWq!* z(W0_--Ni((-3+HNWAesZs3#7}tSq}k=PVbxIlkb-*uFN`fV@xuMVS0a_{k{`NJ;8+ zaVNdR8uorUS4sK8*EXK}91FU>u2bNY*5*pvv)>IL>b@brG!wN>a4JcN3l@51tw(Q7 z)>}%Z!zG4(6~(1Yt#9V%ES43W$!SvGN!LKN5u!=OAiIt#4i)I7(Nod=2}&$%(;niq zq%UpXAc@^fm|GIGO<^>6!>$G}$oIAT$k?Drm7(+ymxBmjU~Us*-8`-8OFLIkGHO!& zO@Omd(X@1*s=+=Vk*pp*5}m4KX_{xSD1Uq~h7p6^&^uFZJFjl)^A68m{Ezh_tQ~>L z7lf)_25Q76QgNfw$$MT9{>{|(*+7(poiiCS-J9JKJE$yUWwr}{d1PSKa+2yZaJ00X ziM*7yVti=B(d}VZ!jyZ*^h<$Ujj-`?!M>8Iq^S~3e}YlZ5sNV`mu2FTJR&voiWG+N zd)d{s{@Ic&9o43zE=PkymNpZVP@h~?^rPmY&&)+&z(!i*mabKDsdP4EhNr@qq)1;2 zJ%t)!p}S;XqEr#q{j}d9vF9pO&Zr`lCmed?{p6-Spmff+|9PP@7v=llv%DRFl9g!? z$P_ieK&$R*;S{PqYuC8S4V+4guY#rXab?N3VIEf(iPXeKu@g9#&&A>nsXAv3>qtsh zXoNyuboy`J0Ei_|H5BVi=s8#yZ3)ZS!-5=KI*zKqhaVqL7OX^?U#sA&wP%gR^`O+? zE-5?TfRPKH4(3nDXkRCU4yw2XQOC-9D~ir|D0io^XMNOLxxadeXXmMQ=M{<2TSokNg!>-d* ztL5?t)E54&am-hRm=4ebP82KSq9{8VGJ!fpovTC>v{_S*b^l;nV(K)!P-9lOa#KUC zMOU#06J|DKVx_N*hx);CjQb{v=4sr_-YZ^t2cP6*TGFV)VfsVEh3Y<#iF9H@=vVf> z&SXQcL3FzM&9xv8VhL>lL;p#lz9#~PsWW^@3^WM46@(pI{D;tFN@=2Xo?TRO&G8|| z+GMPnvx=+iu~I1AeN1{}rHW-AtuT+)+cQG$@N=f-O*vBHi$GIsd<-RM0b}YaUk`p8 zmvHcR&N-i_debpP>jg=&Mz@`_S#4IB7~Rc{N%>r^UmPl&)n|eVc%~BG9J~BD&5q$n zShQNyOKWEvNDY4r? zncSw9@=hvTRkRRt&MI0cZklCF2rV&VlK-I!`pMfh_7Ts_WWG2xXAm3n*#cF)@rSDK zUy0rll+7N~Gt9}dm?bEf+@7etL?S|a<>kWfe;EvxnSud`@}PJjBsNoe4^i{sVLWrv z>I64m-sE_S%&0nvRtcs&dK_(=z@S|U0tt*hV*`iS7W!}83fg2z3Rk9NgeDa{BB`@i zI^-HCVkZ;nBk1;2I`-MRfBEQH-QLcJ++a%#>_;R-%nCkgc{daO5d=1)fRNCgP>~*u zT0zb z4VpU_EFQ_o4;&k3m(cA&Y`EbQf{0_$Fh7dv`*09pEa8cDI9z^TA;lYpakyI55$Q?1 z!7~1hV0Yu*8eOe!o8Ef{f`T89EiXN&8RPD^*gQf$?Q4JYfg#goDtM>8{&v)E4p=?) zBt84VtNXodQz<-}6|y4$?ji&JerZQmfM$JpH)`AhFu50=Vf-dRu=i!$KNde=zHgW> zj7GNB2x5t@@a@=wQG`BNOSj*oL)v!{n?#n7vgR`4jX0-4*&3_xx zP$LX0pKBQQwz)mI;=@!1(QuJkLP@xc&@j+!N1-CLq16C~B+n-YBMYxXb`eV-NJzM+ z0^f!?^;t+9sP9^Cd*yrgk>`?T;e06ygdJvEjy9D)mku|dUJnpWG15Kf!ZkBFPDvq; zep>0`K))K+RpT;^%_7X0_Wd#QI@N5x={SZ*&t*PI+(ED+TZSXhLFm466t!=~A?$e( zBbO6Nak-0<_oHiNWf;#A)9q>U$AY#J^EV3|Jp4sNW4|vVAQ4`ar%=ob(?y=!lG?ew z*1sXSr4=%$Ij%D2%4mg66T~b3yiS5P4}Tr1RkYx;z~qHw(}z31lGZ;WCH5n*clF$q zLCZTSsahkhd^=g?qM6H2YAbvcfVf7FL^Nh& za-A*p$Vm4miD>`(NgZPK^6)ta_Me{A1_am32DcHPX5Gx7Tii4kU}|M3R@1mspX+7 zt&1|5fd%%dBsg&qqb$UObeIbMt}TLYH!fp>ja;jA!JIgDkZ8hc8O`j>pJp<4#A-5J zt<->t1$iRYzboj}{4I$zJ!uSyg6->Cq!rX(7mDpC{2U(iVA287XWYzJIw)rjfrSU5 zD-dF0EOXxUg^&IZh{L!?KkQwRj#KszWH8eR2Q0}^uM-OVzD~qFENu8wq9%WDZMoCg z8)?e!j$^JWu4$ve;Yp9#%=E4p<2(^>c1dsc1y*JKZ%uKD-34r#h>#110{3O5T1w_G zaO>htn+NWG@E8d?*GflucRzBy_}t5|0@-Dp9_;?T&>A0izpu`NIYNbkZ-Q9}M$Hwn zL_$%yiGN)HBl<&(X~~s8lr9c@W68CQ0|Bv$`l4bIbD0mOi}+UC5_3VHOw)FoJdC3OyP>53;+%ENY8(cfs6SxI9LKNwgoaM6*@Y$hEU`#zYCd2JF# zPfdUbgs>cRh^E%XB(ALGGH;D6AK-Z7TdjbZ^r4b6l2TX}GbzjcA_g^-;>h%@!%t}# zNDn2&>(W{^L?O!tq|0SqVqv9B%w_+<-%d@@cNHP3zs+$bYG1JxqzlpgOQ*DH+5`T+ zp|~bUYXU{MC?O^3#+-8h^TUN>;?#n~{%k#8vajP-ALiB}wH_Xrw?muUz3rdpA;am^ zq@ms6;+17Fts;M}#&;UtLF_7fr^X)<`WzadW-Hh#)Rf0Cr%_Ur@tYd|rq3Fpn4Oku zI2=W5I1YJ-4{Jx<{d6?RU$}CFM*tnkUsQOIzbHi8N93Rjh+BPC#icfTqAGEcQL$go zi+}Ji^lD`T;5A?^2V&+9SFk;J4EhO=?8@<@G~ui1Q7yHiIe0kB93JtZat9pD(s#-{ zkv5vM?>hqFS|E|v=F?5e0Q<7+D6ZgWIn}0%`~IP(zbe>-*3tZ-;M32PvR;G_UIU5# zM>#61M$)Ia?&pV5p7Y~T5j#q9`B6^LWQ7)OBpGQf^?bTY{{hfhr;B6};?Br|%ReIP z#5#`>-8>RuabhCVh!`Bor~+FiZ5_6}y=H$%=2*Hl0wGHApCAac9sa(PU>zts8VF1Y zEuHIKKu!-*OsxgwCrhH`h1n#IH?9z}T5p25Wa>(GxxVUl^5}iL-AxL!0%AoUx%D^N zOomlS+>Xe0dKiq*11CmhpxK08Ghq;iH<&L}%yTl33x;K5r15v?ti^A|m1nCDxPv_E z$Q%wGMWMOkT37N0%FsHIaT(Ov4}hkt+QuD7e>Hdu8n$X{m0D$^jYyi6E^sIXDciDw zLP{BnHCOXUXJI^~7io5O(CRk3gH+;yWlm2!=;_fW_x>cF3_q@nRYMLE$}?OU1vZfu zm)WXJ}q~O=BKhg|xZTk1HD$+bGi;|DumZ=yxG1=-t zKQU9^Xm2nV-{`gI?zk_tre%|7Q#TYcd|n}4Ly(92+{J<}lQ=TTTDno6JI7T4v7&3M z6Na`X*$AIT3|k457km9A#WPlvrYVC^q&uyLnanoM%}kavnPFWIH>gl5zx@Jq9f(Qqo3ljU|8sLJ+AfVc!KAy5DNBlUF~s8>o#ZS9G;42ln@6n1r=Eja1UGm)5R6 z)mi6}!fh@~H`Zx&;JN9e@|8EuxqDumYGF+4X=0kMMCrJ8T_z8bm}AcD%y0*5l~?x2 z3UtN+W&;tfAxk2hHpfdeTLi^2*7sG+W2_=?;hXg~ISLQS{W!T?tG#Q&s<}Xcx%^H6 z*>2XPtUUl}C3BMT>%h?C0DO|)+y+7{JosqW^kwYl9cr?Dnusi>OMObY!iu4DnLklN zDY(1`&qS8ceqFGd;m+9i?Z74$Hoqd*S~~q+eVJO=VP~P||NDFCh)O#$Ztsu{*oavz zIm+${w_}p)WfG^at9H?;W=UuA2x>jaFLB8(!o6pU09;~K`U-GNU(-+BsMp|pW;-?RrWXXcTM~|;O_1<6>9ZR7iz>|wr4AUz!xjg zUnjc**^zj zdj469Ys<57)d)6Y8|HTU-I|~rYP;9AB=x{Mx5~eF=wDyK5o(X3zXH4JybLef9Jc42V5<;xI)%C{RS#xkY1Llm^=Ox;lBgc4 zr3ka}`J41g@pgFx5%kPfI9<09>iDX0?(fZ-rQ&D1Ji0`?ce7?dgAWF_x(Bl&Lwex$ z=O}fWK>p2EeP^%!ccc=y0ay8v?4;ucXAV}Hp+iS_C@}tyrx5Yxd$2zTV#*-Z{~Bw^ zurSkN>^;*Dz{hSQB0$tVMC#55Fn-wIF@@JRL%)rqx?P4XBt$nSQ+!3L2jh9RLGS%d znp(+#dZA9X%5FQiU|-IUHFZ97dpt<>cV3A9kkh}uzMG8mn7@P&>z>QRDhaG{WvZWQ z4&Rd9@fp|>|Ho{u-HiC-t4eJg_ z|C<8X|5E|H&F8Q0enA-a^pfKLX9Op3-AJq+)H~0y(<&#ep_$#=RlV}Bc`)BFj>Gm# z@5JvOi@R_5e|ks$@RIy~-F5$T>gCmTx$vn5@oxopZxyY9s2Qr+60^$kw}gQL>z}S) z*h#A9L8)&?hym)Xj_n5gn{%KJetpmG5W%XM&6Pv z`SZzuXnW?L(}9B6O}J#IG4FAG{Hn=6MYGF|0&A>dX@=fCv?Ie1uBrJQi=tEinhYej zQfFk0UnW*uyMS=+IB#-vuK6-$$HI!J z&My*c5`@u2gfCxoz~;{8g1aOB#nDC2_xz*-w5>0k}52^Iec85m!_P;VI z@+{eM5;?W?fmHJq6_%edu!k-sGj9^nPsOHGq<=1TjFktEhiNRqj|$!@o`#gnW#kV2 zOF%=B^KStSJRNk4+C1z<$jcXmH z7N6+ZOALt}gm&ZKY*Lw-6))8I-CBP7@cvqbN2p?dfeDZp{2Vq|nsqZL6~XW+3M7(9|mv?6S3ft6F3W9+?3aTKDDoVIG{vXgsI+)>q%439;7})IA`tKj`L?B zYkxF~$sbl`w6_Lk{ahfd;4+VtKs9bx_GpWT=%V4&;jD?8B|Ks=X2zG>lk%ipt%ks}wq6GnXVej9_e#S?6V5*ob ziwTwbp(eR)oOHZ|AAAyA#{fRCncB?+B^uOJXw+#^bLeW8c49D+2v@Unlym1EC~(d~ zLA93)eUAXnmNE;ukk~>Xma=|_?&InFiWo4{IhzeiW@MDR|Hja!q^cgr0OLh*s}8;A z$~2aiA_ME^Jl4sD(@_O{+tY3TgE;?wpK*g!}DRanFuGDaxc zXcf@<(s6s-FJ)(8OOGn1K;JtIPbHHY2<&jE ztS1)PaF9Upai12JFA|x>lYWn2VE8S9Atj?+^Dcs6dnT7#z40)oSL=m-M+(-gl*KV+ zE;y2)f4FdTbO&8stEeH!hmGN}2X0FH=)+Q5<$0m~yd&>1DH{RRMRk198vgF*#z20} zBO&Dxd=%F=CAc+VQ^E&(xyw(evC=MOJF$J@ln=R;ixNL=jVFO~^((Xu-b;uNI%O5i z3fLy(S^QTFLqJHtMKWMVXc?%6mL+QE{<_mI#z@yeSrXyR6Ce-+BV zPXtu-$&v}GuMku*HhF6A`r27Qby8)@P&lv=&3Z~Dtx=V&D~edXX%N#yg!f#xl%uPE z=QK*#e}_w!e=hTeG>mCfzFkeC04zImv>;?rkgH0aV4z!6pjS8~#`#!uGgs3==wnI+`@t`uh-*)iHqY|d8y$7Q(EB^g{)J{5%PNUy(QiN^*jb%U z56bHEK3f1VE*8orKPh(L7oAs!97s-{owI~fJbJy1x_vmiQr5|t%#WjrBdn_aYUhAt znH;*W8j8was~D$0M9U>mGwQDuqj3Ereo}_?&S&yfUr!w?Xp_DjS8RnrB`xQ(fha~U z=XT*RHtSS#@oGB-PuzyYw{|w|GpRIv3T}EFA3P`v1_@m*yh8QM=sW$Qr;jU$8{QjO zPO6AjUw8VM`*Jbv;;i&rEq5OBNmuTwI6+m;gWUzZZs;*ardP0=<{CG>54lUHe%{m< zAEWjyC|?*9D%qEy&f=fb*5)Udz`bFs_S1(;zHR!jZO&O#vk8Nn-e<%ztQ6AaQ8&UY=S5L2Kz8`AbaX-(O;E2t7y;3Vc|4SGHY2(ABwnV|K zK!$i;MP5R7qp8)3e+gsg{`z|uga1hkuW~DuR9&*By_z8J`?{*@{5b4R6SjoZ%fEZD$#9eGPF^!aG)rxqC>V+w26M9 zlKMe`_p3e+`_G9OwLu%P6s)>jR+wncqVbSe_?!EhO#N{c1=ILAH5VDl!=b}2q@RH} zq3kb&E()ngplj|A&Sd&inO)J+jY0beFqW#0+YX=C+!A``@abbm_k`zPjwOT#ab=q4J>gXNyho}DU1 z%MZr2oZQ7fB{vMjF=4`?+1j%kIwyy51>Oe-Av|9@bc7d)w!zWSQ%wxF>vN~IOzJmq zHYhtfuxN-lEZ&Zdwp`C^4^07#i474I9{tw*OXE25!^MoNK@eXDjXQ{311PT!Nzgl1G4% zX_9oTuo6u)mLRAVl$HNUK-Ku2JLM0a_9BL(vo!CgJDjnv`#sr|ErxRa?4@pM8N}7> zFJtUfPc-ZDkI`m51z8MuVEq<47Fhi}7No{{v2YK?7ACI*la<^Y_x#nBF2}fS7vFwW z;=IfdK|%wR%QVy5wY=HW-8oV&7kMlg8N=P0`t4nM+TEC?=-I4jE6}Mj{qus`qmj#@ z{FW1$o(DY|@hMxnISU+tt8I^WxCPdB6*2i=%ssOZHw5WlZ{(%9XxFA}kK4biSv7i4 zv?^5-cE~{1hP0WTIqbB_4_@6FZdI-!XLq4pB4>3O@UjU1cKOoNU1B?xWQD2P$1Y%& zj0S0syUvF>JScv}MSXuk)CjTllIm>fa9aH5S>4eq}yB~d?a8;@rt5aiduSRE^#hQm;d&`|TxP})|wREn^@c#H)9pxyOs^#V* z1J?jWwZ46Zm<#VR0YEQTp$tkh9Nn+Ib=Nc&6=~bMg0>T3YsN|MlcjYNzqCA^9OHrrG2lOEIMb=WxzIDN!$*TA-irQzzT1d@)%-U%r`_>8bz-_e(O~b1>xRjUI z&SQQ{IKTwZ>>Cu^-$+$yn6Hbw&Tc#4`NqUk=Nl5rd;S6^{Tmam)Zpgm?evpGF2E*9 zN5@IWbCZI^Wr`IX`jj&QZyMosNB(P+G;(zM4W-!+s-e{IXA~%l+*OKZwSCn9juZF) zbmd>f$-8;_K{FzGpb^MUz51!O8X$Y=t(qFgWWKt<(HxpBYT4UC<31kQxzS?(4PMs1 zh8g3bUQIkKD1U{vb;U_Aq0^aj?veFn|LTZre!-DXk=)a7sIQ;>m=alX-VN{g|-(pV{nBT^UJo$|PdS0ah6wdrK)RtXV>$YY{opF!L&#ETQ2V7;ig- z^w<^P(ymmfT7Im%bg0C{RfCTkQwRgCUr;iG?{t1~&4uJHZ?55UTZTCl&FlilFP}WO z`VF7!J+6sqw~8eW(w5q(TK0EfWPbt}t{~W+aZd_dniE5Rdm>P{%JLlmy9-`bPqd^6 z#eX-sEj0h3{5A6v)(}k#YaJox2s#~lLp|{Y@|6F>*gM5Z_5}ZeGi}?P?w+=7SKHIJ zZQIk+rDP+6H-6&aD|b55R&Z$w65g{Q9ltpsJ}S_W%g zlbc0cGpjbWs?NZj+wU&1{7WZVN*=k3-@{o9xfj}QiufcumFsrt6a(j@e{Us+WIIxspEL#kZydhpdG)UK-Yr$HRg^*ljM0rD%~X1voBacDgxg` zMgOOmyW`li#D?HrWs`#`mfo5GwBWX0z6H)#cb9ntZ2OBhpDKI58Ym|ChD9?kGFP#X|C7(RU5KW-nRZm&^i zSbyzu94;`vQ%+3H)+#M7mvYRR4_3;@6wh+#{elxj+$P>OEpMlpv{AmFo9`Vjn+NXE1OVlF?(PJ57G8kY_9xvrXa^0oA8Oi@S+Z6bo$9v>ecKbg|Z=& zAU|CdQQuR-XwASz?wsGLc*=+gR3RM9glb;)&xz+nIy{($+_Q>*rNf%eY_&71boW@I#F3*y4MSKYNkT|-?~6w|Qrm$Fai@&v{I zwl-#fjUp`$Nn}SV2*n6onCQG4mY#amxoS;p{79MW4gtT%#7sT->JTquV+i;LOcCIz@19g-60;|qHP&`jurn@ z`MKF`En>Txn)r`i;CvqJDruNpQ@ruRSueoO-Orz+Jj|z*fQ)9!hdc3-Kxgf9IJdbsM)n;Cl3UW$QC zcCBl5UMrNxzpUwX!b~rhS)b5lbuDh~-|xY@X0*pm507C42HIDj7fC6WpUnxj`SG1) z{cO^g0rV$~62*T~qvU?rZ1PHmnf*(?^A~JozrU`~=Skft(Q8Yd1?0A3LS-f?u$uqu z*c$|XcO8e$N*~I(`=QDc9q#A#ze3)*f{bw(Sx7BIy0x>R9-kI zfqZ`pJ;%t<8zX<(;M(s+jHcd4>tW+m&t-ZP7~}|gpsaL!934XuA}I)C`Fz!C98xS0lkx3;FBN>Oa!V-udb0 z&`jPLD}`~EQ}WprV9xS-W4aM1eQYMU!1Upn+rDmc-Q0v@gF2g!l1!kECMzRXcEf5H zZ`Uz`CX2?-oN=P1GX`0s3!<>Ryv-ffvU3BsN_Ugj~zi7Q6BTFan_(9O&$PQOJ;7gJC0nP zSDRa>`p zYyB7(6GV)v?zeV>W*ff`n+N!#nzOyDYpeYLh=+HD zGNXu?u*I#1joHk7{29(xp+}5HEGb#R%bwVsX0Jyij*uSwiH(G5d}v`XW!}F30U%nH z6L?MUX1}K-t#i58jO?}H{ei#a-bD{h_(*zUi};TOVYxN}*53Rjsg`D~lM9~8fp>R4 z9f;XG+OM=YbMFIs%e&@#Hsd;sY^X=lQ6g@1>{62AX?W1$x9)oNrbSsFRK3fxJ>r zcQcyDNb%^s3#OXjdeLaFO?NKa-sxZQm^&U)W*1HgGSOzLu_I(wNr87<+lzMC$7EY# zLct!`)B9?-H6}MZ_e*L1q16XP3Wdg$2A#h&zm}EIc`SMr07|WPACEEUqU4<`OzJ+? z0He7B1l0}=1DpMlZ!QerE0wpwbRD@VlhSgFYJM_E#(5!NvT*A9F(* zBK5b`m6*xV`yMCbIkwRPO~xk<`bMp(U@3&e6$`XZl4qg#+8PUD?PBHEgmMUFyAIrH zk2R@(dy+p{(mGOi8E^Dz)OPi1_Zsgxfvsh%e#*DCch!`PbaTm$QDHY5x0`wQejO0= zqbD_>(7zZyV}Wv`PL?RTlK|79SM zNRU7x9!)%CME`Ok*U#{7A|9QTbBiB3iIs|OBeT5>{V?q?C-Yz31pVK~sqUu~rn<3H zSU#n3+cKcn%L)>X9$@gJgP+8Q8cM zPyPyipmV6}(_DZ=x*H%H5dR(1bu$JZ*L4G9jxtlF z!4*ufHMSe`zYAC=k6HsH`yqyNoK8LyfunOFx;thvV%GnPMmFMmvh?hfT%Kk65KGDI zsKxe#ty{@8K2GO}SZrauZi2e3o!MB>S)UftJw_he82JOa&GbzO+HJ45niT)@PHFoS zwefD>V|jb*rE8U{ui+&thD~$LAB%QbWf$yRkKtEngwF+P8?oBgtMRfMUe<5XC!B|e znGY#qbdDZ3vA8q-YuGj8(_0C;q$SgL4yun=vq*PJ%>F?3+A#6CQ?}s0%Z3qV0!#P& zugaboN>3+#L)eyQFX%6HIvcu9(p*({)6QH#oWH02orNDNIcYziw-vF;JK1tWrbGB$ zau0XAUgJA-o3q6DZ!QdMx?|9e1fM+NyD!>)*Yd6aG2>*tfBY zc+&ikLrRyE4?g^?PF+VEDz-(h9^2>7BfT85=e^awjA!7^1^24z+8K3ilQ7*-d%CpM zRtBhi>oI-StLjRs&kl>yS#3Q{UJ2SaRefG=G!4g9WVGv|jwj%()8NP8WQyyiX$t4} zt*Kg0H`PVkP1Q75=7CvZ)}(Bk8`L0aoGdhGSGo8Gdum7O)2iyG%oaTQS{lYcV;5Ta zC5QG#Y8sY1bQm%;JH#>3(j~7gR?50RXJe)yH0t&S8IHkq&gqm)T_?YBH4JPWNU1Mv z&@3!vow|<0 z$spa@jGw$ZQ1jbv>f3mAKrJ|EQ?xOeC*Y$Bq$v<6H63TYDZin+y_4iKi zrUD~cmP7P)r?Ts@A?fvrutM;&gf86dhDY_|CZV%`Sh=p2U;?I>{F7s)v#$~w|Kf>> zTr7Wuzw+|G!k&=|bMkdZ^BU6T)!%cUFZ^4zXiD251#QXG&MY~(V?ywhKF%6pY@o~M z4cDP^^|G_Nwt=d;B7@^U5wkHN^J-jxu`+h14KuhwuY|$V zVYM;dGlA1V@#dCzUyZJWPyG~&pr$5Q@~_$x+rDCvG8G4in~95ye~`X${3hE4SNQz>}svJSp>D@8=BYAT&=v$b8nk%8+0?Hg<*xVh4;G^YPVY0BjiWd_7j=_=4YZY zD6e<5ERRHp`i4eQAX+w3GcOeGnd(YPp;S{d%}{wK!j40Xb=Py-NMigs#8JfAS)mHw z$Mehp38`ZzeAt-j>48Id@|cqt*HBiOG_(gd7a(XZI>%57ltxp?EX%G_t791~45lc9 z21tW-E8-CTbmkDA1Yh{A;Q$t;cZ>L`-b)Vyzs6W6|X1dI^*D+rRur;Zj*+9v~Yo(SF{ud zDL&!U3d}L5tF%nak6666)PZY=`#CPXH6J6q#Zh?t=xTTk#jvS$Yc%{$i1_W9ZqB| z1pK^WIu)m};Y2m%h3v`A$ziGQ2MD&~4;i|kxhjkRJm;gK zvH*1;-k{dIP&Z?D(ZYAE?a%f&rC_$_41Oazfj(!PCHebSaE=z}X>cb8A129LuQ!q) zK?Q}(T0QpJnT+FOIo&XK8=@hSu1@>MYXLY*u9;B#WXw;)bH=JsYKVnbGkh*bjHfv z+HJh)ml6HA`q(fw~SIrAamBGI9Pr?tQ?2Kb1=5SxDoQxDmbCmb2u6jfIR@e2q z?UmXp<8%~LM|Ho4BLJlqm^31O#x2+$$E-K1NsF}6ufuF?vr{}It7-( z@_xUwHkPApw0CMK-RTv@RvZ&m`@{3K3E^TsRrGWV^5lx$ENhD~ywf6ap7fjvYfJI$ ziOB(fVGLcmAif#lJN`jcs0cU7!_uyIS0#+(Ac|sP0xi z!?j|nd)XxKPgl<{P>=20MVBzhsl3^X&iMK-xxg73v1>$J$B=~XUg6eI&NPJ@Hg|bc z)}omFU)_VDzBj~{)8u${sO-gSc9fLLq#IwpctGvCZD!s=92NVE5UqHz+>Kw7S z3u{5UkD%bui9wwmAE}+Y!+=t?f=16KBmckC#5-qcRyy9gziiP^fqFFs3}RlBY9}QF zC%Ze_npo@mdC2xEF+XHyq@)D{1=$aEX|L{kw}T8i`cXKe>&kyfLW+3PAPzSY1%JJu z*M0!#`Mqy?vHpcJ$Oq5j>M4{xdvhG*u zn1?zUda_i`Ur|RMo@V|^Dn6T1B(<$Hveg5K*|;b3uqOE}lg$3&))`$%a#B$;4+UPR zRn0}6L@MiM<3c+Mx{?;Y%+}5z7|$eVvOJf~ARK0RuwV_Folhwa&}o}BEW4V~RK*S) zFqj(sbu~MZLX*$@m2wbzHpLWK#PQ|2n7+F?DSJA-l%5YjB^6twIG>^uT828C!l9^# z07)9(LT`-XgYRlqCZr=;=Vezt6TOe4l{|K$ZCmSupX>^0yh}t?j8R=xGTaZii^%&#%w=`Otl} z$*|SmnVTq!`y|e0MJM|K%Im>`zgM#gyutm5-20!d19y_|C-FlPm<U%T15$@nKn-{6wM%ZFwKM-7#MJuQVP$1N8-8lLNPP}LTC z3x9P)l0uy}v%<~lZDrm8{YI4TUf(Z4{w`qfGP2%om6?H&k@l|l&hwau$zTzC%bE@{ zasL8V38!>{Dt^X?bPTt6Z+WlxfkR77F^k+UL-2-0>fyWF=R|CW|E1Ytxh8COV$iHd zeyb1$55W5naN84Q+u9vm)(3(Gm-FA^39IZpzUGAq(?V-}{nq<@`r-V;naok4!RmlxKoe8c)tCnMU~11Rl3K8JxB{2O|#G)ioyzm_r5 z3%PKD^WJZ5I-2Z}xbjK8fFq zZy=qmKaCKtRk#-t?Dg?;^)v6C8;*Mi;R`H-_yOJE-j{MHJgpvi%bl9hzAs^#b{L>f z+|L3C+G=I&Sk-j;aK{zqFmL7bxuEpe7dQ!2{A057Hhns*t!5H(%uc}O|4tj5O`IcK zDIj0mwY=wWPxgZO)~uR5+**idQx3w)l&r}y?H zLVi9=$^#hyW9s#4*olLVs1O=j(@bWWL8;?p{^YK^oxpNZB6)1rQsVK{`#JbWjNd9R$= zVYr%~ljQhJt2?0u=*r6|Y`w;*LFggMy2tSCjA0I-+7Bd%E8^#Bclp zhoWTk{X-IoO&n*Fi1F~C%J_;f3D$#C1hl>JNS|}1Uf}Xs!9~>RP276wa}W&XPU(r@ z%?tbVMp^vs>l*0@hpmfugdOuVyjSZlIWMr~*r&;4=R7+<1n~`Q_ZjEqHU%zF;!piy z>{;y2>q``qIPJGFii_97oqWv4t=8H?{nMNYf4C3q@+LNwuajGh<>Q2C#A>R}fw7Y+ zZ#|;&o1j|t4gDv$BguI?^UL`}>lRUyhp681C#W|}_+lS+$uQ#2wp{q?L5YsC-%M_T z{W>GgGL8rfO^K^Ip42n~RTtVV{9i8%)BQvE94kS&I)QJ3{U0=4d{M;LhPV*gJLsS9 zk%QUyl*mBQdHkLj;=Qj*LqVfX6xaA|42mDtF#@1-<~hR$LiZ>ij`T8#JI+?RyK!y# z>7OMxN1}R!RS#BKxVKIKHfuSo!b7c=!*gXi@j|dDrG%%1WWf=z&u7hN+G1a^`KTo4 z2QQw3G3Y3AWi6NVfqUmG$tPY!XAK(Zb7#sjJ6EZVrVN?W3~LwO3LX357l#F0AIRoWjlQTGMx` zir4nderu0tPOLjvDB9~UJOWyuy#GkFSi>Z8JoL|)ZHH^ z!MLPUGBU{GD;I}J2`zo1t;lAicr>fyc4N{^G>#-8kkGvYlT}!b~>?oV_i}R z+Y}mp_xXUX1?a#q8$o>Z!(`8qX`O4N&5>S^7zau~ALPXS*t0$B*yj!2OC$43`ZL1ceM$6poA(iobR> zqD99sp^=;gY=ExDG=C!*~=o4cYclB4WFt=8!3&rOozugY$_)pt?XN^`{a z6L%kdte=XZ0IRX`Vv|o)-IDT7qA8iz5sN0qmeK}_2FH%E97?7o(Q4Bc8wC_zNb4d7 zp5)8xFGKF2&q1f5_b_>gt?9e3@5YbE-_xf34JiXM{XD>x@yU+8H8JS71qJ3X>gev= zKT^`SQd#15tTPhPh8%yX$Pct5a_FKw_G zZjW1ZNDlpr{t=<7we6YK!U6o1BCN_x#M{^sNX#*#$0Sed^m2RNnJtxiwQdV=!O7t4 z;R3T4yiy~#ldwUXKky3}#4ISVaRT4`gx7ATH2D*Xk!d0pc#5MP2<&_(kJqoe)W%j~ zJ3D>-UID=mdFm#y$Gq{qI&&1yGPb&upK>O7SNSuFA#M!Y+ccc5rOU0gv$wOXN6J?Q zM?oU!zqCbjqP}m>lTlgi)JoB+dQdQUneC8g%JLDwU$c%-83m6R;jL7O)Dq1P$^XOq zXIgP2CrpfpCr@fo#x&9t^Ul>)N<#ermIDolMmnei1O?)lp-%CYAh;Ib6{oe%-Q3QO zdac!A@Bh&hLNsHj1GwOz`57T513z_ZeqxqC4`ki66_to!dcmPK2u~z9BZLZ&(Z(=k zm1#<1UG^{2S#VFH;rM<*6HW#9!GMuu1Den-ueYq>XFhHeyPolC`Urb^8yo>{5v;=u z^*!|d;pea>`*6NuDOTrT{xC6Qtjk0aW^j9Bbd7slECxy#YhAU2_VedU5xZew9Ud>) z_Tz+5MpTUDH;N}TO+&XX@3i>3MVxOK-M2RVuHu%fD0Xj_-v)w>Q9d}`ck^wo=IDmZ zBQ33MrVoSD^XdSG(rM2{)n5bRg}QT<}c0tja+LXTGJ}L zY!k}dX2I{d>WpDxTK9tg0zBWzu3gxltbr{`ux-2K!x~q1P-Ld!S1NJ($nM$c`+h=} z@r}}#YhxfJPg_dv?;B3GcMevHxGuiaif_CZYPS+~-*?AR zu(o*;)3T-=ddp8!QZq99SXD z&f>*VgT_R-#@HPBaVC}2UNdb33YH(?3qs}9Bf|ur-?2BbC|)HiLfM>$>8xvh9%Yhd&__A{nC6e^%!h!WVIg#07R zoyoW6T=hqlJ#9djEPi^MvNa*$oa5D;aE_|MFC`?+0n8I=tpGS z?F@3rYeSS4X*>lQ_$zk^5;E{^`;Y85ABFvaIn>!98A66jy#YY`{c=cbTL8j^u=a&7D{T~!$XEMB^9ir|UQgForT8;fif>5X z6zT8@^BIqieun-?&B-XcZk&SY+81>p%iuxn7jTp-6t!?Gn^lTF-Fz@+G#YPa{s%ci z*pMr05L)l!xpR}E$FcPQY!aBs&8n9v9amWpBzNQrVfNO?O&sU-i;YIL*2i5}S7m#0 zy{+p>pQK!-0Aw}|tPE1~LIrhP9_FpTchs%1NYc*6Gn?zHI_l$+jr6dXT~Qm4wC;yK z$SyZfwu(F{c420$<*W&oPy`b`(%~is?s%p|U!LxcFFrlom{@sR*=4++d9E6dJgH)i z_t?#a{?M@`RKs0uQ8ly9C|rMPQyn3WtY)b?r_6jD-|wXio~7R6{?`lkphaC-kjW=U zA`Hjjll~J~iQpe2qaUu!@>mU-m?N@K7FAXiV54BErof?UMfJZJFiS#m%At#e1fMUZ z?w$fLM?9zDH|B7PGx6f6HH&^{tyilfMc}c580W3V{;Uo4?COl;p#m<$4Yv>WX1Xp2 zGPL8N{21dSm=fpJq8uYnru%qx53&QBM%PuY zjGEOEfW>!zs+5>wSU9B1VjG?1M>cyAj*ol|4vtktix&{tYF&ry1ZeEZk$O&-{x

  • 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 literal 0 HcmV?d00001 diff --git a/manager/pom.xml b/manager/pom.xml index 3e7e3530..7373bc2b 100755 --- a/manager/pom.xml +++ b/manager/pom.xml @@ -143,6 +143,11 @@ dao + + cc.iotkit + gateway-server + + diff --git a/manager/src/main/java/cc/iotkit/manager/Application.java b/manager/src/main/java/cc/iotkit/manager/Application.java index 15b2122f..81e84f32 100755 --- a/manager/src/main/java/cc/iotkit/manager/Application.java +++ b/manager/src/main/java/cc/iotkit/manager/Application.java @@ -5,7 +5,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; @EnableFeignClients(basePackages = {"cc.iotkit.deviceapi"}) -@SpringBootApplication(scanBasePackages = {"cc.iotkit.manager", "cc.iotkit.dao", "cc.iotkit.ruleengine"}) +@SpringBootApplication(scanBasePackages = {"cc.iotkit"}) public class Application { public static void main(String[] args) { diff --git a/manager/src/main/java/cc/iotkit/manager/config/KeycloakSecurityConfig.java b/manager/src/main/java/cc/iotkit/manager/config/KeycloakSecurityConfig.java index a87de6b1..c6bb3d02 100755 --- a/manager/src/main/java/cc/iotkit/manager/config/KeycloakSecurityConfig.java +++ b/manager/src/main/java/cc/iotkit/manager/config/KeycloakSecurityConfig.java @@ -53,7 +53,8 @@ public class KeycloakSecurityConfig extends KeycloakWebSecurityConfigurerAdapter super.configure(http); http .authorizeRequests() - .antMatchers("/*.html", "/favicon.ico","/v2/api-docs", "/webjars/**", "/swagger-resources/**", "/*.js").permitAll() + .antMatchers("/*.html", "/favicon.ico", "/v2/api-docs", "/webjars/**", "/swagger-resources/**", "/*.js").permitAll() + .antMatchers("/device_behaviour/**").permitAll() .antMatchers("/**/save*").hasRole("iot_write") .antMatchers("/**/del*").hasRole("iot_write") .antMatchers("/**/add*").hasRole("iot_write") diff --git a/manager/src/main/java/cc/iotkit/manager/controller/DeviceController.java b/manager/src/main/java/cc/iotkit/manager/controller/DeviceController.java index f89e0ec8..5d6359d4 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/DeviceController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/DeviceController.java @@ -1,6 +1,6 @@ package cc.iotkit.manager.controller; -import cc.iotkit.dao.DeviceDao; +import cc.iotkit.dao.DeviceCache; import cc.iotkit.dao.DeviceEventDao; import cc.iotkit.dao.DeviceEventRepository; import cc.iotkit.dao.DeviceRepository; @@ -36,7 +36,7 @@ public class DeviceController { @Autowired private DeviceEventDao deviceEventDao; @Autowired - private DeviceDao deviceDao; + private DeviceCache deviceCache; @Autowired private DataOwnerService dataOwnerService; @Autowired @@ -78,8 +78,8 @@ public class DeviceController { if (online != null) { condition.and("state.online").is(online); } - return new PagingData<>(deviceDao.count(condition), - deviceDao.find(condition, (page - 1) * limit, limit, Sort.Order.desc("createAt"))); + return new PagingData<>(deviceCache.count(condition), + deviceCache.find(condition, (page - 1) * limit, limit, Sort.Order.desc("createAt"))); } @GetMapping("/{deviceId}/children") diff --git a/manager/src/main/java/cc/iotkit/manager/controller/ProductController.java b/manager/src/main/java/cc/iotkit/manager/controller/ProductController.java index b0ea953b..005c46f2 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/ProductController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/ProductController.java @@ -50,7 +50,6 @@ public class ProductController { @PostMapping("/save") public void save(Product product) { - product.setId(product.getCode()); dataOwnerService.checkOwnerSave(productRepository, product); if (product.getCreateAt() == null) { @@ -66,19 +65,19 @@ public class ProductController { @GetMapping("/thingModel/{productKey}") public ThingModel getThingModel(@PathVariable("productKey") String productKey) { - productKey = getProduct(productKey).getCode(); + productKey = getProduct(productKey).getId(); return thingModelRepository.findById(productKey).orElse(new ThingModel(productKey)); } @PostMapping("/thingModel/save") public void saveThingModel(String productKey, String model) { - productKey = getProduct(productKey).getCode(); + productKey = getProduct(productKey).getId(); thingModelRepository.save(new ThingModel(productKey, productKey, JsonUtil.parse(model, ThingModel.Model.class))); } @DeleteMapping("/thingModel/{productKey}") public void deleteThingModel(String productKey) { - productKey = getProduct(productKey).getCode(); + productKey = getProduct(productKey).getId(); thingModelRepository.deleteById(productKey); } @@ -104,7 +103,7 @@ public class ProductController { @PostMapping("/uploadImg/{productKey}") public String uploadImg(@PathVariable("productKey") String productKey, @RequestParam("file") MultipartFile file) { - productKey = getProduct(productKey).getCode(); + productKey = getProduct(productKey).getId(); String fileName = file.getOriginalFilename(); String end = fileName.substring(fileName.lastIndexOf(".")); diff --git a/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java b/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java new file mode 100644 index 00000000..ae666898 --- /dev/null +++ b/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java @@ -0,0 +1,126 @@ +package cc.iotkit.manager.controller; + +import cc.iotkit.common.exception.BizException; +import cc.iotkit.common.utils.ReflectUtil; +import cc.iotkit.dao.ProtocolGatewayRepository; +import cc.iotkit.dao.UserInfoRepository; +import cc.iotkit.manager.service.DataOwnerService; +import cc.iotkit.manager.utils.AuthUtil; +import cc.iotkit.model.Paging; +import cc.iotkit.model.UserInfo; +import cc.iotkit.model.protocol.ProtocolGateway; +import cc.iotkit.protocol.server.service.GatewayService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.web.bind.annotation.*; + +import java.util.Optional; + +@Slf4j +@RestController +@RequestMapping("/protocol") +public class ProtocolController { + + @Value("${gateway.function-jar}") + private String functionJar; + + @Autowired + private ProtocolGatewayRepository gatewayRepository; + + @Autowired + private GatewayService gatewayService; + + @Autowired + private DataOwnerService dataOwnerService; + + @Autowired + private UserInfoRepository userInfoRepository; + + @PostMapping("/addGateway") + public void addGateway(ProtocolGateway gateway) { + Optional optGateway = gatewayRepository.findById(gateway.getId()); + if (optGateway.isPresent()) { + throw new BizException("gateway already exists"); + } + try { + Optional optUser = userInfoRepository.findById(AuthUtil.getUserId()); + if (!optUser.isPresent()) { + throw new BizException("user does not exists"); + } + + gateway.setScript("new (function () {this.decode = function (msg) {return null; };})().decode(msg)"); + gateway.setCreateAt(System.currentTimeMillis()); + gateway.setUid(AuthUtil.getUserId()); + gateway.setUuid(optUser.get().getUid()); + gatewayService.saveFunction(gateway.getUuid(), gateway.getId(), gateway.getScript(), functionJar); + gatewayRepository.save(gateway); + } catch (Throwable e) { + throw new BizException("add protocol gateway error", e); + } + } + + @PostMapping("/saveGateway") + public void saveGateway(ProtocolGateway gateway) { + Optional optGateway = gatewayRepository.findById(gateway.getId()); + if (!optGateway.isPresent()) { + throw new BizException("the gateway does not exists"); + } + Optional optUser = userInfoRepository.findById(AuthUtil.getUserId()); + if (!optUser.isPresent()) { + throw new BizException("user does not exists"); + } + + ProtocolGateway oldGateway = optGateway.get(); + gateway = ReflectUtil.copyNoNulls(gateway, oldGateway); + dataOwnerService.checkOwner(gateway); + try { + gatewayRepository.save(gateway); + gatewayService.saveFunction(gateway.getUuid(), gateway.getId(), gateway.getScript(), functionJar); + } catch (Throwable e) { + throw new BizException("add protocol gateway error", e); + } + } + + @PostMapping("/saveGatewayScript") + public void saveGatewayScript(@RequestBody ProtocolGateway gateway) { + Optional optGateway = gatewayRepository.findById(gateway.getId()); + if (!optGateway.isPresent()) { + throw new BizException("the gateway does not exists"); + } + dataOwnerService.checkOwner(gateway); + ProtocolGateway oldGateway = optGateway.get(); + oldGateway.setScript(gateway.getScript()); + try { + gatewayService.saveFunction(oldGateway.getUuid(), oldGateway.getId(), + "new (function (){" + oldGateway.getScript() + "})()", functionJar); + gatewayRepository.save(oldGateway); + } catch (Throwable e) { + throw new BizException("save protocol gateway script error", e); + } + } + + @PostMapping("/deleteGateway/{id}") + public void deleteGateway(@PathVariable("id") String id) { + dataOwnerService.checkOwner(gatewayRepository, id); + try { + gatewayRepository.deleteById(id); + gatewayService.deleteFunction(AuthUtil.getUserId(), id); + } catch (Throwable e) { + throw new BizException("delete protocol gateway error", e); + } + } + + @PostMapping("/gateways/{size}/{page}") + public Paging getGateways( + @PathVariable("size") int size, + @PathVariable("page") int page) { + Page gateways = gatewayRepository.findAll( + PageRequest.of(page - 1, size, Sort.by(Sort.Order.desc("createAt")))); + return new Paging<>(gateways.getTotalElements(), gateways.getContent()); + } + +} diff --git a/manager/src/main/java/cc/iotkit/manager/controller/RuleEngineController.java b/manager/src/main/java/cc/iotkit/manager/controller/RuleEngineController.java index e855629b..c0289408 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/RuleEngineController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/RuleEngineController.java @@ -40,9 +40,6 @@ public class RuleEngineController { @Autowired private SceneLogRepository sceneLogRepository; - @Autowired - private SceneLogDao sceneLogDao; - @Autowired private DataOwnerService dataOwnerService; @@ -52,9 +49,6 @@ public class RuleEngineController { @Autowired private SceneManager sceneManager; - @Autowired - private TaskLogDao taskLogDao; - @Autowired private TaskLogRepository taskLogRepository; @@ -132,7 +126,7 @@ public class RuleEngineController { dataOwnerService.checkOwner(sceneInfo); sceneInfoRepository.delete(sceneInfo); sceneManager.remove(sceneInfo.getId()); - sceneLogDao.deleteLogs(sceneId); + sceneLogRepository.deleteBySceneId(sceneId); } @PostMapping("/scene/{sceneId}/logs/{size}/{page}") @@ -150,7 +144,7 @@ public class RuleEngineController { @DeleteMapping("/scene/{sceneId}/logs/clear") public void clearSceneLogs(@PathVariable("sceneId") String sceneId) { - sceneLogDao.deleteLogs(sceneId); + sceneLogRepository.deleteBySceneId(sceneId); } @PostMapping("/tasks") @@ -230,7 +224,7 @@ public class RuleEngineController { dataOwnerService.checkOwner(taskInfo); taskManager.deleteTask(taskId, "delete by " + AuthUtil.getUserId()); taskInfoRepository.deleteById(taskId); - taskLogDao.deleteLogs(taskId); + taskLogRepository.deleteByTaskId(taskId); } @PostMapping("/task/{taskId}/logs/{size}/{page}") @@ -248,7 +242,7 @@ public class RuleEngineController { @DeleteMapping("/task/{taskId}/logs/clear") public void clearTaskLogs(@PathVariable("taskId") String taskId) { - taskLogDao.deleteLogs(taskId); + taskLogRepository.deleteByTaskId(taskId); } } diff --git a/manager/src/main/java/cc/iotkit/manager/controller/SpaceController.java b/manager/src/main/java/cc/iotkit/manager/controller/SpaceController.java index 46e9608a..e95f07fd 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/SpaceController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/SpaceController.java @@ -30,9 +30,9 @@ public class SpaceController { @Autowired private DeviceRepository deviceRepository; @Autowired - private DeviceDao deviceDao; + private DeviceCache deviceCache; @Autowired - private ProductDao productDao; + private ProductCache productCache; @PostMapping("/list") public PagingData getDevices(int page, @@ -58,8 +58,8 @@ public class SpaceController { List deviceVos = new ArrayList<>(); List devices = spaceDeviceRepository.findAll(Example.of(SpaceDevice.builder().uid(userId).build())); devices.forEach(sd -> { - DeviceInfo deviceInfo = deviceDao.get(sd.getDeviceId()); - Product product = productDao.get(deviceInfo.getProductKey()); + DeviceInfo deviceInfo = deviceCache.findByDeviceId(sd.getDeviceId()); + Product product = productCache.findById(deviceInfo.getProductKey()); deviceVos.add(SpaceDeviceVo.builder() .deviceId(sd.getDeviceId()) .name(sd.getName()) diff --git a/manager/src/main/java/cc/iotkit/manager/controller/UserInfoController.java b/manager/src/main/java/cc/iotkit/manager/controller/UserInfoController.java index 4cb24426..07e1f132 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/UserInfoController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/UserInfoController.java @@ -6,11 +6,11 @@ import cc.iotkit.common.utils.ReflectUtil; import cc.iotkit.dao.UserInfoRepository; import cc.iotkit.manager.service.AligenieService; import cc.iotkit.manager.service.KeycloakAdminService; +import cc.iotkit.manager.service.PulsarAdminService; import cc.iotkit.manager.utils.AuthUtil; import cc.iotkit.model.UserInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.data.domain.Example; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; @@ -29,15 +29,18 @@ public class UserInfoController extends DbBaseController getPlatformUsers() { - return userInfoRepository.findAll(Example.of(UserInfo.builder() - .type(UserInfo.USER_TYPE_PLATFORM).build())); + return userInfoRepository.findByType(UserInfo.USER_TYPE_PLATFORM); } /** @@ -55,13 +57,26 @@ public class UserInfoController extends DbBaseController clientUsers() { - return userInfoRepository.findAll(Example.of( - UserInfo.builder() - .type(UserInfo.USER_TYPE_CLIENT) - .ownerId(AuthUtil.getUserId()) - .build())); + return userInfoRepository.findByTypeAndOwnerId(UserInfo.USER_TYPE_CLIENT, AuthUtil.getUserId()); } /** diff --git a/manager/src/main/java/cc/iotkit/manager/controller/aligenie/AligenieProductController.java b/manager/src/main/java/cc/iotkit/manager/controller/aligenie/AligenieProductController.java index c7cd9502..a14982da 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/aligenie/AligenieProductController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/aligenie/AligenieProductController.java @@ -2,7 +2,7 @@ package cc.iotkit.manager.controller.aligenie; import cc.iotkit.dao.AligenieProductDao; import cc.iotkit.dao.AligenieProductRepository; -import cc.iotkit.dao.ProductDao; +import cc.iotkit.dao.ProductCache; import cc.iotkit.manager.controller.DbBaseController; import cc.iotkit.manager.model.aligenie.AligenieProductVo; import cc.iotkit.manager.service.DataOwnerService; @@ -23,18 +23,18 @@ import java.util.List; @RequestMapping("/aligenie/product") public class AligenieProductController extends DbBaseController { - private final ProductDao productDao; + private final ProductCache productCache; private final AligenieProductDao aligenieProductDao; private final DataOwnerService dataOwnerService; @Autowired public AligenieProductController(AligenieProductRepository aligenieProductRepository, - ProductDao productDao, + ProductCache productCache, AligenieProductDao aligenieProductDao, DataOwnerService dataOwnerService) { super(aligenieProductRepository); - this.productDao = productDao; + this.productCache = productCache; this.aligenieProductDao = aligenieProductDao; this.dataOwnerService = dataOwnerService; } @@ -49,7 +49,7 @@ public class AligenieProductController extends DbBaseController T checkOwner(T data) { //管理员不限制 if (AuthUtil.isAdmin()) { @@ -37,19 +40,21 @@ public class DataOwnerService { throw new BizException("无权限操作"); } - public void checkOwner(MongoRepository repository, T data) { + /** + * 从库中取对应数据Id的数据中的uid是否与当前登录用户一致 + */ + public void checkOwner(MongoRepository repository, String id) { //管理员不限制 if (AuthUtil.isAdmin()) { return; } - String dataId = data.getId(); - //没有数据id为新数据 - if (StringUtils.isBlank(dataId)) { + //数据id为空的新数据 + if (StringUtils.isBlank(id)) { return; } - T old = repository.findById(dataId).orElse(null); + T old = repository.findById(id).orElse(null); //新数据 if (old == null) { return; @@ -63,8 +68,11 @@ public class DataOwnerService { throw new BizException("无权限操作"); } + /** + * 从库中取对应数据Id的数据中的uid是否与当前登录用户一致,并把当前用户id设置到数据中 + */ public void checkOwnerSave(MongoRepository repository, T data) { - checkOwner(repository, data); + checkOwner(repository, data.getId()); data.setUid(AuthUtil.getUserId()); } diff --git a/manager/src/main/java/cc/iotkit/manager/service/DeviceService.java b/manager/src/main/java/cc/iotkit/manager/service/DeviceService.java index fdfca40f..70448a0f 100755 --- a/manager/src/main/java/cc/iotkit/manager/service/DeviceService.java +++ b/manager/src/main/java/cc/iotkit/manager/service/DeviceService.java @@ -1,7 +1,7 @@ package cc.iotkit.manager.service; import cc.iotkit.common.exception.NotFoundException; -import cc.iotkit.dao.DeviceDao; +import cc.iotkit.dao.DeviceCache; import cc.iotkit.dao.DeviceEventRepository; import cc.iotkit.dao.DeviceRepository; import cc.iotkit.dao.ThingModelRepository; @@ -23,7 +23,7 @@ import java.util.Map; public class DeviceService { @Autowired - private DeviceDao deviceDao; + private DeviceCache deviceCache; @Autowired private DeviceRepository deviceRepository; @Autowired diff --git a/manager/src/main/java/cc/iotkit/manager/service/KeycloakAdminService.java b/manager/src/main/java/cc/iotkit/manager/service/KeycloakAdminService.java index 03175e13..5e1f4135 100755 --- a/manager/src/main/java/cc/iotkit/manager/service/KeycloakAdminService.java +++ b/manager/src/main/java/cc/iotkit/manager/service/KeycloakAdminService.java @@ -14,6 +14,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.Arrays; +import java.util.List; @Slf4j @Service @@ -49,7 +50,7 @@ public class KeycloakAdminService { return keycloak; } - public void createUser(UserInfo user,String pwd) { + public void createUser(UserInfo user, String pwd) { Keycloak keycloak = getKeycloak(); UsersResource usersResource = keycloak.realm(realm) .users(); @@ -96,6 +97,21 @@ public class KeycloakAdminService { userResource.update(userRepresentation); } + public UserInfo getUser(String uid) { + Keycloak keycloak = getKeycloak(); + List users = keycloak.realm(realm) + .users().search(uid); + if (users.size() == 0) { + return null; + } + UserRepresentation user = users.get(0); + + return UserInfo.builder() + .id(user.getId()) + .uid(uid) + .build(); + } + public void resetUserPwd(String id, String pwd) { Keycloak keycloak = getKeycloak(); UserResource userResource = keycloak.realm(realm) diff --git a/manager/src/main/java/cc/iotkit/manager/service/PulsarAdminService.java b/manager/src/main/java/cc/iotkit/manager/service/PulsarAdminService.java new file mode 100644 index 00000000..3c9a8af3 --- /dev/null +++ b/manager/src/main/java/cc/iotkit/manager/service/PulsarAdminService.java @@ -0,0 +1,51 @@ +package cc.iotkit.manager.service; + +import cc.iotkit.common.utils.JsonUtil; +import org.apache.pulsar.client.admin.PulsarAdmin; +import org.apache.pulsar.client.admin.PulsarAdminException; +import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.pulsar.common.policies.data.TenantInfo; +import org.apache.pulsar.shade.com.google.common.collect.Sets; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.util.HashSet; + +@Service +public class PulsarAdminService { + + @Value("${pulsar.service}") + private String pulsarServiceUrl; + + private PulsarAdmin pulsarAdmin; + + private PulsarAdmin getPulsarAdmin() throws PulsarClientException { + if (pulsarAdmin == null) { + pulsarAdmin = PulsarAdmin.builder() + .serviceHttpUrl(pulsarServiceUrl) + .build(); + } + return pulsarAdmin; + } + + public boolean tenantExists(String uid) throws PulsarAdminException, PulsarClientException { + PulsarAdmin pulsarAdmin = getPulsarAdmin(); + return pulsarAdmin.tenants().getTenants().contains(uid); + } + + public void createTenant(String uid) throws PulsarClientException, PulsarAdminException { + PulsarAdmin pulsarAdmin = getPulsarAdmin(); + pulsarAdmin.tenants().createTenant(uid, TenantInfo.builder() + .adminRoles(new HashSet<>()) + .allowedClusters(Sets.newHashSet("standalone")) + .build()); + + pulsarAdmin.namespaces().createNamespace(uid + "/default"); + } + + public void deleteTenant(String uid) throws PulsarClientException, PulsarAdminException { + PulsarAdmin pulsarAdmin = getPulsarAdmin(); + pulsarAdmin.tenants().deleteTenant(uid); + } + +} diff --git a/manager/src/main/java/cc/iotkit/manager/service/SpaceDeviceService.java b/manager/src/main/java/cc/iotkit/manager/service/SpaceDeviceService.java index d60e9639..e450aac5 100755 --- a/manager/src/main/java/cc/iotkit/manager/service/SpaceDeviceService.java +++ b/manager/src/main/java/cc/iotkit/manager/service/SpaceDeviceService.java @@ -1,7 +1,7 @@ package cc.iotkit.manager.service; -import cc.iotkit.dao.DeviceDao; -import cc.iotkit.dao.ProductDao; +import cc.iotkit.dao.DeviceCache; +import cc.iotkit.dao.ProductCache; import cc.iotkit.dao.SpaceDeviceRepository; import cc.iotkit.manager.model.vo.SpaceDeviceVo; import cc.iotkit.model.device.DeviceInfo; @@ -20,9 +20,9 @@ public class SpaceDeviceService { @Autowired private SpaceDeviceRepository spaceDeviceRepository; @Autowired - private DeviceDao deviceDao; + private DeviceCache deviceCache; @Autowired - private ProductDao productDao; + private ProductCache productCache; public List getUserDevices(String uid, String spaceId) { SpaceDevice device = new SpaceDevice(); @@ -33,8 +33,8 @@ public class SpaceDeviceService { List spaceDevices = spaceDeviceRepository.findAll(Example.of(device)); List spaceDeviceVos = new ArrayList<>(); spaceDevices.forEach(sd -> { - DeviceInfo deviceInfo = deviceDao.get(sd.getDeviceId()); - Product product = productDao.get(deviceInfo.getProductKey()); + DeviceInfo deviceInfo = deviceCache.findByDeviceId(sd.getDeviceId()); + Product product = productCache.findById(deviceInfo.getProductKey()); spaceDeviceVos.add(SpaceDeviceVo.builder() .uid(sd.getUid()) .deviceId(sd.getDeviceId()) diff --git a/manager/src/main/resources/application-dev.yml b/manager/src/main/resources/application-dev.yml index c2aa6d16..8c3f5c39 100755 --- a/manager/src/main/resources/application-dev.yml +++ b/manager/src/main/resources/application-dev.yml @@ -4,11 +4,17 @@ spring: uri: mongodb://填写mongodb地址/admin database: iotkit + elasticsearch: + rest: + uris: http://elasticsearch 连接地址 + username: elasticsearch 用户名 + password: 密码 + connection-timeout: 10s + cache: cache-names: foo,bar caffeine: spec: maximumSize=5000,expireAfterAccess=120s - mvc: pathmatch: matching-strategy: ant_path_matcher @@ -47,3 +53,5 @@ app: mqtt: url: tcp://填写mqtt连接地址 +gateway: + function-jar: 填写protocol-function打包的jar存放路径:/xx/xx.jar diff --git a/manager/src/main/resources/application.yml b/manager/src/main/resources/application.yml index c2aa6d16..8c3f5c39 100755 --- a/manager/src/main/resources/application.yml +++ b/manager/src/main/resources/application.yml @@ -4,11 +4,17 @@ spring: uri: mongodb://填写mongodb地址/admin database: iotkit + elasticsearch: + rest: + uris: http://elasticsearch 连接地址 + username: elasticsearch 用户名 + password: 密码 + connection-timeout: 10s + cache: cache-names: foo,bar caffeine: spec: maximumSize=5000,expireAfterAccess=120s - mvc: pathmatch: matching-strategy: ant_path_matcher @@ -47,3 +53,5 @@ app: mqtt: url: tcp://填写mqtt连接地址 +gateway: + function-jar: 填写protocol-function打包的jar存放路径:/xx/xx.jar diff --git a/model/pom.xml b/model/pom.xml index b2bc841b..1e7c5d40 100755 --- a/model/pom.xml +++ b/model/pom.xml @@ -19,10 +19,17 @@ lombok provided + org.springframework.data spring-data-mongodb + + + org.springframework.data + spring-data-elasticsearch + + com.fasterxml.jackson.core jackson-annotations diff --git a/model/src/main/java/cc/iotkit/model/device/DeviceInfo.java b/model/src/main/java/cc/iotkit/model/device/DeviceInfo.java index b709e6e5..4b1b01dc 100755 --- a/model/src/main/java/cc/iotkit/model/device/DeviceInfo.java +++ b/model/src/main/java/cc/iotkit/model/device/DeviceInfo.java @@ -37,11 +37,18 @@ public class DeviceInfo implements Owned { private State state = new State(); - private Map property; + private Map property; + + /** + * 设备标签 + */ + private Map tag; private Long createAt; @Data + @NoArgsConstructor + @AllArgsConstructor public static class State { private Boolean online; @@ -49,5 +56,6 @@ public class DeviceInfo implements Owned { private Long onlineTime; private Long offlineTime; + } } diff --git a/model/src/main/java/cc/iotkit/model/device/message/ThingModelMessage.java b/model/src/main/java/cc/iotkit/model/device/message/ThingModelMessage.java new file mode 100755 index 00000000..f984a941 --- /dev/null +++ b/model/src/main/java/cc/iotkit/model/device/message/ThingModelMessage.java @@ -0,0 +1,61 @@ +package cc.iotkit.model.device.message; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.Id; +import org.springframework.data.elasticsearch.annotations.Document; +import org.springframework.data.elasticsearch.annotations.Field; +import org.springframework.data.elasticsearch.annotations.FieldType; + +import java.util.Map; + +/** + * 物模型消息 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Document(indexName = "thing_model_messages") +public class ThingModelMessage { + + public static final String TYPE_PROPERTY="property"; + public static final String TYPE_EVENT="event"; + public static final String TYPE_SERVICE="service"; + + public static final String ID_PROPERTY_GET="get"; + public static final String ID_PROPERTY_SET="set"; + + @Id + private String mid; + + private String productKey; + + private String deviceName; + + /** + * 消息类型 + * property:属性 + * event:事件 + * service:服务 + */ + private String type; + + private String identifier; + + private Map data; + + /** + * 时间戳,设备上的事件或数据产生的本地时间 + */ + @Field(type = FieldType.Date) + private Long occur; + + /** + * 消息上报时间 + */ + @Field(type = FieldType.Date) + private Long time; +} diff --git a/model/src/main/java/cc/iotkit/model/product/Product.java b/model/src/main/java/cc/iotkit/model/product/Product.java index d4bd8c54..1dc2691e 100755 --- a/model/src/main/java/cc/iotkit/model/product/Product.java +++ b/model/src/main/java/cc/iotkit/model/product/Product.java @@ -18,8 +18,6 @@ public class Product implements Owned { @Id private String id; - private String code; - private String name; private String category; diff --git a/model/src/main/java/cc/iotkit/model/protocol/ProtocolGateway.java b/model/src/main/java/cc/iotkit/model/protocol/ProtocolGateway.java new file mode 100644 index 00000000..38752ddf --- /dev/null +++ b/model/src/main/java/cc/iotkit/model/protocol/ProtocolGateway.java @@ -0,0 +1,33 @@ +package cc.iotkit.model.protocol; + +import cc.iotkit.model.Owned; +import lombok.Data; +import org.springframework.data.annotation.Id; + +@Data +public class ProtocolGateway implements Owned { + + @Id + private String id; + + /** + * 所属性用户id + */ + private String uid; + + /** + * 用户账号ID + */ + private String uuid; + + private String name; + + private String protocol; + + private String config; + + private String script; + + private Long createAt; + +} diff --git a/pom.xml b/pom.xml index 8893c748..930bf49d 100755 --- a/pom.xml +++ b/pom.xml @@ -12,6 +12,9 @@ dao tppa-server protocol-gateway + communication + communication/mqtt-component + communication/component org.springframework.boot @@ -137,6 +140,12 @@ 3.10.2 + + co.elastic.clients + elasticsearch-java + 8.1.0 + + joda-time joda-time @@ -144,18 +153,29 @@ - org.eclipse.paho - org.eclipse.paho.client.mqttv3 - 1.2.2 + org.apache.pulsar + pulsar-client-all + 2.9.1 - org.apache.pulsar pulsar-client 2.9.1 + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + 1.2.5 + + + + org.apache.pulsar + pulsar-functions-api + 2.6.0 + + cc.iotkit model @@ -188,7 +208,19 @@ cc.iotkit - gateway-api + gateway-client + ${project.version} + + + + cc.iotkit + protocol-function + ${project.version} + + + + cc.iotkit + gateway-server ${project.version} diff --git a/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/RegisterInfo.java b/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/RegisterInfo.java deleted file mode 100644 index b4f324fa..00000000 --- a/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/RegisterInfo.java +++ /dev/null @@ -1,18 +0,0 @@ -package cc.iotkit.protocol; - -import lombok.Data; - -import java.util.Map; - -/** - * 注册信息 - */ -@Data -public class RegisterInfo { - - private String productKey; - - private String deviceName; - - private Map label; -} diff --git a/protocol-gateway/gateway-api/pom.xml b/protocol-gateway/gateway-client/pom.xml old mode 100644 new mode 100755 similarity index 85% rename from protocol-gateway/gateway-api/pom.xml rename to protocol-gateway/gateway-client/pom.xml index 296fb9bd..9f54e7c2 --- a/protocol-gateway/gateway-api/pom.xml +++ b/protocol-gateway/gateway-client/pom.xml @@ -9,7 +9,7 @@ 4.0.0 - gateway-api + gateway-client 8 @@ -18,6 +18,11 @@ + + org.springframework + spring-web + + com.squareup.okhttp3 okhttp diff --git a/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/DeregisterInfo.java b/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeregisterInfo.java old mode 100644 new mode 100755 similarity index 100% rename from protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/DeregisterInfo.java rename to protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeregisterInfo.java diff --git a/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/DeviceBehaviour.java b/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeviceBehaviour.java old mode 100644 new mode 100755 similarity index 86% rename from protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/DeviceBehaviour.java rename to protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeviceBehaviour.java index 81126e37..f4e944a6 --- a/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/DeviceBehaviour.java +++ b/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeviceBehaviour.java @@ -11,11 +11,6 @@ public interface DeviceBehaviour { */ Result register(RegisterInfo info); - /** - * 设备注销 - */ - Result deregister(DeregisterInfo info); - /** * 设备上线 */ @@ -36,5 +31,4 @@ public interface DeviceBehaviour { */ void otaProgressReport(OtaMessage msg); - } diff --git a/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeviceGateway.java b/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeviceGateway.java new file mode 100755 index 00000000..d9e125af --- /dev/null +++ b/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeviceGateway.java @@ -0,0 +1,23 @@ +package cc.iotkit.protocol; + + +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * 设备网关接口 + */ +public interface DeviceGateway { + + /** + * 指令下发 + */ + @RequestMapping("/sendMessage") + Result sendMessage(DeviceMessage msg); + + /** + * OTA升级任务下发 + */ + @RequestMapping("/sendOta") + Result sendOta(OtaInfo ota); + +} diff --git a/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/DeviceMessage.java b/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeviceMessage.java old mode 100644 new mode 100755 similarity index 62% rename from protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/DeviceMessage.java rename to protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeviceMessage.java index 9a8daca5..cc2d18de --- a/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/DeviceMessage.java +++ b/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeviceMessage.java @@ -1,22 +1,23 @@ package cc.iotkit.protocol; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; /** * 设备消息 */ @Data +@NoArgsConstructor +@AllArgsConstructor +@Builder public class DeviceMessage { - public static final String TYPE_REQUEST = "request"; - public static final String TYPE_ACK = "ack"; - private String productKey; private String deviceName; - private String type; - private String mid; private String content; diff --git a/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/OtaInfo.java b/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/OtaInfo.java new file mode 100755 index 00000000..d064e65e --- /dev/null +++ b/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/OtaInfo.java @@ -0,0 +1,7 @@ +package cc.iotkit.protocol; + +import lombok.Data; + +@Data +public class OtaInfo { +} diff --git a/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/OtaMessage.java b/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/OtaMessage.java old mode 100644 new mode 100755 similarity index 100% rename from protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/OtaMessage.java rename to protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/OtaMessage.java diff --git a/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/RegisterInfo.java b/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/RegisterInfo.java new file mode 100755 index 00000000..7fd26c75 --- /dev/null +++ b/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/RegisterInfo.java @@ -0,0 +1,49 @@ +package cc.iotkit.protocol; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Map; + +/** + * 注册信息 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class RegisterInfo { + + private String productKey; + + private String deviceName; + + private String model; + + private Map tag; + + private List subDevices; + + public RegisterInfo(String productKey, String deviceName, String model) { + this.productKey = productKey; + this.deviceName = deviceName; + this.model = model; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class SubDevice { + + private String productKey; + + private String deviceName; + + private String model; + + private Map tag; + } +} diff --git a/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/Result.java b/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/Result.java old mode 100644 new mode 100755 similarity index 100% rename from protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/Result.java rename to protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/Result.java diff --git a/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/client/DeviceBehaviourClient.java b/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/client/DeviceBehaviourClient.java old mode 100644 new mode 100755 similarity index 53% rename from protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/client/DeviceBehaviourClient.java rename to protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/client/DeviceBehaviourClient.java index dc5a5d3f..b1976e89 --- a/protocol-gateway/gateway-api/src/main/java/cc/iotkit/protocol/client/DeviceBehaviourClient.java +++ b/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/client/DeviceBehaviourClient.java @@ -1,9 +1,16 @@ package cc.iotkit.protocol.client; +import cc.iotkit.common.exception.BizException; import cc.iotkit.common.utils.JsonUtil; import cc.iotkit.protocol.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.SneakyThrows; import okhttp3.*; +import org.apache.pulsar.client.api.Producer; import org.apache.pulsar.client.api.PulsarClient; +import org.apache.pulsar.client.impl.schema.JSONSchema; import java.util.HashMap; import java.util.Map; @@ -11,18 +18,41 @@ import java.util.concurrent.TimeUnit; public class DeviceBehaviourClient implements DeviceBehaviour { - private final String server; + public final String gatewayServer; + + private GatewayConfig gatewayConfig; private final OkHttpClient httpClient; - private PulsarClient client; + private Producer deviceMessageProducer; + private Producer otaMessageProducer; + + + @SneakyThrows public DeviceBehaviourClient(String server) { - this.server = server.replaceAll("/$", ""); + //初始化协议网关http客户端 + this.gatewayServer = server.replaceAll("/$", ""); httpClient = new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .build(); + + //获取协议网关配置 + getConfig(); + + //初始化pulsar客户端 + PulsarClient client = PulsarClient.builder() + .serviceUrl(gatewayConfig.getMqServiceUrl()) + .build(); + + deviceMessageProducer = client.newProducer(JSONSchema.of(DeviceMessage.class)) + .topic("persistent://public/default/device_raw") + .create(); + + otaMessageProducer = client.newProducer(JSONSchema.of(OtaMessage.class)) + .topic("persistent://public/default/device_ota") + .create(); } public Request buildRequest(String url, String method, String type, Map data) { @@ -42,8 +72,17 @@ public class DeviceBehaviourClient implements DeviceBehaviour { return requestBuilder.build(); } + private Result invoke(String path, T data) { - Request request = buildRequest(server + path, "post", "form", + return invoke(path, "form", data); + } + + private Result invokeJson(String path, T data) { + return invoke(path, "json", data); + } + + private Result invoke(String path, String type, T data) { + Request request = buildRequest(gatewayServer + path, "post", type, (data instanceof Map) ? (Map) data : JsonUtil.parse(JsonUtil.toJsonString(data), Map.class)); @@ -51,24 +90,28 @@ public class DeviceBehaviourClient implements DeviceBehaviour { try { Response response = call.execute(); if (!response.isSuccessful() || response.body() == null) { - return new Result(false, "接口调用失败"); + return new Result(false, "Remote interface call failed:" + response.body().string()); } String content = response.body().string(); return JsonUtil.parse(content, Result.class); } catch (Throwable e) { - return new Result(false, "接口调用失败:" + e.getMessage()); + return new Result(false, "Interface call failed:" + e.getMessage()); } } - - @Override - public Result register(RegisterInfo info) { - return invoke("/register", info); + private void getConfig() { + if (this.gatewayConfig == null) { + Result result = invoke("/getConfig", new HashMap<>()); + if (!result.isSuccess()) { + throw new BizException("get gateway config failed"); + } + this.gatewayConfig = JsonUtil.parse(result.getContent(), GatewayConfig.class); + } } @Override - public Result deregister(DeregisterInfo info) { - return invoke("/deregister", info); + public Result register(RegisterInfo info) { + return invokeJson("/register", info); } @Override @@ -87,12 +130,22 @@ public class DeviceBehaviourClient implements DeviceBehaviour { return invoke("/offline", data); } + @SneakyThrows @Override public void messageReport(DeviceMessage msg) { - + deviceMessageProducer.send(msg); } @Override public void otaProgressReport(OtaMessage msg) { } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class GatewayConfig { + + private String mqServiceUrl; + + } } diff --git a/protocol-gateway/gateway-server/.DS_Store b/protocol-gateway/gateway-server/.DS_Store new file mode 100755 index 0000000000000000000000000000000000000000..7a073db34a652072acd90eb46422e5a6bacc355e GIT binary patch literal 6148 zcmeHKyG{c^3>=dbC()!#xj#U`AFQJA1^EFAAPqVsNT{#kyZAK54Lp5PX|Mc0K_HJ zVO+;7L2RBN_QENV8JZ=Pm{h9~!;;Q?tGZq|B_(SMo$Pf6NI0V(jW6tLxXx83lSs<+Nw&U7la6h5avFf#>ui$JH?2TxnmDzDm7XyqsR`b$xira!cl!eic>D~wKO%FMi1 zplPf~bc0|taUmu~gBq!ct8UnssEIC&n%D&_bm8B|g+}ATm7Y6y+E_{#CPteuH<|n0 zIp>}`cfR|*dvoRi0Ji7NCIB4(6uJbmGOBJ-gkM}sN>OAfB}9q`;1Fad{PC>qW|#Di z4KV{T12F?J12F?J11o_6I<*Zg7}qfaF#}5(5V`v*2*3ajPTZ8g|DGMUEk9^%ypBc1C8euYE2>temaQu*JKBHJ zo#+pYAn&&uUWQfoTPDvM-jHPmCkMFGW%B}e4tfWSfO|(o=KY0 z8>dpq$=24!RB}gi%hZ&rDphseeaG_WF1~vC%3E*0^WjI51B~_&sF3#y^~cm&M2P9< z>@3Y*1T1pcexXBt=_opVE2i}BeLY%+tuN5K9vlxW*YOW=&nL{Va-TTapL3mFj|=}$ z&b9Mnj-O!_Im6E7Z6dDCw)?HK+#e43=|HqbeAf#)!j8ih#R^-7vAoawI0aY*-brCT zLv?1&#?4!6>KnGV?rob}yRMv7tk<*=;@1hRCoJv_PKbp%Z1_3un3i*5s9^b4*5(6_ zF~-@~su~7us?_!2eAYUZw}LaQMp5S2y7IMJwZ27Vv&yJR4|~it#ein$(W~{l73GMq zcX*s?Y1Z!1>r`ea13t}H4soBBQkky~JVi?_Lm$wZ6lSV}wvpwwH0{t@6!xe(RFI@e z<1THFQh_OTIOmRy(d+oq{E(hj*r&=d@$3VJ9~>O#4n1DHdV9659~SmD)8wY2kaX(h zYKL!IlWvrEDxE-8a6g?lJuphYgmE|n7vLgXg3E9P-iKNE06u}w;B)u_zJwd_Eqo6@ zz>n}V`~ttiZwRQOhGkfZNxTbduomyd?bwVvu?6>FCwAdJ?7_!z2#0Y5k6;dM9K&%u zg=g_uJde-e^Y{wBj_=}CoWb{S7O!C>)}nc_J|d?&U*i(7k|v|CZ$(FMrO8BB_rCv0 zlQ-5#A>OfJBC-7ee_|qu(bFog{ywFhw*?#2$1TQ>==7yEDk2k{VQ&>+c~$k8FudFW$+Q}{GKgXc(o z7w`qVgfHSt_%gnRZ{Srau?6AnpO>6OoFQDa85a6I$9A0)WS;UmH+%hKz#nk=YOcY+q?P;quKCH literal 0 HcmV?d00001 diff --git a/protocol-gateway/gateway-server/fun-test/pom.xml b/protocol-gateway/gateway-server/fun-test/pom.xml new file mode 100755 index 00000000..0e12c219 --- /dev/null +++ b/protocol-gateway/gateway-server/fun-test/pom.xml @@ -0,0 +1,71 @@ + + + + iotkit-parent + cc.iotkit + 0.0.1-SNAPSHOT + ../../../pom.xml + + 4.0.0 + + fun-test + + + + org.apache.pulsar + pulsar-functions-api + 2.6.0 + + + + cc.iotkit + common + + + + cc.iotkit + gateway-client + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.1.0 + + + + cc.iotkit.fun.TestFunction + + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + + \ No newline at end of file diff --git a/protocol-gateway/gateway-server/fun-test/src/main/java/cc/iotkit/fun/TestFunction.java b/protocol-gateway/gateway-server/fun-test/src/main/java/cc/iotkit/fun/TestFunction.java new file mode 100755 index 00000000..282853b2 --- /dev/null +++ b/protocol-gateway/gateway-server/fun-test/src/main/java/cc/iotkit/fun/TestFunction.java @@ -0,0 +1,50 @@ +package cc.iotkit.fun; + +import cc.iotkit.common.utils.JsonUtil; +import jdk.nashorn.api.scripting.NashornScriptEngine; +import org.apache.pulsar.functions.api.Context; +import org.apache.pulsar.functions.api.Function; + +import javax.script.Bindings; +import javax.script.CompiledScript; +import javax.script.ScriptEngineManager; +import javax.script.SimpleBindings; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +public class TestFunction implements Function { + + private static final NashornScriptEngine engine = (NashornScriptEngine) (new ScriptEngineManager()).getEngineByName("nashorn"); + private static final Map compiledScripts = new ConcurrentHashMap<>(); + + @Override + public byte[] process(byte[] bs, Context context) throws Exception { + Optional objPk = context.getUserConfigValue("pk"); + Optional objTrans = context.getUserConfigValue("transform"); + if (!objPk.isPresent() || !objTrans.isPresent()) { + return null; + } + String s = new String(bs); + String pk = objPk.get().toString(); + compiledScripts.putIfAbsent(pk, engine.compile(objTrans.get().toString())); + + CompiledScript script = compiledScripts.get(pk); + context.getLogger().debug(script.toString()); + + Map data = new HashMap<>(); + data.putIfAbsent("msg", s); + Bindings bindings = new SimpleBindings(data); + Object result = script.eval(bindings); + + if (result == null) { + context.getLogger().error("translate failed:" + s); + return null; + } + s = JsonUtil.toJsonString(result); + return s.getBytes(); + } + + +} diff --git a/protocol-gateway/gateway-server/pom.xml b/protocol-gateway/gateway-server/pom.xml old mode 100644 new mode 100755 index 46cf5cf6..ca42050c --- a/protocol-gateway/gateway-server/pom.xml +++ b/protocol-gateway/gateway-server/pom.xml @@ -18,14 +18,44 @@ + + org.springframework.boot + spring-boot-starter-web + + org.apache.pulsar - pulsar-client + pulsar-client-all + + + + org.springframework.boot + spring-boot-starter-data-elasticsearch cc.iotkit - gateway-api + gateway-client + + + + cc.iotkit + model + + + + cc.iotkit + dao + + + + org.projectlombok + lombok + + + + cc.iotkit + protocol-function diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/Application.java b/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/Application.java similarity index 64% rename from device-server/mqtt-server/src/main/java/cc/iotkit/server/Application.java rename to protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/Application.java index c774fd20..c154603c 100755 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/Application.java +++ b/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/Application.java @@ -1,11 +1,9 @@ -package cc.iotkit.server; +package cc.iotkit.protocol; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.client.discovery.EnableDiscoveryClient; -@EnableDiscoveryClient -@SpringBootApplication +@SpringBootApplication(scanBasePackages = {"cc.iotkit.protocol", "cc.iotkit.dao"}) public class Application { public static void main(String[] args) { diff --git a/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/Test1.java b/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/Test1.java old mode 100644 new mode 100755 index 9bb4eb98..08e2ebf3 --- a/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/Test1.java +++ b/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/Test1.java @@ -1,17 +1,27 @@ package cc.iotkit.protocol.server; +import cc.iotkit.protocol.DeviceMessage; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.SneakyThrows; +import org.apache.pulsar.client.admin.PulsarAdmin; +import org.apache.pulsar.client.admin.PulsarAdminException; import org.apache.pulsar.client.api.*; import org.apache.pulsar.client.impl.schema.JSONSchema; import org.apache.pulsar.common.functions.FunctionConfig; +import java.util.Set; import java.util.regex.Pattern; public class Test1 { - public static void main(String[] args) throws PulsarClientException, InterruptedException { + public static void main(String[] args) throws PulsarClientException, InterruptedException, PulsarAdminException { + +// PulsarAdmin admin = PulsarAdmin.builder() +// .serviceHttpUrl("http://localhost:8080") +// .build(); +// // FunctionConfig functionConfig = new FunctionConfig(); // functionConfig.setTenant("tenant"); // functionConfig.setNamespace("namespace"); @@ -20,34 +30,44 @@ public class Test1 { // functionConfig.setParallelism(1); // functionConfig.setClassName("org.apache.pulsar.functions.api.examples.ExclamationFunction"); // functionConfig.setProcessingGuarantees(FunctionConfig.ProcessingGuarantees.ATLEAST_ONCE); -// functionConfig.setTopicsPattern(sourceTopicPattern); -// functionConfig.setSubName(subscriptionName); +// functionConfig.setTopicsPattern("persistent://public/default/test.*"); +// functionConfig.setSubName("fun-test1"); // functionConfig.setAutoAck(true); -// functionConfig.setOutput(sinkTopic); -// admin.functions().createFunction(functionConfig, fileName); +// functionConfig.setOutput("persistent://public/default/fun_out"); +// admin.functions().createFunction(functionConfig, "/examples/api-examples.jar"); PulsarClient client = PulsarClient.builder() - .serviceUrl("pulsar://localhost:6650") + .serviceUrl("pulsar://192.168.0.112:6650") .build(); - client.newConsumer(JSONSchema.of(Msg.class)) - .topicsPattern(Pattern.compile("persistent://public/default/test.*")) + client.newConsumer(JSONSchema.of(DeviceMessage.class)) + .topicsPattern(Pattern.compile("persistent://public/default/device_raw")) .subscriptionName("test1") .consumerName("test1") - .messageListener((MessageListener) (consumer, msg) -> { - Msg m = msg.getValue(); - System.out.printf("=====received:%s,%s%n", m.getIdentifier(), m.getDeviceId()); + .messageListener((MessageListener) (consumer, msg) -> { + try { + DeviceMessage m = msg.getValue(); + System.out.printf("==============received:%s,%s%n", m.getMid(), m.getContent()); + consumer.acknowledge(msg); + } catch (Throwable e) { + e.printStackTrace(); + } }).subscribe(); - Producer producer = client.newProducer(JSONSchema.of(Msg.class)) - .topic("test1234") - .create(); - for (int i = 0; i < 1000; i++) { - producer.send(new Msg("test", "xxxx11222333" + i)); - Thread.sleep(500); - } +// for (int i = 0; i < 3; i++) { +// Producer producer = client.newProducer(JSONSchema.of(Msg.class)) +// .topic("test_" + i) +// .create(); +// for (int j = 0; j < 10; j++) { +// producer.newMessage() +// .value(new Msg("QQQQQ" + i, "id_test_" + i + "_" + j)) +// .property("aa", "1") +// .send(); +// } +// Thread.sleep(100); +// } } diff --git a/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/Test3.java b/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/Test3.java new file mode 100755 index 00000000..b1b7a766 --- /dev/null +++ b/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/Test3.java @@ -0,0 +1,40 @@ +package cc.iotkit.protocol.server; + +import cc.iotkit.common.utils.JsonUtil; +import jdk.nashorn.api.scripting.NashornScriptEngine; + +import javax.script.*; +import java.util.HashMap; +import java.util.Map; + +public class Test3 { + private static final NashornScriptEngine engine = (NashornScriptEngine) (new ScriptEngineManager()).getEngineByName("nashorn"); + + + public static void main(String[] args) throws ScriptException { + + Map data = new HashMap<>(); + data.putIfAbsent("msg", "aaa"); + CompiledScript script = engine.compile("a={data:msg+'===111',b:2}"); + Bindings bindings = new SimpleBindings(data); + Object result = script.eval(bindings); + System.out.println(JsonUtil.toJsonString(result)); + + script = engine.compile("new (function() {\n" + + " function add(n){\n" + + " return n+1;\n" + + " }\n" + + " this.decode = function(msg) {\n" + + " return \"=>decode:\"+add(msg);\n" + + " };\n" + + "})().decode(color)"); + + for (int i = 0; i < 100; i++) { + data.put("color", "black" + i); + bindings = new SimpleBindings(data); + result = script.eval(bindings); + System.out.println(result); + } + + } +} diff --git a/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/TestFunction.java b/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/TestFunction.java new file mode 100644 index 00000000..af8923aa --- /dev/null +++ b/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/TestFunction.java @@ -0,0 +1,88 @@ +package cc.iotkit.protocol.server; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.pulsar.client.admin.PulsarAdmin; +import org.apache.pulsar.client.admin.PulsarAdminException; +import org.apache.pulsar.client.api.MessageListener; +import org.apache.pulsar.client.api.PulsarClient; +import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.pulsar.client.impl.schema.JSONSchema; +import org.apache.pulsar.common.functions.FunctionConfig; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; + +public class TestFunction { + + public static void main(String[] args) throws PulsarClientException, InterruptedException, PulsarAdminException { + + PulsarAdmin admin = PulsarAdmin.builder() + .serviceHttpUrl("http://192.168.0.112:8080") + .build(); + + String gatewayName = "test3"; + String tenant = "public"; + String namespace = "default"; + String inputTopicsPattern = "device_raw"; + String fullInputTopic = String.format("persistent://%s/%s/%s", tenant, namespace, inputTopicsPattern); + String outputTopic = "device_thing"; + String transform = "new (function() {\n this.decode=function(msg){\n //对msg进行解析,并返回物模型数据\n var mqttMsg=JSON.parse(msg.content);\n var topic=mqttMsg.topic;\n var payload=mqttMsg.payload;\n\n if(topic.endWith(\"/property/post\")){\n //属性上报\n return {\n \"mid\":msg.mid,\n \"productKey\":msg.productKey, //可根据消息内容判断填写不同产品\n \"deviceName\":msg.deviceName,\n \"identifier\":\"propertyReport\", //属性上报\n \"occur\":new Date().getTime(), //时间戳,设备上的事件或数据产生的本地时间\n \"time\":new Date().getTime(), //时间戳,消息上报时间\n \"data\":payload.params\n }\n }else if(topic.indexOf(\"/event/\")>0){\n var identifier=topic.substring(topic.lastIndexOf(\"/\")+1);\n //事件上报\n return {\n \"mid\":msg.mid,\n \"productKey\":msg.productKey,\n \"deviceName\":msg.deviceName,\n \"identifier\":identifier,\n \"occur\":new Date().getTime(),\n \"time\":new Date().getTime(),\n \"data\":payload.params\n }\n }else if(topic.endWith(\"_reply\")){\n var identifier=topic.substring(topic.lastIndexOf(\"/\")+1);\n //服务回复\n return {\n \"mid\":msg.mid,\n \"productKey\":msg.productKey,\n \"deviceName\":msg.deviceName,\n \"identifier\":identifier.replace(\"_reply\",\"Reply\"),\n \"occur\":new Date().getTime(),\n \"time\":new Date().getTime(),\n \"code\":payload.code,\n \"data\":payload.data\n } \n }\n return null;\n }\n\n})().decode(msg)"; + String functionClass = "cc.iotkit.protocol.function.UplinkTranslateFunction"; + String jarFile = "/Users/sjg/home/gitee/open-source/iotkit-parent/protocol-gateway/protocol-function/target/protocol-function-0.0.1-SNAPSHOT-jar-with-dependencies.jar"; + + FunctionConfig functionConfig = new FunctionConfig(); + functionConfig.setTenant(tenant); + functionConfig.setNamespace(namespace); + functionConfig.setName("UplinkTranslateFunction_" + gatewayName); + functionConfig.setRuntime(FunctionConfig.Runtime.JAVA); + functionConfig.setParallelism(1); + functionConfig.setClassName(functionClass); + functionConfig.setProcessingGuarantees(FunctionConfig.ProcessingGuarantees.ATLEAST_ONCE); + functionConfig.setTopicsPattern(fullInputTopic); + functionConfig.setSubName(functionConfig.getName()); + functionConfig.setAutoAck(true); + functionConfig.setOutput(String.format("persistent://%s/%s/%s", tenant, namespace, outputTopic)); + Map userConfig = new HashMap<>(); + userConfig.put("script", transform); + functionConfig.setUserConfig(userConfig); + for (String function : admin.functions().getFunctions(tenant, namespace)) { + System.out.println(function); + if (function.contains("test")) { + admin.functions().deleteFunction(tenant, namespace, function); + } + } +// if (admin.functions().getFunction(tenant, namespace, functionConfig.getName()) != null) { +// admin.functions().updateFunction(functionConfig, jarFile); +// } else { +// admin.functions().createFunction(functionConfig, jarFile); +// } + +// admin.functions().stopFunction("public", "default", "fun_4", 0); +// admin.functions().startFunction("public", "default", "fun_4", 0); + +// +// PulsarClient client = PulsarClient.builder() +// .serviceUrl("pulsar://localhost:6650") +// .build(); +// +// client.newConsumer() +// .topicsPattern(Pattern.compile("persistent://public/default/fun_out.*")) +// .subscriptionName("test1") +// .consumerName("test-fun-1") +// .messageListener((MessageListener) (consumer, msg) -> { +// try { +// System.out.printf("==============received:%s\n", new String(msg.getValue())); +// consumer.acknowledge(msg); +// } catch (Throwable e) { +// e.printStackTrace(); +// } +// }).subscribe(); + + + } + + +} diff --git a/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/config/ServerConfig.java b/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/config/ServerConfig.java new file mode 100755 index 00000000..6a5a01d8 --- /dev/null +++ b/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/config/ServerConfig.java @@ -0,0 +1,17 @@ +package cc.iotkit.protocol.server.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +@Data +public class ServerConfig { + + @Value("${pulsar.broker}") + private String pulsarBrokerUrl; + + @Value("${pulsar.service}") + private String pulsarServiceUrl; + +} diff --git a/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/controller/DeviceBehaviourController.java b/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/controller/DeviceBehaviourController.java new file mode 100755 index 00000000..0724da7f --- /dev/null +++ b/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/controller/DeviceBehaviourController.java @@ -0,0 +1,60 @@ +package cc.iotkit.protocol.server.controller; + +import cc.iotkit.common.utils.JsonUtil; +import cc.iotkit.protocol.*; +import cc.iotkit.protocol.client.DeviceBehaviourClient; +import cc.iotkit.protocol.server.config.ServerConfig; +import cc.iotkit.protocol.server.service.DeviceBehaviourService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.*; + +@Slf4j +@RestController +@RequestMapping("/device_behaviour") +public class DeviceBehaviourController implements DeviceBehaviour { + + @Autowired + private ServerConfig serverConfig; + + @Autowired + private DeviceBehaviourService behaviourService; + + + @Override + @PostMapping("/register") + public Result register(@RequestBody RegisterInfo info) { + return behaviourService.register(info); + } + + @Override + @PostMapping("/online") + public Result online(String productKey, String deviceName) { + return behaviourService.deviceStateChange(productKey, deviceName, true); + } + + @Override + @PostMapping("/offline") + public Result offline(String productKey, String deviceName) { + return behaviourService.deviceStateChange(productKey, deviceName, false); + } + + @PostMapping("/getConfig") + public Result getConfig() { + return new Result(true, JsonUtil.toJsonString( + new DeviceBehaviourClient.GatewayConfig(serverConfig.getPulsarBrokerUrl()))); + } + + @Override + public void messageReport(DeviceMessage msg) { + throw new UnsupportedOperationException(); + } + + @Override + public void otaProgressReport(OtaMessage msg) { + throw new UnsupportedOperationException(); + } + + +} diff --git a/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/service/DeviceBehaviourService.java b/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/service/DeviceBehaviourService.java new file mode 100755 index 00000000..38d067c6 --- /dev/null +++ b/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/service/DeviceBehaviourService.java @@ -0,0 +1,142 @@ +package cc.iotkit.protocol.server.service; + +import cc.iotkit.common.exception.BizException; +import cc.iotkit.common.utils.JsonUtil; +import cc.iotkit.dao.DeviceRepository; +import cc.iotkit.dao.ProductRepository; +import cc.iotkit.model.device.DeviceInfo; +import cc.iotkit.model.product.Product; +import cc.iotkit.protocol.RegisterInfo; +import cc.iotkit.protocol.Result; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.RandomUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +@Slf4j +@Service +public class DeviceBehaviourService { + + @Autowired + private ProductRepository productRepository; + @Autowired + private DeviceRepository deviceRepository; + + + public Result register(RegisterInfo info) { + try { + DeviceInfo deviceInfo = register(null, info); + //子设备注册 + List subDevices = info.getSubDevices(); + if (subDevices != null && subDevices.size() != 0) { + for (RegisterInfo.SubDevice subDevice : subDevices) { + register(deviceInfo.getDeviceId(), + new RegisterInfo(subDevice.getProductKey(), + subDevice.getDeviceName(), + subDevice.getModel(), + subDevice.getTag(), null)); + } + } + //todo 产生设备注册事件 + } catch (BizException e) { + log.error("register device error", e); + return new Result(false, e.getMessage()); + } catch (Throwable e) { + log.error("register device error", e); + return new Result(false, "unknown error:" + e.getMessage()); + } + + return new Result(true, ""); + } + + public DeviceInfo register(String parentId, RegisterInfo info) { + String pk = info.getProductKey(); + Optional optProduct = productRepository.findById(pk); + if (!optProduct.isPresent()) { + throw new BizException("Product does not exist"); + } + String uid = optProduct.get().getUid(); + DeviceInfo device = deviceRepository.findByProductKeyAndDeviceName(pk, info.getDeviceName()); + + if (device != null) { + //更新设备信息 + device.setParentId(parentId); + device.setUid(uid); + Map tag = info.getTag(); + Map oldTag = device.getTag(); + + if (oldTag == null) { + oldTag = new HashMap<>(); + } + + if (tag != null) { + oldTag.putAll(tag); + } + + device.setTag(oldTag); + } else { + //不存在,注册新设备 + device = new DeviceInfo(); + device.setParentId(parentId); + device.setUid(uid); + device.setDeviceId(newDeviceId(info.getDeviceName())); + device.setProductKey(info.getProductKey()); + device.setDeviceName(info.getDeviceName()); + device.setTag(info.getTag()); + device.setState(new DeviceInfo.State(false, null, null)); + device.setCreateAt(System.currentTimeMillis()); + } + + deviceRepository.save(device); + log.info("device registered:{}", JsonUtil.toJsonString(device)); + + return device; + } + + /** + * 1-13位 时间戳 + * 14-29位 deviceNae,去除非字母和数字,不足16位补0,超过16位的mac取后16位,共16位 + * 30-31位 mac长度,共2位 + * 32位 随机一个0-f字符 + */ + public static String newDeviceId(String deviceNae) { + int maxDnLen = 16; + String dn = deviceNae.replaceAll("[^0-9A-Za-z]", ""); + if (dn.length() > maxDnLen) { + dn = dn.substring(dn.length() - maxDnLen); + } else { + dn = (dn + "00000000000000000000").substring(0, maxDnLen); + } + String len = StringUtils.leftPad(deviceNae.length() + "", 2, '0'); + String rnd = Integer.toHexString(RandomUtils.nextInt(0, 16)); + return (System.currentTimeMillis() + "0" + dn + len + rnd).toLowerCase(); + } + + public Result deviceStateChange(String productKey, + String deviceName, + boolean online) { + DeviceInfo device = deviceRepository.findByProductKeyAndDeviceName(productKey, deviceName); + if (device == null) { + return new Result(false, "device does not exist"); + } + + if (online) { + device.getState().setOnline(true); + device.getState().setOnlineTime(System.currentTimeMillis()); + } else { + device.getState().setOnline(false); + device.getState().setOfflineTime(System.currentTimeMillis()); + } + deviceRepository.save(device); + //todo 产生在离线事件 + + return new Result(true, ""); + } + +} diff --git a/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/service/DeviceMessageConsumer.java b/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/service/DeviceMessageConsumer.java new file mode 100755 index 00000000..a819a7a2 --- /dev/null +++ b/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/service/DeviceMessageConsumer.java @@ -0,0 +1,75 @@ +package cc.iotkit.protocol.server.service; + +import cc.iotkit.common.Constants; +import cc.iotkit.common.utils.JsonUtil; +import cc.iotkit.dao.ThingModelMessageRepository; +import cc.iotkit.dao.UserInfoRepository; +import cc.iotkit.model.UserInfo; +import cc.iotkit.model.device.message.ThingModelMessage; +import cc.iotkit.protocol.server.config.ServerConfig; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.pulsar.client.api.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@Service +public class DeviceMessageConsumer implements MessageListener { + + private final ServerConfig serverConfig; + + private final ThingModelMessageRepository messageRepository; + + private final UserInfoRepository userInfoRepository; + + @SneakyThrows + @Autowired + public DeviceMessageConsumer(ServerConfig serverConfig, + ThingModelMessageRepository messageRepository, + UserInfoRepository userInfoRepository) { + this.serverConfig = serverConfig; + this.messageRepository = messageRepository; + this.userInfoRepository = userInfoRepository; + + PulsarClient client = PulsarClient.builder() + .serviceUrl(this.serverConfig.getPulsarBrokerUrl()) + .build(); + + String topicFormat = "persistent://%s/default/" + Constants.THING_MODEL_MESSAGE_TOPIC; + List platformUsers = userInfoRepository.findByType(UserInfo.USER_TYPE_PLATFORM); + List topics = platformUsers.stream().map(u -> String.format(topicFormat, u.getUid())) + .collect(Collectors.toList()); + log.info("subscribe device_thing topic:{}", JsonUtil.toJsonString(topics)); + + client.newConsumer(Schema.JSON(ThingModelMessage.class)) + .topics(topics) + .subscriptionName("thing-model-message") + .consumerName("thing-model-message-consumer") + .messageListener(this).subscribe(); + } + + @SneakyThrows + @Override + public void received(Consumer consumer, Message msg) { + ThingModelMessage modelMessage = msg.getValue(); + log.info("receive message:{}", JsonUtil.toJsonString(modelMessage)); + //设备消息日志入库 + messageRepository.save(modelMessage); + + messageRepository.findAll().forEach(m -> { + log.info(JsonUtil.toJsonString(m)); + }); + + consumer.acknowledge(msg); + } + + @Override + public void reachedEndOfTopic(Consumer consumer) { + + } + +} diff --git a/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/service/GatewayService.java b/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/service/GatewayService.java new file mode 100644 index 00000000..544c3954 --- /dev/null +++ b/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/service/GatewayService.java @@ -0,0 +1,98 @@ +package cc.iotkit.protocol.server.service; + +import cc.iotkit.common.Constants; +import cc.iotkit.common.utils.JsonUtil; +import cc.iotkit.protocol.function.UplinkTranslateFunction; +import cc.iotkit.protocol.server.config.ServerConfig; +import lombok.extern.slf4j.Slf4j; +import org.apache.pulsar.client.admin.PulsarAdmin; +import org.apache.pulsar.client.admin.PulsarAdminException; +import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.pulsar.common.functions.FunctionConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@Service +public class GatewayService { + + private PulsarAdmin pulsarAdmin; + + @Autowired + private ServerConfig serverConfig; + + private PulsarAdmin getPulsarAdmin() throws PulsarClientException { + if (pulsarAdmin == null) { + pulsarAdmin = PulsarAdmin.builder() + .serviceHttpUrl(serverConfig.getPulsarServiceUrl()) + .build(); + } + return pulsarAdmin; + } + + public void saveFunction(String tenant, String gatewayId, String script, + String jarFile) throws PulsarClientException, PulsarAdminException { + saveFunction(tenant, gatewayId, "default", script, jarFile); + } + + public void saveFunction(String tenant, String gatewayId, + String namespace, String script, + String jarFile) throws PulsarClientException, PulsarAdminException { + PulsarAdmin pulsarAdmin = getPulsarAdmin(); + +// String gatewayName = ""; +// String tenant = "public"; +// String namespace = "default"; +// String inputTopicsPattern = ""; + String fullInputTopic = String.format("persistent://%s/%s/%s", + tenant, namespace, Constants.DEVICE_RAW_MESSAGE_TOPIC); +// String outputTopic = ""; +// String transform = ""; +// String functionClass = "cc.iotkit.protocol.function.UplinkTranslateFunction"; +// String jarFile = "/Users/sjg/home/gitee/open-source/iotkit-parent/protocol-gateway/gateway-server/fun-test/target/fun-test-0.0.1-SNAPSHOT-jar-with-dependencies.jar"; + + String functionClass = UplinkTranslateFunction.class.getName(); + String functionName = functionClass.substring(functionClass.lastIndexOf(".") + 1) + "_" + gatewayId; + + FunctionConfig functionConfig = new FunctionConfig(); + functionConfig.setTenant(tenant); + functionConfig.setNamespace(namespace); + functionConfig.setName(functionName); + functionConfig.setRuntime(FunctionConfig.Runtime.JAVA); + functionConfig.setParallelism(1); + functionConfig.setClassName(functionClass); + functionConfig.setProcessingGuarantees(FunctionConfig.ProcessingGuarantees.ATLEAST_ONCE); + functionConfig.setTopicsPattern(fullInputTopic); + functionConfig.setSubName(functionConfig.getName()); + functionConfig.setAutoAck(true); + functionConfig.setOutput(String.format("persistent://%s/%s/%s", tenant, + namespace, Constants.THING_MODEL_MESSAGE_TOPIC)); + log.info("creating function:{}", JsonUtil.toJsonString(functionConfig)); + + Map userConfig = new HashMap<>(); + userConfig.put("script", script); + userConfig.put("gateway", gatewayId); + functionConfig.setUserConfig(userConfig); + + if (pulsarAdmin.functions().getFunctions(tenant, namespace).contains(functionName)) { + pulsarAdmin.functions().updateFunction(functionConfig, jarFile); + } else { + pulsarAdmin.functions().createFunction(functionConfig, jarFile); + } + } + + public void deleteFunction(String tenant, String gatewayId) throws PulsarClientException, PulsarAdminException { + String namespace = "default"; + String functionClass = UplinkTranslateFunction.class.getName(); + String functionName = functionClass.substring(functionClass.lastIndexOf(".") + 1) + "_" + gatewayId; + PulsarAdmin pulsarAdmin = getPulsarAdmin(); + if (!pulsarAdmin.functions().getFunctions(tenant, namespace).contains(functionName)) { + log.warn("function does not found,delete success."); + return; + } + pulsarAdmin.functions().deleteFunction(tenant, namespace, functionName); + } +} diff --git a/device-server/mqtt-auth/src/main/resources/logback-spring.xml b/protocol-gateway/gateway-server/src/main/resources/logback-spring.xml similarity index 93% rename from device-server/mqtt-auth/src/main/resources/logback-spring.xml rename to protocol-gateway/gateway-server/src/main/resources/logback-spring.xml index 40a98cf0..6322c4b5 100755 --- a/device-server/mqtt-auth/src/main/resources/logback-spring.xml +++ b/protocol-gateway/gateway-server/src/main/resources/logback-spring.xml @@ -72,6 +72,12 @@ + + + + + + diff --git a/protocol-gateway/pom.xml b/protocol-gateway/pom.xml old mode 100644 new mode 100755 index e2ef3a51..23277303 --- a/protocol-gateway/pom.xml +++ b/protocol-gateway/pom.xml @@ -12,8 +12,10 @@ protocol-gateway pom - gateway-api + gateway-client gateway-server + gateway-server/fun-test + protocol-function diff --git a/device-server/mqtt-auth/.DS_Store b/protocol-gateway/protocol-function/.DS_Store old mode 100755 new mode 100644 similarity index 100% rename from device-server/mqtt-auth/.DS_Store rename to protocol-gateway/protocol-function/.DS_Store diff --git a/protocol-gateway/protocol-function/pom.xml b/protocol-gateway/protocol-function/pom.xml new file mode 100755 index 00000000..6968dbea --- /dev/null +++ b/protocol-gateway/protocol-function/pom.xml @@ -0,0 +1,70 @@ + + + + iotkit-parent + cc.iotkit + 0.0.1-SNAPSHOT + ../../pom.xml + + 4.0.0 + + protocol-function + + + + org.apache.pulsar + pulsar-functions-api + + + + org.projectlombok + lombok + + + + cc.iotkit + common + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.1.0 + + + + cc.iotkit.fun.TestFunction + + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + + \ No newline at end of file diff --git a/protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/DeviceMessage.java b/protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/DeviceMessage.java new file mode 100755 index 00000000..1066d03d --- /dev/null +++ b/protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/DeviceMessage.java @@ -0,0 +1,25 @@ +package cc.iotkit.protocol.function; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 设备消息 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class DeviceMessage { + + private String productKey; + + private String deviceName; + + private String mid; + + private String content; + +} diff --git a/protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/MessageDistributionFunction.java b/protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/MessageDistributionFunction.java new file mode 100755 index 00000000..eb6cd986 --- /dev/null +++ b/protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/MessageDistributionFunction.java @@ -0,0 +1,52 @@ +package cc.iotkit.protocol.function; + +import cc.iotkit.common.utils.JsonUtil; +import jdk.nashorn.api.scripting.NashornScriptEngine; +import org.apache.pulsar.functions.api.Context; +import org.apache.pulsar.functions.api.Function; + +import javax.script.Bindings; +import javax.script.CompiledScript; +import javax.script.ScriptEngineManager; +import javax.script.SimpleBindings; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 消息分发函数 + */ +public class MessageDistributionFunction implements Function { + + private static final NashornScriptEngine engine = (NashornScriptEngine) (new ScriptEngineManager()).getEngineByName("nashorn"); + private static final Map compiledScripts = new ConcurrentHashMap<>(); + + @Override + public ThingModelMessage process(ThingModelMessage msg, Context context) throws Exception { + Optional optName = context.getUserConfigValue("name"); + Optional optScript = context.getUserConfigValue("script"); + if (!optName.isPresent() || !optScript.isPresent()) { + return null; + } + + String name = optName.get().toString(); + compiledScripts.putIfAbsent(name, engine.compile(optScript.get().toString())); + + CompiledScript script = compiledScripts.get(name); + context.getLogger().debug(script.toString()); + + Map data = new HashMap<>(); + data.putIfAbsent("msg", msg); + Bindings bindings = new SimpleBindings(data); + Object result = script.eval(bindings); + + if (result == null) { + context.getLogger().error("translate msg failed:{}", JsonUtil.toJsonString(msg)); + return null; + } + return JsonUtil.parse(JsonUtil.toJsonString(result), ThingModelMessage.class); + } + + +} diff --git a/protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/ThingModelMessage.java b/protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/ThingModelMessage.java new file mode 100755 index 00000000..3904273b --- /dev/null +++ b/protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/ThingModelMessage.java @@ -0,0 +1,62 @@ +package cc.iotkit.protocol.function; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.HashMap; +import java.util.Map; + +/** + * 物模型消息 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ThingModelMessage { + + private String productKey; + + private String deviceName; + + private String mid; + + private String identifier; + + private Map data; + + /** + * 时间戳,设备上的事件或数据产生的本地时间 + */ + private Long occur; + + /** + * 消息上报时间 + */ + private Long time; + + public static ThingModelMessage from(Map map) { + ThingModelMessage message = new ThingModelMessage(); + message.setProductKey(getStr(map, "productKey")); + message.setDeviceName(getStr(map, "deviceName")); + message.setMid(getStr(map, "mid")); + message.setIdentifier(getStr(map, "identifier")); + Object data = map.get("data"); + if (data instanceof Map) { + message.setData((Map) data); + } else { + message.setData(new HashMap<>()); + } + return message; + } + + private static String getStr(Map map, String key) { + Object val = map.get(key); + if (val == null) { + return null; + } + return val.toString(); + } +} diff --git a/protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/UplinkTranslateFunction.java b/protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/UplinkTranslateFunction.java new file mode 100755 index 00000000..bcc087db --- /dev/null +++ b/protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/UplinkTranslateFunction.java @@ -0,0 +1,51 @@ +package cc.iotkit.protocol.function; + +import cc.iotkit.common.utils.JsonUtil; +import jdk.nashorn.api.scripting.NashornScriptEngine; +import org.apache.pulsar.functions.api.Context; +import org.apache.pulsar.functions.api.Function; + +import javax.script.*; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 上行消息转换函数 + */ +public class UplinkTranslateFunction implements Function { + + private static final NashornScriptEngine engine = (NashornScriptEngine) (new ScriptEngineManager()).getEngineByName("nashorn"); + private static final Map compiledScripts = new ConcurrentHashMap<>(); + + @Override + public ThingModelMessage process(DeviceMessage msg, Context context) throws Exception { + Optional optGateway = context.getUserConfigValue("gateway"); + Optional optScript = context.getUserConfigValue("script"); + if (!optGateway.isPresent() || !optScript.isPresent()) { + return null; + } + + String gateway = optGateway.get().toString(); + compiledScripts.putIfAbsent(gateway, engine.compile(optScript.get() + ".decode(msg)")); + + CompiledScript script = compiledScripts.get(gateway); + context.getLogger().debug(script.toString()); + + Map data = new HashMap<>(); + data.putIfAbsent("msg", msg); + Bindings bindings = new SimpleBindings(data); + Object result = script.eval(bindings); + + if (result == null) { + context.getLogger().error("translate msg failed:{}", JsonUtil.toJsonString(msg)); + return null; + } + if (result instanceof Map) { + return ThingModelMessage.from((Map) result); + } + return null; + } + +} diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceActionExecutor.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceActionExecutor.java index 65d29758..2e9f3c59 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceActionExecutor.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceActionExecutor.java @@ -1,7 +1,7 @@ package cc.iotkit.ruleengine.action; import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.dao.DeviceDao; +import cc.iotkit.dao.DeviceCache; import cc.iotkit.deviceapi.IDeviceService; import cc.iotkit.deviceapi.Service; import lombok.extern.slf4j.Slf4j; @@ -20,7 +20,7 @@ public class DeviceActionExecutor implements ActionExecutor { private IDeviceService deviceService; @Autowired - private DeviceDao deviceDao; + private DeviceCache deviceCache; @Override public String getName() { diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/filter/DeviceCondition.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/filter/DeviceCondition.java index b802f6f8..778d0d00 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/filter/DeviceCondition.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/filter/DeviceCondition.java @@ -1,6 +1,6 @@ package cc.iotkit.ruleengine.filter; -import cc.iotkit.dao.DeviceDao; +import cc.iotkit.dao.DeviceCache; import cc.iotkit.model.device.DeviceInfo; import cc.iotkit.ruleengine.expression.Expression; import lombok.Data; @@ -20,11 +20,11 @@ public class DeviceCondition { private String comparator; - private DeviceDao deviceDao; + private DeviceCache deviceCache; public boolean matches() { String[] pkDn = device.split("/"); - DeviceInfo deviceInfo = deviceDao.getByPkAndDn(pkDn[0], pkDn[1]); + DeviceInfo deviceInfo = deviceCache.findByProductKeyAndDeviceName(pkDn[0], pkDn[1]); Object left = null; if ("property".equals(type)) { Map properties = deviceInfo.getProperty(); diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/filter/DeviceFilter.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/filter/DeviceFilter.java index b1973126..02d68c24 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/filter/DeviceFilter.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/filter/DeviceFilter.java @@ -1,6 +1,6 @@ package cc.iotkit.ruleengine.filter; -import cc.iotkit.dao.DeviceDao; +import cc.iotkit.dao.DeviceCache; import lombok.Data; import java.util.List; @@ -14,7 +14,7 @@ public class DeviceFilter implements Filter { private List conditions; - private DeviceDao deviceDao; + private DeviceCache deviceCache; @Override public String getType() { @@ -24,7 +24,7 @@ public class DeviceFilter implements Filter { @Override public boolean execute() { for (DeviceCondition condition : getConditions()) { - condition.setDeviceDao(deviceDao); + condition.setDeviceCache(deviceCache); if (!condition.matches()) { return false; } diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/scene/SceneManager.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/scene/SceneManager.java index 3ae04242..cd4aaafc 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/scene/SceneManager.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/scene/SceneManager.java @@ -1,7 +1,7 @@ package cc.iotkit.ruleengine.scene; import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.dao.DeviceDao; +import cc.iotkit.dao.DeviceCache; import cc.iotkit.dao.SceneInfoRepository; import cc.iotkit.deviceapi.IDeviceService; import cc.iotkit.model.rule.RuleAction; @@ -43,7 +43,7 @@ public class SceneManager { private SceneInfoRepository sceneInfoRepository; @Autowired - private DeviceDao deviceDao; + private DeviceCache deviceCache; @Autowired private IDeviceService deviceService; @@ -156,7 +156,7 @@ public class SceneManager { private Filter parseFilter(String type, String config) { if (DeviceFilter.TYPE.equals(type)) { DeviceFilter filter = parse(config, DeviceFilter.class); - filter.setDeviceDao(deviceDao); + filter.setDeviceCache(deviceCache); return filter; } return null; diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/task/TaskManager.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/task/TaskManager.java index 910b30bf..a16767f6 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/task/TaskManager.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/task/TaskManager.java @@ -2,7 +2,7 @@ package cc.iotkit.ruleengine.task; import cc.iotkit.common.exception.BizException; import cc.iotkit.dao.TaskInfoRepository; -import cc.iotkit.dao.TaskLogDao; +import cc.iotkit.dao.TaskLogRepository; import cc.iotkit.model.rule.TaskInfo; import cc.iotkit.model.rule.TaskLog; import lombok.SneakyThrows; @@ -32,7 +32,7 @@ public class TaskManager implements ApplicationContextAware { private TaskInfoRepository taskInfoRepository; @Autowired - private TaskLogDao taskLogDao; + private TaskLogRepository taskLogRepository; public TaskManager() { ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); @@ -205,7 +205,7 @@ public class TaskManager implements ApplicationContextAware { } public void addLog(String taskId, boolean success, String content) { - taskLogDao.save(TaskLog.builder() + taskLogRepository.save(TaskLog.builder() .id(UUID.randomUUID().toString()) .taskId(taskId) .success(success) From 48b591cc67f21ac235608492a83c8b650489a528 Mon Sep 17 00:00:00 2001 From: xiwa Date: Mon, 21 Mar 2022 06:34:39 +0800 Subject: [PATCH 04/16] =?UTF-8?q?=E5=8D=8F=E8=AE=AE=E7=BD=91=E5=85=B3?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + communication/component/pom.xml | 16 --- communication/pom.xml | 15 -- log/error.2022-03-14.0.gz | Bin 4041 -> 0 bytes log/info.2022-03-14.0.gz | Bin 36764 -> 0 bytes manager/pom.xml | 3 +- .../java/cc/iotkit/manager/Application.java | 3 + pom.xml | 31 ++++- .../component}/pom.xml | 12 +- .../cc/iotkit/comp/AbstractComponent.java | 10 ++ .../main/java/cc/iotkit/comp/Component.java | 15 ++ .../java/cc/iotkit/comp/ComponentManager.java | 37 +++++ .../src/main/java/cc/iotkit/comp/Device.java | 7 + .../java/cc/iotkit/comp/MessageHandler.java | 61 ++++++++ .../cc/iotkit/comp/model/RegisterInfo.java | 49 +++++++ .../.DS_Store | Bin .../pom.xml | 0 .../protocol/function/DecodeFunction.java} | 2 +- .../protocol/function/DeviceMessage.java | 0 .../protocol/function/ThingModelMessage.java | 0 protocol-gateway/mqtt-component/pom.xml | 49 +++++++ .../cc/iotkit/comp/mqtt/MqttComponent.java | 52 +++++++ .../java/cc/iotkit/comp/mqtt/MqttConfig.java | 16 +++ .../cc/iotkit/comp/mqtt/MqttVerticle.java | 130 ++++++++++++++++++ protocol-gateway/pom.xml | 5 +- .../function/MessageDistributionFunction.java | 52 ------- .../.DS_Store | Bin .../fun-test/.DS_Store | Bin .../fun-test/pom.xml | 0 .../main/java/cc/iotkit/fun/TestFunction.java | 0 .../pom.xml | 2 +- .../java/cc/iotkit/protocol/Application.java | 0 .../java/cc/iotkit/protocol/server/Test1.java | 0 .../java/cc/iotkit/protocol/server/Test3.java | 0 .../iotkit/protocol/server/TestFunction.java | 0 .../protocol/server/config/ServerConfig.java | 0 .../controller/DeviceBehaviourController.java | 0 .../service/DeviceBehaviourService.java | 0 .../server/service/DeviceMessageConsumer.java | 0 .../server/service/GatewayService.java | 6 +- .../src/main/resources/logback-spring.xml | 0 .../src/main/resources/spring.factories | 0 42 files changed, 476 insertions(+), 98 deletions(-) delete mode 100644 communication/component/pom.xml delete mode 100644 communication/pom.xml delete mode 100755 log/error.2022-03-14.0.gz delete mode 100755 log/info.2022-03-14.0.gz rename {communication/mqtt-component => protocol-gateway/component}/pom.xml (63%) create mode 100644 protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java create mode 100644 protocol-gateway/component/src/main/java/cc/iotkit/comp/Component.java create mode 100644 protocol-gateway/component/src/main/java/cc/iotkit/comp/ComponentManager.java create mode 100644 protocol-gateway/component/src/main/java/cc/iotkit/comp/Device.java create mode 100644 protocol-gateway/component/src/main/java/cc/iotkit/comp/MessageHandler.java create mode 100755 protocol-gateway/component/src/main/java/cc/iotkit/comp/model/RegisterInfo.java rename protocol-gateway/{protocol-function => decode-function}/.DS_Store (100%) rename protocol-gateway/{protocol-function => decode-function}/pom.xml (100%) rename protocol-gateway/{protocol-function/src/main/java/cc/iotkit/protocol/function/UplinkTranslateFunction.java => decode-function/src/main/java/cc/iotkit/protocol/function/DecodeFunction.java} (94%) rename protocol-gateway/{protocol-function => decode-function}/src/main/java/cc/iotkit/protocol/function/DeviceMessage.java (100%) rename protocol-gateway/{protocol-function => decode-function}/src/main/java/cc/iotkit/protocol/function/ThingModelMessage.java (100%) create mode 100644 protocol-gateway/mqtt-component/pom.xml create mode 100644 protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttComponent.java create mode 100644 protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttConfig.java create mode 100644 protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttVerticle.java delete mode 100755 protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/MessageDistributionFunction.java rename protocol-gateway/{gateway-server => protocol-server}/.DS_Store (100%) rename protocol-gateway/{gateway-server => protocol-server}/fun-test/.DS_Store (100%) rename protocol-gateway/{gateway-server => protocol-server}/fun-test/pom.xml (100%) rename protocol-gateway/{gateway-server => protocol-server}/fun-test/src/main/java/cc/iotkit/fun/TestFunction.java (100%) rename protocol-gateway/{gateway-server => protocol-server}/pom.xml (97%) rename protocol-gateway/{gateway-server => protocol-server}/src/main/java/cc/iotkit/protocol/Application.java (100%) rename protocol-gateway/{gateway-server => protocol-server}/src/main/java/cc/iotkit/protocol/server/Test1.java (100%) rename protocol-gateway/{gateway-server => protocol-server}/src/main/java/cc/iotkit/protocol/server/Test3.java (100%) rename protocol-gateway/{gateway-server => protocol-server}/src/main/java/cc/iotkit/protocol/server/TestFunction.java (100%) rename protocol-gateway/{gateway-server => protocol-server}/src/main/java/cc/iotkit/protocol/server/config/ServerConfig.java (100%) rename protocol-gateway/{gateway-server => protocol-server}/src/main/java/cc/iotkit/protocol/server/controller/DeviceBehaviourController.java (100%) rename protocol-gateway/{gateway-server => protocol-server}/src/main/java/cc/iotkit/protocol/server/service/DeviceBehaviourService.java (100%) rename protocol-gateway/{gateway-server => protocol-server}/src/main/java/cc/iotkit/protocol/server/service/DeviceMessageConsumer.java (100%) rename protocol-gateway/{gateway-server => protocol-server}/src/main/java/cc/iotkit/protocol/server/service/GatewayService.java (95%) rename protocol-gateway/{gateway-server => protocol-server}/src/main/resources/logback-spring.xml (100%) rename protocol-gateway/{gateway-server => protocol-server}/src/main/resources/spring.factories (100%) diff --git a/.gitignore b/.gitignore index 668b97f4..8da0c3c1 100755 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ hs_err_pid* target *.iml *.yml +log diff --git a/communication/component/pom.xml b/communication/component/pom.xml deleted file mode 100644 index 02396859..00000000 --- a/communication/component/pom.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - iotkit-parent - cc.iotkit - 0.0.1-SNAPSHOT - ../../pom.xml - - 4.0.0 - - component - - - \ No newline at end of file diff --git a/communication/pom.xml b/communication/pom.xml deleted file mode 100644 index a25ff27e..00000000 --- a/communication/pom.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - iotkit-parent - cc.iotkit - 0.0.1-SNAPSHOT - - 4.0.0 - - communication - - - \ No newline at end of file diff --git a/log/error.2022-03-14.0.gz b/log/error.2022-03-14.0.gz deleted file mode 100755 index 395381df7f2a46e41fe5b384775bc534244ca24d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4041 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 a+Vh;*U*DnzJLu<5Sp!K)y%kQdvHk-W8<1fD diff --git a/log/info.2022-03-14.0.gz b/log/info.2022-03-14.0.gz deleted file mode 100755 index e1a670e8e3f8fbc5dc1385142ea56cf2ff78b055..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36764 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 diff --git a/manager/pom.xml b/manager/pom.xml index 7373bc2b..8268b1f2 100755 --- a/manager/pom.xml +++ b/manager/pom.xml @@ -12,6 +12,7 @@ manager + org.springframework.boot spring-boot-starter-data-mongodb @@ -145,7 +146,7 @@ cc.iotkit - gateway-server + protocol-server diff --git a/manager/src/main/java/cc/iotkit/manager/Application.java b/manager/src/main/java/cc/iotkit/manager/Application.java index 81e84f32..f296ebd0 100755 --- a/manager/src/main/java/cc/iotkit/manager/Application.java +++ b/manager/src/main/java/cc/iotkit/manager/Application.java @@ -1,9 +1,11 @@ package cc.iotkit.manager; +import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; +@Slf4j @EnableFeignClients(basePackages = {"cc.iotkit.deviceapi"}) @SpringBootApplication(scanBasePackages = {"cc.iotkit"}) public class Application { @@ -11,4 +13,5 @@ public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } + } diff --git a/pom.xml b/pom.xml index 930bf49d..36a9cd2d 100755 --- a/pom.xml +++ b/pom.xml @@ -12,9 +12,8 @@ dao tppa-server protocol-gateway - communication - communication/mqtt-component - communication/component + protocol-gateway/mqtt-component + protocol-gateway/component org.springframework.boot @@ -176,6 +175,24 @@ 2.6.0 + + io.vertx + vertx-core + 4.2.6 + + + + io.vertx + vertx-web + 4.2.6 + + + + io.vertx + vertx-mqtt + 4.2.6 + + cc.iotkit model @@ -220,7 +237,13 @@ cc.iotkit - gateway-server + protocol-server + ${project.version} + + + + cc.iotkit + component ${project.version} diff --git a/communication/mqtt-component/pom.xml b/protocol-gateway/component/pom.xml similarity index 63% rename from communication/mqtt-component/pom.xml rename to protocol-gateway/component/pom.xml index 565bb85a..03ab87dc 100644 --- a/communication/mqtt-component/pom.xml +++ b/protocol-gateway/component/pom.xml @@ -10,11 +10,19 @@ 4.0.0 - mqtt-component - + component + + org.projectlombok + lombok + + + + cc.iotkit + common + diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java new file mode 100644 index 00000000..56cc5d96 --- /dev/null +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java @@ -0,0 +1,10 @@ +package cc.iotkit.comp; + +import lombok.Data; + +@Data +public class AbstractComponent { + + protected MessageHandler messageHandler; + +} diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/Component.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/Component.java new file mode 100644 index 00000000..f5f45693 --- /dev/null +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/Component.java @@ -0,0 +1,15 @@ +package cc.iotkit.comp; + +public interface Component { + + void create(String config); + + void start(); + + void stop(); + + void destroy(); + + void setHandler(MessageHandler handler); + +} diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/ComponentManager.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/ComponentManager.java new file mode 100644 index 00000000..fed3f3b5 --- /dev/null +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/ComponentManager.java @@ -0,0 +1,37 @@ +package cc.iotkit.comp; + + +import java.util.HashMap; +import java.util.Map; + +public class ComponentManager { + + private final Map components = new HashMap<>(); + + public void register(String id, Component component) { + components.put(id, component); + } + + public void deRegister(String id) { + Component component = components.remove(id); + component.destroy(); + } + + public void start(String id, String script) { + Component component = components.get(id); + if (component == null) { + return; + } + component.setHandler(new MessageHandler(script)); + component.start(); + } + + public void stop(String id) { + Component component = components.get(id); + if (component == null) { + return; + } + component.stop(); + } + +} diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/Device.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/Device.java new file mode 100644 index 00000000..8c214b45 --- /dev/null +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/Device.java @@ -0,0 +1,7 @@ +package cc.iotkit.comp; + +import lombok.Data; + +@Data +public class Device { +} diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/MessageHandler.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/MessageHandler.java new file mode 100644 index 00000000..43de863a --- /dev/null +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/MessageHandler.java @@ -0,0 +1,61 @@ +package cc.iotkit.comp; + +import cc.iotkit.common.utils.JsonUtil; +import cc.iotkit.comp.model.RegisterInfo; +import jdk.nashorn.api.scripting.NashornScriptEngine; +import jdk.nashorn.api.scripting.ScriptObjectMirror; +import lombok.Data; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +import javax.script.ScriptEngineManager; +import java.util.Map; + +@Slf4j +@Data +public class MessageHandler { + private final NashornScriptEngine engine = (NashornScriptEngine) (new ScriptEngineManager()).getEngineByName("nashorn"); + + private final String script; + + @SneakyThrows + public MessageHandler(String script) { + this.script = script; + engine.eval(script); + } + + public void register(Map head, String msg) { + } + + public void auth(Map head, String msg) { + } + + public void state(Map head, String msg) { + } + + public void onReceive(Map head, String type, String msg) { + try { + ScriptObjectMirror obj = (ScriptObjectMirror) engine.invokeFunction("onReceive", head, type, msg); + Object rstType = obj.get("type"); + if (rstType == null) { + return; + } + Object data = obj.get("data"); + + if ("register".equals(rstType)) { + RegisterInfo regInfo = getData(data, RegisterInfo.class); + } else if ("report".equals(rstType)) { + + } + + } catch (Throwable e) { + log.error("onReceive error", e); + } + + } + + private T getData(Object data, Class cls) { + return JsonUtil.parse(JsonUtil.toJsonString(data), cls); + } + +} diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/RegisterInfo.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/RegisterInfo.java new file mode 100755 index 00000000..84357c91 --- /dev/null +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/RegisterInfo.java @@ -0,0 +1,49 @@ +package cc.iotkit.comp.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Map; + +/** + * 注册信息 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class RegisterInfo { + + private String productKey; + + private String deviceName; + + private String model; + + private Map tag; + + private List subDevices; + + public RegisterInfo(String productKey, String deviceName, String model) { + this.productKey = productKey; + this.deviceName = deviceName; + this.model = model; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class SubDevice { + + private String productKey; + + private String deviceName; + + private String model; + + private Map tag; + } +} diff --git a/protocol-gateway/protocol-function/.DS_Store b/protocol-gateway/decode-function/.DS_Store similarity index 100% rename from protocol-gateway/protocol-function/.DS_Store rename to protocol-gateway/decode-function/.DS_Store diff --git a/protocol-gateway/protocol-function/pom.xml b/protocol-gateway/decode-function/pom.xml similarity index 100% rename from protocol-gateway/protocol-function/pom.xml rename to protocol-gateway/decode-function/pom.xml diff --git a/protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/UplinkTranslateFunction.java b/protocol-gateway/decode-function/src/main/java/cc/iotkit/protocol/function/DecodeFunction.java similarity index 94% rename from protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/UplinkTranslateFunction.java rename to protocol-gateway/decode-function/src/main/java/cc/iotkit/protocol/function/DecodeFunction.java index bcc087db..dce944b0 100755 --- a/protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/UplinkTranslateFunction.java +++ b/protocol-gateway/decode-function/src/main/java/cc/iotkit/protocol/function/DecodeFunction.java @@ -14,7 +14,7 @@ import java.util.concurrent.ConcurrentHashMap; /** * 上行消息转换函数 */ -public class UplinkTranslateFunction implements Function { +public class DecodeFunction implements Function { private static final NashornScriptEngine engine = (NashornScriptEngine) (new ScriptEngineManager()).getEngineByName("nashorn"); private static final Map compiledScripts = new ConcurrentHashMap<>(); diff --git a/protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/DeviceMessage.java b/protocol-gateway/decode-function/src/main/java/cc/iotkit/protocol/function/DeviceMessage.java similarity index 100% rename from protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/DeviceMessage.java rename to protocol-gateway/decode-function/src/main/java/cc/iotkit/protocol/function/DeviceMessage.java diff --git a/protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/ThingModelMessage.java b/protocol-gateway/decode-function/src/main/java/cc/iotkit/protocol/function/ThingModelMessage.java similarity index 100% rename from protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/ThingModelMessage.java rename to protocol-gateway/decode-function/src/main/java/cc/iotkit/protocol/function/ThingModelMessage.java diff --git a/protocol-gateway/mqtt-component/pom.xml b/protocol-gateway/mqtt-component/pom.xml new file mode 100644 index 00000000..21e910b6 --- /dev/null +++ b/protocol-gateway/mqtt-component/pom.xml @@ -0,0 +1,49 @@ + + + + iotkit-parent + cc.iotkit + 0.0.1-SNAPSHOT + ../../pom.xml + + 4.0.0 + + mqtt-component + + + + + io.vertx + vertx-core + + + + io.vertx + vertx-mqtt + + + + org.projectlombok + lombok + + + + org.slf4j + slf4j-api + + + + cc.iotkit + common + + + + cc.iotkit + component + + + + + \ No newline at end of file diff --git a/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttComponent.java b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttComponent.java new file mode 100644 index 00000000..550194dd --- /dev/null +++ b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttComponent.java @@ -0,0 +1,52 @@ +package cc.iotkit.comp.mqtt; + +import cc.iotkit.common.exception.BizException; +import cc.iotkit.common.utils.JsonUtil; +import cc.iotkit.comp.AbstractComponent; +import io.vertx.core.Future; +import io.vertx.core.Vertx; +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.CountDownLatch; + +@Slf4j +public class MqttComponent extends AbstractComponent { + + private Vertx vertx; + private final CountDownLatch countDownLatch = new CountDownLatch(1); + private String deployedId; + private MqttConfig mqttConfig; + + public void create(String config) { + vertx = Vertx.vertx(); + mqttConfig = JsonUtil.parse(config, MqttConfig.class); + } + + public void start() { + try { + Future future = vertx.deployVerticle(new MqttVerticle(mqttConfig, getMessageHandler())); + future.onSuccess((s -> { + deployedId = s; + countDownLatch.countDown(); + })); + future.onFailure((e) -> { + countDownLatch.countDown(); + log.error("start mqtt component failed", e); + }); + countDownLatch.await(); + future.succeeded(); + } catch (Throwable e) { + throw new BizException("start mqtt component error", e); + } + } + + public void stop() { + Future future = vertx.undeploy(deployedId); + future.onSuccess(unused -> log.info("stop mqtt component success")); + } + + public void destroy() { + vertx.close(); + } + +} diff --git a/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttConfig.java b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttConfig.java new file mode 100644 index 00000000..84edb733 --- /dev/null +++ b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttConfig.java @@ -0,0 +1,16 @@ +package cc.iotkit.comp.mqtt; + +import lombok.Data; + +@Data +public class MqttConfig { + + private int port; + + private String sslKey; + + private String sslCert; + + private boolean ssl; + +} diff --git a/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttVerticle.java b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttVerticle.java new file mode 100644 index 00000000..bada79d3 --- /dev/null +++ b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttVerticle.java @@ -0,0 +1,130 @@ +package cc.iotkit.comp.mqtt; + +import cc.iotkit.comp.MessageHandler; +import io.netty.handler.codec.mqtt.MqttConnectReturnCode; +import io.netty.handler.codec.mqtt.MqttProperties; +import io.netty.handler.codec.mqtt.MqttQoS; +import io.vertx.core.AbstractVerticle; +import io.vertx.core.net.PemKeyCertOptions; +import io.vertx.mqtt.MqttAuth; +import io.vertx.mqtt.MqttServer; +import io.vertx.mqtt.MqttServerOptions; +import io.vertx.mqtt.MqttTopicSubscription; +import io.vertx.mqtt.messages.codes.MqttSubAckReasonCode; +import lombok.extern.slf4j.Slf4j; + +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Slf4j +public class MqttVerticle extends AbstractVerticle { + + private MqttServer mqttServer; + + private final MqttConfig config; + + private final MessageHandler executor; + + public MqttVerticle(MqttConfig config, MessageHandler executor) { + this.config = config; + this.executor = executor; + } + + @Override + public void start() throws Exception { + MqttServerOptions options = new MqttServerOptions() + .setPort(config.getPort()); + if (config.isSsl()) { + options = options.setSsl(true) + .setKeyCertOptions(new PemKeyCertOptions() + .setKeyPath(config.getSslKey()) + .setCertPath(config.getSslCert())); + } + + mqttServer = MqttServer.create(vertx, options); + mqttServer.endpointHandler(endpoint -> { + log.info("MQTT client:{} request to connect, clean session = {}", endpoint.clientIdentifier(), endpoint.isCleanSession()); + + MqttAuth auth = endpoint.auth(); + if (auth == null) { + return; + } + + String authJson = auth.toJson() + .put("clientid", endpoint.clientIdentifier()).toString(); + + log.info("MQTT client auth,username:{},password:{}", auth.getUsername(), auth.getPassword()); + try { + executor.onReceive(new HashMap<>(), "auth", authJson); + } catch (Throwable e) { + log.error("auth failed", e); + endpoint.reject(MqttConnectReturnCode.CONNECTION_REFUSED_NOT_AUTHORIZED); + } + + log.info("MQTT client keep alive timeout = {} ", endpoint.keepAliveTimeSeconds()); + + endpoint.accept(false); + endpoint.disconnectMessageHandler(disconnectMessage -> { + log.info("Received disconnect from client, reason code = {}", disconnectMessage.code()); + executor.onReceive(new HashMap<>(), "disconnect", authJson); + }).subscribeHandler(subscribe -> { + List reasonCodes = new ArrayList<>(); + for (MqttTopicSubscription s : subscribe.topicSubscriptions()) { + log.info("Subscription for {},with QoS {}", s.topicName(), s.qualityOfService()); + try { + executor.onReceive(new HashMap<>(), "subscribe", s.topicName()); + reasonCodes.add(MqttSubAckReasonCode.qosGranted(s.qualityOfService())); + } catch (Throwable e) { + log.error("subscribe failed,topic:" + s.topicName(), e); + reasonCodes.add(MqttSubAckReasonCode.NOT_AUTHORIZED); + } + } + // ack the subscriptions request + endpoint.subscribeAcknowledge(subscribe.messageId(), reasonCodes, MqttProperties.NO_PROPERTIES); + + }).unsubscribeHandler(unsubscribe -> { + for (String t : unsubscribe.topics()) { + log.info("Unsubscription for {}", t); + try { + executor.onReceive(new HashMap<>(), "unsubscribe", t); + } catch (Throwable e) { + log.error("unsubscribe failed,topic:" + t, e); + } + } + // ack the subscriptions request + endpoint.unsubscribeAcknowledge(unsubscribe.messageId()); + }).publishHandler(message -> { + String payload = message.payload().toString(Charset.defaultCharset()); + log.info("Received message:{}, with QoS {}", payload, + message.qosLevel()); + try { + Map head = new HashMap<>(); + head.put("topic", message.topicName()); + executor.onReceive(head, "", payload); + } catch (Throwable e) { + log.error("handler message failed,topic:" + message.topicName(), e); + } + + if (message.qosLevel() == MqttQoS.AT_LEAST_ONCE) { + endpoint.publishAcknowledge(message.messageId()); + } else if (message.qosLevel() == MqttQoS.EXACTLY_ONCE) { + endpoint.publishReceived(message.messageId()); + } + }).publishReleaseHandler(endpoint::publishComplete); + }).listen(ar -> { + if (ar.succeeded()) { + log.info("MQTT server is listening on port " + ar.result().actualPort()); + } else { + log.error("Error on starting the server", ar.cause()); + } + }); + } + + @Override + public void stop() throws Exception { + mqttServer.close(voidAsyncResult -> log.info("close mqtt server...")); + } +} diff --git a/protocol-gateway/pom.xml b/protocol-gateway/pom.xml index 23277303..3e9bf227 100755 --- a/protocol-gateway/pom.xml +++ b/protocol-gateway/pom.xml @@ -13,9 +13,8 @@ pom gateway-client - gateway-server - gateway-server/fun-test - protocol-function + protocol-server + decode-function diff --git a/protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/MessageDistributionFunction.java b/protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/MessageDistributionFunction.java deleted file mode 100755 index eb6cd986..00000000 --- a/protocol-gateway/protocol-function/src/main/java/cc/iotkit/protocol/function/MessageDistributionFunction.java +++ /dev/null @@ -1,52 +0,0 @@ -package cc.iotkit.protocol.function; - -import cc.iotkit.common.utils.JsonUtil; -import jdk.nashorn.api.scripting.NashornScriptEngine; -import org.apache.pulsar.functions.api.Context; -import org.apache.pulsar.functions.api.Function; - -import javax.script.Bindings; -import javax.script.CompiledScript; -import javax.script.ScriptEngineManager; -import javax.script.SimpleBindings; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; - -/** - * 消息分发函数 - */ -public class MessageDistributionFunction implements Function { - - private static final NashornScriptEngine engine = (NashornScriptEngine) (new ScriptEngineManager()).getEngineByName("nashorn"); - private static final Map compiledScripts = new ConcurrentHashMap<>(); - - @Override - public ThingModelMessage process(ThingModelMessage msg, Context context) throws Exception { - Optional optName = context.getUserConfigValue("name"); - Optional optScript = context.getUserConfigValue("script"); - if (!optName.isPresent() || !optScript.isPresent()) { - return null; - } - - String name = optName.get().toString(); - compiledScripts.putIfAbsent(name, engine.compile(optScript.get().toString())); - - CompiledScript script = compiledScripts.get(name); - context.getLogger().debug(script.toString()); - - Map data = new HashMap<>(); - data.putIfAbsent("msg", msg); - Bindings bindings = new SimpleBindings(data); - Object result = script.eval(bindings); - - if (result == null) { - context.getLogger().error("translate msg failed:{}", JsonUtil.toJsonString(msg)); - return null; - } - return JsonUtil.parse(JsonUtil.toJsonString(result), ThingModelMessage.class); - } - - -} diff --git a/protocol-gateway/gateway-server/.DS_Store b/protocol-gateway/protocol-server/.DS_Store similarity index 100% rename from protocol-gateway/gateway-server/.DS_Store rename to protocol-gateway/protocol-server/.DS_Store diff --git a/protocol-gateway/gateway-server/fun-test/.DS_Store b/protocol-gateway/protocol-server/fun-test/.DS_Store similarity index 100% rename from protocol-gateway/gateway-server/fun-test/.DS_Store rename to protocol-gateway/protocol-server/fun-test/.DS_Store diff --git a/protocol-gateway/gateway-server/fun-test/pom.xml b/protocol-gateway/protocol-server/fun-test/pom.xml similarity index 100% rename from protocol-gateway/gateway-server/fun-test/pom.xml rename to protocol-gateway/protocol-server/fun-test/pom.xml diff --git a/protocol-gateway/gateway-server/fun-test/src/main/java/cc/iotkit/fun/TestFunction.java b/protocol-gateway/protocol-server/fun-test/src/main/java/cc/iotkit/fun/TestFunction.java similarity index 100% rename from protocol-gateway/gateway-server/fun-test/src/main/java/cc/iotkit/fun/TestFunction.java rename to protocol-gateway/protocol-server/fun-test/src/main/java/cc/iotkit/fun/TestFunction.java diff --git a/protocol-gateway/gateway-server/pom.xml b/protocol-gateway/protocol-server/pom.xml similarity index 97% rename from protocol-gateway/gateway-server/pom.xml rename to protocol-gateway/protocol-server/pom.xml index ca42050c..ce0c779f 100755 --- a/protocol-gateway/gateway-server/pom.xml +++ b/protocol-gateway/protocol-server/pom.xml @@ -9,7 +9,7 @@ 4.0.0 - gateway-server + protocol-server 8 diff --git a/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/Application.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/Application.java similarity index 100% rename from protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/Application.java rename to protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/Application.java diff --git a/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/Test1.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/Test1.java similarity index 100% rename from protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/Test1.java rename to protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/Test1.java diff --git a/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/Test3.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/Test3.java similarity index 100% rename from protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/Test3.java rename to protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/Test3.java diff --git a/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/TestFunction.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/TestFunction.java similarity index 100% rename from protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/TestFunction.java rename to protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/TestFunction.java diff --git a/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/config/ServerConfig.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/config/ServerConfig.java similarity index 100% rename from protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/config/ServerConfig.java rename to protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/config/ServerConfig.java diff --git a/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/controller/DeviceBehaviourController.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/controller/DeviceBehaviourController.java similarity index 100% rename from protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/controller/DeviceBehaviourController.java rename to protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/controller/DeviceBehaviourController.java diff --git a/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/service/DeviceBehaviourService.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/DeviceBehaviourService.java similarity index 100% rename from protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/service/DeviceBehaviourService.java rename to protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/DeviceBehaviourService.java diff --git a/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/service/DeviceMessageConsumer.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/DeviceMessageConsumer.java similarity index 100% rename from protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/service/DeviceMessageConsumer.java rename to protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/DeviceMessageConsumer.java diff --git a/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/service/GatewayService.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/GatewayService.java similarity index 95% rename from protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/service/GatewayService.java rename to protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/GatewayService.java index 544c3954..90d6cd7e 100644 --- a/protocol-gateway/gateway-server/src/main/java/cc/iotkit/protocol/server/service/GatewayService.java +++ b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/GatewayService.java @@ -2,7 +2,7 @@ package cc.iotkit.protocol.server.service; import cc.iotkit.common.Constants; import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.protocol.function.UplinkTranslateFunction; +import cc.iotkit.protocol.function.DecodeFunction; import cc.iotkit.protocol.server.config.ServerConfig; import lombok.extern.slf4j.Slf4j; import org.apache.pulsar.client.admin.PulsarAdmin; @@ -54,7 +54,7 @@ public class GatewayService { // String functionClass = "cc.iotkit.protocol.function.UplinkTranslateFunction"; // String jarFile = "/Users/sjg/home/gitee/open-source/iotkit-parent/protocol-gateway/gateway-server/fun-test/target/fun-test-0.0.1-SNAPSHOT-jar-with-dependencies.jar"; - String functionClass = UplinkTranslateFunction.class.getName(); + String functionClass = DecodeFunction.class.getName(); String functionName = functionClass.substring(functionClass.lastIndexOf(".") + 1) + "_" + gatewayId; FunctionConfig functionConfig = new FunctionConfig(); @@ -86,7 +86,7 @@ public class GatewayService { public void deleteFunction(String tenant, String gatewayId) throws PulsarClientException, PulsarAdminException { String namespace = "default"; - String functionClass = UplinkTranslateFunction.class.getName(); + String functionClass = DecodeFunction.class.getName(); String functionName = functionClass.substring(functionClass.lastIndexOf(".") + 1) + "_" + gatewayId; PulsarAdmin pulsarAdmin = getPulsarAdmin(); if (!pulsarAdmin.functions().getFunctions(tenant, namespace).contains(functionName)) { diff --git a/protocol-gateway/gateway-server/src/main/resources/logback-spring.xml b/protocol-gateway/protocol-server/src/main/resources/logback-spring.xml similarity index 100% rename from protocol-gateway/gateway-server/src/main/resources/logback-spring.xml rename to protocol-gateway/protocol-server/src/main/resources/logback-spring.xml diff --git a/protocol-gateway/gateway-server/src/main/resources/spring.factories b/protocol-gateway/protocol-server/src/main/resources/spring.factories similarity index 100% rename from protocol-gateway/gateway-server/src/main/resources/spring.factories rename to protocol-gateway/protocol-server/src/main/resources/spring.factories From e4cb721d0e3700aee54c97f4b4b30f8a924ec29b Mon Sep 17 00:00:00 2001 From: xiwa Date: Mon, 21 Mar 2022 19:01:24 +0800 Subject: [PATCH 05/16] =?UTF-8?q?=E6=A8=A1=E5=9D=97=E5=90=8D=E8=B0=83?= =?UTF-8?q?=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dao/ThingModelMessageRepository.java | 0 .../config/ElasticsearchConfiguration.java | 0 log/error.2022-03-15.0.gz | Bin 20999 -> 0 bytes log/error.2022-03-16.0.gz | Bin 7595 -> 0 bytes log/error.2022-03-16.01767963764004696.tmp | 900 --------------- log/error.2022-03-17.0.gz | Bin 20450 -> 0 bytes log/error.2022-03-18.0.gz | Bin 14387 -> 0 bytes log/info.2022-03-15.0.gz | Bin 43469 -> 0 bytes log/info.2022-03-16.0.gz | Bin 44742 -> 0 bytes log/info.2022-03-16.01767904371465962.tmp | 1019 ----------------- log/info.2022-03-17.0.gz | Bin 107296 -> 0 bytes log/info.2022-03-18.0.gz | Bin 93228 -> 0 bytes .../controller/ProtocolController.java | 0 .../manager/service/PulsarAdminService.java | 0 .../model/protocol/ProtocolGateway.java | 0 pom.xml | 2 +- protocol-gateway/component/pom.xml | 0 .../cc/iotkit/comp/AbstractComponent.java | 0 .../main/java/cc/iotkit/comp/Component.java | 0 .../java/cc/iotkit/comp/ComponentManager.java | 0 .../src/main/java/cc/iotkit/comp/Device.java | 0 .../java/cc/iotkit/comp/MessageHandler.java | 0 protocol-gateway/decode-function/.DS_Store | Bin protocol-gateway/decode-function/pom.xml | 2 +- protocol-gateway/mqtt-component/pom.xml | 0 .../cc/iotkit/comp/mqtt/MqttComponent.java | 0 .../java/cc/iotkit/comp/mqtt/MqttConfig.java | 0 .../cc/iotkit/comp/mqtt/MqttVerticle.java | 0 protocol-gateway/protocol-server/pom.xml | 2 +- .../iotkit/protocol/server/TestFunction.java | 0 .../server/service/GatewayService.java | 0 31 files changed, 3 insertions(+), 1922 deletions(-) mode change 100644 => 100755 dao/src/main/java/cc/iotkit/dao/ThingModelMessageRepository.java mode change 100644 => 100755 dao/src/main/java/cc/iotkit/dao/config/ElasticsearchConfiguration.java delete mode 100644 log/error.2022-03-15.0.gz delete mode 100644 log/error.2022-03-16.0.gz delete mode 100644 log/error.2022-03-16.01767963764004696.tmp delete mode 100644 log/error.2022-03-17.0.gz delete mode 100644 log/error.2022-03-18.0.gz delete mode 100644 log/info.2022-03-15.0.gz delete mode 100644 log/info.2022-03-16.0.gz delete mode 100644 log/info.2022-03-16.01767904371465962.tmp delete mode 100644 log/info.2022-03-17.0.gz delete mode 100644 log/info.2022-03-18.0.gz mode change 100644 => 100755 manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java mode change 100644 => 100755 manager/src/main/java/cc/iotkit/manager/service/PulsarAdminService.java mode change 100644 => 100755 model/src/main/java/cc/iotkit/model/protocol/ProtocolGateway.java mode change 100644 => 100755 protocol-gateway/component/pom.xml mode change 100644 => 100755 protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java mode change 100644 => 100755 protocol-gateway/component/src/main/java/cc/iotkit/comp/Component.java mode change 100644 => 100755 protocol-gateway/component/src/main/java/cc/iotkit/comp/ComponentManager.java mode change 100644 => 100755 protocol-gateway/component/src/main/java/cc/iotkit/comp/Device.java mode change 100644 => 100755 protocol-gateway/component/src/main/java/cc/iotkit/comp/MessageHandler.java mode change 100644 => 100755 protocol-gateway/decode-function/.DS_Store mode change 100644 => 100755 protocol-gateway/mqtt-component/pom.xml mode change 100644 => 100755 protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttComponent.java mode change 100644 => 100755 protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttConfig.java mode change 100644 => 100755 protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttVerticle.java mode change 100644 => 100755 protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/TestFunction.java mode change 100644 => 100755 protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/GatewayService.java diff --git a/dao/src/main/java/cc/iotkit/dao/ThingModelMessageRepository.java b/dao/src/main/java/cc/iotkit/dao/ThingModelMessageRepository.java old mode 100644 new mode 100755 diff --git a/dao/src/main/java/cc/iotkit/dao/config/ElasticsearchConfiguration.java b/dao/src/main/java/cc/iotkit/dao/config/ElasticsearchConfiguration.java old mode 100644 new mode 100755 diff --git a/log/error.2022-03-15.0.gz b/log/error.2022-03-15.0.gz deleted file mode 100644 index b307f51a54733e2883ab52e5b7d9d5b2e59b4025..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20999 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 diff --git a/log/error.2022-03-16.0.gz b/log/error.2022-03-16.0.gz deleted file mode 100644 index d5f2d074e9b9013294d288a382b77de2e23b1c6f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7595 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 diff --git a/log/error.2022-03-18.0.gz b/log/error.2022-03-18.0.gz deleted file mode 100644 index ae23775520f0d58c589998acb988de7da048fdcc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14387 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 AE&u=k diff --git a/log/info.2022-03-15.0.gz b/log/info.2022-03-15.0.gz deleted file mode 100644 index 7053b26e66e542029b948005ce8d2d076718420b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43469 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 DKWz5Y diff --git a/log/info.2022-03-16.0.gz b/log/info.2022-03-16.0.gz deleted file mode 100644 index f93541e9a69ce1f54311833f079fd2ee2f847ee7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44742 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 diff --git a/log/info.2022-03-16.01767904371465962.tmp b/log/info.2022-03-16.01767904371465962.tmp deleted file mode 100644 index d5c5f3f7..00000000 --- a/log/info.2022-03-16.01767904371465962.tmp +++ /dev/null @@ -1,1019 +0,0 @@ -2022-03-17 00:22:07.709 INFO 35086 --- [nio-8086-exec-3] o.keycloak.adapters.KeycloakDeployment : Loaded URLs from https://auth.iotkit.cc/realms/iotkit/.well-known/openid-configuration -2022-03-17 00:22:08.815 INFO 35086 --- [nio-8086-exec-3] org.mongodb.driver.connection : Opened connection [connectionId{localValue:5, serverValue:5942935}] to dds-wz9rfynv908bptqw-pub.mongodb.rds.aliyuncs.com:3717 -2022-03-17 00:22:10.444 ERROR 35086 --- [nio-8086-exec-3] c.i.m.config.GlobalExceptionHandler : handler exception - -cc.iotkit.common.exception.BizException: add protocol gateway error - at cc.iotkit.manager.controller.ProtocolController.addGateway(ProtocolController.java:38) - at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.lang.reflect.Method.invoke(Method.java:498) - at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) - at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) - at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) - at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) - at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067) - at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) - at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) - at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) - at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter.doFilter(KeycloakAuthenticatedActionsFilter.java:57) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter.doFilter(KeycloakSecurityContextRequestFilter.java:61) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:96) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter.successfulAuthentication(KeycloakAuthenticationProcessingFilter.java:214) - at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:233) - at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:327) - at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115) - at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122) - at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126) - at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter.doFilter(KeycloakAuthenticatedActionsFilter.java:74) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter.doFilter(KeycloakSecurityContextRequestFilter.java:92) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103) - at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter.successfulAuthentication(KeycloakAuthenticationProcessingFilter.java:214) - at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:233) - at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:96) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) - at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110) - at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211) - at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183) - at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354) - at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) - at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) - at org.keycloak.adapters.tomcat.AbstractAuthenticatedActionsValve.invoke(AbstractAuthenticatedActionsValve.java:67) - at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540) - at org.keycloak.adapters.tomcat.AbstractKeycloakAuthenticatorValve.invoke(AbstractKeycloakAuthenticatorValve.java:181) - at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) - at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) - at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) - at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) - at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382) - at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) - at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895) - at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732) - at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) - at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) - at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) - at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) - at java.lang.Thread.run(Thread.java:748) -Caused by: org.apache.pulsar.client.admin.PulsarAdminException: java.lang.IllegalArgumentException: The URI scheme, of the URI pulsar://192.168.0.112:6650/admin/v3/functions/public/iot/.UplinkTranslateFunction_mqtt-gateway, must be equal (ignoring case) to 'http', 'https', 'ws', or 'wss' - at org.apache.pulsar.client.admin.internal.BaseResource.getApiException(BaseResource.java:247) - at org.apache.pulsar.client.admin.internal.FunctionsImpl$2.failed(FunctionsImpl.java:154) - at org.apache.pulsar.shade.org.glassfish.jersey.client.JerseyInvocation$1.failed(JerseyInvocation.java:882) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.processFailure(ClientRuntime.java:247) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.processFailure(ClientRuntime.java:242) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.lambda$null$6(ClientRuntime.java:184) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors$1.call(Errors.java:248) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors$1.call(Errors.java:244) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:292) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:274) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:244) - at org.apache.pulsar.shade.org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:288) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.lambda$createRunnableForAsyncProcessing$7(ClientRuntime.java:156) - at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) - at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) - at java.util.concurrent.FutureTask.run(FutureTask.java) - at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) - at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) - ... 1 common frames omitted -Caused by: java.lang.IllegalArgumentException: The URI scheme, of the URI pulsar://192.168.0.112:6650/admin/v3/functions/public/iot/.UplinkTranslateFunction_mqtt-gateway, must be equal (ignoring case) to 'http', 'https', 'ws', or 'wss' - at org.apache.pulsar.shade.org.asynchttpclient.uri.Uri.validateSupportedScheme(Uri.java:289) - at org.apache.pulsar.shade.org.asynchttpclient.RequestBuilderBase.computeUri(RequestBuilderBase.java:605) - at org.apache.pulsar.shade.org.asynchttpclient.RequestBuilderBase.build(RequestBuilderBase.java:614) - at org.apache.pulsar.shade.org.asynchttpclient.BoundRequestBuilder.execute(BoundRequestBuilder.java:39) - at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.oneShot(AsyncHttpConnector.java:316) - at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$retryOrTimeOut$2(AsyncHttpConnector.java:236) - at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.retryOperation(AsyncHttpConnector.java:248) - at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.retryOrTimeOut(AsyncHttpConnector.java:236) - at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.apply(AsyncHttpConnector.java:201) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.lambda$null$6(ClientRuntime.java:182) - ... 13 common frames omitted - -2022-03-17 00:23:44.681 INFO 35086 --- [ionShutdownHook] org.quartz.core.QuartzScheduler : Scheduler schedulerFactoryBean_$_NON_CLUSTERED paused. -2022-03-17 00:23:49.731 INFO 35086 --- [ionShutdownHook] .m.i.MqttPahoMessageDrivenChannelAdapter : stopped bean 'inbound'; defined in: 'class path resource [cc/iotkit/ruleengine/config/RuleConfiguration.class]'; from source: 'cc.iotkit.ruleengine.config.RuleConfiguration.inbound()' -2022-03-17 00:23:49.732 INFO 35086 --- [ionShutdownHook] o.s.i.endpoint.EventDrivenConsumer : Removing {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel -2022-03-17 00:23:49.732 INFO 35086 --- [ionShutdownHook] o.s.i.channel.PublishSubscribeChannel : Channel 'application.errorChannel' has 0 subscriber(s). -2022-03-17 00:23:49.732 INFO 35086 --- [ionShutdownHook] o.s.i.endpoint.EventDrivenConsumer : stopped bean '_org.springframework.integration.errorLogger' -2022-03-17 00:23:49.733 INFO 35086 --- [ionShutdownHook] o.s.i.endpoint.EventDrivenConsumer : Removing {message-handler:ruleConfiguration.handler.serviceActivator} as a subscriber to the 'mqttInboundChannel' channel -2022-03-17 00:23:49.733 INFO 35086 --- [ionShutdownHook] o.s.integration.channel.DirectChannel : Channel 'application.mqttInboundChannel' has 0 subscriber(s). -2022-03-17 00:23:49.733 INFO 35086 --- [ionShutdownHook] o.s.i.endpoint.EventDrivenConsumer : stopped bean 'ruleConfiguration.handler.serviceActivator' -2022-03-17 00:23:49.741 INFO 35086 --- [ionShutdownHook] org.quartz.core.QuartzScheduler : Scheduler schedulerFactoryBean_$_NON_CLUSTERED shutting down. -2022-03-17 00:23:49.741 INFO 35086 --- [ionShutdownHook] org.quartz.core.QuartzScheduler : Scheduler schedulerFactoryBean_$_NON_CLUSTERED paused. -2022-03-17 00:23:49.742 INFO 35086 --- [ionShutdownHook] org.quartz.core.QuartzScheduler : Scheduler schedulerFactoryBean_$_NON_CLUSTERED shutdown complete. -2022-03-17 00:23:49.743 INFO 35086 --- [ionShutdownHook] o.s.s.quartz.SchedulerFactoryBean : Shutting down Quartz Scheduler -2022-03-17 00:23:55.525 INFO 35449 --- [ main] cc.iotkit.manager.Application : Starting Application using Java 1.8.0_261 on songjiangangdeMacBook-Pro.local with PID 35449 (/Users/sjg/home/gitee/open-source/iotkit-parent/manager/target/classes started by sjg in /Users/sjg/home/gitee/open-source/iotkit-parent) -2022-03-17 00:23:55.529 DEBUG 35449 --- [ main] cc.iotkit.manager.Application : Running with Spring Boot v2.6.2, Spring v5.3.14 -2022-03-17 00:23:55.529 INFO 35449 --- [ main] cc.iotkit.manager.Application : The following profiles are active: dev -2022-03-17 00:23:56.897 INFO 35449 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode! -2022-03-17 00:23:56.898 INFO 35449 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Elasticsearch repositories in DEFAULT mode. -2022-03-17 00:23:57.180 INFO 35449 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 275 ms. Found 1 Elasticsearch repository interfaces. -2022-03-17 00:23:57.296 INFO 35449 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode! -2022-03-17 00:23:57.296 INFO 35449 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data MongoDB repositories in DEFAULT mode. -2022-03-17 00:23:57.422 INFO 35449 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 125 ms. Found 20 MongoDB repository interfaces. -2022-03-17 00:23:57.690 INFO 35449 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode! -2022-03-17 00:23:57.692 INFO 35449 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Reactive Elasticsearch repositories in DEFAULT mode. -2022-03-17 00:23:57.701 INFO 35449 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 8 ms. Found 0 Reactive Elasticsearch repository interfaces. -2022-03-17 00:23:58.019 INFO 35449 --- [ main] faultConfiguringBeanFactoryPostProcessor : No bean named 'errorChannel' has been explicitly defined. Therefore, a default PublishSubscribeChannel will be created. -2022-03-17 00:23:58.048 INFO 35449 --- [ main] faultConfiguringBeanFactoryPostProcessor : No bean named 'integrationHeaderChannelRegistry' has been explicitly defined. Therefore, a default DefaultHeaderChannelRegistry will be created. -2022-03-17 00:23:58.264 INFO 35449 --- [ main] o.s.cloud.context.scope.GenericScope : BeanFactory id=cfb87af3-c30c-3a03-8b33-421165292980 -2022-03-17 00:23:58.602 INFO 35449 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.integration.config.IntegrationManagementConfiguration' of type [org.springframework.integration.config.IntegrationManagementConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) -2022-03-17 00:23:58.626 INFO 35449 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'integrationChannelResolver' of type [org.springframework.integration.support.channel.BeanFactoryChannelResolver] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) -2022-03-17 00:23:59.221 INFO 35449 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8086 (http) -2022-03-17 00:23:59.237 INFO 35449 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] -2022-03-17 00:23:59.238 INFO 35449 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.56] -2022-03-17 00:23:59.370 INFO 35449 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext -2022-03-17 00:23:59.370 INFO 35449 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 3717 ms -2022-03-17 00:23:59.800 INFO 35449 --- [ main] org.mongodb.driver.cluster : Cluster created with settings {hosts=[dds-wz9rfynv908bptqw-pub.mongodb.rds.aliyuncs.com:3717], mode=SINGLE, requiredClusterType=UNKNOWN, serverSelectionTimeout='30000 ms'} -2022-03-17 00:23:59.984 WARN 35449 --- [ main] o.s.data.convert.CustomConversions : Registering converter from class java.time.LocalDateTime to class org.joda.time.LocalDateTime as reading converter although it doesn't convert from a store-supported type! You might want to check your annotation setup at the converter implementation. -2022-03-17 00:24:00.039 INFO 35449 --- [iyuncs.com:3717] org.mongodb.driver.connection : Opened connection [connectionId{localValue:2, serverValue:5943240}] to dds-wz9rfynv908bptqw-pub.mongodb.rds.aliyuncs.com:3717 -2022-03-17 00:24:00.039 INFO 35449 --- [iyuncs.com:3717] org.mongodb.driver.connection : Opened connection [connectionId{localValue:1, serverValue:5943239}] to dds-wz9rfynv908bptqw-pub.mongodb.rds.aliyuncs.com:3717 -2022-03-17 00:24:00.039 INFO 35449 --- [iyuncs.com:3717] org.mongodb.driver.cluster : Monitor thread successfully connected to server with description ServerDescription{address=dds-wz9rfynv908bptqw-pub.mongodb.rds.aliyuncs.com:3717, type=SHARD_ROUTER, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=8, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=72114855} -2022-03-17 00:24:00.128 WARN 35449 --- [ main] o.s.data.convert.CustomConversions : Registering converter from class java.time.LocalDateTime to class org.joda.time.LocalDateTime as reading converter although it doesn't convert from a store-supported type! You might want to check your annotation setup at the converter implementation. -2022-03-17 00:24:02.145 WARN 35449 --- [ main] .m.SimpleElasticsearchPersistentProperty : Unsupported type 'class java.lang.Long' for date property 'occur'. -2022-03-17 00:24:02.148 WARN 35449 --- [ main] .m.SimpleElasticsearchPersistentProperty : Unsupported type 'class java.lang.Long' for date property 'time'. -2022-03-17 00:24:02.310 INFO 35449 --- [pool-3-thread-1] org.mongodb.driver.connection : Opened connection [connectionId{localValue:3, serverValue:5943246}] to dds-wz9rfynv908bptqw-pub.mongodb.rds.aliyuncs.com:3717 -2022-03-17 00:24:02.471 WARN 35449 --- [ main] org.elasticsearch.client.RestClient : request [HEAD http://192.168.0.112:9200/thing_model_messages?ignore_throttled=false&ignore_unavailable=false&expand_wildcards=open%2Cclosed&allow_no_indices=false] returned 1 warnings: [299 Elasticsearch-8.1.0-3700f7679f7d95e36da0b43762189bab189bc53a "[ignore_throttled] parameter is deprecated because frozen indices have been deprecated. Consider cold or frozen tiers in place of frozen indices."] -2022-03-17 00:24:02.871 WARN 35449 --- [ main] .i.n.r.d.DnsServerAddressStreamProviders : Can not find org.apache.pulsar.shade.io.netty.resolver.dns.macos.MacOSDnsServerAddressStreamProvider in the classpath, fallback to system defaults. This may result in incorrect DNS resolutions on MacOS. -2022-03-17 00:24:03.770 INFO 35449 --- [r-client-io-1-1] o.a.pulsar.client.impl.ConnectionPool : [[id: 0xae4892c5, L:/192.168.0.109:54411 - R:/192.168.0.112:6650]] Connected to server -2022-03-17 00:24:04.593 INFO 35449 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Will secure any request with [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@503b5337, org.springframework.security.web.context.SecurityContextPersistenceFilter@65e4eba5, org.springframework.security.web.header.HeaderWriterFilter@56511eda, org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter@6abe62bb, org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter@11c3d22f, org.springframework.security.web.authentication.logout.LogoutFilter@14c1cba6, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@be56353, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@1ae69abe, org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter@29c25bbc, org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter@30704f85, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@265361a, org.springframework.security.web.session.SessionManagementFilter@760f4310, org.springframework.security.web.access.ExceptionTranslationFilter@70c6c6a7, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@5fc3dfc1] -2022-03-17 00:24:04.660 INFO 35449 --- [ main] org.quartz.impl.StdSchedulerFactory : Using default implementation for ThreadExecutor -2022-03-17 00:24:04.682 INFO 35449 --- [ main] org.quartz.core.SchedulerSignalerImpl : Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl -2022-03-17 00:24:04.682 INFO 35449 --- [ main] org.quartz.core.QuartzScheduler : Quartz Scheduler v.2.3.2 created. -2022-03-17 00:24:04.684 INFO 35449 --- [ main] org.quartz.simpl.RAMJobStore : RAMJobStore initialized. -2022-03-17 00:24:04.685 INFO 35449 --- [ main] org.quartz.core.QuartzScheduler : Scheduler meta-data: Quartz Scheduler (v2.3.2) 'schedulerFactoryBean' with instanceId 'NON_CLUSTERED' - Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally. - NOT STARTED. - Currently in standby mode. - Number of jobs executed: 0 - Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads. - Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered. - -2022-03-17 00:24:04.685 INFO 35449 --- [ main] org.quartz.impl.StdSchedulerFactory : Quartz scheduler 'schedulerFactoryBean' initialized from an externally provided properties instance. -2022-03-17 00:24:04.685 INFO 35449 --- [ main] org.quartz.impl.StdSchedulerFactory : Quartz scheduler version: 2.3.2 -2022-03-17 00:24:04.685 INFO 35449 --- [ main] org.quartz.core.QuartzScheduler : JobFactory set to: cc.iotkit.ruleengine.config.JobFactory@331fe6d4 -2022-03-17 00:24:05.310 INFO 35449 --- [pool-4-thread-1] org.mongodb.driver.connection : Opened connection [connectionId{localValue:4, serverValue:5943253}] to dds-wz9rfynv908bptqw-pub.mongodb.rds.aliyuncs.com:3717 -2022-03-17 00:24:05.556 INFO 35449 --- [pool-4-thread-1] cc.iotkit.ruleengine.scene.SceneManager : got scene 460f0805-503f-428a-936c-c5e7278024d5 to init -2022-03-17 00:24:05.653 INFO 35449 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel -2022-03-17 00:24:05.654 INFO 35449 --- [ main] o.s.i.channel.PublishSubscribeChannel : Channel 'application.errorChannel' has 1 subscriber(s). -2022-03-17 00:24:05.654 INFO 35449 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started bean '_org.springframework.integration.errorLogger' -2022-03-17 00:24:05.654 INFO 35449 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {message-handler:ruleConfiguration.handler.serviceActivator} as a subscriber to the 'mqttInboundChannel' channel -2022-03-17 00:24:05.654 INFO 35449 --- [ main] o.s.integration.channel.DirectChannel : Channel 'application.mqttInboundChannel' has 1 subscriber(s). -2022-03-17 00:24:05.654 INFO 35449 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started bean 'ruleConfiguration.handler.serviceActivator' -2022-03-17 00:24:05.670 INFO 35449 --- [pool-4-thread-1] cc.iotkit.ruleengine.scene.SceneManager : got scene bef61d60-f78f-4ab4-a1a8-dc4f1bab4978 to init -2022-03-17 00:24:06.055 INFO 35449 --- [ main] .m.i.MqttPahoMessageDrivenChannelAdapter : started bean 'inbound'; defined in: 'class path resource [cc/iotkit/ruleengine/config/RuleConfiguration.class]'; from source: 'cc.iotkit.ruleengine.config.RuleConfiguration.inbound()' -2022-03-17 00:24:06.073 INFO 35449 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8086 (http) with context path '' -2022-03-17 00:24:06.587 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void -2022-03-17 00:24:06.592 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void -2022-03-17 00:24:06.593 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void -2022-03-17 00:24:06.599 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void -2022-03-17 00:24:06.599 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void -2022-03-17 00:24:06.603 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void -2022-03-17 00:24:06.632 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void -2022-03-17 00:24:06.635 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void -2022-03-17 00:24:06.636 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void -2022-03-17 00:24:06.641 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void -2022-03-17 00:24:06.642 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void -2022-03-17 00:24:06.697 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void -2022-03-17 00:24:06.702 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void -2022-03-17 00:24:06.809 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void -2022-03-17 00:24:06.811 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void -2022-03-17 00:24:06.812 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void -2022-03-17 00:24:06.817 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void -2022-03-17 00:24:06.818 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void -2022-03-17 00:24:06.819 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void -2022-03-17 00:24:06.833 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void -2022-03-17 00:24:06.834 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void -2022-03-17 00:24:06.837 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void -2022-03-17 00:24:06.840 WARN 35449 --- [ main] d.s.r.o.OperationImplicitParameterReader : Unable to interpret the implicit parameter configuration with dataType: String, dataTypeClass: class java.lang.Void -2022-03-17 00:24:06.920 INFO 35449 --- [ main] o.s.s.quartz.SchedulerFactoryBean : Starting Quartz Scheduler now -2022-03-17 00:24:06.920 INFO 35449 --- [ main] org.quartz.core.QuartzScheduler : Scheduler schedulerFactoryBean_$_NON_CLUSTERED started. -2022-03-17 00:24:06.930 INFO 35449 --- [ main] cc.iotkit.manager.Application : Started Application in 12.648 seconds (JVM running for 13.495) -2022-03-17 00:24:14.552 INFO 35449 --- [nio-8086-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' -2022-03-17 00:24:14.553 INFO 35449 --- [nio-8086-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' -2022-03-17 00:24:14.558 INFO 35449 --- [nio-8086-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 5 ms -2022-03-17 00:24:15.726 INFO 35449 --- [nio-8086-exec-1] o.keycloak.adapters.KeycloakDeployment : Loaded URLs from https://auth.iotkit.cc/realms/iotkit/.well-known/openid-configuration -2022-03-17 00:24:16.809 INFO 35449 --- [nio-8086-exec-1] org.mongodb.driver.connection : Opened connection [connectionId{localValue:5, serverValue:5943283}] to dds-wz9rfynv908bptqw-pub.mongodb.rds.aliyuncs.com:3717 -2022-03-17 00:24:19.269 ERROR 35449 --- [nio-8086-exec-1] c.i.m.config.GlobalExceptionHandler : handler exception - -cc.iotkit.common.exception.BizException: add protocol gateway error - at cc.iotkit.manager.controller.ProtocolController.addGateway(ProtocolController.java:38) - at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.lang.reflect.Method.invoke(Method.java:498) - at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) - at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) - at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) - at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) - at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067) - at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) - at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) - at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) - at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter.doFilter(KeycloakAuthenticatedActionsFilter.java:57) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter.doFilter(KeycloakSecurityContextRequestFilter.java:61) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:96) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter.successfulAuthentication(KeycloakAuthenticationProcessingFilter.java:214) - at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:233) - at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:327) - at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115) - at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122) - at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126) - at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter.doFilter(KeycloakAuthenticatedActionsFilter.java:74) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter.doFilter(KeycloakSecurityContextRequestFilter.java:92) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103) - at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter.successfulAuthentication(KeycloakAuthenticationProcessingFilter.java:214) - at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:233) - at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:96) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) - at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110) - at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211) - at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183) - at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354) - at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) - at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) - at org.keycloak.adapters.tomcat.AbstractAuthenticatedActionsValve.invoke(AbstractAuthenticatedActionsValve.java:67) - at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540) - at org.keycloak.adapters.tomcat.AbstractKeycloakAuthenticatorValve.invoke(AbstractKeycloakAuthenticatorValve.java:181) - at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) - at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) - at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) - at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) - at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382) - at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) - at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895) - at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732) - at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) - at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) - at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) - at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) - at java.lang.Thread.run(Thread.java:748) -Caused by: org.apache.pulsar.client.admin.PulsarAdminException: java.util.concurrent.CompletionException: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Remotely closed - at org.apache.pulsar.client.admin.internal.BaseResource.getApiException(BaseResource.java:247) - at org.apache.pulsar.client.admin.internal.FunctionsImpl$2.failed(FunctionsImpl.java:154) - at org.apache.pulsar.shade.org.glassfish.jersey.client.JerseyInvocation$1.failed(JerseyInvocation.java:882) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.processFailure(ClientRuntime.java:247) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.processFailure(ClientRuntime.java:242) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.access$100(ClientRuntime.java:62) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime$2.lambda$failure$1(ClientRuntime.java:178) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors$1.call(Errors.java:248) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors$1.call(Errors.java:244) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:292) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:274) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:244) - at org.apache.pulsar.shade.org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:288) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime$2.failure(ClientRuntime.java:178) - at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$apply$1(AsyncHttpConnector.java:204) - at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:774) - at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:750) - at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:488) - at java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:1990) - at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$retryOperation$4(AsyncHttpConnector.java:263) - at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:774) - at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:750) - at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:488) - at java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:1990) - at org.apache.pulsar.shade.org.asynchttpclient.netty.NettyResponseFuture.abort(NettyResponseFuture.java:273) - at org.apache.pulsar.shade.org.asynchttpclient.netty.request.NettyRequestSender.abort(NettyRequestSender.java:473) - at org.apache.pulsar.shade.org.asynchttpclient.netty.request.NettyRequestSender.handleUnexpectedClosedChannel(NettyRequestSender.java:484) - at org.apache.pulsar.shade.org.asynchttpclient.netty.handler.AsyncHttpClientHandler.channelInactive(AsyncHttpClientHandler.java:145) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) - at org.apache.pulsar.shade.io.netty.handler.stream.ChunkedWriteHandler.channelInactive(ChunkedWriteHandler.java:137) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) - at org.apache.pulsar.shade.io.netty.channel.ChannelInboundHandlerAdapter.channelInactive(ChannelInboundHandlerAdapter.java:81) - at org.apache.pulsar.shade.io.netty.handler.codec.http.HttpContentDecoder.channelInactive(HttpContentDecoder.java:235) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) - at org.apache.pulsar.shade.io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelInactive(CombinedChannelDuplexHandler.java:418) - at org.apache.pulsar.shade.io.netty.handler.codec.ByteToMessageDecoder.channelInputClosed(ByteToMessageDecoder.java:389) - at org.apache.pulsar.shade.io.netty.handler.codec.ByteToMessageDecoder.channelInactive(ByteToMessageDecoder.java:354) - at org.apache.pulsar.shade.io.netty.handler.codec.http.HttpClientCodec$Decoder.channelInactive(HttpClientCodec.java:326) - at org.apache.pulsar.shade.io.netty.channel.CombinedChannelDuplexHandler.channelInactive(CombinedChannelDuplexHandler.java:221) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) - at org.apache.pulsar.shade.io.netty.channel.DefaultChannelPipeline$HeadContext.channelInactive(DefaultChannelPipeline.java:1405) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) - at org.apache.pulsar.shade.io.netty.channel.DefaultChannelPipeline.fireChannelInactive(DefaultChannelPipeline.java:901) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannel$AbstractUnsafe$8.run(AbstractChannel.java:831) - at org.apache.pulsar.shade.io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164) - at org.apache.pulsar.shade.io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:469) - at org.apache.pulsar.shade.io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500) - at org.apache.pulsar.shade.io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986) - at org.apache.pulsar.shade.io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) - at org.apache.pulsar.shade.io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) - ... 1 common frames omitted -Caused by: java.util.concurrent.CompletionException: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Remotely closed - at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:292) - at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:308) - at java.util.concurrent.CompletableFuture.orApply(CompletableFuture.java:1385) - at java.util.concurrent.CompletableFuture$OrApply.tryFire(CompletableFuture.java:1364) - ... 43 common frames omitted -Caused by: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Remotely closed - at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$retryOperation$4(AsyncHttpConnector.java:265) - ... 40 common frames omitted -Caused by: org.apache.pulsar.shade.org.asynchttpclient.exception.RemotelyClosedException: Remotely closed - at org.apache.pulsar.shade.org.asynchttpclient.exception.RemotelyClosedException.INSTANCE(Unknown Source) - -2022-03-17 00:29:56.110 ERROR 35449 --- [nio-8086-exec-5] c.i.m.config.GlobalExceptionHandler : handler exception - -cc.iotkit.common.exception.BizException: add protocol gateway error - at cc.iotkit.manager.controller.ProtocolController.addGateway(ProtocolController.java:38) - at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.lang.reflect.Method.invoke(Method.java:498) - at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) - at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) - at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) - at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) - at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067) - at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) - at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) - at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) - at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter.doFilter(KeycloakAuthenticatedActionsFilter.java:57) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter.doFilter(KeycloakSecurityContextRequestFilter.java:61) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:96) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter.successfulAuthentication(KeycloakAuthenticationProcessingFilter.java:214) - at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:233) - at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:327) - at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115) - at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122) - at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126) - at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter.doFilter(KeycloakAuthenticatedActionsFilter.java:74) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter.doFilter(KeycloakSecurityContextRequestFilter.java:92) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103) - at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter.successfulAuthentication(KeycloakAuthenticationProcessingFilter.java:214) - at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:233) - at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:96) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) - at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110) - at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211) - at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183) - at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354) - at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) - at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) - at org.keycloak.adapters.tomcat.AbstractAuthenticatedActionsValve.invoke(AbstractAuthenticatedActionsValve.java:67) - at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540) - at org.keycloak.adapters.tomcat.AbstractKeycloakAuthenticatorValve.invoke(AbstractKeycloakAuthenticatorValve.java:181) - at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) - at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) - at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) - at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) - at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382) - at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) - at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895) - at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732) - at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) - at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) - at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) - at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) - at java.lang.Thread.run(Thread.java:748) -Caused by: org.apache.pulsar.client.admin.PulsarAdminException: java.util.concurrent.CompletionException: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Remotely closed - at org.apache.pulsar.client.admin.internal.BaseResource.getApiException(BaseResource.java:247) - at org.apache.pulsar.client.admin.internal.FunctionsImpl$2.failed(FunctionsImpl.java:154) - at org.apache.pulsar.shade.org.glassfish.jersey.client.JerseyInvocation$1.failed(JerseyInvocation.java:882) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.processFailure(ClientRuntime.java:247) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.processFailure(ClientRuntime.java:242) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.access$100(ClientRuntime.java:62) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime$2.lambda$failure$1(ClientRuntime.java:178) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors$1.call(Errors.java:248) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors$1.call(Errors.java:244) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:292) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:274) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:244) - at org.apache.pulsar.shade.org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:288) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime$2.failure(ClientRuntime.java:178) - at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$apply$1(AsyncHttpConnector.java:204) - at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:774) - at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:750) - at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:488) - at java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:1990) - at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$retryOperation$4(AsyncHttpConnector.java:263) - at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:774) - at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:750) - at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:488) - at java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:1990) - at org.apache.pulsar.shade.org.asynchttpclient.netty.NettyResponseFuture.abort(NettyResponseFuture.java:273) - at org.apache.pulsar.shade.org.asynchttpclient.netty.request.NettyRequestSender.abort(NettyRequestSender.java:473) - at org.apache.pulsar.shade.org.asynchttpclient.netty.request.NettyRequestSender.handleUnexpectedClosedChannel(NettyRequestSender.java:484) - at org.apache.pulsar.shade.org.asynchttpclient.netty.handler.AsyncHttpClientHandler.channelInactive(AsyncHttpClientHandler.java:145) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) - at org.apache.pulsar.shade.io.netty.handler.stream.ChunkedWriteHandler.channelInactive(ChunkedWriteHandler.java:137) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) - at org.apache.pulsar.shade.io.netty.channel.ChannelInboundHandlerAdapter.channelInactive(ChannelInboundHandlerAdapter.java:81) - at org.apache.pulsar.shade.io.netty.handler.codec.http.HttpContentDecoder.channelInactive(HttpContentDecoder.java:235) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) - at org.apache.pulsar.shade.io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelInactive(CombinedChannelDuplexHandler.java:418) - at org.apache.pulsar.shade.io.netty.handler.codec.ByteToMessageDecoder.channelInputClosed(ByteToMessageDecoder.java:389) - at org.apache.pulsar.shade.io.netty.handler.codec.ByteToMessageDecoder.channelInactive(ByteToMessageDecoder.java:354) - at org.apache.pulsar.shade.io.netty.handler.codec.http.HttpClientCodec$Decoder.channelInactive(HttpClientCodec.java:326) - at org.apache.pulsar.shade.io.netty.channel.CombinedChannelDuplexHandler.channelInactive(CombinedChannelDuplexHandler.java:221) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) - at org.apache.pulsar.shade.io.netty.channel.DefaultChannelPipeline$HeadContext.channelInactive(DefaultChannelPipeline.java:1405) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) - at org.apache.pulsar.shade.io.netty.channel.DefaultChannelPipeline.fireChannelInactive(DefaultChannelPipeline.java:901) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannel$AbstractUnsafe$8.run(AbstractChannel.java:831) - at org.apache.pulsar.shade.io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164) - at org.apache.pulsar.shade.io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:469) - at org.apache.pulsar.shade.io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500) - at org.apache.pulsar.shade.io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986) - at org.apache.pulsar.shade.io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) - at org.apache.pulsar.shade.io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) - ... 1 common frames omitted -Caused by: java.util.concurrent.CompletionException: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Remotely closed - at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:292) - at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:308) - at java.util.concurrent.CompletableFuture.orApply(CompletableFuture.java:1385) - at java.util.concurrent.CompletableFuture$OrApply.tryFire(CompletableFuture.java:1364) - ... 43 common frames omitted -Caused by: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Remotely closed - at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$retryOperation$4(AsyncHttpConnector.java:265) - ... 40 common frames omitted -Caused by: org.apache.pulsar.shade.org.asynchttpclient.exception.RemotelyClosedException: Remotely closed - at org.apache.pulsar.shade.org.asynchttpclient.exception.RemotelyClosedException.INSTANCE(Unknown Source) - -2022-03-17 00:31:07.512 ERROR 35449 --- [nio-8086-exec-6] c.i.m.config.GlobalExceptionHandler : handler exception - -cc.iotkit.common.exception.BizException: add protocol gateway error - at cc.iotkit.manager.controller.ProtocolController.addGateway(ProtocolController.java:38) - at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.lang.reflect.Method.invoke(Method.java:498) - at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) - at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) - at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) - at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) - at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067) - at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) - at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) - at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) - at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter.doFilter(KeycloakAuthenticatedActionsFilter.java:57) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter.doFilter(KeycloakSecurityContextRequestFilter.java:61) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:96) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter.successfulAuthentication(KeycloakAuthenticationProcessingFilter.java:214) - at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:233) - at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:327) - at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115) - at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122) - at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126) - at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter.doFilter(KeycloakAuthenticatedActionsFilter.java:74) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter.doFilter(KeycloakSecurityContextRequestFilter.java:92) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103) - at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter.successfulAuthentication(KeycloakAuthenticationProcessingFilter.java:214) - at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:233) - at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:96) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) - at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110) - at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211) - at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183) - at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354) - at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) - at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) - at org.keycloak.adapters.tomcat.AbstractAuthenticatedActionsValve.invoke(AbstractAuthenticatedActionsValve.java:67) - at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540) - at org.keycloak.adapters.tomcat.AbstractKeycloakAuthenticatorValve.invoke(AbstractKeycloakAuthenticatorValve.java:181) - at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) - at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) - at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) - at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) - at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382) - at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) - at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895) - at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732) - at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) - at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) - at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) - at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) - at java.lang.Thread.run(Thread.java:748) -Caused by: org.apache.pulsar.client.admin.PulsarAdminException: java.util.concurrent.CompletionException: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Remotely closed - at org.apache.pulsar.client.admin.internal.BaseResource.getApiException(BaseResource.java:247) - at org.apache.pulsar.client.admin.internal.FunctionsImpl$2.failed(FunctionsImpl.java:154) - at org.apache.pulsar.shade.org.glassfish.jersey.client.JerseyInvocation$1.failed(JerseyInvocation.java:882) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.processFailure(ClientRuntime.java:247) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.processFailure(ClientRuntime.java:242) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.access$100(ClientRuntime.java:62) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime$2.lambda$failure$1(ClientRuntime.java:178) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors$1.call(Errors.java:248) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors$1.call(Errors.java:244) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:292) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:274) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:244) - at org.apache.pulsar.shade.org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:288) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime$2.failure(ClientRuntime.java:178) - at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$apply$1(AsyncHttpConnector.java:204) - at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:774) - at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:750) - at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:488) - at java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:1990) - at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$retryOperation$4(AsyncHttpConnector.java:263) - at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:774) - at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:750) - at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:488) - at java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:1990) - at org.apache.pulsar.shade.org.asynchttpclient.netty.NettyResponseFuture.abort(NettyResponseFuture.java:273) - at org.apache.pulsar.shade.org.asynchttpclient.netty.request.NettyRequestSender.abort(NettyRequestSender.java:473) - at org.apache.pulsar.shade.org.asynchttpclient.netty.request.NettyRequestSender.handleUnexpectedClosedChannel(NettyRequestSender.java:484) - at org.apache.pulsar.shade.org.asynchttpclient.netty.handler.AsyncHttpClientHandler.channelInactive(AsyncHttpClientHandler.java:145) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) - at org.apache.pulsar.shade.io.netty.handler.stream.ChunkedWriteHandler.channelInactive(ChunkedWriteHandler.java:137) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) - at org.apache.pulsar.shade.io.netty.channel.ChannelInboundHandlerAdapter.channelInactive(ChannelInboundHandlerAdapter.java:81) - at org.apache.pulsar.shade.io.netty.handler.codec.http.HttpContentDecoder.channelInactive(HttpContentDecoder.java:235) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) - at org.apache.pulsar.shade.io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelInactive(CombinedChannelDuplexHandler.java:418) - at org.apache.pulsar.shade.io.netty.handler.codec.ByteToMessageDecoder.channelInputClosed(ByteToMessageDecoder.java:389) - at org.apache.pulsar.shade.io.netty.handler.codec.ByteToMessageDecoder.channelInactive(ByteToMessageDecoder.java:354) - at org.apache.pulsar.shade.io.netty.handler.codec.http.HttpClientCodec$Decoder.channelInactive(HttpClientCodec.java:326) - at org.apache.pulsar.shade.io.netty.channel.CombinedChannelDuplexHandler.channelInactive(CombinedChannelDuplexHandler.java:221) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) - at org.apache.pulsar.shade.io.netty.channel.DefaultChannelPipeline$HeadContext.channelInactive(DefaultChannelPipeline.java:1405) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) - at org.apache.pulsar.shade.io.netty.channel.DefaultChannelPipeline.fireChannelInactive(DefaultChannelPipeline.java:901) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannel$AbstractUnsafe$8.run(AbstractChannel.java:831) - at org.apache.pulsar.shade.io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164) - at org.apache.pulsar.shade.io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:469) - at org.apache.pulsar.shade.io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500) - at org.apache.pulsar.shade.io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986) - at org.apache.pulsar.shade.io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) - at org.apache.pulsar.shade.io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) - ... 1 common frames omitted -Caused by: java.util.concurrent.CompletionException: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Remotely closed - at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:292) - at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:308) - at java.util.concurrent.CompletableFuture.orApply(CompletableFuture.java:1385) - at java.util.concurrent.CompletableFuture$OrApply.tryFire(CompletableFuture.java:1364) - ... 43 common frames omitted -Caused by: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Remotely closed - at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$retryOperation$4(AsyncHttpConnector.java:265) - ... 40 common frames omitted -Caused by: org.apache.pulsar.shade.org.asynchttpclient.exception.RemotelyClosedException: Remotely closed - at org.apache.pulsar.shade.org.asynchttpclient.exception.RemotelyClosedException.INSTANCE(Unknown Source) - -2022-03-17 00:32:01.292 INFO 35449 --- [r-client-io-1-1] org.apache.pulsar.client.impl.ClientCnx : [id: 0xae4892c5, L:/192.168.0.109:54411 ! R:/192.168.0.112:6650] Disconnected -2022-03-17 00:32:14.472 WARN 35449 --- [r-client-io-1-1] o.a.pulsar.client.impl.ConnectionPool : Failed to open connection to 192.168.0.112:6650 : org.apache.pulsar.shade.io.netty.channel.ConnectTimeoutException: connection timed out: /192.168.0.112:6650 -2022-03-17 00:32:14.577 WARN 35449 --- [al-listener-3-1] o.a.p.c.impl.BinaryProtoLookupService : [namespace: public/iot] Could not get connection while getTopicsUnderNamespace -- Will try again in 100 ms -2022-03-17 00:32:24.581 WARN 35449 --- [r-client-io-1-1] o.a.pulsar.client.impl.ConnectionPool : Failed to open connection to 192.168.0.112:6650 : org.apache.pulsar.shade.io.netty.channel.ConnectTimeoutException: connection timed out: /192.168.0.112:6650 -2022-03-17 00:32:24.785 WARN 35449 --- [al-listener-3-1] o.a.p.c.impl.BinaryProtoLookupService : [namespace: public/iot] Could not get connection while getTopicsUnderNamespace -- Will try again in 197 ms -2022-03-17 00:32:34.789 WARN 35449 --- [r-client-io-1-1] o.a.pulsar.client.impl.ConnectionPool : Failed to open connection to 192.168.0.112:6650 : org.apache.pulsar.shade.io.netty.channel.ConnectTimeoutException: connection timed out: /192.168.0.112:6650 -2022-03-17 00:32:35.181 WARN 35449 --- [al-listener-3-1] o.a.p.c.impl.BinaryProtoLookupService : [namespace: public/iot] Could not get connection while getTopicsUnderNamespace -- Will try again in 391 ms -2022-03-17 00:32:45.187 WARN 35449 --- [r-client-io-1-1] o.a.pulsar.client.impl.ConnectionPool : Failed to open connection to 192.168.0.112:6650 : org.apache.pulsar.shade.io.netty.channel.ConnectTimeoutException: connection timed out: /192.168.0.112:6650 -2022-03-17 00:32:45.953 WARN 35449 --- [al-listener-3-1] o.a.p.c.impl.BinaryProtoLookupService : [namespace: public/iot] Could not get connection while getTopicsUnderNamespace -- Will try again in 765 ms -2022-03-17 00:32:55.955 WARN 35449 --- [r-client-io-1-1] o.a.pulsar.client.impl.ConnectionPool : Failed to open connection to 192.168.0.112:6650 : org.apache.pulsar.shade.io.netty.channel.ConnectTimeoutException: connection timed out: /192.168.0.112:6650 -2022-03-17 00:32:57.456 WARN 35449 --- [al-listener-3-1] o.a.p.c.impl.BinaryProtoLookupService : [namespace: public/iot] Could not get connection while getTopicsUnderNamespace -- Will try again in 1498 ms -2022-03-17 00:32:59.602 INFO 35449 --- [r-client-io-1-1] o.a.pulsar.client.impl.ConnectionPool : [[id: 0x745631fb, L:/192.168.0.109:58210 - R:/192.168.0.112:6650]] Connected to server -2022-03-17 00:33:47.330 ERROR 35449 --- [nio-8086-exec-7] c.i.m.config.GlobalExceptionHandler : handler exception - -cc.iotkit.common.exception.BizException: add protocol gateway error - at cc.iotkit.manager.controller.ProtocolController.addGateway(ProtocolController.java:38) - at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.lang.reflect.Method.invoke(Method.java:498) - at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) - at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) - at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) - at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) - at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067) - at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) - at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) - at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) - at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) - at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter.doFilter(KeycloakAuthenticatedActionsFilter.java:57) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter.doFilter(KeycloakSecurityContextRequestFilter.java:61) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:96) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter.successfulAuthentication(KeycloakAuthenticationProcessingFilter.java:214) - at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:233) - at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:327) - at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115) - at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122) - at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126) - at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter.doFilter(KeycloakAuthenticatedActionsFilter.java:74) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter.doFilter(KeycloakSecurityContextRequestFilter.java:92) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103) - at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter.successfulAuthentication(KeycloakAuthenticationProcessingFilter.java:214) - at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:233) - at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:96) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) - at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110) - at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) - at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211) - at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183) - at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354) - at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) - at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) - at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) - at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) - at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) - at org.keycloak.adapters.tomcat.AbstractAuthenticatedActionsValve.invoke(AbstractAuthenticatedActionsValve.java:67) - at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540) - at org.keycloak.adapters.tomcat.AbstractKeycloakAuthenticatorValve.invoke(AbstractKeycloakAuthenticatorValve.java:181) - at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) - at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) - at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) - at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) - at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382) - at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) - at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895) - at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732) - at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) - at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) - at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) - at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) - at java.lang.Thread.run(Thread.java:748) -Caused by: org.apache.pulsar.client.admin.PulsarAdminException: java.util.concurrent.CompletionException: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Remotely closed - at org.apache.pulsar.client.admin.internal.BaseResource.getApiException(BaseResource.java:247) - at org.apache.pulsar.client.admin.internal.FunctionsImpl$2.failed(FunctionsImpl.java:154) - at org.apache.pulsar.shade.org.glassfish.jersey.client.JerseyInvocation$1.failed(JerseyInvocation.java:882) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.processFailure(ClientRuntime.java:247) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.processFailure(ClientRuntime.java:242) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime.access$100(ClientRuntime.java:62) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime$2.lambda$failure$1(ClientRuntime.java:178) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors$1.call(Errors.java:248) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors$1.call(Errors.java:244) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:292) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:274) - at org.apache.pulsar.shade.org.glassfish.jersey.internal.Errors.process(Errors.java:244) - at org.apache.pulsar.shade.org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:288) - at org.apache.pulsar.shade.org.glassfish.jersey.client.ClientRuntime$2.failure(ClientRuntime.java:178) - at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$apply$1(AsyncHttpConnector.java:204) - at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:774) - at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:750) - at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:488) - at java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:1990) - at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$retryOperation$4(AsyncHttpConnector.java:263) - at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:774) - at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:750) - at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:488) - at java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:1990) - at org.apache.pulsar.shade.org.asynchttpclient.netty.NettyResponseFuture.abort(NettyResponseFuture.java:273) - at org.apache.pulsar.shade.org.asynchttpclient.netty.request.NettyRequestSender.abort(NettyRequestSender.java:473) - at org.apache.pulsar.shade.org.asynchttpclient.netty.request.NettyRequestSender.handleUnexpectedClosedChannel(NettyRequestSender.java:484) - at org.apache.pulsar.shade.org.asynchttpclient.netty.handler.AsyncHttpClientHandler.channelInactive(AsyncHttpClientHandler.java:145) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) - at org.apache.pulsar.shade.io.netty.handler.stream.ChunkedWriteHandler.channelInactive(ChunkedWriteHandler.java:137) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) - at org.apache.pulsar.shade.io.netty.channel.ChannelInboundHandlerAdapter.channelInactive(ChannelInboundHandlerAdapter.java:81) - at org.apache.pulsar.shade.io.netty.handler.codec.http.HttpContentDecoder.channelInactive(HttpContentDecoder.java:235) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) - at org.apache.pulsar.shade.io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelInactive(CombinedChannelDuplexHandler.java:418) - at org.apache.pulsar.shade.io.netty.handler.codec.ByteToMessageDecoder.channelInputClosed(ByteToMessageDecoder.java:389) - at org.apache.pulsar.shade.io.netty.handler.codec.ByteToMessageDecoder.channelInactive(ByteToMessageDecoder.java:354) - at org.apache.pulsar.shade.io.netty.handler.codec.http.HttpClientCodec$Decoder.channelInactive(HttpClientCodec.java:326) - at org.apache.pulsar.shade.io.netty.channel.CombinedChannelDuplexHandler.channelInactive(CombinedChannelDuplexHandler.java:221) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:241) - at org.apache.pulsar.shade.io.netty.channel.DefaultChannelPipeline$HeadContext.channelInactive(DefaultChannelPipeline.java:1405) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:262) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:248) - at org.apache.pulsar.shade.io.netty.channel.DefaultChannelPipeline.fireChannelInactive(DefaultChannelPipeline.java:901) - at org.apache.pulsar.shade.io.netty.channel.AbstractChannel$AbstractUnsafe$8.run(AbstractChannel.java:831) - at org.apache.pulsar.shade.io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164) - at org.apache.pulsar.shade.io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:469) - at org.apache.pulsar.shade.io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500) - at org.apache.pulsar.shade.io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986) - at org.apache.pulsar.shade.io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) - at org.apache.pulsar.shade.io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) - ... 1 common frames omitted -Caused by: java.util.concurrent.CompletionException: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Remotely closed - at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:292) - at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:308) - at java.util.concurrent.CompletableFuture.orApply(CompletableFuture.java:1385) - at java.util.concurrent.CompletableFuture$OrApply.tryFire(CompletableFuture.java:1364) - ... 43 common frames omitted -Caused by: org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector$RetryException: Could not complete the operation. Number of retries has been exhausted. Failed reason: Remotely closed - at org.apache.pulsar.client.admin.internal.http.AsyncHttpConnector.lambda$retryOperation$4(AsyncHttpConnector.java:265) - ... 40 common frames omitted -Caused by: org.apache.pulsar.shade.org.asynchttpclient.exception.RemotelyClosedException: Remotely closed - at org.apache.pulsar.shade.org.asynchttpclient.exception.RemotelyClosedException.INSTANCE(Unknown Source) - -2022-03-17 00:39:21.706 INFO 35449 --- [ionShutdownHook] org.quartz.core.QuartzScheduler : Scheduler schedulerFactoryBean_$_NON_CLUSTERED paused. diff --git a/log/info.2022-03-17.0.gz b/log/info.2022-03-17.0.gz deleted file mode 100644 index 9e81d1aca3a4b77357d0c80c8731da21425f1f36..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 107296 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
  • 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 diff --git a/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java b/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java old mode 100644 new mode 100755 diff --git a/manager/src/main/java/cc/iotkit/manager/service/PulsarAdminService.java b/manager/src/main/java/cc/iotkit/manager/service/PulsarAdminService.java old mode 100644 new mode 100755 diff --git a/model/src/main/java/cc/iotkit/model/protocol/ProtocolGateway.java b/model/src/main/java/cc/iotkit/model/protocol/ProtocolGateway.java old mode 100644 new mode 100755 diff --git a/pom.xml b/pom.xml index 36a9cd2d..85ab415a 100755 --- a/pom.xml +++ b/pom.xml @@ -231,7 +231,7 @@ cc.iotkit - protocol-function + decode-function ${project.version} diff --git a/protocol-gateway/component/pom.xml b/protocol-gateway/component/pom.xml old mode 100644 new mode 100755 diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/Component.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/Component.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/ComponentManager.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/ComponentManager.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/Device.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/Device.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/MessageHandler.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/MessageHandler.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/decode-function/.DS_Store b/protocol-gateway/decode-function/.DS_Store old mode 100644 new mode 100755 diff --git a/protocol-gateway/decode-function/pom.xml b/protocol-gateway/decode-function/pom.xml index 6968dbea..abdc3fcb 100755 --- a/protocol-gateway/decode-function/pom.xml +++ b/protocol-gateway/decode-function/pom.xml @@ -10,7 +10,7 @@ 4.0.0 - protocol-function + decode-function diff --git a/protocol-gateway/mqtt-component/pom.xml b/protocol-gateway/mqtt-component/pom.xml old mode 100644 new mode 100755 diff --git a/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttComponent.java b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttComponent.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttConfig.java b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttConfig.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttVerticle.java b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttVerticle.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/protocol-server/pom.xml b/protocol-gateway/protocol-server/pom.xml index ce0c779f..822782c0 100755 --- a/protocol-gateway/protocol-server/pom.xml +++ b/protocol-gateway/protocol-server/pom.xml @@ -55,7 +55,7 @@ cc.iotkit - protocol-function + decode-function diff --git a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/TestFunction.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/TestFunction.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/GatewayService.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/GatewayService.java old mode 100644 new mode 100755 From 55154d615f02f84ed558e65d65001d012f3f8322 Mon Sep 17 00:00:00 2001 From: xiwa Date: Tue, 22 Mar 2022 19:05:54 +0800 Subject: [PATCH 06/16] =?UTF-8?q?=E9=80=9A=E8=AE=AF=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 6 ++ protocol-gateway/component/pom.xml | 5 ++ .../cc/iotkit/comp/AbstractComponent.java | 7 ++- .../main/java/cc/iotkit/comp/Component.java | 6 ++ .../java/cc/iotkit/comp/ComponentManager.java | 2 +- .../java/cc/iotkit/comp/MessageHandler.java | 9 ++- protocol-gateway/converter/pom.xml | 28 +++++++++ .../java/cc/iotkit/converter/Converter.java | 8 +++ .../cc/iotkit/converter/ScriptConverter.java | 9 +++ .../iotkit/converter/ThingModelMessage.java | 62 +++++++++++++++++++ .../cc/iotkit/comp/mqtt/MqttComponent.java | 2 +- protocol-gateway/pom.xml | 1 + 12 files changed, 140 insertions(+), 5 deletions(-) create mode 100644 protocol-gateway/converter/pom.xml create mode 100644 protocol-gateway/converter/src/main/java/cc/iotkit/converter/Converter.java create mode 100644 protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java create mode 100755 protocol-gateway/converter/src/main/java/cc/iotkit/converter/ThingModelMessage.java diff --git a/pom.xml b/pom.xml index 85ab415a..9ff7fea9 100755 --- a/pom.xml +++ b/pom.xml @@ -247,6 +247,12 @@ ${project.version} + + cc.iotkit + converter + ${project.version} + + diff --git a/protocol-gateway/component/pom.xml b/protocol-gateway/component/pom.xml index 03ab87dc..d57e08c0 100755 --- a/protocol-gateway/component/pom.xml +++ b/protocol-gateway/component/pom.xml @@ -24,6 +24,11 @@ common + + cc.iotkit + converter + + \ No newline at end of file diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java index 56cc5d96..e08be90b 100755 --- a/protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java @@ -1,10 +1,13 @@ package cc.iotkit.comp; +import cc.iotkit.converter.Converter; import lombok.Data; @Data -public class AbstractComponent { +public abstract class AbstractComponent implements Component { - protected MessageHandler messageHandler; + protected MessageHandler handler; + + protected Converter converter; } diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/Component.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/Component.java index f5f45693..2de633f4 100755 --- a/protocol-gateway/component/src/main/java/cc/iotkit/comp/Component.java +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/Component.java @@ -1,5 +1,7 @@ package cc.iotkit.comp; +import cc.iotkit.converter.Converter; + public interface Component { void create(String config); @@ -12,4 +14,8 @@ public interface Component { void setHandler(MessageHandler handler); + void setConverter(Converter converter); + + Converter getConverter(); + } diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/ComponentManager.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/ComponentManager.java index fed3f3b5..f12db384 100755 --- a/protocol-gateway/component/src/main/java/cc/iotkit/comp/ComponentManager.java +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/ComponentManager.java @@ -22,7 +22,7 @@ public class ComponentManager { if (component == null) { return; } - component.setHandler(new MessageHandler(script)); + component.setHandler(new MessageHandler(script, component.getConverter())); component.start(); } diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/MessageHandler.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/MessageHandler.java index 43de863a..f039f83b 100755 --- a/protocol-gateway/component/src/main/java/cc/iotkit/comp/MessageHandler.java +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/MessageHandler.java @@ -2,6 +2,7 @@ package cc.iotkit.comp; import cc.iotkit.common.utils.JsonUtil; import cc.iotkit.comp.model.RegisterInfo; +import cc.iotkit.converter.Converter; import jdk.nashorn.api.scripting.NashornScriptEngine; import jdk.nashorn.api.scripting.ScriptObjectMirror; import lombok.Data; @@ -18,9 +19,12 @@ public class MessageHandler { private final String script; + private final Converter converter; + @SneakyThrows - public MessageHandler(String script) { + public MessageHandler(String script, Converter converter) { this.script = script; + this.converter = converter; engine.eval(script); } @@ -40,11 +44,14 @@ public class MessageHandler { if (rstType == null) { return; } + //取脚本执行后返回的数据 Object data = obj.get("data"); if ("register".equals(rstType)) { + //注册数据 RegisterInfo regInfo = getData(data, RegisterInfo.class); } else if ("report".equals(rstType)) { + //上报数据 } diff --git a/protocol-gateway/converter/pom.xml b/protocol-gateway/converter/pom.xml new file mode 100644 index 00000000..0c843b96 --- /dev/null +++ b/protocol-gateway/converter/pom.xml @@ -0,0 +1,28 @@ + + + + protocol-gateway + cc.iotkit + 0.0.1-SNAPSHOT + + 4.0.0 + + converter + + + 8 + 8 + + + + + + org.projectlombok + lombok + + + + + \ No newline at end of file diff --git a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/Converter.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/Converter.java new file mode 100644 index 00000000..abafa4e8 --- /dev/null +++ b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/Converter.java @@ -0,0 +1,8 @@ +package cc.iotkit.converter; + +public interface Converter { + + ThingModelMessage decode(String msg); + + +} diff --git a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java new file mode 100644 index 00000000..1be49df2 --- /dev/null +++ b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java @@ -0,0 +1,9 @@ +package cc.iotkit.converter; + +public class ScriptConverter implements Converter { + + public ThingModelMessage decode(String msg) { + return null; + } + +} diff --git a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ThingModelMessage.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ThingModelMessage.java new file mode 100755 index 00000000..605c5ebb --- /dev/null +++ b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ThingModelMessage.java @@ -0,0 +1,62 @@ +package cc.iotkit.converter; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.HashMap; +import java.util.Map; + +/** + * 物模型消息 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ThingModelMessage { + + private String productKey; + + private String deviceName; + + private String mid; + + private String identifier; + + private Map data; + + /** + * 时间戳,设备上的事件或数据产生的本地时间 + */ + private Long occur; + + /** + * 消息上报时间 + */ + private Long time; + + public static ThingModelMessage from(Map map) { + ThingModelMessage message = new ThingModelMessage(); + message.setProductKey(getStr(map, "productKey")); + message.setDeviceName(getStr(map, "deviceName")); + message.setMid(getStr(map, "mid")); + message.setIdentifier(getStr(map, "identifier")); + Object data = map.get("data"); + if (data instanceof Map) { + message.setData((Map) data); + } else { + message.setData(new HashMap<>()); + } + return message; + } + + private static String getStr(Map map, String key) { + Object val = map.get(key); + if (val == null) { + return null; + } + return val.toString(); + } +} diff --git a/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttComponent.java b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttComponent.java index 550194dd..dd6c5329 100755 --- a/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttComponent.java +++ b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttComponent.java @@ -24,7 +24,7 @@ public class MqttComponent extends AbstractComponent { public void start() { try { - Future future = vertx.deployVerticle(new MqttVerticle(mqttConfig, getMessageHandler())); + Future future = vertx.deployVerticle(new MqttVerticle(mqttConfig, getHandler())); future.onSuccess((s -> { deployedId = s; countDownLatch.countDown(); diff --git a/protocol-gateway/pom.xml b/protocol-gateway/pom.xml index 3e9bf227..3fab41c3 100755 --- a/protocol-gateway/pom.xml +++ b/protocol-gateway/pom.xml @@ -15,6 +15,7 @@ gateway-client protocol-server decode-function + converter From 5c4694b080c2b92c73b72acd46561d626b1628e4 Mon Sep 17 00:00:00 2001 From: xiwa Date: Wed, 23 Mar 2022 18:58:29 +0800 Subject: [PATCH 07/16] =?UTF-8?q?=E5=8D=8F=E8=AE=AE=E7=BD=91=E5=85=B3?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 6148 -> 8196 bytes .../main/java/cc/iotkit/common/Constants.java | 2 +- .../cc/iotkit/simulator/service/Gateway.java | 2 +- .../mqtt/controller/MqttAuthController.java | 2 +- .../mqtt/service/DeviceAuthService.java | 2 +- .../server/mqtt/service/MqttManager.java | 2 +- manager/pom.xml | 10 + .../controller/ProtocolController.java | 16 ++ pom.xml | 14 +- protocol-gateway/.DS_Store | Bin 0 -> 6148 bytes protocol-gateway/component-server/pom.xml | 74 +++++++ .../cc/iotkit/comps/ComponentManager.java | 47 +++++ .../java/cc/iotkit/comps/MessageHandler.java | 132 ++++++++++++ .../cc/iotkit/comps}/config/ServerConfig.java | 2 +- .../java/cc/iotkit/comps/model/AuthInfo.java | 15 ++ .../cc/iotkit/comps/model/DeviceState.java | 17 ++ .../cc/iotkit/comps/model/RegisterInfo.java | 49 +++++ .../comps/service/DeviceBehaviourService.java | 188 ++++++++++++++++++ .../comps/service/DeviceMessageConsumer.java | 75 +++++++ protocol-gateway/component/pom.xml | 23 +-- .../cc/iotkit/comp/AbstractComponent.java | 8 +- .../main/java/cc/iotkit/comp/Component.java | 21 -- .../java/cc/iotkit/comp/ComponentManager.java | 37 ---- .../main/java/cc/iotkit/comp/IComponent.java | 21 ++ .../java/cc/iotkit/comp/IMessageHandler.java | 14 ++ .../java/cc/iotkit/comp/MessageHandler.java | 68 ------- .../java/cc/iotkit/comp/model/AuthInfo.java | 12 ++ .../cc/iotkit/comp/model/DeviceMessage.java | 15 ++ protocol-gateway/converter/pom.xml | 15 ++ .../java/cc/iotkit/converter/Converter.java | 8 - .../java/cc/iotkit/converter}/Device.java | 4 +- .../cc/iotkit/converter/DeviceService.java | 20 ++ .../java/cc/iotkit/converter/IConverter.java | 13 ++ .../cc/iotkit/converter/ScriptConverter.java | 45 ++++- .../iotkit/converter/ThingModelMessage.java | 62 ------ .../cc/iotkit/comp/mqtt/MqttVerticle.java | 6 +- protocol-gateway/pom.xml | 8 +- .../server/config/ProtocolConfig.java | 17 ++ .../controller/DeviceBehaviourController.java | 9 +- ...iourService.java => BehaviourService.java} | 2 +- .../server/service/DeviceMessageConsumer.java | 8 +- .../server/service/GatewayService.java | 4 +- .../ruleengine/config/RuleConfiguration.java | 2 +- 43 files changed, 848 insertions(+), 243 deletions(-) create mode 100644 protocol-gateway/.DS_Store create mode 100755 protocol-gateway/component-server/pom.xml create mode 100755 protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentManager.java create mode 100755 protocol-gateway/component-server/src/main/java/cc/iotkit/comps/MessageHandler.java rename protocol-gateway/{protocol-server/src/main/java/cc/iotkit/protocol/server => component-server/src/main/java/cc/iotkit/comps}/config/ServerConfig.java (88%) create mode 100644 protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/AuthInfo.java create mode 100644 protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/DeviceState.java create mode 100755 protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/RegisterInfo.java create mode 100755 protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceBehaviourService.java create mode 100755 protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceMessageConsumer.java mode change 100755 => 100644 protocol-gateway/component/pom.xml delete mode 100755 protocol-gateway/component/src/main/java/cc/iotkit/comp/Component.java delete mode 100755 protocol-gateway/component/src/main/java/cc/iotkit/comp/ComponentManager.java create mode 100755 protocol-gateway/component/src/main/java/cc/iotkit/comp/IComponent.java create mode 100644 protocol-gateway/component/src/main/java/cc/iotkit/comp/IMessageHandler.java delete mode 100755 protocol-gateway/component/src/main/java/cc/iotkit/comp/MessageHandler.java create mode 100644 protocol-gateway/component/src/main/java/cc/iotkit/comp/model/AuthInfo.java create mode 100644 protocol-gateway/component/src/main/java/cc/iotkit/comp/model/DeviceMessage.java delete mode 100644 protocol-gateway/converter/src/main/java/cc/iotkit/converter/Converter.java rename protocol-gateway/{component/src/main/java/cc/iotkit/comp => converter/src/main/java/cc/iotkit/converter}/Device.java (62%) mode change 100755 => 100644 create mode 100644 protocol-gateway/converter/src/main/java/cc/iotkit/converter/DeviceService.java create mode 100644 protocol-gateway/converter/src/main/java/cc/iotkit/converter/IConverter.java delete mode 100755 protocol-gateway/converter/src/main/java/cc/iotkit/converter/ThingModelMessage.java create mode 100755 protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/config/ProtocolConfig.java rename protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/{DeviceBehaviourService.java => BehaviourService.java} (99%) diff --git a/.DS_Store b/.DS_Store index 7722cb09355f57d9136253a620408d833f19de59..f9d353f370a1db4f78c1f5da0233068cda235af4 100755 GIT binary patch literal 8196 zcmeHMO>fgc5S?w(#!*z11Bf0iaSbA^s-lXE70MsL2o41W8(YD`^+t(PtBNA|3V(=y z!tdejM^RZfa6m%T%vv+gp500Gp4Yn>hls>vl^hZs5RnH{I2^#;(p0~)M%%HGdq9DF zB1uJDE$4AAuAi?u<$ zbinBn0N6!XH=Lsm&^f-vz+!Dsr{XhB^&o7juqB2t>FD>>aA07uHfYjGm~;~Mn}w}V zg#LEq`Fc2sz#w~8fE8#eplbI$`hd#)0>{tw``37$XUlRt{w8)h-QB&O*YgJ6yYQo| z!ZIpX%Sp62S68p3%;W3xD1M!#)pU6Oxh%>kE7FBd$dVL8-oD9-L{<~IDw3tn4NZsF z_xjV}!}a>;xU(rerX~CW*YNG2{R@JQ6g^Dqhzi)O zJ@g$?4&`0_B&!*ax8rW#AmmUT(i{_8QVCOwSdPg)!@Vv+z5-sgLxA7XbYvMofH{t+ zjnDoTa*hPfrofj?1v(~lpz8k@+u#2;6FI^PumY`7Ky=T-vkB;2|Dtx8sao5Iy@#o$ z#?=OO3Y;#-fw~+A{`kWX=RSt2oWNpj5D~P${vzNmmNUHn>$yUtYCGQltr&j<-vOw) BMSTDO delta 269 zcmZp1XfcprU|?W$DortDU=RQ@Ie-{MGjUEV6q~50D9Qwq2aBaMq%ssGl@}Kz zwRJOrZU8w0=ngR8hte==*5rM{iW^Hlvn*!k;1Fbn2n%onX;+X>HWq$op3E=f2=Xe( UFDxJ$=r538!D5@^dFC(!051eIH~;_u diff --git a/common/src/main/java/cc/iotkit/common/Constants.java b/common/src/main/java/cc/iotkit/common/Constants.java index 860ab832..233ad8c9 100755 --- a/common/src/main/java/cc/iotkit/common/Constants.java +++ b/common/src/main/java/cc/iotkit/common/Constants.java @@ -2,7 +2,7 @@ package cc.iotkit.common; public interface Constants { - String MQTT_SECRET = "xdkKUymrEGSCYWswqCvSPyRSFvH5j7CU"; + String PRODUCT_SECRET = "xdkKUymrEGSCYWswqCvSPyRSFvH5j7CU"; String ACCOUNT_SECRET = "3n1z33kzvpgz1foijpkepyd3e8tw84us"; diff --git a/device-server/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/service/Gateway.java b/device-server/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/service/Gateway.java index bded1d2c..f447d76d 100755 --- a/device-server/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/service/Gateway.java +++ b/device-server/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/service/Gateway.java @@ -36,7 +36,7 @@ public class Gateway extends Device { // MQTT 连接选项 MqttConnectOptions connOpts = new MqttConnectOptions(); connOpts.setUserName(this.deviceName); - connOpts.setPassword(DigestUtils.md5Hex(Constants.MQTT_SECRET + clientId).toCharArray()); + connOpts.setPassword(DigestUtils.md5Hex(Constants.PRODUCT_SECRET + clientId).toCharArray()); // 保留会话 connOpts.setCleanSession(true); diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/controller/MqttAuthController.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/controller/MqttAuthController.java index 3b3c79e5..a9b82d6b 100755 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/controller/MqttAuthController.java +++ b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/controller/MqttAuthController.java @@ -53,7 +53,7 @@ public class MqttAuthController { return false; } clientId = clientId.replaceFirst("su_", ""); - return CodecUtil.aesDecrypt(clientId, Constants.MQTT_SECRET).startsWith("admin_"); + return CodecUtil.aesDecrypt(clientId, Constants.PRODUCT_SECRET).startsWith("admin_"); } catch (Throwable e) { log.error("aesDecrypt error.", e); return false; diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/service/DeviceAuthService.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/service/DeviceAuthService.java index f4f30a7d..b1fc8142 100755 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/service/DeviceAuthService.java +++ b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/service/DeviceAuthService.java @@ -24,7 +24,7 @@ public class DeviceAuthService { String clientId = auth.getClientid(); String[] pkDnAndModel = getPkDnAndModel(clientId); - String hmac = DigestUtils.md5Hex(Constants.MQTT_SECRET + clientId); + String hmac = DigestUtils.md5Hex(Constants.PRODUCT_SECRET + clientId); if (!hmac.equalsIgnoreCase(auth.getPassword())) { throw new RuntimeException("password is illegal."); } diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/service/MqttManager.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/service/MqttManager.java index f2bf9bee..5c9b6a3a 100755 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/service/MqttManager.java +++ b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/service/MqttManager.java @@ -73,7 +73,7 @@ public class MqttManager implements MqttCallback, IMqttMessageListener { if (mqttClient == null) { MemoryPersistence persistence = new MemoryPersistence(); String clientId = "mqtt-server-consumer-" + env; - clientId = "su_" + CodecUtil.aesEncrypt("admin_" + clientId, Constants.MQTT_SECRET); + clientId = "su_" + CodecUtil.aesEncrypt("admin_" + clientId, Constants.PRODUCT_SECRET); mqttClient = new MqttClient(url, clientId, persistence); mqttClient.setCallback(this); } diff --git a/manager/pom.xml b/manager/pom.xml index 8268b1f2..182092a3 100755 --- a/manager/pom.xml +++ b/manager/pom.xml @@ -149,6 +149,16 @@ protocol-server + + cc.iotkit + component-server + + + + cc.iotkit + mqtt-component + + diff --git a/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java b/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java index ae666898..ea825b2e 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java @@ -2,6 +2,9 @@ package cc.iotkit.manager.controller; import cc.iotkit.common.exception.BizException; import cc.iotkit.common.utils.ReflectUtil; +import cc.iotkit.comp.mqtt.MqttComponent; +import cc.iotkit.comps.ComponentManager; +import cc.iotkit.converter.ScriptConverter; import cc.iotkit.dao.ProtocolGatewayRepository; import cc.iotkit.dao.UserInfoRepository; import cc.iotkit.manager.service.DataOwnerService; @@ -18,6 +21,7 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.web.bind.annotation.*; +import javax.annotation.PostConstruct; import java.util.Optional; @Slf4j @@ -40,6 +44,9 @@ public class ProtocolController { @Autowired private UserInfoRepository userInfoRepository; + @Autowired + private ComponentManager componentManager; + @PostMapping("/addGateway") public void addGateway(ProtocolGateway gateway) { Optional optGateway = gatewayRepository.findById(gateway.getId()); @@ -123,4 +130,13 @@ public class ProtocolController { return new Paging<>(gateways.getTotalElements(), gateways.getContent()); } + @PostConstruct + public void init() { + MqttComponent component = new MqttComponent(); + ScriptConverter converter = new ScriptConverter(); + converter.setScript(""); + component.setConverter(converter); + componentManager.register("123", component); + componentManager.start("123", ""); + } } diff --git a/pom.xml b/pom.xml index 9ff7fea9..14ab8abc 100755 --- a/pom.xml +++ b/pom.xml @@ -12,8 +12,6 @@ dao tppa-server protocol-gateway - protocol-gateway/mqtt-component - protocol-gateway/component org.springframework.boot @@ -253,6 +251,18 @@ ${project.version} + + cc.iotkit + component-server + ${project.version} + + + + cc.iotkit + mqtt-component + ${project.version} + + diff --git a/protocol-gateway/.DS_Store b/protocol-gateway/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 + + + iotkit-parent + cc.iotkit + 0.0.1-SNAPSHOT + ../../pom.xml + + 4.0.0 + + component-server + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.apache.pulsar + pulsar-client-all + + + + org.springframework.boot + spring-boot-starter-data-elasticsearch + + + + org.springframework + spring-context + + + + org.slf4j + slf4j-api + + + + org.projectlombok + lombok + + + + cc.iotkit + common + + + + cc.iotkit + converter + + + + cc.iotkit + model + + + + cc.iotkit + dao + + + + cc.iotkit + component + + + + + \ No newline at end of file diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentManager.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentManager.java new file mode 100755 index 00000000..3662ffd6 --- /dev/null +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentManager.java @@ -0,0 +1,47 @@ +package cc.iotkit.comps; + + +import cc.iotkit.comp.IComponent; +import cc.iotkit.comps.service.DeviceBehaviourService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +@Component +public class ComponentManager { + + private final Map components = new HashMap<>(); + + @Autowired + private DeviceBehaviourService deviceBehaviourService; + + public void register(String id, IComponent component) { + components.put(id, component); + } + + public void deRegister(String id) { + IComponent component = components.remove(id); + component.destroy(); + } + + public void start(String id, String script) { + IComponent component = components.get(id); + if (component == null) { + return; + } + component.setHandler(new MessageHandler(script, component.getConverter(), + deviceBehaviourService)); + component.start(); + } + + public void stop(String id) { + IComponent component = components.get(id); + if (component == null) { + return; + } + component.stop(); + } + +} diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/MessageHandler.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/MessageHandler.java new file mode 100755 index 00000000..3fba5d70 --- /dev/null +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/MessageHandler.java @@ -0,0 +1,132 @@ +package cc.iotkit.comps; + +import cc.iotkit.comp.IMessageHandler; +import cc.iotkit.comp.model.DeviceMessage; +import cc.iotkit.comps.model.AuthInfo; +import cc.iotkit.comps.model.DeviceState; +import cc.iotkit.comps.model.RegisterInfo; +import cc.iotkit.comps.service.DeviceBehaviourService; +import cc.iotkit.converter.IConverter; +import jdk.nashorn.api.scripting.NashornScriptEngine; +import jdk.nashorn.api.scripting.ScriptObjectMirror; +import lombok.Data; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.beanutils.BeanUtils; + +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; +import java.util.Map; + +@Slf4j +@Data +public class MessageHandler implements IMessageHandler { + private final NashornScriptEngine engine = (NashornScriptEngine) (new ScriptEngineManager()).getEngineByName("nashorn"); + + private final String script; + + private final IConverter converter; + + private final DeviceBehaviourService deviceBehaviourService; + + @SneakyThrows + public MessageHandler(String script, IConverter converter, + DeviceBehaviourService deviceBehaviourService) { + this.script = script; + this.converter = converter; + this.deviceBehaviourService = deviceBehaviourService; + engine.eval(script); + } + + public void register(Map head, String msg) { + } + + public void auth(Map head, String msg) { + } + + public void state(Map head, String msg) { + } + + public void onReceive(Map head, String type, String msg) { + try { + ScriptObjectMirror result = (ScriptObjectMirror) engine.invokeFunction("onReceive", head, type, msg); + Object rstType = result.get("type"); + if (rstType == null) { + return; + } + //取脚本执行后返回的数据 + Object data = result.get("data"); + if (!(data instanceof Map)) { + return; + } + Map dataMap = (Map) data; + + if ("register".equals(rstType)) { + //注册数据 + RegisterInfo regInfo = new RegisterInfo(); + BeanUtils.populate(regInfo, dataMap); + doRegister(regInfo); + } else if ("auth".equals(rstType)) { + //设备认证 + AuthInfo authInfo = new AuthInfo(); + BeanUtils.populate(authInfo, dataMap); + doAuth(authInfo); + } else if ("state".equals(rstType)) { + //设备状态变更 + DeviceState state = new DeviceState(); + BeanUtils.populate(state, dataMap); + doStateChange(state); + } else if ("report".equals(rstType)) { + //上报数据 + DeviceMessage message = new DeviceMessage(); + BeanUtils.populate(message, dataMap); + doReport(message); + } + + } catch (Throwable e) { + log.error("onReceive error", e); + } + } + + private void doRegister(RegisterInfo reg) throws ScriptException, NoSuchMethodException { + try { + deviceBehaviourService.register(reg); + engine.invokeFunction("onRegistered", reg, true); + } catch (Throwable e) { + log.error("register error", e); + engine.invokeFunction("onRegistered", reg, false); + } + } + + private void doAuth(AuthInfo auth) throws ScriptException, NoSuchMethodException { + try { + deviceBehaviourService.deviceAuth(auth.getProductKey(), + auth.getDeviceName(), + auth.getProductSecret(), + auth.getDeviceSecret()); + engine.invokeFunction("onAuthed", auth, true); + } catch (Throwable e) { + log.error("device auth error", e); + engine.invokeFunction("onAuthed", auth, false); + } + } + + private void doStateChange(DeviceState state) { + try { + deviceBehaviourService.deviceStateChange(state.getProductKey(), + state.getDeviceName(), + DeviceState.STATE_ONLINE.equals(state.getState())); + } catch (Throwable e) { + log.error("device state change error", e); + } + } + + private void doReport(DeviceMessage message) { + try { + deviceBehaviourService.reportMessage(message); + } catch (Throwable e) { + log.error("report device message error", e); + } + } + +} diff --git a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/config/ServerConfig.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/ServerConfig.java similarity index 88% rename from protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/config/ServerConfig.java rename to protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/ServerConfig.java index 6a5a01d8..7238b060 100755 --- a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/config/ServerConfig.java +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/ServerConfig.java @@ -1,4 +1,4 @@ -package cc.iotkit.protocol.server.config; +package cc.iotkit.comps.config; import lombok.Data; import org.springframework.beans.factory.annotation.Value; diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/AuthInfo.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/AuthInfo.java new file mode 100644 index 00000000..cce5fc36 --- /dev/null +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/AuthInfo.java @@ -0,0 +1,15 @@ +package cc.iotkit.comps.model; + +import lombok.Data; + +@Data +public class AuthInfo { + + private String productKey; + + private String deviceName; + + private String productSecret; + + private String deviceSecret; +} diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/DeviceState.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/DeviceState.java new file mode 100644 index 00000000..150ce9cb --- /dev/null +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/DeviceState.java @@ -0,0 +1,17 @@ +package cc.iotkit.comps.model; + +import lombok.Data; + +@Data +public class DeviceState { + + public static final String STATE_ONLINE = "online"; + public static final String STATE_OFFLINE = "offline"; + + private String productKey; + + private String deviceName; + + private String state; + +} diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/RegisterInfo.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/RegisterInfo.java new file mode 100755 index 00000000..0cc51c19 --- /dev/null +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/RegisterInfo.java @@ -0,0 +1,49 @@ +package cc.iotkit.comps.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Map; + +/** + * 注册信息 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class RegisterInfo { + + private String productKey; + + private String deviceName; + + private String model; + + private Map tag; + + private List subDevices; + + public RegisterInfo(String productKey, String deviceName, String model) { + this.productKey = productKey; + this.deviceName = deviceName; + this.model = model; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class SubDevice { + + private String productKey; + + private String deviceName; + + private String model; + + private Map tag; + } +} diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceBehaviourService.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceBehaviourService.java new file mode 100755 index 00000000..4f8d03ff --- /dev/null +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceBehaviourService.java @@ -0,0 +1,188 @@ +package cc.iotkit.comps.service; + +import cc.iotkit.common.Constants; +import cc.iotkit.common.exception.BizException; +import cc.iotkit.common.utils.JsonUtil; +import cc.iotkit.comp.model.DeviceMessage; +import cc.iotkit.comps.config.ServerConfig; +import cc.iotkit.comps.model.RegisterInfo; +import cc.iotkit.dao.DeviceRepository; +import cc.iotkit.dao.ProductRepository; +import cc.iotkit.model.device.DeviceInfo; +import cc.iotkit.model.product.Product; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.RandomUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.pulsar.client.api.Producer; +import org.apache.pulsar.client.api.PulsarClient; +import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.pulsar.client.impl.schema.JSONSchema; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +@Slf4j +@Service +public class DeviceBehaviourService { + + @Autowired + private ProductRepository productRepository; + @Autowired + private DeviceRepository deviceRepository; + @Autowired + private ServerConfig serverConfig; + + private Producer deviceMessageProducer; + + @PostConstruct + public void init() throws PulsarClientException { + //初始化pulsar客户端 + PulsarClient client = PulsarClient.builder() + .serviceUrl(serverConfig.getPulsarBrokerUrl()) + .build(); + deviceMessageProducer = client.newProducer(JSONSchema.of(DeviceMessage.class)) + .topic("persistent://public/default/device_raw") + .create(); + + } + + + public void register(RegisterInfo info) { + try { + DeviceInfo deviceInfo = register(null, info); + //子设备注册 + List subDevices = info.getSubDevices(); + if (subDevices != null && subDevices.size() != 0) { + for (RegisterInfo.SubDevice subDevice : subDevices) { + register(deviceInfo.getDeviceId(), + new RegisterInfo(subDevice.getProductKey(), + subDevice.getDeviceName(), + subDevice.getModel(), + subDevice.getTag(), null)); + } + } + //todo 产生设备注册事件 + } catch (BizException e) { + log.error("register device error", e); + throw e; + } catch (Throwable e) { + log.error("register device error", e); + throw new BizException("register device error", e); + } + } + + public DeviceInfo register(String parentId, RegisterInfo info) { + String pk = info.getProductKey(); + Optional optProduct = productRepository.findById(pk); + if (!optProduct.isPresent()) { + throw new BizException("Product does not exist"); + } + String uid = optProduct.get().getUid(); + DeviceInfo device = deviceRepository.findByProductKeyAndDeviceName(pk, info.getDeviceName()); + + if (device != null) { + //更新设备信息 + device.setParentId(parentId); + device.setUid(uid); + Map tag = info.getTag(); + Map oldTag = device.getTag(); + + if (oldTag == null) { + oldTag = new HashMap<>(); + } + + if (tag != null) { + oldTag.putAll(tag); + } + + device.setTag(oldTag); + } else { + //不存在,注册新设备 + device = new DeviceInfo(); + device.setParentId(parentId); + device.setUid(uid); + device.setDeviceId(newDeviceId(info.getDeviceName())); + device.setProductKey(info.getProductKey()); + device.setDeviceName(info.getDeviceName()); + device.setTag(info.getTag()); + device.setState(new DeviceInfo.State(false, null, null)); + device.setCreateAt(System.currentTimeMillis()); + } + + deviceRepository.save(device); + log.info("device registered:{}", JsonUtil.toJsonString(device)); + + return device; + } + + /** + * 1-13位 时间戳 + * 14-29位 deviceNae,去除非字母和数字,不足16位补0,超过16位的mac取后16位,共16位 + * 30-31位 mac长度,共2位 + * 32位 随机一个0-f字符 + */ + public static String newDeviceId(String deviceNae) { + int maxDnLen = 16; + String dn = deviceNae.replaceAll("[^0-9A-Za-z]", ""); + if (dn.length() > maxDnLen) { + dn = dn.substring(dn.length() - maxDnLen); + } else { + dn = (dn + "00000000000000000000").substring(0, maxDnLen); + } + String len = StringUtils.leftPad(deviceNae.length() + "", 2, '0'); + String rnd = Integer.toHexString(RandomUtils.nextInt(0, 16)); + return (System.currentTimeMillis() + "0" + dn + len + rnd).toLowerCase(); + } + + public void deviceAuth(String productKey, + String deviceName, + String productSecret, + String deviceSecret) { + DeviceInfo deviceInfo = deviceRepository.findByProductKeyAndDeviceName(productKey, deviceName); + if (deviceInfo == null) { + throw new BizException("device does not exist"); + } + if (!Constants.PRODUCT_SECRET.equals(productSecret)) { + throw new BizException("incorrect productSecret"); + } + + //todo 按产品ProductSecret认证,子设备需要父设备认证后可通过验证 +// Optional optProduct = productRepository.findById(productKey); +// if (!optProduct.isPresent()) { +// throw new BizException("product does not exist"); +// } +// Product product = optProduct.get(); +// if (product.getNodeType()) { +// +// } + + } + + public void deviceStateChange(String productKey, + String deviceName, + boolean online) { + DeviceInfo device = deviceRepository.findByProductKeyAndDeviceName(productKey, deviceName); + if (device == null) { + throw new BizException("device does not exist"); + } + + if (online) { + device.getState().setOnline(true); + device.getState().setOnlineTime(System.currentTimeMillis()); + } else { + device.getState().setOnline(false); + device.getState().setOfflineTime(System.currentTimeMillis()); + } + deviceRepository.save(device); + //todo 产生在离线事件 + } + + public void reportMessage(DeviceMessage message) throws PulsarClientException { + deviceMessageProducer.send(message); + } +} diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceMessageConsumer.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceMessageConsumer.java new file mode 100755 index 00000000..8a90b95b --- /dev/null +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceMessageConsumer.java @@ -0,0 +1,75 @@ +package cc.iotkit.comps.service; + +import cc.iotkit.common.Constants; +import cc.iotkit.common.utils.JsonUtil; +import cc.iotkit.comps.config.ServerConfig; +import cc.iotkit.dao.ThingModelMessageRepository; +import cc.iotkit.dao.UserInfoRepository; +import cc.iotkit.model.UserInfo; +import cc.iotkit.model.device.message.ThingModelMessage; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.pulsar.client.api.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@Service +public class DeviceMessageConsumer implements MessageListener { + + private final ServerConfig serverConfig; + + private final ThingModelMessageRepository messageRepository; + + private final UserInfoRepository userInfoRepository; + + @SneakyThrows + @Autowired + public DeviceMessageConsumer(ServerConfig serverConfig, + ThingModelMessageRepository messageRepository, + UserInfoRepository userInfoRepository) { + this.serverConfig = serverConfig; + this.messageRepository = messageRepository; + this.userInfoRepository = userInfoRepository; + + PulsarClient client = PulsarClient.builder() + .serviceUrl(this.serverConfig.getPulsarBrokerUrl()) + .build(); + + String topicFormat = "persistent://%s/default/" + Constants.THING_MODEL_MESSAGE_TOPIC; + List platformUsers = userInfoRepository.findByType(UserInfo.USER_TYPE_PLATFORM); + List topics = platformUsers.stream().map(u -> String.format(topicFormat, u.getUid())) + .collect(Collectors.toList()); + log.info("subscribe device_thing topic:{}", JsonUtil.toJsonString(topics)); + + client.newConsumer(Schema.JSON(ThingModelMessage.class)) + .topics(topics) + .subscriptionName("thing-model-message") + .consumerName("thing-model-message-consumer") + .messageListener(this).subscribe(); + } + + @SneakyThrows + @Override + public void received(Consumer consumer, Message msg) { + ThingModelMessage modelMessage = msg.getValue(); + log.info("receive message:{}", JsonUtil.toJsonString(modelMessage)); + //设备消息日志入库 + messageRepository.save(modelMessage); + + messageRepository.findAll().forEach(m -> { + log.info(JsonUtil.toJsonString(m)); + }); + + consumer.acknowledge(msg); + } + + @Override + public void reachedEndOfTopic(Consumer consumer) { + + } + +} diff --git a/protocol-gateway/component/pom.xml b/protocol-gateway/component/pom.xml old mode 100755 new mode 100644 index d57e08c0..4086ecf6 --- a/protocol-gateway/component/pom.xml +++ b/protocol-gateway/component/pom.xml @@ -3,32 +3,31 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - iotkit-parent + protocol-gateway cc.iotkit 0.0.1-SNAPSHOT - ../../pom.xml 4.0.0 component + + 8 + 8 + + - - org.projectlombok - lombok - - - - cc.iotkit - common - - cc.iotkit converter + + org.projectlombok + lombok + + \ No newline at end of file diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java index e08be90b..da9714f4 100755 --- a/protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java @@ -1,13 +1,13 @@ package cc.iotkit.comp; -import cc.iotkit.converter.Converter; +import cc.iotkit.converter.IConverter; import lombok.Data; @Data -public abstract class AbstractComponent implements Component { +public abstract class AbstractComponent implements IComponent { - protected MessageHandler handler; + protected IMessageHandler handler; - protected Converter converter; + protected IConverter converter; } diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/Component.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/Component.java deleted file mode 100755 index 2de633f4..00000000 --- a/protocol-gateway/component/src/main/java/cc/iotkit/comp/Component.java +++ /dev/null @@ -1,21 +0,0 @@ -package cc.iotkit.comp; - -import cc.iotkit.converter.Converter; - -public interface Component { - - void create(String config); - - void start(); - - void stop(); - - void destroy(); - - void setHandler(MessageHandler handler); - - void setConverter(Converter converter); - - Converter getConverter(); - -} diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/ComponentManager.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/ComponentManager.java deleted file mode 100755 index f12db384..00000000 --- a/protocol-gateway/component/src/main/java/cc/iotkit/comp/ComponentManager.java +++ /dev/null @@ -1,37 +0,0 @@ -package cc.iotkit.comp; - - -import java.util.HashMap; -import java.util.Map; - -public class ComponentManager { - - private final Map components = new HashMap<>(); - - public void register(String id, Component component) { - components.put(id, component); - } - - public void deRegister(String id) { - Component component = components.remove(id); - component.destroy(); - } - - public void start(String id, String script) { - Component component = components.get(id); - if (component == null) { - return; - } - component.setHandler(new MessageHandler(script, component.getConverter())); - component.start(); - } - - public void stop(String id) { - Component component = components.get(id); - if (component == null) { - return; - } - component.stop(); - } - -} diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/IComponent.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/IComponent.java new file mode 100755 index 00000000..0d8b4f53 --- /dev/null +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/IComponent.java @@ -0,0 +1,21 @@ +package cc.iotkit.comp; + +import cc.iotkit.converter.IConverter; + +public interface IComponent { + + void create(String config); + + void start(); + + void stop(); + + void destroy(); + + void setHandler(IMessageHandler handler); + + void setConverter(IConverter converter); + + IConverter getConverter(); + +} diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/IMessageHandler.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/IMessageHandler.java new file mode 100644 index 00000000..54a7d4ec --- /dev/null +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/IMessageHandler.java @@ -0,0 +1,14 @@ +package cc.iotkit.comp; + +import java.util.Map; + +public interface IMessageHandler { + + void register(Map head, String msg); + + void auth(Map head, String msg); + + void state(Map head, String msg); + + void onReceive(Map head, String type, String msg); +} diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/MessageHandler.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/MessageHandler.java deleted file mode 100755 index f039f83b..00000000 --- a/protocol-gateway/component/src/main/java/cc/iotkit/comp/MessageHandler.java +++ /dev/null @@ -1,68 +0,0 @@ -package cc.iotkit.comp; - -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.comp.model.RegisterInfo; -import cc.iotkit.converter.Converter; -import jdk.nashorn.api.scripting.NashornScriptEngine; -import jdk.nashorn.api.scripting.ScriptObjectMirror; -import lombok.Data; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; - -import javax.script.ScriptEngineManager; -import java.util.Map; - -@Slf4j -@Data -public class MessageHandler { - private final NashornScriptEngine engine = (NashornScriptEngine) (new ScriptEngineManager()).getEngineByName("nashorn"); - - private final String script; - - private final Converter converter; - - @SneakyThrows - public MessageHandler(String script, Converter converter) { - this.script = script; - this.converter = converter; - engine.eval(script); - } - - public void register(Map head, String msg) { - } - - public void auth(Map head, String msg) { - } - - public void state(Map head, String msg) { - } - - public void onReceive(Map head, String type, String msg) { - try { - ScriptObjectMirror obj = (ScriptObjectMirror) engine.invokeFunction("onReceive", head, type, msg); - Object rstType = obj.get("type"); - if (rstType == null) { - return; - } - //取脚本执行后返回的数据 - Object data = obj.get("data"); - - if ("register".equals(rstType)) { - //注册数据 - RegisterInfo regInfo = getData(data, RegisterInfo.class); - } else if ("report".equals(rstType)) { - //上报数据 - - } - - } catch (Throwable e) { - log.error("onReceive error", e); - } - - } - - private T getData(Object data, Class cls) { - return JsonUtil.parse(JsonUtil.toJsonString(data), cls); - } - -} diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/AuthInfo.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/AuthInfo.java new file mode 100644 index 00000000..4aae434a --- /dev/null +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/AuthInfo.java @@ -0,0 +1,12 @@ +package cc.iotkit.comp.model; + +import lombok.Data; + +@Data +public class AuthInfo { + + private String productKey; + + private String deviceName; + +} diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/DeviceMessage.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/DeviceMessage.java new file mode 100644 index 00000000..3cc305c7 --- /dev/null +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/DeviceMessage.java @@ -0,0 +1,15 @@ +package cc.iotkit.comp.model; + +import lombok.Data; + +@Data +public class DeviceMessage { + + private String productKey; + + private String deviceName; + + private String mid; + + private String content; +} diff --git a/protocol-gateway/converter/pom.xml b/protocol-gateway/converter/pom.xml index 0c843b96..0dc29b76 100644 --- a/protocol-gateway/converter/pom.xml +++ b/protocol-gateway/converter/pom.xml @@ -18,6 +18,21 @@ + + org.slf4j + slf4j-api + + + + commons-beanutils + commons-beanutils + + + + cc.iotkit + model + + org.projectlombok lombok diff --git a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/Converter.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/Converter.java deleted file mode 100644 index abafa4e8..00000000 --- a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/Converter.java +++ /dev/null @@ -1,8 +0,0 @@ -package cc.iotkit.converter; - -public interface Converter { - - ThingModelMessage decode(String msg); - - -} diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/Device.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/Device.java old mode 100755 new mode 100644 similarity index 62% rename from protocol-gateway/component/src/main/java/cc/iotkit/comp/Device.java rename to protocol-gateway/converter/src/main/java/cc/iotkit/converter/Device.java index 8c214b45..20379d03 --- a/protocol-gateway/component/src/main/java/cc/iotkit/comp/Device.java +++ b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/Device.java @@ -1,7 +1,9 @@ -package cc.iotkit.comp; +package cc.iotkit.converter; import lombok.Data; @Data public class Device { + + } diff --git a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/DeviceService.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/DeviceService.java new file mode 100644 index 00000000..efa87010 --- /dev/null +++ b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/DeviceService.java @@ -0,0 +1,20 @@ +package cc.iotkit.converter; + +import lombok.Data; + +@Data +public class DeviceService { + + private String mid; + + private String productKey; + + private String deviceName; + + private String type; + + private String identifier; + + private T params; + +} diff --git a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/IConverter.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/IConverter.java new file mode 100644 index 00000000..93230295 --- /dev/null +++ b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/IConverter.java @@ -0,0 +1,13 @@ +package cc.iotkit.converter; + +import cc.iotkit.model.device.message.ThingModelMessage; + +public interface IConverter { + + void setScript(String script); + + ThingModelMessage decode(String msg); + + String encode(DeviceService service, Device device); + +} diff --git a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java index 1be49df2..75517bf5 100644 --- a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java +++ b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java @@ -1,8 +1,51 @@ package cc.iotkit.converter; -public class ScriptConverter implements Converter { +import cc.iotkit.model.device.message.ThingModelMessage; +import jdk.nashorn.api.scripting.NashornScriptEngine; +import jdk.nashorn.api.scripting.ScriptObjectMirror; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.beanutils.BeanUtils; + +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; + +@Slf4j +@Data +public class ScriptConverter implements IConverter { + private final NashornScriptEngine engine = (NashornScriptEngine) (new ScriptEngineManager()).getEngineByName("nashorn"); + + private String script; + + public void setScript(String script) { + this.script = script; + try { + engine.eval(script); + } catch (ScriptException e) { + log.error("eval converter script error", e); + } + } public ThingModelMessage decode(String msg) { + try { + ScriptObjectMirror result = (ScriptObjectMirror) engine.invokeFunction("decode", msg); + ThingModelMessage modelMessage = new ThingModelMessage(); + BeanUtils.populate(modelMessage, result); + return modelMessage; + } catch (Throwable e) { + log.error("execute decode script error", e); + } + return null; + } + + @Override + public String encode(DeviceService service, Device device) { + try { + ScriptObjectMirror result = (ScriptObjectMirror) engine.invokeFunction("encode", service, device); + return result.toString(); + } catch (Throwable e) { + log.error("execute encode script error", e); + } return null; } diff --git a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ThingModelMessage.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ThingModelMessage.java deleted file mode 100755 index 605c5ebb..00000000 --- a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ThingModelMessage.java +++ /dev/null @@ -1,62 +0,0 @@ -package cc.iotkit.converter; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.HashMap; -import java.util.Map; - -/** - * 物模型消息 - */ -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class ThingModelMessage { - - private String productKey; - - private String deviceName; - - private String mid; - - private String identifier; - - private Map data; - - /** - * 时间戳,设备上的事件或数据产生的本地时间 - */ - private Long occur; - - /** - * 消息上报时间 - */ - private Long time; - - public static ThingModelMessage from(Map map) { - ThingModelMessage message = new ThingModelMessage(); - message.setProductKey(getStr(map, "productKey")); - message.setDeviceName(getStr(map, "deviceName")); - message.setMid(getStr(map, "mid")); - message.setIdentifier(getStr(map, "identifier")); - Object data = map.get("data"); - if (data instanceof Map) { - message.setData((Map) data); - } else { - message.setData(new HashMap<>()); - } - return message; - } - - private static String getStr(Map map, String key) { - Object val = map.get(key); - if (val == null) { - return null; - } - return val.toString(); - } -} diff --git a/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttVerticle.java b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttVerticle.java index bada79d3..9263ca4c 100755 --- a/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttVerticle.java +++ b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttVerticle.java @@ -1,6 +1,6 @@ package cc.iotkit.comp.mqtt; -import cc.iotkit.comp.MessageHandler; +import cc.iotkit.comp.IMessageHandler; import io.netty.handler.codec.mqtt.MqttConnectReturnCode; import io.netty.handler.codec.mqtt.MqttProperties; import io.netty.handler.codec.mqtt.MqttQoS; @@ -26,9 +26,9 @@ public class MqttVerticle extends AbstractVerticle { private final MqttConfig config; - private final MessageHandler executor; + private final IMessageHandler executor; - public MqttVerticle(MqttConfig config, MessageHandler executor) { + public MqttVerticle(MqttConfig config, IMessageHandler executor) { this.config = config; this.executor = executor; } diff --git a/protocol-gateway/pom.xml b/protocol-gateway/pom.xml index 3fab41c3..f53cf12b 100755 --- a/protocol-gateway/pom.xml +++ b/protocol-gateway/pom.xml @@ -15,12 +15,10 @@ gateway-client protocol-server decode-function + component-server converter + mqtt-component + component - - 8 - 8 - - \ No newline at end of file diff --git a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/config/ProtocolConfig.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/config/ProtocolConfig.java new file mode 100755 index 00000000..275a3443 --- /dev/null +++ b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/config/ProtocolConfig.java @@ -0,0 +1,17 @@ +package cc.iotkit.protocol.server.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +@Data +public class ProtocolConfig { + + @Value("${pulsar.broker}") + private String pulsarBrokerUrl; + + @Value("${pulsar.service}") + private String pulsarServiceUrl; + +} diff --git a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/controller/DeviceBehaviourController.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/controller/DeviceBehaviourController.java index 0724da7f..1b4d76d4 100755 --- a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/controller/DeviceBehaviourController.java +++ b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/controller/DeviceBehaviourController.java @@ -3,11 +3,10 @@ package cc.iotkit.protocol.server.controller; import cc.iotkit.common.utils.JsonUtil; import cc.iotkit.protocol.*; import cc.iotkit.protocol.client.DeviceBehaviourClient; -import cc.iotkit.protocol.server.config.ServerConfig; -import cc.iotkit.protocol.server.service.DeviceBehaviourService; +import cc.iotkit.protocol.server.config.ProtocolConfig; +import cc.iotkit.protocol.server.service.BehaviourService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.*; @Slf4j @@ -16,10 +15,10 @@ import org.springframework.web.bind.annotation.*; public class DeviceBehaviourController implements DeviceBehaviour { @Autowired - private ServerConfig serverConfig; + private ProtocolConfig serverConfig; @Autowired - private DeviceBehaviourService behaviourService; + private BehaviourService behaviourService; @Override diff --git a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/DeviceBehaviourService.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/BehaviourService.java similarity index 99% rename from protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/DeviceBehaviourService.java rename to protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/BehaviourService.java index 38d067c6..8a4ca0a8 100755 --- a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/DeviceBehaviourService.java +++ b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/BehaviourService.java @@ -21,7 +21,7 @@ import java.util.Optional; @Slf4j @Service -public class DeviceBehaviourService { +public class BehaviourService { @Autowired private ProductRepository productRepository; diff --git a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/DeviceMessageConsumer.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/DeviceMessageConsumer.java index a819a7a2..04364c8d 100755 --- a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/DeviceMessageConsumer.java +++ b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/DeviceMessageConsumer.java @@ -6,7 +6,7 @@ import cc.iotkit.dao.ThingModelMessageRepository; import cc.iotkit.dao.UserInfoRepository; import cc.iotkit.model.UserInfo; import cc.iotkit.model.device.message.ThingModelMessage; -import cc.iotkit.protocol.server.config.ServerConfig; +import cc.iotkit.protocol.server.config.ProtocolConfig; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.pulsar.client.api.*; @@ -17,10 +17,10 @@ import java.util.List; import java.util.stream.Collectors; @Slf4j -@Service +//@Service public class DeviceMessageConsumer implements MessageListener { - private final ServerConfig serverConfig; + private final ProtocolConfig serverConfig; private final ThingModelMessageRepository messageRepository; @@ -28,7 +28,7 @@ public class DeviceMessageConsumer implements MessageListener @SneakyThrows @Autowired - public DeviceMessageConsumer(ServerConfig serverConfig, + public DeviceMessageConsumer(ProtocolConfig serverConfig, ThingModelMessageRepository messageRepository, UserInfoRepository userInfoRepository) { this.serverConfig = serverConfig; diff --git a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/GatewayService.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/GatewayService.java index 90d6cd7e..c00faf9d 100755 --- a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/GatewayService.java +++ b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/GatewayService.java @@ -3,7 +3,7 @@ package cc.iotkit.protocol.server.service; import cc.iotkit.common.Constants; import cc.iotkit.common.utils.JsonUtil; import cc.iotkit.protocol.function.DecodeFunction; -import cc.iotkit.protocol.server.config.ServerConfig; +import cc.iotkit.protocol.server.config.ProtocolConfig; import lombok.extern.slf4j.Slf4j; import org.apache.pulsar.client.admin.PulsarAdmin; import org.apache.pulsar.client.admin.PulsarAdminException; @@ -22,7 +22,7 @@ public class GatewayService { private PulsarAdmin pulsarAdmin; @Autowired - private ServerConfig serverConfig; + private ProtocolConfig serverConfig; private PulsarAdmin getPulsarAdmin() throws PulsarClientException { if (pulsarAdmin == null) { diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/config/RuleConfiguration.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/config/RuleConfiguration.java index 8c2048a2..7720469f 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/config/RuleConfiguration.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/config/RuleConfiguration.java @@ -79,7 +79,7 @@ public class RuleConfiguration { @Bean public MessageProducer inbound() { String clientId = "rule-consumer-" + env; - clientId = "su_" + CodecUtil.aesEncrypt("admin_" + clientId, Constants.MQTT_SECRET); + clientId = "su_" + CodecUtil.aesEncrypt("admin_" + clientId, Constants.PRODUCT_SECRET); adapter = new MqttPahoMessageDrivenChannelAdapter( clientId, mqttClientFactory()); adapter.setCompletionTimeout(5000); From f658e344dd47ba2303a90a9061798c96c0a5c4ff Mon Sep 17 00:00:00 2001 From: xiwa Date: Thu, 24 Mar 2022 06:53:42 +0800 Subject: [PATCH 08/16] =?UTF-8?q?mqtt=E9=80=9A=E8=AE=AF=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- manager/pom.xml | 5 ++ .../config/KeycloakSecurityConfig.java | 2 +- .../controller/ProtocolController.java | 18 +++- protocol-gateway/.DS_Store | Bin .../java/cc/iotkit/comps/MessageHandler.java | 23 ++--- .../java/cc/iotkit/comps/model/AuthInfo.java | 0 .../cc/iotkit/comps/model/DeviceState.java | 0 .../comps/service/DeviceBehaviourService.java | 5 +- protocol-gateway/component/pom.xml | 0 .../java/cc/iotkit/comp/IMessageHandler.java | 0 .../java/cc/iotkit/comp/model/AuthInfo.java | 0 .../cc/iotkit/comp/model/DeviceMessage.java | 0 protocol-gateway/converter/pom.xml | 0 .../main/java/cc/iotkit/converter/Device.java | 0 .../cc/iotkit/converter/DeviceService.java | 0 .../java/cc/iotkit/converter/IConverter.java | 0 .../cc/iotkit/converter/ScriptConverter.java | 0 .../cc/iotkit/comp/mqtt/MqttComponent.java | 16 ++-- .../cc/iotkit/comp/mqtt/MqttVerticle.java | 8 +- .../src/main/resources/component.js | 84 ++++++++++++++++++ .../src/main/resources/converter.js | 51 +++++++++++ 21 files changed, 187 insertions(+), 25 deletions(-) mode change 100644 => 100755 protocol-gateway/.DS_Store mode change 100644 => 100755 protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/AuthInfo.java mode change 100644 => 100755 protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/DeviceState.java mode change 100644 => 100755 protocol-gateway/component/pom.xml mode change 100644 => 100755 protocol-gateway/component/src/main/java/cc/iotkit/comp/IMessageHandler.java mode change 100644 => 100755 protocol-gateway/component/src/main/java/cc/iotkit/comp/model/AuthInfo.java mode change 100644 => 100755 protocol-gateway/component/src/main/java/cc/iotkit/comp/model/DeviceMessage.java mode change 100644 => 100755 protocol-gateway/converter/pom.xml mode change 100644 => 100755 protocol-gateway/converter/src/main/java/cc/iotkit/converter/Device.java mode change 100644 => 100755 protocol-gateway/converter/src/main/java/cc/iotkit/converter/DeviceService.java mode change 100644 => 100755 protocol-gateway/converter/src/main/java/cc/iotkit/converter/IConverter.java mode change 100644 => 100755 protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java create mode 100644 protocol-gateway/mqtt-component/src/main/resources/component.js create mode 100644 protocol-gateway/mqtt-component/src/main/resources/converter.js diff --git a/manager/pom.xml b/manager/pom.xml index 182092a3..f6678ab9 100755 --- a/manager/pom.xml +++ b/manager/pom.xml @@ -159,6 +159,11 @@ mqtt-component + + cc.iotkit + converter + + diff --git a/manager/src/main/java/cc/iotkit/manager/config/KeycloakSecurityConfig.java b/manager/src/main/java/cc/iotkit/manager/config/KeycloakSecurityConfig.java index c6bb3d02..91451d0c 100755 --- a/manager/src/main/java/cc/iotkit/manager/config/KeycloakSecurityConfig.java +++ b/manager/src/main/java/cc/iotkit/manager/config/KeycloakSecurityConfig.java @@ -54,7 +54,7 @@ public class KeycloakSecurityConfig extends KeycloakWebSecurityConfigurerAdapter http .authorizeRequests() .antMatchers("/*.html", "/favicon.ico", "/v2/api-docs", "/webjars/**", "/swagger-resources/**", "/*.js").permitAll() - .antMatchers("/device_behaviour/**").permitAll() + .antMatchers("/protocol/**").permitAll()//todo for test .antMatchers("/**/save*").hasRole("iot_write") .antMatchers("/**/del*").hasRole("iot_write") .antMatchers("/**/add*").hasRole("iot_write") diff --git a/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java b/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java index ea825b2e..7e1edd7f 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java @@ -14,6 +14,7 @@ import cc.iotkit.model.UserInfo; import cc.iotkit.model.protocol.ProtocolGateway; import cc.iotkit.protocol.server.service.GatewayService; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; @@ -22,6 +23,8 @@ import org.springframework.data.domain.Sort; import org.springframework.web.bind.annotation.*; import javax.annotation.PostConstruct; +import java.io.File; +import java.io.IOException; import java.util.Optional; @Slf4j @@ -130,13 +133,20 @@ public class ProtocolController { return new Paging<>(gateways.getTotalElements(), gateways.getContent()); } - @PostConstruct - public void init() { + @GetMapping("/registerMqtt") + public void registerMqtt() throws IOException { MqttComponent component = new MqttComponent(); + component.create("{\"port\":2883,\"ssl\":false}"); ScriptConverter converter = new ScriptConverter(); - converter.setScript(""); + converter.setScript(FileUtils.readFileToString(new File("/Users/sjg/home/gitee/open-source/converter.js"), "UTF-8")); component.setConverter(converter); componentManager.register("123", component); - componentManager.start("123", ""); + componentManager.start("123", FileUtils.readFileToString(new File("/Users/sjg/home/gitee/open-source/component.js"), "UTF-8")); + } + + @GetMapping("/deregisterMqtt") + public void deregisterMqtt() { + componentManager.stop("123"); + componentManager.deRegister("123"); } } diff --git a/protocol-gateway/.DS_Store b/protocol-gateway/.DS_Store old mode 100644 new mode 100755 diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/MessageHandler.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/MessageHandler.java index 3fba5d70..b5393850 100755 --- a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/MessageHandler.java +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/MessageHandler.java @@ -1,5 +1,6 @@ package cc.iotkit.comps; +import cc.iotkit.common.exception.BizException; import cc.iotkit.comp.IMessageHandler; import cc.iotkit.comp.model.DeviceMessage; import cc.iotkit.comps.model.AuthInfo; @@ -23,7 +24,7 @@ import java.util.Map; public class MessageHandler implements IMessageHandler { private final NashornScriptEngine engine = (NashornScriptEngine) (new ScriptEngineManager()).getEngineByName("nashorn"); - private final String script; + private final Object scriptObj; private final IConverter converter; @@ -32,10 +33,9 @@ public class MessageHandler implements IMessageHandler { @SneakyThrows public MessageHandler(String script, IConverter converter, DeviceBehaviourService deviceBehaviourService) { - this.script = script; this.converter = converter; this.deviceBehaviourService = deviceBehaviourService; - engine.eval(script); + scriptObj = engine.eval(script); } public void register(Map head, String msg) { @@ -49,7 +49,7 @@ public class MessageHandler implements IMessageHandler { public void onReceive(Map head, String type, String msg) { try { - ScriptObjectMirror result = (ScriptObjectMirror) engine.invokeFunction("onReceive", head, type, msg); + ScriptObjectMirror result = (ScriptObjectMirror) engine.invokeMethod(scriptObj, "onReceive", head, type, msg); Object rstType = result.get("type"); if (rstType == null) { return; @@ -57,7 +57,7 @@ public class MessageHandler implements IMessageHandler { //取脚本执行后返回的数据 Object data = result.get("data"); if (!(data instanceof Map)) { - return; + throw new BizException("script result data is incorrect"); } Map dataMap = (Map) data; @@ -83,18 +83,20 @@ public class MessageHandler implements IMessageHandler { doReport(message); } + } catch (BizException e) { + throw e; } catch (Throwable e) { - log.error("onReceive error", e); + throw new BizException("receive component message error", e); } } private void doRegister(RegisterInfo reg) throws ScriptException, NoSuchMethodException { try { deviceBehaviourService.register(reg); - engine.invokeFunction("onRegistered", reg, true); + engine.invokeMethod(scriptObj, "onRegistered", reg, "true"); } catch (Throwable e) { log.error("register error", e); - engine.invokeFunction("onRegistered", reg, false); + engine.invokeMethod(scriptObj, "onRegistered", reg, "false"); } } @@ -104,10 +106,10 @@ public class MessageHandler implements IMessageHandler { auth.getDeviceName(), auth.getProductSecret(), auth.getDeviceSecret()); - engine.invokeFunction("onAuthed", auth, true); + engine.invokeMethod(scriptObj, "onAuthed", auth, true); } catch (Throwable e) { log.error("device auth error", e); - engine.invokeFunction("onAuthed", auth, false); + engine.invokeMethod(scriptObj, "onAuthed", auth, false); } } @@ -128,5 +130,4 @@ public class MessageHandler implements IMessageHandler { log.error("report device message error", e); } } - } diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/AuthInfo.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/AuthInfo.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/DeviceState.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/DeviceState.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceBehaviourService.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceBehaviourService.java index 4f8d03ff..ec5fd1c7 100755 --- a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceBehaviourService.java +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceBehaviourService.java @@ -104,10 +104,11 @@ public class DeviceBehaviourService { } else { //不存在,注册新设备 device = new DeviceInfo(); + device.setId(newDeviceId(info.getDeviceName())); device.setParentId(parentId); device.setUid(uid); - device.setDeviceId(newDeviceId(info.getDeviceName())); - device.setProductKey(info.getProductKey()); + device.setDeviceId(device.getId()); + device.setProductKey(pk); device.setDeviceName(info.getDeviceName()); device.setTag(info.getTag()); device.setState(new DeviceInfo.State(false, null, null)); diff --git a/protocol-gateway/component/pom.xml b/protocol-gateway/component/pom.xml old mode 100644 new mode 100755 diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/IMessageHandler.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/IMessageHandler.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/AuthInfo.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/AuthInfo.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/DeviceMessage.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/DeviceMessage.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/converter/pom.xml b/protocol-gateway/converter/pom.xml old mode 100644 new mode 100755 diff --git a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/Device.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/Device.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/DeviceService.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/DeviceService.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/IConverter.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/IConverter.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttComponent.java b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttComponent.java index dd6c5329..a64a4638 100755 --- a/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttComponent.java +++ b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttComponent.java @@ -3,8 +3,10 @@ package cc.iotkit.comp.mqtt; import cc.iotkit.common.exception.BizException; import cc.iotkit.common.utils.JsonUtil; import cc.iotkit.comp.AbstractComponent; +import cc.iotkit.comp.IMessageHandler; import io.vertx.core.Future; import io.vertx.core.Vertx; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.CountDownLatch; @@ -13,18 +15,21 @@ import java.util.concurrent.CountDownLatch; public class MqttComponent extends AbstractComponent { private Vertx vertx; - private final CountDownLatch countDownLatch = new CountDownLatch(1); + private CountDownLatch countDownLatch; private String deployedId; - private MqttConfig mqttConfig; + private MqttVerticle mqttVerticle; public void create(String config) { vertx = Vertx.vertx(); - mqttConfig = JsonUtil.parse(config, MqttConfig.class); + MqttConfig mqttConfig = JsonUtil.parse(config, MqttConfig.class); + mqttVerticle = new MqttVerticle(mqttConfig); } public void start() { try { - Future future = vertx.deployVerticle(new MqttVerticle(mqttConfig, getHandler())); + mqttVerticle.setExecutor(getHandler()); + countDownLatch = new CountDownLatch(1); + Future future = vertx.deployVerticle(mqttVerticle); future.onSuccess((s -> { deployedId = s; countDownLatch.countDown(); @@ -40,13 +45,14 @@ public class MqttComponent extends AbstractComponent { } } + @SneakyThrows public void stop() { + mqttVerticle.stop(); Future future = vertx.undeploy(deployedId); future.onSuccess(unused -> log.info("stop mqtt component success")); } public void destroy() { - vertx.close(); } } diff --git a/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttVerticle.java b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttVerticle.java index 9263ca4c..ff73ae1e 100755 --- a/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttVerticle.java +++ b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttVerticle.java @@ -26,10 +26,13 @@ public class MqttVerticle extends AbstractVerticle { private final MqttConfig config; - private final IMessageHandler executor; + private IMessageHandler executor; - public MqttVerticle(MqttConfig config, IMessageHandler executor) { + public MqttVerticle(MqttConfig config) { this.config = config; + } + + public void setExecutor(IMessageHandler executor) { this.executor = executor; } @@ -62,6 +65,7 @@ public class MqttVerticle extends AbstractVerticle { } catch (Throwable e) { log.error("auth failed", e); endpoint.reject(MqttConnectReturnCode.CONNECTION_REFUSED_NOT_AUTHORIZED); + return; } log.info("MQTT client keep alive timeout = {} ", endpoint.keepAliveTimeSeconds()); diff --git a/protocol-gateway/mqtt-component/src/main/resources/component.js b/protocol-gateway/mqtt-component/src/main/resources/component.js new file mode 100644 index 00000000..b9c8a840 --- /dev/null +++ b/protocol-gateway/mqtt-component/src/main/resources/component.js @@ -0,0 +1,84 @@ +new (function () { + !function(n){"use strict";function d(n,t){var r=(65535&n)+(65535&t);return(n>>16)+(t>>16)+(r>>16)<<16|65535&r}function f(n,t,r,e,o,u){return d((u=d(d(t,n),d(e,u)))<>>32-o,r)}function l(n,t,r,e,o,u,c){return f(t&r|~t&e,n,t,o,u,c)}function g(n,t,r,e,o,u,c){return f(t&e|r&~e,n,t,o,u,c)}function v(n,t,r,e,o,u,c){return f(t^r^e,n,t,o,u,c)}function m(n,t,r,e,o,u,c){return f(r^(t|~e),n,t,o,u,c)}function c(n,t){var r,e,o,u;n[t>>5]|=128<>>9<<4)]=t;for(var c=1732584193,f=-271733879,i=-1732584194,a=271733878,h=0;h>5]>>>e%32&255);return t}function a(n){var t=[];for(t[(n.length>>2)-1]=void 0,e=0;e>5]|=(255&n.charCodeAt(e/8))<>>4&15)+r.charAt(15&t);return e}function r(n){return unescape(encodeURIComponent(n))}function o(n){return i(c(a(n=r(n)),8*n.length))}function u(n,t){return function(n,t){var r,e=a(n),o=[],u=[];for(o[15]=u[15]=void 0,16 0) { + var identifier = topic.substring(topic.lastIndexOf("/") + 1); + //事件上报 + return { + mid: msg.mid, + productKey: msg.productKey, + deviceName: msg.deviceName, + type:"event", + identifier: identifier, + occur: new Date().getTime(), + time: new Date().getTime(), + data: payload.params, + }; + } else if (topic.endsWith("_reply")) { + var identifier = topic.substring(topic.lastIndexOf("/") + 1); + //服务回复 + return { + mid: msg.mid, + productKey: msg.productKey, + deviceName: msg.deviceName, + type:"service", + identifier: identifier.replace("_reply", "Reply"), + occur: new Date().getTime(), + time: new Date().getTime(), + code: payload.code, + data: payload.data, + }; + } + return null; + }; + })() + \ No newline at end of file From 9aaa87dc511df38653393055f9841d27b9854c00 Mon Sep 17 00:00:00 2001 From: xiwa Date: Mon, 28 Mar 2022 08:20:00 +0800 Subject: [PATCH 09/16] =?UTF-8?q?=E5=8D=8F=E8=AE=AE=E7=BD=91=E5=85=B3?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cc/iotkit/common/utils/JsonUtil.java | 35 +++ .../cc/iotkit/common/utils/ThreadUtil.java | 25 ++ .../cc/iotkit/dao/AligenieProductDao.java | 28 -- dao/src/main/java/cc/iotkit/dao/BaseDao.java | 59 ---- .../main/java/cc/iotkit/dao/DeviceCache.java | 12 +- .../main/java/cc/iotkit/dao/DeviceDao.java | 44 +++ .../java/cc/iotkit/dao/DeviceEventDao.java | 15 - .../java/cc/iotkit/dao/DevicePropertyDao.java | 40 +++ .../iotkit/dao/DevicePropertyRepository.java | 11 + .../java/cc/iotkit/dao/DeviceRepository.java | 4 + .../cc/iotkit/dao/ThingModelMessageDao.java | 45 +++ .../dao/ThingModelMessageRepository.java | 5 + .../main/java/cc/iotkit/dao/UserInfoDao.java | 15 - device-server/.DS_Store | Bin 8196 -> 0 bytes device-server/device-api/pom.xml | 35 --- .../cc/iotkit/deviceapi/IDeviceManager.java | 44 --- .../cc/iotkit/deviceapi/IDeviceService.java | 16 -- .../java/cc/iotkit/deviceapi/Service.java | 31 --- device-server/mqtt-server/.DS_Store | Bin 6148 -> 0 bytes device-server/mqtt-server/pom.xml | 81 ------ .../cc/iotkit/server/mqtt/Application.java | 12 - .../server/mqtt/config/AutobeanConfig.java | 19 -- .../mqtt/controller/DeviceController.java | 47 ---- .../mqtt/controller/MqttAuthController.java | 63 ----- .../mqtt/handler/DisconnectedHandler.java | 41 --- .../cc/iotkit/server/mqtt/model/EmqAcl.java | 19 -- .../iotkit/server/mqtt/model/EmqAuthInfo.java | 18 -- .../cc/iotkit/server/mqtt/model/Request.java | 17 -- .../cc/iotkit/server/mqtt/model/Response.java | 25 -- .../mqtt/service/DeviceAuthService.java | 71 ----- .../server/mqtt/service/MqttManager.java | 256 ------------------ .../src/main/resources/application-dev.yml | 17 -- .../src/main/resources/application.yml | 16 -- .../src/main/resources/logback-spring.xml | 87 ------ device-server/pom.xml | 21 -- manager/pom.xml | 10 - .../manager/controller/AppController.java | 6 +- .../manager/controller/DbBaseController.java | 32 --- .../manager/controller/DeviceController.java | 68 +++-- .../manager/controller/ProductController.java | 6 +- .../controller/ProtocolController.java | 15 +- .../manager/controller/SpaceController.java | 40 ++- .../controller/UserAccountController.java | 18 -- .../controller/UserInfoController.java | 13 +- .../aligenie/AligenieDeviceController.java | 19 -- .../aligenie/AligenieProductController.java | 32 +-- .../controller/api/SpaceController.java | 2 +- .../cc/iotkit/manager/model/vo/DeviceLog.java | 9 + .../manager/service/AligenieService.java | 90 ------ .../iotkit/manager/service/DeviceService.java | 73 +++-- .../manager/service/SpaceDeviceService.java | 2 +- .../main/java/cc/iotkit/model/PagingData.java | 18 -- .../cc/iotkit/model/device/DeviceInfo.java | 3 +- .../model/device/message/DeviceProperty.java | 29 ++ .../device/message/ThingModelMessage.java | 25 +- pom.xml | 29 +- protocol-gateway/component-server/pom.xml | 12 +- .../cc/iotkit/comps/ComponentManager.java | 56 +++- .../java/cc/iotkit/comps/MessageHandler.java | 75 +++-- .../java/cc/iotkit/comps/config/CacheKey.java | 11 + .../java/cc/iotkit/comps/model/AuthInfo.java | 15 - .../cc/iotkit/comps/model/DeviceState.java | 17 -- .../cc/iotkit/comps/model/RegisterInfo.java | 49 ---- .../comps/service/DeviceBehaviourService.java | 118 +++++--- .../comps/service/DeviceMessageConsumer.java | 49 +++- .../comps/service/DeviceStateHolder.java | 122 +++++++++ .../cc/iotkit/comp/AbstractComponent.java | 11 + .../main/java/cc/iotkit/comp/CompConfig.java} | 8 +- .../main/java/cc/iotkit/comp/IComponent.java | 12 +- .../java/cc/iotkit/comp/IMessageHandler.java | 10 +- .../java/cc/iotkit/comp/model/AuthInfo.java | 4 + .../cc/iotkit/comp/model/DeviceState.java | 33 +++ .../cc/iotkit/comp/model/ReceiveResult.java} | 13 +- .../cc/iotkit/comp/model/RegisterInfo.java | 38 ++- .../cc/iotkit/converter}/DeviceMessage.java | 4 +- .../cc/iotkit/converter/DeviceService.java | 20 -- .../java/cc/iotkit/converter/IConverter.java | 4 +- .../cc/iotkit/converter/ScriptConverter.java | 20 +- .../cc/iotkit/converter/ThingService.java} | 15 +- protocol-gateway/decode-function/.DS_Store | Bin 6148 -> 0 bytes protocol-gateway/decode-function/pom.xml | 70 ----- .../protocol/function/DecodeFunction.java | 51 ---- .../protocol/function/ThingModelMessage.java | 62 ----- .../pom.xml | 28 +- .../cc/iotkit/comp/emqx/AuthVerticle.java | 70 +++++ .../cc/iotkit/comp/emqx/EmqxComponent.java | 147 ++++++++++ .../java/cc/iotkit/comp/emqx/EmqxConfig.java | 25 ++ .../cc/iotkit/protocol/DeregisterInfo.java | 17 -- .../cc/iotkit/protocol/DeviceBehaviour.java | 34 --- .../cc/iotkit/protocol/DeviceGateway.java | 23 -- .../main/java/cc/iotkit/protocol/OtaInfo.java | 7 - .../java/cc/iotkit/protocol/OtaMessage.java | 30 -- .../java/cc/iotkit/protocol/RegisterInfo.java | 49 ---- .../client/DeviceBehaviourClient.java | 151 ----------- .../mqtt-client-simulator/.DS_Store | Bin .../mqtt-client-simulator/pom.xml | 2 +- .../java/cc/iotkit/simulator/Application.java | 0 .../java/cc/iotkit/simulator/config/Mqtt.java | 0 .../cc/iotkit/simulator/service/Device.java | 0 .../cc/iotkit/simulator/service/Gateway.java | 0 protocol-gateway/mqtt-component/pom.xml | 3 +- .../cc/iotkit/comp/mqtt/MqttComponent.java | 90 +++++- .../cc/iotkit/comp/mqtt/MqttVerticle.java | 70 ++++- protocol-gateway/pom.xml | 4 +- protocol-gateway/protocol-server/.DS_Store | Bin 6148 -> 0 bytes .../protocol-server/fun-test/.DS_Store | Bin 8196 -> 0 bytes .../protocol-server/fun-test/pom.xml | 71 ----- .../main/java/cc/iotkit/fun/TestFunction.java | 50 ---- protocol-gateway/protocol-server/pom.xml | 63 ----- .../java/cc/iotkit/protocol/Application.java | 12 - .../java/cc/iotkit/protocol/server/Test1.java | 86 ------ .../java/cc/iotkit/protocol/server/Test3.java | 40 --- .../iotkit/protocol/server/TestFunction.java | 88 ------ .../server/config/ProtocolConfig.java | 17 -- .../controller/DeviceBehaviourController.java | 59 ---- .../server/service/BehaviourService.java | 142 ---------- .../server/service/DeviceMessageConsumer.java | 75 ----- .../server/service/GatewayService.java | 98 ------- .../src/main/resources/logback-spring.xml | 87 ------ .../src/main/resources/spring.factories | 1 - rule-engine/pom.xml | 4 +- .../ruleengine/action/DeviceAction.java | 12 +- .../action/DeviceActionExecutor.java | 12 +- .../action/DeviceActionService.java | 56 ++++ .../ruleengine/filter/DeviceCondition.java | 2 +- .../iotkit/ruleengine/scene/SceneManager.java | 6 +- 126 files changed, 1345 insertions(+), 3098 deletions(-) create mode 100755 common/src/main/java/cc/iotkit/common/utils/ThreadUtil.java delete mode 100755 dao/src/main/java/cc/iotkit/dao/AligenieProductDao.java delete mode 100755 dao/src/main/java/cc/iotkit/dao/BaseDao.java create mode 100644 dao/src/main/java/cc/iotkit/dao/DeviceDao.java delete mode 100755 dao/src/main/java/cc/iotkit/dao/DeviceEventDao.java create mode 100644 dao/src/main/java/cc/iotkit/dao/DevicePropertyDao.java create mode 100755 dao/src/main/java/cc/iotkit/dao/DevicePropertyRepository.java create mode 100644 dao/src/main/java/cc/iotkit/dao/ThingModelMessageDao.java delete mode 100755 dao/src/main/java/cc/iotkit/dao/UserInfoDao.java delete mode 100755 device-server/.DS_Store delete mode 100755 device-server/device-api/pom.xml delete mode 100755 device-server/device-api/src/main/java/cc/iotkit/deviceapi/IDeviceManager.java delete mode 100755 device-server/device-api/src/main/java/cc/iotkit/deviceapi/IDeviceService.java delete mode 100755 device-server/device-api/src/main/java/cc/iotkit/deviceapi/Service.java delete mode 100755 device-server/mqtt-server/.DS_Store delete mode 100755 device-server/mqtt-server/pom.xml delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/Application.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/config/AutobeanConfig.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/controller/DeviceController.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/controller/MqttAuthController.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/handler/DisconnectedHandler.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/EmqAcl.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/EmqAuthInfo.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/Request.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/Response.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/service/DeviceAuthService.java delete mode 100755 device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/service/MqttManager.java delete mode 100755 device-server/mqtt-server/src/main/resources/application-dev.yml delete mode 100755 device-server/mqtt-server/src/main/resources/application.yml delete mode 100755 device-server/mqtt-server/src/main/resources/logback-spring.xml delete mode 100755 device-server/pom.xml delete mode 100755 manager/src/main/java/cc/iotkit/manager/controller/DbBaseController.java delete mode 100755 manager/src/main/java/cc/iotkit/manager/controller/UserAccountController.java delete mode 100755 manager/src/main/java/cc/iotkit/manager/controller/aligenie/AligenieDeviceController.java create mode 100644 manager/src/main/java/cc/iotkit/manager/model/vo/DeviceLog.java delete mode 100755 manager/src/main/java/cc/iotkit/manager/service/AligenieService.java delete mode 100755 model/src/main/java/cc/iotkit/model/PagingData.java create mode 100644 model/src/main/java/cc/iotkit/model/device/message/DeviceProperty.java create mode 100644 protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/CacheKey.java delete mode 100755 protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/AuthInfo.java delete mode 100755 protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/DeviceState.java delete mode 100755 protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/RegisterInfo.java create mode 100644 protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceStateHolder.java rename protocol-gateway/{gateway-client/src/main/java/cc/iotkit/protocol/Result.java => component/src/main/java/cc/iotkit/comp/CompConfig.java} (56%) mode change 100755 => 100644 create mode 100755 protocol-gateway/component/src/main/java/cc/iotkit/comp/model/DeviceState.java rename protocol-gateway/{decode-function/src/main/java/cc/iotkit/protocol/function/DeviceMessage.java => component/src/main/java/cc/iotkit/comp/model/ReceiveResult.java} (53%) mode change 100755 => 100644 rename protocol-gateway/{component/src/main/java/cc/iotkit/comp/model => converter/src/main/java/cc/iotkit/converter}/DeviceMessage.java (71%) delete mode 100755 protocol-gateway/converter/src/main/java/cc/iotkit/converter/DeviceService.java rename protocol-gateway/{gateway-client/src/main/java/cc/iotkit/protocol/DeviceMessage.java => converter/src/main/java/cc/iotkit/converter/ThingService.java} (64%) delete mode 100755 protocol-gateway/decode-function/.DS_Store delete mode 100755 protocol-gateway/decode-function/pom.xml delete mode 100755 protocol-gateway/decode-function/src/main/java/cc/iotkit/protocol/function/DecodeFunction.java delete mode 100755 protocol-gateway/decode-function/src/main/java/cc/iotkit/protocol/function/ThingModelMessage.java rename protocol-gateway/{gateway-client => emqx-component}/pom.xml (57%) mode change 100755 => 100644 create mode 100644 protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/AuthVerticle.java create mode 100644 protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/EmqxComponent.java create mode 100644 protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/EmqxConfig.java delete mode 100755 protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeregisterInfo.java delete mode 100755 protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeviceBehaviour.java delete mode 100755 protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeviceGateway.java delete mode 100755 protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/OtaInfo.java delete mode 100755 protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/OtaMessage.java delete mode 100755 protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/RegisterInfo.java delete mode 100755 protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/client/DeviceBehaviourClient.java rename {device-server => protocol-gateway}/mqtt-client-simulator/.DS_Store (100%) rename {device-server => protocol-gateway}/mqtt-client-simulator/pom.xml (97%) rename {device-server => protocol-gateway}/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/Application.java (100%) rename {device-server => protocol-gateway}/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/config/Mqtt.java (100%) rename {device-server => protocol-gateway}/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/service/Device.java (100%) rename {device-server => protocol-gateway}/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/service/Gateway.java (100%) delete mode 100755 protocol-gateway/protocol-server/.DS_Store delete mode 100755 protocol-gateway/protocol-server/fun-test/.DS_Store delete mode 100755 protocol-gateway/protocol-server/fun-test/pom.xml delete mode 100755 protocol-gateway/protocol-server/fun-test/src/main/java/cc/iotkit/fun/TestFunction.java delete mode 100755 protocol-gateway/protocol-server/pom.xml delete mode 100755 protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/Application.java delete mode 100755 protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/Test1.java delete mode 100755 protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/Test3.java delete mode 100755 protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/TestFunction.java delete mode 100755 protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/config/ProtocolConfig.java delete mode 100755 protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/controller/DeviceBehaviourController.java delete mode 100755 protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/BehaviourService.java delete mode 100755 protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/DeviceMessageConsumer.java delete mode 100755 protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/GatewayService.java delete mode 100755 protocol-gateway/protocol-server/src/main/resources/logback-spring.xml delete mode 100755 protocol-gateway/protocol-server/src/main/resources/spring.factories create mode 100644 rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceActionService.java diff --git a/common/src/main/java/cc/iotkit/common/utils/JsonUtil.java b/common/src/main/java/cc/iotkit/common/utils/JsonUtil.java index c3b3365d..8bd2b5e2 100755 --- a/common/src/main/java/cc/iotkit/common/utils/JsonUtil.java +++ b/common/src/main/java/cc/iotkit/common/utils/JsonUtil.java @@ -5,8 +5,14 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import jdk.nashorn.api.scripting.ScriptObjectMirror; import lombok.SneakyThrows; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + public final class JsonUtil { private final static ObjectMapper MAPPER = new ObjectMapper() @@ -32,4 +38,33 @@ public final class JsonUtil { public static JsonNode parse(String json) { return MAPPER.readTree(json); } + + public static Object toObject(ScriptObjectMirror mirror) { + if (mirror.isEmpty()) { + return null; + } + if (mirror.isArray()) { + List list = new ArrayList<>(); + for (Map.Entry entry : mirror.entrySet()) { + Object result = entry.getValue(); + if (result instanceof ScriptObjectMirror) { + list.add(toObject((ScriptObjectMirror) result)); + } else { + list.add(result); + } + } + return list; + } + + Map map = new HashMap<>(); + for (Map.Entry entry : mirror.entrySet()) { + Object result = entry.getValue(); + if (result instanceof ScriptObjectMirror) { + map.put(entry.getKey(), toObject((ScriptObjectMirror) result)); + } else { + map.put(entry.getKey(), result); + } + } + return map; + } } diff --git a/common/src/main/java/cc/iotkit/common/utils/ThreadUtil.java b/common/src/main/java/cc/iotkit/common/utils/ThreadUtil.java new file mode 100755 index 00000000..bbe481d5 --- /dev/null +++ b/common/src/main/java/cc/iotkit/common/utils/ThreadUtil.java @@ -0,0 +1,25 @@ +package cc.iotkit.common.utils; + +import java.util.concurrent.ScheduledThreadPoolExecutor; + +public class ThreadUtil { + + public static ScheduledThreadPoolExecutor newScheduled(int poolSize, String threadName) { + return new ScheduledThreadPoolExecutor(poolSize, (Runnable r) -> { + SecurityManager s = System.getSecurityManager(); + ThreadGroup group = (s != null) ? s.getThreadGroup() : + Thread.currentThread().getThreadGroup(); + Thread t = new Thread(group, r, + threadName, + 0); + if (t.isDaemon()) { + t.setDaemon(false); + } + if (t.getPriority() != Thread.NORM_PRIORITY) { + t.setPriority(Thread.NORM_PRIORITY); + } + return t; + }); + } + +} diff --git a/dao/src/main/java/cc/iotkit/dao/AligenieProductDao.java b/dao/src/main/java/cc/iotkit/dao/AligenieProductDao.java deleted file mode 100755 index 2a1d648e..00000000 --- a/dao/src/main/java/cc/iotkit/dao/AligenieProductDao.java +++ /dev/null @@ -1,28 +0,0 @@ -package cc.iotkit.dao; - -import cc.iotkit.model.aligenie.AligenieProduct; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.data.domain.Example; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.stereotype.Repository; - -@Repository -public class AligenieProductDao extends BaseDao { - - private final AligenieProductRepository aligenieProductRepository; - - @Autowired - public AligenieProductDao(MongoTemplate mongoTemplate, - AligenieProductRepository aligenieProductRepository) { - super(mongoTemplate, AligenieProduct.class); - this.aligenieProductRepository = aligenieProductRepository; - } - - @Cacheable(value = "cache_getAligenieProduct", key = "'getAligenieProduct'+#pk", unless = "#result == null") - public AligenieProduct getAligenieProduct(String pk) { - return aligenieProductRepository.findOne(Example.of( - AligenieProduct.builder().productKey(pk).build() - )).orElse(null); - } -} diff --git a/dao/src/main/java/cc/iotkit/dao/BaseDao.java b/dao/src/main/java/cc/iotkit/dao/BaseDao.java deleted file mode 100755 index 96773013..00000000 --- a/dao/src/main/java/cc/iotkit/dao/BaseDao.java +++ /dev/null @@ -1,59 +0,0 @@ -package cc.iotkit.dao; - -import org.springframework.data.domain.Sort; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.query.Criteria; -import org.springframework.data.mongodb.core.query.Query; - -import java.util.List; - -import static org.springframework.data.mongodb.core.query.Criteria.where; -import static org.springframework.data.mongodb.core.query.Query.query; - -public class BaseDao { - - protected MongoTemplate mongoTemplate; - - private Class cls; - - public BaseDao(MongoTemplate mongoTemplate, Class cls) { - this.mongoTemplate = mongoTemplate; - this.cls = cls; - } - - public List find(Criteria condition) { - Query query = new Query(); - query.addCriteria(condition); - return mongoTemplate.find(query, cls); - } - - public List find(Criteria condition, long skip, int count, Sort.Order order) { - Query query = new Query(); - query.addCriteria(condition) - .with(Sort.by(order)) - .skip(skip) - .limit(count); - return mongoTemplate.find(query, cls); - } - - public long count(Criteria condition) { - Query query = new Query(); - query.addCriteria(condition); - return mongoTemplate.count(query, cls); - } - - public T save(String id, T entity) { - if (id == null) { - return mongoTemplate.save(entity); - } else { - mongoTemplate.updateFirst(query(where("_id").is(id)), - DaoTool.update(entity), entity.getClass()); - return (T) mongoTemplate.findById(id, entity.getClass()); - } - } - - public T save(T entity) { - return mongoTemplate.save(entity); - } - -} diff --git a/dao/src/main/java/cc/iotkit/dao/DeviceCache.java b/dao/src/main/java/cc/iotkit/dao/DeviceCache.java index 524487e4..7464b4fb 100755 --- a/dao/src/main/java/cc/iotkit/dao/DeviceCache.java +++ b/dao/src/main/java/cc/iotkit/dao/DeviceCache.java @@ -4,24 +4,14 @@ import cc.iotkit.common.Constants; import cc.iotkit.model.device.DeviceInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.Cacheable; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.query.Query; import org.springframework.stereotype.Repository; -import static org.springframework.data.mongodb.core.query.Criteria.where; -import static org.springframework.data.mongodb.core.query.Query.query; - @Repository -public class DeviceCache extends BaseDao { +public class DeviceCache { @Autowired private DeviceRepository deviceRepository; - @Autowired - public DeviceCache(MongoTemplate mongoTemplate) { - super(mongoTemplate, DeviceInfo.class); - } - @Cacheable(value = Constants.DEVICE_CACHE, key = "#pk+'_'+#dn") public DeviceInfo findByProductKeyAndDeviceName(String pk, String dn) { return deviceRepository.findByProductKeyAndDeviceName(pk, dn); diff --git a/dao/src/main/java/cc/iotkit/dao/DeviceDao.java b/dao/src/main/java/cc/iotkit/dao/DeviceDao.java new file mode 100644 index 00000000..dc281f01 --- /dev/null +++ b/dao/src/main/java/cc/iotkit/dao/DeviceDao.java @@ -0,0 +1,44 @@ +package cc.iotkit.dao; + +import cc.iotkit.model.Paging; +import cc.iotkit.model.device.DeviceInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.data.mongodb.core.query.Update; +import org.springframework.stereotype.Repository; + +import java.util.Map; + +@Repository +public class DeviceDao { + + @Autowired + private MongoTemplate mongoTemplate; + + public Paging find(Criteria condition, int size, int page) { + Query query = Query.query(condition); + return new Paging<>( + mongoTemplate.count(query, DeviceInfo.class), + mongoTemplate.find( + query.with(PageRequest.of(page-1, size, Sort.by(Sort.Order.desc("createAt")))) + , DeviceInfo.class) + ); + } + + /** + * 更新设备属性 + */ + public void updateProperties(String deviceId, Map properties) { + Query query = Query.query(new Criteria().and("deviceId").is(deviceId)); + Update update = new Update(); + for (String key : properties.keySet()) { + update.set("property." + key, properties.get(key)); + } + mongoTemplate.updateFirst(query, update, DeviceInfo.class); + } + +} diff --git a/dao/src/main/java/cc/iotkit/dao/DeviceEventDao.java b/dao/src/main/java/cc/iotkit/dao/DeviceEventDao.java deleted file mode 100755 index 15e9e56f..00000000 --- a/dao/src/main/java/cc/iotkit/dao/DeviceEventDao.java +++ /dev/null @@ -1,15 +0,0 @@ -package cc.iotkit.dao; - -import cc.iotkit.model.device.message.DeviceEvent; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.stereotype.Repository; - -@Repository -public class DeviceEventDao extends BaseDao { - - @Autowired - public DeviceEventDao(MongoTemplate mongoTemplate) { - super(mongoTemplate, DeviceEvent.class); - } -} diff --git a/dao/src/main/java/cc/iotkit/dao/DevicePropertyDao.java b/dao/src/main/java/cc/iotkit/dao/DevicePropertyDao.java new file mode 100644 index 00000000..91d1650a --- /dev/null +++ b/dao/src/main/java/cc/iotkit/dao/DevicePropertyDao.java @@ -0,0 +1,40 @@ +package cc.iotkit.dao; + +import cc.iotkit.model.device.message.DeviceProperty; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.search.sort.FieldSortBuilder; +import org.elasticsearch.search.sort.SortOrder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; +import org.springframework.data.elasticsearch.core.SearchHit; +import org.springframework.data.elasticsearch.core.SearchHits; +import org.springframework.data.elasticsearch.core.query.NativeSearchQuery; +import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.stream.Collectors; + +@Repository +public class DevicePropertyDao { + + @Autowired + private ElasticsearchRestTemplate template; + + public List findDevicePropertyHistory(String deviceId, String name, long start, long end) { + NativeSearchQuery query = new NativeSearchQueryBuilder() + .withQuery( + QueryBuilders.boolQuery() + .must(QueryBuilders.termQuery("deviceId", deviceId)) + .must(QueryBuilders.termQuery("name", name)) + .must(QueryBuilders.rangeQuery("time") + .from(start, true).to(end, true)) + ) + .withSorts(new FieldSortBuilder("time").order(SortOrder.ASC)) + .build(); + SearchHits result = template.search(query, DeviceProperty.class); + return result.getSearchHits().stream() + .map(SearchHit::getContent).collect(Collectors.toList()); + } + +} diff --git a/dao/src/main/java/cc/iotkit/dao/DevicePropertyRepository.java b/dao/src/main/java/cc/iotkit/dao/DevicePropertyRepository.java new file mode 100755 index 00000000..3300b370 --- /dev/null +++ b/dao/src/main/java/cc/iotkit/dao/DevicePropertyRepository.java @@ -0,0 +1,11 @@ +package cc.iotkit.dao; + +import cc.iotkit.model.device.message.DeviceProperty; +import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface DevicePropertyRepository extends ElasticsearchRepository { + + +} diff --git a/dao/src/main/java/cc/iotkit/dao/DeviceRepository.java b/dao/src/main/java/cc/iotkit/dao/DeviceRepository.java index 334e0f3d..14a98cd2 100755 --- a/dao/src/main/java/cc/iotkit/dao/DeviceRepository.java +++ b/dao/src/main/java/cc/iotkit/dao/DeviceRepository.java @@ -4,6 +4,8 @@ import cc.iotkit.model.device.DeviceInfo; import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface DeviceRepository extends MongoRepository { @@ -11,4 +13,6 @@ public interface DeviceRepository extends MongoRepository { DeviceInfo findByDeviceId(String deviceId); + List findByParentId(String parentId); + } diff --git a/dao/src/main/java/cc/iotkit/dao/ThingModelMessageDao.java b/dao/src/main/java/cc/iotkit/dao/ThingModelMessageDao.java new file mode 100644 index 00000000..2b06157f --- /dev/null +++ b/dao/src/main/java/cc/iotkit/dao/ThingModelMessageDao.java @@ -0,0 +1,45 @@ +package cc.iotkit.dao; + +import cc.iotkit.model.Paging; +import cc.iotkit.model.device.message.ThingModelMessage; +import org.apache.commons.lang3.StringUtils; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; +import org.springframework.data.elasticsearch.core.SearchHit; +import org.springframework.data.elasticsearch.core.SearchHits; +import org.springframework.data.elasticsearch.core.query.NativeSearchQuery; +import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; +import org.springframework.stereotype.Repository; + +import java.util.stream.Collectors; + +@Repository +public class ThingModelMessageDao { + + @Autowired + private ElasticsearchRestTemplate template; + + public Paging findByTypeAndIdentifier(String deviceId, String type, + String identifier, + int page, int size) { + BoolQueryBuilder builder = QueryBuilders.boolQuery(); + builder.must(QueryBuilders.termQuery("deviceId", deviceId)); + if (StringUtils.isNotBlank(type)) { + builder.must(QueryBuilders.termQuery("type", type)); + } + if (StringUtils.isNotBlank(identifier)) { + builder.must(QueryBuilders.matchPhraseQuery("identifier", identifier)); + } + NativeSearchQuery query = new NativeSearchQueryBuilder().withQuery(builder) + .withPageable(PageRequest.of(page, size, Sort.by(Sort.Order.desc("time")))) + .build(); + SearchHits result = template.search(query, ThingModelMessage.class); + return new Paging<>(result.getTotalHits(), result.getSearchHits().stream() + .map(SearchHit::getContent).collect(Collectors.toList())); + } + +} diff --git a/dao/src/main/java/cc/iotkit/dao/ThingModelMessageRepository.java b/dao/src/main/java/cc/iotkit/dao/ThingModelMessageRepository.java index c865fbdd..5e95e53d 100755 --- a/dao/src/main/java/cc/iotkit/dao/ThingModelMessageRepository.java +++ b/dao/src/main/java/cc/iotkit/dao/ThingModelMessageRepository.java @@ -1,9 +1,14 @@ package cc.iotkit.dao; import cc.iotkit.model.device.message.ThingModelMessage; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; import org.springframework.stereotype.Repository; @Repository public interface ThingModelMessageRepository extends ElasticsearchRepository { + + Page findByTypeAndIdentifier(String type, String identifier, Pageable pageable); + } diff --git a/dao/src/main/java/cc/iotkit/dao/UserInfoDao.java b/dao/src/main/java/cc/iotkit/dao/UserInfoDao.java deleted file mode 100755 index 0b9b2151..00000000 --- a/dao/src/main/java/cc/iotkit/dao/UserInfoDao.java +++ /dev/null @@ -1,15 +0,0 @@ -package cc.iotkit.dao; - -import cc.iotkit.model.UserInfo; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.stereotype.Repository; - -@Repository -public class UserInfoDao extends BaseDao { - - @Autowired - public UserInfoDao(MongoTemplate mongoTemplate) { - super(mongoTemplate, UserInfo.class); - } -} diff --git a/device-server/.DS_Store b/device-server/.DS_Store deleted file mode 100755 index b021504d786d6df4fce72479620e1e8ee2da60a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHMTWl0n7(U;&z>FQ}v=%5UunQ{`v4LVM*MLh~5TupLF0=)t%P?fkf?#X?ObNl-jv2J>@6-eAshau<0= ziU@%Sfe3*Jfe3*JfvW)l+Ov6+F0=0oYt%;wL*B?d$|*^}IzWIB|?LW*z(5zY`^8DWKj;OZ2Y z4BQ#gLPmXrK!m`>2=L`ImibI$F6%F=-+#>wTBheWHGPX%Mdg^W<0SdID!FPxRn^^@ zoz76k*ZhLls=0mY)QqVcInC`hb$@5puvb||(XiLM9hz^rTex%9aV&BWV=cGIG=}=r zx;Dr5HPbfSAfL#wwcE6HXQuQ9oI(W0itWJ~kHefwltn$oa(!?wZ$PrmTtp~J7ee(bow0O5Ot)rj+v{sfIi z0b+T@Ht|6t_F)N-(-#1ujE}Ebd&fGZv&YOkcE-HV=u@jbn(|sY?Q)GGO|?7kScL)G z>r-p;nw2kDgv(0H;?AV2_VTV{SzV52`le&|_V~sgzm#Z{sb{n2xPDuZtWQ-7p0UB8 zTxQW|r;L=UmS1iCAW!3MGF*>jD%~U|C%-vi^3)l#=FV?fvZC!|wOUiF)G3p?i>7Dh zEMwyke|Ei^mp5$PwEH*H)3AMWhiSNS4Ki}p)&`7|wQ5au{gimTr;s!6DVYAfYD$ts zuIcfltiC60)#*+;9i2z&fh9gYexoF9;rce$pkAnzhWJggs!3UoP!K5^m3gx2$=Th+ z01>)CX_i!7-e_q#!xE~6%3?`fCwCXc^n`MmvRtY`qui5s1_tQ9J)us=TP5`~X&b+G zhvxa~2MwDp&u7s-Js$7n`jxtF=#nI*N)$+?=ZIk{-6#gZ++~&TQPbFLwwU&$EZe~x zwx2!04zMHaDEo+g&c0@6*bnSyc8;BAzp>xJAfpy_n21S8Ac>hsp$SW{6w7csx^NdV z$f6fHcYOVc_L(0cY&PwP_?IG3-ln>cB5a@O2=&5M_} zj?kd&$&VuEg^UbHC|DM-uf#6FdSd(yQ>Q73jl@f1Px(qItsr$AXP|VFd(W7eNT{58 z;&gUHLQz4hLk_GrH;^?J+U7Trt%4SUu(jN(B-Am)c@eo}siLTrv?zpi#cgCAOY|4k zwsx{IzC7iB=kGtV_bYaq{lv~8hH)5Atc??6=U^UMumY>G2J6s)PHaLCHe(C65?}ja zVpqV~V!+w`cn}ZaVPfu6cpA^*IXsU8#M@VK2#4_&-o`rtgOB249K&&(z$f?u-{5C^bbkY)4?Zmb diff --git a/device-server/device-api/pom.xml b/device-server/device-api/pom.xml deleted file mode 100755 index d10955a6..00000000 --- a/device-server/device-api/pom.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - device-server - cc.iotkit - 0.0.1-SNAPSHOT - - 4.0.0 - - device-api - - - - - org.springframework.cloud - spring-cloud-openfeign-core - - - org.springframework - spring-web - - - org.projectlombok - lombok - compile - - - cc.iotkit - model - - - - \ No newline at end of file diff --git a/device-server/device-api/src/main/java/cc/iotkit/deviceapi/IDeviceManager.java b/device-server/device-api/src/main/java/cc/iotkit/deviceapi/IDeviceManager.java deleted file mode 100755 index 8e8087c7..00000000 --- a/device-server/device-api/src/main/java/cc/iotkit/deviceapi/IDeviceManager.java +++ /dev/null @@ -1,44 +0,0 @@ -package cc.iotkit.deviceapi; - -import cc.iotkit.model.device.DeviceInfo; -import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.stereotype.Component; -import org.springframework.web.bind.annotation.*; - -import java.util.Map; - -@Component -@FeignClient(value = "iot-device-manager",url = "localhost:8091") -public interface IDeviceManager { - - /** - * 设备注册 - */ - @PostMapping("/register") - @ResponseBody - DeviceInfo register(@RequestParam("parentId") String parentId, - @RequestParam("productKey") String productKey, - @RequestParam("deviceName") String deviceName, - @RequestParam("model") String model); - - /** - * 解绑子设备 - */ - @PostMapping("/{deviceId}/unbind") - void unbind(@PathVariable("deviceId") String deviceId); - - /** - * 设置属性 - */ - @PostMapping("/{deviceId}/property/set") - String setProperty(@PathVariable("deviceId") String deviceId, - @RequestBody Map properties); - - /** - * 调用服务 - */ - @PostMapping("/{deviceId}/{identifier}/invoke") - String invokeService(@PathVariable("deviceId") String deviceId, - @PathVariable("identifier") String identifier, - @RequestBody Map properties); -} diff --git a/device-server/device-api/src/main/java/cc/iotkit/deviceapi/IDeviceService.java b/device-server/device-api/src/main/java/cc/iotkit/deviceapi/IDeviceService.java deleted file mode 100755 index d98a44b3..00000000 --- a/device-server/device-api/src/main/java/cc/iotkit/deviceapi/IDeviceService.java +++ /dev/null @@ -1,16 +0,0 @@ -package cc.iotkit.deviceapi; - -import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.stereotype.Component; -import org.springframework.web.bind.annotation.*; - -@Component -@FeignClient(value = "iot-device-service", url = "localhost:8091") -public interface IDeviceService { - - /** - * 调用服务 - */ - @PostMapping("/invoke") - String invoke(@RequestBody Service service); -} diff --git a/device-server/device-api/src/main/java/cc/iotkit/deviceapi/Service.java b/device-server/device-api/src/main/java/cc/iotkit/deviceapi/Service.java deleted file mode 100755 index 7501e1b8..00000000 --- a/device-server/device-api/src/main/java/cc/iotkit/deviceapi/Service.java +++ /dev/null @@ -1,31 +0,0 @@ -package cc.iotkit.deviceapi; - -import lombok.Data; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@Data -public class Service { - - private String device; - - private String identifier; - - private List inputData; - - public Map parseInputData() { - Map data = new HashMap<>(); - for (Parameter p : inputData) { - data.put(p.getIdentifier(), p.getValue()); - } - return data; - } - - @Data - public static class Parameter { - private String identifier; - private Object value; - } -} diff --git a/device-server/mqtt-server/.DS_Store b/device-server/mqtt-server/.DS_Store deleted file mode 100755 index a3c148ab93c7cf32694845be75a6aeb0e3f13311..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}V4z5bhpFO$jtL1)mXJuM$2klGVIN>0 zK(D&{9_mB*BHpd)?h%I3qszKfLG@RuuBuMH4*kOzu2#+b_(vp^ARHZ*St_M=Wn z&3F*Gs*x}m^}Cl*Rzwrg>MWfc9vWv`Chpj%A`EO;KQQGAVAw;bd)Cj zw!5%dF-VbF5>R2oOk8{PRZP{&iaWL?{dJW-u z&0#|fHa40KvF?2v4sF|7THQJL-uwCM`sViT_n-R*JqsLuSS4Q!j^GiDF+#3_GS7}=!4+z((fI5|%D+br;;1?#&H&|)Z>5Qw9p^h1un;QyOqk~_laK?R&)Di>4 zz&Ha_`q9PxfBXIW|9BET5d*})f5iZ=Zv|T|_$0HpPJA5hwF2}U6b0idjjt(SsI3@c eaVuT~RRVs22B2@S(g+?9ItVBls38XaDg!TZMq*_E diff --git a/device-server/mqtt-server/pom.xml b/device-server/mqtt-server/pom.xml deleted file mode 100755 index 6289248d..00000000 --- a/device-server/mqtt-server/pom.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - - device-server - cc.iotkit - 0.0.1-SNAPSHOT - - 4.0.0 - - mqtt-server - - - - - org.springframework.boot - spring-boot-starter-web - - - - org.projectlombok - lombok - true - - - - commons-codec - commons-codec - - - - org.bouncycastle - bcprov-jdk15on - - - - org.eclipse.paho - org.eclipse.paho.client.mqttv3 - - - - cc.iotkit - model - - - - cc.iotkit - common - - - - cc.iotkit - device-api - - - - cc.iotkit - gateway-client - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - - - - - - \ No newline at end of file diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/Application.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/Application.java deleted file mode 100755 index 25c2b9fc..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/Application.java +++ /dev/null @@ -1,12 +0,0 @@ -package cc.iotkit.server.mqtt; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/config/AutobeanConfig.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/config/AutobeanConfig.java deleted file mode 100755 index 41fe6042..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/config/AutobeanConfig.java +++ /dev/null @@ -1,19 +0,0 @@ -package cc.iotkit.server.mqtt.config; - -import cc.iotkit.protocol.client.DeviceBehaviourClient; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class AutobeanConfig { - - @Value("${gateway.server:}") - private String gatewayServer; - - @Bean - public DeviceBehaviourClient getDeviceBehaviourClient() { - return new DeviceBehaviourClient(gatewayServer); - } - -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/controller/DeviceController.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/controller/DeviceController.java deleted file mode 100755 index e2e1b2b0..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/controller/DeviceController.java +++ /dev/null @@ -1,47 +0,0 @@ -package cc.iotkit.server.mqtt.controller; - -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.protocol.DeviceGateway; -import cc.iotkit.protocol.DeviceMessage; -import cc.iotkit.protocol.OtaInfo; -import cc.iotkit.protocol.Result; -import cc.iotkit.server.mqtt.service.MqttManager; -import lombok.Data; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RestController; - -@Slf4j -@RestController -public class DeviceController implements DeviceGateway { - - @Autowired - private MqttManager mqttManager; - - @Override - public Result sendMessage(DeviceMessage msg) { - try { - MqttMessage mqttMessage = JsonUtil.parse(msg.getContent(), MqttMessage.class); - mqttManager.sendMsg(mqttMessage.getTopic(), mqttMessage.getPayload()); - return new Result(true, ""); - } catch (Throwable e) { - log.error("send message error", e); - return new Result(false, e.getMessage()); - } - } - - @Override - public Result sendOta(OtaInfo ota) { - return null; - } - - @Data - public static class MqttMessage { - - private String topic; - - private String payload; - - } - -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/controller/MqttAuthController.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/controller/MqttAuthController.java deleted file mode 100755 index a9b82d6b..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/controller/MqttAuthController.java +++ /dev/null @@ -1,63 +0,0 @@ -package cc.iotkit.server.mqtt.controller; - - -import cc.iotkit.common.Constants; -import cc.iotkit.common.utils.CodecUtil; -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.server.mqtt.model.EmqAcl; -import cc.iotkit.server.mqtt.model.EmqAuthInfo; -import cc.iotkit.server.mqtt.service.DeviceAuthService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; - -import javax.servlet.http.HttpServletResponse; - -@Slf4j -@RestController -public class MqttAuthController { - - @Autowired - private DeviceAuthService deviceAuthService; - - @PostMapping("/mqtt/auth") - public void auth(@RequestBody EmqAuthInfo auth) { - log.info("mqtt auth:" + JsonUtil.toJsonString(auth)); - String clientId = auth.getClientid(); - if (isSupperUser(clientId)) { - return; - } - deviceAuthService.auth(auth); - } - - @PostMapping("/mqtt/acl") - public void acl(@RequestBody EmqAcl acl) { - log.info("mqtt acl:{}", JsonUtil.toJsonString(acl)); - if (isSupperUser(acl.getClientid())) { - return; - } - deviceAuthService.acl(acl); - log.info("topic:{}, acl success", acl.getTopic()); - } - - @PostMapping("/mqtt/superuser") - public void superuser(@RequestBody EmqAcl acl, HttpServletResponse response) { - response.setStatus(HttpServletResponse.SC_BAD_GATEWAY); - } - - public boolean isSupperUser(String clientId) { - try { - if (!clientId.startsWith("su_")) { - return false; - } - clientId = clientId.replaceFirst("su_", ""); - return CodecUtil.aesDecrypt(clientId, Constants.PRODUCT_SECRET).startsWith("admin_"); - } catch (Throwable e) { - log.error("aesDecrypt error.", e); - return false; - } - } - -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/handler/DisconnectedHandler.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/handler/DisconnectedHandler.java deleted file mode 100755 index 4a9206ef..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/handler/DisconnectedHandler.java +++ /dev/null @@ -1,41 +0,0 @@ -package cc.iotkit.server.mqtt.handler; - -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.protocol.client.DeviceBehaviourClient; -import com.fasterxml.jackson.core.type.TypeReference; -import lombok.Data; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Slf4j -@Component -public class DisconnectedHandler { - - @Autowired - private DeviceBehaviourClient behaviourClient; - - public void handler(String msg) { - Disconnected disconnected = JsonUtil.parse(msg, new TypeReference() { - }); - String clientId = disconnected.getClientid(); - String[] parts = clientId.split("_"); - if (parts.length < 2) { - return; - } - String pk = parts[0]; - String dn = parts[1]; - behaviourClient.offline(pk, dn); - log.info("client disconnected, offline,pk:{},dn:{}", pk, dn); - } - - @Data - private static class Disconnected { - private String reason; - private String clientid; - private String username; - private String peername; - private String sockname; - } - -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/EmqAcl.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/EmqAcl.java deleted file mode 100755 index f4cdbee4..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/EmqAcl.java +++ /dev/null @@ -1,19 +0,0 @@ -package cc.iotkit.server.mqtt.model; - -import lombok.Data; - -@Data -public class EmqAcl { - - private String access; - - private String username; - - private String clientid; - - private String ipaddr; - - private String protocol; - - private String topic; -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/EmqAuthInfo.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/EmqAuthInfo.java deleted file mode 100755 index 1ca3f4d5..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/EmqAuthInfo.java +++ /dev/null @@ -1,18 +0,0 @@ -package cc.iotkit.server.mqtt.model; - -import lombok.Data; - -@Data -public class EmqAuthInfo { - - private String clientid; - - private String password; - - private String username; - - private String ipaddress; - - private String protocol; - -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/Request.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/Request.java deleted file mode 100755 index 1b365b70..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/Request.java +++ /dev/null @@ -1,17 +0,0 @@ -package cc.iotkit.server.mqtt.model; - - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -@JsonIgnoreProperties(ignoreUnknown = true) -public class Request { - protected String id; - - protected T params; -} \ No newline at end of file diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/Response.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/Response.java deleted file mode 100755 index 5a9d9421..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/model/Response.java +++ /dev/null @@ -1,25 +0,0 @@ -package cc.iotkit.server.mqtt.model; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class Response { - - private String id; - - private int code; - - private T data; - - public static Empty empty() { - return new Empty(); - } - - @Data - public static class Empty { - } -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/service/DeviceAuthService.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/service/DeviceAuthService.java deleted file mode 100755 index b1fc8142..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/service/DeviceAuthService.java +++ /dev/null @@ -1,71 +0,0 @@ -package cc.iotkit.server.mqtt.service; - -import cc.iotkit.common.Constants; -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.protocol.RegisterInfo; -import cc.iotkit.protocol.Result; -import cc.iotkit.protocol.client.DeviceBehaviourClient; -import cc.iotkit.server.mqtt.model.EmqAcl; -import cc.iotkit.server.mqtt.model.EmqAuthInfo; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.codec.digest.DigestUtils; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Slf4j -@Component -public class DeviceAuthService { - - @Autowired - private DeviceBehaviourClient behaviourClient; - - public void auth(EmqAuthInfo auth) { - String clientId = auth.getClientid(); - String[] pkDnAndModel = getPkDnAndModel(clientId); - - String hmac = DigestUtils.md5Hex(Constants.PRODUCT_SECRET + clientId); - if (!hmac.equalsIgnoreCase(auth.getPassword())) { - throw new RuntimeException("password is illegal."); - } - - String pk = pkDnAndModel[0]; - String dn = pkDnAndModel[1]; - String model = pkDnAndModel[2]; - - Result result = behaviourClient.register(new RegisterInfo(pk, dn, model)); - log.info("register result:{}", JsonUtil.toJsonString(result)); - } - - public void acl(EmqAcl acl) { - String[] pkDn = getPkDnFromTopic(acl.getTopic()); - String pk = pkDn[2]; - String dn = pkDn[3]; - behaviourClient.online(pk, dn); - } - - private String[] getPkDnAndModel(String clientId) { - if (StringUtils.isBlank(clientId)) { - throw new RuntimeException("clientId is blank."); - } - clientId += "_"; - - String[] pkDnAndModel = clientId.split("_", -1); - if (pkDnAndModel.length < 3) { - throw new RuntimeException("clientId is illegal."); - } - return pkDnAndModel; - } - - private String[] getPkDnFromTopic(String topic) { - if (StringUtils.isBlank(topic)) { - throw new RuntimeException("topic is blank."); - } - - String[] pkDn = topic.split("/", -1); - if (pkDn.length < 4) { - throw new RuntimeException("topic is illegal."); - } - return pkDn; - } -} diff --git a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/service/MqttManager.java b/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/service/MqttManager.java deleted file mode 100755 index 5c9b6a3a..00000000 --- a/device-server/mqtt-server/src/main/java/cc/iotkit/server/mqtt/service/MqttManager.java +++ /dev/null @@ -1,256 +0,0 @@ -package cc.iotkit.server.mqtt.service; - -import cc.iotkit.common.Constants; -import cc.iotkit.common.utils.CodecUtil; -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.protocol.DeviceMessage; -import cc.iotkit.protocol.RegisterInfo; -import cc.iotkit.protocol.client.DeviceBehaviourClient; -import cc.iotkit.server.mqtt.handler.DisconnectedHandler; -import cc.iotkit.server.mqtt.model.Request; -import cc.iotkit.server.mqtt.model.Response; -import com.fasterxml.jackson.core.type.TypeReference; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.eclipse.paho.client.mqttv3.*; -import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -import java.util.Collections; -import java.util.HashMap; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -@Slf4j -@Component -public class MqttManager implements MqttCallback, IMqttMessageListener { - - @Value("${mqtt.url}") - private String url; - - @Value(("${spring.profiles.active:}")) - private String env; - - private MqttClient mqttClient; - - @Autowired - private DisconnectedHandler disconnectedHandler; - @Autowired - private DeviceBehaviourClient behaviourClient; - - public MqttManager() { - ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); - executorService.scheduleWithFixedDelay(this::createClient, 1, 3, TimeUnit.SECONDS); - } - - private MqttConnectOptions getMqttConnectOptions() { - MqttConnectOptions options = new MqttConnectOptions(); - // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录, - // 这里设置为true表示每次连接到服务器都以新的身份连接 - options.setCleanSession(true); - // 设置连接的用户名 - options.setUserName("admin"); - // 设置连接的密码 - options.setPassword("password".toCharArray()); - options.setServerURIs(StringUtils.split(url, ",")); - // 设置超时时间 单位为秒 - options.setConnectionTimeout(10); - // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送心跳判断客户端是否在线,但这个方法并没有重连的机制 - options.setKeepAliveInterval(20); - return options; - } - - @SneakyThrows - private void createClient() { - try { - if (mqttClient == null) { - MemoryPersistence persistence = new MemoryPersistence(); - String clientId = "mqtt-server-consumer-" + env; - clientId = "su_" + CodecUtil.aesEncrypt("admin_" + clientId, Constants.PRODUCT_SECRET); - mqttClient = new MqttClient(url, clientId, persistence); - mqttClient.setCallback(this); - } - if (mqttClient.isConnected()) { - return; - } - connect(); - } catch (Throwable e) { - log.error("create mqttClient error", e); - } - } - - private void connect() { - try { - log.info("Connecting to broker:{} ", url); - IMqttToken mqttToken = mqttClient.connectWithResult(getMqttConnectOptions()); - if (mqttToken.isComplete()) { - log.info("connect mqtt-broker success"); - } else { - log.error("connect mqtt-broker failed", mqttToken.getException()); - } - IMqttToken response = mqttClient.subscribeWithResponse( - new String[]{"/sys/+/+/s/#", "/sys/session/topic/unsubscribed", "/sys/client/disconnected"}); - if (response.isComplete()) { - log.info("subscribe topics success"); - } else { - log.error("subscribe topics failed", mqttToken.getException()); - } - } catch (Throwable e) { - log.error("connect to mqtt-broker error", e); - } - } - - @SneakyThrows - @Override - public void connectionLost(Throwable e) { - log.error("mqtt connection lost", e); - while (true) { - try { - Thread.sleep(1000); - if (mqttClient.isConnected()) { - mqttClient.disconnect(); - } - connect(); - break; - } catch (Throwable e1) { - log.error("connect error,retry...", e1); - } - } - } - - @Override - public void messageArrived(String topic, MqttMessage mqttMessage) { - handleMessage(topic, mqttMessage); - } - - @Override - public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) { - } - - public void handleMessage(String topic, MqttMessage msg) { - log.info("receive msg,topic:{},msg:{}", topic, JsonUtil.toJsonString(msg)); - if (topic == null) { - log.error("message topic is null."); - return; - } - int code = 0; - String mid = ""; - - try { - String payload = new String(msg.getPayload()); - - //取消订阅 - if (topic.equals("/sys/session/topic/unsubscribed")) { - topicUnsubscribed(payload); - return; - } - - //连接断开 - if (topic.equals("/sys/client/disconnected")) { - disconnectedHandler.handler(payload); - return; - } - - String[] parts = topic.split("/"); - if (parts.length < 5) { - log.error("message topic is illegal."); - return; - } - String productKey = parts[2]; - String deviceName = parts[3]; - - //子设备注册 - if (topic.endsWith("/register")) { - RegisterRequest registerRequest = JsonUtil.parse(payload, RegisterRequest.class); - mid = registerRequest.getId(); - - RegisterInfo registerInfo = RegisterInfo.builder() - .productKey(productKey) - .deviceName(deviceName) - .subDevices(Collections.singletonList(registerRequest.getParams())) - .build(); - behaviourClient.register(registerInfo); - return; - } - - Request request = JsonUtil.parse(payload, Request.class); - mid = request.getId(); - MqtMsg mqtMsg = new MqtMsg(topic, request); - - behaviourClient.messageReport(DeviceMessage.builder() - .productKey(productKey) - .deviceName(deviceName) - .mid(request.getId()) - .content(JsonUtil.toJsonString(mqtMsg)) - .build()); - - } catch (Throwable e) { - log.error("message process error", e); - code = 500; - } finally { - reply(topic, mid, code); - } - - } - - @SneakyThrows - private void reply(String topic, String id, int code) { - //回复消息不需要再回复 - if (topic.endsWith("_reply")) { - return; - } - - topic = topic.replace("/s/", "/c/") + "_reply"; - String msg = JsonUtil.toJsonString(new Response<>(id, code, new HashMap<>())); - mqttClient.publish(topic, new MqttMessage(msg.getBytes())); - } - - private void topicUnsubscribed(String msg) { - Unsubscribed unsubscribed = JsonUtil.parse(msg, new TypeReference() { - }); - String topic = unsubscribed.getTopic(); - String[] parts = topic.split("/"); - if (parts.length < 4) { - return; - } - - log.info("device offline,pk:{},dn:{}", parts[2], parts[3]); - behaviourClient.offline(parts[2], parts[3]); - } - - @SneakyThrows - public void sendMsg(String topic, String msg) { - mqttClient.publish(topic, new MqttMessage(msg.getBytes())); - } - - @Data - private static class Unsubscribed { - private String clientid; - private String username; - private String topic; - private String peerhost; - } - - public static class RegisterRequest extends Request { - - } - - @Data - @NoArgsConstructor - @AllArgsConstructor - private static class MqtMsg { - - private String topic; - - private Object payload; - - } - -} diff --git a/device-server/mqtt-server/src/main/resources/application-dev.yml b/device-server/mqtt-server/src/main/resources/application-dev.yml deleted file mode 100755 index 63e3cdec..00000000 --- a/device-server/mqtt-server/src/main/resources/application-dev.yml +++ /dev/null @@ -1,17 +0,0 @@ -server: - port: 8091 - -spring: - data: - mongodb: - uri: mongodb://填写mongodb地址/admin - database: iotkit - - cache: - cache-names: foo,bar - caffeine: - spec: maximumSize=5000,expireAfterAccess=120s - -mqtt: - url: tcp://填写mqtt连接地址 - diff --git a/device-server/mqtt-server/src/main/resources/application.yml b/device-server/mqtt-server/src/main/resources/application.yml deleted file mode 100755 index 5b877471..00000000 --- a/device-server/mqtt-server/src/main/resources/application.yml +++ /dev/null @@ -1,16 +0,0 @@ -server: - port: 8091 - -spring: - data: - mongodb: - uri: mongodb://填写mongodb地址/admin - database: iotkit - - cache: - cache-names: foo,bar - caffeine: - spec: maximumSize=5000,expireAfterAccess=120s - -mqtt: - url: tcp://填写mqtt连接地址 diff --git a/device-server/mqtt-server/src/main/resources/logback-spring.xml b/device-server/mqtt-server/src/main/resources/logback-spring.xml deleted file mode 100755 index 6322c4b5..00000000 --- a/device-server/mqtt-server/src/main/resources/logback-spring.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - DEBUG - - - ${CONSOLE_LOG_PATTERN} - utf8 - - - - - - ${LOG_FILE}/info.log - - ${LOG_FILE}/info.%d{yyyy-MM-dd}.%i.gz - - 5 - - 20GB - - - 1GB - - - - ${CONSOLE_LOG_PATTERN} - utf8 - - - - - - ${LOG_FILE}/error.log - - ${LOG_FILE}/error.%d{yyyy-MM-dd}.%i.gz - - 5 - - 5GB - - - 1GB - - - - ${CONSOLE_LOG_PATTERN} - utf8 - - - ERROR - ACCEPT - DENY - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/device-server/pom.xml b/device-server/pom.xml deleted file mode 100755 index 6693a251..00000000 --- a/device-server/pom.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - iotkit-parent - cc.iotkit - 0.0.1-SNAPSHOT - - 4.0.0 - - device-server - pom - - mqtt-server - device-api - mqtt-client-simulator - - - - \ No newline at end of file diff --git a/manager/pom.xml b/manager/pom.xml index f6678ab9..bd0aaef7 100755 --- a/manager/pom.xml +++ b/manager/pom.xml @@ -129,11 +129,6 @@ common - - cc.iotkit - device-api - - cc.iotkit rule-engine @@ -144,11 +139,6 @@ dao - - cc.iotkit - protocol-server - - cc.iotkit component-server diff --git a/manager/src/main/java/cc/iotkit/manager/controller/AppController.java b/manager/src/main/java/cc/iotkit/manager/controller/AppController.java index b9a16536..c54d5d98 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/AppController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/AppController.java @@ -5,9 +5,9 @@ import cc.iotkit.dao.CategoryRepository; import cc.iotkit.dao.ProductRepository; import cc.iotkit.manager.model.vo.AppDesignVo; import cc.iotkit.manager.service.DataOwnerService; +import cc.iotkit.model.Paging; import cc.iotkit.model.product.AppDesign; import cc.iotkit.model.product.Category; -import cc.iotkit.model.PagingData; import cc.iotkit.model.product.Product; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -37,7 +37,7 @@ public class AppController { private DataOwnerService dataOwnerService; @PostMapping("/designs") - public PagingData getDesigns() { + public Paging getDesigns() { List appDesignVos = new ArrayList<>(); List products = productRepository.findAll(Example @@ -64,7 +64,7 @@ public class AppController { } }); - return new PagingData<>(appDesignRepository.count(), + return new Paging<>(appDesignRepository.count(), appDesignVos); } diff --git a/manager/src/main/java/cc/iotkit/manager/controller/DbBaseController.java b/manager/src/main/java/cc/iotkit/manager/controller/DbBaseController.java deleted file mode 100755 index fdebab1d..00000000 --- a/manager/src/main/java/cc/iotkit/manager/controller/DbBaseController.java +++ /dev/null @@ -1,32 +0,0 @@ -package cc.iotkit.manager.controller; - -import org.springframework.data.mongodb.repository.MongoRepository; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; - -import java.util.List; - -public class DbBaseController, T> { - - protected final R repository; - - public DbBaseController(R r) { - this.repository = r; - } - - @GetMapping("/list") - public List list() { - return repository.findAll(); - } - - @PostMapping("/save") - public void save(T t) { - repository.save(t); - } - - @DeleteMapping("/delete") - public void delete(T t) { - repository.delete(t); - } -} diff --git a/manager/src/main/java/cc/iotkit/manager/controller/DeviceController.java b/manager/src/main/java/cc/iotkit/manager/controller/DeviceController.java index 5d6359d4..b9adba84 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/DeviceController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/DeviceController.java @@ -1,21 +1,18 @@ package cc.iotkit.manager.controller; -import cc.iotkit.dao.DeviceCache; -import cc.iotkit.dao.DeviceEventDao; -import cc.iotkit.dao.DeviceEventRepository; -import cc.iotkit.dao.DeviceRepository; +import cc.iotkit.dao.*; import cc.iotkit.manager.service.DataOwnerService; import cc.iotkit.manager.service.DeviceService; import cc.iotkit.manager.utils.AuthUtil; -import cc.iotkit.model.device.message.DeviceEvent; +import cc.iotkit.model.Paging; import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.model.PagingData; +import cc.iotkit.model.device.message.DeviceProperty; +import cc.iotkit.model.device.message.ThingModelMessage; import cc.iotkit.model.product.ThingModel; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Example; -import org.springframework.data.domain.Sort; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.web.bind.annotation.*; @@ -32,15 +29,15 @@ public class DeviceController { @Autowired private DeviceRepository deviceRepository; @Autowired - private DeviceEventRepository deviceEventRepository; - @Autowired - private DeviceEventDao deviceEventDao; - @Autowired - private DeviceCache deviceCache; + private DeviceDao deviceDao; @Autowired private DataOwnerService dataOwnerService; @Autowired private ProductController productController; + @Autowired + private ThingModelMessageDao thingModelMessageDao; + @Autowired + private DevicePropertyDao devicePropertyDao; @PostMapping("/{deviceId}/service/{service}") public String invokeService(@PathVariable("deviceId") String deviceId, @@ -60,11 +57,11 @@ public class DeviceController { } @PostMapping("/list") - public PagingData getDevices(int page, - int limit, - String pk, - Boolean online, - String dn) { + public Paging getDevices(int page, + int size, + String pk, + Boolean online, + String dn) { Criteria condition = new Criteria(); if (!AuthUtil.isAdmin()) { condition.and("uid").is(AuthUtil.getUserId()); @@ -78,8 +75,8 @@ public class DeviceController { if (online != null) { condition.and("state.online").is(online); } - return new PagingData<>(deviceCache.count(condition), - deviceCache.find(condition, (page - 1) * limit, limit, Sort.Order.desc("createAt"))); + + return deviceDao.find(condition, size, page); } @GetMapping("/{deviceId}/children") @@ -112,29 +109,28 @@ public class DeviceController { deviceRepository.deleteById(deviceId); } - @PostMapping("/{deviceId}/events") - public PagingData events(@PathVariable("deviceId") String deviceId, - int page, - int limit, - String type, - String identifier) { - Criteria condition = Criteria.where("deviceId").is(deviceId); - if (StringUtils.isNotBlank(type)) { - condition.and("type").is(type); - } - if (StringUtils.isNotBlank(identifier)) { - condition.and("identifier").regex(".*" + identifier + ".*"); - } + @PostMapping("/{deviceId}/logs/{size}/{page}") + public Paging logs( + @PathVariable("deviceId") String deviceId, + @PathVariable("size") int size, + @PathVariable("page") int page, + String type, String identifier) { + return thingModelMessageDao.findByTypeAndIdentifier(deviceId, type, identifier, page, size); + } - return new PagingData<>(deviceEventDao.count(condition), - deviceEventDao.find(condition, - (page - 1) * limit, limit, Sort.Order.desc("createAt"))); + @GetMapping("/{deviceId}/property/{name}/{start}/{end}") + public List getPropertyHistory( + @PathVariable("deviceId") String deviceId, + @PathVariable("name") String name, + @PathVariable("start") long start, + @PathVariable("end") long end) { + return devicePropertyDao.findDevicePropertyHistory(deviceId, name, start, end); } @PostMapping("/{deviceId}/unbind") public void unbindDevice(@PathVariable("deviceId") String deviceId) { deviceId = getDetail(deviceId).getDeviceId(); - deviceService.unbindDevice(deviceId); +// deviceService.unbindDevice(deviceId); } @GetMapping("/{deviceId}/thingModel") diff --git a/manager/src/main/java/cc/iotkit/manager/controller/ProductController.java b/manager/src/main/java/cc/iotkit/manager/controller/ProductController.java index 005c46f2..1d7e28f5 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/ProductController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/ProductController.java @@ -6,8 +6,8 @@ import cc.iotkit.dao.ProductRepository; import cc.iotkit.dao.ThingModelRepository; import cc.iotkit.manager.config.AliyunConfig; import cc.iotkit.manager.service.DataOwnerService; +import cc.iotkit.model.Paging; import cc.iotkit.model.product.Category; -import cc.iotkit.model.PagingData; import cc.iotkit.model.product.Product; import cc.iotkit.model.product.ThingModel; import com.aliyun.oss.OSS; @@ -42,9 +42,9 @@ public class ProductController { private OSS ossClient; @PostMapping("/list") - public PagingData getProducts(Product form) { + public Paging getProducts(Product form) { form = dataOwnerService.wrapExample(form); - return new PagingData<>(productRepository.count(Example.of(form)), + return new Paging<>(productRepository.count(Example.of(form)), productRepository.findAll(Example.of(form))); } diff --git a/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java b/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java index 7e1edd7f..03a02fdc 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java @@ -2,6 +2,7 @@ package cc.iotkit.manager.controller; import cc.iotkit.common.exception.BizException; import cc.iotkit.common.utils.ReflectUtil; +import cc.iotkit.comp.CompConfig; import cc.iotkit.comp.mqtt.MqttComponent; import cc.iotkit.comps.ComponentManager; import cc.iotkit.converter.ScriptConverter; @@ -12,7 +13,6 @@ import cc.iotkit.manager.utils.AuthUtil; import cc.iotkit.model.Paging; import cc.iotkit.model.UserInfo; import cc.iotkit.model.protocol.ProtocolGateway; -import cc.iotkit.protocol.server.service.GatewayService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FileUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -22,7 +22,6 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.web.bind.annotation.*; -import javax.annotation.PostConstruct; import java.io.File; import java.io.IOException; import java.util.Optional; @@ -38,9 +37,6 @@ public class ProtocolController { @Autowired private ProtocolGatewayRepository gatewayRepository; - @Autowired - private GatewayService gatewayService; - @Autowired private DataOwnerService dataOwnerService; @@ -66,7 +62,6 @@ public class ProtocolController { gateway.setCreateAt(System.currentTimeMillis()); gateway.setUid(AuthUtil.getUserId()); gateway.setUuid(optUser.get().getUid()); - gatewayService.saveFunction(gateway.getUuid(), gateway.getId(), gateway.getScript(), functionJar); gatewayRepository.save(gateway); } catch (Throwable e) { throw new BizException("add protocol gateway error", e); @@ -89,7 +84,6 @@ public class ProtocolController { dataOwnerService.checkOwner(gateway); try { gatewayRepository.save(gateway); - gatewayService.saveFunction(gateway.getUuid(), gateway.getId(), gateway.getScript(), functionJar); } catch (Throwable e) { throw new BizException("add protocol gateway error", e); } @@ -105,8 +99,8 @@ public class ProtocolController { ProtocolGateway oldGateway = optGateway.get(); oldGateway.setScript(gateway.getScript()); try { - gatewayService.saveFunction(oldGateway.getUuid(), oldGateway.getId(), - "new (function (){" + oldGateway.getScript() + "})()", functionJar); +// gatewayService.saveFunction(oldGateway.getUuid(), oldGateway.getId(), +// "new (function (){" + oldGateway.getScript() + "})()", functionJar); gatewayRepository.save(oldGateway); } catch (Throwable e) { throw new BizException("save protocol gateway script error", e); @@ -118,7 +112,6 @@ public class ProtocolController { dataOwnerService.checkOwner(gatewayRepository, id); try { gatewayRepository.deleteById(id); - gatewayService.deleteFunction(AuthUtil.getUserId(), id); } catch (Throwable e) { throw new BizException("delete protocol gateway error", e); } @@ -136,7 +129,7 @@ public class ProtocolController { @GetMapping("/registerMqtt") public void registerMqtt() throws IOException { MqttComponent component = new MqttComponent(); - component.create("{\"port\":2883,\"ssl\":false}"); + component.create(new CompConfig(300, "{\"port\":2883,\"ssl\":false}")); ScriptConverter converter = new ScriptConverter(); converter.setScript(FileUtils.readFileToString(new File("/Users/sjg/home/gitee/open-source/converter.js"), "UTF-8")); component.setConverter(converter); diff --git a/manager/src/main/java/cc/iotkit/manager/controller/SpaceController.java b/manager/src/main/java/cc/iotkit/manager/controller/SpaceController.java index e95f07fd..fc63f838 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/SpaceController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/SpaceController.java @@ -23,8 +23,6 @@ import java.util.stream.Collectors; @RequestMapping("/space") public class SpaceController { - @Autowired - private UserInfoDao userInfoDao; @Autowired private SpaceDeviceRepository spaceDeviceRepository; @Autowired @@ -34,24 +32,24 @@ public class SpaceController { @Autowired private ProductCache productCache; - @PostMapping("/list") - public PagingData getDevices(int page, - int limit, - String address) { - Criteria condition = new Criteria(); - if (StringUtils.isNotBlank(address)) { - condition.and("address").regex(".*" + address + ".*"); - } - List userInfoList = userInfoDao.find(condition, (page - 1) * limit, - limit, Sort.Order.desc("createAt")); - - List spaces = userInfoList.stream().map((u -> - new SpaceInfo(u.getAddress(), u.getUid()))) - .collect(Collectors.toList()); - - return new PagingData<>(userInfoDao.count(condition), - spaces); - } +// @PostMapping("/list") +// public Paging getDevices(int page, +// int limit, +// String address) { +// Criteria condition = new Criteria(); +// if (StringUtils.isNotBlank(address)) { +// condition.and("address").regex(".*" + address + ".*"); +// } +// List userInfoList = userInfoDao.find(condition, (page - 1) * limit, +// limit, Sort.Order.desc("createAt")); +// +// List spaces = userInfoList.stream().map((u -> +// new SpaceInfo(u.getAddress(), u.getUid()))) +// .collect(Collectors.toList()); +// +// return new Paging<>(userInfoDao.count(condition), +// spaces); +// } @GetMapping("/{userId}/devices") public List getDevices(@PathVariable("userId") String userId) { @@ -65,7 +63,7 @@ public class SpaceController { .name(sd.getName()) .picUrl(product.getImg()) .spaceName(sd.getSpaceName()) - .online(deviceInfo.getState().getOnline()) + .online(deviceInfo.getState().isOnline()) .property(deviceInfo.getProperty()) .productKey(deviceInfo.getProductKey()) .build()); diff --git a/manager/src/main/java/cc/iotkit/manager/controller/UserAccountController.java b/manager/src/main/java/cc/iotkit/manager/controller/UserAccountController.java deleted file mode 100755 index 72a04306..00000000 --- a/manager/src/main/java/cc/iotkit/manager/controller/UserAccountController.java +++ /dev/null @@ -1,18 +0,0 @@ -package cc.iotkit.manager.controller; - -import cc.iotkit.dao.UserAccountRepository; -import cc.iotkit.model.UserAccount; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/userAccount") -public class UserAccountController extends DbBaseController { - - @Autowired - public UserAccountController(UserAccountRepository userAccountRepository) { - super(userAccountRepository); - } - -} diff --git a/manager/src/main/java/cc/iotkit/manager/controller/UserInfoController.java b/manager/src/main/java/cc/iotkit/manager/controller/UserInfoController.java index 07e1f132..ff2b1d81 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/UserInfoController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/UserInfoController.java @@ -4,7 +4,6 @@ import cc.iotkit.common.Constants; import cc.iotkit.common.exception.BizException; import cc.iotkit.common.utils.ReflectUtil; import cc.iotkit.dao.UserInfoRepository; -import cc.iotkit.manager.service.AligenieService; import cc.iotkit.manager.service.KeycloakAdminService; import cc.iotkit.manager.service.PulsarAdminService; import cc.iotkit.manager.utils.AuthUtil; @@ -21,25 +20,21 @@ import java.util.UUID; @RestController @RequestMapping("/user") -public class UserInfoController extends DbBaseController { +public class UserInfoController { @Value("${app.systemRole}") private String systemRole; private final KeycloakAdminService keycloakAdminService; private final UserInfoRepository userInfoRepository; - private final AligenieService aligenieService; private final PulsarAdminService pulsarAdminService; @Autowired public UserInfoController(UserInfoRepository userInfoRepository, KeycloakAdminService keycloakAdminService, - AligenieService aligenieService, PulsarAdminService pulsarAdminService) { - super(userInfoRepository); this.keycloakAdminService = keycloakAdminService; this.userInfoRepository = userInfoRepository; - this.aligenieService = aligenieService; this.pulsarAdminService = pulsarAdminService; } @@ -113,11 +108,5 @@ public class UserInfoController extends DbBaseController { - - @Autowired - public AligenieDeviceController(AligenieDeviceRepository aligenieDeviceRepository) { - super(aligenieDeviceRepository); - } - -} diff --git a/manager/src/main/java/cc/iotkit/manager/controller/aligenie/AligenieProductController.java b/manager/src/main/java/cc/iotkit/manager/controller/aligenie/AligenieProductController.java index a14982da..8a5a62ce 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/aligenie/AligenieProductController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/aligenie/AligenieProductController.java @@ -1,14 +1,12 @@ package cc.iotkit.manager.controller.aligenie; -import cc.iotkit.dao.AligenieProductDao; import cc.iotkit.dao.AligenieProductRepository; import cc.iotkit.dao.ProductCache; -import cc.iotkit.manager.controller.DbBaseController; import cc.iotkit.manager.model.aligenie.AligenieProductVo; import cc.iotkit.manager.service.DataOwnerService; import cc.iotkit.manager.utils.AuthUtil; -import cc.iotkit.model.product.Product; import cc.iotkit.model.aligenie.AligenieProduct; +import cc.iotkit.model.product.Product; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Example; import org.springframework.web.bind.annotation.GetMapping; @@ -21,28 +19,20 @@ import java.util.List; @RestController @RequestMapping("/aligenie/product") -public class AligenieProductController extends DbBaseController { - - private final ProductCache productCache; - private final AligenieProductDao aligenieProductDao; - private final DataOwnerService dataOwnerService; - +public class AligenieProductController { @Autowired - public AligenieProductController(AligenieProductRepository aligenieProductRepository, - ProductCache productCache, - AligenieProductDao aligenieProductDao, - DataOwnerService dataOwnerService) { - super(aligenieProductRepository); - this.productCache = productCache; - this.aligenieProductDao = aligenieProductDao; - this.dataOwnerService = dataOwnerService; - } + private ProductCache productCache; + @Autowired + private DataOwnerService dataOwnerService; + @Autowired + private AligenieProductRepository aligenieProductRepository; + @GetMapping("/products") public List products() { List productVos = new ArrayList<>(); - List aligenieProducts = repository + List aligenieProducts = aligenieProductRepository .findAll(Example .of(AligenieProduct.builder() .uid(AuthUtil.getUserId()) @@ -61,7 +51,7 @@ public class AligenieProductController extends DbBaseController() : deviceInfo.getProperty()) .productKey(deviceInfo.getProductKey()) .build(); diff --git a/manager/src/main/java/cc/iotkit/manager/model/vo/DeviceLog.java b/manager/src/main/java/cc/iotkit/manager/model/vo/DeviceLog.java new file mode 100644 index 00000000..82a0b7cf --- /dev/null +++ b/manager/src/main/java/cc/iotkit/manager/model/vo/DeviceLog.java @@ -0,0 +1,9 @@ +package cc.iotkit.manager.model.vo; + +import lombok.Data; + +@Data +public class DeviceLog { + + +} diff --git a/manager/src/main/java/cc/iotkit/manager/service/AligenieService.java b/manager/src/main/java/cc/iotkit/manager/service/AligenieService.java deleted file mode 100755 index 6228bbbe..00000000 --- a/manager/src/main/java/cc/iotkit/manager/service/AligenieService.java +++ /dev/null @@ -1,90 +0,0 @@ -package cc.iotkit.manager.service; - -import cc.iotkit.dao.AligenieDeviceRepository; -import cc.iotkit.dao.AligenieProductDao; -import cc.iotkit.dao.DeviceCache; -import cc.iotkit.dao.SpaceDeviceRepository; -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.model.space.SpaceDevice; -import cc.iotkit.model.UserInfo; -import cc.iotkit.model.aligenie.AligenieDevice; -import cc.iotkit.model.aligenie.AligenieProduct; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Example; -import org.springframework.stereotype.Service; - -import java.util.List; - -@Service -public class AligenieService { - - @Autowired - private SpaceDeviceRepository spaceDeviceRepository; - - @Autowired - private AligenieDeviceRepository aligenieDeviceRepository; - - @Autowired - private AligenieProductDao aligenieProductDao; - - @Autowired - private DeviceCache deviceCache; - - public void syncDevice(UserInfo user) { - if (!user.getUsePlatforms().isAligenie()) { - //清空 - List aligenieDevices = aligenieDeviceRepository.findAll(Example.of( - AligenieDevice.builder() - .uid(user.getId()) - .build())); - for (AligenieDevice aligenieDevice : aligenieDevices) { - aligenieDeviceRepository.delete(aligenieDevice); - } - return; - } - - //找出用户空间下所有设备 - List spaceDeviceList = spaceDeviceRepository.findAll(Example.of( - SpaceDevice.builder().uid(user.getId()).build() - )); - - for (SpaceDevice spaceDevice : spaceDeviceList) { - AligenieDevice aligenieDevice = aligenieDeviceRepository.findOne(Example.of( - AligenieDevice.builder() - .deviceId(spaceDevice.getDeviceId()) - .uid(user.getId()) - .build() - )).orElse(null); - - //不存在设备,新增 - if (aligenieDevice == null) { - DeviceInfo deviceInfo = deviceCache.findByDeviceId(spaceDevice.getDeviceId()); - AligenieProduct aligenieProduct = aligenieProductDao.getAligenieProduct(deviceInfo.getProductKey()); - if(aligenieProduct==null){ - continue; - } - - aligenieDeviceRepository.save( - AligenieDevice.builder() - .uid(user.getId()) - .deviceId(spaceDevice.getDeviceId()) - .name(spaceDevice.getName()) - .spaceName(spaceDevice.getSpaceName()) - .productId(aligenieProduct.getProductId()) - .build() - ); - } else { - //存在,更新设备信息 - aligenieDeviceRepository.save( - AligenieDevice.builder() - .id(aligenieDevice.getId()) - .name(spaceDevice.getName()) - .spaceName(spaceDevice.getSpaceName()) - .build() - ); - } - - } - } - -} diff --git a/manager/src/main/java/cc/iotkit/manager/service/DeviceService.java b/manager/src/main/java/cc/iotkit/manager/service/DeviceService.java index 70448a0f..14cdd9f2 100755 --- a/manager/src/main/java/cc/iotkit/manager/service/DeviceService.java +++ b/manager/src/main/java/cc/iotkit/manager/service/DeviceService.java @@ -1,48 +1,49 @@ package cc.iotkit.manager.service; +import cc.iotkit.common.exception.BizException; import cc.iotkit.common.exception.NotFoundException; -import cc.iotkit.dao.DeviceCache; -import cc.iotkit.dao.DeviceEventRepository; +import cc.iotkit.common.utils.UniqueIdUtil; +import cc.iotkit.comps.ComponentManager; +import cc.iotkit.converter.ThingService; import cc.iotkit.dao.DeviceRepository; -import cc.iotkit.dao.ThingModelRepository; -import cc.iotkit.deviceapi.IDeviceManager; import cc.iotkit.model.device.DeviceInfo; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; +import cc.iotkit.model.device.message.ThingModelMessage; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Example; import org.springframework.stereotype.Service; -import java.util.List; import java.util.Map; @Slf4j @Service public class DeviceService { - @Autowired - private DeviceCache deviceCache; @Autowired private DeviceRepository deviceRepository; @Autowired - private ThingModelRepository thingModelRepository; - @Autowired - private ThingModelService thingModelService; - @Autowired - private DeviceEventRepository deviceEventRepository; - @Autowired private DataOwnerService dataOwnerService; @Autowired - private IDeviceManager deviceManager; + private ComponentManager componentManager; public String invokeService(String deviceId, String service, Map args) { DeviceInfo device = deviceRepository.findById(deviceId) .orElseThrow(() -> new NotFoundException("device not found by deviceId")); dataOwnerService.checkOwner(device); - return this.deviceManager.invokeService(deviceId, service, args); + if (!device.getState().isOnline()) { + throw new BizException("device is offline"); + } + + ThingService thingService = ThingService.builder() + .mid(UniqueIdUtil.newRequestId()) + .productKey(device.getProductKey()) + .deviceName(device.getDeviceName()) + .type(ThingModelMessage.TYPE_SERVICE) + .identifier(service) + .params(args) + .build(); + componentManager.send(thingService); + return thingService.getMid(); } public String setProperty(String deviceId, Map properties) { @@ -50,26 +51,20 @@ public class DeviceService { .orElseThrow(() -> new NotFoundException("device not found by deviceId")); dataOwnerService.checkOwner(device); - return deviceManager.setProperty(deviceId, properties); + if (!device.getState().isOnline()) { + throw new BizException("device is offline"); + } + + ThingService thingService = ThingService.builder() + .mid(UniqueIdUtil.newRequestId()) + .productKey(device.getProductKey()) + .deviceName(device.getDeviceName()) + .type(ThingModelMessage.TYPE_PROPERTY) + .identifier("set") + .params(properties) + .build(); + componentManager.send(thingService); + return thingService.getMid(); } - public void unbindDevice(String deviceId) { - deviceManager.unbind(deviceId); - } - - public List findDevices(DeviceInfo form) { - return deviceRepository.findAll(Example.of(form)); - } - - public long count(DeviceInfo form) { - return deviceRepository.count(Example.of(form)); - } - - @Data - @NoArgsConstructor - @AllArgsConstructor - private static class CmdRequest { - private String id; - private Object params; - } } diff --git a/manager/src/main/java/cc/iotkit/manager/service/SpaceDeviceService.java b/manager/src/main/java/cc/iotkit/manager/service/SpaceDeviceService.java index e450aac5..4bec68b2 100755 --- a/manager/src/main/java/cc/iotkit/manager/service/SpaceDeviceService.java +++ b/manager/src/main/java/cc/iotkit/manager/service/SpaceDeviceService.java @@ -41,7 +41,7 @@ public class SpaceDeviceService { .name(sd.getName()) .picUrl(product.getImg()) .spaceName(sd.getSpaceName()) - .online(deviceInfo.getState().getOnline()) + .online(deviceInfo.getState().isOnline()) .property(deviceInfo.getProperty()) .productKey(deviceInfo.getProductKey()) .build()); diff --git a/model/src/main/java/cc/iotkit/model/PagingData.java b/model/src/main/java/cc/iotkit/model/PagingData.java deleted file mode 100755 index 30637bf9..00000000 --- a/model/src/main/java/cc/iotkit/model/PagingData.java +++ /dev/null @@ -1,18 +0,0 @@ -package cc.iotkit.model; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.List; - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class PagingData { - - private long count; - - private List data; - -} diff --git a/model/src/main/java/cc/iotkit/model/device/DeviceInfo.java b/model/src/main/java/cc/iotkit/model/device/DeviceInfo.java index 4b1b01dc..d9babfa6 100755 --- a/model/src/main/java/cc/iotkit/model/device/DeviceInfo.java +++ b/model/src/main/java/cc/iotkit/model/device/DeviceInfo.java @@ -51,11 +51,12 @@ public class DeviceInfo implements Owned { @AllArgsConstructor public static class State { - private Boolean online; + private boolean online; private Long onlineTime; private Long offlineTime; } + } diff --git a/model/src/main/java/cc/iotkit/model/device/message/DeviceProperty.java b/model/src/main/java/cc/iotkit/model/device/message/DeviceProperty.java new file mode 100644 index 00000000..53acacf8 --- /dev/null +++ b/model/src/main/java/cc/iotkit/model/device/message/DeviceProperty.java @@ -0,0 +1,29 @@ +package cc.iotkit.model.device.message; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.Id; +import org.springframework.data.elasticsearch.annotations.Document; +import org.springframework.data.elasticsearch.annotations.Field; +import org.springframework.data.elasticsearch.annotations.FieldType; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Document(indexName = "device_property") +public class DeviceProperty { + + @Id + private String mid; + + private String deviceId; + + private String name; + + private Object value; + + @Field(type = FieldType.Date) + private Long time; + +} diff --git a/model/src/main/java/cc/iotkit/model/device/message/ThingModelMessage.java b/model/src/main/java/cc/iotkit/model/device/message/ThingModelMessage.java index f984a941..937aa734 100755 --- a/model/src/main/java/cc/iotkit/model/device/message/ThingModelMessage.java +++ b/model/src/main/java/cc/iotkit/model/device/message/ThingModelMessage.java @@ -21,22 +21,28 @@ import java.util.Map; @Document(indexName = "thing_model_messages") public class ThingModelMessage { - public static final String TYPE_PROPERTY="property"; - public static final String TYPE_EVENT="event"; - public static final String TYPE_SERVICE="service"; + public static final String TYPE_LIFETIME = "lifetime"; + public static final String TYPE_STATE = "state"; + public static final String TYPE_PROPERTY = "property"; + public static final String TYPE_EVENT = "event"; + public static final String TYPE_SERVICE = "service"; - public static final String ID_PROPERTY_GET="get"; - public static final String ID_PROPERTY_SET="set"; + public static final String ID_PROPERTY_GET = "get"; + public static final String ID_PROPERTY_SET = "set"; @Id private String mid; + private String deviceId; + private String productKey; private String deviceName; /** * 消息类型 + * lifetime:生命周期 + * state:状态 * property:属性 * event:事件 * service:服务 @@ -45,13 +51,18 @@ public class ThingModelMessage { private String identifier; - private Map data; + /** + * 消息状态码 + */ + private int code; + + private Object data; /** * 时间戳,设备上的事件或数据产生的本地时间 */ @Field(type = FieldType.Date) - private Long occur; + private Long occurred; /** * 消息上报时间 diff --git a/pom.xml b/pom.xml index 14ab8abc..b9873bf3 100755 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,6 @@ 4.0.0 pom - device-server model rule-engine common @@ -181,13 +180,13 @@ io.vertx - vertx-web + vertx-mqtt 4.2.6 io.vertx - vertx-mqtt + vertx-web-proxy 4.2.6 @@ -209,36 +208,12 @@ ${project.version} - - cc.iotkit - device-api - ${project.version} - - cc.iotkit rule-engine ${project.version} - - cc.iotkit - gateway-client - ${project.version} - - - - cc.iotkit - decode-function - ${project.version} - - - - cc.iotkit - protocol-server - ${project.version} - - cc.iotkit component diff --git a/protocol-gateway/component-server/pom.xml b/protocol-gateway/component-server/pom.xml index 8def08ce..3fc4ffbb 100755 --- a/protocol-gateway/component-server/pom.xml +++ b/protocol-gateway/component-server/pom.xml @@ -3,10 +3,9 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - iotkit-parent + protocol-gateway cc.iotkit 0.0.1-SNAPSHOT - ../../pom.xml 4.0.0 @@ -34,6 +33,15 @@ spring-context + + org.springframework.data + spring-data-redis + + + redis.clients + jedis + + org.slf4j slf4j-api diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentManager.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentManager.java index 3662ffd6..2a60e15b 100755 --- a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentManager.java +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentManager.java @@ -1,14 +1,24 @@ package cc.iotkit.comps; +import cc.iotkit.common.exception.BizException; +import cc.iotkit.common.utils.JsonUtil; import cc.iotkit.comp.IComponent; +import cc.iotkit.comps.config.CacheKey; import cc.iotkit.comps.service.DeviceBehaviourService; +import cc.iotkit.converter.DeviceMessage; +import cc.iotkit.converter.ThingService; +import cc.iotkit.model.device.message.ThingModelMessage; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.TimeUnit; +@Slf4j @Component public class ComponentManager { @@ -16,6 +26,8 @@ public class ComponentManager { @Autowired private DeviceBehaviourService deviceBehaviourService; + @Autowired + private StringRedisTemplate redisTemplate; public void register(String id, IComponent component) { components.put(id, component); @@ -31,8 +43,10 @@ public class ComponentManager { if (component == null) { return; } - component.setHandler(new MessageHandler(script, component.getConverter(), - deviceBehaviourService)); + component.setHandler( + new MessageHandler(this, component, + script, component.getConverter(), + deviceBehaviourService)); component.start(); } @@ -44,4 +58,42 @@ public class ComponentManager { component.stop(); } + public void send(ThingService service) { + log.info("start exec device service:{}", JsonUtil.toJsonString(service)); + if (components.size() == 0) { + throw new BizException("there is no components"); + } + + for (IComponent com : components.values()) { + if (com.exist(service.getProductKey(), service.getDeviceName())) { + DeviceMessage message = com.getConverter().encode(service, null); + if (message == null) { + throw new BizException("encode send message failed"); + } + //保存设备端mid与平台mid对应关系 + redisTemplate.opsForValue().set( + CacheKey.getKeyCmdMid(service.getDeviceName(), message.getMid()), + service.getMid(), com.getConfig().getCmdTimeout(), TimeUnit.SECONDS); + com.send(message); + + ThingModelMessage thingModelMessage = ThingModelMessage.builder() + .mid(service.getMid()) + .productKey(service.getProductKey()) + .deviceName(service.getDeviceName()) + .identifier(service.getIdentifier()) + .type(service.getType()) + .data(service.getParams()) + .build(); + deviceBehaviourService.reportMessage(thingModelMessage); + + return; + } + } + throw new BizException("send destination not found"); + } + + public String getPlatformMid(String deviceName, String mid) { + return redisTemplate.opsForValue().get(CacheKey.getKeyCmdMid(deviceName, mid)); + } + } diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/MessageHandler.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/MessageHandler.java index b5393850..1c61dec1 100755 --- a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/MessageHandler.java +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/MessageHandler.java @@ -1,13 +1,18 @@ package cc.iotkit.comps; import cc.iotkit.common.exception.BizException; +import cc.iotkit.common.utils.JsonUtil; +import cc.iotkit.common.utils.UniqueIdUtil; +import cc.iotkit.comp.IComponent; import cc.iotkit.comp.IMessageHandler; -import cc.iotkit.comp.model.DeviceMessage; -import cc.iotkit.comps.model.AuthInfo; -import cc.iotkit.comps.model.DeviceState; -import cc.iotkit.comps.model.RegisterInfo; +import cc.iotkit.comp.model.AuthInfo; +import cc.iotkit.comp.model.ReceiveResult; +import cc.iotkit.comp.model.RegisterInfo; +import cc.iotkit.converter.DeviceMessage; +import cc.iotkit.comp.model.DeviceState; import cc.iotkit.comps.service.DeviceBehaviourService; import cc.iotkit.converter.IConverter; +import cc.iotkit.model.device.message.ThingModelMessage; import jdk.nashorn.api.scripting.NashornScriptEngine; import jdk.nashorn.api.scripting.ScriptObjectMirror; import lombok.Data; @@ -30,32 +35,32 @@ public class MessageHandler implements IMessageHandler { private final DeviceBehaviourService deviceBehaviourService; + private final ComponentManager componentManager; + + private final IComponent component; + @SneakyThrows - public MessageHandler(String script, IConverter converter, + public MessageHandler(ComponentManager componentManager, + IComponent component, + String script, IConverter converter, DeviceBehaviourService deviceBehaviourService) { + this.componentManager = componentManager; + this.component = component; this.converter = converter; this.deviceBehaviourService = deviceBehaviourService; scriptObj = engine.eval(script); } - public void register(Map head, String msg) { - } - - public void auth(Map head, String msg) { - } - - public void state(Map head, String msg) { - } - - public void onReceive(Map head, String type, String msg) { + public ReceiveResult onReceive(Map head, String type, String msg) { try { ScriptObjectMirror result = (ScriptObjectMirror) engine.invokeMethod(scriptObj, "onReceive", head, type, msg); + log.info("onReceive script result:{}", JsonUtil.toJsonString(result)); Object rstType = result.get("type"); if (rstType == null) { - return; + return null; } //取脚本执行后返回的数据 - Object data = result.get("data"); + Object data = JsonUtil.toObject((ScriptObjectMirror) result.get("data")); if (!(data instanceof Map)) { throw new BizException("script result data is incorrect"); } @@ -63,24 +68,32 @@ public class MessageHandler implements IMessageHandler { if ("register".equals(rstType)) { //注册数据 - RegisterInfo regInfo = new RegisterInfo(); - BeanUtils.populate(regInfo, dataMap); + RegisterInfo regInfo = RegisterInfo.from(dataMap); + if (regInfo == null) { + return null; + } doRegister(regInfo); + return new ReceiveResult(regInfo.getProductKey(), regInfo.getDeviceName(), regInfo); } else if ("auth".equals(rstType)) { //设备认证 AuthInfo authInfo = new AuthInfo(); BeanUtils.populate(authInfo, dataMap); doAuth(authInfo); + return new ReceiveResult(authInfo.getProductKey(), authInfo.getDeviceName(), authInfo); } else if ("state".equals(rstType)) { //设备状态变更 - DeviceState state = new DeviceState(); - BeanUtils.populate(state, dataMap); + DeviceState state = DeviceState.from(dataMap); + if (state == null) { + return null; + } doStateChange(state); + return new ReceiveResult(state.getProductKey(), state.getDeviceName(), state); } else if ("report".equals(rstType)) { //上报数据 DeviceMessage message = new DeviceMessage(); BeanUtils.populate(message, dataMap); doReport(message); + return new ReceiveResult(message.getProductKey(), message.getDeviceName(), message); } } catch (BizException e) { @@ -88,6 +101,7 @@ public class MessageHandler implements IMessageHandler { } catch (Throwable e) { throw new BizException("receive component message error", e); } + return null; } private void doRegister(RegisterInfo reg) throws ScriptException, NoSuchMethodException { @@ -115,6 +129,7 @@ public class MessageHandler implements IMessageHandler { private void doStateChange(DeviceState state) { try { + component.onDeviceStateChange(state); deviceBehaviourService.deviceStateChange(state.getProductKey(), state.getDeviceName(), DeviceState.STATE_ONLINE.equals(state.getState())); @@ -124,10 +139,20 @@ public class MessageHandler implements IMessageHandler { } private void doReport(DeviceMessage message) { - try { - deviceBehaviourService.reportMessage(message); - } catch (Throwable e) { - log.error("report device message error", e); + ThingModelMessage thingModelMessage = converter.decode(message); + + //服务回复需要重新对应mid + if (thingModelMessage.getIdentifier().endsWith("_reply")) { + String platformMid = componentManager.getPlatformMid(message.getDeviceName(), message.getMid()); + if (platformMid == null) { + platformMid = UniqueIdUtil.newRequestId(); + } + thingModelMessage.setMid(platformMid); + } else { + //其它消息重新生成唯一MID + thingModelMessage.setMid(UniqueIdUtil.newRequestId()); } + + deviceBehaviourService.reportMessage(thingModelMessage); } } diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/CacheKey.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/CacheKey.java new file mode 100644 index 00000000..115cfe82 --- /dev/null +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/CacheKey.java @@ -0,0 +1,11 @@ +package cc.iotkit.comps.config; + +public class CacheKey { + + private static final String KEY_CMD_MID = "str:cmd:mid:%s:%s"; + + public static String getKeyCmdMid(String deviceName, String downMid) { + return String.format(KEY_CMD_MID, deviceName, downMid); + } + +} diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/AuthInfo.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/AuthInfo.java deleted file mode 100755 index cce5fc36..00000000 --- a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/AuthInfo.java +++ /dev/null @@ -1,15 +0,0 @@ -package cc.iotkit.comps.model; - -import lombok.Data; - -@Data -public class AuthInfo { - - private String productKey; - - private String deviceName; - - private String productSecret; - - private String deviceSecret; -} diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/DeviceState.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/DeviceState.java deleted file mode 100755 index 150ce9cb..00000000 --- a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/DeviceState.java +++ /dev/null @@ -1,17 +0,0 @@ -package cc.iotkit.comps.model; - -import lombok.Data; - -@Data -public class DeviceState { - - public static final String STATE_ONLINE = "online"; - public static final String STATE_OFFLINE = "offline"; - - private String productKey; - - private String deviceName; - - private String state; - -} diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/RegisterInfo.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/RegisterInfo.java deleted file mode 100755 index 0cc51c19..00000000 --- a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/model/RegisterInfo.java +++ /dev/null @@ -1,49 +0,0 @@ -package cc.iotkit.comps.model; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.List; -import java.util.Map; - -/** - * 注册信息 - */ -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class RegisterInfo { - - private String productKey; - - private String deviceName; - - private String model; - - private Map tag; - - private List subDevices; - - public RegisterInfo(String productKey, String deviceName, String model) { - this.productKey = productKey; - this.deviceName = deviceName; - this.model = model; - } - - @Data - @NoArgsConstructor - @AllArgsConstructor - public static class SubDevice { - - private String productKey; - - private String deviceName; - - private String model; - - private Map tag; - } -} diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceBehaviourService.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceBehaviourService.java index ec5fd1c7..49adf445 100755 --- a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceBehaviourService.java +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceBehaviourService.java @@ -3,12 +3,15 @@ package cc.iotkit.comps.service; import cc.iotkit.common.Constants; import cc.iotkit.common.exception.BizException; import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.comp.model.DeviceMessage; +import cc.iotkit.common.utils.UniqueIdUtil; +import cc.iotkit.comp.model.RegisterInfo; +import cc.iotkit.comp.model.DeviceState; import cc.iotkit.comps.config.ServerConfig; -import cc.iotkit.comps.model.RegisterInfo; +import cc.iotkit.dao.DeviceCache; import cc.iotkit.dao.DeviceRepository; import cc.iotkit.dao.ProductRepository; import cc.iotkit.model.device.DeviceInfo; +import cc.iotkit.model.device.message.ThingModelMessage; import cc.iotkit.model.product.Product; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomUtils; @@ -23,7 +26,6 @@ import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Optional; @Slf4j @@ -36,8 +38,12 @@ public class DeviceBehaviourService { private DeviceRepository deviceRepository; @Autowired private ServerConfig serverConfig; + @Autowired + private DeviceCache deviceCache; + @Autowired + private DeviceStateHolder deviceStateHolder; - private Producer deviceMessageProducer; + private Producer deviceMessageProducer; @PostConstruct public void init() throws PulsarClientException { @@ -45,13 +51,12 @@ public class DeviceBehaviourService { PulsarClient client = PulsarClient.builder() .serviceUrl(serverConfig.getPulsarBrokerUrl()) .build(); - deviceMessageProducer = client.newProducer(JSONSchema.of(DeviceMessage.class)) - .topic("persistent://public/default/device_raw") + deviceMessageProducer = client.newProducer(JSONSchema.of(ThingModelMessage.class)) + .topic("persistent://iotkit/default/device_thing") .create(); } - public void register(RegisterInfo info) { try { DeviceInfo deviceInfo = register(null, info); @@ -66,7 +71,17 @@ public class DeviceBehaviourService { subDevice.getTag(), null)); } } - //todo 产生设备注册事件 + + //设备注册消息 + ThingModelMessage modelMessage = new ThingModelMessage( + UniqueIdUtil.newRequestId(), "", + info.getProductKey(), info.getDeviceName(), + ThingModelMessage.TYPE_LIFETIME, "register", + 0, new HashMap<>(), System.currentTimeMillis(), + System.currentTimeMillis() + ); + + reportMessage(modelMessage); } catch (BizException e) { log.error("register device error", e); throw e; @@ -86,34 +101,20 @@ public class DeviceBehaviourService { DeviceInfo device = deviceRepository.findByProductKeyAndDeviceName(pk, info.getDeviceName()); if (device != null) { - //更新设备信息 - device.setParentId(parentId); - device.setUid(uid); - Map tag = info.getTag(); - Map oldTag = device.getTag(); - - if (oldTag == null) { - oldTag = new HashMap<>(); - } - - if (tag != null) { - oldTag.putAll(tag); - } - - device.setTag(oldTag); - } else { - //不存在,注册新设备 - device = new DeviceInfo(); - device.setId(newDeviceId(info.getDeviceName())); - device.setParentId(parentId); - device.setUid(uid); - device.setDeviceId(device.getId()); - device.setProductKey(pk); - device.setDeviceName(info.getDeviceName()); - device.setTag(info.getTag()); - device.setState(new DeviceInfo.State(false, null, null)); - device.setCreateAt(System.currentTimeMillis()); + log.info("device already registered."); + return device; } + //不存在,注册新设备 + device = new DeviceInfo(); + device.setId(newDeviceId(info.getDeviceName())); + device.setParentId(parentId); + device.setUid(uid); + device.setDeviceId(device.getId()); + device.setProductKey(pk); + device.setDeviceName(info.getDeviceName()); + device.setTag(info.getTag()); + device.setState(new DeviceInfo.State(false, null, null)); + device.setCreateAt(System.currentTimeMillis()); deviceRepository.save(device); log.info("device registered:{}", JsonUtil.toJsonString(device)); @@ -171,19 +172,60 @@ public class DeviceBehaviourService { if (device == null) { throw new BizException("device does not exist"); } + deviceStateChange(device, online); + //可能是父设备,父设备离线,子设备也要离线 + if (!online && device.getParentId() == null) { + List subDevices = deviceRepository.findByParentId(device.getDeviceId()); + for (DeviceInfo subDevice : subDevices) { + deviceStateChange(subDevice, false); + } + } + } + + private void deviceStateChange(DeviceInfo device, boolean online) { if (online) { device.getState().setOnline(true); device.getState().setOnlineTime(System.currentTimeMillis()); + deviceStateHolder.online(device.getDeviceId()); } else { device.getState().setOnline(false); device.getState().setOfflineTime(System.currentTimeMillis()); + deviceStateHolder.offline(device.getDeviceId()); } deviceRepository.save(device); - //todo 产生在离线事件 + + //设备状态变更消息 + ThingModelMessage modelMessage = new ThingModelMessage( + UniqueIdUtil.newRequestId(), "", + device.getProductKey(), device.getDeviceName(), + ThingModelMessage.TYPE_STATE, + online ? DeviceState.STATE_ONLINE : DeviceState.STATE_OFFLINE, + 0, + new HashMap<>(), System.currentTimeMillis(), + System.currentTimeMillis() + ); + + reportMessage(modelMessage); } - public void reportMessage(DeviceMessage message) throws PulsarClientException { - deviceMessageProducer.send(message); + public void reportMessage(ThingModelMessage message) { + try { + DeviceInfo device = deviceCache.findByProductKeyAndDeviceName(message.getProductKey(), + message.getDeviceName()); + if (device == null) { + return; + } + if (message.getOccurred() == null) { + message.setOccurred(System.currentTimeMillis()); + } + if (message.getTime() == null) { + message.setTime(System.currentTimeMillis()); + } + message.setDeviceId(device.getDeviceId()); + deviceMessageProducer.send(message); + } catch (PulsarClientException e) { + log.error("send thing model message error", e); + } } } diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceMessageConsumer.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceMessageConsumer.java index 8a90b95b..5a727588 100755 --- a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceMessageConsumer.java +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceMessageConsumer.java @@ -3,9 +3,12 @@ package cc.iotkit.comps.service; import cc.iotkit.common.Constants; import cc.iotkit.common.utils.JsonUtil; import cc.iotkit.comps.config.ServerConfig; +import cc.iotkit.dao.DeviceDao; +import cc.iotkit.dao.DevicePropertyRepository; import cc.iotkit.dao.ThingModelMessageRepository; import cc.iotkit.dao.UserInfoRepository; import cc.iotkit.model.UserInfo; +import cc.iotkit.model.device.message.DeviceProperty; import cc.iotkit.model.device.message.ThingModelMessage; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @@ -14,6 +17,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; @Slf4j @@ -21,20 +25,21 @@ import java.util.stream.Collectors; public class DeviceMessageConsumer implements MessageListener { private final ServerConfig serverConfig; - private final ThingModelMessageRepository messageRepository; - - private final UserInfoRepository userInfoRepository; + private final DevicePropertyRepository propertyRepository; + private final DeviceDao deviceDao; @SneakyThrows @Autowired public DeviceMessageConsumer(ServerConfig serverConfig, ThingModelMessageRepository messageRepository, - UserInfoRepository userInfoRepository) { + UserInfoRepository userInfoRepository, + DevicePropertyRepository propertyRepository, + DeviceDao deviceDao) { this.serverConfig = serverConfig; this.messageRepository = messageRepository; - this.userInfoRepository = userInfoRepository; - + this.propertyRepository = propertyRepository; + this.deviceDao = deviceDao; PulsarClient client = PulsarClient.builder() .serviceUrl(this.serverConfig.getPulsarBrokerUrl()) .build(); @@ -56,14 +61,34 @@ public class DeviceMessageConsumer implements MessageListener @Override public void received(Consumer consumer, Message msg) { ThingModelMessage modelMessage = msg.getValue(); - log.info("receive message:{}", JsonUtil.toJsonString(modelMessage)); + String deviceId = modelMessage.getDeviceId(); + log.info("save message to es:{}", JsonUtil.toJsonString(modelMessage)); + //属性入库 + if (ThingModelMessage.TYPE_PROPERTY.equals(modelMessage.getType()) + && "report".equals(modelMessage.getIdentifier())) { + log.info("update device property,deviceId:{},property:{}", + deviceId, JsonUtil.toJsonString(modelMessage.getData())); + deviceDao.updateProperties(deviceId, (Map) modelMessage.getData()); + + //设备属性历史数据存储 + if (modelMessage.getData() instanceof Map) { + Map map = (Map) modelMessage.getData(); + for (Object key : map.keySet()) { + propertyRepository.save( + new DeviceProperty( + modelMessage.getMid(), + deviceId, + key.toString(), + map.get(key), + modelMessage.getOccurred() + ) + ); + } + } + } + //设备消息日志入库 messageRepository.save(modelMessage); - - messageRepository.findAll().forEach(m -> { - log.info(JsonUtil.toJsonString(m)); - }); - consumer.acknowledge(msg); } diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceStateHolder.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceStateHolder.java new file mode 100644 index 00000000..95811205 --- /dev/null +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceStateHolder.java @@ -0,0 +1,122 @@ +package cc.iotkit.comps.service; + +import cc.iotkit.common.utils.ThreadUtil; +import cc.iotkit.comps.config.ServerConfig; +import cc.iotkit.dao.DeviceRepository; +import cc.iotkit.model.device.DeviceInfo; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.pulsar.client.api.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * 设备状态维持,每1分钟更新一次心跳 + */ +@Slf4j +@Service +public class DeviceStateHolder implements MessageListener { + + private ScheduledThreadPoolExecutor stateHolderTask; + + private Set devices = new TreeSet<>(); + + @Autowired + private StringRedisTemplate redisTemplate; + @Autowired + private ServerConfig serverConfig; + @Autowired + private DeviceRepository deviceRepository; + + private Producer offlineMessageProducer; + + @PostConstruct + public void init() throws PulsarClientException { + stateHolderTask = ThreadUtil.newScheduled(4, "thread-device-state-holder"); + stateHolderTask.scheduleAtFixedRate(this::hold, 0, 1, TimeUnit.MINUTES); + + PulsarClient client = PulsarClient.builder() + .serviceUrl(this.serverConfig.getPulsarBrokerUrl()) + .build(); + + offlineMessageProducer = client.newProducer(Schema.JSON(OfflineMessage.class)) + .topic("persistent://iotkit/default/holder_offline") + .create(); + + client.newConsumer(Schema.JSON(OfflineMessage.class)) + .topic("persistent://iotkit/default/holder_offline") + .subscriptionName("holder_offline") + .consumerName("device-state-holder-consumer") + .messageListener(this).subscribe(); + } + + public void online(String deviceId) { + try { + devices.add(deviceId); + hold(deviceId); + //上线后先产生离线消息 + offlineMessageProducer.send(new OfflineMessage(deviceId)); + } catch (Throwable e) { + log.error("state holder online error", e); + } + } + + public void offline(String deviceId) { + devices.remove(deviceId); + } + + private void hold() { + //标识在线 + for (String deviceId : devices) { + hold(deviceId); + } + } + + private void hold(String deviceId) { + redisTemplate.opsForValue().set("str:device:state:holder:" + deviceId, + "1", 5, TimeUnit.SECONDS); + } + + @SneakyThrows + @Override + public void received(Consumer consumer, Message msg) { + String deviceId = msg.getValue().getDeviceId(); + //如果设备在线,不处理离线消息 + String hold = redisTemplate.opsForValue().get("str:device:state:holder:" + deviceId); + if (hold != null) { + return; + } + //如果设备不在线,则将设备更新为离线 + DeviceInfo device = deviceRepository.findByDeviceId(deviceId); + DeviceInfo.State state = device.getState(); + state.setOnline(false); + state.setOfflineTime(System.currentTimeMillis()); + deviceRepository.save(device); + log.info("device offline,deviceId:{}", deviceId); + + consumer.acknowledge(msg); + } + + @Override + public void reachedEndOfTopic(Consumer consumer) { + + } + + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class OfflineMessage { + private String deviceId; + } +} diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java index da9714f4..81e7936f 100755 --- a/protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java @@ -10,4 +10,15 @@ public abstract class AbstractComponent implements IComponent { protected IConverter converter; + protected CompConfig config; + + @Override + public void create(CompConfig config) { + this.config=config; + } + + @Override + public CompConfig getConfig() { + return config; + } } diff --git a/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/Result.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/CompConfig.java old mode 100755 new mode 100644 similarity index 56% rename from protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/Result.java rename to protocol-gateway/component/src/main/java/cc/iotkit/comp/CompConfig.java index 10479669..724c7a85 --- a/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/Result.java +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/CompConfig.java @@ -1,4 +1,4 @@ -package cc.iotkit.protocol; +package cc.iotkit.comp; import lombok.AllArgsConstructor; import lombok.Data; @@ -7,10 +7,10 @@ import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor -public class Result { +public class CompConfig { - private boolean success; + private long cmdTimeout; - private String content; + private String other; } diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/IComponent.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/IComponent.java index 0d8b4f53..110e89c5 100755 --- a/protocol-gateway/component/src/main/java/cc/iotkit/comp/IComponent.java +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/IComponent.java @@ -1,10 +1,13 @@ package cc.iotkit.comp; +import cc.iotkit.comp.model.DeviceState; +import cc.iotkit.comp.model.RegisterInfo; +import cc.iotkit.converter.DeviceMessage; import cc.iotkit.converter.IConverter; public interface IComponent { - void create(String config); + void create(CompConfig config); void start(); @@ -12,10 +15,17 @@ public interface IComponent { void destroy(); + void onDeviceStateChange(DeviceState state); + + void send(DeviceMessage message); + + boolean exist(String productKey, String deviceName); + void setHandler(IMessageHandler handler); void setConverter(IConverter converter); IConverter getConverter(); + CompConfig getConfig(); } diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/IMessageHandler.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/IMessageHandler.java index 54a7d4ec..e3eed223 100755 --- a/protocol-gateway/component/src/main/java/cc/iotkit/comp/IMessageHandler.java +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/IMessageHandler.java @@ -1,14 +1,10 @@ package cc.iotkit.comp; +import cc.iotkit.comp.model.ReceiveResult; + import java.util.Map; public interface IMessageHandler { - void register(Map head, String msg); - - void auth(Map head, String msg); - - void state(Map head, String msg); - - void onReceive(Map head, String type, String msg); + ReceiveResult onReceive(Map head, String type, String msg); } diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/AuthInfo.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/AuthInfo.java index 4aae434a..29a61d53 100755 --- a/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/AuthInfo.java +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/AuthInfo.java @@ -9,4 +9,8 @@ public class AuthInfo { private String deviceName; + private String productSecret; + + private String deviceSecret; + } diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/DeviceState.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/DeviceState.java new file mode 100755 index 00000000..bff86846 --- /dev/null +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/DeviceState.java @@ -0,0 +1,33 @@ +package cc.iotkit.comp.model; + +import cc.iotkit.common.utils.JsonUtil; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +import java.util.Map; + +@Data +@Slf4j +public class DeviceState { + + public static final String STATE_ONLINE = "online"; + public static final String STATE_OFFLINE = "offline"; + + private String productKey; + + private String deviceName; + + private String state; + + private Parent parent; + + public static DeviceState from(Map map) { + return JsonUtil.parse(JsonUtil.toJsonString(map), DeviceState.class); + } + + @Data + public static class Parent { + private String productKey; + private String deviceName; + } +} diff --git a/protocol-gateway/decode-function/src/main/java/cc/iotkit/protocol/function/DeviceMessage.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/ReceiveResult.java old mode 100755 new mode 100644 similarity index 53% rename from protocol-gateway/decode-function/src/main/java/cc/iotkit/protocol/function/DeviceMessage.java rename to protocol-gateway/component/src/main/java/cc/iotkit/comp/model/ReceiveResult.java index 1066d03d..3119ff7c --- a/protocol-gateway/decode-function/src/main/java/cc/iotkit/protocol/function/DeviceMessage.java +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/ReceiveResult.java @@ -1,25 +1,18 @@ -package cc.iotkit.protocol.function; +package cc.iotkit.comp.model; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -/** - * 设备消息 - */ @Data @NoArgsConstructor @AllArgsConstructor -@Builder -public class DeviceMessage { +public class ReceiveResult { private String productKey; private String deviceName; - private String mid; - - private String content; + private Object data; } diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/RegisterInfo.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/RegisterInfo.java index 84357c91..4decb820 100755 --- a/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/RegisterInfo.java +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/RegisterInfo.java @@ -4,13 +4,17 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.beanutils.BeanUtils; +import java.util.ArrayList; import java.util.List; import java.util.Map; /** * 注册信息 */ +@Slf4j @Data @NoArgsConstructor @AllArgsConstructor @@ -33,6 +37,38 @@ public class RegisterInfo { this.model = model; } + public RegisterInfo(String productKey, String deviceName, String subProductKey, String subDeviceName) { + this.productKey = productKey; + this.deviceName = deviceName; + if (subProductKey != null && subDeviceName != null) { + SubDevice subDevice = new SubDevice(subProductKey, subDeviceName, null, null); + subDevices = new ArrayList<>(); + subDevices.add(subDevice); + } + } + + public static RegisterInfo from(Map map) { + RegisterInfo bean = new RegisterInfo(); + try { + BeanUtils.populate(bean, map); + List subDevices = new ArrayList<>(); + List sourceSubDevices = (List) map.get("subDevices"); + if (sourceSubDevices == null) { + return bean; + } + for (Object sourceSubDevice : sourceSubDevices) { + SubDevice subDevice = new SubDevice(); + BeanUtils.populate(subDevice, (Map) sourceSubDevice); + subDevices.add(subDevice); + } + bean.setSubDevices(subDevices); + } catch (Throwable e) { + log.error("parse bean from map error", e); + return null; + } + return bean; + } + @Data @NoArgsConstructor @AllArgsConstructor @@ -46,4 +82,4 @@ public class RegisterInfo { private Map tag; } -} +} \ No newline at end of file diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/DeviceMessage.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/DeviceMessage.java similarity index 71% rename from protocol-gateway/component/src/main/java/cc/iotkit/comp/model/DeviceMessage.java rename to protocol-gateway/converter/src/main/java/cc/iotkit/converter/DeviceMessage.java index 3cc305c7..a5f3ce66 100755 --- a/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/DeviceMessage.java +++ b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/DeviceMessage.java @@ -1,4 +1,4 @@ -package cc.iotkit.comp.model; +package cc.iotkit.converter; import lombok.Data; @@ -11,5 +11,5 @@ public class DeviceMessage { private String mid; - private String content; + private Object content; } diff --git a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/DeviceService.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/DeviceService.java deleted file mode 100755 index efa87010..00000000 --- a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/DeviceService.java +++ /dev/null @@ -1,20 +0,0 @@ -package cc.iotkit.converter; - -import lombok.Data; - -@Data -public class DeviceService { - - private String mid; - - private String productKey; - - private String deviceName; - - private String type; - - private String identifier; - - private T params; - -} diff --git a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/IConverter.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/IConverter.java index 93230295..d5c208da 100755 --- a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/IConverter.java +++ b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/IConverter.java @@ -6,8 +6,8 @@ public interface IConverter { void setScript(String script); - ThingModelMessage decode(String msg); + ThingModelMessage decode(DeviceMessage msg); - String encode(DeviceService service, Device device); + DeviceMessage encode(ThingService service, Device device); } diff --git a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java index 75517bf5..8e7ec8fd 100755 --- a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java +++ b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java @@ -1,5 +1,6 @@ package cc.iotkit.converter; +import cc.iotkit.common.utils.JsonUtil; import cc.iotkit.model.device.message.ThingModelMessage; import jdk.nashorn.api.scripting.NashornScriptEngine; import jdk.nashorn.api.scripting.ScriptObjectMirror; @@ -9,26 +10,26 @@ import org.apache.commons.beanutils.BeanUtils; import javax.script.ScriptEngineManager; import javax.script.ScriptException; +import java.util.Map; @Slf4j @Data public class ScriptConverter implements IConverter { private final NashornScriptEngine engine = (NashornScriptEngine) (new ScriptEngineManager()).getEngineByName("nashorn"); - private String script; + private Object scriptObj; public void setScript(String script) { - this.script = script; try { - engine.eval(script); + scriptObj = engine.eval(script); } catch (ScriptException e) { log.error("eval converter script error", e); } } - public ThingModelMessage decode(String msg) { + public ThingModelMessage decode(DeviceMessage msg) { try { - ScriptObjectMirror result = (ScriptObjectMirror) engine.invokeFunction("decode", msg); + ScriptObjectMirror result = (ScriptObjectMirror) engine.invokeMethod(scriptObj, "decode", msg); ThingModelMessage modelMessage = new ThingModelMessage(); BeanUtils.populate(modelMessage, result); return modelMessage; @@ -39,10 +40,13 @@ public class ScriptConverter implements IConverter { } @Override - public String encode(DeviceService service, Device device) { + public DeviceMessage encode(ThingService service, Device device) { try { - ScriptObjectMirror result = (ScriptObjectMirror) engine.invokeFunction("encode", service, device); - return result.toString(); + ScriptObjectMirror result = (ScriptObjectMirror) engine.invokeMethod(scriptObj, "encode", service, device); + Map map = (Map) JsonUtil.toObject(result); + DeviceMessage message = new DeviceMessage(); + BeanUtils.populate(message, map); + return message; } catch (Throwable e) { log.error("execute encode script error", e); } diff --git a/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeviceMessage.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ThingService.java similarity index 64% rename from protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeviceMessage.java rename to protocol-gateway/converter/src/main/java/cc/iotkit/converter/ThingService.java index cc2d18de..5f32c50f 100755 --- a/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeviceMessage.java +++ b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ThingService.java @@ -1,25 +1,26 @@ -package cc.iotkit.protocol; +package cc.iotkit.converter; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -/** - * 设备消息 - */ @Data @NoArgsConstructor @AllArgsConstructor @Builder -public class DeviceMessage { +public class ThingService { + + private String mid; private String productKey; private String deviceName; - private String mid; + private String type; - private String content; + private String identifier; + + private T params; } diff --git a/protocol-gateway/decode-function/.DS_Store b/protocol-gateway/decode-function/.DS_Store deleted file mode 100755 index ee771938787a1bb39cadddab0eb4f7463f2ead2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKI|>3Z5S>vG!N$@uSMUZw^aOhW1;s`bM6I{-TprCgpGH?ZZR8D1UNV`NkXP*N zh=|TFo0-T&L`HB!x!KS)+c)o6FCz+si0p zwti-h{ zq5pp-aYY5Fz+Wk#gGIBL<4IXtJCCzkTi`3W<=o+Bm^%f7mt&xpV=Sy3PdzE}ip{ZK V6Wc(iBkpt{e+En!8Ws4p0uNe26{i3I diff --git a/protocol-gateway/decode-function/pom.xml b/protocol-gateway/decode-function/pom.xml deleted file mode 100755 index abdc3fcb..00000000 --- a/protocol-gateway/decode-function/pom.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - iotkit-parent - cc.iotkit - 0.0.1-SNAPSHOT - ../../pom.xml - - 4.0.0 - - decode-function - - - - org.apache.pulsar - pulsar-functions-api - - - - org.projectlombok - lombok - - - - cc.iotkit - common - - - - - - - - org.apache.maven.plugins - maven-assembly-plugin - 3.1.0 - - - - cc.iotkit.fun.TestFunction - - - - jar-with-dependencies - - - - - make-assembly - package - - single - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - 8 - 8 - - - - - - \ No newline at end of file diff --git a/protocol-gateway/decode-function/src/main/java/cc/iotkit/protocol/function/DecodeFunction.java b/protocol-gateway/decode-function/src/main/java/cc/iotkit/protocol/function/DecodeFunction.java deleted file mode 100755 index dce944b0..00000000 --- a/protocol-gateway/decode-function/src/main/java/cc/iotkit/protocol/function/DecodeFunction.java +++ /dev/null @@ -1,51 +0,0 @@ -package cc.iotkit.protocol.function; - -import cc.iotkit.common.utils.JsonUtil; -import jdk.nashorn.api.scripting.NashornScriptEngine; -import org.apache.pulsar.functions.api.Context; -import org.apache.pulsar.functions.api.Function; - -import javax.script.*; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; - -/** - * 上行消息转换函数 - */ -public class DecodeFunction implements Function { - - private static final NashornScriptEngine engine = (NashornScriptEngine) (new ScriptEngineManager()).getEngineByName("nashorn"); - private static final Map compiledScripts = new ConcurrentHashMap<>(); - - @Override - public ThingModelMessage process(DeviceMessage msg, Context context) throws Exception { - Optional optGateway = context.getUserConfigValue("gateway"); - Optional optScript = context.getUserConfigValue("script"); - if (!optGateway.isPresent() || !optScript.isPresent()) { - return null; - } - - String gateway = optGateway.get().toString(); - compiledScripts.putIfAbsent(gateway, engine.compile(optScript.get() + ".decode(msg)")); - - CompiledScript script = compiledScripts.get(gateway); - context.getLogger().debug(script.toString()); - - Map data = new HashMap<>(); - data.putIfAbsent("msg", msg); - Bindings bindings = new SimpleBindings(data); - Object result = script.eval(bindings); - - if (result == null) { - context.getLogger().error("translate msg failed:{}", JsonUtil.toJsonString(msg)); - return null; - } - if (result instanceof Map) { - return ThingModelMessage.from((Map) result); - } - return null; - } - -} diff --git a/protocol-gateway/decode-function/src/main/java/cc/iotkit/protocol/function/ThingModelMessage.java b/protocol-gateway/decode-function/src/main/java/cc/iotkit/protocol/function/ThingModelMessage.java deleted file mode 100755 index 3904273b..00000000 --- a/protocol-gateway/decode-function/src/main/java/cc/iotkit/protocol/function/ThingModelMessage.java +++ /dev/null @@ -1,62 +0,0 @@ -package cc.iotkit.protocol.function; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.HashMap; -import java.util.Map; - -/** - * 物模型消息 - */ -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class ThingModelMessage { - - private String productKey; - - private String deviceName; - - private String mid; - - private String identifier; - - private Map data; - - /** - * 时间戳,设备上的事件或数据产生的本地时间 - */ - private Long occur; - - /** - * 消息上报时间 - */ - private Long time; - - public static ThingModelMessage from(Map map) { - ThingModelMessage message = new ThingModelMessage(); - message.setProductKey(getStr(map, "productKey")); - message.setDeviceName(getStr(map, "deviceName")); - message.setMid(getStr(map, "mid")); - message.setIdentifier(getStr(map, "identifier")); - Object data = map.get("data"); - if (data instanceof Map) { - message.setData((Map) data); - } else { - message.setData(new HashMap<>()); - } - return message; - } - - private static String getStr(Map map, String key) { - Object val = map.get(key); - if (val == null) { - return null; - } - return val.toString(); - } -} diff --git a/protocol-gateway/gateway-client/pom.xml b/protocol-gateway/emqx-component/pom.xml old mode 100755 new mode 100644 similarity index 57% rename from protocol-gateway/gateway-client/pom.xml rename to protocol-gateway/emqx-component/pom.xml index 9f54e7c2..55ea7dbc --- a/protocol-gateway/gateway-client/pom.xml +++ b/protocol-gateway/emqx-component/pom.xml @@ -9,33 +9,28 @@ 4.0.0 - gateway-client - - - 8 - 8 - + emqx-component - org.springframework - spring-web + io.vertx + vertx-core - com.squareup.okhttp3 - okhttp + io.vertx + vertx-web-proxy - org.apache.pulsar - pulsar-client + io.vertx + vertx-mqtt - org.projectlombok - lombok + cc.iotkit + model @@ -43,6 +38,11 @@ common + + cc.iotkit + component + + \ No newline at end of file diff --git a/protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/AuthVerticle.java b/protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/AuthVerticle.java new file mode 100644 index 00000000..9a89df27 --- /dev/null +++ b/protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/AuthVerticle.java @@ -0,0 +1,70 @@ +package cc.iotkit.comp.emqx; + +import cc.iotkit.comp.IMessageHandler; +import io.vertx.core.AbstractVerticle; +import io.vertx.core.http.HttpMethod; +import io.vertx.core.http.HttpServer; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.web.Router; +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; +import java.util.Map; + +@Slf4j +public class AuthVerticle extends AbstractVerticle { + + private HttpServer backendServer; + + private IMessageHandler executor; + + private EmqxConfig config; + + public void setExecutor(IMessageHandler executor) { + this.executor = executor; + } + + public AuthVerticle(EmqxConfig config) { + this.config = config; + } + + @Override + public void start() throws Exception { + backendServer = vertx.createHttpServer(); + Router backendRouter = Router.router(vertx); + + backendRouter.route(HttpMethod.POST, "/mqtt/auth").handler(rc -> { + JsonObject json = rc.getBodyAsJson(); + try { + executor.onReceive(new HashMap<>(), "auth", json.toString()); + rc.response().setStatusCode(200) + .end(); + } catch (Throwable e) { + rc.response().setStatusCode(500) + .end(); + log.error("mqtt auth failed", e); + } + }); + backendRouter.route(HttpMethod.POST, "/mqtt/acl").handler(rc -> { + JsonObject json = rc.getBodyAsJson(); + try { + Map head = new HashMap<>(); + head.put("topic", json.getString("topic")); + executor.onReceive(head, "subscribe", json.toString()); + rc.response().setStatusCode(200) + .end(); + } catch (Throwable e) { + rc.response().setStatusCode(500) + .end(); + log.error("mqtt acl failed", e); + } + }); + + backendServer.requestHandler(backendRouter).listen(config.getAuthPort()); + } + + @Override + public void stop() throws Exception { + backendServer.close(voidAsyncResult -> log.info("close emqx auth server...")); + } +} diff --git a/protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/EmqxComponent.java b/protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/EmqxComponent.java new file mode 100644 index 00000000..b698e745 --- /dev/null +++ b/protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/EmqxComponent.java @@ -0,0 +1,147 @@ +package cc.iotkit.comp.emqx; + +import cc.iotkit.common.exception.BizException; +import cc.iotkit.common.utils.JsonUtil; +import cc.iotkit.comp.AbstractComponent; +import cc.iotkit.comp.CompConfig; +import cc.iotkit.comp.model.DeviceState; +import cc.iotkit.converter.DeviceMessage; +import io.vertx.core.Future; +import io.vertx.core.Vertx; +import io.vertx.mqtt.MqttClient; +import io.vertx.mqtt.MqttClientOptions; +import io.vertx.mqtt.messages.MqttConnAckMessage; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; + +@Slf4j +public class EmqxComponent extends AbstractComponent { + + private Vertx vertx; + private AuthVerticle authVerticle; + private CountDownLatch countDownLatch; + private String deployedId; + private EmqxConfig mqttConfig; + + public void create(CompConfig config) { + super.create(config); + vertx = Vertx.vertx(); + mqttConfig = JsonUtil.parse(config.getOther(), EmqxConfig.class); + authVerticle = new AuthVerticle(mqttConfig); + } + + @Override + public void start() { + try { + authVerticle.setExecutor(getHandler()); + countDownLatch = new CountDownLatch(1); + Future future = vertx.deployVerticle(authVerticle); + future.onSuccess((s -> { + deployedId = s; + countDownLatch.countDown(); + })); + future.onFailure((e) -> { + countDownLatch.countDown(); + log.error("start emqx auth component failed", e); + }); + countDownLatch.await(); + + MqttClientOptions options = new MqttClientOptions() + .setClientId(mqttConfig.getClientId()) + .setUsername(mqttConfig.getUsername()) + .setPassword(mqttConfig.getPassword()) + .setCleanSession(true) + .setKeepAliveInterval(60); + + if (mqttConfig.isSsl()) { + options.setSsl(true) + .setTrustAll(true); + } + MqttClient client = MqttClient.create(vertx, options); + + Future connFuture = + client.connect(mqttConfig.getPort(), mqttConfig.getBroker()); + connFuture.onSuccess(ack -> log.info("connect emqx broker success")) + .onFailure(e -> log.error("connect emqx broker failed", e)); + + List topics = mqttConfig.getSubscribeTopics(); + Map subscribes = new HashMap<>(); + for (String topic : topics) { + subscribes.put(topic, 1); + } + + client.publishHandler(s -> { + String topic = s.topicName(); + String payload = s.payload().toString(); + log.info("receive message,topic:{},payload:{}", topic, payload); + +// +// //取消订阅 +// if (topic.equals("/sys/session/topic/unsubscribed")) { +// topicUnsubscribed(payload); +// return; +// } +// +// //连接断开 +// if (topic.equals("/sys/client/disconnected")) { +// disconnectedHandler.handler(payload); +// return; +// } +// +// String[] parts = topic.split("/"); +// if (parts.length < 5) { +// log.error("message topic is illegal."); +// return; +// } +// String productKey = parts[2]; +// String deviceName = parts[3]; +// +// //子设备注册 +// if (topic.endsWith("/register")) { + + + Map head = new HashMap<>(); + head.put("topic", topic); + getHandler().onReceive(head, "", payload); + }).subscribe(subscribes).onSuccess(a -> log.info("subscribe topic success")) + .onFailure(e -> log.error("subscribe topic failed", e)); + + } catch (Throwable e) { + throw new BizException("start emqx auth component error", e); + } + } + + @SneakyThrows + @Override + public void stop() { + authVerticle.stop(); + Future future = vertx.undeploy(deployedId); + future.onSuccess(unused -> log.info("stop emqx auth component success")); + } + + @Override + public void destroy() { + + } + + @Override + public void onDeviceStateChange(DeviceState state) { + + } + + @Override + public void send(DeviceMessage message) { + + } + + @Override + public boolean exist(String productKey, String deviceName) { + return false; + } + +} diff --git a/protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/EmqxConfig.java b/protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/EmqxConfig.java new file mode 100644 index 00000000..4c3cf453 --- /dev/null +++ b/protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/EmqxConfig.java @@ -0,0 +1,25 @@ +package cc.iotkit.comp.emqx; + +import lombok.Data; + +import java.util.List; + +@Data +public class EmqxConfig { + + private int authPort; + + private String broker; + + private int port; + + private boolean ssl; + + private String clientId; + + private String username; + + private String password; + + private List subscribeTopics; +} diff --git a/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeregisterInfo.java b/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeregisterInfo.java deleted file mode 100755 index 4e8f03ed..00000000 --- a/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeregisterInfo.java +++ /dev/null @@ -1,17 +0,0 @@ -package cc.iotkit.protocol; - -import lombok.Data; - - -/** - * 注销信息 - */ -@Data -public class DeregisterInfo { - - private String productKey; - - private String deviceName; - - private boolean cascade; -} diff --git a/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeviceBehaviour.java b/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeviceBehaviour.java deleted file mode 100755 index f4e944a6..00000000 --- a/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeviceBehaviour.java +++ /dev/null @@ -1,34 +0,0 @@ -package cc.iotkit.protocol; - - -/** - * 设备行为接口 - */ -public interface DeviceBehaviour { - - /** - * 设备注册 - */ - Result register(RegisterInfo info); - - /** - * 设备上线 - */ - Result online(String productKey, String deviceName); - - /** - * 设备离线 - */ - Result offline(String productKey, String deviceName); - - /** - * 设备消息上报 - */ - void messageReport(DeviceMessage msg); - - /** - * OTA消息上报 - */ - void otaProgressReport(OtaMessage msg); - -} diff --git a/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeviceGateway.java b/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeviceGateway.java deleted file mode 100755 index d9e125af..00000000 --- a/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/DeviceGateway.java +++ /dev/null @@ -1,23 +0,0 @@ -package cc.iotkit.protocol; - - -import org.springframework.web.bind.annotation.RequestMapping; - -/** - * 设备网关接口 - */ -public interface DeviceGateway { - - /** - * 指令下发 - */ - @RequestMapping("/sendMessage") - Result sendMessage(DeviceMessage msg); - - /** - * OTA升级任务下发 - */ - @RequestMapping("/sendOta") - Result sendOta(OtaInfo ota); - -} diff --git a/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/OtaInfo.java b/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/OtaInfo.java deleted file mode 100755 index d064e65e..00000000 --- a/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/OtaInfo.java +++ /dev/null @@ -1,7 +0,0 @@ -package cc.iotkit.protocol; - -import lombok.Data; - -@Data -public class OtaInfo { -} diff --git a/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/OtaMessage.java b/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/OtaMessage.java deleted file mode 100755 index 65ad1be2..00000000 --- a/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/OtaMessage.java +++ /dev/null @@ -1,30 +0,0 @@ -package cc.iotkit.protocol; - -import lombok.Data; - -/** - * OTA消息 - */ -@Data -public class OtaMessage { - - private final String TYPE_PROGRESS="progress"; - private final String TYPE_RESULT="result"; - - private final String PROGRESS_DOWNLOADING="downloading"; - private final String PROGRESS_DOWNLOADED="downloaded"; - private final String PROGRESS_UPGRADING="upgrading"; - private final String PROGRESS_UPGRADED="upgraded"; - - private String productKey; - - private String deviceName; - - private String type; - - private String jobId; - - private String progress; - - private String result; -} diff --git a/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/RegisterInfo.java b/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/RegisterInfo.java deleted file mode 100755 index 7fd26c75..00000000 --- a/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/RegisterInfo.java +++ /dev/null @@ -1,49 +0,0 @@ -package cc.iotkit.protocol; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.List; -import java.util.Map; - -/** - * 注册信息 - */ -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class RegisterInfo { - - private String productKey; - - private String deviceName; - - private String model; - - private Map tag; - - private List subDevices; - - public RegisterInfo(String productKey, String deviceName, String model) { - this.productKey = productKey; - this.deviceName = deviceName; - this.model = model; - } - - @Data - @NoArgsConstructor - @AllArgsConstructor - public static class SubDevice { - - private String productKey; - - private String deviceName; - - private String model; - - private Map tag; - } -} diff --git a/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/client/DeviceBehaviourClient.java b/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/client/DeviceBehaviourClient.java deleted file mode 100755 index b1976e89..00000000 --- a/protocol-gateway/gateway-client/src/main/java/cc/iotkit/protocol/client/DeviceBehaviourClient.java +++ /dev/null @@ -1,151 +0,0 @@ -package cc.iotkit.protocol.client; - -import cc.iotkit.common.exception.BizException; -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.protocol.*; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.SneakyThrows; -import okhttp3.*; -import org.apache.pulsar.client.api.Producer; -import org.apache.pulsar.client.api.PulsarClient; -import org.apache.pulsar.client.impl.schema.JSONSchema; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -public class DeviceBehaviourClient implements DeviceBehaviour { - - public final String gatewayServer; - - private GatewayConfig gatewayConfig; - - private final OkHttpClient httpClient; - - private Producer deviceMessageProducer; - - private Producer otaMessageProducer; - - - @SneakyThrows - public DeviceBehaviourClient(String server) { - //初始化协议网关http客户端 - this.gatewayServer = server.replaceAll("/$", ""); - httpClient = new OkHttpClient.Builder() - .connectTimeout(10, TimeUnit.SECONDS) - .readTimeout(30, TimeUnit.SECONDS) - .build(); - - //获取协议网关配置 - getConfig(); - - //初始化pulsar客户端 - PulsarClient client = PulsarClient.builder() - .serviceUrl(gatewayConfig.getMqServiceUrl()) - .build(); - - deviceMessageProducer = client.newProducer(JSONSchema.of(DeviceMessage.class)) - .topic("persistent://public/default/device_raw") - .create(); - - otaMessageProducer = client.newProducer(JSONSchema.of(OtaMessage.class)) - .topic("persistent://public/default/device_ota") - .create(); - } - - public Request buildRequest(String url, String method, String type, Map data) { - Request.Builder requestBuilder = new Request.Builder() - .url(url); - - RequestBody requestBody; - if ("json".equals(type)) { - requestBody = RequestBody.create(MediaType.get("application/json; charset=utf-8"), - JsonUtil.toJsonString(data)); - } else { - FormBody.Builder builder = new FormBody.Builder(); - data.forEach((key, val) -> builder.add(key, val.toString())); - requestBody = builder.build(); - } - requestBuilder.method(method.toUpperCase(), requestBody); - return requestBuilder.build(); - } - - - private Result invoke(String path, T data) { - return invoke(path, "form", data); - } - - private Result invokeJson(String path, T data) { - return invoke(path, "json", data); - } - - private Result invoke(String path, String type, T data) { - Request request = buildRequest(gatewayServer + path, "post", type, - (data instanceof Map) ? (Map) data : - JsonUtil.parse(JsonUtil.toJsonString(data), Map.class)); - - Call call = httpClient.newCall(request); - try { - Response response = call.execute(); - if (!response.isSuccessful() || response.body() == null) { - return new Result(false, "Remote interface call failed:" + response.body().string()); - } - String content = response.body().string(); - return JsonUtil.parse(content, Result.class); - } catch (Throwable e) { - return new Result(false, "Interface call failed:" + e.getMessage()); - } - } - - private void getConfig() { - if (this.gatewayConfig == null) { - Result result = invoke("/getConfig", new HashMap<>()); - if (!result.isSuccess()) { - throw new BizException("get gateway config failed"); - } - this.gatewayConfig = JsonUtil.parse(result.getContent(), GatewayConfig.class); - } - } - - @Override - public Result register(RegisterInfo info) { - return invokeJson("/register", info); - } - - @Override - public Result online(String productKey, String deviceName) { - Map data = new HashMap<>(); - data.put("productKey", productKey); - data.put("deviceName", deviceName); - return invoke("/online", data); - } - - @Override - public Result offline(String productKey, String deviceName) { - Map data = new HashMap<>(); - data.put("productKey", productKey); - data.put("deviceName", deviceName); - return invoke("/offline", data); - } - - @SneakyThrows - @Override - public void messageReport(DeviceMessage msg) { - deviceMessageProducer.send(msg); - } - - @Override - public void otaProgressReport(OtaMessage msg) { - } - - @Data - @NoArgsConstructor - @AllArgsConstructor - public static class GatewayConfig { - - private String mqServiceUrl; - - } -} diff --git a/device-server/mqtt-client-simulator/.DS_Store b/protocol-gateway/mqtt-client-simulator/.DS_Store similarity index 100% rename from device-server/mqtt-client-simulator/.DS_Store rename to protocol-gateway/mqtt-client-simulator/.DS_Store diff --git a/device-server/mqtt-client-simulator/pom.xml b/protocol-gateway/mqtt-client-simulator/pom.xml similarity index 97% rename from device-server/mqtt-client-simulator/pom.xml rename to protocol-gateway/mqtt-client-simulator/pom.xml index 989e1f3b..72a6fe2b 100755 --- a/device-server/mqtt-client-simulator/pom.xml +++ b/protocol-gateway/mqtt-client-simulator/pom.xml @@ -3,7 +3,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - device-server + protocol-gateway cc.iotkit 0.0.1-SNAPSHOT diff --git a/device-server/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/Application.java b/protocol-gateway/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/Application.java similarity index 100% rename from device-server/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/Application.java rename to protocol-gateway/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/Application.java diff --git a/device-server/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/config/Mqtt.java b/protocol-gateway/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/config/Mqtt.java similarity index 100% rename from device-server/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/config/Mqtt.java rename to protocol-gateway/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/config/Mqtt.java diff --git a/device-server/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/service/Device.java b/protocol-gateway/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/service/Device.java similarity index 100% rename from device-server/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/service/Device.java rename to protocol-gateway/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/service/Device.java diff --git a/device-server/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/service/Gateway.java b/protocol-gateway/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/service/Gateway.java similarity index 100% rename from device-server/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/service/Gateway.java rename to protocol-gateway/mqtt-client-simulator/src/main/java/cc/iotkit/simulator/service/Gateway.java diff --git a/protocol-gateway/mqtt-component/pom.xml b/protocol-gateway/mqtt-component/pom.xml index 21e910b6..9119c3b3 100755 --- a/protocol-gateway/mqtt-component/pom.xml +++ b/protocol-gateway/mqtt-component/pom.xml @@ -3,10 +3,9 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - iotkit-parent + protocol-gateway cc.iotkit 0.0.1-SNAPSHOT - ../../pom.xml 4.0.0 diff --git a/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttComponent.java b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttComponent.java index a64a4638..d7c1505b 100755 --- a/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttComponent.java +++ b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttComponent.java @@ -3,12 +3,17 @@ package cc.iotkit.comp.mqtt; import cc.iotkit.common.exception.BizException; import cc.iotkit.common.utils.JsonUtil; import cc.iotkit.comp.AbstractComponent; -import cc.iotkit.comp.IMessageHandler; +import cc.iotkit.comp.CompConfig; +import cc.iotkit.comp.model.DeviceState; +import cc.iotkit.converter.DeviceMessage; import io.vertx.core.Future; import io.vertx.core.Vertx; -import lombok.SneakyThrows; +import lombok.*; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.beanutils.BeanUtils; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.CountDownLatch; @Slf4j @@ -18,10 +23,12 @@ public class MqttComponent extends AbstractComponent { private CountDownLatch countDownLatch; private String deployedId; private MqttVerticle mqttVerticle; + private Map deviceChildToParent = new HashMap<>(); - public void create(String config) { + public void create(CompConfig config) { + super.create(config); vertx = Vertx.vertx(); - MqttConfig mqttConfig = JsonUtil.parse(config, MqttConfig.class); + MqttConfig mqttConfig = JsonUtil.parse(config.getOther(), MqttConfig.class); mqttVerticle = new MqttVerticle(mqttConfig); } @@ -55,4 +62,79 @@ public class MqttComponent extends AbstractComponent { public void destroy() { } + @Override + public void onDeviceStateChange(DeviceState state) { + DeviceState.Parent parent = state.getParent(); + if (parent == null) { + return; + } + Device device = new Device(state.getProductKey(), state.getDeviceName()); + + if (DeviceState.STATE_ONLINE.equals(state.getState())) { + //保存子设备所属父设备 + deviceChildToParent.put(device.toString(), + new Device(parent.getProductKey(), parent.getDeviceName()) + ); + } else { + //删除关系 + deviceChildToParent.remove(device.toString()); + } + + } + + @Override + public void send(DeviceMessage message) { + Device child = new Device(message.getProductKey(), message.getDeviceName()); + //作为子设备查找父设备 + Device parent = deviceChildToParent.get(child.toString()); + if (parent == null) { + parent = child; + } + + Object obj = message.getContent(); + if (!(obj instanceof Map)) { + throw new BizException("message content is not Map"); + } + Message msg = new Message(); + try { + BeanUtils.populate(msg, (Map) obj); + } catch (Throwable e) { + throw new BizException("message content is incorrect"); + } + + mqttVerticle.publish(parent.getProductKey(), parent.getDeviceName(), + msg.getTopic(), msg.getPayload()); + } + + @Override + public boolean exist(String productKey, String deviceName) { + //先作为子设备查找是否存在父设备 + Device device = deviceChildToParent.get(new Device(productKey, deviceName).toString()); + if (device != null) { + return true; + } + + return mqttVerticle.exist(productKey, deviceName); + } + + @Override + public CompConfig getConfig() { + return config; + } + + @Data + public static class Message { + private String topic; + private String payload; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + @ToString + public static class Device { + private String productKey; + private String deviceName; + } + } diff --git a/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttVerticle.java b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttVerticle.java index ff73ae1e..85102aba 100755 --- a/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttVerticle.java +++ b/protocol-gateway/mqtt-component/src/main/java/cc/iotkit/comp/mqtt/MqttVerticle.java @@ -1,15 +1,17 @@ package cc.iotkit.comp.mqtt; +import cc.iotkit.common.exception.BizException; import cc.iotkit.comp.IMessageHandler; +import cc.iotkit.comp.model.ReceiveResult; import io.netty.handler.codec.mqtt.MqttConnectReturnCode; import io.netty.handler.codec.mqtt.MqttProperties; import io.netty.handler.codec.mqtt.MqttQoS; import io.vertx.core.AbstractVerticle; +import io.vertx.core.Future; +import io.vertx.core.Handler; +import io.vertx.core.buffer.Buffer; import io.vertx.core.net.PemKeyCertOptions; -import io.vertx.mqtt.MqttAuth; -import io.vertx.mqtt.MqttServer; -import io.vertx.mqtt.MqttServerOptions; -import io.vertx.mqtt.MqttTopicSubscription; +import io.vertx.mqtt.*; import io.vertx.mqtt.messages.codes.MqttSubAckReasonCode; import lombok.extern.slf4j.Slf4j; @@ -28,6 +30,8 @@ public class MqttVerticle extends AbstractVerticle { private IMessageHandler executor; + private Map endpointMap = new HashMap<>(); + public MqttVerticle(MqttConfig config) { this.config = config; } @@ -56,12 +60,15 @@ public class MqttVerticle extends AbstractVerticle { return; } + String clientId = endpoint.clientIdentifier(); String authJson = auth.toJson() - .put("clientid", endpoint.clientIdentifier()).toString(); + .put("clientid", clientId).toString(); log.info("MQTT client auth,username:{},password:{}", auth.getUsername(), auth.getPassword()); try { - executor.onReceive(new HashMap<>(), "auth", authJson); + ReceiveResult result = executor.onReceive(new HashMap<>(), "auth", authJson); + //保存设备与连接关系 + endpointMap.put(getEndpointKey(result), endpoint); } catch (Throwable e) { log.error("auth failed", e); endpoint.reject(MqttConnectReturnCode.CONNECTION_REFUSED_NOT_AUTHORIZED); @@ -73,13 +80,17 @@ public class MqttVerticle extends AbstractVerticle { endpoint.accept(false); endpoint.disconnectMessageHandler(disconnectMessage -> { log.info("Received disconnect from client, reason code = {}", disconnectMessage.code()); - executor.onReceive(new HashMap<>(), "disconnect", authJson); + ReceiveResult result = executor.onReceive(new HashMap<>(), "disconnect", clientId); + //删除设备与连接关系 + endpointMap.remove(getEndpointKey(result)); }).subscribeHandler(subscribe -> { List reasonCodes = new ArrayList<>(); for (MqttTopicSubscription s : subscribe.topicSubscriptions()) { log.info("Subscription for {},with QoS {}", s.topicName(), s.qualityOfService()); try { - executor.onReceive(new HashMap<>(), "subscribe", s.topicName()); + Map head = new HashMap<>(); + head.put("topic", s.topicName()); + executor.onReceive(head, "subscribe", clientId); reasonCodes.add(MqttSubAckReasonCode.qosGranted(s.qualityOfService())); } catch (Throwable e) { log.error("subscribe failed,topic:" + s.topicName(), e); @@ -93,7 +104,9 @@ public class MqttVerticle extends AbstractVerticle { for (String t : unsubscribe.topics()) { log.info("Unsubscription for {}", t); try { - executor.onReceive(new HashMap<>(), "unsubscribe", t); + Map head = new HashMap<>(); + head.put("topic", t); + executor.onReceive(head, "unsubscribe", clientId); } catch (Throwable e) { log.error("unsubscribe failed,topic:" + t, e); } @@ -108,15 +121,14 @@ public class MqttVerticle extends AbstractVerticle { Map head = new HashMap<>(); head.put("topic", message.topicName()); executor.onReceive(head, "", payload); + if (message.qosLevel() == MqttQoS.AT_LEAST_ONCE) { + endpoint.publishAcknowledge(message.messageId()); + } else if (message.qosLevel() == MqttQoS.EXACTLY_ONCE) { + endpoint.publishReceived(message.messageId()); + } } catch (Throwable e) { log.error("handler message failed,topic:" + message.topicName(), e); } - - if (message.qosLevel() == MqttQoS.AT_LEAST_ONCE) { - endpoint.publishAcknowledge(message.messageId()); - } else if (message.qosLevel() == MqttQoS.EXACTLY_ONCE) { - endpoint.publishReceived(message.messageId()); - } }).publishReleaseHandler(endpoint::publishComplete); }).listen(ar -> { if (ar.succeeded()) { @@ -129,6 +141,34 @@ public class MqttVerticle extends AbstractVerticle { @Override public void stop() throws Exception { + for (MqttEndpoint endpoint : endpointMap.values()) { + executor.onReceive(new HashMap<>(), "disconnect", endpoint.clientIdentifier()); + } mqttServer.close(voidAsyncResult -> log.info("close mqtt server...")); } + + private String getEndpointKey(ReceiveResult result) { + return getEndpointKey(result.getProductKey(), result.getDeviceName()); + } + + private String getEndpointKey(String productKey, String deviceName) { + return String.format("%s_%s", productKey, deviceName); + } + + public boolean exist(String productKey, String deviceName) { + return endpointMap.containsKey(getEndpointKey(productKey, deviceName)); + } + + public void publish(String productKey, String deviceName, String topic, String msg) { + MqttEndpoint endpoint = endpointMap.get(getEndpointKey(productKey, deviceName)); + if (endpoint == null) { + throw new BizException("endpoint does not exist"); + } + Future result = endpoint.publish(topic, Buffer.buffer(msg), + MqttQoS.AT_LEAST_ONCE, false, false); + result.onFailure(e -> log.error("public topic failed", e)); + result.onSuccess(integer -> { + log.info("publish success,topic:{},payload:{}", topic, msg); + }); + } } diff --git a/protocol-gateway/pom.xml b/protocol-gateway/pom.xml index f53cf12b..71ac04b7 100755 --- a/protocol-gateway/pom.xml +++ b/protocol-gateway/pom.xml @@ -12,12 +12,10 @@ protocol-gateway pom - gateway-client - protocol-server - decode-function component-server converter mqtt-component + emqx-component component diff --git a/protocol-gateway/protocol-server/.DS_Store b/protocol-gateway/protocol-server/.DS_Store deleted file mode 100755 index 7a073db34a652072acd90eb46422e5a6bacc355e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKyG{c^3>=dbC()!#xj#U`AFQJA1^EFAAPqVsNT{#kyZAK54Lp5PX|Mc0K_HJ zVO+;7L2RBN_QENV8JZ=Pm{h9~!;;Q?tGZq|B_(SMo$Pf6NI0V(jW6tLxXx83lSs<+Nw&U7la6h5avFf#>ui$JH?2TxnmDzDm7XyqsR`b$xira!cl!eic>D~wKO%FMi1 zplPf~bc0|taUmu~gBq!ct8UnssEIC&n%D&_bm8B|g+}ATm7Y6y+E_{#CPteuH<|n0 zIp>}`cfR|*dvoRi0Ji7NCIB4(6uJbmGOBJ-gkM}sN>OAfB}9q`;1Fad{PC>qW|#Di z4KV{T12F?J12F?J11o_6I<*Zg7}qfaF#}5(5V`v*2*3ajPTZ8g|DGMUEk9^%ypBc1C8euYE2>temaQu*JKBHJ zo#+pYAn&&uUWQfoTPDvM-jHPmCkMFGW%B}e4tfWSfO|(o=KY0 z8>dpq$=24!RB}gi%hZ&rDphseeaG_WF1~vC%3E*0^WjI51B~_&sF3#y^~cm&M2P9< z>@3Y*1T1pcexXBt=_opVE2i}BeLY%+tuN5K9vlxW*YOW=&nL{Va-TTapL3mFj|=}$ z&b9Mnj-O!_Im6E7Z6dDCw)?HK+#e43=|HqbeAf#)!j8ih#R^-7vAoawI0aY*-brCT zLv?1&#?4!6>KnGV?rob}yRMv7tk<*=;@1hRCoJv_PKbp%Z1_3un3i*5s9^b4*5(6_ zF~-@~su~7us?_!2eAYUZw}LaQMp5S2y7IMJwZ27Vv&yJR4|~it#ein$(W~{l73GMq zcX*s?Y1Z!1>r`ea13t}H4soBBQkky~JVi?_Lm$wZ6lSV}wvpwwH0{t@6!xe(RFI@e z<1THFQh_OTIOmRy(d+oq{E(hj*r&=d@$3VJ9~>O#4n1DHdV9659~SmD)8wY2kaX(h zYKL!IlWvrEDxE-8a6g?lJuphYgmE|n7vLgXg3E9P-iKNE06u}w;B)u_zJwd_Eqo6@ zz>n}V`~ttiZwRQOhGkfZNxTbduomyd?bwVvu?6>FCwAdJ?7_!z2#0Y5k6;dM9K&%u zg=g_uJde-e^Y{wBj_=}CoWb{S7O!C>)}nc_J|d?&U*i(7k|v|CZ$(FMrO8BB_rCv0 zlQ-5#A>OfJBC-7ee_|qu(bFog{ywFhw*?#2$1TQ>==7yEDk2k{VQ&>+c~$k8FudFW$+Q}{GKgXc(o z7w`qVgfHSt_%gnRZ{Srau?6AnpO>6OoFQDa85a6I$9A0)WS;UmH+%hKz#nk=YOcY+q?P;quKCH diff --git a/protocol-gateway/protocol-server/fun-test/pom.xml b/protocol-gateway/protocol-server/fun-test/pom.xml deleted file mode 100755 index 0e12c219..00000000 --- a/protocol-gateway/protocol-server/fun-test/pom.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - - iotkit-parent - cc.iotkit - 0.0.1-SNAPSHOT - ../../../pom.xml - - 4.0.0 - - fun-test - - - - org.apache.pulsar - pulsar-functions-api - 2.6.0 - - - - cc.iotkit - common - - - - cc.iotkit - gateway-client - - - - - - - - org.apache.maven.plugins - maven-assembly-plugin - 3.1.0 - - - - cc.iotkit.fun.TestFunction - - - - jar-with-dependencies - - - - - make-assembly - package - - single - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - 8 - 8 - - - - - - \ No newline at end of file diff --git a/protocol-gateway/protocol-server/fun-test/src/main/java/cc/iotkit/fun/TestFunction.java b/protocol-gateway/protocol-server/fun-test/src/main/java/cc/iotkit/fun/TestFunction.java deleted file mode 100755 index 282853b2..00000000 --- a/protocol-gateway/protocol-server/fun-test/src/main/java/cc/iotkit/fun/TestFunction.java +++ /dev/null @@ -1,50 +0,0 @@ -package cc.iotkit.fun; - -import cc.iotkit.common.utils.JsonUtil; -import jdk.nashorn.api.scripting.NashornScriptEngine; -import org.apache.pulsar.functions.api.Context; -import org.apache.pulsar.functions.api.Function; - -import javax.script.Bindings; -import javax.script.CompiledScript; -import javax.script.ScriptEngineManager; -import javax.script.SimpleBindings; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; - -public class TestFunction implements Function { - - private static final NashornScriptEngine engine = (NashornScriptEngine) (new ScriptEngineManager()).getEngineByName("nashorn"); - private static final Map compiledScripts = new ConcurrentHashMap<>(); - - @Override - public byte[] process(byte[] bs, Context context) throws Exception { - Optional objPk = context.getUserConfigValue("pk"); - Optional objTrans = context.getUserConfigValue("transform"); - if (!objPk.isPresent() || !objTrans.isPresent()) { - return null; - } - String s = new String(bs); - String pk = objPk.get().toString(); - compiledScripts.putIfAbsent(pk, engine.compile(objTrans.get().toString())); - - CompiledScript script = compiledScripts.get(pk); - context.getLogger().debug(script.toString()); - - Map data = new HashMap<>(); - data.putIfAbsent("msg", s); - Bindings bindings = new SimpleBindings(data); - Object result = script.eval(bindings); - - if (result == null) { - context.getLogger().error("translate failed:" + s); - return null; - } - s = JsonUtil.toJsonString(result); - return s.getBytes(); - } - - -} diff --git a/protocol-gateway/protocol-server/pom.xml b/protocol-gateway/protocol-server/pom.xml deleted file mode 100755 index 822782c0..00000000 --- a/protocol-gateway/protocol-server/pom.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - protocol-gateway - cc.iotkit - 0.0.1-SNAPSHOT - - 4.0.0 - - protocol-server - - - 8 - 8 - - - - - - org.springframework.boot - spring-boot-starter-web - - - - org.apache.pulsar - pulsar-client-all - - - - org.springframework.boot - spring-boot-starter-data-elasticsearch - - - - cc.iotkit - gateway-client - - - - cc.iotkit - model - - - - cc.iotkit - dao - - - - org.projectlombok - lombok - - - - cc.iotkit - decode-function - - - - - \ No newline at end of file diff --git a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/Application.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/Application.java deleted file mode 100755 index c154603c..00000000 --- a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/Application.java +++ /dev/null @@ -1,12 +0,0 @@ -package cc.iotkit.protocol; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication(scanBasePackages = {"cc.iotkit.protocol", "cc.iotkit.dao"}) -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } -} diff --git a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/Test1.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/Test1.java deleted file mode 100755 index 08e2ebf3..00000000 --- a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/Test1.java +++ /dev/null @@ -1,86 +0,0 @@ -package cc.iotkit.protocol.server; - -import cc.iotkit.protocol.DeviceMessage; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.SneakyThrows; -import org.apache.pulsar.client.admin.PulsarAdmin; -import org.apache.pulsar.client.admin.PulsarAdminException; -import org.apache.pulsar.client.api.*; -import org.apache.pulsar.client.impl.schema.JSONSchema; -import org.apache.pulsar.common.functions.FunctionConfig; - -import java.util.Set; -import java.util.regex.Pattern; - -public class Test1 { - - public static void main(String[] args) throws PulsarClientException, InterruptedException, PulsarAdminException { - -// PulsarAdmin admin = PulsarAdmin.builder() -// .serviceHttpUrl("http://localhost:8080") -// .build(); -// -// FunctionConfig functionConfig = new FunctionConfig(); -// functionConfig.setTenant("tenant"); -// functionConfig.setNamespace("namespace"); -// functionConfig.setName("functionName"); -// functionConfig.setRuntime(FunctionConfig.Runtime.JAVA); -// functionConfig.setParallelism(1); -// functionConfig.setClassName("org.apache.pulsar.functions.api.examples.ExclamationFunction"); -// functionConfig.setProcessingGuarantees(FunctionConfig.ProcessingGuarantees.ATLEAST_ONCE); -// functionConfig.setTopicsPattern("persistent://public/default/test.*"); -// functionConfig.setSubName("fun-test1"); -// functionConfig.setAutoAck(true); -// functionConfig.setOutput("persistent://public/default/fun_out"); -// admin.functions().createFunction(functionConfig, "/examples/api-examples.jar"); - - - PulsarClient client = PulsarClient.builder() - .serviceUrl("pulsar://192.168.0.112:6650") - .build(); - - client.newConsumer(JSONSchema.of(DeviceMessage.class)) - .topicsPattern(Pattern.compile("persistent://public/default/device_raw")) - .subscriptionName("test1") - .consumerName("test1") - .messageListener((MessageListener) (consumer, msg) -> { - try { - DeviceMessage m = msg.getValue(); - System.out.printf("==============received:%s,%s%n", m.getMid(), m.getContent()); - consumer.acknowledge(msg); - } catch (Throwable e) { - e.printStackTrace(); - } - }).subscribe(); - - -// for (int i = 0; i < 3; i++) { -// Producer producer = client.newProducer(JSONSchema.of(Msg.class)) -// .topic("test_" + i) -// .create(); -// for (int j = 0; j < 10; j++) { -// producer.newMessage() -// .value(new Msg("QQQQQ" + i, "id_test_" + i + "_" + j)) -// .property("aa", "1") -// .send(); -// } -// Thread.sleep(100); -// } - - - } - - @Data - @NoArgsConstructor - @AllArgsConstructor - public static class Msg { - - private String identifier; - - private String deviceId; - - } - -} diff --git a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/Test3.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/Test3.java deleted file mode 100755 index b1b7a766..00000000 --- a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/Test3.java +++ /dev/null @@ -1,40 +0,0 @@ -package cc.iotkit.protocol.server; - -import cc.iotkit.common.utils.JsonUtil; -import jdk.nashorn.api.scripting.NashornScriptEngine; - -import javax.script.*; -import java.util.HashMap; -import java.util.Map; - -public class Test3 { - private static final NashornScriptEngine engine = (NashornScriptEngine) (new ScriptEngineManager()).getEngineByName("nashorn"); - - - public static void main(String[] args) throws ScriptException { - - Map data = new HashMap<>(); - data.putIfAbsent("msg", "aaa"); - CompiledScript script = engine.compile("a={data:msg+'===111',b:2}"); - Bindings bindings = new SimpleBindings(data); - Object result = script.eval(bindings); - System.out.println(JsonUtil.toJsonString(result)); - - script = engine.compile("new (function() {\n" + - " function add(n){\n" + - " return n+1;\n" + - " }\n" + - " this.decode = function(msg) {\n" + - " return \"=>decode:\"+add(msg);\n" + - " };\n" + - "})().decode(color)"); - - for (int i = 0; i < 100; i++) { - data.put("color", "black" + i); - bindings = new SimpleBindings(data); - result = script.eval(bindings); - System.out.println(result); - } - - } -} diff --git a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/TestFunction.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/TestFunction.java deleted file mode 100755 index af8923aa..00000000 --- a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/TestFunction.java +++ /dev/null @@ -1,88 +0,0 @@ -package cc.iotkit.protocol.server; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.apache.pulsar.client.admin.PulsarAdmin; -import org.apache.pulsar.client.admin.PulsarAdminException; -import org.apache.pulsar.client.api.MessageListener; -import org.apache.pulsar.client.api.PulsarClient; -import org.apache.pulsar.client.api.PulsarClientException; -import org.apache.pulsar.client.impl.schema.JSONSchema; -import org.apache.pulsar.common.functions.FunctionConfig; - -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Pattern; - -public class TestFunction { - - public static void main(String[] args) throws PulsarClientException, InterruptedException, PulsarAdminException { - - PulsarAdmin admin = PulsarAdmin.builder() - .serviceHttpUrl("http://192.168.0.112:8080") - .build(); - - String gatewayName = "test3"; - String tenant = "public"; - String namespace = "default"; - String inputTopicsPattern = "device_raw"; - String fullInputTopic = String.format("persistent://%s/%s/%s", tenant, namespace, inputTopicsPattern); - String outputTopic = "device_thing"; - String transform = "new (function() {\n this.decode=function(msg){\n //对msg进行解析,并返回物模型数据\n var mqttMsg=JSON.parse(msg.content);\n var topic=mqttMsg.topic;\n var payload=mqttMsg.payload;\n\n if(topic.endWith(\"/property/post\")){\n //属性上报\n return {\n \"mid\":msg.mid,\n \"productKey\":msg.productKey, //可根据消息内容判断填写不同产品\n \"deviceName\":msg.deviceName,\n \"identifier\":\"propertyReport\", //属性上报\n \"occur\":new Date().getTime(), //时间戳,设备上的事件或数据产生的本地时间\n \"time\":new Date().getTime(), //时间戳,消息上报时间\n \"data\":payload.params\n }\n }else if(topic.indexOf(\"/event/\")>0){\n var identifier=topic.substring(topic.lastIndexOf(\"/\")+1);\n //事件上报\n return {\n \"mid\":msg.mid,\n \"productKey\":msg.productKey,\n \"deviceName\":msg.deviceName,\n \"identifier\":identifier,\n \"occur\":new Date().getTime(),\n \"time\":new Date().getTime(),\n \"data\":payload.params\n }\n }else if(topic.endWith(\"_reply\")){\n var identifier=topic.substring(topic.lastIndexOf(\"/\")+1);\n //服务回复\n return {\n \"mid\":msg.mid,\n \"productKey\":msg.productKey,\n \"deviceName\":msg.deviceName,\n \"identifier\":identifier.replace(\"_reply\",\"Reply\"),\n \"occur\":new Date().getTime(),\n \"time\":new Date().getTime(),\n \"code\":payload.code,\n \"data\":payload.data\n } \n }\n return null;\n }\n\n})().decode(msg)"; - String functionClass = "cc.iotkit.protocol.function.UplinkTranslateFunction"; - String jarFile = "/Users/sjg/home/gitee/open-source/iotkit-parent/protocol-gateway/protocol-function/target/protocol-function-0.0.1-SNAPSHOT-jar-with-dependencies.jar"; - - FunctionConfig functionConfig = new FunctionConfig(); - functionConfig.setTenant(tenant); - functionConfig.setNamespace(namespace); - functionConfig.setName("UplinkTranslateFunction_" + gatewayName); - functionConfig.setRuntime(FunctionConfig.Runtime.JAVA); - functionConfig.setParallelism(1); - functionConfig.setClassName(functionClass); - functionConfig.setProcessingGuarantees(FunctionConfig.ProcessingGuarantees.ATLEAST_ONCE); - functionConfig.setTopicsPattern(fullInputTopic); - functionConfig.setSubName(functionConfig.getName()); - functionConfig.setAutoAck(true); - functionConfig.setOutput(String.format("persistent://%s/%s/%s", tenant, namespace, outputTopic)); - Map userConfig = new HashMap<>(); - userConfig.put("script", transform); - functionConfig.setUserConfig(userConfig); - for (String function : admin.functions().getFunctions(tenant, namespace)) { - System.out.println(function); - if (function.contains("test")) { - admin.functions().deleteFunction(tenant, namespace, function); - } - } -// if (admin.functions().getFunction(tenant, namespace, functionConfig.getName()) != null) { -// admin.functions().updateFunction(functionConfig, jarFile); -// } else { -// admin.functions().createFunction(functionConfig, jarFile); -// } - -// admin.functions().stopFunction("public", "default", "fun_4", 0); -// admin.functions().startFunction("public", "default", "fun_4", 0); - -// -// PulsarClient client = PulsarClient.builder() -// .serviceUrl("pulsar://localhost:6650") -// .build(); -// -// client.newConsumer() -// .topicsPattern(Pattern.compile("persistent://public/default/fun_out.*")) -// .subscriptionName("test1") -// .consumerName("test-fun-1") -// .messageListener((MessageListener) (consumer, msg) -> { -// try { -// System.out.printf("==============received:%s\n", new String(msg.getValue())); -// consumer.acknowledge(msg); -// } catch (Throwable e) { -// e.printStackTrace(); -// } -// }).subscribe(); - - - } - - -} diff --git a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/config/ProtocolConfig.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/config/ProtocolConfig.java deleted file mode 100755 index 275a3443..00000000 --- a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/config/ProtocolConfig.java +++ /dev/null @@ -1,17 +0,0 @@ -package cc.iotkit.protocol.server.config; - -import lombok.Data; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Configuration; - -@Configuration -@Data -public class ProtocolConfig { - - @Value("${pulsar.broker}") - private String pulsarBrokerUrl; - - @Value("${pulsar.service}") - private String pulsarServiceUrl; - -} diff --git a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/controller/DeviceBehaviourController.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/controller/DeviceBehaviourController.java deleted file mode 100755 index 1b4d76d4..00000000 --- a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/controller/DeviceBehaviourController.java +++ /dev/null @@ -1,59 +0,0 @@ -package cc.iotkit.protocol.server.controller; - -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.protocol.*; -import cc.iotkit.protocol.client.DeviceBehaviourClient; -import cc.iotkit.protocol.server.config.ProtocolConfig; -import cc.iotkit.protocol.server.service.BehaviourService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; - -@Slf4j -@RestController -@RequestMapping("/device_behaviour") -public class DeviceBehaviourController implements DeviceBehaviour { - - @Autowired - private ProtocolConfig serverConfig; - - @Autowired - private BehaviourService behaviourService; - - - @Override - @PostMapping("/register") - public Result register(@RequestBody RegisterInfo info) { - return behaviourService.register(info); - } - - @Override - @PostMapping("/online") - public Result online(String productKey, String deviceName) { - return behaviourService.deviceStateChange(productKey, deviceName, true); - } - - @Override - @PostMapping("/offline") - public Result offline(String productKey, String deviceName) { - return behaviourService.deviceStateChange(productKey, deviceName, false); - } - - @PostMapping("/getConfig") - public Result getConfig() { - return new Result(true, JsonUtil.toJsonString( - new DeviceBehaviourClient.GatewayConfig(serverConfig.getPulsarBrokerUrl()))); - } - - @Override - public void messageReport(DeviceMessage msg) { - throw new UnsupportedOperationException(); - } - - @Override - public void otaProgressReport(OtaMessage msg) { - throw new UnsupportedOperationException(); - } - - -} diff --git a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/BehaviourService.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/BehaviourService.java deleted file mode 100755 index 8a4ca0a8..00000000 --- a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/BehaviourService.java +++ /dev/null @@ -1,142 +0,0 @@ -package cc.iotkit.protocol.server.service; - -import cc.iotkit.common.exception.BizException; -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.dao.DeviceRepository; -import cc.iotkit.dao.ProductRepository; -import cc.iotkit.model.device.DeviceInfo; -import cc.iotkit.model.product.Product; -import cc.iotkit.protocol.RegisterInfo; -import cc.iotkit.protocol.Result; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.RandomUtils; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -@Slf4j -@Service -public class BehaviourService { - - @Autowired - private ProductRepository productRepository; - @Autowired - private DeviceRepository deviceRepository; - - - public Result register(RegisterInfo info) { - try { - DeviceInfo deviceInfo = register(null, info); - //子设备注册 - List subDevices = info.getSubDevices(); - if (subDevices != null && subDevices.size() != 0) { - for (RegisterInfo.SubDevice subDevice : subDevices) { - register(deviceInfo.getDeviceId(), - new RegisterInfo(subDevice.getProductKey(), - subDevice.getDeviceName(), - subDevice.getModel(), - subDevice.getTag(), null)); - } - } - //todo 产生设备注册事件 - } catch (BizException e) { - log.error("register device error", e); - return new Result(false, e.getMessage()); - } catch (Throwable e) { - log.error("register device error", e); - return new Result(false, "unknown error:" + e.getMessage()); - } - - return new Result(true, ""); - } - - public DeviceInfo register(String parentId, RegisterInfo info) { - String pk = info.getProductKey(); - Optional optProduct = productRepository.findById(pk); - if (!optProduct.isPresent()) { - throw new BizException("Product does not exist"); - } - String uid = optProduct.get().getUid(); - DeviceInfo device = deviceRepository.findByProductKeyAndDeviceName(pk, info.getDeviceName()); - - if (device != null) { - //更新设备信息 - device.setParentId(parentId); - device.setUid(uid); - Map tag = info.getTag(); - Map oldTag = device.getTag(); - - if (oldTag == null) { - oldTag = new HashMap<>(); - } - - if (tag != null) { - oldTag.putAll(tag); - } - - device.setTag(oldTag); - } else { - //不存在,注册新设备 - device = new DeviceInfo(); - device.setParentId(parentId); - device.setUid(uid); - device.setDeviceId(newDeviceId(info.getDeviceName())); - device.setProductKey(info.getProductKey()); - device.setDeviceName(info.getDeviceName()); - device.setTag(info.getTag()); - device.setState(new DeviceInfo.State(false, null, null)); - device.setCreateAt(System.currentTimeMillis()); - } - - deviceRepository.save(device); - log.info("device registered:{}", JsonUtil.toJsonString(device)); - - return device; - } - - /** - * 1-13位 时间戳 - * 14-29位 deviceNae,去除非字母和数字,不足16位补0,超过16位的mac取后16位,共16位 - * 30-31位 mac长度,共2位 - * 32位 随机一个0-f字符 - */ - public static String newDeviceId(String deviceNae) { - int maxDnLen = 16; - String dn = deviceNae.replaceAll("[^0-9A-Za-z]", ""); - if (dn.length() > maxDnLen) { - dn = dn.substring(dn.length() - maxDnLen); - } else { - dn = (dn + "00000000000000000000").substring(0, maxDnLen); - } - String len = StringUtils.leftPad(deviceNae.length() + "", 2, '0'); - String rnd = Integer.toHexString(RandomUtils.nextInt(0, 16)); - return (System.currentTimeMillis() + "0" + dn + len + rnd).toLowerCase(); - } - - public Result deviceStateChange(String productKey, - String deviceName, - boolean online) { - DeviceInfo device = deviceRepository.findByProductKeyAndDeviceName(productKey, deviceName); - if (device == null) { - return new Result(false, "device does not exist"); - } - - if (online) { - device.getState().setOnline(true); - device.getState().setOnlineTime(System.currentTimeMillis()); - } else { - device.getState().setOnline(false); - device.getState().setOfflineTime(System.currentTimeMillis()); - } - deviceRepository.save(device); - //todo 产生在离线事件 - - return new Result(true, ""); - } - -} diff --git a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/DeviceMessageConsumer.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/DeviceMessageConsumer.java deleted file mode 100755 index 04364c8d..00000000 --- a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/DeviceMessageConsumer.java +++ /dev/null @@ -1,75 +0,0 @@ -package cc.iotkit.protocol.server.service; - -import cc.iotkit.common.Constants; -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.dao.ThingModelMessageRepository; -import cc.iotkit.dao.UserInfoRepository; -import cc.iotkit.model.UserInfo; -import cc.iotkit.model.device.message.ThingModelMessage; -import cc.iotkit.protocol.server.config.ProtocolConfig; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.apache.pulsar.client.api.*; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.List; -import java.util.stream.Collectors; - -@Slf4j -//@Service -public class DeviceMessageConsumer implements MessageListener { - - private final ProtocolConfig serverConfig; - - private final ThingModelMessageRepository messageRepository; - - private final UserInfoRepository userInfoRepository; - - @SneakyThrows - @Autowired - public DeviceMessageConsumer(ProtocolConfig serverConfig, - ThingModelMessageRepository messageRepository, - UserInfoRepository userInfoRepository) { - this.serverConfig = serverConfig; - this.messageRepository = messageRepository; - this.userInfoRepository = userInfoRepository; - - PulsarClient client = PulsarClient.builder() - .serviceUrl(this.serverConfig.getPulsarBrokerUrl()) - .build(); - - String topicFormat = "persistent://%s/default/" + Constants.THING_MODEL_MESSAGE_TOPIC; - List platformUsers = userInfoRepository.findByType(UserInfo.USER_TYPE_PLATFORM); - List topics = platformUsers.stream().map(u -> String.format(topicFormat, u.getUid())) - .collect(Collectors.toList()); - log.info("subscribe device_thing topic:{}", JsonUtil.toJsonString(topics)); - - client.newConsumer(Schema.JSON(ThingModelMessage.class)) - .topics(topics) - .subscriptionName("thing-model-message") - .consumerName("thing-model-message-consumer") - .messageListener(this).subscribe(); - } - - @SneakyThrows - @Override - public void received(Consumer consumer, Message msg) { - ThingModelMessage modelMessage = msg.getValue(); - log.info("receive message:{}", JsonUtil.toJsonString(modelMessage)); - //设备消息日志入库 - messageRepository.save(modelMessage); - - messageRepository.findAll().forEach(m -> { - log.info(JsonUtil.toJsonString(m)); - }); - - consumer.acknowledge(msg); - } - - @Override - public void reachedEndOfTopic(Consumer consumer) { - - } - -} diff --git a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/GatewayService.java b/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/GatewayService.java deleted file mode 100755 index c00faf9d..00000000 --- a/protocol-gateway/protocol-server/src/main/java/cc/iotkit/protocol/server/service/GatewayService.java +++ /dev/null @@ -1,98 +0,0 @@ -package cc.iotkit.protocol.server.service; - -import cc.iotkit.common.Constants; -import cc.iotkit.common.utils.JsonUtil; -import cc.iotkit.protocol.function.DecodeFunction; -import cc.iotkit.protocol.server.config.ProtocolConfig; -import lombok.extern.slf4j.Slf4j; -import org.apache.pulsar.client.admin.PulsarAdmin; -import org.apache.pulsar.client.admin.PulsarAdminException; -import org.apache.pulsar.client.api.PulsarClientException; -import org.apache.pulsar.common.functions.FunctionConfig; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.HashMap; -import java.util.Map; - -@Slf4j -@Service -public class GatewayService { - - private PulsarAdmin pulsarAdmin; - - @Autowired - private ProtocolConfig serverConfig; - - private PulsarAdmin getPulsarAdmin() throws PulsarClientException { - if (pulsarAdmin == null) { - pulsarAdmin = PulsarAdmin.builder() - .serviceHttpUrl(serverConfig.getPulsarServiceUrl()) - .build(); - } - return pulsarAdmin; - } - - public void saveFunction(String tenant, String gatewayId, String script, - String jarFile) throws PulsarClientException, PulsarAdminException { - saveFunction(tenant, gatewayId, "default", script, jarFile); - } - - public void saveFunction(String tenant, String gatewayId, - String namespace, String script, - String jarFile) throws PulsarClientException, PulsarAdminException { - PulsarAdmin pulsarAdmin = getPulsarAdmin(); - -// String gatewayName = ""; -// String tenant = "public"; -// String namespace = "default"; -// String inputTopicsPattern = ""; - String fullInputTopic = String.format("persistent://%s/%s/%s", - tenant, namespace, Constants.DEVICE_RAW_MESSAGE_TOPIC); -// String outputTopic = ""; -// String transform = ""; -// String functionClass = "cc.iotkit.protocol.function.UplinkTranslateFunction"; -// String jarFile = "/Users/sjg/home/gitee/open-source/iotkit-parent/protocol-gateway/gateway-server/fun-test/target/fun-test-0.0.1-SNAPSHOT-jar-with-dependencies.jar"; - - String functionClass = DecodeFunction.class.getName(); - String functionName = functionClass.substring(functionClass.lastIndexOf(".") + 1) + "_" + gatewayId; - - FunctionConfig functionConfig = new FunctionConfig(); - functionConfig.setTenant(tenant); - functionConfig.setNamespace(namespace); - functionConfig.setName(functionName); - functionConfig.setRuntime(FunctionConfig.Runtime.JAVA); - functionConfig.setParallelism(1); - functionConfig.setClassName(functionClass); - functionConfig.setProcessingGuarantees(FunctionConfig.ProcessingGuarantees.ATLEAST_ONCE); - functionConfig.setTopicsPattern(fullInputTopic); - functionConfig.setSubName(functionConfig.getName()); - functionConfig.setAutoAck(true); - functionConfig.setOutput(String.format("persistent://%s/%s/%s", tenant, - namespace, Constants.THING_MODEL_MESSAGE_TOPIC)); - log.info("creating function:{}", JsonUtil.toJsonString(functionConfig)); - - Map userConfig = new HashMap<>(); - userConfig.put("script", script); - userConfig.put("gateway", gatewayId); - functionConfig.setUserConfig(userConfig); - - if (pulsarAdmin.functions().getFunctions(tenant, namespace).contains(functionName)) { - pulsarAdmin.functions().updateFunction(functionConfig, jarFile); - } else { - pulsarAdmin.functions().createFunction(functionConfig, jarFile); - } - } - - public void deleteFunction(String tenant, String gatewayId) throws PulsarClientException, PulsarAdminException { - String namespace = "default"; - String functionClass = DecodeFunction.class.getName(); - String functionName = functionClass.substring(functionClass.lastIndexOf(".") + 1) + "_" + gatewayId; - PulsarAdmin pulsarAdmin = getPulsarAdmin(); - if (!pulsarAdmin.functions().getFunctions(tenant, namespace).contains(functionName)) { - log.warn("function does not found,delete success."); - return; - } - pulsarAdmin.functions().deleteFunction(tenant, namespace, functionName); - } -} diff --git a/protocol-gateway/protocol-server/src/main/resources/logback-spring.xml b/protocol-gateway/protocol-server/src/main/resources/logback-spring.xml deleted file mode 100755 index 6322c4b5..00000000 --- a/protocol-gateway/protocol-server/src/main/resources/logback-spring.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - DEBUG - - - ${CONSOLE_LOG_PATTERN} - utf8 - - - - - - ${LOG_FILE}/info.log - - ${LOG_FILE}/info.%d{yyyy-MM-dd}.%i.gz - - 5 - - 20GB - - - 1GB - - - - ${CONSOLE_LOG_PATTERN} - utf8 - - - - - - ${LOG_FILE}/error.log - - ${LOG_FILE}/error.%d{yyyy-MM-dd}.%i.gz - - 5 - - 5GB - - - 1GB - - - - ${CONSOLE_LOG_PATTERN} - utf8 - - - ERROR - ACCEPT - DENY - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/protocol-gateway/protocol-server/src/main/resources/spring.factories b/protocol-gateway/protocol-server/src/main/resources/spring.factories deleted file mode 100755 index ae3134d9..00000000 --- a/protocol-gateway/protocol-server/src/main/resources/spring.factories +++ /dev/null @@ -1 +0,0 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration= cc.iotkit.protocol.config.GatewayConfig \ No newline at end of file diff --git a/rule-engine/pom.xml b/rule-engine/pom.xml index d911db84..81b00ac8 100755 --- a/rule-engine/pom.xml +++ b/rule-engine/pom.xml @@ -58,12 +58,12 @@ cc.iotkit - device-api + dao cc.iotkit - dao + component-server diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceAction.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceAction.java index f0c020ac..3876a679 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceAction.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceAction.java @@ -1,7 +1,5 @@ package cc.iotkit.ruleengine.action; -import cc.iotkit.deviceapi.IDeviceService; -import cc.iotkit.deviceapi.Service; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -11,15 +9,15 @@ import java.util.List; @NoArgsConstructor @AllArgsConstructor @Data -public class DeviceAction implements Action { +public class DeviceAction implements Action { public static final String TYPE = "device"; private String type; - private List services; + private List services; - private IDeviceService deviceService; + private DeviceActionService deviceActionService; @Override public String getType() { @@ -28,8 +26,8 @@ public class DeviceAction implements Action { @Override public void execute() { - for (Service service : services) { - deviceService.invoke(service); + for (DeviceActionService.Service service : services) { + deviceActionService.invoke(service); } } diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceActionExecutor.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceActionExecutor.java index 2e9f3c59..3a076772 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceActionExecutor.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceActionExecutor.java @@ -2,8 +2,6 @@ package cc.iotkit.ruleengine.action; import cc.iotkit.common.utils.JsonUtil; import cc.iotkit.dao.DeviceCache; -import cc.iotkit.deviceapi.IDeviceService; -import cc.iotkit.deviceapi.Service; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -16,11 +14,11 @@ import org.springframework.stereotype.Component; @Component public class DeviceActionExecutor implements ActionExecutor { - @Autowired - private IDeviceService deviceService; - @Autowired private DeviceCache deviceCache; + @Autowired + private DeviceActionService deviceActionService; + @Override public String getName() { @@ -36,8 +34,8 @@ public class DeviceActionExecutor implements ActionExecutor { //将执行的数据转换为动作配置 DeviceAction action = JsonUtil.parse(config, DeviceAction.class); log.info("start device service invoke,{}", JsonUtil.toJsonString(action)); - for (Service service : action.getServices()) { - deviceService.invoke(service); + for (DeviceActionService.Service service : action.getServices()) { + deviceActionService.invoke(service); } } } diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceActionService.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceActionService.java new file mode 100644 index 00000000..c06f9283 --- /dev/null +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceActionService.java @@ -0,0 +1,56 @@ +package cc.iotkit.ruleengine.action; + +import cc.iotkit.common.utils.UniqueIdUtil; +import cc.iotkit.comps.ComponentManager; +import cc.iotkit.converter.ThingService; +import lombok.Data; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +public class DeviceActionService { + + @Autowired + private ComponentManager componentManager; + + public String invoke(Service service) { + String[] pkDn = service.getDevice().split("/"); + ThingService> thingService = new ThingService<>(); + thingService.setMid(UniqueIdUtil.newRequestId()); + thingService.setProductKey(pkDn[0]); + thingService.setDeviceName(pkDn[1]); + thingService.setIdentifier(service.getIdentifier()); + thingService.setParams(service.parseInputData()); + componentManager.send(thingService); + return thingService.getMid(); + } + + @Data + public static class Service { + + private String device; + + private String identifier; + + private List inputData; + + public Map parseInputData() { + Map data = new HashMap<>(); + for (Parameter p : inputData) { + data.put(p.getIdentifier(), p.getValue()); + } + return data; + } + + @Data + public static class Parameter { + private String identifier; + private Object value; + } + } + +} diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/filter/DeviceCondition.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/filter/DeviceCondition.java index 778d0d00..df10e052 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/filter/DeviceCondition.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/filter/DeviceCondition.java @@ -31,7 +31,7 @@ public class DeviceCondition { left = properties.get(identifier); } else if ("state".equals(type)) { DeviceInfo.State state = deviceInfo.getState(); - left = state != null && state.getOnline(); + left = state != null && state.isOnline(); } return Expression.eval(comparator, left, value); } diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/scene/SceneManager.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/scene/SceneManager.java index cd4aaafc..3cb79b59 100755 --- a/rule-engine/src/main/java/cc/iotkit/ruleengine/scene/SceneManager.java +++ b/rule-engine/src/main/java/cc/iotkit/ruleengine/scene/SceneManager.java @@ -3,11 +3,11 @@ package cc.iotkit.ruleengine.scene; import cc.iotkit.common.utils.JsonUtil; import cc.iotkit.dao.DeviceCache; import cc.iotkit.dao.SceneInfoRepository; -import cc.iotkit.deviceapi.IDeviceService; import cc.iotkit.model.rule.RuleAction; import cc.iotkit.model.rule.SceneInfo; import cc.iotkit.ruleengine.action.Action; import cc.iotkit.ruleengine.action.DeviceAction; +import cc.iotkit.ruleengine.action.DeviceActionService; import cc.iotkit.ruleengine.config.RuleConfiguration; import cc.iotkit.ruleengine.filter.DeviceFilter; import cc.iotkit.ruleengine.filter.Filter; @@ -46,7 +46,7 @@ public class SceneManager { private DeviceCache deviceCache; @Autowired - private IDeviceService deviceService; + private DeviceActionService deviceActionService; public SceneManager() { ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); @@ -165,7 +165,7 @@ public class SceneManager { private Action parseAction(String type, String config) { if (DeviceAction.TYPE.equals(type)) { DeviceAction action = parse(config, DeviceAction.class); - action.setDeviceService(deviceService); + action.setDeviceActionService(deviceActionService); return action; } return null; From 758f6e12f8d08fa2105270d8d771d0131f2e764f Mon Sep 17 00:00:00 2001 From: xiwa Date: Mon, 28 Mar 2022 19:02:35 +0800 Subject: [PATCH 10/16] =?UTF-8?q?pom=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cc/iotkit/dao/DeviceDao.java | 0 .../java/cc/iotkit/dao/DevicePropertyDao.java | 0 .../cc/iotkit/dao/ThingModelMessageDao.java | 0 .../cc/iotkit/manager/model/vo/DeviceLog.java | 0 .../src/main/resources/application-dev.yml | 10 ++++++ manager/src/main/resources/application.yml | 12 +++++-- .../model/device/message/DeviceProperty.java | 0 .../java/cc/iotkit/comps/config/CacheKey.java | 0 .../comps/service/DeviceStateHolder.java | 0 .../cc/iotkit/comp/AbstractComponent.java | 15 ++++++++ .../main/java/cc/iotkit/comp/CompConfig.java | 0 .../main/java/cc/iotkit/comp/IComponent.java | 5 +++ .../cc/iotkit/comp/model/ReceiveResult.java | 0 protocol-gateway/emqx-component/pom.xml | 0 .../cc/iotkit/comp/emqx/AuthVerticle.java | 0 .../cc/iotkit/comp/emqx/EmqxComponent.java | 0 .../java/cc/iotkit/comp/emqx/EmqxConfig.java | 0 protocol-gateway/mqtt-component/.DS_Store | Bin 0 -> 8196 bytes protocol-gateway/mqtt-component/pom.xml | 34 ++++++++++++++++++ .../src/main/resources/component.js | 0 .../src/main/resources/converter.js | 0 protocol-gateway/pom.xml | 1 + .../action/DeviceActionService.java | 0 23 files changed, 75 insertions(+), 2 deletions(-) mode change 100644 => 100755 dao/src/main/java/cc/iotkit/dao/DeviceDao.java mode change 100644 => 100755 dao/src/main/java/cc/iotkit/dao/DevicePropertyDao.java mode change 100644 => 100755 dao/src/main/java/cc/iotkit/dao/ThingModelMessageDao.java mode change 100644 => 100755 manager/src/main/java/cc/iotkit/manager/model/vo/DeviceLog.java mode change 100644 => 100755 model/src/main/java/cc/iotkit/model/device/message/DeviceProperty.java mode change 100644 => 100755 protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/CacheKey.java mode change 100644 => 100755 protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceStateHolder.java mode change 100644 => 100755 protocol-gateway/component/src/main/java/cc/iotkit/comp/CompConfig.java mode change 100644 => 100755 protocol-gateway/component/src/main/java/cc/iotkit/comp/model/ReceiveResult.java mode change 100644 => 100755 protocol-gateway/emqx-component/pom.xml mode change 100644 => 100755 protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/AuthVerticle.java mode change 100644 => 100755 protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/EmqxComponent.java mode change 100644 => 100755 protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/EmqxConfig.java create mode 100644 protocol-gateway/mqtt-component/.DS_Store mode change 100644 => 100755 protocol-gateway/mqtt-component/src/main/resources/component.js mode change 100644 => 100755 protocol-gateway/mqtt-component/src/main/resources/converter.js mode change 100644 => 100755 rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceActionService.java diff --git a/dao/src/main/java/cc/iotkit/dao/DeviceDao.java b/dao/src/main/java/cc/iotkit/dao/DeviceDao.java old mode 100644 new mode 100755 diff --git a/dao/src/main/java/cc/iotkit/dao/DevicePropertyDao.java b/dao/src/main/java/cc/iotkit/dao/DevicePropertyDao.java old mode 100644 new mode 100755 diff --git a/dao/src/main/java/cc/iotkit/dao/ThingModelMessageDao.java b/dao/src/main/java/cc/iotkit/dao/ThingModelMessageDao.java old mode 100644 new mode 100755 diff --git a/manager/src/main/java/cc/iotkit/manager/model/vo/DeviceLog.java b/manager/src/main/java/cc/iotkit/manager/model/vo/DeviceLog.java old mode 100644 new mode 100755 diff --git a/manager/src/main/resources/application-dev.yml b/manager/src/main/resources/application-dev.yml index 8c3f5c39..2a9c0ec1 100755 --- a/manager/src/main/resources/application-dev.yml +++ b/manager/src/main/resources/application-dev.yml @@ -11,6 +11,12 @@ spring: password: 密码 connection-timeout: 10s + redis: + host: redis地址 + port: 6379 + database: 0 + password: redis密码 + cache: cache-names: foo,bar caffeine: @@ -47,6 +53,10 @@ keycloak-admin-clientid : 填写keycloak中定义的clientId keycloak-admin-user : 填写keycloak中添加的管理员用户名 keycloak-admin-password : 填写keycloak中添加的管理员密码 +pulsar: + broker: pulsar://pulsar broker地址:6650 + service: http://pulsar 服务地址:8080 + app: systemRole: iot_system_user diff --git a/manager/src/main/resources/application.yml b/manager/src/main/resources/application.yml index 8c3f5c39..8973fa15 100755 --- a/manager/src/main/resources/application.yml +++ b/manager/src/main/resources/application.yml @@ -7,10 +7,14 @@ spring: elasticsearch: rest: uris: http://elasticsearch 连接地址 - username: elasticsearch 用户名 - password: 密码 connection-timeout: 10s + redis: + host: redis地址 + port: 6379 + database: 0 + password: + cache: cache-names: foo,bar caffeine: @@ -47,6 +51,10 @@ keycloak-admin-clientid : 填写keycloak中定义的clientId keycloak-admin-user : 填写keycloak中添加的管理员用户名 keycloak-admin-password : 填写keycloak中添加的管理员密码 +pulsar: + broker: pulsar://pulsar broker地址:6650 + service: http://pulsar 服务地址:8080 + app: systemRole: iot_system_user diff --git a/model/src/main/java/cc/iotkit/model/device/message/DeviceProperty.java b/model/src/main/java/cc/iotkit/model/device/message/DeviceProperty.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/CacheKey.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/CacheKey.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceStateHolder.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/service/DeviceStateHolder.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java index 81e7936f..7fd6ebbb 100755 --- a/protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/AbstractComponent.java @@ -1,5 +1,8 @@ package cc.iotkit.comp; +import cc.iotkit.comp.model.AuthInfo; +import cc.iotkit.comp.model.DeviceState; +import cc.iotkit.comp.model.RegisterInfo; import cc.iotkit.converter.IConverter; import lombok.Data; @@ -17,6 +20,18 @@ public abstract class AbstractComponent implements IComponent { this.config=config; } + @Override + public void onDeviceRegister(RegisterInfo info) { + } + + @Override + public void onDeviceAuth(AuthInfo authInfo) { + } + + @Override + public void onDeviceStateChange(DeviceState state) { + } + @Override public CompConfig getConfig() { return config; diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/CompConfig.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/CompConfig.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/IComponent.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/IComponent.java index 110e89c5..7f42d4fe 100755 --- a/protocol-gateway/component/src/main/java/cc/iotkit/comp/IComponent.java +++ b/protocol-gateway/component/src/main/java/cc/iotkit/comp/IComponent.java @@ -1,5 +1,6 @@ package cc.iotkit.comp; +import cc.iotkit.comp.model.AuthInfo; import cc.iotkit.comp.model.DeviceState; import cc.iotkit.comp.model.RegisterInfo; import cc.iotkit.converter.DeviceMessage; @@ -15,6 +16,10 @@ public interface IComponent { void destroy(); + void onDeviceAuth(AuthInfo authInfo); + + void onDeviceRegister(RegisterInfo info); + void onDeviceStateChange(DeviceState state); void send(DeviceMessage message); diff --git a/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/ReceiveResult.java b/protocol-gateway/component/src/main/java/cc/iotkit/comp/model/ReceiveResult.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/emqx-component/pom.xml b/protocol-gateway/emqx-component/pom.xml old mode 100644 new mode 100755 diff --git a/protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/AuthVerticle.java b/protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/AuthVerticle.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/EmqxComponent.java b/protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/EmqxComponent.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/EmqxConfig.java b/protocol-gateway/emqx-component/src/main/java/cc/iotkit/comp/emqx/EmqxConfig.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/mqtt-component/.DS_Store b/protocol-gateway/mqtt-component/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..827186b49513595a75535f93cfc68c54c4dafbbd GIT binary patch literal 8196 zcmeHMO^g&p6n?LFS-Rw}7TKR31V&Z?aR{@Ei^!r5JG=ZS1Z4IfbnKaKc02TTuhTs< z2(H;gjL|3>e{O2R#RG|GjEU&M6BkYJpc{h1!Gm7Bc+r42Usd%GSePSXLRV7ts_MO0 z)$jH9y5`jY0QQ!xPJng*(5VW_7f^GHBKV@-RJ3TOktmWrfDK`x8cY>jzi^XuJP~^! z_CV}`*aNW#Vh{WuJV0l*D0-c9Uvc9$_CV}`yV3*V`;eq6XeOdFipoz1H8KStDpCMh zs84x-)JaA(6VVw(r7EqdvImS*F-kE|sS`gb#EE7iI-{sk2UO~S(asoUC@6O)y`&Te z%qSYSu?J!g-0T4nK1~pU2_+bxlfQpem~x#UOs6lP*3dYwX}&&RU!XsmoA9f-&rMqdJ0G{>qp=9=UNm8`mw zXlSUJbg^a*kzeb}$m!M?=vY3;a@;m4YJ<>592LUn=zXO@)r{1w(czAj;U8g)J*q zuX#A#z4giL&OQ5Q7cE}G*;2M_xZ(s(!L?^P|idt|)8y z)6rzlHfD?z{mDr(C1}P}G@YTHpA$RpF@td5l9lAa$c-t+@wq|)-d+V;< zhA|dQm?e8(l`zJC6i-U?dud+2IO2$v`Yk8)OA+%K$>fe#aR|Wl3KWiYUGK=OQ!tV) z?Z~9nh>LT{fD}9dJ75fo;6WAMgty=%d<37s8Tb;uh40{dI1fL-PjDH2gFoOe_#3Xk zRYbf8+t9!SF2@Hjjh)zqJ($5>%wiwz#RE8igE)kFv~e6K(7_TO!Lds zhpfcu4d|9Ql`nPI!86w!nQIB9^N=>5N@|U&KL&~)U38rR@Zr5WY)#y zDL4(E!&x{-xV!+D;8*yQun5?M99s#G0*xzh4X(w9a6P858#m(?e2kFUhyAz{ci~f* zBV-QYFpgpYi)i6t^l^&N8DN>PIfJj@349e#;@gDMcL}E-;;A{P+f~DxqIh~P>MFUC z=lb3_&DW56qe?uw-5zLA8?=l3zrX(d|LuN^c>UM|u?Oy;2e7d(*VjuAQ13%5a_uD5 z=c$S! + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.4 + + + package + + shade + + + + + + + io.vertx:vertx-core + io.vertx:vertx-mqtt + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + \ No newline at end of file diff --git a/protocol-gateway/mqtt-component/src/main/resources/component.js b/protocol-gateway/mqtt-component/src/main/resources/component.js old mode 100644 new mode 100755 diff --git a/protocol-gateway/mqtt-component/src/main/resources/converter.js b/protocol-gateway/mqtt-component/src/main/resources/converter.js old mode 100644 new mode 100755 diff --git a/protocol-gateway/pom.xml b/protocol-gateway/pom.xml index 71ac04b7..81409a9e 100755 --- a/protocol-gateway/pom.xml +++ b/protocol-gateway/pom.xml @@ -17,6 +17,7 @@ mqtt-component emqx-component component + mqtt-client-simulator \ No newline at end of file diff --git a/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceActionService.java b/rule-engine/src/main/java/cc/iotkit/ruleengine/action/DeviceActionService.java old mode 100644 new mode 100755 From 2d74d0fb91e4fac0feb113feace8659f89d7920a Mon Sep 17 00:00:00 2001 From: xiwa Date: Tue, 29 Mar 2022 05:12:40 +0800 Subject: [PATCH 11/16] =?UTF-8?q?=E9=80=9A=E8=AE=AF=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E5=92=8C=E4=B8=8A=E4=BC=A0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dao/ProtocolComponentRepository.java | 9 ++ .../iotkit/dao/ProtocolGatewayRepository.java | 4 +- data/elasticsearch/nodes/0/_state/_3.cfe | Bin 0 -> 278 bytes data/elasticsearch/nodes/0/_state/_3.cfs | Bin 0 -> 1274 bytes data/elasticsearch/nodes/0/_state/_3.si | Bin 0 -> 378 bytes .../nodes/0/_state/manifest-0.st | Bin 0 -> 109 bytes data/elasticsearch/nodes/0/_state/node-0.st | Bin 0 -> 89 bytes data/elasticsearch/nodes/0/_state/segments_5 | Bin 0 -> 245 bytes data/elasticsearch/nodes/0/_state/write.lock | 0 data/elasticsearch/nodes/0/node.lock | 0 .../manager/config/ElasticSearchConfig.java | 76 +++++++++++ .../controller/ProtocolController.java | 120 +++++++++++------- .../src/main/resources/application-dev.yml | 7 + manager/src/main/resources/application.yml | 7 + ...colGateway.java => ProtocolComponent.java} | 11 +- pom.xml | 2 +- .../cc/iotkit/comps/ComponentClassLoader.java | 30 +++++ protocol-gateway/mqtt-component/.DS_Store | Bin .../mqtt-component/dependency-reduced-pom.xml | 79 ++++++++++++ 19 files changed, 293 insertions(+), 52 deletions(-) create mode 100755 dao/src/main/java/cc/iotkit/dao/ProtocolComponentRepository.java create mode 100644 data/elasticsearch/nodes/0/_state/_3.cfe create mode 100644 data/elasticsearch/nodes/0/_state/_3.cfs create mode 100644 data/elasticsearch/nodes/0/_state/_3.si create mode 100644 data/elasticsearch/nodes/0/_state/manifest-0.st create mode 100644 data/elasticsearch/nodes/0/_state/node-0.st create mode 100644 data/elasticsearch/nodes/0/_state/segments_5 create mode 100644 data/elasticsearch/nodes/0/_state/write.lock create mode 100644 data/elasticsearch/nodes/0/node.lock create mode 100644 manager/src/main/java/cc/iotkit/manager/config/ElasticSearchConfig.java rename model/src/main/java/cc/iotkit/model/protocol/{ProtocolGateway.java => ProtocolComponent.java} (71%) create mode 100644 protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentClassLoader.java mode change 100644 => 100755 protocol-gateway/mqtt-component/.DS_Store create mode 100644 protocol-gateway/mqtt-component/dependency-reduced-pom.xml diff --git a/dao/src/main/java/cc/iotkit/dao/ProtocolComponentRepository.java b/dao/src/main/java/cc/iotkit/dao/ProtocolComponentRepository.java new file mode 100755 index 00000000..68d51cbb --- /dev/null +++ b/dao/src/main/java/cc/iotkit/dao/ProtocolComponentRepository.java @@ -0,0 +1,9 @@ +package cc.iotkit.dao; + +import cc.iotkit.model.protocol.ProtocolComponent; +import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ProtocolComponentRepository extends MongoRepository { +} diff --git a/dao/src/main/java/cc/iotkit/dao/ProtocolGatewayRepository.java b/dao/src/main/java/cc/iotkit/dao/ProtocolGatewayRepository.java index d304423c..8248a283 100755 --- a/dao/src/main/java/cc/iotkit/dao/ProtocolGatewayRepository.java +++ b/dao/src/main/java/cc/iotkit/dao/ProtocolGatewayRepository.java @@ -1,11 +1,11 @@ package cc.iotkit.dao; -import cc.iotkit.model.protocol.ProtocolGateway; +import cc.iotkit.model.protocol.ProtocolComponent; import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.stereotype.Repository; @Repository -public interface ProtocolGatewayRepository extends MongoRepository { +public interface ProtocolGatewayRepository extends MongoRepository { } diff --git a/data/elasticsearch/nodes/0/_state/_3.cfe b/data/elasticsearch/nodes/0/_state/_3.cfe new file mode 100644 index 0000000000000000000000000000000000000000..cf99088bf5625d865d7b89fabca7ebe890759c25 GIT binary patch literal 278 zcmcD&o+B>qQ<|KbmuhO@oS$2eUz(TVnpaYknOe*M1T&9(IKDFS&sz=7)5~-XV}CJl zu;`_wRDh&_Ko3GOIPk|q%&;(tH_%JTPlk%;L1{mbrd%jz50st<6wHGPGDblKSD~0x zk_nY(Vu8wsf=nubaF`+?G-ErOrUHmK^8*OY;DIWin*tGM(SXVyI-oK61(eNDd+lv6 E09fZbod5s; literal 0 HcmV?d00001 diff --git a/data/elasticsearch/nodes/0/_state/_3.cfs b/data/elasticsearch/nodes/0/_state/_3.cfs new file mode 100644 index 0000000000000000000000000000000000000000..4d78d2464bca17efdfe4c3ec9f14f85be378fc4a GIT binary patch literal 1274 zcmah|&ubGw6rS0nsjaYxmKM?CLB#eDNuf=O2Machu0|;&Aw-a{*`372-JP&INt58A zAk-GYOO&7o5f6eO2%bIEB6uixD`Nfv4=Q^qZ6fN-{-B$*)(6X*<$dqlZ|8k)?u$A$ zlB`HbM>COmtd(&^m*XN40gb00txvCWzkW;%ZN3Um-R^)niXL^)voi?=sj?~PGO7u3 z?LhqcMDrUfu+ZP1PqO}#ZvXTmHi@E_%&eghWW=#VL9qXm!yY;xN&49uZ-ZNmZR`Lw zH;^qq*v|!)*Uxe6BlH=j4?DAnI0=BcW$(0?y<&9!#r~>Wgi8=Yzq+sQE)6nu#~pRi zh<#UrUc@G4=JpBWf}~zXfP>(V8{GIJGVCtzniAO1L~@~Mrz76A{0nAQibbUcBOoZ# zVX{B=m;vxB&At3EX)C>~V(D($Kq!q2&5SD&p*^8~rM__lrb{X=h-x4NA$PBbbfoqC zJ0m^qs*I%wHjwNXCLx-{HQ4?Mfe?Jg!Ex@47o*39EWX8EoE#qLtZHj0Lb?#k33uwLoK_~+%9*IePYI3Lr6-aPm6x!lDTE;Tti?CI ziiEKtE4oN1Z|6Q`)HWVdaw>NZPfvPLDeYvWd^8ciZt;Sc7P1X7lU4FJ>kGN1-KO0j zN)jp)i$`)_haYe8c1Np<*&evSJgPB4RD;EvJGoQ<|Kbmug`aoSL4SnpfhPmzK`}1T&9(IKDFS&sz=7)5~-XV}F6fIDnWF z#9&0`fcT7DO!>tezKO{S{=o_n+*yfbiF#$Jc`5ltLjFaG$vLSC&iO?J`9+B(nfZA< zQ0by#AcxaX&qB{2-pI_5A0nI!)CiX0GBVWz3hO2r8u8_T9SM_Rwa~NFGhojz)=Ml( z&S0ysFpD=c5dmv2D$Og&%uR)<JCys=(!CL54UPAi5`sf_Z_kTVZ1$uCMxam!52 qNhx;AFUn0U(aX(GN#$~K4GxJ94sdmKVK|^M`2{H8KtOS#qZI(z>u)Fk literal 0 HcmV?d00001 diff --git a/data/elasticsearch/nodes/0/_state/manifest-0.st b/data/elasticsearch/nodes/0/_state/manifest-0.st new file mode 100644 index 0000000000000000000000000000000000000000..030f9cbe09eade2c5fa41802ec7ca16ee9e3ac1f GIT binary patch literal 109 zcmcD&o+Hj$T#{Il%D}+D2*OsHT&%yklS_+=Qu9jUOHzw+4@^nUDJ=%F;=u~z%TkMq tGxPHfbf%}~r4}WY0NDp8Wag!$R>UJjihun4eL!RK3!sr;pmG1sCIFIlD$W1^ literal 0 HcmV?d00001 diff --git a/data/elasticsearch/nodes/0/_state/node-0.st b/data/elasticsearch/nodes/0/_state/node-0.st new file mode 100644 index 0000000000000000000000000000000000000000..a819c66f42c5335dada71a9525e4aec2c24bd285 GIT binary patch literal 89 zcmcD&o+Hj$T#{Il%D}+D2*OsHT&%y^^72zs<1zeDFQX|3Cj$pi1_UHofCM8@ zfGOS>P2n#NpVH*iyi^PG|4;zZ0As^wkQgJH&OabQ1{R*Y{FK!AvecsD%=|odb3;=D zBTGxsoW$ai_{8Mo)Pj=K6qqcdAy0B?Q4!F|@g=E6xr~PFV7-|sV#)DlZZ6)Qi6Nfh cRf(bDnel#=u94*jG$y|QTLL7WWS?UJ01?Sx(*OVf literal 0 HcmV?d00001 diff --git a/data/elasticsearch/nodes/0/_state/write.lock b/data/elasticsearch/nodes/0/_state/write.lock new file mode 100644 index 00000000..e69de29b diff --git a/data/elasticsearch/nodes/0/node.lock b/data/elasticsearch/nodes/0/node.lock new file mode 100644 index 00000000..e69de29b diff --git a/manager/src/main/java/cc/iotkit/manager/config/ElasticSearchConfig.java b/manager/src/main/java/cc/iotkit/manager/config/ElasticSearchConfig.java new file mode 100644 index 00000000..e67249e1 --- /dev/null +++ b/manager/src/main/java/cc/iotkit/manager/config/ElasticSearchConfig.java @@ -0,0 +1,76 @@ +package cc.iotkit.manager.config; + +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.node.InternalSettingsPreparer; +import org.elasticsearch.node.Node; +import org.elasticsearch.transport.Netty4Plugin; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +import java.util.Collections; + +@Slf4j +@Configuration +public class ElasticSearchConfig { + + static { + System.setProperty("es.set.netty.runtime.available.processors", "false"); + } + + + @SneakyThrows + @Bean + public EmbeddedElasticSearch getEmbeddedElasticSearch(ConfigProperty configProperty) { + if (configProperty.enabled) { + EmbeddedElasticSearch embeddedElasticSearch = new EmbeddedElasticSearch(configProperty); + embeddedElasticSearch.start(); + return embeddedElasticSearch; + } + return null; + } + + @Component + @ConfigurationProperties(prefix = "elasticsearch.embedded") + public static class ConfigProperty { + + private boolean enabled; + + private String dataPath = "./data/elasticsearch"; + + private String homePath = "./"; + + private int port = 9200; + + private String host = "0.0.0.0"; + + public Settings.Builder applySetting(Settings.Builder settings) { + return settings.put("network.host", host) + .put("http.port", port) + .put("path.data", dataPath) + .put("path.home", homePath); + } + + } + + public static class EmbeddedElasticSearch extends Node { + + @SneakyThrows + public EmbeddedElasticSearch(ConfigProperty properties) { + super(InternalSettingsPreparer.prepareEnvironment( + properties.applySetting( + Settings.builder() + .put("node.name", "test") + .put("discovery.type", "single-node") + .put("transport.type", Netty4Plugin.NETTY_TRANSPORT_NAME) + .put("http.type", Netty4Plugin.NETTY_HTTP_TRANSPORT_NAME) + .put("network.host", "0.0.0.0") + .put("http.port", 9200) + ).build(), Collections.emptyMap(), null, () -> "default"), + Collections.singleton(Netty4Plugin.class), false); + } + } +} diff --git a/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java b/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java index 03a02fdc..13cf7f48 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java @@ -6,13 +6,14 @@ import cc.iotkit.comp.CompConfig; import cc.iotkit.comp.mqtt.MqttComponent; import cc.iotkit.comps.ComponentManager; import cc.iotkit.converter.ScriptConverter; -import cc.iotkit.dao.ProtocolGatewayRepository; +import cc.iotkit.dao.ProtocolComponentRepository; import cc.iotkit.dao.UserInfoRepository; import cc.iotkit.manager.service.DataOwnerService; import cc.iotkit.manager.utils.AuthUtil; import cc.iotkit.model.Paging; import cc.iotkit.model.UserInfo; -import cc.iotkit.model.protocol.ProtocolGateway; +import cc.iotkit.model.protocol.ProtocolComponent; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FileUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -20,10 +21,17 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; +import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import javax.annotation.PostConstruct; import java.io.File; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; import java.util.Optional; @Slf4j @@ -34,8 +42,11 @@ public class ProtocolController { @Value("${gateway.function-jar}") private String functionJar; + @Value("${spring.servlet.multipart.upload-dir}") + private String uploadDir; + @Autowired - private ProtocolGatewayRepository gatewayRepository; + private ProtocolComponentRepository protocolComponentRepository; @Autowired private DataOwnerService dataOwnerService; @@ -46,11 +57,35 @@ public class ProtocolController { @Autowired private ComponentManager componentManager; - @PostMapping("/addGateway") - public void addGateway(ProtocolGateway gateway) { - Optional optGateway = gatewayRepository.findById(gateway.getId()); - if (optGateway.isPresent()) { - throw new BizException("gateway already exists"); + private Path fileStorageLocation; + + @SneakyThrows + @PostConstruct + public void init() { + this.fileStorageLocation = Paths.get(uploadDir).toAbsolutePath().normalize(); + Files.createDirectories(this.fileStorageLocation); + } + + @PostMapping("/uploadJar") + public void uploadJar(@RequestParam("file") MultipartFile file) { + if (file == null) { + throw new BizException("file is null"); + } + + String fileName = StringUtils.cleanPath(file.getOriginalFilename()); + try { + Path targetLocation = this.fileStorageLocation.resolve(fileName); + Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException ex) { + throw new BizException("upload jar error", ex); + } + } + + @PostMapping("/addComponent") + public void addComponent(ProtocolComponent component) { + Optional optComponent = protocolComponentRepository.findById(component.getId()); + if (optComponent.isPresent()) { + throw new BizException("component already exists"); } try { Optional optUser = userInfoRepository.findById(AuthUtil.getUserId()); @@ -58,72 +93,71 @@ public class ProtocolController { throw new BizException("user does not exists"); } - gateway.setScript("new (function () {this.decode = function (msg) {return null; };})().decode(msg)"); - gateway.setCreateAt(System.currentTimeMillis()); - gateway.setUid(AuthUtil.getUserId()); - gateway.setUuid(optUser.get().getUid()); - gatewayRepository.save(gateway); + component.setScript("new (function () {this.decode = function (msg) {return null; };})().decode(msg)"); + component.setCreateAt(System.currentTimeMillis()); + component.setUid(AuthUtil.getUserId()); + protocolComponentRepository.save(component); } catch (Throwable e) { - throw new BizException("add protocol gateway error", e); + throw new BizException("add protocol component error", e); } } - @PostMapping("/saveGateway") - public void saveGateway(ProtocolGateway gateway) { - Optional optGateway = gatewayRepository.findById(gateway.getId()); - if (!optGateway.isPresent()) { - throw new BizException("the gateway does not exists"); + @PostMapping("/saveComponent") + public void saveComponent(ProtocolComponent component) { + Optional optComponent = protocolComponentRepository.findById(component.getId()); + if (!optComponent.isPresent()) { + throw new BizException("the protocol component does not exists"); } Optional optUser = userInfoRepository.findById(AuthUtil.getUserId()); if (!optUser.isPresent()) { throw new BizException("user does not exists"); } - ProtocolGateway oldGateway = optGateway.get(); - gateway = ReflectUtil.copyNoNulls(gateway, oldGateway); - dataOwnerService.checkOwner(gateway); + ProtocolComponent oldComponent = optComponent.get(); + component = ReflectUtil.copyNoNulls(component, oldComponent); + dataOwnerService.checkOwner(component); try { - gatewayRepository.save(gateway); + protocolComponentRepository.save(component); } catch (Throwable e) { - throw new BizException("add protocol gateway error", e); + throw new BizException("add protocol component error", e); } } - @PostMapping("/saveGatewayScript") - public void saveGatewayScript(@RequestBody ProtocolGateway gateway) { - Optional optGateway = gatewayRepository.findById(gateway.getId()); - if (!optGateway.isPresent()) { - throw new BizException("the gateway does not exists"); + @PostMapping("/saveComponentScript") + public void saveComponentScript(@RequestBody ProtocolComponent component) { + Optional optComponent = protocolComponentRepository.findById(component.getId()); + if (!optComponent.isPresent()) { + throw new BizException("the component does not exists"); } - dataOwnerService.checkOwner(gateway); - ProtocolGateway oldGateway = optGateway.get(); - oldGateway.setScript(gateway.getScript()); + dataOwnerService.checkOwner(component); + ProtocolComponent oldComponent = optComponent.get(); + oldComponent.setScript(component.getScript()); try { // gatewayService.saveFunction(oldGateway.getUuid(), oldGateway.getId(), // "new (function (){" + oldGateway.getScript() + "})()", functionJar); - gatewayRepository.save(oldGateway); + protocolComponentRepository.save(oldComponent); } catch (Throwable e) { - throw new BizException("save protocol gateway script error", e); + throw new BizException("save protocol component script error", e); } } - @PostMapping("/deleteGateway/{id}") - public void deleteGateway(@PathVariable("id") String id) { - dataOwnerService.checkOwner(gatewayRepository, id); + @PostMapping("/deleteComponent/{id}") + public void deleteComponent(@PathVariable("id") String id) { + dataOwnerService.checkOwner(protocolComponentRepository, id); try { - gatewayRepository.deleteById(id); + protocolComponentRepository.deleteById(id); } catch (Throwable e) { - throw new BizException("delete protocol gateway error", e); + throw new BizException("delete protocol component error", e); } } - @PostMapping("/gateways/{size}/{page}") - public Paging getGateways( + @PostMapping("/components/{size}/{page}") + public Paging getComponents( @PathVariable("size") int size, @PathVariable("page") int page) { - Page gateways = gatewayRepository.findAll( + Page components = protocolComponentRepository.findAll( PageRequest.of(page - 1, size, Sort.by(Sort.Order.desc("createAt")))); - return new Paging<>(gateways.getTotalElements(), gateways.getContent()); + return new Paging<>(components.getTotalElements(), components.getContent()); } @GetMapping("/registerMqtt") diff --git a/manager/src/main/resources/application-dev.yml b/manager/src/main/resources/application-dev.yml index 2a9c0ec1..ebc395c7 100755 --- a/manager/src/main/resources/application-dev.yml +++ b/manager/src/main/resources/application-dev.yml @@ -1,4 +1,11 @@ spring: + servlet: + multipart: + enabled: true + max-file-size: 10MB + max-request-size: 12MB + upload-dir: ./component_jar + data: mongodb: uri: mongodb://填写mongodb地址/admin diff --git a/manager/src/main/resources/application.yml b/manager/src/main/resources/application.yml index 8973fa15..1b6731d8 100755 --- a/manager/src/main/resources/application.yml +++ b/manager/src/main/resources/application.yml @@ -1,4 +1,11 @@ spring: + servlet: + multipart: + enabled: true + max-file-size: 10MB + max-request-size: 12MB + upload-dir: ./component_jar + data: mongodb: uri: mongodb://填写mongodb地址/admin diff --git a/model/src/main/java/cc/iotkit/model/protocol/ProtocolGateway.java b/model/src/main/java/cc/iotkit/model/protocol/ProtocolComponent.java similarity index 71% rename from model/src/main/java/cc/iotkit/model/protocol/ProtocolGateway.java rename to model/src/main/java/cc/iotkit/model/protocol/ProtocolComponent.java index 38752ddf..e80098a1 100755 --- a/model/src/main/java/cc/iotkit/model/protocol/ProtocolGateway.java +++ b/model/src/main/java/cc/iotkit/model/protocol/ProtocolComponent.java @@ -3,9 +3,11 @@ package cc.iotkit.model.protocol; import cc.iotkit.model.Owned; import lombok.Data; import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; @Data -public class ProtocolGateway implements Owned { +@Document +public class ProtocolComponent implements Owned { @Id private String id; @@ -15,15 +17,12 @@ public class ProtocolGateway implements Owned { */ private String uid; - /** - * 用户账号ID - */ - private String uuid; - private String name; private String protocol; + private String jarFile; + private String config; private String script; diff --git a/pom.xml b/pom.xml index b9873bf3..d150113b 100755 --- a/pom.xml +++ b/pom.xml @@ -139,7 +139,7 @@ co.elastic.clients elasticsearch-java - 8.1.0 + 7.17 diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentClassLoader.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentClassLoader.java new file mode 100644 index 00000000..0f8cbc02 --- /dev/null +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentClassLoader.java @@ -0,0 +1,30 @@ +package cc.iotkit.comps; + +import cc.iotkit.comp.CompConfig; +import cc.iotkit.comp.IComponent; + +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; + +public class ComponentClassLoader { + + protected Class findClass(String name) throws ClassNotFoundException { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + return (Class) classLoader.loadClass("cc.iotkit.comp.mqtt.MqttComponent"); + } + + public void addUrl(File jarPath) throws NoSuchMethodException, InvocationTargetException, + IllegalAccessException, MalformedURLException { + URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); + Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); + if (!method.isAccessible()) { + method.setAccessible(true); + } + URL url = jarPath.toURI().toURL(); + method.invoke(classLoader, url); + } +} diff --git a/protocol-gateway/mqtt-component/.DS_Store b/protocol-gateway/mqtt-component/.DS_Store old mode 100644 new mode 100755 diff --git a/protocol-gateway/mqtt-component/dependency-reduced-pom.xml b/protocol-gateway/mqtt-component/dependency-reduced-pom.xml new file mode 100644 index 00000000..6278059c --- /dev/null +++ b/protocol-gateway/mqtt-component/dependency-reduced-pom.xml @@ -0,0 +1,79 @@ + + + + protocol-gateway + cc.iotkit + 0.0.1-SNAPSHOT + + 4.0.0 + mqtt-component + + + + maven-shade-plugin + 3.2.4 + + + package + + shade + + + + + + + io.vertx:vertx-core + io.vertx:vertx-mqtt + + + + + + maven-compiler-plugin + + 8 + 8 + + + + + + + io.vertx + vertx-core + 4.2.6 + provided + + + io.vertx + vertx-mqtt + 4.2.6 + provided + + + org.projectlombok + lombok + 1.18.22 + compile + + + org.slf4j + slf4j-api + 1.7.32 + compile + + + cc.iotkit + common + 0.0.1-SNAPSHOT + compile + + + cc.iotkit + component + 0.0.1-SNAPSHOT + compile + + + From b44c3d44c6cd89ce26a33392a31306ca1eb218ae Mon Sep 17 00:00:00 2001 From: xiwa Date: Tue, 29 Mar 2022 19:08:07 +0800 Subject: [PATCH 12/16] =?UTF-8?q?=E7=BB=84=E4=BB=B6=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E3=80=81=E5=8A=A0=E8=BD=BD=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 8196 -> 10244 bytes components/.DS_Store | Bin 0 -> 6148 bytes .../controller/ProtocolController.java | 59 +++++++++---- .../src/main/resources/application-dev.yml | 4 +- manager/src/main/resources/application.yml | 4 +- .../model/protocol/ProtocolComponent.java | 7 +- protocol-gateway/component-server/pom.xml | 5 ++ .../cc/iotkit/comps/ComponentClassLoader.java | 29 +++++-- .../emqx-component/dependency-reduced-pom.xml | 80 ++++++++++++++++++ protocol-gateway/emqx-component/pom.xml | 35 ++++++++ .../src/main/resources/component.spi | 1 + .../src/main/resources/component.spi | 1 + 12 files changed, 200 insertions(+), 25 deletions(-) create mode 100644 components/.DS_Store create mode 100644 protocol-gateway/emqx-component/dependency-reduced-pom.xml create mode 100644 protocol-gateway/emqx-component/src/main/resources/component.spi create mode 100644 protocol-gateway/mqtt-component/src/main/resources/component.spi diff --git a/.DS_Store b/.DS_Store index f9d353f370a1db4f78c1f5da0233068cda235af4..2d69961b9f409d4a1f6e08399659abb3484ed372 100755 GIT binary patch delta 323 zcmZp1XbF&DU|?W$DortDU{C-uIe-{M3-C-V6q~50$SAlmU^hRb;A9?wPtv>$$qe}n zxeNtBGLIn@h)Wpa8L}7>8Hy&$2s8*A8yo2;7}V-0R2v!?0htyi#*_PnOjB^`N-0jx zNy^X9VFcQU$MCY?qP(2^ymX){kV-Br&M3y|fb{~#qS$r37x=XKjgU0!#)eyLg3LgJ rfk1&9NVtOhzp?N;^JIRRKoKTLsAzzsfz}&<=*a~#y_;_fGcyAKrH4e% delta 140 zcmZn(XmOBWU|?W$DortDU;r^WfEYvza8E20o2aMA$hR?IH$NlaWFCP}ll6rk^YSvJ zFr+e+F=R3%Go(%y5Wj*Z@>X1Svyg~1s~|Jb6d;h`1`@6y12-0aXP(Tj63D>_v4&xC RJkQk02I5;bUl$8z0sxa<9LoRz diff --git a/components/.DS_Store b/components/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..612370d1330a9cfae3ada62dc7c11631f71ed1a3 GIT binary patch literal 6148 zcmeHKyG{c!5S)b+k!VsqsBBem|*YVrTK9CaK(Ne&!v>toC zW6M+A-U5*IM|%g%08HtM_|#!&y01R4i--u3&NDi+*kgxVG=uE%fO2o}fE6CeIpxo> zz?LU1d0vAz&bHj|Y}R3pdvaFXS@6aNPxNK`zCY}a$Acc4mI|Z-sX!`_3Zw#~3PhQl zUXAW%FcnAz{<8x5eJFIr8rVD9r-OsF0K^HyW}I6uK`a^|*1+D85t=xa=v0XoL!8cd ziM$%vJ31W_&4=z?L5C&I;1-0m optComponent = protocolComponentRepository.findById(component.getId()); + String id = component.getId(); + if (!StringUtils.hasLength(id)) { + throw new BizException("component id is blank"); + } + Path jarPath = getFilePath(id, "jar"); + if (!jarPath.resolve(component.getJarFile()).toFile().exists()) { + throw new BizException("component jar file does not exist"); + } + + Optional optComponent = protocolComponentRepository.findById(id); if (optComponent.isPresent()) { throw new BizException("component already exists"); } @@ -93,7 +101,6 @@ public class ProtocolController { throw new BizException("user does not exists"); } - component.setScript("new (function () {this.decode = function (msg) {return null; };})().decode(msg)"); component.setCreateAt(System.currentTimeMillis()); component.setUid(AuthUtil.getUserId()); protocolComponentRepository.save(component); @@ -104,6 +111,15 @@ public class ProtocolController { @PostMapping("/saveComponent") public void saveComponent(ProtocolComponent component) { + String id = component.getId(); + if (!StringUtils.hasLength(id)) { + throw new BizException("component id is blank"); + } + Path jarPath = getFilePath(id, "jar"); + if (!jarPath.resolve(component.getJarFile()).toFile().exists()) { + throw new BizException("component jar file does not exist"); + } + Optional optComponent = protocolComponentRepository.findById(component.getId()); if (!optComponent.isPresent()) { throw new BizException("the protocol component does not exists"); @@ -131,7 +147,7 @@ public class ProtocolController { } dataOwnerService.checkOwner(component); ProtocolComponent oldComponent = optComponent.get(); - oldComponent.setScript(component.getScript()); + oldComponent.setScriptFile(component.getScriptFile()); try { // gatewayService.saveFunction(oldGateway.getUuid(), oldGateway.getId(), // "new (function (){" + oldGateway.getScript() + "})()", functionJar); @@ -145,6 +161,14 @@ public class ProtocolController { public void deleteComponent(@PathVariable("id") String id) { dataOwnerService.checkOwner(protocolComponentRepository, id); try { + Path path = Paths.get(String.format("%s/%s", componentDir, id)) + .toAbsolutePath().normalize(); + File file = path.toFile(); + if (file.isDirectory()) { + FileUtils.deleteDirectory(file); + } else { + FileUtils.delete(file); + } protocolComponentRepository.deleteById(id); } catch (Throwable e) { throw new BizException("delete protocol component error", e); @@ -176,4 +200,5 @@ public class ProtocolController { componentManager.stop("123"); componentManager.deRegister("123"); } + } diff --git a/manager/src/main/resources/application-dev.yml b/manager/src/main/resources/application-dev.yml index ebc395c7..33ee2342 100755 --- a/manager/src/main/resources/application-dev.yml +++ b/manager/src/main/resources/application-dev.yml @@ -4,7 +4,6 @@ spring: enabled: true max-file-size: 10MB max-request-size: 12MB - upload-dir: ./component_jar data: mongodb: @@ -70,5 +69,8 @@ app: mqtt: url: tcp://填写mqtt连接地址 +component: + dir: ./components + gateway: function-jar: 填写protocol-function打包的jar存放路径:/xx/xx.jar diff --git a/manager/src/main/resources/application.yml b/manager/src/main/resources/application.yml index 1b6731d8..a69332eb 100755 --- a/manager/src/main/resources/application.yml +++ b/manager/src/main/resources/application.yml @@ -4,7 +4,6 @@ spring: enabled: true max-file-size: 10MB max-request-size: 12MB - upload-dir: ./component_jar data: mongodb: @@ -68,5 +67,8 @@ app: mqtt: url: tcp://填写mqtt连接地址 +component: + dir: ./components + gateway: function-jar: 填写protocol-function打包的jar存放路径:/xx/xx.jar diff --git a/model/src/main/java/cc/iotkit/model/protocol/ProtocolComponent.java b/model/src/main/java/cc/iotkit/model/protocol/ProtocolComponent.java index e80098a1..40ee8bf7 100755 --- a/model/src/main/java/cc/iotkit/model/protocol/ProtocolComponent.java +++ b/model/src/main/java/cc/iotkit/model/protocol/ProtocolComponent.java @@ -9,6 +9,9 @@ import org.springframework.data.mongodb.core.mapping.Document; @Document public class ProtocolComponent implements Owned { + public static final String STATE_STOPPED = "stopped"; + public static final String STATE_RUNNING = "running"; + @Id private String id; @@ -25,7 +28,9 @@ public class ProtocolComponent implements Owned { private String config; - private String script; + private String scriptFile; + + private String state; private Long createAt; diff --git a/protocol-gateway/component-server/pom.xml b/protocol-gateway/component-server/pom.xml index 3fc4ffbb..cc6164ce 100755 --- a/protocol-gateway/component-server/pom.xml +++ b/protocol-gateway/component-server/pom.xml @@ -47,6 +47,11 @@ slf4j-api + + commons-io + commons-io + + org.projectlombok lombok diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentClassLoader.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentClassLoader.java index 0f8cbc02..f025f5d3 100644 --- a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentClassLoader.java +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentClassLoader.java @@ -1,24 +1,28 @@ package cc.iotkit.comps; -import cc.iotkit.comp.CompConfig; import cc.iotkit.comp.IComponent; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.StreamUtils; import java.io.File; +import java.io.IOException; +import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; +import java.nio.charset.Charset; +@Slf4j public class ComponentClassLoader { protected Class findClass(String name) throws ClassNotFoundException { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - return (Class) classLoader.loadClass("cc.iotkit.comp.mqtt.MqttComponent"); + return (Class) classLoader.loadClass(name); } - public void addUrl(File jarPath) throws NoSuchMethodException, InvocationTargetException, - IllegalAccessException, MalformedURLException { + private String addUrl(File jarPath) throws NoSuchMethodException, InvocationTargetException, + IllegalAccessException, IOException { URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); if (!method.isAccessible()) { @@ -26,5 +30,20 @@ public class ComponentClassLoader { } URL url = jarPath.toURI().toURL(); method.invoke(classLoader, url); + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + InputStream is = loader.getResourceAsStream("component.spi"); + return StreamUtils.copyToString(is, Charset.forName("UTF-8")); } + + public IComponent getComponent(File jarPath) { + try { + String className = addUrl(jarPath); + Class componentClass = findClass(className); + return componentClass.newInstance(); + } catch (Throwable e) { + log.error("instance component from jar error", e); + return null; + } + } + } diff --git a/protocol-gateway/emqx-component/dependency-reduced-pom.xml b/protocol-gateway/emqx-component/dependency-reduced-pom.xml new file mode 100644 index 00000000..7a20b0f0 --- /dev/null +++ b/protocol-gateway/emqx-component/dependency-reduced-pom.xml @@ -0,0 +1,80 @@ + + + + protocol-gateway + cc.iotkit + 0.0.1-SNAPSHOT + + 4.0.0 + emqx-component + + + + maven-shade-plugin + 3.2.4 + + + package + + shade + + + + + + + io.vertx:vertx-core + io.vertx:vertx-web-proxy + io.vertx:vertx-mqtt + + + + + + maven-compiler-plugin + + 8 + 8 + + + + + + + io.vertx + vertx-core + 4.2.6 + provided + + + io.vertx + vertx-web-proxy + 4.2.6 + provided + + + io.vertx + vertx-mqtt + 4.2.6 + provided + + + cc.iotkit + model + 0.0.1-SNAPSHOT + compile + + + cc.iotkit + common + 0.0.1-SNAPSHOT + compile + + + cc.iotkit + component + 0.0.1-SNAPSHOT + compile + + + diff --git a/protocol-gateway/emqx-component/pom.xml b/protocol-gateway/emqx-component/pom.xml index 55ea7dbc..3e9788b0 100755 --- a/protocol-gateway/emqx-component/pom.xml +++ b/protocol-gateway/emqx-component/pom.xml @@ -45,4 +45,39 @@ + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.4 + + + package + + shade + + + + + + + io.vertx:vertx-core + io.vertx:vertx-web-proxy + io.vertx:vertx-mqtt + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + \ No newline at end of file diff --git a/protocol-gateway/emqx-component/src/main/resources/component.spi b/protocol-gateway/emqx-component/src/main/resources/component.spi new file mode 100644 index 00000000..672ee448 --- /dev/null +++ b/protocol-gateway/emqx-component/src/main/resources/component.spi @@ -0,0 +1 @@ +cc.iotkit.comp.emqx.EmqxComponent \ No newline at end of file diff --git a/protocol-gateway/mqtt-component/src/main/resources/component.spi b/protocol-gateway/mqtt-component/src/main/resources/component.spi new file mode 100644 index 00000000..87d0d822 --- /dev/null +++ b/protocol-gateway/mqtt-component/src/main/resources/component.spi @@ -0,0 +1 @@ +cc.iotkit.comp.mqtt.MqttComponent \ No newline at end of file From 48b6ec7eb3a4e2f2d4d04428fc74a46d5dbdcf1b Mon Sep 17 00:00:00 2001 From: xiwa Date: Wed, 30 Mar 2022 01:59:14 +0800 Subject: [PATCH 13/16] =?UTF-8?q?=E9=80=9A=E8=AE=AF=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + components/.DS_Store | Bin 6148 -> 6148 bytes data/elasticsearch/nodes/0/_state/_3.cfe | Bin 278 -> 0 bytes data/elasticsearch/nodes/0/_state/_3.cfs | Bin 1274 -> 0 bytes data/elasticsearch/nodes/0/_state/_3.si | Bin 378 -> 0 bytes .../nodes/0/_state/manifest-0.st | Bin 109 -> 0 bytes data/elasticsearch/nodes/0/_state/node-0.st | Bin 89 -> 0 bytes data/elasticsearch/nodes/0/_state/segments_5 | Bin 245 -> 0 bytes data/elasticsearch/nodes/0/_state/write.lock | 0 data/elasticsearch/nodes/0/node.lock | 0 .../manager/config/ElasticSearchConfig.java | 0 .../controller/ProtocolController.java | 58 ++++++-- .../model/protocol/ProtocolComponent.java | 4 +- .../cc/iotkit/comps/ComponentClassLoader.java | 0 .../src/main/resources/component.spi | 0 .../src/main/resources/component.js | 137 +++++++++--------- .../src/main/resources/component.spi | 0 17 files changed, 113 insertions(+), 88 deletions(-) mode change 100644 => 100755 components/.DS_Store delete mode 100644 data/elasticsearch/nodes/0/_state/_3.cfe delete mode 100644 data/elasticsearch/nodes/0/_state/_3.cfs delete mode 100644 data/elasticsearch/nodes/0/_state/_3.si delete mode 100644 data/elasticsearch/nodes/0/_state/manifest-0.st delete mode 100644 data/elasticsearch/nodes/0/_state/node-0.st delete mode 100644 data/elasticsearch/nodes/0/_state/segments_5 delete mode 100644 data/elasticsearch/nodes/0/_state/write.lock delete mode 100644 data/elasticsearch/nodes/0/node.lock mode change 100644 => 100755 manager/src/main/java/cc/iotkit/manager/config/ElasticSearchConfig.java mode change 100644 => 100755 protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentClassLoader.java mode change 100644 => 100755 protocol-gateway/emqx-component/src/main/resources/component.spi mode change 100644 => 100755 protocol-gateway/mqtt-component/src/main/resources/component.spi diff --git a/.gitignore b/.gitignore index 8da0c3c1..d9c4d48c 100755 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,5 @@ target *.iml *.yml log +components +data diff --git a/components/.DS_Store b/components/.DS_Store old mode 100644 new mode 100755 index 612370d1330a9cfae3ada62dc7c11631f71ed1a3..d35af10813ea88294ea88c8f5c1aae3821a506f4 GIT binary patch delta 586 zcmZoMXfc=|#>B!ku~2NHo}wrV0|Nsi1A_nqLo!1ugE@l*gD!*F#)r$9LqRes3}y@_ zK$waw3shstU<_1e!eGjf1ZIImEEv*&Vu=h!K(Q3C3JV4UAkPw{sw}uDFDE}QePTyU zy$aA8kYx}HErE)4fg*`O2(sJ+C~g5Hb%7dFfJP>P4K)R_je)96fJP<)MGZl8Qh9Mf zQcivn(4k+G3UV@wOAHKdFfuW-u(GjpaB^{Ta`SO>#|CHQmj{<5mXsDdB^JdC$kYdC zrlck%7KLY~lw^dY=DFsimZj$T7x^TXq!vYkREOl}=KvKz*ojGDnW^RR0wT`&c_oRN zd8tKU10iO_glFcZ>&Xz`)7D881*TQC)3p zYOJGRY-~`gqfl*bZlI%JVr*7h%gMIjfQYH+H6A_;4F!XgQ1=*9=D7&o(X@N)oD%EpJ^nJ4p$7_x#~(JCJ*u~2NHo}wrt0|NsP3otOGGNdphGbAzSG8jxORG*y861iD~Lzrb_ jg8=hpb`E|Hpq|Zw9N(EI^NScVGEBDNk=`65vVs`^%)SyF diff --git a/data/elasticsearch/nodes/0/_state/_3.cfe b/data/elasticsearch/nodes/0/_state/_3.cfe deleted file mode 100644 index cf99088bf5625d865d7b89fabca7ebe890759c25..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 278 zcmcD&o+B>qQ<|KbmuhO@oS$2eUz(TVnpaYknOe*M1T&9(IKDFS&sz=7)5~-XV}CJl zu;`_wRDh&_Ko3GOIPk|q%&;(tH_%JTPlk%;L1{mbrd%jz50st<6wHGPGDblKSD~0x zk_nY(Vu8wsf=nubaF`+?G-ErOrUHmK^8*OY;DIWin*tGM(SXVyI-oK61(eNDd+lv6 E09fZbod5s; diff --git a/data/elasticsearch/nodes/0/_state/_3.cfs b/data/elasticsearch/nodes/0/_state/_3.cfs deleted file mode 100644 index 4d78d2464bca17efdfe4c3ec9f14f85be378fc4a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1274 zcmah|&ubGw6rS0nsjaYxmKM?CLB#eDNuf=O2Machu0|;&Aw-a{*`372-JP&INt58A zAk-GYOO&7o5f6eO2%bIEB6uixD`Nfv4=Q^qZ6fN-{-B$*)(6X*<$dqlZ|8k)?u$A$ zlB`HbM>COmtd(&^m*XN40gb00txvCWzkW;%ZN3Um-R^)niXL^)voi?=sj?~PGO7u3 z?LhqcMDrUfu+ZP1PqO}#ZvXTmHi@E_%&eghWW=#VL9qXm!yY;xN&49uZ-ZNmZR`Lw zH;^qq*v|!)*Uxe6BlH=j4?DAnI0=BcW$(0?y<&9!#r~>Wgi8=Yzq+sQE)6nu#~pRi zh<#UrUc@G4=JpBWf}~zXfP>(V8{GIJGVCtzniAO1L~@~Mrz76A{0nAQibbUcBOoZ# zVX{B=m;vxB&At3EX)C>~V(D($Kq!q2&5SD&p*^8~rM__lrb{X=h-x4NA$PBbbfoqC zJ0m^qs*I%wHjwNXCLx-{HQ4?Mfe?Jg!Ex@47o*39EWX8EoE#qLtZHj0Lb?#k33uwLoK_~+%9*IePYI3Lr6-aPm6x!lDTE;Tti?CI ziiEKtE4oN1Z|6Q`)HWVdaw>NZPfvPLDeYvWd^8ciZt;Sc7P1X7lU4FJ>kGN1-KO0j zN)jp)i$`)_haYe8c1Np<*&evSJgPB4RD;EvJGoQ<|Kbmug`aoSL4SnpfhPmzK`}1T&9(IKDFS&sz=7)5~-XV}F6fIDnWF z#9&0`fcT7DO!>tezKO{S{=o_n+*yfbiF#$Jc`5ltLjFaG$vLSC&iO?J`9+B(nfZA< zQ0by#AcxaX&qB{2-pI_5A0nI!)CiX0GBVWz3hO2r8u8_T9SM_Rwa~NFGhojz)=Ml( z&S0ysFpD=c5dmv2D$Og&%uR)<JCys=(!CL54UPAi5`sf_Z_kTVZ1$uCMxam!52 qNhx;AFUn0U(aX(GN#$~K4GxJ94sdmKVK|^M`2{H8KtOS#qZI(z>u)Fk diff --git a/data/elasticsearch/nodes/0/_state/manifest-0.st b/data/elasticsearch/nodes/0/_state/manifest-0.st deleted file mode 100644 index 030f9cbe09eade2c5fa41802ec7ca16ee9e3ac1f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 109 zcmcD&o+Hj$T#{Il%D}+D2*OsHT&%yklS_+=Qu9jUOHzw+4@^nUDJ=%F;=u~z%TkMq tGxPHfbf%}~r4}WY0NDp8Wag!$R>UJjihun4eL!RK3!sr;pmG1sCIFIlD$W1^ diff --git a/data/elasticsearch/nodes/0/_state/node-0.st b/data/elasticsearch/nodes/0/_state/node-0.st deleted file mode 100644 index a819c66f42c5335dada71a9525e4aec2c24bd285..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 89 zcmcD&o+Hj$T#{Il%D}+D2*OsHT&%y^^72zs<1zeDFQX|3Cj$pi1_UHofCM8@ zfGOS>P2n#NpVH*iyi^PG|4;zZ0As^wkQgJH&OabQ1{R*Y{FK!AvecsD%=|odb3;=D zBTGxsoW$ai_{8Mo)Pj=K6qqcdAy0B?Q4!F|@g=E6xr~PFV7-|sV#)DlZZ6)Qi6Nfh cRf(bDnel#=u94*jG$y|QTLL7WWS?UJ01?Sx(*OVf diff --git a/data/elasticsearch/nodes/0/_state/write.lock b/data/elasticsearch/nodes/0/_state/write.lock deleted file mode 100644 index e69de29b..00000000 diff --git a/data/elasticsearch/nodes/0/node.lock b/data/elasticsearch/nodes/0/node.lock deleted file mode 100644 index e69de29b..00000000 diff --git a/manager/src/main/java/cc/iotkit/manager/config/ElasticSearchConfig.java b/manager/src/main/java/cc/iotkit/manager/config/ElasticSearchConfig.java old mode 100644 new mode 100755 diff --git a/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java b/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java index 9fabe171..dee6ae4a 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java @@ -1,6 +1,7 @@ package cc.iotkit.manager.controller; import cc.iotkit.common.exception.BizException; +import cc.iotkit.common.utils.JsonUtil; import cc.iotkit.common.utils.ReflectUtil; import cc.iotkit.comp.CompConfig; import cc.iotkit.comp.mqtt.MqttComponent; @@ -56,21 +57,29 @@ public class ProtocolController { @Autowired private ComponentManager componentManager; - private Path getFilePath(String comId, String type) { - return Paths.get(String.format("%s/%s/%s", componentDir, comId, type)) + private Path getFilePath(String comId) { + return Paths.get(String.format("%s/%s", componentDir, comId)) .toAbsolutePath().normalize(); } @PostMapping("/uploadJar") - public String uploadJar(@RequestParam("file") MultipartFile file) { + public String uploadJar(@RequestParam("file") MultipartFile file, String id) { if (file == null) { throw new BizException("file is null"); } log.info("saving upload jar file:{}", file.getName()); String fileName = StringUtils.cleanPath(file.getOriginalFilename()); try { - String id = UUID.randomUUID().toString(); - Path jarFilePath = getFilePath(id, "jar"); + if (StringUtils.hasLength(id)) { + Optional optComponent = protocolComponentRepository.findById(id); + if (!optComponent.isPresent()) { + throw new BizException("the protocol component does not exists"); + } + dataOwnerService.checkOwner(optComponent.get()); + } else { + id = UUID.randomUUID().toString(); + } + Path jarFilePath = getFilePath(id); Files.createDirectories(jarFilePath); Path targetLocation = jarFilePath.resolve(fileName); Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING); @@ -86,7 +95,7 @@ public class ProtocolController { if (!StringUtils.hasLength(id)) { throw new BizException("component id is blank"); } - Path jarPath = getFilePath(id, "jar"); + Path jarPath = getFilePath(id); if (!jarPath.resolve(component.getJarFile()).toFile().exists()) { throw new BizException("component jar file does not exist"); } @@ -115,7 +124,7 @@ public class ProtocolController { if (!StringUtils.hasLength(id)) { throw new BizException("component id is blank"); } - Path jarPath = getFilePath(id, "jar"); + Path jarPath = getFilePath(id); if (!jarPath.resolve(component.getJarFile()).toFile().exists()) { throw new BizException("component jar file does not exist"); } @@ -139,18 +148,39 @@ public class ProtocolController { } } - @PostMapping("/saveComponentScript") - public void saveComponentScript(@RequestBody ProtocolComponent component) { - Optional optComponent = protocolComponentRepository.findById(component.getId()); + @GetMapping("/getComponentScript/{id}") + public String getComponentScript(@PathVariable("id") String id) { + Optional optComponent = protocolComponentRepository.findById(id); if (!optComponent.isPresent()) { throw new BizException("the component does not exists"); } + ProtocolComponent component = optComponent.get(); dataOwnerService.checkOwner(component); - ProtocolComponent oldComponent = optComponent.get(); - oldComponent.setScriptFile(component.getScriptFile()); try { -// gatewayService.saveFunction(oldGateway.getUuid(), oldGateway.getId(), -// "new (function (){" + oldGateway.getScript() + "})()", functionJar); + Path path = getFilePath(id); + File file = path.resolve(ProtocolComponent.SCRIPT_FILE_NAME).toFile(); + return FileUtils.readFileToString(file, "UTF-8"); + } catch (Throwable e) { + log.error("read component script file error", e); + return ""; + } + } + + @PostMapping("/saveComponentScript/{id}") + public void saveComponentScript( + @PathVariable("id") String id, + @RequestBody String script) { + Optional optComponent = protocolComponentRepository.findById(id); + if (!optComponent.isPresent()) { + throw new BizException("the component does not exists"); + } + ProtocolComponent oldComponent = optComponent.get(); + dataOwnerService.checkOwner(oldComponent); + try { + Path path = getFilePath(id); + File file = path.resolve(ProtocolComponent.SCRIPT_FILE_NAME).toFile(); + script = JsonUtil.parse(script, String.class); + FileUtils.writeStringToFile(file, script, "UTF-8", false); protocolComponentRepository.save(oldComponent); } catch (Throwable e) { throw new BizException("save protocol component script error", e); diff --git a/model/src/main/java/cc/iotkit/model/protocol/ProtocolComponent.java b/model/src/main/java/cc/iotkit/model/protocol/ProtocolComponent.java index 40ee8bf7..97b1aa0c 100755 --- a/model/src/main/java/cc/iotkit/model/protocol/ProtocolComponent.java +++ b/model/src/main/java/cc/iotkit/model/protocol/ProtocolComponent.java @@ -12,6 +12,8 @@ public class ProtocolComponent implements Owned { public static final String STATE_STOPPED = "stopped"; public static final String STATE_RUNNING = "running"; + public static final String SCRIPT_FILE_NAME = "component.js"; + @Id private String id; @@ -28,8 +30,6 @@ public class ProtocolComponent implements Owned { private String config; - private String scriptFile; - private String state; private Long createAt; diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentClassLoader.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentClassLoader.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/emqx-component/src/main/resources/component.spi b/protocol-gateway/emqx-component/src/main/resources/component.spi old mode 100644 new mode 100755 diff --git a/protocol-gateway/mqtt-component/src/main/resources/component.js b/protocol-gateway/mqtt-component/src/main/resources/component.js index b9c8a840..cd505874 100755 --- a/protocol-gateway/mqtt-component/src/main/resources/component.js +++ b/protocol-gateway/mqtt-component/src/main/resources/component.js @@ -1,84 +1,77 @@ -new (function () { - !function(n){"use strict";function d(n,t){var r=(65535&n)+(65535&t);return(n>>16)+(t>>16)+(r>>16)<<16|65535&r}function f(n,t,r,e,o,u){return d((u=d(d(t,n),d(e,u)))<>>32-o,r)}function l(n,t,r,e,o,u,c){return f(t&r|~t&e,n,t,o,u,c)}function g(n,t,r,e,o,u,c){return f(t&e|r&~e,n,t,o,u,c)}function v(n,t,r,e,o,u,c){return f(t^r^e,n,t,o,u,c)}function m(n,t,r,e,o,u,c){return f(r^(t|~e),n,t,o,u,c)}function c(n,t){var r,e,o,u;n[t>>5]|=128<>>9<<4)]=t;for(var c=1732584193,f=-271733879,i=-1732584194,a=271733878,h=0;h>5]>>>e%32&255);return t}function a(n){var t=[];for(t[(n.length>>2)-1]=void 0,e=0;e>5]|=(255&n.charCodeAt(e/8))<>>4&15)+r.charAt(15&t);return e}function r(n){return unescape(encodeURIComponent(n))}function o(n){return i(c(a(n=r(n)),8*n.length))}function u(n,t){return function(n,t){var r,e=a(n),o=[],u=[];for(o[15]=u[15]=void 0,16>16)+(t>>16)+(r>>16)<<16|65535&r}function f(n,t,r,e,o,u){return d((u=d(d(t,n),d(e,u)))<>>32-o,r)}function l(n,t,r,e,o,u,c){return f(t&r|~t&e,n,t,o,u,c)}function g(n,t,r,e,o,u,c){return f(t&e|r&~e,n,t,o,u,c)}function v(n,t,r,e,o,u,c){return f(t^r^e,n,t,o,u,c)}function m(n,t,r,e,o,u,c){return f(r^(t|~e),n,t,o,u,c)}function c(n,t){var r,e,o,u;n[t>>5]|=128<>>9<<4)]=t;for(var c=1732584193,f=-271733879,i=-1732584194,a=271733878,h=0;h>5]>>>e%32&255);return t}function a(n){var t=[];for(t[(n.length>>2)-1]=void 0,e=0;e>5]|=(255&n.charCodeAt(e/8))<>>4&15)+r.charAt(15&t);return e}function r(n){return unescape(encodeURIComponent(n))}function o(n){return i(c(a(n=r(n)),8*n.length))}function u(n,t){return function(n,t){var r,e=a(n),o=[],u=[];for(o[15]=u[15]=void 0,16 Date: Wed, 30 Mar 2022 20:00:01 +0800 Subject: [PATCH 14/16] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=BD=AC=E6=8D=A2?= =?UTF-8?q?=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 10244 -> 8196 bytes components/.DS_Store | Bin 6148 -> 0 bytes .../dao/ProtocolConverterRepository.java | 9 + .../controller/ProtocolController.java | 164 +++++++++++++++--- .../src/main/resources/application-dev.yml | 5 - manager/src/main/resources/application.yml | 5 - .../model/protocol/ProtocolComponent.java | 2 + .../model/protocol/ProtocolConverter.java | 27 +++ .../src/main/resources/converter.js | 97 +++++------ 9 files changed, 221 insertions(+), 88 deletions(-) delete mode 100755 components/.DS_Store create mode 100644 dao/src/main/java/cc/iotkit/dao/ProtocolConverterRepository.java create mode 100644 model/src/main/java/cc/iotkit/model/protocol/ProtocolConverter.java diff --git a/.DS_Store b/.DS_Store index 2d69961b9f409d4a1f6e08399659abb3484ed372..ac1be05f5ebe4b07e3357523ea12d5a053f85321 100755 GIT binary patch delta 96 zcmZn(XmOBWU|?W$DortDU;r^WfEYvza8E20o2aMA$hR?IH$NlaWFCP}n+=3G*#((_ kvOplg4J2Ga3O5#hXP(Tj63D>_(atbAo@eT2eKB@s01HVFNB{r; delta 213 zcmZp1XbF&DU|?W$DortDU{C-uIe-{M3-C-V6q~50$SAlmU^hRb;A9?wPm;V0$qe}n zxeNtBGLIn@h)Wpa8L}7>C%+YHnmk$1%?YOphN6_>3EcFelH-wzOmsP vn;irdw)2AvumIA)mU`qMapg(_j=Z3apv}ymq&+THAOM`f>essYf1Ga+^97NsC*$ zbb_{!?x8J~9$j)#>#^6_pv7WX$$+#bu!^Z7F8YfX$ z9;R_MI!N;UEICW^hvkE?O3J6~e1LhvLD^ySBu%En#?9R#ufjA>O39}MJ})Gc}`t zQQ+Sw!25%P%ou1~D3n_V3V8(p@@Irhu=y^*F^_kVx?zZ_(0MggP1f2Dw^ z?G5(&cqM(dF1;L|wGQ$TGAH(1D3l>6^l>Z=K8iPyWkR3B1~AaLP>2>J^C2K*FojXz HuPX2z-sy=0 diff --git a/dao/src/main/java/cc/iotkit/dao/ProtocolConverterRepository.java b/dao/src/main/java/cc/iotkit/dao/ProtocolConverterRepository.java new file mode 100644 index 00000000..336d2aaf --- /dev/null +++ b/dao/src/main/java/cc/iotkit/dao/ProtocolConverterRepository.java @@ -0,0 +1,9 @@ +package cc.iotkit.dao; + +import cc.iotkit.model.protocol.ProtocolConverter; +import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ProtocolConverterRepository extends MongoRepository { +} diff --git a/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java b/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java index dee6ae4a..a5b63f50 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java @@ -8,12 +8,13 @@ import cc.iotkit.comp.mqtt.MqttComponent; import cc.iotkit.comps.ComponentManager; import cc.iotkit.converter.ScriptConverter; import cc.iotkit.dao.ProtocolComponentRepository; +import cc.iotkit.dao.ProtocolConverterRepository; import cc.iotkit.dao.UserInfoRepository; import cc.iotkit.manager.service.DataOwnerService; import cc.iotkit.manager.utils.AuthUtil; import cc.iotkit.model.Paging; -import cc.iotkit.model.UserInfo; import cc.iotkit.model.protocol.ProtocolComponent; +import cc.iotkit.model.protocol.ProtocolConverter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FileUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -27,10 +28,7 @@ import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; +import java.nio.file.*; import java.util.Optional; import java.util.UUID; @@ -39,15 +37,18 @@ import java.util.UUID; @RequestMapping("/protocol") public class ProtocolController { - @Value("${gateway.function-jar}") - private String functionJar; - - @Value("${component.dir}") + @Value("${component.dir:./data/components}") private String componentDir; + @Value("${converter.dir:./data/converters}") + private String converterDir; + @Autowired private ProtocolComponentRepository protocolComponentRepository; + @Autowired + private ProtocolConverterRepository protocolConverterRepository; + @Autowired private DataOwnerService dataOwnerService; @@ -57,11 +58,16 @@ public class ProtocolController { @Autowired private ComponentManager componentManager; - private Path getFilePath(String comId) { + private Path getComponentFilePath(String comId) { return Paths.get(String.format("%s/%s", componentDir, comId)) .toAbsolutePath().normalize(); } + private Path getConverterFilePath(String conId) { + return Paths.get(String.format("%s/%s", converterDir, conId)) + .toAbsolutePath().normalize(); + } + @PostMapping("/uploadJar") public String uploadJar(@RequestParam("file") MultipartFile file, String id) { if (file == null) { @@ -79,7 +85,7 @@ public class ProtocolController { } else { id = UUID.randomUUID().toString(); } - Path jarFilePath = getFilePath(id); + Path jarFilePath = getComponentFilePath(id); Files.createDirectories(jarFilePath); Path targetLocation = jarFilePath.resolve(fileName); Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING); @@ -95,7 +101,7 @@ public class ProtocolController { if (!StringUtils.hasLength(id)) { throw new BizException("component id is blank"); } - Path jarPath = getFilePath(id); + Path jarPath = getComponentFilePath(id); if (!jarPath.resolve(component.getJarFile()).toFile().exists()) { throw new BizException("component jar file does not exist"); } @@ -105,11 +111,6 @@ public class ProtocolController { throw new BizException("component already exists"); } try { - Optional optUser = userInfoRepository.findById(AuthUtil.getUserId()); - if (!optUser.isPresent()) { - throw new BizException("user does not exists"); - } - component.setCreateAt(System.currentTimeMillis()); component.setUid(AuthUtil.getUserId()); protocolComponentRepository.save(component); @@ -124,7 +125,7 @@ public class ProtocolController { if (!StringUtils.hasLength(id)) { throw new BizException("component id is blank"); } - Path jarPath = getFilePath(id); + Path jarPath = getComponentFilePath(id); if (!jarPath.resolve(component.getJarFile()).toFile().exists()) { throw new BizException("component jar file does not exist"); } @@ -133,10 +134,6 @@ public class ProtocolController { if (!optComponent.isPresent()) { throw new BizException("the protocol component does not exists"); } - Optional optUser = userInfoRepository.findById(AuthUtil.getUserId()); - if (!optUser.isPresent()) { - throw new BizException("user does not exists"); - } ProtocolComponent oldComponent = optComponent.get(); component = ReflectUtil.copyNoNulls(component, oldComponent); @@ -157,7 +154,7 @@ public class ProtocolController { ProtocolComponent component = optComponent.get(); dataOwnerService.checkOwner(component); try { - Path path = getFilePath(id); + Path path = getComponentFilePath(id); File file = path.resolve(ProtocolComponent.SCRIPT_FILE_NAME).toFile(); return FileUtils.readFileToString(file, "UTF-8"); } catch (Throwable e) { @@ -177,7 +174,7 @@ public class ProtocolController { ProtocolComponent oldComponent = optComponent.get(); dataOwnerService.checkOwner(oldComponent); try { - Path path = getFilePath(id); + Path path = getComponentFilePath(id); File file = path.resolve(ProtocolComponent.SCRIPT_FILE_NAME).toFile(); script = JsonUtil.parse(script, String.class); FileUtils.writeStringToFile(file, script, "UTF-8", false); @@ -194,10 +191,14 @@ public class ProtocolController { Path path = Paths.get(String.format("%s/%s", componentDir, id)) .toAbsolutePath().normalize(); File file = path.toFile(); - if (file.isDirectory()) { - FileUtils.deleteDirectory(file); - } else { - FileUtils.delete(file); + try { + if (file.isDirectory()) { + FileUtils.deleteDirectory(file); + } else { + FileUtils.delete(file); + } + } catch (NoSuchFileException e) { + log.warn("delete component script error", e); } protocolComponentRepository.deleteById(id); } catch (Throwable e) { @@ -214,6 +215,113 @@ public class ProtocolController { return new Paging<>(components.getTotalElements(), components.getContent()); } + @PostMapping("/converters/{size}/{page}") + public Paging getConverters( + @PathVariable("size") int size, + @PathVariable("page") int page) { + protocolConverterRepository.deleteById(""); + protocolConverterRepository.deleteById("null"); + Page converters = protocolConverterRepository.findAll( + PageRequest.of(page - 1, size, Sort.by(Sort.Order.desc("createAt")))); + return new Paging<>(converters.getTotalElements(), converters.getContent()); + } + + @PostMapping("/addConverter") + public void addConverter(ProtocolConverter converter) { + try { + converter.setId(null); + converter.setCreateAt(System.currentTimeMillis()); + converter.setUid(AuthUtil.getUserId()); + protocolConverterRepository.save(converter); + } catch (Throwable e) { + throw new BizException("add protocol converter error", e); + } + } + + @PostMapping("/saveConverter") + public void saveConverter(ProtocolConverter converter) { + Optional optConverter = protocolConverterRepository.findById(converter.getId()); + if (!optConverter.isPresent()) { + throw new BizException("the protocol converter does not exists"); + } + + ProtocolConverter oldConverter = optConverter.get(); + converter = ReflectUtil.copyNoNulls(converter, oldConverter); + dataOwnerService.checkOwner(converter); + try { + protocolConverterRepository.save(converter); + } catch (Throwable e) { + throw new BizException("add protocol converter error", e); + } + } + + @GetMapping("/getConverterScript/{id}") + public String getConverterScript(@PathVariable("id") String id) { + Optional optConverter = protocolConverterRepository.findById(id); + if (!optConverter.isPresent()) { + throw new BizException("the converter does not exists"); + } + ProtocolConverter converter = optConverter.get(); + dataOwnerService.checkOwner(converter); + try { + Path path = getConverterFilePath(id); + File file = path.resolve(ProtocolConverter.SCRIPT_FILE_NAME).toFile(); + return FileUtils.readFileToString(file, "UTF-8"); + } catch (Throwable e) { + log.error("read converter script file error", e); + return ""; + } + } + + @PostMapping("/saveConverterScript/{id}") + public void saveConverterScript( + @PathVariable("id") String id, + @RequestBody String script) { + Optional optConverter = protocolConverterRepository.findById(id); + if (!optConverter.isPresent()) { + throw new BizException("the converter does not exists"); + } + ProtocolConverter oldConverter = optConverter.get(); + dataOwnerService.checkOwner(oldConverter); + try { + Path path = getConverterFilePath(id); + File file = path.resolve(ProtocolConverter.SCRIPT_FILE_NAME).toFile(); + script = JsonUtil.parse(script, String.class); + FileUtils.writeStringToFile(file, script, "UTF-8", false); + } catch (Throwable e) { + throw new BizException("save protocol converter script error", e); + } + } + + @PostMapping("/deleteConverter/{id}") + public void deleteConverter(@PathVariable("id") String id) { + dataOwnerService.checkOwner(protocolConverterRepository, id); + try { + Path path = Paths.get(String.format("%s/%s", componentDir, id)) + .toAbsolutePath().normalize(); + File file = path.toFile(); + try { + if (file.isDirectory()) { + FileUtils.deleteDirectory(file); + } else { + FileUtils.delete(file); + } + } catch (NoSuchFileException e) { + log.warn("delete converter script error", e); + } + protocolConverterRepository.deleteById(id); + } catch (Throwable e) { + throw new BizException("delete protocol converter error", e); + } + } + + @PostMapping("/component/{id}/{state}") + public void startComponent(@PathVariable("id") String id, + @PathVariable("state") String state) { + + } + + @GetMapping("/registerMqtt") public void registerMqtt() throws IOException { MqttComponent component = new MqttComponent(); diff --git a/manager/src/main/resources/application-dev.yml b/manager/src/main/resources/application-dev.yml index 33ee2342..4b5a94ae 100755 --- a/manager/src/main/resources/application-dev.yml +++ b/manager/src/main/resources/application-dev.yml @@ -69,8 +69,3 @@ app: mqtt: url: tcp://填写mqtt连接地址 -component: - dir: ./components - -gateway: - function-jar: 填写protocol-function打包的jar存放路径:/xx/xx.jar diff --git a/manager/src/main/resources/application.yml b/manager/src/main/resources/application.yml index a69332eb..363f3651 100755 --- a/manager/src/main/resources/application.yml +++ b/manager/src/main/resources/application.yml @@ -67,8 +67,3 @@ app: mqtt: url: tcp://填写mqtt连接地址 -component: - dir: ./components - -gateway: - function-jar: 填写protocol-function打包的jar存放路径:/xx/xx.jar diff --git a/model/src/main/java/cc/iotkit/model/protocol/ProtocolComponent.java b/model/src/main/java/cc/iotkit/model/protocol/ProtocolComponent.java index 97b1aa0c..3d9ab585 100755 --- a/model/src/main/java/cc/iotkit/model/protocol/ProtocolComponent.java +++ b/model/src/main/java/cc/iotkit/model/protocol/ProtocolComponent.java @@ -30,6 +30,8 @@ public class ProtocolComponent implements Owned { private String config; + private String converter; + private String state; private Long createAt; diff --git a/model/src/main/java/cc/iotkit/model/protocol/ProtocolConverter.java b/model/src/main/java/cc/iotkit/model/protocol/ProtocolConverter.java new file mode 100644 index 00000000..8aaec0f0 --- /dev/null +++ b/model/src/main/java/cc/iotkit/model/protocol/ProtocolConverter.java @@ -0,0 +1,27 @@ +package cc.iotkit.model.protocol; + +import cc.iotkit.model.Owned; +import lombok.Data; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +@Document +@Data +public class ProtocolConverter implements Owned { + + public static final String SCRIPT_FILE_NAME = "converter.js"; + + @Id + private String id; + + /** + * 所属性用户id + */ + private String uid; + + private String name; + + private String desc; + + private Long createAt; +} diff --git a/protocol-gateway/mqtt-component/src/main/resources/converter.js b/protocol-gateway/mqtt-component/src/main/resources/converter.js index b3973cb8..f2bbae9e 100755 --- a/protocol-gateway/mqtt-component/src/main/resources/converter.js +++ b/protocol-gateway/mqtt-component/src/main/resources/converter.js @@ -1,51 +1,48 @@ -new (function () { - this.decode = function (msg) { - //对msg进行解析,并返回物模型数据 - var mqttMsg = JSON.parse(msg.content); - var topic = mqttMsg.topic; - var payload = mqttMsg.payload; - - if (topic.endsWith("/property/post")) { - //属性上报 - return { - mid: msg.mid, - productKey: msg.productKey, //可根据消息内容判断填写不同产品 - deviceName: msg.deviceName, - type:"property", - identifier: "report", //属性上报 - occur: new Date().getTime(), //时间戳,设备上的事件或数据产生的本地时间 - time: new Date().getTime(), //时间戳,消息上报时间 - data: payload.params, - }; - } else if (topic.indexOf("/event/") > 0) { - var identifier = topic.substring(topic.lastIndexOf("/") + 1); - //事件上报 - return { - mid: msg.mid, - productKey: msg.productKey, - deviceName: msg.deviceName, - type:"event", - identifier: identifier, - occur: new Date().getTime(), - time: new Date().getTime(), - data: payload.params, - }; - } else if (topic.endsWith("_reply")) { - var identifier = topic.substring(topic.lastIndexOf("/") + 1); - //服务回复 - return { - mid: msg.mid, - productKey: msg.productKey, - deviceName: msg.deviceName, - type:"service", - identifier: identifier.replace("_reply", "Reply"), - occur: new Date().getTime(), - time: new Date().getTime(), - code: payload.code, - data: payload.data, - }; - } - return null; +this.decode = function (msg) { + //对msg进行解析,并返回物模型数据 + var mqttMsg = JSON.parse(msg.content); + var topic = mqttMsg.topic; + var payload = mqttMsg.payload; + + if (topic.endsWith("/property/post")) { + //属性上报 + return { + mid: msg.mid, + productKey: msg.productKey, //可根据消息内容判断填写不同产品 + deviceName: msg.deviceName, + type:"property", + identifier: "report", //属性上报 + occur: new Date().getTime(), //时间戳,设备上的事件或数据产生的本地时间 + time: new Date().getTime(), //时间戳,消息上报时间 + data: payload.params, }; - })() - \ No newline at end of file + } else if (topic.indexOf("/event/") > 0) { + var identifier = topic.substring(topic.lastIndexOf("/") + 1); + //事件上报 + return { + mid: msg.mid, + productKey: msg.productKey, + deviceName: msg.deviceName, + type:"event", + identifier: identifier, + occur: new Date().getTime(), + time: new Date().getTime(), + data: payload.params, + }; + } else if (topic.endsWith("_reply")) { + var identifier = topic.substring(topic.lastIndexOf("/") + 1); + //服务回复 + return { + mid: msg.mid, + productKey: msg.productKey, + deviceName: msg.deviceName, + type:"service", + identifier: identifier.replace("_reply", "Reply"), + occur: new Date().getTime(), + time: new Date().getTime(), + code: payload.code, + data: payload.data, + }; + } + return null; +}; From 983e8572751921fd8a8ea3b63b10b56327409ab0 Mon Sep 17 00:00:00 2001 From: xiwa Date: Fri, 1 Apr 2022 07:32:56 +0800 Subject: [PATCH 15/16] =?UTF-8?q?=E9=80=9A=E8=AE=AF=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dao/ProtocolComponentRepository.java | 5 + .../dao/ProtocolConverterRepository.java | 0 .../controller/ProtocolController.java | 151 +++++++----------- .../model/protocol/ProtocolConverter.java | 0 .../cc/iotkit/comps/ComponentClassLoader.java | 8 +- .../cc/iotkit/comps/ComponentManager.java | 74 ++++++++- .../java/cc/iotkit/comps/MessageHandler.java | 19 ++- .../iotkit/comps/config/ComponentConfig.java | 29 ++++ .../cc/iotkit/converter/ScriptConverter.java | 2 +- .../emqx-component/dependency-reduced-pom.xml | 0 .../mqtt-component/dependency-reduced-pom.xml | 0 11 files changed, 186 insertions(+), 102 deletions(-) mode change 100644 => 100755 dao/src/main/java/cc/iotkit/dao/ProtocolConverterRepository.java mode change 100644 => 100755 model/src/main/java/cc/iotkit/model/protocol/ProtocolConverter.java create mode 100755 protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/ComponentConfig.java mode change 100644 => 100755 protocol-gateway/emqx-component/dependency-reduced-pom.xml mode change 100644 => 100755 protocol-gateway/mqtt-component/dependency-reduced-pom.xml diff --git a/dao/src/main/java/cc/iotkit/dao/ProtocolComponentRepository.java b/dao/src/main/java/cc/iotkit/dao/ProtocolComponentRepository.java index 68d51cbb..2da53005 100755 --- a/dao/src/main/java/cc/iotkit/dao/ProtocolComponentRepository.java +++ b/dao/src/main/java/cc/iotkit/dao/ProtocolComponentRepository.java @@ -4,6 +4,11 @@ import cc.iotkit.model.protocol.ProtocolComponent; import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface ProtocolComponentRepository extends MongoRepository { + + List findByState(String state); + } diff --git a/dao/src/main/java/cc/iotkit/dao/ProtocolConverterRepository.java b/dao/src/main/java/cc/iotkit/dao/ProtocolConverterRepository.java old mode 100644 new mode 100755 diff --git a/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java b/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java index a5b63f50..005097ae 100755 --- a/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java +++ b/manager/src/main/java/cc/iotkit/manager/controller/ProtocolController.java @@ -6,6 +6,7 @@ import cc.iotkit.common.utils.ReflectUtil; import cc.iotkit.comp.CompConfig; import cc.iotkit.comp.mqtt.MqttComponent; import cc.iotkit.comps.ComponentManager; +import cc.iotkit.comps.config.ComponentConfig; import cc.iotkit.converter.ScriptConverter; import cc.iotkit.dao.ProtocolComponentRepository; import cc.iotkit.dao.ProtocolConverterRepository; @@ -37,11 +38,8 @@ import java.util.UUID; @RequestMapping("/protocol") public class ProtocolController { - @Value("${component.dir:./data/components}") - private String componentDir; - - @Value("${converter.dir:./data/converters}") - private String converterDir; + @Autowired + private ComponentConfig componentConfig; @Autowired private ProtocolComponentRepository protocolComponentRepository; @@ -58,16 +56,6 @@ public class ProtocolController { @Autowired private ComponentManager componentManager; - private Path getComponentFilePath(String comId) { - return Paths.get(String.format("%s/%s", componentDir, comId)) - .toAbsolutePath().normalize(); - } - - private Path getConverterFilePath(String conId) { - return Paths.get(String.format("%s/%s", converterDir, conId)) - .toAbsolutePath().normalize(); - } - @PostMapping("/uploadJar") public String uploadJar(@RequestParam("file") MultipartFile file, String id) { if (file == null) { @@ -77,15 +65,11 @@ public class ProtocolController { String fileName = StringUtils.cleanPath(file.getOriginalFilename()); try { if (StringUtils.hasLength(id)) { - Optional optComponent = protocolComponentRepository.findById(id); - if (!optComponent.isPresent()) { - throw new BizException("the protocol component does not exists"); - } - dataOwnerService.checkOwner(optComponent.get()); + getAndCheckComponent(id); } else { id = UUID.randomUUID().toString(); } - Path jarFilePath = getComponentFilePath(id); + Path jarFilePath = componentConfig.getComponentFilePath(id); Files.createDirectories(jarFilePath); Path targetLocation = jarFilePath.resolve(fileName); Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING); @@ -101,7 +85,7 @@ public class ProtocolController { if (!StringUtils.hasLength(id)) { throw new BizException("component id is blank"); } - Path jarPath = getComponentFilePath(id); + Path jarPath = componentConfig.getComponentFilePath(id); if (!jarPath.resolve(component.getJarFile()).toFile().exists()) { throw new BizException("component jar file does not exist"); } @@ -125,20 +109,15 @@ public class ProtocolController { if (!StringUtils.hasLength(id)) { throw new BizException("component id is blank"); } - Path jarPath = getComponentFilePath(id); + Path jarPath = componentConfig.getComponentFilePath(id); if (!jarPath.resolve(component.getJarFile()).toFile().exists()) { throw new BizException("component jar file does not exist"); } - Optional optComponent = protocolComponentRepository.findById(component.getId()); - if (!optComponent.isPresent()) { - throw new BizException("the protocol component does not exists"); - } - - ProtocolComponent oldComponent = optComponent.get(); + ProtocolComponent oldComponent = getAndCheckComponent(id); component = ReflectUtil.copyNoNulls(component, oldComponent); - dataOwnerService.checkOwner(component); try { + componentManager.deRegister(id); protocolComponentRepository.save(component); } catch (Throwable e) { throw new BizException("add protocol component error", e); @@ -147,14 +126,9 @@ public class ProtocolController { @GetMapping("/getComponentScript/{id}") public String getComponentScript(@PathVariable("id") String id) { - Optional optComponent = protocolComponentRepository.findById(id); - if (!optComponent.isPresent()) { - throw new BizException("the component does not exists"); - } - ProtocolComponent component = optComponent.get(); - dataOwnerService.checkOwner(component); + getAndCheckComponent(id); try { - Path path = getComponentFilePath(id); + Path path = componentConfig.getComponentFilePath(id); File file = path.resolve(ProtocolComponent.SCRIPT_FILE_NAME).toFile(); return FileUtils.readFileToString(file, "UTF-8"); } catch (Throwable e) { @@ -167,28 +141,37 @@ public class ProtocolController { public void saveComponentScript( @PathVariable("id") String id, @RequestBody String script) { - Optional optComponent = protocolComponentRepository.findById(id); - if (!optComponent.isPresent()) { - throw new BizException("the component does not exists"); - } - ProtocolComponent oldComponent = optComponent.get(); - dataOwnerService.checkOwner(oldComponent); + ProtocolComponent oldComponent = getAndCheckComponent(id); try { - Path path = getComponentFilePath(id); + Path path = componentConfig.getComponentFilePath(id); File file = path.resolve(ProtocolComponent.SCRIPT_FILE_NAME).toFile(); script = JsonUtil.parse(script, String.class); FileUtils.writeStringToFile(file, script, "UTF-8", false); + + componentManager.deRegister(id); protocolComponentRepository.save(oldComponent); } catch (Throwable e) { throw new BizException("save protocol component script error", e); } } + private ProtocolComponent getAndCheckComponent(@PathVariable("id") String id) { + Optional optComponent = protocolComponentRepository.findById(id); + if (!optComponent.isPresent()) { + throw new BizException("the component does not exists"); + } + ProtocolComponent oldComponent = optComponent.get(); + dataOwnerService.checkOwner(oldComponent); + return oldComponent; + } + @PostMapping("/deleteComponent/{id}") public void deleteComponent(@PathVariable("id") String id) { - dataOwnerService.checkOwner(protocolComponentRepository, id); + ProtocolComponent component = getAndCheckComponent(id); try { - Path path = Paths.get(String.format("%s/%s", componentDir, id)) + componentManager.deRegister(id); + + Path path = Paths.get(String.format("%s/%s", componentConfig.getComponentDir(), id)) .toAbsolutePath().normalize(); File file = path.toFile(); try { @@ -200,7 +183,7 @@ public class ProtocolController { } catch (NoSuchFileException e) { log.warn("delete component script error", e); } - protocolComponentRepository.deleteById(id); + protocolComponentRepository.deleteById(component.getId()); } catch (Throwable e) { throw new BizException("delete protocol component error", e); } @@ -212,6 +195,8 @@ public class ProtocolController { @PathVariable("page") int page) { Page components = protocolComponentRepository.findAll( PageRequest.of(page - 1, size, Sort.by(Sort.Order.desc("createAt")))); + components.getContent().forEach(c -> c.setState(componentManager.isRunning(c.getId()) ? + ProtocolComponent.STATE_RUNNING : ProtocolComponent.STATE_STOPPED)); return new Paging<>(components.getTotalElements(), components.getContent()); } @@ -240,14 +225,8 @@ public class ProtocolController { @PostMapping("/saveConverter") public void saveConverter(ProtocolConverter converter) { - Optional optConverter = protocolConverterRepository.findById(converter.getId()); - if (!optConverter.isPresent()) { - throw new BizException("the protocol converter does not exists"); - } - - ProtocolConverter oldConverter = optConverter.get(); + ProtocolConverter oldConverter = getAndCheckConverter(converter.getId()); converter = ReflectUtil.copyNoNulls(converter, oldConverter); - dataOwnerService.checkOwner(converter); try { protocolConverterRepository.save(converter); } catch (Throwable e) { @@ -255,16 +234,22 @@ public class ProtocolController { } } - @GetMapping("/getConverterScript/{id}") - public String getConverterScript(@PathVariable("id") String id) { + private ProtocolConverter getAndCheckConverter(String id) { Optional optConverter = protocolConverterRepository.findById(id); if (!optConverter.isPresent()) { - throw new BizException("the converter does not exists"); + throw new BizException("the protocol converter does not exists"); } + ProtocolConverter converter = optConverter.get(); dataOwnerService.checkOwner(converter); + return converter; + } + + @GetMapping("/getConverterScript/{id}") + public String getConverterScript(@PathVariable("id") String id) { + getAndCheckConverter(id); try { - Path path = getConverterFilePath(id); + Path path = componentConfig.getConverterFilePath(id); File file = path.resolve(ProtocolConverter.SCRIPT_FILE_NAME).toFile(); return FileUtils.readFileToString(file, "UTF-8"); } catch (Throwable e) { @@ -277,14 +262,9 @@ public class ProtocolController { public void saveConverterScript( @PathVariable("id") String id, @RequestBody String script) { - Optional optConverter = protocolConverterRepository.findById(id); - if (!optConverter.isPresent()) { - throw new BizException("the converter does not exists"); - } - ProtocolConverter oldConverter = optConverter.get(); - dataOwnerService.checkOwner(oldConverter); + getAndCheckConverter(id); try { - Path path = getConverterFilePath(id); + Path path = componentConfig.getConverterFilePath(id); File file = path.resolve(ProtocolConverter.SCRIPT_FILE_NAME).toFile(); script = JsonUtil.parse(script, String.class); FileUtils.writeStringToFile(file, script, "UTF-8", false); @@ -295,9 +275,9 @@ public class ProtocolController { @PostMapping("/deleteConverter/{id}") public void deleteConverter(@PathVariable("id") String id) { - dataOwnerService.checkOwner(protocolConverterRepository, id); + getAndCheckConverter(id); try { - Path path = Paths.get(String.format("%s/%s", componentDir, id)) + Path path = Paths.get(String.format("%s/%s", componentConfig.getConverterDir(), id)) .toAbsolutePath().normalize(); File file = path.toFile(); try { @@ -315,28 +295,21 @@ public class ProtocolController { } } - @PostMapping("/component/{id}/{state}") - public void startComponent(@PathVariable("id") String id, - @PathVariable("state") String state) { - - } - - - @GetMapping("/registerMqtt") - public void registerMqtt() throws IOException { - MqttComponent component = new MqttComponent(); - component.create(new CompConfig(300, "{\"port\":2883,\"ssl\":false}")); - ScriptConverter converter = new ScriptConverter(); - converter.setScript(FileUtils.readFileToString(new File("/Users/sjg/home/gitee/open-source/converter.js"), "UTF-8")); - component.setConverter(converter); - componentManager.register("123", component); - componentManager.start("123", FileUtils.readFileToString(new File("/Users/sjg/home/gitee/open-source/component.js"), "UTF-8")); - } - - @GetMapping("/deregisterMqtt") - public void deregisterMqtt() { - componentManager.stop("123"); - componentManager.deRegister("123"); + @PostMapping("/component/{id}/state/{state}") + public void changeComponentState(@PathVariable("id") String id, + @PathVariable("state") String state) { + ProtocolComponent component = getAndCheckComponent(id); + String converterId = component.getConverter(); + getAndCheckConverter(converterId); + if (ProtocolComponent.STATE_RUNNING.equals(state)) { + componentManager.register(component); + componentManager.start(component.getId()); + component.setState(ProtocolComponent.STATE_RUNNING); + } else { + componentManager.deRegister(id); + component.setState(ProtocolComponent.STATE_STOPPED); + } + protocolComponentRepository.save(component); } } diff --git a/model/src/main/java/cc/iotkit/model/protocol/ProtocolConverter.java b/model/src/main/java/cc/iotkit/model/protocol/ProtocolConverter.java old mode 100644 new mode 100755 diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentClassLoader.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentClassLoader.java index f025f5d3..bd205160 100755 --- a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentClassLoader.java +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentClassLoader.java @@ -16,12 +16,12 @@ import java.nio.charset.Charset; @Slf4j public class ComponentClassLoader { - protected Class findClass(String name) throws ClassNotFoundException { + protected static Class findClass(String name) throws ClassNotFoundException { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); return (Class) classLoader.loadClass(name); } - private String addUrl(File jarPath) throws NoSuchMethodException, InvocationTargetException, + private static String addUrl(File jarPath) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException { URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); @@ -35,9 +35,9 @@ public class ComponentClassLoader { return StreamUtils.copyToString(is, Charset.forName("UTF-8")); } - public IComponent getComponent(File jarPath) { + public static IComponent getComponent(File jarFile) { try { - String className = addUrl(jarPath); + String className = addUrl(jarFile); Class componentClass = findClass(className); return componentClass.newInstance(); } catch (Throwable e) { diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentManager.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentManager.java index 2a60e15b..7e27ceae 100755 --- a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentManager.java +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentManager.java @@ -3,18 +3,30 @@ package cc.iotkit.comps; import cc.iotkit.common.exception.BizException; import cc.iotkit.common.utils.JsonUtil; +import cc.iotkit.comp.CompConfig; import cc.iotkit.comp.IComponent; import cc.iotkit.comps.config.CacheKey; +import cc.iotkit.comps.config.ComponentConfig; import cc.iotkit.comps.service.DeviceBehaviourService; import cc.iotkit.converter.DeviceMessage; +import cc.iotkit.converter.ScriptConverter; import cc.iotkit.converter.ThingService; +import cc.iotkit.dao.ProtocolComponentRepository; import cc.iotkit.model.device.message.ThingModelMessage; +import cc.iotkit.model.protocol.ProtocolComponent; +import cc.iotkit.model.protocol.ProtocolConverter; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; +import javax.annotation.PostConstruct; +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -23,31 +35,84 @@ import java.util.concurrent.TimeUnit; public class ComponentManager { private final Map components = new HashMap<>(); + private final Map scripts = new HashMap<>(); + private final Map states = new HashMap<>(); @Autowired private DeviceBehaviourService deviceBehaviourService; @Autowired private StringRedisTemplate redisTemplate; + @Autowired + private ComponentConfig componentConfig; + @Autowired + private ProtocolComponentRepository componentRepository; - public void register(String id, IComponent component) { + @PostConstruct + public void init() { + List componentList = componentRepository.findByState(ProtocolComponent.STATE_RUNNING); + for (ProtocolComponent component : componentList) { + register(component); + start(component.getId()); + } + } + + public void register(ProtocolComponent component) { + String id = component.getId(); + if (components.containsKey(id)) { + return; + } + + Path path = componentConfig.getComponentFilePath(id); + File file = path.resolve(component.getJarFile()).toAbsolutePath().toFile(); + IComponent componentInstance = ComponentClassLoader.getComponent(file); + if (componentInstance == null) { + throw new BizException("instance component failed"); + } + componentInstance.create(new CompConfig(300, component.getConfig())); + + try { + ScriptConverter scriptConverter = new ScriptConverter(); + Path converterPath = componentConfig.getConverterFilePath(component.getConverter()); + String converterScript = FileUtils.readFileToString(converterPath. + resolve(ProtocolConverter.SCRIPT_FILE_NAME).toFile(), "UTF-8"); + + scriptConverter.setScript(converterScript); + componentInstance.setConverter(scriptConverter); + + String componentScript = FileUtils.readFileToString(path. + resolve(ProtocolComponent.SCRIPT_FILE_NAME).toFile(), "UTF-8"); + register(id, componentInstance, componentScript); + } catch (IOException e) { + throw new BizException("get component script error", e); + } + } + + public void register(String id, IComponent component, String script) { components.put(id, component); + scripts.put(id, script); + states.put(id, false); } public void deRegister(String id) { IComponent component = components.remove(id); + scripts.remove(id); + states.remove(id); + component.stop(); component.destroy(); } - public void start(String id, String script) { + public void start(String id) { IComponent component = components.get(id); if (component == null) { return; } + String script = scripts.get(id); component.setHandler( new MessageHandler(this, component, script, component.getConverter(), deviceBehaviourService)); component.start(); + states.put(id, true); } public void stop(String id) { @@ -56,6 +121,11 @@ public class ComponentManager { return; } component.stop(); + states.put(id, false); + } + + public boolean isRunning(String id) { + return states.containsKey(id) && states.get(id); } public void send(ThingService service) { diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/MessageHandler.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/MessageHandler.java index 1c61dec1..21aeec60 100755 --- a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/MessageHandler.java +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/MessageHandler.java @@ -48,12 +48,12 @@ public class MessageHandler implements IMessageHandler { this.component = component; this.converter = converter; this.deviceBehaviourService = deviceBehaviourService; - scriptObj = engine.eval(script); + scriptObj = engine.eval(String.format("new (function () {\n%s})()", script)); } public ReceiveResult onReceive(Map head, String type, String msg) { try { - ScriptObjectMirror result = (ScriptObjectMirror) engine.invokeMethod(scriptObj, "onReceive", head, type, msg); + ScriptObjectMirror result = (ScriptObjectMirror) invokeMethod("onReceive", head, type, msg); log.info("onReceive script result:{}", JsonUtil.toJsonString(result)); Object rstType = result.get("type"); if (rstType == null) { @@ -107,10 +107,10 @@ public class MessageHandler implements IMessageHandler { private void doRegister(RegisterInfo reg) throws ScriptException, NoSuchMethodException { try { deviceBehaviourService.register(reg); - engine.invokeMethod(scriptObj, "onRegistered", reg, "true"); } catch (Throwable e) { log.error("register error", e); - engine.invokeMethod(scriptObj, "onRegistered", reg, "false"); + } finally { + invokeMethod("onRegistered", reg, "false"); } } @@ -120,13 +120,20 @@ public class MessageHandler implements IMessageHandler { auth.getDeviceName(), auth.getProductSecret(), auth.getDeviceSecret()); - engine.invokeMethod(scriptObj, "onAuthed", auth, true); } catch (Throwable e) { log.error("device auth error", e); - engine.invokeMethod(scriptObj, "onAuthed", auth, false); + } finally { + invokeMethod("onAuthed", auth, "false"); } } + private Object invokeMethod(String name, Object... args) throws ScriptException, NoSuchMethodException { + if (((ScriptObjectMirror) scriptObj).get(name) != null) { + return engine.invokeMethod(scriptObj, name, args); + } + return null; + } + private void doStateChange(DeviceState state) { try { component.onDeviceStateChange(state); diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/ComponentConfig.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/ComponentConfig.java new file mode 100755 index 00000000..bb8d5db4 --- /dev/null +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/config/ComponentConfig.java @@ -0,0 +1,29 @@ +package cc.iotkit.comps.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +import java.nio.file.Path; +import java.nio.file.Paths; + +@Configuration +@Data +public class ComponentConfig { + + @Value("${component.dir:./data/components}") + private String componentDir; + + @Value("${converter.dir:./data/converters}") + private String converterDir; + + public Path getComponentFilePath(String comId) { + return Paths.get(componentDir, comId) + .toAbsolutePath().normalize(); + } + + public Path getConverterFilePath(String conId) { + return Paths.get(converterDir, conId) + .toAbsolutePath().normalize(); + } +} diff --git a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java index 8e7ec8fd..0c56ba70 100755 --- a/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java +++ b/protocol-gateway/converter/src/main/java/cc/iotkit/converter/ScriptConverter.java @@ -21,7 +21,7 @@ public class ScriptConverter implements IConverter { public void setScript(String script) { try { - scriptObj = engine.eval(script); + scriptObj = engine.eval(String.format("new (function () {\n%s})()", script)); } catch (ScriptException e) { log.error("eval converter script error", e); } diff --git a/protocol-gateway/emqx-component/dependency-reduced-pom.xml b/protocol-gateway/emqx-component/dependency-reduced-pom.xml old mode 100644 new mode 100755 diff --git a/protocol-gateway/mqtt-component/dependency-reduced-pom.xml b/protocol-gateway/mqtt-component/dependency-reduced-pom.xml old mode 100644 new mode 100755 From 1c61923d0e80187efe70d7c8e971a84453ed942a Mon Sep 17 00:00:00 2001 From: xiwa Date: Sat, 2 Apr 2022 10:30:08 +0800 Subject: [PATCH 16/16] =?UTF-8?q?=E9=80=9A=E8=AE=AF=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E9=94=99=E8=AF=AF=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cc/iotkit/comps/ComponentManager.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentManager.java b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentManager.java index 7e27ceae..027e6699 100755 --- a/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentManager.java +++ b/protocol-gateway/component-server/src/main/java/cc/iotkit/comps/ComponentManager.java @@ -49,10 +49,14 @@ public class ComponentManager { @PostConstruct public void init() { - List componentList = componentRepository.findByState(ProtocolComponent.STATE_RUNNING); - for (ProtocolComponent component : componentList) { - register(component); - start(component.getId()); + try { + List componentList = componentRepository.findByState(ProtocolComponent.STATE_RUNNING); + for (ProtocolComponent component : componentList) { + register(component); + start(component.getId()); + } + } catch (Throwable e) { + log.error("init protocol components error", e); } }