From 48b591cc67f21ac235608492a83c8b650489a528 Mon Sep 17 00:00:00 2001 From: xiwa Date: Mon, 21 Mar 2022 06:34:39 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8D=8F=E8=AE=AE=E7=BD=91=E5=85=B3=E4=BF=AE?= =?UTF-8?q?=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