diff --git a/.gitignore b/.gitignore index d51be2f6e01449f28a65a77a44eaf0233e770489..7ea256ffb7e64b2932659b88b6ca03695e112796 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ ./.idea/** /.idea/ target/ - +*.versionsBackup # Log file *.log @@ -26,4 +26,5 @@ target/ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* - +/ignite/ +./ignite/** diff --git a/README.md b/README.md index 8178277e170fd5c639b24de5c4d36ee821512a15..c38d5147b101c121c1d3e65655f458f3e5009186 100644 --- a/README.md +++ b/README.md @@ -1,143 +1,210 @@ -## SMQTT是一款开源的MQTT消息代理Broker, +## SMQTT重磅升级 +感谢大家帮忙给新项目点Star,感谢! +- [Gitee](https://gitee.com/quickmsg/smqttx) +- [Github](https://github.com/quickmsg/smqttx) +- + + +## ![image](icon/logo.png) SMQTT开源的MQTT消息代理Broker + +SMQTT基于reactor-netty(spring-webflux底层依赖) +开发,底层采用Reactor3反应堆模型,支持单机部署,支持容器化部署,具备低延迟,高吞吐量,支持百万TCP连接,同时支持多种协议交互,是一款非常优秀的消息中间件! -SMQTT基于Netty开发,底层采用Reactor3反应堆模型,支持单机部署,支持容器化部署,具备低延迟,高吞吐量,支持百万TCP连接,同时支持多种协议交互,是一款非常优秀的消息中间件! ## smqtt目前拥有的功能如下: -1. 消息质量等级实现(支持qos0,qos1,qos2) -2. 会话消息 -3. 保留消息 -4. 遗嘱消息 -5. 客户端认证 -6. tls加密 -7. websocket协议支持 -8. http协议交互 -9. SPI接口扩展支持 +![架构图](icon/component.png) + +1. 消息质量等级实现(支持qos0,qos1,qos2) +2. topicFilter支持 + - topic分级(test/test) + - +支持(单层匹配) + - *支持(多层匹配) +3. 会话消息 + - 默认内存存储 + - 支持持久化(redis/db) +4. 保留消息 + - 默认内存存储 + - 支持持久化(redis/db) +5. 遗嘱消息 + + > 设备掉线时候触发 +6. 客户端认证 + - 支持spi注入外部认证 +7. tls加密 + - 支持tls加密(mqtt端口/http端口) +8. websocket协议支持x + + > 使用mqtt over websocket +9. http协议交互 + - 支持http接口推送消息 + - 支持spi扩展http接口 +10. SPI接口扩展支持 - 消息管理接口(会话消息/保留消息管理) - 通道管理接口 (管理系统的客户端连接) - - 认证接口 (用于自定义外部认证) - - 拦截器 (用户自定义拦截消息) -10. 集群支持(gossip协议实现) -11. 容器化支持 -12. 持久化支持(session 保留消息) + - ~~认证接口 (用于自定义外部认证)~~ + - 拦截器 (用户自定义拦截消息) +11. 集群支持(gossip协议实现) +12. 容器化支持 + + > 默认镜像最新tag: 1ssqq1lxr/smqtt +13. 持久化支持(session 保留消息) +14. 规则引擎支持 +15. 支持springboot starter启动 +16. 管理后台 + + > 请参考smqtt文档如何启动管理后台 +17. grafana监控集成 + - 支持influxdb + - 支持prometheus +18. ACL权限管理 + - 对设备、资访问授权 +19. 认证模块 + - 支持http + - 支持匿名 + - 支持固定密码 + - 支持sql + +## 尝试一下 + +> 大家不要恶意链接,谢谢! +| 管理 | 说明 | 其他 | +|----------------------------------------| ---- |---- | +| 121.40.92.152:1883 | mqtt端口 |用户名:smqtt 密码:smqtt | +| 121.40.92.152:18888 | mqtt over websocket |用户名:smqtt 密码:smqtt | +| http://121.40.92.152:60000/smqtt/admin | 管理后台 |用户名:smqtt 密码:smqtt | +## 启动方式 -## main方式启动 +### main方式启动 引入依赖 + ```markdown + io.github.quickmsg smqtt-core - 1.0.5 + ${Latest version} + + + + smqtt-registry-scube + io.github.quickmsg + ${Latest version} + + + + smqtt-ui + io.github.quickmsg + ${Latest version} - ``` -阻塞式启动服务: +- 阻塞式启动服务: ```markdown - - Bootstrap.builder() - .port(8555) - .websocketPort(8999) - .options(channelOptionMap -> {}) - .ssl(false) - .reactivePasswordAuth((U,P)->true) - .sslContext(new SslContext("crt","key")) - .isWebsocket(true) - .wiretap(false) - .httpOptions(Bootstrap.HttpOptions.builder().ssl(false).accessLog(true).build()) - .build() - .startAwait(); - + Bootstrap.builder() + .rootLevel(Level.INFO) + .websocketConfig( + BootstrapConfig.WebsocketConfig + .builder() + .enable(false) + .path("/mqtt") + .port(8888) + .build() + ) + .tcpConfig( + BootstrapConfig + .TcpConfig + .builder() + .port(1883) + .ssl(SslContext.builder().enable(false).build()) + .build()) + .httpConfig( + BootstrapConfig + .HttpConfig + .builder() + .enable(false) + .accessLog(true) + .admin(BootstrapConfig.HttpAdmin.builder().enable(true).username("smqtt").password("smqtt").build()) + .build()) + .clusterConfig( + BootstrapConfig. + ClusterConfig + .builder() + .enable(false) + .namespace("smqtt") + .node("node-1") + .port(7773) + .url("127.0.0.1:7771,127.0.0.1:7772"). + build()) + .build() + .startAwait(); ``` -非阻塞式启动服务: +- 非阻塞式启动服务: ```markdown - - - Bootstrap bootstrap = - Bootstrap.builder() - .port(8555) - .websocketPort(8999) - .options(channelOptionMap -> {}) - .ssl(false) - .sslContext(new SslContext("crt","key")) - .isWebsocket(true) - .wiretap(false) - .httpOptions(Bootstrap.HttpOptions.builder().ssl(false).accessLog(true).build()) - .build() - .start().block(); - -assert bootstrap != null; - // 关闭服务 - bootstrap.shutdown(); - + Bootstrap bootstrap = Bootstrap.builder() + .rootLevel(Level.INFO) + .websocketConfig( + BootstrapConfig.WebsocketConfig + .builder() + .enable(false) + .path("/mqtt") + .port(8888) + .build() + ) + .tcpConfig( + BootstrapConfig + .TcpConfig + .builder() + .port(1883) + .ssl(SslContext.builder().enable(false).build()) + .build()) + .httpConfig( + BootstrapConfig + .HttpConfig + .builder() + .enable(false) + .accessLog(true) + .admin(BootstrapConfig.HttpAdmin.builder().enable(true).username("smqtt").password("smqtt").build()) + .build()) + .clusterConfig( + BootstrapConfig. + ClusterConfig + .builder() + .enable(false) + .namespace("smqtt") + .node("node-1") + .port(7773) + .url("127.0.0.1:7771,127.0.0.1:7772"). + build()) + .build() + .start().block(); ``` +### jar方式 -## jar方式 - - -1. 下载源码 mvn compile package -Dmaven.test.skip=true -P jar +1. 下载源码 mvn compile package -Dmaven.test.skip=true -P jar,web ```markdown 在smqtt-bootstrap/target目录下生成jar ``` -2. 准备配置文件 config.properties +2. 准备配置文件 config.yaml -```markdown - - # 开启tcp端口 - smqtt.tcp.port=1883 - # 高水位 - smqtt.tcp.lowWaterMark=4000000 - # 低水位 - smqtt.tcp.highWaterMark=80000000 - # 开启ssl加密 - smqtt.tcp.ssl=false - # 证书crt smqtt.tcp.ssl.crt = - # 证书key smqtt.tcp.ssl.key = - # 开启日志 - smqtt.tcp.wiretap=false - # boss线程 - smqtt.tcp.bossThreadSize=4 - # work线程 - smqtt.tcp.workThreadSize=8 - # websocket端口 - smqtt.websocket.port=8999 - # websocket开启 - smqtt.websocket.enable=true - # smqtt用户 - smqtt.tcp.username=smqtt - # smqtt密码 - smqtt.tcp.password=smqtt - # 开启http - smqtt.http.enable=true - # 开启http端口 - smqtt.http.port=1999 - # 开启http日志 - smqtt.http.accesslog=true - # 开启ssl - smqtt.http.ssl.enable=false - # smqtt.http.ssl.crt = - # smqtt.http.ssl.key - ``` + [config.yaml](config/config.yaml) 3. 启动服务 ```markdown - java -jar smqtt-bootstrap-1.0.1-SNAPSHOT.jar + java -jar smqtt-bootstrap-1.0.1-SNAPSHOT.jar ``` - - -## docker 方式 - +### docker 方式 拉取镜像 @@ -153,44 +220,99 @@ docker pull 1ssqq1lxr/smqtt:latest docker run -it -p 1883:1883 1ssqq1lxr/smqtt ``` -启动镜像使用自定义配置( 准备配置文件conf.properties) - +启动镜像使用自定义配置(同上准备配置文件config.yaml) ``` # 启动服务 docker run -it -v <配置文件路径目录>:/conf -p 1883:1883 -p 1999:1999 1ssqq1lxr/smqtt ``` +### springboot方式 -## 测试服务(启动http端口) +1. 引入依赖 -- 启动客户端订阅主题 test/+ + ```markdown + + io.github.quickmsg + smqtt-spring-boot-starter + ${Latest version >= 1.0.8} + + ``` -- 使用http接口推送mqtt消息 +2. 启动类Application上添加注解 ` @EnableMqttServer` -``` -# 推送消息 -curl -H "Content-Type: application/json" -X POST -d '{"topic": "test/teus", "qos":2, "retain":true, "message":"我来测试保留消息3" }' "http://localhost:1999/smqtt/publish" +3. 配置application.yml文件 + > properties也支持,但是需要自己转换,没有提供demo文件 + + [config.yaml](config/config.yaml) + +4. 启动springboot服务服务即可 +5. 如果引入的是spring-boot-starter-parent的管理包,如果启动报错,则需要添加以下依赖 + +```xml + + + io.projectreactor + reactor-core + 3.4.9 + + +io.projectreactor.netty +reactor-netty +1.0.10 + ``` +## 官网地址 +[smqtt官网](https://www.smqtt.cc/) ## wiki地址 -集群类配置参考文档: +[wiki地址](https://wiki.smqtt.cc/) + +## 管理后台 + +![image](icon/admin.png) + +## 监控页面 -[smqtt文档](https://quickmsg.github.io/smqtt) +### Mqtt监控 + +![image](icon/application.png) + +### Jvm监控 + +![image](icon/jvm.png) + +### Netty监控 + +![image](icon/netty.png) ## License -[Apache License, Version 2.0](https://github.com/quickmsg/smqtt/blob/main/LICENSE) +[Apache License, Version 2.0](LICENSE) + +## 商业版本 +[商业版演示地址](http://114.116.14.30) +## 友情链接 + +一款非常好用的IOT平台 thinglinks: + +- [Github](https://github.com/mqttsnet/thinglinks) +- [Gitee](https://gitee.com/mqttsnet/thinglinks) + +## 相关技术文档 + +- [reactor3](https://projectreactor.io/docs/core/release/reference/) +- [reactor-netty](https://projectreactor.io/docs/netty/1.0.12/reference/index.html) ## 麻烦关注下公众号! + ![image](icon/icon.jpg) - 添加微信号`Lemon877164954`,拉入smqtt官方交流群 - 加入qq群 `700152283` - diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000000000000000000000000000000000..034e848032092eaf8ef96eac731b6ed5961987f3 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,21 @@ +# Security Policy + +## Supported Versions + +Use this section to tell people about which versions of your project are +currently being supported with security updates. + +| Version | Supported | +| ------- | ------------------ | +| 5.1.x | :white_check_mark: | +| 5.0.x | :x: | +| 4.0.x | :white_check_mark: | +| < 4.0 | :x: | + +## Reporting a Vulnerability + +Use this section to tell people how to report a vulnerability. + +Tell them where to go, how often they can expect to get an update on a +reported vulnerability, what to expect if the vulnerability is accepted or +declined, etc. diff --git a/config.properties b/config.properties deleted file mode 100644 index 156849c5632e4cf6628ea924433a7abc88f45a03..0000000000000000000000000000000000000000 --- a/config.properties +++ /dev/null @@ -1,90 +0,0 @@ -# 日志级别 ALL|TRACE|DEBUG|INFO|WARN|ERROR|OFF -smqtt.log.level=info -# 开启tcp端口 -smqtt.tcp.port=1883 -# 高水位 -smqtt.tcp.lowWaterMark=4000000 -# 低水位 -smqtt.tcp.highWaterMark=80000000 -# 开启ssl加密 -smqtt.tcp.ssl=false -# 证书crt smqtt.tcp.ssl.crt = -# 证书key smqtt.tcp.ssl.key = -# 开启日志 -smqtt.tcp.wiretap=false -# boss线程 -smqtt.tcp.bossThreadSize=4 -# work线程 -smqtt.tcp.workThreadSize=8 -# websocket端口 -smqtt.websocket.port=8999 -# websocket开启 -smqtt.websocket.enable=true -# smqtt用户 -smqtt.tcp.username=smqtt -# smqtt密码 -smqtt.tcp.password=smqtt -# 开启http -smqtt.http.enable=true -# 开启http端口 -smqtt.http.port=60000 -# 开启http日志 -smqtt.http.accesslog=true -# 开启ssl -smqtt.http.ssl.enable=false -# smqtt.http.ssl.crt =; -# smqtt.http.ssl.key; -# 开启集群 -smqtt.cluster.enable=false -# 集群节点地址 -smqtt.cluster.url=127.0.0.1:7771,127.0.0.1:7772 -# 节点端口 -smqtt.cluster.port=7771 -# 节点名称 -smqtt.cluster.node=node-1 - -# 数据库配置(选配) -db.driverClassName=com.mysql.jdbc.Driver -db.url=jdbc:mysql://127.0.0.1:3306/smqtt?characterEncoding=utf-8&useSSL=false&useInformationSchema=true&serverTimezone=UTC -db.username=root -db.password=123 -# 连接池初始化连接数 -db.initialSize=10 -# 连接池中最多支持多少个活动会话 -db.maxActive=300 -# 向连接池中请求连接时,超过maxWait的值后,认为本次请求失败 -db.maxWait=60000 -# 回收空闲连接时,将保证至少有minIdle个连接 -db.minIdle=2 - -# redis配置(选配) -# 单机模式:single 哨兵模式:sentinel 集群模式:cluster -redis.mode=single -# 数据库 -redis.database=0 -# 密码 -redis.password= -# 超时时间 -redis.timeout=3000 -# 最小空闲数 -redis.pool.min.idle=8 -# 连接超时时间(毫秒) -redis.pool.conn.timeout=3000 -# 连接池大小 -redis.pool.size=10 - -# 单机配置 -redis.single.address=127.0.0.1:6379 - -# 集群配置 -redis.cluster.scan.interval=1000 -redis.cluster.nodes=127.0.0.1:7000,127.0.0.1:7001,127.0.0.1:7002,127.0.0.1:7003,127.0.0.1:7004,127.0.0.1:7005 -redis.cluster.read.mode=SLAVE -redis.cluster.retry.attempts=3 -redis.cluster.slave.connection.pool.size=64 -redis.cluster.master.connection.pool.size=64 -redis.cluster.retry.interval=1500 - -# 哨兵配置 -redis.sentinel.master=mymaster -redis.sentinel.nodes=127.0.0.1:26379,127.0.0.1:26379,127.0.0.1:26379 \ No newline at end of file diff --git a/config/acl/basic_policy.csv b/config/acl/basic_policy.csv new file mode 100644 index 0000000000000000000000000000000000000000..ca87dd9f23c79be67351b0a9077de269b6f46fc5 --- /dev/null +++ b/config/acl/basic_policy.csv @@ -0,0 +1,4 @@ +p, client01, topicA, PUBLISH,allow +p, client02, topicB, PUBLISH,deny +p, ip{192.168.0.172/24}, topicB, PUBLISH,deny +p, all, topicB, SUBSCRIBE,allow diff --git a/config/config.yaml b/config/config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f7896c153c3cb68f6134363a035e852c8ea47e93 --- /dev/null +++ b/config/config.yaml @@ -0,0 +1,97 @@ +smqtt: + logLevel: INFO # 系统日志 + tcp: # tcp配置 + connectModel: KICK # UNIQUE 唯一 KICK 互踢 + notKickSecond: 30 # KICK互踢模式生效, 单位秒, 指定时间内客户端不互踢, 避免客户端自动连接持续互踢 + port: 1883 # mqtt端口号 + wiretap: false # 二进制日志 前提是 smqtt.logLevel = DEBUG + bossThreadSize: 1 # boss线程 默认=1 + workThreadSize: 9 # work线程 默认=cpu核心数+1 + businessThreadSize: 8 # 业务线程数 默认=cpu核心数 + businessQueueSize: 100000 #业务队列 默认=100000 + messageMaxSize: 4194304 # 接收消息的最大限制 默认4194304(4M) + lowWaterMark: 4000000 # 不建议配置 默认 32768 + highWaterMark: 80000000 # 不建议配置 默认 65536 + # globalReadWriteSize: 10000000,100000000 全局读写大小限制 + # channelReadWriteSize: 10000000,100000000 单个channel读写大小限制 + options: + SO_BACKLOG: 2000 +# ssl: # ssl配置 +# enable: false # 开关 +# key: /user/server.key # 指定ssl文件 默认系统生成 +# crt: /user/server.crt # 指定ssl文件 默认系统生成 +# ca: /user/server.ca # ca证书 双向加密配置 + acl: + aclPolicy: NONE # NONE or FILE or JDBC + filePath: D:\smqtt\config\acl\basic_policy.csv # FILE时配置filePath + jdbcAclConfig: + driver: com.mysql.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/smqtt + username: root + password: 123 + http: # http相关配置 端口固定60000 + enable: true # 开关 + accessLog: true # http访问日志 + ssl: # ssl配置 + enable: false + admin: # 后台管理配置 + enable: true # 开关 + username: smqtt # 访问用户名 + password: smqtt # 访问密码 + auth: + fixed: + username: smqtt + password: smqtt + ws: # websocket配置 + enable: true # 开关 + port: 8999 # 端口 + path: /mqtt # ws 的访问path mqtt.js请设置此选项 + cluster: # 集群配置 + enable: false # 集群开关 + url: 127.0.0.1:7771,127.0.0.1:7772 # 启动节点 + port: 7771 # 端口 + node: node-1 # 集群节点名称 唯一 + namespace: smqtt + external: + host: localhost # 用于映射容器ip 请不要随意设置,如果不需要请移除此选项 + port: 7777 # 用于映射容器端口 请不要随意设置,如果不需要请移除此选项 + meter: + meterType: PROMETHEUS # INFLUXDB , PROMETHEUS + db: # 参数值配置参考https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration + jdbcUrl: jdbc:mysql://localhost:3306/smqtt + username: root + password: 123 + dataSourceCachePrepStmts: false + dataSourcePrepStmtCacheSize: 250 + dataSourcePrepStmtCacheSqlLimit: 2048 + dataSourceUseServerPrepStmts: true + dataSourceUseLocalSessionState: true + dataSourceRewriteBatchedStatements: true + dataSourceCacheResultSetMetadata: true + dataSourceCacheServerConfiguration: true + dataSourceElideSetAutoCommits: true + dataSourceMaintainTimeStats: false + redis: # redis 请参考 https://wiki.smqtt.cc/%E5%85%B6%E4%BB%96/1.store.html 【如果没有引入相关依赖请移除此配置】 + mode: single + database: 0 + password: + timeout: 3000 + poolMinIdle: 8 + poolConnTimeout: 3000 + poolSize: 10 + single: + address: 127.0.0.1:6379 + cluster: + scanInterval: 1000 + nodes: 127.0.0.1:7000,127.0.0.1:7001,127.0.0.1:7002,127.0.0.1:7003,127.0.0.1:7004,127.0.0.1:7005 + readMode: SLAVE + retryAttempts: 3 + slaveConnectionPoolSize: 64 + masterConnectionPoolSize: 64 + retryInterval: 1500 + sentinel: + master: mymaster + nodes: 127.0.0.1:26379,127.0.0.1:26379,127.0.0.1:26379 + + + diff --git a/config/monitor/prometheus/smqtt-application-1638608184756.json b/config/monitor/prometheus/smqtt-application-1638608184756.json new file mode 100644 index 0000000000000000000000000000000000000000..2dc0aed806559eb7526cc1b15e78f012d566fbab --- /dev/null +++ b/config/monitor/prometheus/smqtt-application-1638608184756.json @@ -0,0 +1,737 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "gnetId": null, + "graphTooltip": 2, + "id": 2, + "iteration": 1638607798289, + "links": [], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 5, + "panels": [], + "repeat": null, + "title": "实时数据", + "type": "row" + }, + { + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 1 + }, + "id": 8, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.2.0", + "targets": [ + { + "exemplar": true, + "expr": "smqtt_connect_count{instance=\"$instance\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "连接计数", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "连接计数", + "transformations": [], + "type": "stat" + }, + { + "datasource": null, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 1 + }, + "id": 10, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.2.0", + "targets": [ + { + "exemplar": true, + "expr": "smqtt_subscribe_count{instance=\"$instance\"}", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "订阅数", + "type": "stat" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 9 + }, + "id": 6, + "panels": [], + "title": "事件(qps)", + "type": "row" + }, + { + "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 10 + }, + "id": 18, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "exemplar": true, + "expr": "rate(smqtt_publish_event_count_total{instance=\"$instance\"}[1m])", + "interval": "", + "legendFormat": "publish", + "refId": "A" + } + ], + "title": "publish", + "type": "timeseries" + }, + { + "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 10 + }, + "id": 24, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "exemplar": true, + "expr": "rate(smqtt_connect_event_count_total{instance=\"$instance\"}[1m])", + "interval": "", + "legendFormat": "connect", + "refId": "A" + } + ], + "title": "connect", + "type": "timeseries" + }, + { + "datasource": null, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 18 + }, + "id": 22, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "exemplar": true, + "expr": "rate(smqtt_subscribe_event_count_total{instance=\"$instance\"}[1m])", + "interval": "", + "legendFormat": "subscribe", + "refId": "A" + } + ], + "title": "subscribe", + "type": "timeseries" + }, + { + "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 18 + }, + "id": 20, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "exemplar": true, + "expr": "rate(smqtt_close_event_count_total{instance=\"$instance\"}[1m])", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "close", + "type": "timeseries" + }, + { + "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 14, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "exemplar": true, + "expr": "rate(smqtt_unscribe_event_count_total{instance=\"$instance\"}[1m])", + "interval": "", + "legendFormat": "unscribe", + "refId": "A" + } + ], + "title": "unscribe", + "type": "timeseries" + }, + { + "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "exemplar": true, + "expr": "rate(smqtt_disconnect_event_count_total{instance=\"$instance\"}[1m])", + "interval": "", + "legendFormat": "disconnect", + "refId": "A" + } + ], + "title": "disconnect", + "type": "timeseries" + } + ], + "refresh": "5s", + "schemaVersion": 31, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": false, + "text": "192.168.124.62:60000", + "value": "192.168.124.62:60000" + }, + "datasource": "Prometheus", + "definition": "", + "description": null, + "error": null, + "hide": 0, + "includeAll": false, + "label": "instance", + "multi": false, + "name": "instance", + "options": [], + "query": { + "query": "label_values(smqtt_connect_count, instance)", + "refId": "Prometheus-instance-Variable-Query" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "smqtt-application", + "uid": "EnxLlX57z", + "version": 5 +} \ No newline at end of file diff --git a/config/monitor/prometheus/smqtt-jvm-1638607233202.json b/config/monitor/prometheus/smqtt-jvm-1638607233202.json new file mode 100644 index 0000000000000000000000000000000000000000..101c1bd24e60b1931302eb221c94023f6b0569d1 --- /dev/null +++ b/config/monitor/prometheus/smqtt-jvm-1638607233202.json @@ -0,0 +1,2806 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "limit": 100, + "name": "Annotations & Alerts", + "showIn": 0, + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + }, + { + "datasource": "Prometheus", + "enable": true, + "expr": "resets(process_uptime_seconds{application=\"$application\", instance=\"$instance\"}[1m]) > 0", + "iconColor": "rgba(255, 96, 96, 1)", + "name": "Restart Detection", + "showIn": 0, + "step": "1m", + "tagKeys": "restart-tag", + "textFormat": "uptime reset", + "titleFormat": "Restart" + } + ] + }, + "description": "smqtt jvm", + "editable": true, + "fiscalYearStartMonth": 0, + "gnetId": 4701, + "graphTooltip": 1, + "id": 3, + "iteration": 1638607226416, + "links": [], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 125, + "panels": [], + "repeat": null, + "title": "Quick Facts", + "type": "row" + }, + { + "cacheTimeout": null, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 2, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 70 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 90 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 1 + }, + "id": 65, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.2.0", + "targets": [ + { + "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"heap\"})*100/sum(jvm_memory_max_bytes{application=\"$application\",instance=\"$instance\", area=\"heap\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 14400 + } + ], + "title": "Heap used", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 2, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + }, + { + "options": { + "from": -1e+32, + "result": { + "text": "N/A" + }, + "to": 0 + }, + "type": "range" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 70 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 90 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 1 + }, + "id": 75, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.2.0", + "targets": [ + { + "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"nonheap\"})*100/sum(jvm_memory_max_bytes{application=\"$application\",instance=\"$instance\", area=\"nonheap\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 14400 + } + ], + "title": "Non-Heap used", + "type": "stat" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 4 + }, + "id": 126, + "panels": [], + "repeat": null, + "title": "JVM Memory", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 5 + }, + "hiddenSeries": false, + "id": 24, + "legend": { + "avg": false, + "current": true, + "max": true, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"heap\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "used", + "metric": "", + "refId": "A", + "step": 2400 + }, + { + "expr": "sum(jvm_memory_committed_bytes{application=\"$application\", instance=\"$instance\", area=\"heap\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "committed", + "refId": "B", + "step": 2400 + }, + { + "expr": "sum(jvm_memory_max_bytes{application=\"$application\", instance=\"$instance\", area=\"heap\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "max", + "refId": "C", + "step": 2400 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "JVM Heap", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "y-axis": true, + "y_formats": [ + "mbytes", + "short" + ], + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 5 + }, + "hiddenSeries": false, + "id": 25, + "legend": { + "avg": false, + "current": true, + "max": true, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"nonheap\"})", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "used", + "metric": "", + "refId": "A", + "step": 2400 + }, + { + "expr": "sum(jvm_memory_committed_bytes{application=\"$application\", instance=\"$instance\", area=\"nonheap\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "committed", + "refId": "B", + "step": 2400 + }, + { + "expr": "sum(jvm_memory_max_bytes{application=\"$application\", instance=\"$instance\", area=\"nonheap\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "max", + "refId": "C", + "step": 2400 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "JVM Non-Heap", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "y-axis": true, + "y_formats": [ + "mbytes", + "short" + ], + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 5 + }, + "hiddenSeries": false, + "id": 26, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "used", + "metric": "", + "refId": "A", + "step": 2400 + }, + { + "expr": "sum(jvm_memory_committed_bytes{application=\"$application\", instance=\"$instance\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "committed", + "refId": "B", + "step": 2400 + }, + { + "expr": "sum(jvm_memory_max_bytes{application=\"$application\", instance=\"$instance\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "max", + "refId": "C", + "step": 2400 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "JVM Total", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "y-axis": true, + "y_formats": [ + "mbytes", + "short" + ], + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 5 + }, + "hiddenSeries": false, + "id": 86, + "legend": { + "avg": false, + "current": true, + "max": true, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_memory_vss_bytes{application=\"$application\", instance=\"$instance\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "vss", + "metric": "", + "refId": "A", + "step": 2400 + }, + { + "expr": "process_memory_rss_bytes{application=\"$application\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "rss", + "refId": "B" + }, + { + "expr": "process_memory_swap_bytes{application=\"$application\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "swap", + "refId": "C" + }, + { + "expr": "process_memory_rss_bytes{application=\"$application\", instance=\"$instance\"} + process_memory_swap_bytes{application=\"$application\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "total", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "JVM Process Memory", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "y-axis": true, + "y_formats": [ + "mbytes", + "short" + ], + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 12 + }, + "id": 127, + "panels": [], + "repeat": null, + "title": "JVM Misc", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 13 + }, + "hiddenSeries": false, + "id": 106, + "legend": { + "avg": false, + "current": true, + "max": true, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "system_cpu_usage{application=\"$application\", instance=\"$instance\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "system", + "metric": "", + "refId": "A", + "step": 2400 + }, + { + "expr": "process_cpu_usage{application=\"$application\", instance=\"$instance\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "process", + "refId": "B" + }, + { + "expr": "avg_over_time(process_cpu_usage{application=\"$application\", instance=\"$instance\"}[1h])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "process-1h", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU Usage", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "y-axis": true, + "y_formats": [ + "short", + "short" + ], + "yaxes": [ + { + "decimals": 1, + "format": "percentunit", + "label": "", + "logBase": 1, + "max": "1", + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 13 + }, + "hiddenSeries": false, + "id": 93, + "legend": { + "avg": false, + "current": true, + "max": true, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "system_load_average_1m{application=\"$application\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "system-1m", + "metric": "", + "refId": "A", + "step": 2400 + }, + { + "expr": "system_cpu_count{application=\"$application\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "cpus", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Load", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "y-axis": true, + "y_formats": [ + "short", + "short" + ], + "yaxes": [ + { + "decimals": 1, + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 13 + }, + "hiddenSeries": false, + "id": 32, + "legend": { + "avg": false, + "current": true, + "max": true, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "jvm_threads_live_threads{application=\"$application\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "live", + "metric": "", + "refId": "A", + "step": 2400 + }, + { + "expr": "jvm_threads_daemon_threads{application=\"$application\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "daemon", + "metric": "", + "refId": "B", + "step": 2400 + }, + { + "expr": "jvm_threads_peak_threads{application=\"$application\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "peak", + "refId": "C", + "step": 2400 + }, + { + "expr": "process_threads{application=\"$application\", instance=\"$instance\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "process", + "refId": "D", + "step": 2400 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Threads", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "y-axis": true, + "y_formats": [ + "short", + "short" + ], + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "blocked": "#bf1b00", + "new": "#fce2de", + "runnable": "#7eb26d", + "terminated": "#511749", + "timed-waiting": "#c15c17", + "waiting": "#eab839" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 13 + }, + "hiddenSeries": false, + "id": 124, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "jvm_threads_states_threads{application=\"$application\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{state}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Thread States", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 128, + "panels": [], + "repeat": "persistence_counts", + "title": "JVM Memory Pools (Heap)", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 21 + }, + "hiddenSeries": false, + "id": 3, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "maxPerRow": 3, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": "jvm_memory_pool_heap", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", id=~\"$jvm_memory_pool_heap\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "used", + "metric": "", + "refId": "A", + "step": 1800 + }, + { + "expr": "jvm_memory_committed_bytes{application=\"$application\", instance=\"$instance\", id=~\"$jvm_memory_pool_heap\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "commited", + "metric": "", + "refId": "B", + "step": 1800 + }, + { + "expr": "jvm_memory_max_bytes{application=\"$application\", instance=\"$instance\", id=~\"$jvm_memory_pool_heap\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "max", + "metric": "", + "refId": "C", + "step": 1800 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "$jvm_memory_pool_heap", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "y-axis": true, + "y_formats": [ + "mbytes", + "short" + ], + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 28 + }, + "id": 129, + "panels": [], + "repeat": null, + "title": "JVM Memory Pools (Non-Heap)", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "editable": true, + "error": false, + "fill": 1, + "fillGradient": 0, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 29 + }, + "hiddenSeries": false, + "id": 78, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "maxPerRow": 3, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": "jvm_memory_pool_nonheap", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", id=~\"$jvm_memory_pool_nonheap\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "used", + "metric": "", + "refId": "A", + "step": 1800 + }, + { + "expr": "jvm_memory_committed_bytes{application=\"$application\", instance=\"$instance\", id=~\"$jvm_memory_pool_nonheap\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "commited", + "metric": "", + "refId": "B", + "step": 1800 + }, + { + "expr": "jvm_memory_max_bytes{application=\"$application\", instance=\"$instance\", id=~\"$jvm_memory_pool_nonheap\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "max", + "metric": "", + "refId": "C", + "step": 1800 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "$jvm_memory_pool_nonheap", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "y-axis": true, + "y_formats": [ + "mbytes", + "short" + ], + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 36 + }, + "id": 130, + "panels": [], + "repeat": null, + "title": "Garbage Collection", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 37 + }, + "hiddenSeries": false, + "id": 98, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(jvm_gc_pause_seconds_count{application=\"$application\", instance=\"$instance\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{action}} ({{cause}})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Collections", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 37 + }, + "hiddenSeries": false, + "id": 101, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(jvm_gc_pause_seconds_sum{application=\"$application\", instance=\"$instance\"}[1m])/rate(jvm_gc_pause_seconds_count{application=\"$application\", instance=\"$instance\"}[1m])", + "format": "time_series", + "hide": false, + "instant": false, + "intervalFactor": 1, + "legendFormat": "avg {{action}} ({{cause}})", + "refId": "A" + }, + { + "expr": "jvm_gc_pause_seconds_max{application=\"$application\", instance=\"$instance\"}", + "format": "time_series", + "hide": false, + "instant": false, + "intervalFactor": 1, + "legendFormat": "max {{action}} ({{cause}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pause Durations", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 37 + }, + "hiddenSeries": false, + "id": 99, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(jvm_gc_memory_allocated_bytes_total{application=\"$application\", instance=\"$instance\"}[1m])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "allocated", + "refId": "A" + }, + { + "expr": "rate(jvm_gc_memory_promoted_bytes_total{application=\"$application\", instance=\"$instance\"}[1m])", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "promoted", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Allocated/Promoted", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 44 + }, + "id": 131, + "panels": [], + "repeat": null, + "title": "Classloading", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "editable": true, + "error": false, + "fill": 1, + "fillGradient": 0, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 45 + }, + "hiddenSeries": false, + "id": 37, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "jvm_classes_loaded_classes{application=\"$application\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "loaded", + "metric": "", + "refId": "A", + "step": 1200 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Classes loaded", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "y-axis": true, + "y_formats": [ + "short", + "short" + ], + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "editable": true, + "error": false, + "fill": 1, + "fillGradient": 0, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 45 + }, + "hiddenSeries": false, + "id": 38, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "delta(jvm_classes_loaded_classes{application=\"$application\",instance=\"$instance\"}[1m])", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "delta-1m", + "metric": "", + "refId": "A", + "step": 1200 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Class delta", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "y-axis": true, + "y_formats": [ + "ops", + "short" + ], + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 52 + }, + "id": 132, + "panels": [], + "repeat": null, + "title": "Buffer Pools", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "editable": true, + "error": false, + "fill": 1, + "fillGradient": 0, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 53 + }, + "hiddenSeries": false, + "id": 33, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "jvm_buffer_memory_used_bytes{application=\"$application\", instance=\"$instance\", id=\"direct\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "used", + "metric": "", + "refId": "A", + "step": 2400 + }, + { + "expr": "jvm_buffer_total_capacity_bytes{application=\"$application\", instance=\"$instance\", id=\"direct\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "capacity", + "metric": "", + "refId": "B", + "step": 2400 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Direct Buffers", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "y-axis": true, + "y_formats": [ + "short", + "short" + ], + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "editable": true, + "error": false, + "fill": 1, + "fillGradient": 0, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 53 + }, + "hiddenSeries": false, + "id": 83, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "jvm_buffer_count_buffers{application=\"$application\", instance=\"$instance\", id=\"direct\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "count", + "metric": "", + "refId": "A", + "step": 2400 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Direct Buffers", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "y-axis": true, + "y_formats": [ + "short", + "short" + ], + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "editable": true, + "error": false, + "fill": 1, + "fillGradient": 0, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 53 + }, + "hiddenSeries": false, + "id": 85, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "jvm_buffer_memory_used_bytes{application=\"$application\", instance=\"$instance\", id=\"mapped\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "used", + "metric": "", + "refId": "A", + "step": 2400 + }, + { + "expr": "jvm_buffer_total_capacity_bytes{application=\"$application\", instance=\"$instance\", id=\"mapped\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "capacity", + "metric": "", + "refId": "B", + "step": 2400 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Mapped Buffers", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "y-axis": true, + "y_formats": [ + "short", + "short" + ], + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "editable": true, + "error": false, + "fill": 1, + "fillGradient": 0, + "grid": { + "leftLogBase": 1, + "leftMax": null, + "leftMin": null, + "rightLogBase": 1, + "rightMax": null, + "rightMin": null + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 53 + }, + "hiddenSeries": false, + "id": 84, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "jvm_buffer_count_buffers{application=\"$application\", instance=\"$instance\", id=\"mapped\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "count", + "metric": "", + "refId": "A", + "step": 2400 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Mapped Buffers", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "x-axis": true, + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "y-axis": true, + "y_formats": [ + "short", + "short" + ], + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "30s", + "schemaVersion": 31, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": false, + "text": "smqtt", + "value": "smqtt" + }, + "datasource": "Prometheus", + "definition": "", + "description": null, + "error": null, + "hide": 0, + "includeAll": false, + "label": "Application", + "multi": false, + "name": "application", + "options": [], + "query": { + "query": "label_values(application)", + "refId": "Prometheus-application-Variable-Query" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allFormat": "glob", + "allValue": null, + "current": { + "selected": false, + "text": "192.168.124.62:60000", + "value": "192.168.124.62:60000" + }, + "datasource": "Prometheus", + "definition": "", + "description": null, + "error": null, + "hide": 0, + "includeAll": false, + "label": "Instance", + "multi": false, + "multiFormat": "glob", + "name": "instance", + "options": [], + "query": { + "query": "label_values(jvm_memory_used_bytes{application=\"$application\"}, instance)", + "refId": "Prometheus-instance-Variable-Query" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allFormat": "glob", + "allValue": null, + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "definition": "", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "JVM Memory Pools Heap", + "multi": false, + "multiFormat": "glob", + "name": "jvm_memory_pool_heap", + "options": [], + "query": { + "query": "label_values(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"heap\"},id)", + "refId": "Prometheus-jvm_memory_pool_heap-Variable-Query" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allFormat": "glob", + "allValue": null, + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "definition": "", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "JVM Memory Pools Non-Heap", + "multi": false, + "multiFormat": "glob", + "name": "jvm_memory_pool_nonheap", + "options": [], + "query": { + "query": "label_values(jvm_memory_used_bytes{application=\"$application\", instance=\"$instance\", area=\"nonheap\"},id)", + "refId": "Prometheus-jvm_memory_pool_nonheap-Variable-Query" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 2, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-24h", + "to": "now" + }, + "timepicker": { + "now": true, + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "smqtt-jvm", + "uid": "3veYlXc7z", + "version": 2 +} \ No newline at end of file diff --git a/config/monitor/prometheus/smqtt-netty-1638607270130.json b/config/monitor/prometheus/smqtt-netty-1638607270130.json new file mode 100644 index 0000000000000000000000000000000000000000..7aab0a8cc37174bede0f94445645449a41f19a57 --- /dev/null +++ b/config/monitor/prometheus/smqtt-netty-1638607270130.json @@ -0,0 +1,687 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "gnetId": null, + "graphTooltip": 0, + "id": 1, + "iteration": 1638607265684, + "links": [], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 6, + "panels": [], + "title": "Tcp", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 12, + "x": 0, + "y": 1 + }, + "hiddenSeries": false, + "id": 1, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": false, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "sum(reactor_netty_tcp_server_data_received_bytes_count{instance=\"$instance\"})", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "reactor_netty_tcp_server_data_received_bytes_count", + "refId": "A" + }, + { + "exemplar": true, + "expr": "max(reactor_netty_tcp_server_data_received_bytes_max{instance=\"$instance\"})", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "reactor_netty_tcp_server_data_received_bytes_max", + "refId": "B" + }, + { + "exemplar": true, + "expr": "sum(reactor_netty_tcp_server_data_received_bytes_sum{instance=\"$instance\"})", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "reactor_netty_tcp_server_data_received_bytes_sum", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Tcp Received Bytes", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 12, + "x": 12, + "y": 1 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": false, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(reactor_netty_tcp_server_data_sent_bytes_count{instance=\"$instance\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "reactor_netty_tcp_server_data_sent_bytes_count", + "refId": "A" + }, + { + "expr": "sum(reactor_netty_tcp_server_data_sent_bytes_max{instance=\"$instance\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "reactor_netty_tcp_server_data_sent_bytes_max", + "refId": "B" + }, + { + "expr": "sum(reactor_netty_tcp_server_data_sent_bytes_sum{instance=\"$instance\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "reactor_netty_tcp_server_data_sent_bytes_sum", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Tcp Sent Bytes", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 12 + }, + "id": 7, + "panels": [], + "title": "Bytebuf监控", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 12, + "x": 0, + "y": 13 + }, + "hiddenSeries": false, + "id": 3, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": false, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "sum(reactor_netty_bytebuf_allocator_chunk_size{instance=\"$instance\"})", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "reactor_netty_bytebuf_allocator_chunk_size", + "refId": "A" + }, + { + "expr": "sum(reactor_netty_bytebuf_allocator_direct_arenas{instance=\"$instance\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "reactor_netty_bytebuf_allocator_direct_arenas", + "refId": "B" + }, + { + "exemplar": true, + "expr": "sum(reactor_netty_bytebuf_allocator_heap_arenas{instance=\"$instance\"})", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "reactor_netty_bytebuf_allocator_heap_arenas", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Bytebuf分配", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 12, + "x": 12, + "y": 13 + }, + "hiddenSeries": false, + "id": 5, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": false, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(reactor_netty_bytebuf_allocator_used_direct_memory{instance=\"$instance\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "reactor_netty_bytebuf_allocator_used_direct_memory", + "refId": "A" + }, + { + "expr": "sum(reactor_netty_bytebuf_allocator_used_heap_memory{instance=\"$instance\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "reactor_netty_bytebuf_allocator_used_heap_memory", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Bytebuf使用", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 12, + "x": 0, + "y": 24 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": false, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(reactor_netty_bytebuf_allocator_normal_cache_size{instance=\"$instance\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "reactor_netty_bytebuf_allocator_normal_cache_size", + "refId": "A" + }, + { + "expr": "sum(reactor_netty_bytebuf_allocator_small_cache_size{instance=\"$instance\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "reactor_netty_bytebuf_allocator_small_cache_size", + "refId": "B" + }, + { + "expr": "sum(reactor_netty_bytebuf_allocator_threadlocal_caches{instance=\"$instance\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "reactor_netty_bytebuf_allocator_threadlocal_caches", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Bytebuf缓存", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "", + "schemaVersion": 31, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": false, + "text": "192.168.124.62:60000", + "value": "192.168.124.62:60000" + }, + "datasource": "Prometheus", + "definition": "", + "description": null, + "error": null, + "hide": 0, + "includeAll": false, + "label": "instance", + "multi": false, + "name": "instance", + "options": [], + "query": { + "query": "label_values(reactor_netty_bytebuf_allocator_heap_arenas, instance)", + "refId": "Prometheus-instance-Variable-Query" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "smqtt-netty", + "uid": "rIDE_Xc7z", + "version": 10 +} \ No newline at end of file diff --git a/docs/.debug.yml b/docs/.debug.yml deleted file mode 100644 index 05d534a00755a7d5259372c61cf977285bee4453..0000000000000000000000000000000000000000 --- a/docs/.debug.yml +++ /dev/null @@ -1,3 +0,0 @@ -remote_theme: false - -theme: jekyll-rtd-theme \ No newline at end of file diff --git a/docs/CNAME b/docs/CNAME deleted file mode 100644 index 02bb93e5bbecbb398201a259315b316519b5eed5..0000000000000000000000000000000000000000 --- a/docs/CNAME +++ /dev/null @@ -1 +0,0 @@ -doc.smqtt.cc \ No newline at end of file diff --git a/docs/Gemfile b/docs/Gemfile deleted file mode 100644 index ccd8f63fd63d3ece0b07d593df6ab699c7d3cf72..0000000000000000000000000000000000000000 --- a/docs/Gemfile +++ /dev/null @@ -1,4 +0,0 @@ -source "https://gems.ruby-china.com" -gem "jekyll-rtd-theme" - -gem "github-pages", group: :jekyll_plugins \ No newline at end of file diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index db29e5ad3fb29fd4feedeb6b24968e5b0845bbcc..0000000000000000000000000000000000000000 --- a/docs/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -DEBUG=JEKYLL_GITHUB_TOKEN=blank PAGES_API_URL=http://0.0.0.0 - -default: - @gem install jekyll bundler && bundle install - -update: - @bundle update - -clean: - @bundle exec jekyll clean - -build: clean - @${DEBUG} bundle exec jekyll build --profile --config _config.yml,.debug.yml - -server: clean - @${DEBUG} bundle exec jekyll server --livereload --config _config.yml,.debug.yml \ No newline at end of file diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index b15a895185b5aa8a7cbea180de3b559bee2ac5de..0000000000000000000000000000000000000000 --- a/docs/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# SMQTT文档 - -SMQTT基于Netty开发,底层采用Reactor3反应堆模型,支持单机部署,支持容器化部署,具备低延迟,高吞吐量,支持百万TCP连接,同时支持多种协议交互,是一款非常优秀的消息中间件! -[项目地址](https://github.com/quickmsg/smqtt) - -## smqtt目前拥有的功能如下: - -1. 消息质量等级实现(支持qos0,qos1,qos2) -2. 会话消息 -3. 保留消息 -4. 遗嘱消息 -5. 客户端认证 -6. tls加密 -7. websocket协议支持 -8. http协议交互 -9. SPI接口扩展支持 - - 消息管理接口(会话消息/保留消息管理) - - 通道管理接口 (管理系统的客户端连接) - - 认证接口 (用于自定义外部认证) - - 拦截器 (用户自定义拦截消息) -10. 集群支持(gossip协议实现) -11. 容器化支持 - - -## 后面规划项目 - -- 规则引擎 -- Web管理系统 -- 监控系统 -- 协议桥接agent(用户其他协议与broker之间交互) - - - -## 麻烦关注下公众号! -![image](icon/icon.jpg) - -- 添加微信号`Lemon877164954`,拉入smqtt官方交流群 -- 加入qq群 `700152283` \ No newline at end of file diff --git a/docs/_config.yml b/docs/_config.yml deleted file mode 100644 index c5198849d2419513ecc931bc476d0de7cbd7d5dd..0000000000000000000000000000000000000000 --- a/docs/_config.yml +++ /dev/null @@ -1,14 +0,0 @@ -title: SMQTT文档 -lang: en -description: a catchy description for your project - -remote_theme: rundocs/jekyll-rtd-theme - -readme_index: - with_frontmatter: true - -exclude: - - Makefile - - CNAME - - Gemfile - - Gemfile.lock \ No newline at end of file diff --git a/docs/cluster/1.jar.md b/docs/cluster/1.jar.md deleted file mode 100644 index 1024f94f392d84d45bacd4658e0f9fb54c300c7f..0000000000000000000000000000000000000000 --- a/docs/cluster/1.jar.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -sort: 1 ---- - -# main启动配置 - -## 引入依赖 -```markdown - - io.github.quickmsg - smqtt-core - 1.0.5 - - - io.github.quickmsg - smqtt-registry-scube - 1.0.5 - -``` - -## 集群启动类 - -示例如下: - -1. cluster-node1 -``` - Bootstrap bootstrap = Bootstrap.builder() - .port(8555) - .websocketPort(8999) - .options(channelOptionMap -> {})//netty options设置 - .childOptions(channelOptionMap ->{}) //netty childOptions设置 - .highWaterMark(1000000) - .lowWaterMark(1000) - .ssl(false) - .sslContext(new SslContext("crt","key")) - .isWebsocket(true) - .wiretap(true) - .httpOptions(Bootstrap.HttpOptions.builder().ssl(false).httpPort(62212).accessLog(true).build()) - .clusterConfig( - ClusterConfig.builder() - .clustered(true) - .port(7773) - .nodeName("node-2") - .clusterUrl("127.0.0.1:7771,127.0.0.1:7772") - .build()) - .build() - .start().block(); -``` -2. cluster-node2 - -``` - Bootstrap bootstrap = Bootstrap.builder() - .port(8556) - .options(channelOptionMap -> {})//netty options设置 - .childOptions(channelOptionMap ->{}) //netty childOptions设置 - .highWaterMark(1000000) - .lowWaterMark(1000) - .ssl(false) - .wiretap(true) - .clusterConfig( - ClusterConfig.builder() - .clustered(true) - .port(7772) - .nodeName("node-3") - .clusterUrl("127.0.0.1:7771,127.0.0.1:7773") - .build()) - .build() - .start().block(); -``` -3. cluster-node3 - -``` - Bootstrap bootstrap = Bootstrap.builder() - .port(8551) - .options(channelOptionMap -> {})//netty options设置 - .childOptions(channelOptionMap ->{}) //netty childOptions设置 - .highWaterMark(1000000) - .lowWaterMark(1000) - .ssl(false) - .wiretap(true) - .clusterConfig( - ClusterConfig.builder() - .clustered(true) - .port(7771) - .nodeName("node-4") - .clusterUrl("127.0.0.1:7772,127.0.0.1:7773") - .build()) - .build() - .start().block(); -``` - -## 启动参数详解 - -ClusterConfig参数: - -| 参数 | 说明 | 必传 | -| ---- | ---- |---- | -| clustered | 开启集群 |是 | -| port | 集群通信端口 |是 | -| nodeName | 节点名称唯一 |是 | -| clusterUrl | 集群节点url |是| - diff --git a/docs/cluster/README.md b/docs/cluster/README.md deleted file mode 100644 index 348b31b4b0de090b995af891bdb9534fd0b8e876..0000000000000000000000000000000000000000 --- a/docs/cluster/README.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -sort: 5 ---- -# 集群文档 - -{% include list.liquid %} \ No newline at end of file diff --git a/docs/http/1.wd.md b/docs/http/1.wd.md deleted file mode 100644 index 40a27357bee353320b53c236a7353a50bcf035e0..0000000000000000000000000000000000000000 --- a/docs/http/1.wd.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -sort: 1 ---- - -# 启动http - -启动Broker时候开启Http服务: - -``` - Bootstrap bootstrap = Bootstrap.builder() - .httpOptions(Bootstrap.HttpOptions - .builder() - .ssl(false) - .sslContext(new SslContext("crt","key")) - .accessLog(true).build()) - .build() - .start().block(); -``` -Bootstrap.HttpOptions参数: - -| 参数 | 说明 | 必传 | -| ---- | ---- |---- | -| ssl | 开启ssl加密 |否 | -| sslContext | ssl证书配置,为空则使用系统生成 |否 | -| httpPort | http服务端口,为空则随机端口 |否 | -| accessLog | http日志开启 |否 | - -sslContext参数: - -| sslContext | 说明 | 必传 | -| ---- | ---- |---- | -| server.crt | CA认证后的证书文件 |是| -| server.key | 密钥文件 |是 | \ No newline at end of file diff --git a/docs/http/2.fs.md b/docs/http/2.fs.md deleted file mode 100644 index 632187e88d3727729ac5d6047b06f6569f4c58ca..0000000000000000000000000000000000000000 --- a/docs/http/2.fs.md +++ /dev/null @@ -1,189 +0,0 @@ ---- -sort: 2 ---- - -# http内置接口 - - - - -- ##推送消息接口 - -> 系统内置了io.github.quickmsg.core.http.PublishActor接口,用于推送mqtt消息。使用方式如下: - -- 请求url /smqtt/publish -- 请求方式 POST -- 请求Body - -| 参数 | 说明 | 必传 | -| ---- | ---- |---- | -| topic | topiuc |是 | -| qos | 服务等级 |是 | -| retain | 保留消息 |是 | -| message | 消息 |是 | - -- 返回body -空 -- 返回状态码 -200 成功 - - -``` -curl -H "Content-Type: application/json" -X POST -d '{"topic": "test/teus", "qos":2, "retain":true, "message":"我来测试保留消息3" }' "http://localhost:1999/smqtt/publish" -``` - - -- ##获取当前连接 - -> 系统内置了io.github.quickmsg.core.http.ConnectionActor,用于获取当前连接。使用方式如下: - -- 请求url /smqtt/connection -- 请求方式 POST -- 请求Body - 无 -- 返回Body - -| 参数 | 说明 | 必传 | -| ---- | ---- |---- | -| connection | 连接 |是 | -| status | 状态 |是 | -| activeTime | 激活时间 |是 | -| authTime | 认证时间 |是 | -| sessionPersistent | session开启 |是 | -| will | 遗嘱消息 |是 | -| keepalive | 心跳时间 |是 | -| topics | 订阅topic |是 | - -```markdown -[ - { - "activeTime": 1624113398783, - "authTime": 1624113398805, - "clientIdentifier": "mqttx_20fe13251", - "connection": { - "disposed": false, - "inboundCancelled": false, - "inboundDisposed": false, - "persistent": true, - "subscriptionDisposed": false - }, - "keepalive": 60, - "sessionPersistent": true, - "status": "ONLINE", - "topics": [], - "will": { - "mqttQoS": "AT_MOST_ONCE", - "retain": false, - "willMessage": "YXNkbmJsa2hhc2Jk", - "willTopic": "test/close" - } - } -] - -``` -- 发送请求 - -``` -curl -H "Content-Type: application/json" -X POST "http://localhost:1999/smqtt/connection" -``` - - - -- ##获取当前集群信息 - -> 系统内置了io.github.quickmsg.core.http.actors.ClusterActor,用于获取当前连接。使用方式如下: - -- 请求url /smqtt/cluster -- 请求方式 POST -- 请求Body - 无 -- 返回Body - -| 参数 | 说明 | 必传 | -| ---- | ---- |---- | -| alias | node名称 |是 | -| host | 主机ip |是 | -| port | 端口 |是 | -| namespace | 命名空间 |是 | - -```markdown -[ - { - "alias": "node-4", - "host": "169.254.122.50", - "namespace": "default", - "port": 7771 - }, - { - "alias": "node-3", - "host": "169.254.122.50", - "namespace": "default", - "port": 7772 - }, - { - "alias": "node-2", - "host": "169.254.122.50", - "namespace": "default", - "port": 7773 - } -] -``` - - -- 发送请求 - -``` -curl -H "Content-Type: application/json" -X POST "http://localhost:1999/smqtt/cluster" -``` - -- ##获取当前订阅信息 - -> 系统内置了io.github.quickmsg.core.http.actors.SubscribeActor,用于获取当前连接。使用方式如下: - -- 请求url /smqtt/subscribe -- 请求方式 POST -- 请求Body - 无 -- 返回Body - -| 参数 | 说明 | 必传 | -| ---- | ---- |---- | -| activeTime | 激活時間 |是 | -| authTime | 认证时间 |是 | -| clientIdentifier | 客户端id |是 | -| keepalive | 心跳时间 |是 | -| sessionPersistent | 是否持久化 |是 | -| status | 在线状态 |是 | -| topics | 订阅topic |是 | - - -```markdown -{ - "test/+": [ - { - "activeTime": 1624110181885, - "authTime": 1624110181923, - "clientIdentifier": "client-id-3", - "connection": { - "disposed": false, - "inboundCancelled": false, - "inboundDisposed": false, - "persistent": true, - "subscriptionDisposed": false - }, - "keepalive": 20, - "sessionPersistent": true, - "status": "ONLINE", - "topics": [ - "test/+" - ] - } - ] -} -``` - -- 发送请求 - -``` -curl -H "Content-Type: application/json" -X POST "http://localhost:1999/smqtt/cluster" -``` \ No newline at end of file diff --git a/docs/http/3.fs.md b/docs/http/3.fs.md deleted file mode 100644 index 8705a5e93ea9086e696f0de62d6038fd3e4f1199..0000000000000000000000000000000000000000 --- a/docs/http/3.fs.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -sort: 3 ---- -# http扩展接口 - -## 注解使用 - -使用@Router(value = "/smqtt/publish", type = HttpType.POST) 定义URL跟请求方式 -## 自定义实现接口 - - 实现io.github.quickmsg.common.http.HttpActor - - 实现io.github.quickmsg.core.http.AbstractHttpActor(内置操作发送mqtt消息接口) - -下面给出实现demo: - -``` -@Router(value = "/smqtt/demo", type = HttpType.POST) -@Slf4j -public class DemoActor extends AbstractHttpActor { - - - @Override - public Publisher doRequest(HttpServerRequest request, HttpServerResponse response) { - return request - .receive() - .asString() - .map(this.toJson(HttpPublishMessage.class)) - .doOnNext(message -> { - //处理request - }).then(response.sendString(Mono.just("success")).then()); - } - -} -``` - -## SPI注入 -`具体参考java SPI注入` - -resources/WEB-INF/services 目录下新建 -名为io.github.quickmsg.common.http.HttpActor文件, -将自定义实现类全限定名写入文件中即可完成注入。 \ No newline at end of file diff --git a/docs/http/README.md b/docs/http/README.md deleted file mode 100644 index f4d464d503a430147ef7bd2724579f45953e3473..0000000000000000000000000000000000000000 --- a/docs/http/README.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -sort: 4 ---- -# http文档 - -{% include list.liquid %} \ No newline at end of file diff --git a/docs/icon/icon.jpg b/docs/icon/icon.jpg deleted file mode 100644 index cb2843461079c358042ebb0669a8c2f37a856df3..0000000000000000000000000000000000000000 Binary files a/docs/icon/icon.jpg and /dev/null differ diff --git a/docs/mqtt/1.auth.md b/docs/mqtt/1.auth.md deleted file mode 100644 index 092e9c7521573b74074c2b9dd37d506e39c95a4d..0000000000000000000000000000000000000000 --- a/docs/mqtt/1.auth.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -sort: 2 ---- - -# 连接鉴权 - -## 自定义认证类 - -实现PasswordAuthentication接口 - -- 请求参数 - -| 参数 | 说明 | 必传 | -| ---- | ---- |---- | -| username | 用户名 |是 | -| password | 密码 |是 | - - -- 返回参数 - - Boolean - - -## 启动类注入认证 - -``` - Bootstrap.builder() - .port(8555) - .websocketPort(8999) - .options(channelOptionMap -> {}) - .ssl(false) - .reactivePasswordAuth((U,P)->true) //认证注入方法 - .sslContext(new SslContext("crt","key")) - .isWebsocket(true) - .wiretap(false) - .httpOptions(Bootstrap.HttpOptions.builder().ssl(false).httpPort(62212).accessLog(true).build()) - .build() - .startAwait(); -``` - -## SPI注入 - -`具体参考java SPI注入` - -resources/WEB-INF/services 目录下新建 -名为io.github.quickmsg.common.auth.PasswordAuthentication文件, -将自定义实现类全限定名写入文件中即可完成注入。 - - - diff --git a/docs/mqtt/1.init.md b/docs/mqtt/1.init.md deleted file mode 100644 index 8c929039613939885885b73cc89b32bafde4ed4c..0000000000000000000000000000000000000000 --- a/docs/mqtt/1.init.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -sort: 1 ---- - -# 启动mqtt - -## 启动参数详解 - -``` - Bootstrap bootstrap = Bootstrap.builder() - .port(8555) - .websocketPort(8999) - .options(channelOptionMap -> {})//netty options设置 - .childOptions(channelOptionMap ->{}) //netty childOptions设置 - .highWaterMark(1000000) - .lowWaterMark(1000) - .ssl(false) - .sslContext(new SslContext("crt","key")) - .isWebsocket(true) - .wiretap(true) - .httpOptions(Bootstrap.HttpOptions.builder().ssl(false).httpPort(62212).accessLog(true).build()) - .clusterConfig( - ClusterConfig.builder() - .clustered(true) - .port(7773) - .nodeName("node-2") - .clusterUrl("127.0.0.1:7771,127.0.0.1:7772") - .build()) - .build() - .start().block(); -``` - -Bootstrap启动参数说明: - -| 参数 | 说明 | 必传 | -| ---- | ---- |---- | -| port | MQTT端口 |否 | -| options | netty options参数设置 |否 | -| childOptions | netty childOptions参数设置 |否 | -| highWaterMark | 高水位 |否 | -| lowWaterMark | 低水位 |否 | -| ssl | ssl开关 |否 | -| sslContext | ssl证书 |否| -| wiretap | 二进制日志 |否 -| isWebsocket | websocket开关 |否 -| websocketPort | websocket端口 |否 | -| httpOptions | http参数 (请参考Http配置文件)|否 | -| clusterConfig | 集群配置(请参考集群配置文件) |否 | - - diff --git a/docs/mqtt/README.md b/docs/mqtt/README.md deleted file mode 100644 index 910c3670214d3ac9797ff342d666df89ad66865d..0000000000000000000000000000000000000000 --- a/docs/mqtt/README.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -sort: 2 ---- -# mqtt文档 - -{% include list.liquid %} \ No newline at end of file diff --git a/docs/websocket/1.init.md b/docs/websocket/1.init.md deleted file mode 100644 index b71e0edacb69fd0886573d5e28b0be36717e3c9d..0000000000000000000000000000000000000000 --- a/docs/websocket/1.init.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -sort: 1 ---- - -# 启动webSocket - - -``` - Bootstrap bootstrap = Bootstrap.builder() - .websocketPort(8999) - .isWebsocket(true) - .build() - .start().block(); -``` \ No newline at end of file diff --git a/docs/websocket/README.md b/docs/websocket/README.md deleted file mode 100644 index f1ae0122a7832ce6e71579be33d98c84268cd4ee..0000000000000000000000000000000000000000 --- a/docs/websocket/README.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -sort: 3 ---- -# websocket文档 - -{% include list.liquid %} \ No newline at end of file diff --git "a/docs/\345\205\245\351\227\250/1.docker.md" "b/docs/\345\205\245\351\227\250/1.docker.md" deleted file mode 100644 index f6079332196c9b821bc8adf8d4011bb38356a03b..0000000000000000000000000000000000000000 --- "a/docs/\345\205\245\351\227\250/1.docker.md" +++ /dev/null @@ -1,43 +0,0 @@ ---- -sort: 3 ---- - -# Docker启动 - - -## 拉取镜像 - -``` -# 拉取docker镜像地址 -docker pull 1ssqq1lxr/smqtt:latest -``` - -## 使用环境变量启动 - -``` -docker run -it -e smqtt.tcp.port=1883 -e smqtt.http.enable=true -p 1883:1883 1ssqq1lxr/smqtt -``` - -## 使用配置文件启动 -- 准备配置文件conf.properties -- 启动服务 - - -``` -docker run -it -v <配置文件路径目录>:/conf -p <宿主机port>:<配置文件port> 1ssqq1lxr/smqtt -``` - -## 构建镜像推送到私有仓库 - -- 下载源码 -- 执行命令 - -``` -mvn clean package -Dmaven.test.skip=true -Djib.to.auth.username={仓库账户} -Djib.to.auth.password={仓库密码}-P docker - -``` - - - - - diff --git "a/docs/\345\205\245\351\227\250/1.jar.md" "b/docs/\345\205\245\351\227\250/1.jar.md" deleted file mode 100644 index e615a457151cde72bb756db9cc8a4befc8731b5c..0000000000000000000000000000000000000000 --- "a/docs/\345\205\245\351\227\250/1.jar.md" +++ /dev/null @@ -1,67 +0,0 @@ ---- -sort: 2 ---- - -# jar启动 - - -## 下载源码 - -```markdown - mvn compile package -Dmaven.test.skip=true -P jar -``` - -在smqtt-bootstrap/target目录下生成jar - -## 使用配置文件 config.properties - -```markdown - - # 开启tcp端口 - smqtt.tcp.port=1883 - # 高水位 - smqtt.tcp.lowWaterMark=4000000 - # 低水位 - smqtt.tcp.highWaterMark=80000000 - # 开启ssl加密 - smqtt.tcp.ssl=false - # 证书crt smqtt.tcp.ssl.crt = - # 证书key smqtt.tcp.ssl.key = - # 开启日志 - smqtt.tcp.wiretap=false - # boss线程 - smqtt.tcp.bossThreadSize=4 - # work线程 - smqtt.tcp.workThreadSize=8 - # websocket端口 - smqtt.websocket.port=8999 - # websocket开启 - smqtt.websocket.enable=true - # smqtt用户 - smqtt.tcp.username=smqtt - # smqtt密码 - smqtt.tcp.password=smqtt - # 开启http - smqtt.http.enable=true - # 开启http端口 - smqtt.http.port=1999 - # 开启http日志 - smqtt.http.accesslog=true - # 开启ssl - smqtt.http.ssl.enable=false - # smqtt.http.ssl.crt = - # smqtt.http.ssl.key= - ``` - -## 不使用配置文件 -使用jvm启动参数: - -```markdown - java -jar -Dsmqtt.tcp.port=1883 -Dsmqtt.http.enable=true smqtt-bootstrap-1.0.5.jar -``` -## 启动服务 - -```markdown - java -jar smqtt-bootstrap-1.0.1-SNAPSHOT.jar -``` - diff --git "a/docs/\345\205\245\351\227\250/1.main.md" "b/docs/\345\205\245\351\227\250/1.main.md" deleted file mode 100644 index 8bd6a01c38641e504929621c0f3a1db2db5cfc97..0000000000000000000000000000000000000000 --- "a/docs/\345\205\245\351\227\250/1.main.md" +++ /dev/null @@ -1,55 +0,0 @@ ---- -sort: 1 ---- - -# main方式启动 - - -## 引入依赖 -```markdown - - io.github.quickmsg - smqtt-core - 1.0.5 - -``` - -## 阻塞式启动服务: - -```markdown - - Bootstrap.builder() - .port(8555) - .websocketPort(8999) - .options(channelOptionMap -> {}) - .ssl(false) - .sslContext(new SslContext("crt","key")) - .isWebsocket(true) - .wiretap(false) - .httpOptions(Bootstrap.HttpOptions.builder().ssl(false).httpPort(62212).accessLog(true).build()) - .build() - .startAwait(); -``` - -## 非阻塞式启动服务: - - ```markdown - - Bootstrap bootstrap = - Bootstrap.builder() - .port(8555) - .websocketPort(8999) - .options(channelOptionMap -> {}) - .ssl(false) - .sslContext(new SslContext("crt","key")) - .isWebsocket(true) - .wiretap(false) - .httpOptions(Bootstrap.HttpOptions.builder().ssl(false).httpPort(62212).accessLog(true).build()) - .build() - .start().block(); - -assert bootstrap != null; - // 关闭服务 - bootstrap.shutdown(); - -``` \ No newline at end of file diff --git "a/docs/\345\205\245\351\227\250/README.md" "b/docs/\345\205\245\351\227\250/README.md" deleted file mode 100644 index 136cb36a2d5254ea945f67029eff3f5d9a27b6ff..0000000000000000000000000000000000000000 --- "a/docs/\345\205\245\351\227\250/README.md" +++ /dev/null @@ -1,6 +0,0 @@ ---- -sort: 1 ---- -# 启动 - -{% include list.liquid %} \ No newline at end of file diff --git "a/docs/\345\205\266\344\273\226/1.interceptor.md" "b/docs/\345\205\266\344\273\226/1.interceptor.md" deleted file mode 100644 index 0dc104e360bf9cb6a99095a42e8514b81adadebc..0000000000000000000000000000000000000000 --- "a/docs/\345\205\266\344\273\226/1.interceptor.md" +++ /dev/null @@ -1,81 +0,0 @@ ---- -sort: 1 ---- - -# 拦截器 - - -## Interceptor接口详解 - -- io.github.quickmsg.common.interceptor.Interceptor - -| 方法 | 说明 | 必传 | -| ---- | ---- |---- | -| Object doInterceptor(Invocation invocation) | 拦截方法 |是 | -| int order() | 拦截排序 |是 | - - - -- Invocation 属性说明 - -| 参数 | 说明 | 必传 | -| ---- | ---- |---- | -| method | 请求的 MqttChannel |是 | -| target | 请求的 MqttMessage |是 | -| args | 请求的ReceiveContext |是 | - -- 方法 - -| 方法 | 说明 | -| ---- | ---- | -| public Object proceed() | 放行拦截器| - - -## 自定义拦截器 - -- 实现接口 - -```markdown - -public class DemoInterceptor implements Interceptor { - - - @Override - public Object intercept(Invocation invocation) { - try { - Method method = invocation.getMethod(); - Object[] args = invocation.getArgs(); - Object target = invocation.getTarget(); -// MqttChannel mqttChannel, MqttMessage mqttMessage, ReceiveContext receiveContext - - MqttChannel mqttChannel = (MqttChannel) args[0]; // channel - MqttMessage mqttMessage = (MqttMessage) args[1]; // MqttMessage - ReceiveContext receiveContext = (ReceiveContext) args[2]; // ReceiveContext - - // 拦截业务 - - return invocation.proceed(); // 放行 - } catch (InvocationTargetException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - return null; - } - - @Override - public int sort() { - return 0; - } -} - -``` - - -- SPI注入 - -`具体参考java SPI注入` - -resources/WEB-INF/services 目录下新建 -名为io.github.quickmsg.common.interceptor.Interceptor文件, -将自定义实现类全限定名写入文件中即可完成注入。 diff --git "a/docs/\345\205\266\344\273\226/1.store.md" "b/docs/\345\205\266\344\273\226/1.store.md" deleted file mode 100644 index 065b4dd361b70a07ee5e195a031aa60ac303a12a..0000000000000000000000000000000000000000 --- "a/docs/\345\205\266\344\273\226/1.store.md" +++ /dev/null @@ -1,123 +0,0 @@ ---- -sort: 2 ---- - -# 数据持久化 - -## 持久化接口 - -- 接口:`io.github.quickmsg.common.message.MessageRegistry` - -> 主要提供 session消息 && 保留消息的持久化 - -| 方法 | 说明 | -| ---- | ---- | -| List getSessionMessages(String clientIdentifier) | 获取连接下线后的session消息 | -| void saveSessionMessages(SessionMessage sessionMessage) | 保存连接下线后的session消息 | -| void saveRetainMessage(RetainMessage retainMessage) | 保留Topic保留消息| -| List getRetainMessage(String topic)| 获取Topic保留消息 | - - -### 使用数据库去存储session/保留消息 - -- 引入DB依赖 -```markdown - - io.github.quickmsg - smqtt-persistent-db - 1.0.5 - -``` -- 引入驱动依赖 -> 根据版本引入 mysql/pg/oracle等驱动依赖 -```markdown -   - - mysql - mysql-connector-java - 5.1.35 - -``` - -- 服务启动时config.properties 添加 配置参数 - -```markdown -# 数据库配置 -db.driverClassName=com.mysql.jdbc.Driver -db.url=jdbc:mysql://127.0.0.1:3306/smqtt?characterEncoding=utf-8&useSSL=false&useInformationSchema=true&serverTimezone=UTC -db.username=root -db.password=123 -# 连接池初始化连接数 -db.initialSize=10 -# 连接池中最多支持多少个活动会话 -db.maxActive=300 -# 向连接池中请求连接时,超过maxWait的值后,认为本次请求失败 -db.maxWait=60000 -# 回收空闲连接时,将保证至少有minIdle个连接 -db.minIdle=2 - -``` - -- 启动服务后会自动生成session表跟retain表 - -### 使用Redis去存储session/保留消息 - -* 引入依赖 - -```markdown - - io.github.quickmsg - smqtt-persistent-redis - 1.0.5 - -``` - -* config.properties 配置参数 - -```markdown -# redis配置 -# 单机模式:single 哨兵模式:sentinel 集群模式:cluster -redis.mode=single -# 数据库 -redis.database=0 -# 密码 -redis.password= -# 超时时间 -redis.timeout=3000 -# 最小空闲数 -redis.pool.min.idle=8 -# 连接超时时间(毫秒) -redis.pool.conn.timeout=3000 -# 连接池大小 -redis.pool.size=10 - -# 单机配置 -redis.single.address=127.0.0.1:6379 - -# 集群配置 -# 集群扫描间隔时间(毫秒) -redis.cluster.scan.interval=1000 -# 节点 -redis.cluster.nodes=127.0.0.1:7000,127.0.0.1:7001,127.0.0.1:7002,127.0.0.1:7003,127.0.0.1:7004,127.0.0.1:7005 -# 读取操作的负载均衡模式 -redis.cluster.read.mode=SLAVE -# 命令失败重试次数 -redis.cluster.retry.attempts=3 -# 从节点连接池大小 -redis.cluster.slave.connection.pool.size=64 -# 主节点最小空闲连接数 -redis.cluster.master.connection.pool.size=64 -# 命令重试发送时间间隔(毫秒) -redis.cluster.retry.interval=1500 - -# 哨兵配置 -# master名称 -redis.sentinel.master=mymaster -# 节点 -redis.sentinel.nodes=127.0.0.1:26379,127.0.0.1:26379,127.0.0.1:26379 -``` - -### 自定义实现持久化 -resources/WEB-INF/services 目录下新建 -名为`io.github.quickmsg.common.message.MessageRegistry`文件, -将自定义实现类全限定名写入文件中即可完成注入。 diff --git "a/docs/\345\205\266\344\273\226/README.md" "b/docs/\345\205\266\344\273\226/README.md" deleted file mode 100644 index 65e19d36e52ff79f1c02c353c021ad68a2094be6..0000000000000000000000000000000000000000 --- "a/docs/\345\205\266\344\273\226/README.md" +++ /dev/null @@ -1,6 +0,0 @@ ---- -sort: 6 ---- -# 其他 - -{% include list.liquid %} \ No newline at end of file diff --git a/icon/admin.png b/icon/admin.png new file mode 100644 index 0000000000000000000000000000000000000000..0705398e206068530b942c909239a99920b08413 Binary files /dev/null and b/icon/admin.png differ diff --git a/icon/application.png b/icon/application.png new file mode 100644 index 0000000000000000000000000000000000000000..5b12aebcc7cd2a46bff85b49ef1021ac910b6dfc Binary files /dev/null and b/icon/application.png differ diff --git a/icon/component.png b/icon/component.png index 95c59e2abdbdee7d0d32a0d6bb6dcee478528798..0c005f7d013701a6d4bcd82c6d802f75e38b27da 100644 Binary files a/icon/component.png and b/icon/component.png differ diff --git a/icon/jvm.png b/icon/jvm.png new file mode 100644 index 0000000000000000000000000000000000000000..afdf14df56dcd5a30d6f4b2cc7fd3818ceb44bfb Binary files /dev/null and b/icon/jvm.png differ diff --git a/icon/logo.png b/icon/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..fccf31bebe01f420d75bfba0119c235483c2000f Binary files /dev/null and b/icon/logo.png differ diff --git a/icon/netty.png b/icon/netty.png new file mode 100644 index 0000000000000000000000000000000000000000..2ea49d94b1b5d007af1c6076db5a4ec7d1e2bd17 Binary files /dev/null and b/icon/netty.png differ diff --git a/icon/smqtt.jpg b/icon/smqtt.jpg deleted file mode 100644 index be402efe3990b837c0180fda361ad63a718247da..0000000000000000000000000000000000000000 Binary files a/icon/smqtt.jpg and /dev/null differ diff --git a/icon/smqtt.png b/icon/smqtt.png deleted file mode 100644 index 068d3dab8598584e4a35755262ed54fb9655336b..0000000000000000000000000000000000000000 Binary files a/icon/smqtt.png and /dev/null differ diff --git a/pom.xml b/pom.xml index f091eff2ea1b668b5834955a492938ea758bbf1a..cb2e46ad8ce4c19a49a0cd9e64593948f3b10df5 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 io.github.quickmsg smqtt - 1.0.5 + 1.1.7 smqtt-common smqtt-core @@ -14,6 +14,8 @@ smqtt-persistent smqtt-rule smqtt-ui + smqtt-metric + smqtt-spring-boot-starter pom @@ -25,11 +27,12 @@ UTF-8 1.8 1.8 - 1.0.5 - 1.18.6 - 2020.0.6 + 1.18.20 + 2020.0.10 1.7.30 2.11.0 + 2.12.4 + 2.12.4 @@ -55,8 +58,24 @@ + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + ${jackson.dataform.version} + + + + com.fasterxml.jackson.dataformat + jackson-dataformat-properties + ${jackson.dataform.version} + + + + com.fasterxml.jackson.core + jackson-core + ${jackson.core.version} + - com.fasterxml.jackson jackson-bom @@ -79,12 +98,7 @@ io.netty netty-codec-mqtt - 4.1.60.Final - - - com.alibaba - fastjson - 1.2.70 + 4.1.66.Final org.projectlombok @@ -107,17 +121,56 @@ logback-classic 1.1.11 + + io.micrometer + micrometer-core + 1.8.0 + + + com.github.oshi + oshi-core + 5.3.6 + + + io.micrometer + micrometer-registry-prometheus + 1.8.0 + + + io.micrometer + micrometer-registry-influx + 1.8.0 + + + + org.casbin + jcasbin + 1.22.1 + + + + org.casbin + jdbc-adapter + 2.1.3 + + + + mysql + mysql-connector-java + 5.1.35 + + + release - true + false - org.sonatype.plugins @@ -176,7 +229,6 @@ - diff --git a/smqtt-bootstrap/pom.xml b/smqtt-bootstrap/pom.xml index b52179e0f82cf32a85299763dd3b3cb149bc3a70..e3fd05673e5ae737a3ad1837113156aebbfa0db8 100644 --- a/smqtt-bootstrap/pom.xml +++ b/smqtt-bootstrap/pom.xml @@ -7,10 +7,10 @@ smqtt io.github.quickmsg - 1.0.5 + 1.1.7 smqtt-bootstrap - 1.0.5 + 1.1.7 smqtt-bootstrap http://www.example.com @@ -21,6 +21,21 @@ + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + + + + com.fasterxml.jackson.core + jackson-core + + + + com.fasterxml.jackson.dataformat + jackson-dataformat-properties + junit junit @@ -30,17 +45,22 @@ io.github.quickmsg smqtt-core - 1.0.5 + 1.1.7 smqtt-registry-scube io.github.quickmsg - 1.0.5 + 1.1.7 smqtt-ui io.github.quickmsg - 1.0.5 + 1.1.7 + + + + mysql + mysql-connector-java @@ -100,19 +120,24 @@ latest ${project.version} + + ${REGISTRY_USERNAME} + ${REGISTRY_PASSWORD} + + io.github.quickmsg.docker.DockerStarter - - - - + + + + - - - + + + USE_CURRENT_TIMESTAMP diff --git a/smqtt-bootstrap/src/main/java/io/github/quickmsg/AbstractStarter.java b/smqtt-bootstrap/src/main/java/io/github/quickmsg/AbstractStarter.java index b5611d8dc03ecb06f079251e0f0acb228c99638c..5c95e352dd87252e618fc8a851c8493820b41057 100644 --- a/smqtt-bootstrap/src/main/java/io/github/quickmsg/AbstractStarter.java +++ b/smqtt-bootstrap/src/main/java/io/github/quickmsg/AbstractStarter.java @@ -1,20 +1,17 @@ package io.github.quickmsg; import ch.qos.logback.classic.Level; -import io.github.quickmsg.common.bootstrap.BootstrapKey; -import io.github.quickmsg.common.cluster.ClusterConfig; -import io.github.quickmsg.common.config.SslContext; -import io.github.quickmsg.common.environment.EnvContext; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.javaprop.JavaPropsFactory; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import io.github.quickmsg.common.config.BootstrapConfig; +import io.github.quickmsg.common.utils.FileExtension; import io.github.quickmsg.common.utils.IPUtils; -import io.github.quickmsg.common.utils.LoggerLevel; -import io.github.quickmsg.common.utils.PropertiesLoader; import io.github.quickmsg.core.Bootstrap; -import io.netty.channel.WriteBufferWaterMark; +import io.github.quickmsg.exception.NotSupportConfigException; import lombok.extern.slf4j.Slf4j; -import java.util.Optional; -import java.util.UUID; -import java.util.function.Function; +import java.io.File; /** * @author luxurong @@ -22,162 +19,65 @@ import java.util.function.Function; @Slf4j public abstract class AbstractStarter { - private static final String DEFAULT_PROPERTIES_LOAD_CONFIG_PATH = "/conf/config.properties"; - private static final Integer DEFAULT_MQTT_PORT = 1883; - - private static final Integer DEFAULT_WEBSOCKET_MQTT_PORT = 8999; - - private static final Integer DEFAULT_CLUSTER_PORT = 4333; - - - private static final Integer DEFAULT_HTTP_PORT = 12000; - - - private static final String DEFAULT_AUTH_USERNAME_PASSWORD = "smqtt"; - - public static void start(Function function) { - start(function, null); - } - - - public static void start(Function function, String path) { - path = path == null ? DEFAULT_PROPERTIES_LOAD_CONFIG_PATH : path; - EnvContext params = PropertiesLoader.loadProperties(path); - - Integer port = Optional.ofNullable(params.obtainKeyOrDefault(BootstrapKey.BOOTSTRAP_PORT, function.apply(BootstrapKey.BOOTSTRAP_PORT))) - .map(Integer::parseInt).orElse(DEFAULT_MQTT_PORT); - - Integer lowWaterMark = Optional.ofNullable(params.obtainKeyOrDefault(BootstrapKey.BOOTSTRAP_LOW_WATERMARK, function.apply(BootstrapKey.BOOTSTRAP_LOW_WATERMARK))) - .map(Integer::parseInt).orElse(WriteBufferWaterMark.DEFAULT.low()); - - Integer highWaterMark = Optional.ofNullable(params.obtainKeyOrDefault(BootstrapKey.BOOTSTRAP_HIGH_WATERMARK, function.apply(BootstrapKey.BOOTSTRAP_HIGH_WATERMARK))) - .map(Integer::parseInt).orElse(WriteBufferWaterMark.DEFAULT.high()); - - Boolean wiretap = Optional.ofNullable(params.obtainKeyOrDefault(BootstrapKey.BOOTSTRAP_WIRETAP, function.apply(BootstrapKey.BOOTSTRAP_WIRETAP))) - .map(Boolean::parseBoolean).orElse(false); - - Integer bossThreadSize = Optional.ofNullable(params.obtainKeyOrDefault(BootstrapKey.BOOTSTRAP_BOSS_THREAD_SIZE, function.apply(BootstrapKey.BOOTSTRAP_BOSS_THREAD_SIZE))) - .map(Integer::parseInt).orElse(Runtime.getRuntime().availableProcessors() >> 1); - - Integer workThreadSize = Optional.ofNullable(params.obtainKeyOrDefault(BootstrapKey.BOOTSTRAP_WORK_THREAD_SIZE, function.apply(BootstrapKey.BOOTSTRAP_WORK_THREAD_SIZE))) - .map(Integer::parseInt).orElse(Runtime.getRuntime().availableProcessors()); - - Boolean isWebsocket = Optional.ofNullable(params.obtainKeyOrDefault(BootstrapKey.BOOTSTRAP_WEB_SOCKET_ENABLE, function.apply(BootstrapKey.BOOTSTRAP_WEB_SOCKET_ENABLE))) - .map(Boolean::parseBoolean).orElse(false); - - Boolean ssl = Optional.ofNullable(params.obtainKeyOrDefault(BootstrapKey.BOOTSTRAP_SSL, function.apply(BootstrapKey.BOOTSTRAP_SSL))) - .map(Boolean::parseBoolean).orElse(false); - - String username = Optional.ofNullable(params.obtainKeyOrDefault(BootstrapKey.BOOTSTRAP_USERNAME, function.apply(BootstrapKey.BOOTSTRAP_USERNAME))) - .map(String::valueOf).orElse(DEFAULT_AUTH_USERNAME_PASSWORD); - - String password = Optional.ofNullable(params.obtainKeyOrDefault(BootstrapKey.BOOTSTRAP_PASSWORD, function.apply(BootstrapKey.BOOTSTRAP_PASSWORD))) - .map(String::valueOf).orElse(DEFAULT_AUTH_USERNAME_PASSWORD); - - - Boolean httpEnable = Optional.ofNullable(params.obtainKeyOrDefault(BootstrapKey.BOOTSTRAP_HTTP_ENABLE, function.apply(BootstrapKey.BOOTSTRAP_HTTP_ENABLE))) - .map(Boolean::parseBoolean).orElse(false); - - Boolean clusterEnable = Optional.ofNullable(params.obtainKeyOrDefault(BootstrapKey.BOOTSTRAP_CLUSTER_ENABLE, function.apply(BootstrapKey.BOOTSTRAP_CLUSTER_ENABLE))) - .map(Boolean::parseBoolean).orElse(false); - - - String loggerLevel = Optional.ofNullable(params.obtainKeyOrDefault(BootstrapKey.BOOTSTRAP_LOGGER_LEVEL, function.apply(BootstrapKey.BOOTSTRAP_LOGGER_LEVEL))) - .map(String::valueOf).orElse(null); - - if (loggerLevel != null) { - LoggerLevel.root(Level.toLevel(loggerLevel)); - } - - Bootstrap.BootstrapBuilder builder = Bootstrap.builder(); - builder.port(port) - .reactivePasswordAuth(((userName, passwordInBytes) -> userName.equals(username) && password.equals(new String(passwordInBytes)))) - .bossThreadSize(bossThreadSize) - .wiretap(wiretap) - .ssl(ssl) - .workThreadSize(workThreadSize) - .lowWaterMark(lowWaterMark) - .envContext(params) - .highWaterMark(highWaterMark); - - if (ssl) { - String sslCrt = Optional.ofNullable(params.obtainKeyOrDefault(BootstrapKey.BOOTSTRAP_SSL_CRT, function.apply(BootstrapKey.BOOTSTRAP_SSL_CRT))) - .map(String::valueOf).orElse(null); - String sslKey = Optional.ofNullable(params.obtainKeyOrDefault(BootstrapKey.BOOTSTRAP_SSL_KEY, function.apply(BootstrapKey.BOOTSTRAP_SSL_KEY))) - .map(String::valueOf).orElse(null); - if (sslCrt == null || sslKey == null) { - builder.sslContext(null); + public static void start(String path) { + BootstrapConfig config = null; + if (path != null) { + if (path.endsWith(FileExtension.PROPERTIES_SYMBOL)) { + ObjectMapper mapper = new ObjectMapper(new JavaPropsFactory()); + try { + config = mapper.readValue(new File(path), BootstrapConfig.class); + } catch (Exception e) { + log.error("properties read error", e); + } + } else if (path.endsWith(FileExtension.YAML_SYMBOL_1) || path.endsWith(FileExtension.YAML_SYMBOL_2)) { + ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); + try { + config = mapper.readValue(new File(path), BootstrapConfig.class); + } catch (Exception e) { + log.error("yaml read error", e); + return; + } } else { - builder.sslContext(new SslContext(sslCrt, sslKey)); + throw new NotSupportConfigException(); } } - if (clusterEnable) { - Integer clusterPort = Optional.ofNullable(params.obtainKeyOrDefault(BootstrapKey.BOOTSTRAP_CLUSTER_PORT, function.apply(BootstrapKey.BOOTSTRAP_CLUSTER_PORT))) - .map(Integer::parseInt).orElse(DEFAULT_CLUSTER_PORT); - String clusterUrl = Optional.ofNullable(params.obtainKeyOrDefault(BootstrapKey.BOOTSTRAP_CLUSTER_URL, function.apply(BootstrapKey.BOOTSTRAP_CLUSTER_URL))) - .map(String::valueOf).orElse(null); - String clusterNode = Optional.ofNullable(params.obtainKeyOrDefault(BootstrapKey.BOOTSTRAP_CLUSTER_NODE, function.apply(BootstrapKey.BOOTSTRAP_CLUSTER_NODE))) - .map(String::valueOf).orElse(UUID.randomUUID().toString().replaceAll("-", "")); - ClusterConfig clusterConfig = - ClusterConfig.builder() - .port(clusterPort) - .clusterUrl(clusterUrl) - .nodeName(clusterNode) - .clustered(true) - .build(); - builder.clusterConfig(clusterConfig); + if (config == null) { + config = BootstrapConfig.defaultConfig(); } - if (isWebsocket) { - Integer websocketPort = Optional.ofNullable(params.obtainKeyOrDefault(BootstrapKey.BOOTSTRAP_WEB_SOCKET_PORT, function.apply(BootstrapKey.BOOTSTRAP_WEB_SOCKET_PORT))) - .map(Integer::parseInt).orElse(DEFAULT_WEBSOCKET_MQTT_PORT); - builder.isWebsocket(true) - .websocketPort(websocketPort); - } - if (httpEnable) { - Bootstrap.HttpOptions.HttpOptionsBuilder optionsBuilder = Bootstrap.HttpOptions.builder(); - - Boolean accessLog = Optional.ofNullable(params.obtainKeyOrDefault(BootstrapKey.BOOTSTRAP_HTTP_ACCESS_LOG, function.apply(BootstrapKey.BOOTSTRAP_HTTP_ACCESS_LOG))) - .map(Boolean::parseBoolean).orElse(false); - - - Boolean httpSsl = Optional.ofNullable(params.obtainKeyOrDefault(BootstrapKey.BOOTSTRAP_HTTP_SSL_ENABLE, function.apply(BootstrapKey.BOOTSTRAP_HTTP_SSL_ENABLE))) - .map(Boolean::parseBoolean).orElse(false); - - if (httpSsl) { - String httpSslCrt = Optional.ofNullable(params.obtainKeyOrDefault(BootstrapKey.BOOTSTRAP_HTTP_SSL_CRT, function.apply(BootstrapKey.BOOTSTRAP_HTTP_SSL_CRT))) - .map(String::valueOf).orElse(null); - String httpSslKey = Optional.ofNullable(params.obtainKeyOrDefault(BootstrapKey.BOOTSTRAP_HTTP_SSL_KEY, function.apply(BootstrapKey.BOOTSTRAP_HTTP_SSL_KEY))) - .map(String::valueOf).orElse(null); - if (httpSslKey == null || httpSslCrt == null) { - optionsBuilder.sslContext(null); - } else { - optionsBuilder.sslContext(new SslContext(httpSslCrt, httpSslKey)); - } - } - optionsBuilder - .accessLog(accessLog) - .ssl(httpSsl); - Bootstrap.HttpOptions options = optionsBuilder.build(); - builder.httpOptions(options); + Bootstrap.builder() + .rootLevel(Level.toLevel(config.getSmqttConfig().getLogLevel())) + .tcpConfig(config.getSmqttConfig().getTcpConfig()) + .httpConfig(config.getSmqttConfig().getHttpConfig()) + .websocketConfig(config.getSmqttConfig().getWebsocketConfig()) + .clusterConfig(config.getSmqttConfig().getClusterConfig()) + .redisConfig(config.getSmqttConfig().getRedisConfig()) + .databaseConfig(config.getSmqttConfig().getDatabaseConfig()) + .meterConfig(config.getSmqttConfig().getMeterConfig()) + .ruleChainDefinitions(config.getSmqttConfig().getRuleChainDefinitions()) + .sourceDefinitions(config.getSmqttConfig().getRuleSources()) + .aclConfig(config.getSmqttConfig().getAcl()) + .authConfig(config.getSmqttConfig().getAuthConfig()) + .build() + .doOnStarted(AbstractStarter::printUiUrl).startAwait(); - } - Bootstrap bootstrap = builder.build(); - bootstrap.doOnStarted(bt -> printUIUrl(bootstrap.getHttpOptions().getHttpPort())).startAwait(); } /** * 打印前端访问地址 * - * @param httpPort http端口 + * @param bootstrap 启动类 */ - public static void printUIUrl(Integer httpPort) { - log.info("\n-------------------------------------------------------------\n\t" + - "Application UI is running AccessURLs:\n\t" + - "Http Local url: http://localhost:{}/smqtt/admin" + "\n\t" + - "Http External url: http://{}:{}/smqtt/admin" + "\n" + - "-------------------------------------------------------------" - , httpPort, IPUtils.getIP(), httpPort); + public static void printUiUrl(Bootstrap bootstrap) { + String start = "\n-------------------------------------------------------------\n\t"; + start += String.format("Smqtt mqtt connect url %s:%s \n\t", IPUtils.getIP(), bootstrap.getTcpConfig().getPort()); + if (bootstrap.getHttpConfig() != null && bootstrap.getHttpConfig().isEnable()) { + Integer port = 60000; + start += String.format("Smqtt-Admin UI is running AccessURLs:\n\t" + + "Http Local url: http://localhost:%s/smqtt/admin" + "\n\t" + + "Http External url: http://%s:%s/smqtt/admin" + "\n" + + "-------------------------------------------------------------", port, IPUtils.getIP(), port); + } + log.info(start); } - } diff --git a/smqtt-bootstrap/src/main/java/io/github/quickmsg/docker/DockerStarter.java b/smqtt-bootstrap/src/main/java/io/github/quickmsg/docker/DockerStarter.java index 951284f8d71f67cb1bc84570d408acbe89b216a7..2cab19c38751193a32ca96196901856d379fcb11 100644 --- a/smqtt-bootstrap/src/main/java/io/github/quickmsg/docker/DockerStarter.java +++ b/smqtt-bootstrap/src/main/java/io/github/quickmsg/docker/DockerStarter.java @@ -1,20 +1,42 @@ package io.github.quickmsg.docker; import io.github.quickmsg.AbstractStarter; +import io.github.quickmsg.common.utils.FileExtension; import lombok.extern.slf4j.Slf4j; +import java.io.File; + /** * @author luxurong */ @Slf4j public class DockerStarter extends AbstractStarter { - private static final String CONFIG_MAPPER_DIR = "config.properties"; - + private final static String CONFIG_DIR_PATH = "/config"; public static void main(String[] args) { log.info("DockerStarter start args {}", String.join(",", args)); - start(System::getenv, CONFIG_MAPPER_DIR); + start(findConfigByPath()); + } + + private static String findConfigByPath() { + File configFile = new File(CONFIG_DIR_PATH); + File[] files = configFile.listFiles(); + if (files != null) { + for (File file : files) { + if (file.isDirectory()) { + continue; + } + String filename = file.getName(); + if (filename.endsWith(FileExtension.PROPERTIES_SYMBOL) + || filename.endsWith(FileExtension.YAML_SYMBOL_1) + || filename.endsWith(FileExtension.YAML_SYMBOL_2)) { + return file.getAbsolutePath(); + } + } + } + + return null; } diff --git a/smqtt-bootstrap/src/main/java/io/github/quickmsg/exception/NotSupportConfigException.java b/smqtt-bootstrap/src/main/java/io/github/quickmsg/exception/NotSupportConfigException.java new file mode 100644 index 0000000000000000000000000000000000000000..55acfa77b60fe5036caf99b20a7702dfd6609877 --- /dev/null +++ b/smqtt-bootstrap/src/main/java/io/github/quickmsg/exception/NotSupportConfigException.java @@ -0,0 +1,11 @@ +package io.github.quickmsg.exception; + +/** + * @author luxurong + */ +public class NotSupportConfigException extends RuntimeException { + + public NotSupportConfigException() { + super("请使用properties/yaml配置文件"); + } +} diff --git a/smqtt-bootstrap/src/main/java/io/github/quickmsg/jar/JarStarter.java b/smqtt-bootstrap/src/main/java/io/github/quickmsg/jar/JarStarter.java index 8343db7b388fd1dc3750a9efc9d3fb3621c7fab4..bf30914c602d6341784adc53701ed9040bdd2342 100644 --- a/smqtt-bootstrap/src/main/java/io/github/quickmsg/jar/JarStarter.java +++ b/smqtt-bootstrap/src/main/java/io/github/quickmsg/jar/JarStarter.java @@ -3,18 +3,21 @@ package io.github.quickmsg.jar; import io.github.quickmsg.AbstractStarter; import lombok.extern.slf4j.Slf4j; +import java.io.IOException; + /** * @author luxurong */ @Slf4j public class JarStarter extends AbstractStarter { - public static void main(String[] args) { + public static void main(String[] args) throws IOException { log.info("JarStarter start args {}", String.join(",", args)); if (args.length > 0) { - start(System::getProperty, args[0]); + start(args[0]); } else { - start(System::getProperty, null); + start(null); } + } } diff --git a/smqtt-bootstrap/src/main/resources/banner.txt b/smqtt-bootstrap/src/main/resources/banner.txt new file mode 100644 index 0000000000000000000000000000000000000000..1894e2c0089cb3d5da258c108a4d3815ab28b9ae --- /dev/null +++ b/smqtt-bootstrap/src/main/resources/banner.txt @@ -0,0 +1,8 @@ + + _____ __ __ ____ _______ _______ + / ____| \/ |/ __ \__ __|__ __| + | (___ | \ / | | | | | | | | + \___ \| |\/| | | | | | | | | + ____) | | | | |__| | | | | | + |_____/|_| |_|\___\_\ |_| |_| + diff --git a/smqtt-bootstrap/src/main/resources/test.yaml b/smqtt-bootstrap/src/main/resources/test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e4203080c7a10e0811258fd56cb1cf8b0f78465e --- /dev/null +++ b/smqtt-bootstrap/src/main/resources/test.yaml @@ -0,0 +1,3 @@ +smqtt: + tcp: + port: 7000 \ No newline at end of file diff --git a/smqtt-bootstrap/src/test/java/ClusterNode1.java b/smqtt-bootstrap/src/test/java/ClusterNode1.java index 2a7206a0691da3fa14aa594b58844c8c5207a444..b4eee816775b80106f85a37e32b6a2177a0ec6f5 100644 --- a/smqtt-bootstrap/src/test/java/ClusterNode1.java +++ b/smqtt-bootstrap/src/test/java/ClusterNode1.java @@ -1,4 +1,6 @@ -import io.github.quickmsg.common.cluster.ClusterConfig; +import ch.qos.logback.classic.Level; +import io.github.quickmsg.common.config.AuthConfig; +import io.github.quickmsg.common.config.BootstrapConfig; import io.github.quickmsg.common.config.SslContext; import io.github.quickmsg.core.Bootstrap; @@ -9,31 +11,44 @@ public class ClusterNode1 { public static void main(String[] args) throws InterruptedException { Bootstrap bootstrap = Bootstrap.builder() - .port(8555) - .websocketPort(8999) - .options(channelOptionMap -> { - })//netty options设置 - .childOptions(channelOptionMap -> { - }) //netty childOptions设置 - .highWaterMark(1000000) - .reactivePasswordAuth((U, P) -> true) - .lowWaterMark(1000) - .ssl(false) - .sslContext(new SslContext("crt", "key")) - .isWebsocket(true) - .wiretap(false) - .httpOptions(Bootstrap.HttpOptions.builder().ssl(false).accessLog(true).build()) + .rootLevel(Level.INFO) + .websocketConfig( + BootstrapConfig.WebsocketConfig + .builder() + .enable(false) + .path("/mqtt") + .port(8888) + .build() + ) + .tcpConfig( + BootstrapConfig + .TcpConfig + .builder() + .port(1883) + .ssl(SslContext.builder().enable(false).build()) + .build()) + .httpConfig( + BootstrapConfig + .HttpConfig + .builder() + .enable(true) + .accessLog(true) + .admin(BootstrapConfig.HttpAdmin.builder().enable(true).username("smqtt").password("smqtt").build()) + .build()) .clusterConfig( - ClusterConfig.builder() - .clustered(false) + BootstrapConfig. + ClusterConfig + .builder() + .enable(true) + .namespace("smqtt") + .node("node-1") .port(7773) - .nodeName("node-2") - .clusterUrl("127.0.0.1:7771,127.0.0.1:7772") - .build()) + .url("127.0.0.1:7771,127.0.0.1:7772"). + build()) .build() .start().block(); assert bootstrap != null; - Thread.sleep(1000000); + Thread.sleep(10000000); } } diff --git a/smqtt-bootstrap/src/test/java/ClusterNode2.java b/smqtt-bootstrap/src/test/java/ClusterNode2.java index 3b04b86205bf8f9b6be63cfd6d00ac3e43891b10..a5a650724c26d3827bd2ff015718cc6d8f926640 100644 --- a/smqtt-bootstrap/src/test/java/ClusterNode2.java +++ b/smqtt-bootstrap/src/test/java/ClusterNode2.java @@ -1,5 +1,5 @@ -import io.github.quickmsg.common.cluster.ClusterConfig; -import io.github.quickmsg.common.config.SslContext; +import ch.qos.logback.classic.Level; +import io.github.quickmsg.common.config.BootstrapConfig; import io.github.quickmsg.core.Bootstrap; /** @@ -11,22 +11,25 @@ public class ClusterNode2 { @org.junit.Test public void startServer() throws InterruptedException { + Bootstrap bootstrap = Bootstrap.builder() - .port(8556) - .options(channelOptionMap -> {})//netty options设置 - .childOptions(channelOptionMap ->{}) //netty childOptions设置 - .highWaterMark(1000000) - .lowWaterMark(1000) - .reactivePasswordAuth((U,P)->true) - .ssl(false) - .wiretap(true) + .rootLevel(Level.DEBUG) + .tcpConfig( + BootstrapConfig + .TcpConfig + .builder() + .port(8551) + .build()) .clusterConfig( - ClusterConfig.builder() - .clustered(true) + BootstrapConfig. + ClusterConfig + .builder() + .enable(true) + .node("node-3") + .namespace("smqtt") .port(7772) - .nodeName("node-3") - .clusterUrl("127.0.0.1:7771,127.0.0.1:7773") - .build()) + .url("127.0.0.1:7773,127.0.0.1:7771"). + build()) .build() .start().block(); assert bootstrap != null; diff --git a/smqtt-bootstrap/src/test/java/ClusterNode3.java b/smqtt-bootstrap/src/test/java/ClusterNode3.java index cc92d7ffe2c187b7e5639c81a1bf831509705a4f..a9fea2c9eee7053a1815b16c31a01964baef31a6 100644 --- a/smqtt-bootstrap/src/test/java/ClusterNode3.java +++ b/smqtt-bootstrap/src/test/java/ClusterNode3.java @@ -1,4 +1,5 @@ -import io.github.quickmsg.common.cluster.ClusterConfig; +import ch.qos.logback.classic.Level; +import io.github.quickmsg.common.config.BootstrapConfig; import io.github.quickmsg.core.Bootstrap; /** @@ -10,22 +11,25 @@ public class ClusterNode3 { @org.junit.Test public void startServer() throws InterruptedException { + Bootstrap bootstrap = Bootstrap.builder() - .port(8551) - .options(channelOptionMap -> {})//netty options设置 - .childOptions(channelOptionMap ->{}) //netty childOptions设置 - .highWaterMark(1000000) - .reactivePasswordAuth((U,P)->true) - .lowWaterMark(1000) - .ssl(false) - .wiretap(true) + .rootLevel(Level.DEBUG) + .tcpConfig( + BootstrapConfig + .TcpConfig + .builder() + .port(8553) + .build()) .clusterConfig( - ClusterConfig.builder() - .clustered(true) + BootstrapConfig. + ClusterConfig + .builder() + .enable(true) + .node("node-4") .port(7771) - .nodeName("node-4") - .clusterUrl("127.0.0.1:7772,127.0.0.1:7773") - .build()) + .namespace("smqtt") + .url("127.0.0.1:7773,127.0.0.1:7772"). + build()) .build() .start().block(); assert bootstrap != null; diff --git a/smqtt-bootstrap/src/test/java/topic/TopicTest.java b/smqtt-bootstrap/src/test/java/topic/TopicTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d67f144ae17d85e0859923faf7a3bdae6390556d --- /dev/null +++ b/smqtt-bootstrap/src/test/java/topic/TopicTest.java @@ -0,0 +1,53 @@ +package topic; + +import io.github.quickmsg.common.channel.MqttChannel; +import io.github.quickmsg.common.topic.SubscribeTopic; +import io.github.quickmsg.common.topic.TopicRegistry; +import io.github.quickmsg.core.spi.DefaultTopicRegistry; +import io.netty.handler.codec.mqtt.MqttQoS; + +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.*; + +/** + * @author luxurong + */ +public class TopicTest { + + static ExecutorService service = Executors.newFixedThreadPool(100); + + private static TopicRegistry topicRegistry = new DefaultTopicRegistry(); + + private static Map channelMap = new ConcurrentHashMap<>(); + + public static void main(String[] args) { + CountDownLatch count = new CountDownLatch(500000); + for(int i=0;i<500000;i++){ + service.execute(()->{ + int index = new Random().nextInt(1000); + MqttChannel mqttChannel =channelMap.computeIfAbsent(index,in->{ + MqttChannel mqttChannel1=new MqttChannel(); + mqttChannel1.setTopics(new CopyOnWriteArraySet<>()); + return mqttChannel1; + }); + SubscribeTopic subscribeTopic=new SubscribeTopic(String.valueOf(index), MqttQoS.AT_MOST_ONCE,mqttChannel); + topicRegistry.registrySubscribeTopic(subscribeTopic); + topicRegistry.getAllTopics(); + count.countDown(); + }); + } + try { + count.await(); + Map> topics = topicRegistry.getAllTopics(); + System.out.println(topics); + + } catch (InterruptedException e) { + e.printStackTrace(); + } + + } + + +} diff --git a/smqtt-common/pom.xml b/smqtt-common/pom.xml index 0860e1da4120a1476c05640fab8d030139c735b7..c8e804ea27958dbe3c42810b43fa61ea96772777 100644 --- a/smqtt-common/pom.xml +++ b/smqtt-common/pom.xml @@ -5,7 +5,7 @@ smqtt io.github.quickmsg - 1.0.5 + 1.1.7 4.0.0 jar @@ -14,13 +14,17 @@ smqtt-common - http://www.example.com + https://doc.smqtt.cc/ - com.alibaba - fastjson + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + + + com.fasterxml.jackson.dataformat + jackson-dataformat-properties io.projectreactor.netty @@ -51,5 +55,45 @@ ch.qos.logback logback-classic + + com.fasterxml.jackson.core + jackson-core + + + com.fasterxml.jackson.core + jackson-databind + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + com.fasterxml.jackson.datatype + jackson-datatype-jdk8 + + + io.micrometer + micrometer-core + + + com.github.oshi + oshi-core + + + io.micrometer + micrometer-registry-prometheus + + + io.micrometer + micrometer-registry-influx + + + org.casbin + jcasbin + + + org.casbin + jdbc-adapter + diff --git a/smqtt-common/pom.xml.versionsBackup b/smqtt-common/pom.xml.versionsBackup new file mode 100644 index 0000000000000000000000000000000000000000..0cc543f7b89c5760e853f3e3314488633889d2df --- /dev/null +++ b/smqtt-common/pom.xml.versionsBackup @@ -0,0 +1,55 @@ + + + + + smqtt + com.github.quickmsg.smqtt + 1.0-SNAPSHOT + + 4.0.0 + jar + + smqtt-common + + smqtt-common + + http://www.example.com + + + + + com.alibaba + fastjson + + + io.projectreactor.netty + reactor-netty + + + io.netty + netty-codec-mqtt + + + org.projectlombok + lombok + + + junit + junit + test + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-core + + + ch.qos.logback + logback-classic + + + diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/StartUp.java b/smqtt-common/src/main/java/io/github/quickmsg/common/StartUp.java index 1141f177019e7d191c486fb1d6b9b2af77af1888..74aed10a735dee73eb8c1a49171049a1fd77c63a 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/StartUp.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/StartUp.java @@ -1,6 +1,6 @@ package io.github.quickmsg.common; -import io.github.quickmsg.common.environment.EnvContext; +import java.util.Map; /** * @author luxurong @@ -11,9 +11,10 @@ public interface StartUp { /** * 注入环境变量 * - * @param envContext 环境变量 + * @param environmentMap 注入不同配置 + * @see io.github.quickmsg.common.config.BootstrapConfig */ - default void startUp(EnvContext envContext) { + default void startUp(Map environmentMap) { } } diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/acl/AclAction.java b/smqtt-common/src/main/java/io/github/quickmsg/common/acl/AclAction.java new file mode 100644 index 0000000000000000000000000000000000000000..2a04a14be3bf48148703f76b4b5c842b4588a5ba --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/acl/AclAction.java @@ -0,0 +1,21 @@ +package io.github.quickmsg.common.acl; + +/** + * @author luxurong + */ +public enum AclAction { + + /** + * mqtt sub + */ + SUBSCRIBE, + + /** + * mqtt pub + */ + PUBLISH, + /** + * 新增ACL配置时, 一次性添加以上三种动作 + */ + ALL +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/acl/AclManager.java b/smqtt-common/src/main/java/io/github/quickmsg/common/acl/AclManager.java new file mode 100644 index 0000000000000000000000000000000000000000..9bb4979eb94ed097331ea898fefe706b1e00e930 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/acl/AclManager.java @@ -0,0 +1,22 @@ +package io.github.quickmsg.common.acl; + +import io.github.quickmsg.common.acl.model.PolicyModel; +import io.github.quickmsg.common.channel.MqttChannel; + +import java.util.List; + +/** + * @author luxurong + */ +public interface AclManager { + + boolean check(MqttChannel mqttChannel, String source, AclAction action); + + boolean add(String sub,String source,AclAction action,AclType type); + + + boolean delete(String sub,String source,AclAction action,AclType type); + + List> get(PolicyModel policyModel); + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/acl/AclPolicy.java b/smqtt-common/src/main/java/io/github/quickmsg/common/acl/AclPolicy.java new file mode 100644 index 0000000000000000000000000000000000000000..274a37bfb9dabce0cc0bddeff2769393404a50f3 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/acl/AclPolicy.java @@ -0,0 +1,22 @@ +package io.github.quickmsg.common.acl; + +/** + * @author luxurong + */ +public enum AclPolicy { + + /** + * no check + */ + NONE, + /** + * disk file + */ + FILE, + + /** + * sql database + */ + JDBC + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/acl/AclType.java b/smqtt-common/src/main/java/io/github/quickmsg/common/acl/AclType.java new file mode 100644 index 0000000000000000000000000000000000000000..a5cf84e83a03897a77bc486d7267fc7c897d65d5 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/acl/AclType.java @@ -0,0 +1,35 @@ +package io.github.quickmsg.common.acl; + + +import lombok.Getter; + +/** + * @author luxurong + */ +public enum AclType { + + ALL(""), + + + ALLOW("allow"), + + DENY("deny"); + + @Getter + private final String desc; + + AclType(String desc) { + this.desc = desc; + } + + public static AclType fromDesc(String desc) { + for (AclType type : AclType.values()) { + if (type.desc.equals(desc)) { + return type; + } + } + return null; + } + + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/acl/filter/AclFunction.java b/smqtt-common/src/main/java/io/github/quickmsg/common/acl/filter/AclFunction.java new file mode 100644 index 0000000000000000000000000000000000000000..6f41fddd4eeda804fd3363008822312b5defb959 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/acl/filter/AclFunction.java @@ -0,0 +1,42 @@ +package io.github.quickmsg.common.acl.filter; + +import com.googlecode.aviator.runtime.function.FunctionUtils; +import com.googlecode.aviator.runtime.type.AviatorBoolean; +import com.googlecode.aviator.runtime.type.AviatorObject; +import org.casbin.jcasbin.util.BuiltInFunctions; +import org.casbin.jcasbin.util.function.CustomFunction; + +import java.util.Map; + +/** + * ip{} + * id{} + * all + * + * @author luxurong + */ +public class AclFunction extends CustomFunction { + + + @Override + public AviatorObject call(Map env, AviatorObject arg1, AviatorObject arg2) { + String requestSubject = FunctionUtils.getStringValue(arg1, env); + String subject = FunctionUtils.getStringValue(arg2, env); + if (subject.startsWith("ip")) { + int startIndex = subject.indexOf("{"); + int endIndex = subject.indexOf("}"); + String ip = requestSubject.split(":")[1]; + return AviatorBoolean.valueOf(BuiltInFunctions.ipMatch(ip, subject.substring(startIndex + 1, endIndex))); + } else if (subject.equals("all")) { + return AviatorBoolean.valueOf(true); + } else { + String clientId = requestSubject.split(":")[0]; + return AviatorBoolean.valueOf(clientId.equals(subject)); + } + } + + @Override + public String getName() { + return "filter"; + } +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/acl/model/PolicyModel.java b/smqtt-common/src/main/java/io/github/quickmsg/common/acl/model/PolicyModel.java new file mode 100644 index 0000000000000000000000000000000000000000..117b3bacef866b4059a903708e62b7a2ff42b45b --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/acl/model/PolicyModel.java @@ -0,0 +1,21 @@ +package io.github.quickmsg.common.acl.model; + +import io.github.quickmsg.common.acl.AclAction; +import io.github.quickmsg.common.acl.AclType; +import lombok.Data; + +/** + * @author luxurong + */ +@Data +public class PolicyModel { + + private String subject; + + private String source; + + private AclAction action; + + private AclType aclType; + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/annotation/AllowCors.java b/smqtt-common/src/main/java/io/github/quickmsg/common/annotation/AllowCors.java new file mode 100644 index 0000000000000000000000000000000000000000..c758da62f640d0b036e159b6a2bb5ccd0493cd20 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/annotation/AllowCors.java @@ -0,0 +1,13 @@ +package io.github.quickmsg.common.annotation; + +import java.lang.annotation.*; + +/** + * @author luxurong + */ +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +public @interface AllowCors { +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/annotation/Intercept.java b/smqtt-common/src/main/java/io/github/quickmsg/common/annotation/Intercept.java index 85786a6d638ca99aca8fe39d59d05912fd2bf2ac..d31810d3874805d72279b493d83f9fa675b5e59b 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/annotation/Intercept.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/annotation/Intercept.java @@ -11,4 +11,6 @@ import java.lang.annotation.*; @Inherited public @interface Intercept { + + } diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/auth/AuthBean.java b/smqtt-common/src/main/java/io/github/quickmsg/common/auth/AuthBean.java new file mode 100644 index 0000000000000000000000000000000000000000..1f8c858fd504b6d21ceb226839339aaf7f717e4f --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/auth/AuthBean.java @@ -0,0 +1,17 @@ +package io.github.quickmsg.common.auth; + +import lombok.Data; + +/** + * @author luxurong + */ +@Data +public class AuthBean { + + private String clientId; + + private String username; + + private String password; + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/auth/PasswordAuthentication.java b/smqtt-common/src/main/java/io/github/quickmsg/common/auth/AuthManager.java similarity index 40% rename from smqtt-common/src/main/java/io/github/quickmsg/common/auth/PasswordAuthentication.java rename to smqtt-common/src/main/java/io/github/quickmsg/common/auth/AuthManager.java index 2e20047367bcc1a869808cbb2dbbd9629950d8f7..ea5e1be69b649a8a7c8e6752aa3d86f240eedb5e 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/auth/PasswordAuthentication.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/auth/AuthManager.java @@ -1,22 +1,18 @@ package io.github.quickmsg.common.auth; -import io.github.quickmsg.common.StartUp; -import io.github.quickmsg.common.spi.DynamicLoader; - /** * @author luxurong */ -public interface PasswordAuthentication extends StartUp { - - PasswordAuthentication INSTANCE = DynamicLoader.findFirst(PasswordAuthentication.class).orElse(null); +public interface AuthManager { /** * 认证接口 * * @param userName 用户名称 * @param passwordInBytes 密钥 + * @param clientIdentifier 设备标志 * @return 布尔 */ - boolean auth(String userName, byte[] passwordInBytes); + Boolean auth(String userName, byte[] passwordInBytes, String clientIdentifier); } diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/bootstrap/BootstrapKey.java b/smqtt-common/src/main/java/io/github/quickmsg/common/bootstrap/BootstrapKey.java index abede646f0637b0055ac2df5e6eb82149a4c1a08..ad5a890440d307136f1e9d9571441c9df4f33736 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/bootstrap/BootstrapKey.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/bootstrap/BootstrapKey.java @@ -6,61 +6,6 @@ package io.github.quickmsg.common.bootstrap; public class BootstrapKey { - public final static String BOOTSTRAP_LOGGER_LEVEL = " smqtt.log.level"; - - public final static String BOOTSTRAP_PORT = "smqtt.tcp.port"; - - public final static String BOOTSTRAP_LOW_WATERMARK = "smqtt.tcp.lowWaterMark"; - - public final static String BOOTSTRAP_HIGH_WATERMARK = "smqtt.tcp.highWaterMark"; - - public final static String BOOTSTRAP_SSL = "smqtt.tcp.ssl"; - - public final static String BOOTSTRAP_SSL_CRT = "smqtt.tcp.ssl.crt"; - - public final static String BOOTSTRAP_SSL_KEY = "smqtt.tcp.ssl.key"; - - public final static String BOOTSTRAP_WIRETAP = "smqtt.tcp.wiretap"; - - public final static String BOOTSTRAP_BOSS_THREAD_SIZE = "smqtt.tcp.bossThreadSize"; - - public final static String BOOTSTRAP_WORK_THREAD_SIZE = "smqtt.tcp.workThreadSize"; - - public final static String BOOTSTRAP_WEB_SOCKET_PORT = "smqtt.websocket.port"; - - public final static String BOOTSTRAP_WEB_SOCKET_ENABLE = "smqtt.websocket.enable"; - - public final static String BOOTSTRAP_USERNAME = "smqtt.tcp.username"; - - public final static String BOOTSTRAP_PASSWORD = "smqtt.tcp.password"; - - public final static String BOOTSTRAP_HTTP_ENABLE = "smqtt.http.enable"; - - public final static String BOOTSTRAP_HTTP_PORT = "smqtt.http.port"; - - public final static String BOOTSTRAP_HTTP_ACCESS_LOG = "smqtt.http.accesslog"; - - public final static String BOOTSTRAP_HTTP_SSL_ENABLE = "smqtt.http.ssl.enable"; - - public final static String BOOTSTRAP_HTTP_SSL_CRT = "smqtt.http.ssl.crt"; - - public final static String BOOTSTRAP_HTTP_SSL_KEY = "smqtt.http.ssl.key"; - - public final static String BOOTSTRAP_HTTP_USERNAME = "smqtt.http.username"; - - public final static String BOOTSTRAP_HTTP_PASSWORD = "smqtt.http.password"; - - - public final static String BOOTSTRAP_CLUSTER_ENABLE = "smqtt.cluster.enable"; - - public final static String BOOTSTRAP_CLUSTER_URL = "smqtt.cluster.url"; - - public final static String BOOTSTRAP_CLUSTER_PORT = "smqtt.cluster.port"; - - public final static String BOOTSTRAP_CLUSTER_NODE = "smqtt.cluster.node"; - /*数据库配置参数前缀*/ - public final static String DB_PREFIX = "db."; - public static class Redis { /*redis前缀key*/ @@ -124,5 +69,4 @@ public class BootstrapKey { public static final String MASTER_SLAVE = "MASTER_SLAVE"; } - } \ No newline at end of file diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/channel/ChannelRegistry.java b/smqtt-common/src/main/java/io/github/quickmsg/common/channel/ChannelRegistry.java index 543854bdc8814b5d7eeedb62750a033e36ff9ed3..a5e08837a077098647a111581388e4e54f6343cf 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/channel/ChannelRegistry.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/channel/ChannelRegistry.java @@ -1,7 +1,6 @@ package io.github.quickmsg.common.channel; import io.github.quickmsg.common.StartUp; -import io.github.quickmsg.common.cluster.ClusterMessage; import io.github.quickmsg.common.spi.DynamicLoader; import java.util.Collection; @@ -59,7 +58,7 @@ public interface ChannelRegistry extends StartUp { /** * 获取说有channel信息 * - * @return {@link Collection} + * @return {@link Collection} */ Collection getChannels(); diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/channel/MockMqttChannel.java b/smqtt-common/src/main/java/io/github/quickmsg/common/channel/MockMqttChannel.java index e022a8b3f9b023f6c298498355b7c4b81af464e0..4b870fb374941c0df38705e4b122cc53ecd476b3 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/channel/MockMqttChannel.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/channel/MockMqttChannel.java @@ -15,6 +15,13 @@ public class MockMqttChannel extends MqttChannel { public final static MockMqttChannel DEFAULT_MOCK_CHANNEL = new MockMqttChannel(); + public static MockMqttChannel wrapClientIdentifier(String clientIdentifier) { + MockMqttChannel mockMqttChannel = new MockMqttChannel(); + mockMqttChannel.setClientIdentifier(clientIdentifier); + return mockMqttChannel; + } + + @Override public Mono write(MqttMessage mqttMessage, boolean retry) { return Mono.empty(); @@ -27,4 +34,9 @@ public class MockMqttChannel extends MqttChannel { } + @Override + public String toString() { + return "MockMqttChannel{" + + ", clientIdentifier='" + getClientIdentifier() + '\'' + '}'; + } } diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/channel/MqttChannel.java b/smqtt-common/src/main/java/io/github/quickmsg/common/channel/MqttChannel.java index 980b1a9adb8a62e56ef6fc7832c9c95d1c671bbe..34fe1e1d5886b62fe7e1efc023507d05a0a87f11 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/channel/MqttChannel.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/channel/MqttChannel.java @@ -1,17 +1,23 @@ package io.github.quickmsg.common.channel; -import com.alibaba.fastjson.annotation.JSONField; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.github.quickmsg.common.retry.Ack; +import io.github.quickmsg.common.retry.RetryAck; +import io.github.quickmsg.common.retry.TimeAckManager; import io.github.quickmsg.common.enums.ChannelStatus; +import io.github.quickmsg.common.topic.SubscribeTopic; import io.github.quickmsg.common.utils.MessageUtils; -import io.netty.buffer.ByteBuf; import io.netty.handler.codec.mqtt.*; import lombok.Builder; import lombok.Data; +import lombok.Getter; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; import reactor.core.Disposable; import reactor.core.publisher.Mono; import reactor.netty.Connection; +import java.lang.reflect.Constructor; import java.time.Duration; import java.util.Map; import java.util.Optional; @@ -24,7 +30,8 @@ import java.util.function.Consumer; /** * @author luxurong */ -@Data +@Getter +@Setter @Slf4j public class MqttChannel { @@ -34,10 +41,10 @@ public class MqttChannel { private ChannelStatus status; - private long activeTime; - private long authTime; + private long connectTime; + private boolean sessionPersistent; private Will will; @@ -46,37 +53,57 @@ public class MqttChannel { private String username; - private Set topics; + private String address; - @JSONField(serialize = false) + @JsonIgnore + private Set topics; + + @JsonIgnore private Boolean isMock = false; - @JSONField(serialize = false) + @JsonIgnore private transient AtomicInteger atomicInteger; - @JSONField(serialize = false) + @JsonIgnore private transient MqttMessageSink mqttMessageSink; - @JSONField(serialize = false) + @JsonIgnore private transient Map qos2MsgCache; - @JSONField(serialize = false) + @JsonIgnore private Map> replyMqttMessageMap; - @JSONField(serialize = false) + @JsonIgnore private Disposable closeDisposable; - public static MqttChannel init(Connection connection) { + @JsonIgnore + private TimeAckManager timeAckManager; + + public void disposableClose() { + if (closeDisposable != null && !closeDisposable.isDisposed()) { + closeDisposable.dispose(); + } + } + + + public boolean isActive() { + return connection == null && !connection.isDisposed(); + } + + + public static MqttChannel init(Connection connection, TimeAckManager timeAckManager) { MqttChannel mqttChannel = new MqttChannel(); mqttChannel.setTopics(new CopyOnWriteArraySet<>()); mqttChannel.setAtomicInteger(new AtomicInteger(0)); mqttChannel.setReplyMqttMessageMap(new ConcurrentHashMap<>()); mqttChannel.setMqttMessageSink(new MqttMessageSink()); mqttChannel.setQos2MsgCache(new ConcurrentHashMap<>()); - mqttChannel.setActiveTime(System.currentTimeMillis()); mqttChannel.setConnection(connection); mqttChannel.setStatus(ChannelStatus.INIT); + mqttChannel.setAddress(connection.address().toString() + .replaceAll("/", "")); + mqttChannel.setTimeAckManager(timeAckManager); return mqttChannel; } @@ -113,7 +140,7 @@ public class MqttChannel { if (!connection.isDisposed()) { connection.dispose(); } - }).delaySubscription(Duration.ofSeconds(2)).subscribe()); + }).delaySubscription(Duration.ofSeconds(10)).subscribe()); return this; } @@ -129,10 +156,10 @@ public class MqttChannel { public int generateMessageId() { int value; while (qos2MsgCache.containsKey(value = atomicInteger.incrementAndGet())) { - if (value >= Integer.MAX_VALUE) { + if (value >= 65535) { synchronized (this) { value = atomicInteger.incrementAndGet(); - if (value >= Integer.MAX_VALUE) { + if (value >= 65535) { atomicInteger.set(0); } else { break; @@ -159,6 +186,11 @@ public class MqttChannel { } + public long generateId(MqttMessageType type, Integer messageId) { + return (long) connection.channel().hashCode() << 32 | (long) type.value() << 28 | messageId<<4>>>4; + } + + /** * 写入消息 * @@ -168,10 +200,10 @@ public class MqttChannel { */ public Mono write(MqttMessage mqttMessage, boolean retry) { // http本地mock - if (this.getIsMock()) { + if (this.getIsMock() && !this.active()) { return Mono.empty(); } else { - return MqttMessageSink.MQTT_SINK.sendMessage(mqttMessage, this, retry, replyMqttMessageMap); + return MqttMessageSink.MQTT_SINK.sendMessage(mqttMessage, this, retry); } } @@ -194,9 +226,7 @@ public class MqttChannel { * @param messageId messageId */ private void removeReply(MqttMessageType type, Integer messageId) { - Optional.ofNullable(replyMqttMessageMap.get(type)) - .map(messageIds -> messageIds.remove(messageId)) - .ifPresent(Disposable::dispose); + Optional.ofNullable(replyMqttMessageMap.get(type)).map(messageIds -> messageIds.remove(messageId)).ifPresent(Disposable::dispose); } @@ -231,15 +261,24 @@ public class MqttChannel { public static MqttMessageSink MQTT_SINK = new MqttMessageSink(); - public Mono sendMessage(MqttMessage mqttMessage, MqttChannel mqttChannel, boolean retry, Map> replyMqttMessageMap) { - log.info("write channel {} message {}", mqttChannel.getConnection(), mqttMessage); + public Mono sendMessage(MqttMessage mqttMessage, MqttChannel mqttChannel, boolean retry) { + if (log.isDebugEnabled()) { + log.debug("write channel {} message {}", mqttChannel.getConnection(), mqttMessage); + } if (retry) { /* Increase the reference count of bytebuf, and the reference count of retrybytebuf is 2 mqttChannel.write() method releases a reference count. */ - MqttMessage dupMessage = getDupMessage(mqttMessage); - return mqttChannel.write(Mono.just(mqttMessage)).then(offerReply(dupMessage, mqttChannel, getMessageId(mqttMessage), replyMqttMessageMap)); + MqttMessage reply = getReplyMqttMessage(mqttMessage); + + Runnable runnable = () -> mqttChannel.write(Mono.just(reply)).subscribe(); + Runnable cleaner = () -> MessageUtils.safeRelease(reply); + + Ack ack = new RetryAck(mqttChannel.generateId(reply.fixedHeader().messageType(), getMessageId(reply)), + 5, 5, runnable, mqttChannel.getTimeAckManager(), cleaner); + ack.start(); + return mqttChannel.write(Mono.just(mqttMessage)).then(); } else { return mqttChannel.write(Mono.just(mqttMessage)); } @@ -257,53 +296,68 @@ public class MqttChannel { } + private MqttMessage getReplyMqttMessage(MqttMessage mqttMessage) { + if (mqttMessage instanceof MqttPublishMessage) { + return ((MqttPublishMessage) mqttMessage).copy().retain(Integer.MAX_VALUE >> 2); + } else { + return mqttMessage; + } + } + + /** * Set resend flag * - * @param mqttMessage mqttMessage + * @param mqttMessage {@link MqttMessage} * @return 消息体 */ private MqttMessage getDupMessage(MqttMessage mqttMessage) { MqttFixedHeader oldFixedHeader = mqttMessage.fixedHeader(); - MqttFixedHeader fixedHeader = new MqttFixedHeader( - oldFixedHeader.messageType(), - true, - oldFixedHeader.qosLevel(), - oldFixedHeader.isRetain(), - oldFixedHeader.remainingLength()); + MqttFixedHeader fixedHeader = new MqttFixedHeader(oldFixedHeader.messageType(), true, oldFixedHeader.qosLevel(), oldFixedHeader.isRetain(), oldFixedHeader.remainingLength()); Object payload = mqttMessage.payload(); - if (payload instanceof ByteBuf) { - ((ByteBuf) payload).copy().retain(Integer.MAX_VALUE >> 2); + try { + Constructor constructor = mqttMessage.getClass().getDeclaredConstructors()[0]; + constructor.setAccessible(true); + if (constructor.getParameterCount() == 2) { + return (MqttMessage) constructor.newInstance(fixedHeader, mqttMessage.variableHeader()); + } else { + return (MqttMessage) constructor.newInstance(fixedHeader, mqttMessage.variableHeader(), payload); + } + } catch (Exception e) { + return mqttMessage; } - return new MqttMessage(fixedHeader, mqttMessage.variableHeader(), payload); + } - /** - * Set resend action - * - * @param message mqttMessage - * @param mqttChannel connection - * @param messageId messageId - * @param replyMqttMessageMap 重试缓存 - * @return 空操作符 - */ - public Mono offerReply(MqttMessage message, final MqttChannel mqttChannel, final int messageId, Map> replyMqttMessageMap) { - - return Mono.fromRunnable(() -> - replyMqttMessageMap.computeIfAbsent(message.fixedHeader().messageType(), mqttMessageType -> new ConcurrentHashMap<>(8)).put(messageId, - mqttChannel.write(Mono.just(message)) - .delaySubscription(Duration.ofSeconds(5)) - .repeat() - .doOnError(error -> { - MessageUtils.safeRelease(message); - log.error("offerReply", error); - }) - .doOnCancel(() -> MessageUtils.safeRelease(message)) - .subscribe())); - } +// /** +// * Set resend action +// * +// * @param message {@link MqttMessage} +// * @param mqttChannel {@link MqttChannel} +// * @param messageId messageId +// * @param replyMqttMessageMap 重试缓存 +// * @return 空操作符 +// */ +// public Mono offerReply(MqttMessage message, final MqttChannel mqttChannel, final int messageId, Map> replyMqttMessageMap) { +// return Mono.fromRunnable(() -> +// replyMqttMessageMap.computeIfAbsent(message.fixedHeader().messageType(), mqttMessageType -> new ConcurrentHashMap<>(8)).put(messageId, +// mqttChannel.write(Mono.fromCallable(() -> getDupMessage(message))) +// .delaySubscription(Duration.ofSeconds(5)) +// .repeat(10,mqttChannel::isActive) +// .doOnError(error -> { +// MessageUtils.safeRelease(message); +// log.error("offerReply", error); +// }) +// .doOnCancel(() -> MessageUtils.safeRelease(message)) +// .subscribe())); +// } } + @Override + public String toString() { + return "MqttChannel{" + " address='" + this.connection.address().toString() + '\'' + ", clientIdentifier='" + clientIdentifier + '\'' + ", status=" + status + ", keepalive=" + keepalive + ", username='" + username + '}'; + } } diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/channel/traffic/TrafficHandlerLoader.java b/smqtt-common/src/main/java/io/github/quickmsg/common/channel/traffic/TrafficHandlerLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..5399f443026eb4fbe39795063c7cbe5df747591d --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/channel/traffic/TrafficHandlerLoader.java @@ -0,0 +1,16 @@ +package io.github.quickmsg.common.channel.traffic; + +import io.netty.handler.traffic.AbstractTrafficShapingHandler; + +/** + * @author luxurong + */ +public interface TrafficHandlerLoader { + + /** + * return TrafficHandlerLoader + * + * @return {@link AbstractTrafficShapingHandler} + */ + AbstractTrafficShapingHandler get(); +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/cluster/ClusterConfig.java b/smqtt-common/src/main/java/io/github/quickmsg/common/cluster/ClusterConfig.java deleted file mode 100644 index dce3f868b76fb5520532f252c25785e1d1a746f8..0000000000000000000000000000000000000000 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/cluster/ClusterConfig.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.github.quickmsg.common.cluster; - -import lombok.Builder; -import lombok.Data; - -import java.util.List; - -/** - * @author luxurong - */ -@Data -@Builder -public class ClusterConfig { - - private Boolean clustered; - - private Integer port; - - private String nodeName; - - private String clusterUrl; - - public static ClusterConfig defaultClusterConfig() { - return ClusterConfig.builder() - .clustered(false) - .port(0) - .build(); - } -} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/cluster/ClusterHandler.java b/smqtt-common/src/main/java/io/github/quickmsg/common/cluster/ClusterHandler.java index 2119448fedd27157aa5f860b57a8e76565807608..4277ab3f729fd67679fbc50ed96455f147c47f87 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/cluster/ClusterHandler.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/cluster/ClusterHandler.java @@ -1,5 +1,6 @@ package io.github.quickmsg.common.cluster; +import io.github.quickmsg.common.message.HeapMqttMessage; import reactor.core.publisher.Mono; import java.util.List; @@ -13,7 +14,7 @@ public interface ClusterHandler { /** * 获取集群信息 * - * @return {@link List} + * @return {@link ClusterNode} */ List getClusterInfo(); @@ -21,19 +22,19 @@ public interface ClusterHandler { /** * 传播集群消息 * - * @param clusterMessage 集群 + * @param heapMqttMessage 集群 * @return {@link Mono} */ - Mono spreadGossip(ClusterMessage clusterMessage); + Mono spreadGossip(HeapMqttMessage heapMqttMessage); /** * 传播集群消息 * - * @param clusterMessage 集群 + * @param heapMqttMessage 集群 * @return {@link Mono} */ - Mono send(ClusterMessage clusterMessage); + Mono send(HeapMqttMessage heapMqttMessage); } diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/cluster/ClusterMessage.java b/smqtt-common/src/main/java/io/github/quickmsg/common/cluster/ClusterMessage.java deleted file mode 100644 index a4a13fba0fc11e3f9a2d940d312a89f11ec6e36a..0000000000000000000000000000000000000000 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/cluster/ClusterMessage.java +++ /dev/null @@ -1,21 +0,0 @@ -package io.github.quickmsg.common.cluster; - -import lombok.*; - -/** - * @author luxurong - */ -@AllArgsConstructor -@NoArgsConstructor -@Builder -@Data -public class ClusterMessage { - - private String topic; - - private int qos; - - private boolean retain; - - private byte[] message; -} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/cluster/ClusterRegistry.java b/smqtt-common/src/main/java/io/github/quickmsg/common/cluster/ClusterRegistry.java index ea3a9a60197bb98ae19d703c02c751a66dfcaf21..2af4b9369b736976184c9c3d8f68fbcf5419819e 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/cluster/ClusterRegistry.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/cluster/ClusterRegistry.java @@ -1,11 +1,10 @@ package io.github.quickmsg.common.cluster; -import io.github.quickmsg.common.enums.ClusterEvent; +import io.github.quickmsg.common.config.BootstrapConfig; +import io.github.quickmsg.common.enums.ClusterStatus; +import io.github.quickmsg.common.message.ClusterMessage; +import io.github.quickmsg.common.message.HeapMqttMessage; import io.github.quickmsg.common.spi.DynamicLoader; -import io.github.quickmsg.common.utils.MessageUtils; -import io.netty.handler.codec.mqtt.MqttFixedHeader; -import io.netty.handler.codec.mqtt.MqttPublishMessage; -import io.netty.handler.codec.mqtt.MqttPublishVariableHeader; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -25,13 +24,13 @@ public interface ClusterRegistry { * * @param c 集群配置 */ - void registry(ClusterConfig c); + void registry(BootstrapConfig.ClusterConfig c); /** * 开始订阅消息 * - * @return {@link Flux} + * @return {@link HeapMqttMessage} */ Flux handlerClusterMessage(); @@ -39,15 +38,15 @@ public interface ClusterRegistry { /** * 开始订阅Node事件 * - * @return {@link Flux} + * @return {@link ClusterStatus} */ - Flux clusterEvent(); + Flux clusterEvent(); /** * 获取集群节点信息 * - * @return {@link Flux} + * @return {@link ClusterNode} */ List getClusterNode(); @@ -75,26 +74,8 @@ public interface ClusterRegistry { * @param message mqtt Publish消息 * @return {@link Mono} */ - default Mono spreadPublishMessage(MqttPublishMessage message) { - return spreadMessage(clusterMessage(message)); - } - - - /** - * 构建集群消息体 - * - * @param message {@link MqttPublishMessage} - * @return {@link ClusterMessage} - */ - default ClusterMessage clusterMessage(MqttPublishMessage message) { - MqttPublishVariableHeader header = message.variableHeader(); - MqttFixedHeader fixedHeader = message.fixedHeader(); - return ClusterMessage.builder() - .message(MessageUtils.copyReleaseByteBuf(message.payload())) - .topic(header.topicName()) - .retain(fixedHeader.isRetain()) - .qos(fixedHeader.qosLevel().value()) - .build(); + default Mono spreadPublishMessage(ClusterMessage message) { + return spreadMessage(message); } diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/config/AbstractConfiguration.java b/smqtt-common/src/main/java/io/github/quickmsg/common/config/AbstractConfiguration.java index a58605e68505f09ed9185aa18dc0a65c70d216ab..23997a173b460a8fe898b94b7fad0f8efa4e7dbe 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/config/AbstractConfiguration.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/config/AbstractConfiguration.java @@ -1,10 +1,11 @@ package io.github.quickmsg.common.config; -import io.github.quickmsg.common.auth.PasswordAuthentication; -import io.github.quickmsg.common.environment.EnvContext; -import reactor.netty.tcp.TcpServerConfig; +import io.github.quickmsg.common.rule.RuleChainDefinition; +import io.github.quickmsg.common.rule.RuleDefinition; +import io.github.quickmsg.common.rule.source.SourceDefinition; -import java.util.function.Consumer; +import java.util.List; +import java.util.Map; /** * @author luxurong @@ -19,29 +20,36 @@ public interface AbstractConfiguration extends Configuration { */ Integer getWebSocketPort(); - /** - * 获取Tcp服务配置 + * 获取规则引擎 * - * @return {@link Consumer } + * @return {@link RuleDefinition} */ - Consumer getTcpServerConfig(); + List getRuleChainDefinitions(); /** - * 获取服务端认证 + * 获取source * - * @return {@link PasswordAuthentication} + * @return {@link SourceDefinition} */ - PasswordAuthentication getReactivePasswordAuth(); + List getSourceDefinitions(); + /** + * 获取acl配置 + * + * @return {@link AclConfig} + */ + AclConfig getAclConfig(); /** - * 获取环境变量 + * 获取环境参数 * - * @return {@link EnvContext} + * @return {@link Map} */ - EnvContext getEnvContext(); + Map getEnvironmentMap(); + AuthConfig getAuthConfig(); } + diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/config/AclConfig.java b/smqtt-common/src/main/java/io/github/quickmsg/common/config/AclConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..daac5b2d3fb1bd80eb66b8ec6cecf6237168b82b --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/config/AclConfig.java @@ -0,0 +1,30 @@ +package io.github.quickmsg.common.config; + +import io.github.quickmsg.common.acl.AclPolicy; +import lombok.Data; + +/** + * @author luxurong + */ +@Data +public class AclConfig { + + private AclPolicy aclPolicy; + + private String filePath; + + private JdbcAclConfig jdbcAclConfig; + + @Data + public static class JdbcAclConfig { + + private String driver; + + private String url; + + private String username; + + private String password; + + } +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/config/AuthConfig.java b/smqtt-common/src/main/java/io/github/quickmsg/common/config/AuthConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..977b49c753907a5af76578fec6889054166fe1d1 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/config/AuthConfig.java @@ -0,0 +1,62 @@ +package io.github.quickmsg.common.config; + +import lombok.Data; + +import java.util.Map; + +/** + * @author luxurong + */ +@Data +public class AuthConfig { + + private SqlAuthConfig sql; + + private HttpAuthConfig http; + + private FixedAuthConfig fixed; + + private String file; + + @Data + public static class FixedAuthConfig { + + private String username; + + private String password; + + } + + @Data + public static class HttpAuthConfig { + + private String host; + + private int port; + + private String path; + + private String method; + + private Map headers; + + private Map params; + + } + + + @Data + public static class SqlAuthConfig { + + private String driver; + + private String url; + + private String username; + + private String password; + + private String authSql; + + } +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/config/BootstrapConfig.java b/smqtt-common/src/main/java/io/github/quickmsg/common/config/BootstrapConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..bcee19a1453dd5d11329cec8465276c69911d3ae --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/config/BootstrapConfig.java @@ -0,0 +1,484 @@ +package io.github.quickmsg.common.config; + +import ch.qos.logback.classic.Level; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.github.quickmsg.common.metric.MeterType; +import io.github.quickmsg.common.rule.RuleChainDefinition; +import io.github.quickmsg.common.rule.source.SourceDefinition; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Map; + +/** + * @author luxurong + */ +@Data +public class BootstrapConfig { + + @JsonProperty("smqtt") + private SmqttConfig smqttConfig; + + public static BootstrapConfig defaultConfig() { + BootstrapConfig bootstrapConfig = new BootstrapConfig(); + SmqttConfig smqttConfig = new SmqttConfig(); + TcpConfig tcpConfig = new TcpConfig(); + tcpConfig.setPort(1883); + smqttConfig.setTcpConfig(tcpConfig); + smqttConfig.setLogLevel("INFO"); + bootstrapConfig.setSmqttConfig(smqttConfig); + smqttConfig.setClusterConfig(ClusterConfig.builder() + .enable(false).build()); + smqttConfig.setHttpConfig(HttpConfig.builder() + .enable(false).build()); + smqttConfig.setWebsocketConfig(WebsocketConfig.builder() + .enable(false).build()); + return bootstrapConfig; + } + + + @Data + public static class SmqttConfig { + + /** + * sfl4j日志级别 + * + * @see Level + */ + private String logLevel; + + /** + * tcp配置 + */ + @JsonProperty("tcp") + private TcpConfig tcpConfig; + + /** + * http配置 + */ + @JsonProperty("http") + private HttpConfig httpConfig; + + /** + * websocket配置 + */ + @JsonProperty("ws") + private WebsocketConfig websocketConfig; + + /** + * 集群配置配置 + */ + @JsonProperty("cluster") + private ClusterConfig clusterConfig; + + + /** + * 数据库配置 + */ + @JsonProperty("db") + private DatabaseConfig databaseConfig; + /** + * redis配置 + */ + @JsonProperty("redis") + private RedisConfig redisConfig; + /** + * 规则定义 + */ + @JsonProperty("rules") + private List ruleChainDefinitions; + + /** + * 规则定义 + */ + @JsonProperty("sources") + private List ruleSources; + + /** + * 指标配置 + */ + @JsonProperty("meter") + private MeterConfig meterConfig; + + /** + * acl配置 + */ + @JsonProperty("acl") + private AclConfig acl; + + + /** + * auth配置 + */ + @JsonProperty("auth") + private AuthConfig authConfig; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class TcpConfig { + + @Builder.Default + private ConnectModel connectModel = ConnectModel.UNIQUE; + + /** + * 不互踢时间 默认60s + */ + @Builder.Default + private Integer notKickSecond = 60; + /** + * 端口 + */ + private Integer port; + /** + * 二进制日志(需要开启root 为debug) + */ + private Boolean wiretap; + /** + * 核心线程数 + */ + private Integer bossThreadSize; + /** + * 工作线程数 + */ + private Integer workThreadSize; + + /** + * 业务线程数 + */ + private Integer businessThreadSize; + + /** + * 业务队列 + */ + private Integer businessQueueSize; + + /** + * 接收消息的最大限制 + */ + private Integer messageMaxSize; + + /** + * 低水位 + */ + private Integer lowWaterMark; + + /** + * 高水位 + */ + private Integer highWaterMark; + /** + * ssl配置 + */ + private SslContext ssl; + + /** + * 全局写字节限制 + */ + private String globalReadWriteSize; + + /** + * 单个连接读写字节限制 + */ + private String channelReadWriteSize; + + + /** + * server channel options + */ + Map options; + + /** + * child client channel options + */ + Map childOptions; + + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class HttpConfig { + /** + * 开启http + */ + private boolean enable; + /** + * http日志 + */ + private boolean accessLog; + /** + * ssl配置 + */ + private SslContext ssl; + /** + * 管理页面配置 + */ + private HttpAdmin admin; + + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class WebsocketConfig { + /** + * 端口 + */ + private Integer port; + /** + * websocket path + * mqtt.js 需要设置 /mqtt + */ + private String path; + /** + * 开启ws + */ + private boolean enable; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class ClusterConfig { + /** + * 开启集群 + */ + private boolean enable; + /** + * 集群url + */ + private String url; + /** + * 集群启动本地端口 + */ + private Integer port; + /** + * 集群名称 需要唯一 + */ + private String node; + + /** + * 集群空间 需要一致才能通信 + */ + private String namespace; + /** + * 集群额外配置(主要用于容器映射) + */ + private ClusterExternal external; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class DatabaseConfig { + /** + * 数据库连接 + */ + private String jdbcUrl; + /** + * 用户名 + */ + private String username; + /** + * 密码 + */ + private String password; + + private Boolean dataSourceCachePrepStmts; + private Integer dataSourcePrepStmtCacheSize; + private Integer dataSourcePrepStmtCacheSqlLimit; + private Boolean dataSourceUseServerPrepStmts; + private Boolean dataSourceUseLocalSessionState; + private Boolean dataSourceRewriteBatchedStatements; + private Boolean dataSourceCacheResultSetMetadata; + private Boolean dataSourceCacheServerConfiguration; + private Boolean dataSourceElideSetAutoCommits; + private Boolean dataSourceMaintainTimeStats; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class RedisConfig { + + /** + * 单机模式:single 哨兵模式:sentinel 集群模式:cluster + */ + private String mode; + /** + * 数据库 + */ + private Integer database; + /** + * 密码 + */ + private String password; + /** + * 超时时间 + */ + private Integer timeout; + /** + * 最小空闲数 + */ + private Integer poolMinIdle; + /** + * 连接超时时间(毫秒) + */ + private Integer poolConnTimeout; + /** + * 连接池大小 + */ + private Integer poolSize; + + /** + * redis单机配置 + */ + private RedisSingle single; + + /** + * redis集群模式配置 + */ + private RedisCluster cluster; + + /** + * redis哨兵模式配置 + */ + private RedisSentinel sentinel; + + } + + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class HttpAdmin { + /** + * 开启http管理页面 + */ + private boolean enable; + /** + * 用户名 + */ + private String username; + /** + * 密码 + */ + private String password; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class ClusterExternal { + /** + * 本地曝光host + */ + private String host; + + /** + * 本地曝光port + */ + private Integer port; + } + + + /** + * redis单机配置 + */ + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class RedisSingle { + /** + * 地址 + */ + private String address; + } + + /** + * redis集群模式配置 + */ + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class RedisCluster { + private Integer scanInterval; + private String nodes; + private String readMode; + private Integer retryAttempts; + private Integer slaveConnectionPoolSize; + private Integer masterConnectionPoolSize; + private Integer retryInterval; + } + + /** + * redis哨兵模式配置 + */ + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class RedisSentinel { + private String master; + private String nodes; + } + + /** + * 指标配置 + */ + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class MeterConfig { + + private MeterType meterType; + + private Influxdb influxdb; + } + + /** + * influx1.x参数 + */ + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class Influxdb { + /** + * 数据库 + */ + private String db; + /** + * uri + */ + private String uri; + /** + * 用户名 + */ + private String userName; + /** + * 密码 + */ + private String password; + /** + * 步长 + */ + private int step; + } +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/config/ConfigCheck.java b/smqtt-common/src/main/java/io/github/quickmsg/common/config/ConfigCheck.java new file mode 100644 index 0000000000000000000000000000000000000000..823a5c61e8fc1b6cc8dab8657f705bc2f8d27a00 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/config/ConfigCheck.java @@ -0,0 +1,23 @@ +package io.github.quickmsg.common.config; + +import io.github.quickmsg.common.metric.MeterType; + +import java.util.Objects; + +/** + * @author luxurong + */ +public class ConfigCheck { + + public static void checkMeterConfig(BootstrapConfig.MeterConfig config) { + if (config != null) { + if (config.getMeterType() == MeterType.INFLUXDB) { + if (config.getInfluxdb() != null) { + Objects.requireNonNull(config.getInfluxdb().getUri()); + Objects.requireNonNull(config.getInfluxdb().getDb()); + } + } + } + } + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/config/Configuration.java b/smqtt-common/src/main/java/io/github/quickmsg/common/config/Configuration.java index 8e85283e8b6a2f938d518837b11888b94469bf6f..ca994d2b793e07445cb35b8d9d21f7d34250ec6e 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/config/Configuration.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/config/Configuration.java @@ -1,14 +1,12 @@ package io.github.quickmsg.common.config; -import io.github.quickmsg.common.auth.PasswordAuthentication; -import io.github.quickmsg.common.cluster.ClusterConfig; -import io.github.quickmsg.common.environment.EnvContext; - /** * @author luxurong */ public interface Configuration { + ConnectModel getConnectModel(); + /** * netty boss线程数 @@ -26,6 +24,43 @@ public interface Configuration { Integer getWorkThreadSize(); + /** + * 业务线程数 + * + * @return 业务线程数 + */ + Integer getBusinessThreadSize(); + + + /** + * 工作队列数 + * + * @return 工作队列数 + */ + Integer getBusinessQueueSize(); + + /** + * 获取消息最大限制值 + * + * @return {@link Integer} + */ + Integer getMessageMaxSize(); + + /** + * 获取全局读写限制 + * + * @return 工作队列数 + */ + String getGlobalReadWriteSize(); + + /** + * 获取单个channel读写限制 + * + * @return 工作队列数 + */ + String getChannelReadWriteSize(); + + /** * mqtt 端口 * @@ -73,12 +108,24 @@ public interface Configuration { SslContext getSslContext(); - /** * 获取集群配置 * - * @return {@link ClusterConfig} + * @return {@link BootstrapConfig.ClusterConfig} */ - ClusterConfig getClusterConfig(); + BootstrapConfig.ClusterConfig getClusterConfig(); + + /** + * 获取监控配置 + * + * @return {@link BootstrapConfig.MeterConfig} + */ + BootstrapConfig.MeterConfig getMeterConfig(); + + + + + + } diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/config/ConnectModel.java b/smqtt-common/src/main/java/io/github/quickmsg/common/config/ConnectModel.java new file mode 100644 index 0000000000000000000000000000000000000000..2a703fde6ccb48e3b8ccc108aecb3e155b94853b --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/config/ConnectModel.java @@ -0,0 +1,9 @@ +package io.github.quickmsg.common.config; + +/** + * @author luxurong + */ +public enum ConnectModel { + UNIQUE, + KICK +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/config/SslContext.java b/smqtt-common/src/main/java/io/github/quickmsg/common/config/SslContext.java index 23ee2a7c5a1f927873492be14db43a77fa4150f4..d3492045182613d921d415daaed18e5e3751cf79 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/config/SslContext.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/config/SslContext.java @@ -1,18 +1,36 @@ package io.github.quickmsg.common.config; import lombok.AllArgsConstructor; -import lombok.Getter; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; /** * @author luxurong */ +@Data +@Builder +@NoArgsConstructor @AllArgsConstructor -@Getter public class SslContext { private String crt; private String key; + private String ca; + private Boolean enable; + + + public SslContext(String crt, String key) { + this.crt = crt; + this.key = key; + } + + public SslContext(String crt, String key, Boolean enable) { + this.crt = crt; + this.key = key; + this.enable = enable; + } } diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/context/ContextHolder.java b/smqtt-common/src/main/java/io/github/quickmsg/common/context/ContextHolder.java new file mode 100644 index 0000000000000000000000000000000000000000..57088c2c4c1df34c506df30468b4eca54afb67b7 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/context/ContextHolder.java @@ -0,0 +1,21 @@ +package io.github.quickmsg.common.context; + +import io.github.quickmsg.common.config.Configuration; + +/** + * @author luxurong + */ +public class ContextHolder { + + private static ReceiveContext context ; + + public static void setReceiveContext(ReceiveContext context){ + ContextHolder.context = context; + } + + public static ReceiveContext getReceiveContext(){ + return ContextHolder.context; + } + + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/context/ReceiveContext.java b/smqtt-common/src/main/java/io/github/quickmsg/common/context/ReceiveContext.java index be52abb119a61c0ab5a11c47dde2aee85e214631..81a7ace7a712ee6beb991a0060ff831f6925b96d 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/context/ReceiveContext.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/context/ReceiveContext.java @@ -1,12 +1,19 @@ package io.github.quickmsg.common.context; +import io.github.quickmsg.common.retry.TimeAckManager; +import io.github.quickmsg.common.acl.AclManager; import io.github.quickmsg.common.channel.ChannelRegistry; import io.github.quickmsg.common.channel.MqttChannel; +import io.github.quickmsg.common.channel.traffic.TrafficHandlerLoader; import io.github.quickmsg.common.cluster.ClusterRegistry; import io.github.quickmsg.common.config.Configuration; import io.github.quickmsg.common.message.MessageRegistry; +import io.github.quickmsg.common.message.EventRegistry; +import io.github.quickmsg.common.message.SmqttMessage; import io.github.quickmsg.common.protocol.ProtocolAdaptor; +import io.github.quickmsg.common.rule.DslExecutor; import io.github.quickmsg.common.topic.TopicRegistry; +import io.github.quickmsg.common.metric.MetricManager; import io.netty.handler.codec.mqtt.MqttMessage; import java.util.function.BiConsumer; @@ -15,7 +22,7 @@ import java.util.function.BiConsumer; * @author luxurong */ -public interface ReceiveContext extends BiConsumer { +public interface ReceiveContext extends BiConsumer> { /** @@ -57,6 +64,22 @@ public interface ReceiveContext extends BiConsumer extends BiConsumer receiveContext) { + MqttPublishMessage mqttPublishMessage = + MqttMessageBuilder.buildPub(false, MqttQoS.AT_MOST_ONCE, 0, CONNECT_TOPIC, writeBody(mqttChannel, body)); + write(receiveContext, mqttChannel, mqttPublishMessage); + } + + @Override + public ByteBuf writeBody(MqttChannel mqttChannel, Object body) { + return PooledByteBufAllocator.DEFAULT + .directBuffer().writeBytes(JacksonUtil.bean2Json(new ChannelStatusMessage( + mqttChannel.getClientIdentifier(), + System.currentTimeMillis(), + mqttChannel.getUsername(), + ChannelStatus.ONLINE)).getBytes()); + } + + }, + /** + * 关闭事件 + */ + CLOSE { + private static final String CLOSE_TOPIC = "$event/close"; + + @Override + public void sender(MqttChannel mqttChannel, Object body, ReceiveContext receiveContext) { + MqttPublishMessage mqttPublishMessage = + MqttMessageBuilder.buildPub(false, MqttQoS.AT_MOST_ONCE, 0, CLOSE_TOPIC, writeBody(mqttChannel, body)); + write(receiveContext, mqttChannel, mqttPublishMessage); + } + + @Override + public ByteBuf writeBody(MqttChannel mqttChannel, Object body) { + return PooledByteBufAllocator.DEFAULT + .directBuffer().writeBytes(JacksonUtil.bean2Json(new ChannelStatusMessage( + mqttChannel.getClientIdentifier(), + System.currentTimeMillis(), + mqttChannel.getUsername(), + ChannelStatus.OFFLINE)).getBytes()); + } + }; + + /** + * write event + * + * @param mqttChannel {@link MqttChannel } + * @param body {@link Object } + * @param receiveContext {@link ReceiveContext } + */ + public abstract void sender(MqttChannel mqttChannel, Object body, ReceiveContext receiveContext); + + + /** + * body + * + * @param mqttChannel {@link MqttChannel } + * @param body {@link Object } + * @return ByteBuf + */ + public abstract ByteBuf writeBody(MqttChannel mqttChannel, Object body); + + + public void write(ReceiveContext receiveContext, MqttChannel mqttChannel, MqttMessage message) { + receiveContext.getProtocolAdaptor() + .chooseProtocol(MockMqttChannel.wrapClientIdentifier(mqttChannel.getClientIdentifier()), new SmqttMessage<>( + message + , System.currentTimeMillis(), Boolean.FALSE), + receiveContext); + if (message instanceof MqttPublishMessage) { + ((MqttPublishMessage) message).release(); + } + } + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/enums/HttpType.java b/smqtt-common/src/main/java/io/github/quickmsg/common/enums/HttpType.java index aeef38971eae0df518020dbb7caf6bbf7372894d..0fb428cd7dd4f1da4c0f9ecc9c49c62351d54540 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/enums/HttpType.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/enums/HttpType.java @@ -22,6 +22,11 @@ public enum HttpType { */ PUT, + /** + * OPTIONS请求 + */ + OPTIONS, + /** * 文件流 */ diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/enums/RuleType.java b/smqtt-common/src/main/java/io/github/quickmsg/common/enums/RuleType.java new file mode 100644 index 0000000000000000000000000000000000000000..8408701c84e3ea774d9c22fd672e69c33a905436 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/enums/RuleType.java @@ -0,0 +1,47 @@ +package io.github.quickmsg.common.enums; + +/** + * @author luxurong + */ +public enum RuleType { + + /** + * 条件过滤器 + */ + PREDICATE, + + /** + * topic转发器 + */ + TOPIC, + /** + * log转发器 + */ + LOG, + /** + * kafka转发器 + */ + KAFKA, + /** + * rocketmq转发器 + */ + ROCKET_MQ, + /** + * rabbitmq转发器 + */ + RABBIT_MQ, + /** + * web + */ + HTTP, + + /** + * 数据库 + */ + DATA_BASE, + /** + * mqtt转发 + */ + MQTT + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/http/HttpActor.java b/smqtt-common/src/main/java/io/github/quickmsg/common/http/HttpActor.java index 99e6fc50723c46f058fb2be685268afb52a2096d..60130617fab3b289368c6ff1f8e85568205edc51 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/http/HttpActor.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/http/HttpActor.java @@ -1,8 +1,8 @@ package io.github.quickmsg.common.http; -import com.alibaba.fastjson.JSON; import io.github.quickmsg.common.config.Configuration; import io.github.quickmsg.common.spi.DynamicLoader; +import io.github.quickmsg.common.utils.JacksonUtil; import org.reactivestreams.Publisher; import reactor.netty.http.server.HttpServerRequest; import reactor.netty.http.server.HttpServerResponse; @@ -38,10 +38,21 @@ public interface HttpActor { * * @param tClass class * @param 返回类型 - * @return {{@link Function} + * @return {{@link Function} */ default Function toJson(Class tClass) { - return message -> JSON.parseObject(message, tClass); + return message -> JacksonUtil.json2Bean(message, tClass); + } + + /** + * json转换器 + * + * @param tClass class + * @param 返回类型 + * @return {{@link Function} + */ + default Function> toList(Class tClass) { + return message -> JacksonUtil.json2List(message, tClass); } diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/interceptor/MessageProxy.java b/smqtt-common/src/main/java/io/github/quickmsg/common/interceptor/MessageProxy.java index 2338d8f8d233ba881d46c42ff92ec2ea8770b9c4..2e71ad47d48ad74edb3320e6f8622541508be3f7 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/interceptor/MessageProxy.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/interceptor/MessageProxy.java @@ -1,8 +1,24 @@ package io.github.quickmsg.common.interceptor; +import io.github.quickmsg.common.channel.MqttChannel; +import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.context.ReceiveContext; +import io.github.quickmsg.common.message.ClusterMessage; +import io.github.quickmsg.common.message.HeapMqttMessage; +import io.github.quickmsg.common.message.SmqttMessage; import io.github.quickmsg.common.protocol.ProtocolAdaptor; +import io.github.quickmsg.common.rule.DslExecutor; import io.github.quickmsg.common.spi.DynamicLoader; +import io.github.quickmsg.common.utils.JacksonUtil; +import io.github.quickmsg.common.utils.MessageUtils; +import io.netty.handler.codec.mqtt.MqttFixedHeader; +import io.netty.handler.codec.mqtt.MqttMessage; +import io.netty.handler.codec.mqtt.MqttPublishMessage; +import io.netty.handler.codec.mqtt.MqttPublishVariableHeader; +import reactor.core.scheduler.Schedulers; +import reactor.netty.ReactorNetty; +import java.nio.charset.StandardCharsets; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; @@ -17,13 +33,89 @@ public class MessageProxy { .collect(Collectors.toList()); public ProtocolAdaptor proxy(ProtocolAdaptor protocolAdaptor) { - if (interceptors.size() > 0) { - for (Interceptor interceptor : interceptors) { - protocolAdaptor = interceptor.proxyProtocol(protocolAdaptor); + protocolAdaptor = new TailIntercept().proxyProtocol(protocolAdaptor); + for (Interceptor interceptor : interceptors) { + protocolAdaptor = interceptor.proxyProtocol(protocolAdaptor); + } + return new HeadIntercept().proxyProtocol(protocolAdaptor); + } + + static class TailIntercept implements Interceptor { + + @Override + @SuppressWarnings("unchecked") + public Object intercept(Invocation invocation) { + MqttChannel mqttChannel = (MqttChannel) invocation.getArgs()[0]; + SmqttMessage smqttMessage = (SmqttMessage) invocation.getArgs()[1]; + ReceiveContext mqttReceiveContext = (ReceiveContext) invocation.getArgs()[2]; + DslExecutor dslExecutor = mqttReceiveContext.getDslExecutor(); + MqttMessage message = smqttMessage.getMessage(); + if (!smqttMessage.getIsCluster() && message instanceof MqttPublishMessage) { + MqttPublishMessage publishMessage = (MqttPublishMessage) message; + HeapMqttMessage heapMqttMessage = this.clusterMessage(publishMessage, mqttChannel, smqttMessage.getTimestamp()); + if (mqttReceiveContext.getConfiguration().getClusterConfig().isEnable()) { + mqttReceiveContext.getClusterRegistry().spreadPublishMessage(new ClusterMessage(heapMqttMessage)).subscribeOn(Schedulers.boundedElastic()).subscribe(); + } + if (dslExecutor.isExecute()) { + dslExecutor.executeRule(mqttChannel, heapMqttMessage, mqttReceiveContext); + } } + return invocation.proceed(); + } + + + /** + * 构建消息体 + * + * @param message {@link MqttPublishMessage} + * @param timestamp + * @return {@link HeapMqttMessage} + */ + private HeapMqttMessage clusterMessage(MqttPublishMessage message, MqttChannel channel, long timestamp) { + MqttPublishVariableHeader header = message.variableHeader(); + MqttFixedHeader fixedHeader = message.fixedHeader(); + return HeapMqttMessage.builder() + .timestamp(timestamp) + .clientIdentifier(channel.getClientIdentifier()) + .message(JacksonUtil.dynamic(new String(MessageUtils.copyReleaseByteBuf(message.payload()), StandardCharsets.UTF_8))) + .topic(header.topicName()) + .retain(fixedHeader.isRetain()) + .qos(fixedHeader.qosLevel().value()) + .properties(header.properties()) + .build(); + } + + @Override + public int sort() { + return 0; } - return protocolAdaptor; } + static class HeadIntercept implements Interceptor { + + @Override + @SuppressWarnings("unchecked") + public Object intercept(Invocation invocation) { + SmqttMessage smqttMessage = (SmqttMessage) invocation.getArgs()[1]; + MqttMessage message = smqttMessage.getMessage(); + try { + if (message instanceof MqttPublishMessage) { + MqttPublishMessage publishMessage = (MqttPublishMessage) message; + publishMessage.retain(); + } + return invocation.proceed(); + } finally { + if (smqttMessage.getIsCluster()) { + ReactorNetty.safeRelease(message.payload()); + } + } + + } + + @Override + public int sort() { + return 0; + } + } } diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/message/CloseMqttMessage.java b/smqtt-common/src/main/java/io/github/quickmsg/common/message/CloseMqttMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..9983e2d8a8960f423480dbb982176b161493b342 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/message/CloseMqttMessage.java @@ -0,0 +1,13 @@ +package io.github.quickmsg.common.message; + +import lombok.Data; + +/** + * @author luxurong + */ +@Data +public class CloseMqttMessage { + + private String clientIdentifier; + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/message/ClusterMessage.java b/smqtt-common/src/main/java/io/github/quickmsg/common/message/ClusterMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..558ecda43a8635bc653318741f4d57793dc47369 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/message/ClusterMessage.java @@ -0,0 +1,35 @@ +package io.github.quickmsg.common.message; + +import lombok.Data; + +/** + * @author luxurong + */ +@Data +public class ClusterMessage { + + public ClusterMessage(){} + + private ClusterEvent clusterEvent; + + private Object message; + + public static enum ClusterEvent{ + + PUBLISH, + + CLOSE + + } + + public ClusterMessage(HeapMqttMessage heapMqttMessage){ + this.clusterEvent = ClusterEvent.PUBLISH; + this.message= heapMqttMessage; + } + + public ClusterMessage(CloseMqttMessage closeMqttMessage){ + this.clusterEvent = ClusterEvent.CLOSE; + this.message= closeMqttMessage; + } + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/message/EventRegistry.java b/smqtt-common/src/main/java/io/github/quickmsg/common/message/EventRegistry.java new file mode 100644 index 0000000000000000000000000000000000000000..630d73ca20c09595a84ee7cccb5007e05ccccbef --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/message/EventRegistry.java @@ -0,0 +1,25 @@ +package io.github.quickmsg.common.message; + +import io.github.quickmsg.common.channel.MqttChannel; +import io.github.quickmsg.common.context.ReceiveContext; +import io.github.quickmsg.common.enums.Event; + +import java.util.Map; + +/** + * @author luxurong + */ +public interface EventRegistry { + + + /** + * message + * + * @param event {@link Event} + * @param mqttChannel {@link MqttChannel} + * @param body {@link Object} + * @param receiveContext {@link ReceiveContext} + */ + void registry(Event event, MqttChannel mqttChannel, Object body, ReceiveContext receiveContext); + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/message/HeapMqttMessage.java b/smqtt-common/src/main/java/io/github/quickmsg/common/message/HeapMqttMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..082942c17853c5f8e92eaaca806ca888fbc6f624 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/message/HeapMqttMessage.java @@ -0,0 +1,49 @@ +package io.github.quickmsg.common.message; + +import io.github.quickmsg.common.utils.JacksonUtil; +import io.netty.handler.codec.mqtt.MqttProperties; +import io.netty.util.internal.StringUtil; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author luxurong + */ +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Data +public class HeapMqttMessage { + + private long timestamp; + + private String clientIdentifier; + + private String topic; + + private int qos; + + private boolean retain; + + private Object message; + + private MqttProperties properties; + + + public Map getKeyMap() { + Map keys = new HashMap<>(5); + keys.put("clientIdentifier", this.clientIdentifier); + keys.put("topic", this.topic); + keys.put("qos", this.qos); + keys.put("retain", this.retain); + keys.put("msg", message); + return keys; + } + + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/message/HttpPublishMessage.java b/smqtt-common/src/main/java/io/github/quickmsg/common/message/HttpPublishMessage.java index 3eea55af5cb4aabdc9616b422851eb6ea7a1ea6e..209431b12869d857e858348aecc9cd0ffb69b5cb 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/message/HttpPublishMessage.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/message/HttpPublishMessage.java @@ -5,6 +5,7 @@ import io.netty.handler.codec.mqtt.MqttPublishMessage; import io.netty.handler.codec.mqtt.MqttQoS; import lombok.Data; +import java.nio.charset.StandardCharsets; import java.util.Map; /** @@ -31,7 +32,7 @@ public class HttpPublishMessage { retain, 1, topic, - PooledByteBufAllocator.DEFAULT.buffer().writeBytes(message.getBytes())); + PooledByteBufAllocator.DEFAULT.buffer().writeBytes(message.getBytes(StandardCharsets.UTF_8))); } diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/message/JsonMap.java b/smqtt-common/src/main/java/io/github/quickmsg/common/message/JsonMap.java new file mode 100644 index 0000000000000000000000000000000000000000..345b75e0997bf46605f7104f6eb15fbf5c26119e --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/message/JsonMap.java @@ -0,0 +1,25 @@ +package io.github.quickmsg.common.message; + +import io.github.quickmsg.common.utils.JacksonUtil; + +import java.util.HashMap; + +/** + * @author luxurong + */ +public class JsonMap extends HashMap { + + public JsonMap() { + super(); + } + + + public JsonMap(int initialCapacity) { + super(initialCapacity); + } + + @Override + public String toString() { + return JacksonUtil.map2Json(this); + } +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/message/MessageRegistry.java b/smqtt-common/src/main/java/io/github/quickmsg/common/message/MessageRegistry.java index b3db4528c8f889672253ce460b66f72b71061bc4..c21887dba432d7aa5498b958707ec25a005e632f 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/message/MessageRegistry.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/message/MessageRegistry.java @@ -17,7 +17,7 @@ public interface MessageRegistry extends StartUp { * 获取连接下线后的session消息 * * @param clientIdentifier 设备id - * @return {@link List} + * @return {@link SessionMessage} */ List getSessionMessage(String clientIdentifier); @@ -42,7 +42,7 @@ public interface MessageRegistry extends StartUp { * 保留Topic保留消息 * * @param topic topic - * @return {@link List} + * @return {@link RetainMessage} */ List getRetainMessage(String topic); diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/message/MqttMessageBuilder.java b/smqtt-common/src/main/java/io/github/quickmsg/common/message/MqttMessageBuilder.java index 8e0828a96c51ba9cbed81f98564098399b44aa2d..f3ef36a646bdead695c6d8c7d1b34266ebb2e84a 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/message/MqttMessageBuilder.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/message/MqttMessageBuilder.java @@ -4,6 +4,13 @@ import io.netty.buffer.ByteBuf; import io.netty.handler.codec.mqtt.*; import java.util.List; +import java.util.Map; + +import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_REFUSED_BAD_USERNAME_OR_PASSWORD; +import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_REFUSED_CLIENT_IDENTIFIER_NOT_VALID; +import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_REFUSED_NOT_AUTHORIZED_5; +import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE_5; +import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_REFUSED_UNSUPPORTED_PROTOCOL_VERSION; /** @@ -11,6 +18,32 @@ import java.util.List; */ public class MqttMessageBuilder { + private static MqttProperties genMqttProperties(Map userPropertiesMap) { + MqttProperties mqttProperties = null; + if (userPropertiesMap != null) { + mqttProperties = new MqttProperties(); + MqttProperties.UserProperties userProperties = new MqttProperties.UserProperties(); + for (Map.Entry entry : userPropertiesMap.entrySet()) { + userProperties.add(entry.getKey(), entry.getValue()); + } + mqttProperties.add(userProperties); + } + return mqttProperties; + } + + public static MqttPublishMessage buildPub(boolean isDup, MqttQoS qoS, int messageId, String topic, ByteBuf message, MqttProperties properties) { + MqttFixedHeader mqttFixedHeader = new MqttFixedHeader(MqttMessageType.PUBLISH, isDup, qoS, false, 0); + MqttPublishVariableHeader mqttPublishVariableHeader = new MqttPublishVariableHeader(topic, messageId, properties); + MqttPublishMessage mqttPublishMessage = new MqttPublishMessage(mqttFixedHeader, mqttPublishVariableHeader, message); + return mqttPublishMessage; + } + + public static MqttPublishMessage buildPub(boolean isDup, MqttQoS qoS, int messageId, String topic, ByteBuf message, Map userPropertiesMap) { + MqttFixedHeader mqttFixedHeader = new MqttFixedHeader(MqttMessageType.PUBLISH, isDup, qoS, false, 0); + MqttPublishVariableHeader mqttPublishVariableHeader = new MqttPublishVariableHeader(topic, messageId, genMqttProperties(userPropertiesMap)); + MqttPublishMessage mqttPublishMessage = new MqttPublishMessage(mqttFixedHeader, mqttPublishVariableHeader, message); + return mqttPublishMessage; + } public static MqttPublishMessage buildPub(boolean isDup, MqttQoS qoS, int messageId, String topic, ByteBuf message) { MqttFixedHeader mqttFixedHeader = new MqttFixedHeader(MqttMessageType.PUBLISH, isDup, qoS, false, 0); @@ -69,8 +102,35 @@ public class MqttMessageBuilder { return new MqttUnsubAckMessage(mqttFixedHeader, variableHeader); } - public static MqttConnAckMessage buildConnectAck(MqttConnectReturnCode connectReturnCode) { - MqttConnAckVariableHeader mqttConnAckVariableHeader = new MqttConnAckVariableHeader(connectReturnCode, true); + public static MqttConnAckMessage buildConnectAck(MqttConnectReturnCode connectReturnCode, byte version) { + MqttProperties properties = MqttProperties.NO_PROPERTIES; + if (MqttVersion.MQTT_5.protocolLevel() == version) { + properties = new MqttProperties(); + // support retain msg + properties.add(new MqttProperties.IntegerProperty(MqttProperties.MqttPropertyType.RETAIN_AVAILABLE.value(), 1)); + // don't support shared subscription + properties.add(new MqttProperties.IntegerProperty(MqttProperties.MqttPropertyType.SHARED_SUBSCRIPTION_AVAILABLE.value(), 0)); + // mqtt3.0 error code transform + switch (connectReturnCode) { + case CONNECTION_REFUSED_IDENTIFIER_REJECTED: + connectReturnCode = CONNECTION_REFUSED_CLIENT_IDENTIFIER_NOT_VALID; + break; + case CONNECTION_REFUSED_UNACCEPTABLE_PROTOCOL_VERSION: + connectReturnCode = CONNECTION_REFUSED_UNSUPPORTED_PROTOCOL_VERSION; + break; + case CONNECTION_REFUSED_SERVER_UNAVAILABLE: + connectReturnCode = CONNECTION_REFUSED_SERVER_UNAVAILABLE_5; + break; + case CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD: + connectReturnCode = CONNECTION_REFUSED_BAD_USERNAME_OR_PASSWORD; + break; + case CONNECTION_REFUSED_NOT_AUTHORIZED: + connectReturnCode = CONNECTION_REFUSED_NOT_AUTHORIZED_5; + break; + + } + } + MqttConnAckVariableHeader mqttConnAckVariableHeader = new MqttConnAckVariableHeader(connectReturnCode, false, properties); MqttFixedHeader mqttFixedHeader = new MqttFixedHeader( MqttMessageType.CONNACK, false, MqttQoS.AT_MOST_ONCE, false, 0X02); return new MqttConnAckMessage(mqttFixedHeader, mqttConnAckVariableHeader); diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/message/RetainMessage.java b/smqtt-common/src/main/java/io/github/quickmsg/common/message/RetainMessage.java index fbc623529cdcbc7e0f9fb110feb2f8899ebc30e4..2d67c21e50281155a26fec9f839a6bfa3c8929a7 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/message/RetainMessage.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/message/RetainMessage.java @@ -1,8 +1,13 @@ package io.github.quickmsg.common.message; +import java.util.HashMap; +import java.util.Optional; + import io.github.quickmsg.common.channel.MqttChannel; +import io.github.quickmsg.common.utils.JacksonUtil; import io.github.quickmsg.common.utils.MessageUtils; import io.netty.buffer.PooledByteBufAllocator; +import io.netty.handler.codec.mqtt.MqttProperties; import io.netty.handler.codec.mqtt.MqttPublishMessage; import io.netty.handler.codec.mqtt.MqttPublishVariableHeader; import io.netty.handler.codec.mqtt.MqttQoS; @@ -22,12 +27,25 @@ public class RetainMessage { private byte[] body; + private String userProperties; + public static RetainMessage of(MqttPublishMessage mqttPublishMessage) { MqttPublishVariableHeader publishVariableHeader = mqttPublishMessage.variableHeader(); return RetainMessage.builder() .topic(publishVariableHeader.topicName()) .qos(mqttPublishMessage.fixedHeader().qosLevel().value()) .body(MessageUtils.copyByteBuf(mqttPublishMessage.payload())) + .userProperties(JacksonUtil.map2Json(Optional.ofNullable(publishVariableHeader + .properties() + .getProperties(MqttProperties.MqttPropertyType.USER_PROPERTY.value())) + .map(list -> { + HashMap propertiesMap = new HashMap<>(list.size()); + list.forEach(property -> { + MqttProperties.StringPair pair = (MqttProperties.StringPair) property.value(); + propertiesMap.put(pair.key, pair.value); + }); + return propertiesMap; + }).orElseGet(HashMap::new))) .build(); } @@ -37,7 +55,8 @@ public class RetainMessage { MqttQoS.valueOf(this.qos), qos > 0 ? mqttChannel.generateMessageId() : 0, topic, - PooledByteBufAllocator.DEFAULT.directBuffer().writeBytes(body)); + PooledByteBufAllocator.DEFAULT.directBuffer().writeBytes(body), + JacksonUtil.json2Map(userProperties, String.class, String.class)); } } diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/message/SessionMessage.java b/smqtt-common/src/main/java/io/github/quickmsg/common/message/SessionMessage.java index a3596af3aa8e4686cf1786d39598480c42efc2d8..f5aecea5ff339c029a868517f2e1d7fb8c243de8 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/message/SessionMessage.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/message/SessionMessage.java @@ -1,8 +1,13 @@ package io.github.quickmsg.common.message; +import java.util.HashMap; +import java.util.Optional; + import io.github.quickmsg.common.channel.MqttChannel; +import io.github.quickmsg.common.utils.JacksonUtil; import io.github.quickmsg.common.utils.MessageUtils; import io.netty.buffer.PooledByteBufAllocator; +import io.netty.handler.codec.mqtt.MqttProperties; import io.netty.handler.codec.mqtt.MqttPublishMessage; import io.netty.handler.codec.mqtt.MqttPublishVariableHeader; import io.netty.handler.codec.mqtt.MqttQoS; @@ -27,6 +32,8 @@ public class SessionMessage { private boolean retain; + private String userProperties; + public static SessionMessage of(String clientIdentifier, MqttPublishMessage mqttPublishMessage) { MqttPublishVariableHeader publishVariableHeader = mqttPublishMessage.variableHeader(); return SessionMessage.builder() @@ -35,6 +42,17 @@ public class SessionMessage { .qos(mqttPublishMessage.fixedHeader().qosLevel().value()) .retain(mqttPublishMessage.fixedHeader().isRetain()) .body(MessageUtils.copyByteBuf(mqttPublishMessage.payload())) + .userProperties(JacksonUtil.map2Json(Optional.ofNullable(publishVariableHeader + .properties() + .getProperties(MqttProperties.MqttPropertyType.USER_PROPERTY.value())) + .map(list -> { + HashMap propertiesMap = new HashMap<>(list.size()); + list.forEach(property -> { + MqttProperties.StringPair pair = (MqttProperties.StringPair) property.value(); + propertiesMap.put(pair.key, pair.value); + }); + return propertiesMap; + }).orElseGet(HashMap::new))) .build(); } @@ -44,7 +62,8 @@ public class SessionMessage { MqttQoS.valueOf(this.qos), qos > 0 ? mqttChannel.generateMessageId() : 0, topic, - PooledByteBufAllocator.DEFAULT.directBuffer().writeBytes(body)); + PooledByteBufAllocator.DEFAULT.directBuffer().writeBytes(body), + JacksonUtil.json2Map(userProperties, String.class, String.class)); } } diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/message/SmqttMessage.java b/smqtt-common/src/main/java/io/github/quickmsg/common/message/SmqttMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..a08d9fadf92972d2a5044fddee96ea169ff3e4b8 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/message/SmqttMessage.java @@ -0,0 +1,24 @@ +package io.github.quickmsg.common.message; + +import io.netty.handler.codec.mqtt.MqttMessage; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +/** + * @author luxurong + */ +@Getter +@Setter +@ToString + @AllArgsConstructor +public class SmqttMessage { + + private T message; + + private long timestamp; + + private Boolean isCluster; + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/message/system/ChannelStatusMessage.java b/smqtt-common/src/main/java/io/github/quickmsg/common/message/system/ChannelStatusMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..1a208c99c213070e7326f3aa76487d1edabb4c5b --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/message/system/ChannelStatusMessage.java @@ -0,0 +1,38 @@ +package io.github.quickmsg.common.message.system; + +import io.github.quickmsg.common.enums.ChannelStatus; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author luxurong + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ChannelStatusMessage { + + /** + * clint id + */ + private String clientIdentifier; + + /** + * timestamp + */ + private long timestamp; + + /** + * username + */ + private String username; + + /** + * channelStatus + * + * @see ChannelStatus + */ + private ChannelStatus channelStatus; + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/metric/AbstractMetricRegistry.java b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/AbstractMetricRegistry.java new file mode 100644 index 0000000000000000000000000000000000000000..dfb29822a80f86d193c000620540b2b6d3713514 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/AbstractMetricRegistry.java @@ -0,0 +1,23 @@ +package io.github.quickmsg.common.metric; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author luxurong + */ +public abstract class AbstractMetricRegistry implements MetricRegistry { + + + private final Map metricCounterMap = new HashMap<>(); + + protected AbstractMetricRegistry(List metricCounters) { + metricCounters.forEach(metricCounter -> metricCounterMap.put(metricCounter.getCounterType(), metricCounter)); + } + + @Override + public MetricCounter getMetricCounter(CounterType counterType) { + return metricCounterMap.get(counterType); + } +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/metric/CounterType.java b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/CounterType.java new file mode 100644 index 0000000000000000000000000000000000000000..89a711af8727abce22f1381705d3d90a993c8989 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/CounterType.java @@ -0,0 +1,26 @@ +package io.github.quickmsg.common.metric; + +import lombok.Getter; + +/** + * @author luxurong + */ +@Getter +public enum CounterType { + + CONNECT("smqtt.connect.count"), + SUBSCRIBE("smqtt.subscribe.count"), + + PUBLISH_EVENT("smqtt.publish.event.count"), + CONNECT_EVENT("smqtt.connect.event.count"), + SUBSCRIBE_EVENT("smqtt.subscribe.event.count"), + UN_SUBSCRIBE_EVENT("smqtt.unscribe.event.count"), + DIS_CONNECT_EVENT("smqtt.disconnect.event.count"), + CLOSE_EVENT("smqtt.close.event.count"); + + private final String desc; + + CounterType(String desc) { + this.desc = desc; + } +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/metric/EventCounter.java b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/EventCounter.java new file mode 100644 index 0000000000000000000000000000000000000000..a63f4aed5fa22a70be47855b899ca9a21899a38c --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/EventCounter.java @@ -0,0 +1,39 @@ +package io.github.quickmsg.common.metric; + +import io.github.quickmsg.common.metric.CounterType; +import io.github.quickmsg.common.metric.MetricBean; +import io.github.quickmsg.common.metric.WholeCounter; +import io.micrometer.core.instrument.Counter; + +/** + * @author luxurong + */ +public class EventCounter extends WholeCounter { + + private CounterType counterType; + + private Counter counter; + + public EventCounter(MetricBean metricBean, CounterType counterType) { + super(metricBean); + this.counterType = counterType; + initCount(); + } + + @Override + public void initCount() { + this.counter = + getMetricBean() + .getMeterRegistry().counter(getCounterType().getDesc(), getMetricBean().getTags()); + } + + @Override + public void callMeter(long count) { + counter.increment(); + } + + @Override + public CounterType getCounterType() { + return this.counterType; + } +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/metric/MeterType.java b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/MeterType.java new file mode 100644 index 0000000000000000000000000000000000000000..65390f3f2a4c3495dfb471410ee70d35debcac89 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/MeterType.java @@ -0,0 +1,12 @@ +package io.github.quickmsg.common.metric; + +/** + * @author luxurong + */ +public enum MeterType { + + INFLUXDB, + + PROMETHEUS + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/metric/MetricBean.java b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/MetricBean.java new file mode 100644 index 0000000000000000000000000000000000000000..057b8d25f9533d122d0fa79839a97aac3e1f83b6 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/MetricBean.java @@ -0,0 +1,18 @@ +package io.github.quickmsg.common.metric; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tags; + +/** + * @author luxurong + */ +public interface MetricBean { + + MetricBean Close(); + + MeterRegistry getMeterRegistry(); + + default Tags getTags() { + return Tags.empty().and(MetricConstant.COMMON_TAG_NAME, MetricConstant.COMMON_TAG_VALUE); + } +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/metric/MetricConstant.java b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/MetricConstant.java new file mode 100644 index 0000000000000000000000000000000000000000..967c4372b8d79aab6f6f201c5dfbfcdb60f373c1 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/MetricConstant.java @@ -0,0 +1,10 @@ +package io.github.quickmsg.common.metric; + +public interface MetricConstant { + + String COMMON_TAG_NAME = "application"; + + String COMMON_TAG_VALUE = "smqtt"; + + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/metric/MetricCounter.java b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/MetricCounter.java new file mode 100644 index 0000000000000000000000000000000000000000..b08e8890d6e542117b7f302f9d8c5a01fa759ae1 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/MetricCounter.java @@ -0,0 +1,26 @@ +package io.github.quickmsg.common.metric; + +/** + * @author luxurong + */ +public interface MetricCounter { + + long getCounter(); + + void increment(); + + void decrement(); + + void reset(); + + void callMeter(long counter); + + MetricBean getMetricBean(); + + CounterType getCounterType(); + + + + + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/metric/MetricFactory.java b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/MetricFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..7af65352e0d68230d068562c0b811ec0e6ad2432 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/MetricFactory.java @@ -0,0 +1,12 @@ +package io.github.quickmsg.common.metric; + + +/** + * @author luxurong + */ +public interface MetricFactory { + + MetricManager getMetricManager(); + + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/metric/MetricManager.java b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/MetricManager.java new file mode 100644 index 0000000000000000000000000000000000000000..4519c81e99925aa06634fcb33d6f55b58074c4e0 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/MetricManager.java @@ -0,0 +1,146 @@ +package io.github.quickmsg.common.metric; + +import io.github.quickmsg.common.config.BootstrapConfig; +import io.github.quickmsg.common.context.ContextHolder; +import io.github.quickmsg.common.utils.FormatUtils; +import io.micrometer.prometheus.PrometheusMeterRegistry; +import io.netty.handler.traffic.TrafficCounter; +import io.prometheus.client.exporter.common.TextFormat; +import oshi.SystemInfo; +import oshi.hardware.CentralProcessor; +import oshi.hardware.HardwareAbstractionLayer; +import oshi.util.Util; + +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; +import java.lang.management.RuntimeMXBean; +import java.lang.management.ThreadMXBean; +import java.text.DecimalFormat; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * @author luxurong + */ +public interface MetricManager { + + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + MetricRegistry getMetricRegistry(); + + MetricBean getMetricBean(); + + BootstrapConfig.MeterConfig getMeterConfig(); + + default Map getJvmMetric() { + Map metrics = new HashMap<>(); + Properties props = System.getProperties(); + MemoryMXBean mxb = ManagementFactory.getMemoryMXBean(); + ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); + RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean(); + metrics.put("smqtt", "1.1.4"); + metrics.put("start_time", sdf.format(new Date(runtimeBean.getStartTime()))); + metrics.put("jdk_home", props.getProperty("java.home")); + metrics.put("jdk_version", props.getProperty("java.version")); + metrics.put("thread.count", threadBean.getThreadCount()); + metrics.put("heap-max", FormatUtils.formatByte(mxb.getHeapMemoryUsage().getMax())); + metrics.put("heap-init", FormatUtils.formatByte(mxb.getHeapMemoryUsage().getInit())); + metrics.put("heap-commit", FormatUtils.formatByte(mxb.getHeapMemoryUsage().getCommitted())); + metrics.put("heap-used", FormatUtils.formatByte(mxb.getHeapMemoryUsage().getUsed())); + metrics.put("no_heap-max", FormatUtils.formatByte(mxb.getNonHeapMemoryUsage().getMax())); + metrics.put("no_heap-init", FormatUtils.formatByte(mxb.getNonHeapMemoryUsage().getInit())); + metrics.put("no_heap-commit", FormatUtils.formatByte(mxb.getNonHeapMemoryUsage().getCommitted())); + metrics.put("no_heap-used", FormatUtils.formatByte(mxb.getNonHeapMemoryUsage().getUsed())); + return metrics; + } + + SystemInfo systemInfo = new SystemInfo(); + + int O_SHI_WAIT_SECOND = 500; + + + default Map getCpuMetric() { + HardwareAbstractionLayer hardware = systemInfo.getHardware(); + Map metrics = new HashMap<>(); + CentralProcessor processor = hardware.getProcessor(); + // CPU信息 + long[] prevTicks = processor.getSystemCpuLoadTicks(); + Util.sleep(O_SHI_WAIT_SECOND); + long[] ticks = processor.getSystemCpuLoadTicks(); + long nice = ticks[CentralProcessor.TickType.NICE.getIndex()] - prevTicks[CentralProcessor.TickType.NICE.getIndex()]; + long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()] - prevTicks[CentralProcessor.TickType.IRQ.getIndex()]; + long softirq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()] - prevTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()]; + long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()] - prevTicks[CentralProcessor.TickType.STEAL.getIndex()]; + long cSys = ticks[CentralProcessor.TickType.SYSTEM.getIndex()] - prevTicks[CentralProcessor.TickType.SYSTEM.getIndex()]; + long user = ticks[CentralProcessor.TickType.USER.getIndex()] - prevTicks[CentralProcessor.TickType.USER.getIndex()]; + long iowait = ticks[CentralProcessor.TickType.IOWAIT.getIndex()] - prevTicks[CentralProcessor.TickType.IOWAIT.getIndex()]; + long idle = ticks[CentralProcessor.TickType.IDLE.getIndex()] - prevTicks[CentralProcessor.TickType.IDLE.getIndex()]; + long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal; + //cpu核数 + metrics.put("cpuNum", processor.getLogicalProcessorCount()); + //cpu系统使用率 + metrics.put("cSys", new DecimalFormat("#.##%").format(cSys * 1.0 / totalCpu)); + //cpu用户使用率 + metrics.put("user", new DecimalFormat("#.##%").format(user * 1.0 / totalCpu)); + //cpu当前等待率 + metrics.put("iowait", new DecimalFormat("#.##%").format(iowait * 1.0 / totalCpu)); + //cpu当前使用率 + metrics.put("idle", new DecimalFormat("#.##%").format(1.0 - (idle * 1.0 / totalCpu))); + return metrics; + } + + default Map getCounterMetric() { + Map metrics = new HashMap<>(); + metrics.put("all_connect_size", getMetricRegistry().getMetricCounter(CounterType.CONNECT).getCounter()); + metrics.put("all_subscribe_size", getMetricRegistry().getMetricCounter(CounterType.SUBSCRIBE).getCounter()); + metrics.put("connect_size", getMetricRegistry().getMetricCounter(CounterType.CONNECT_EVENT).getCounter()); + metrics.put("subscribe_size", getMetricRegistry().getMetricCounter(CounterType.SUBSCRIBE_EVENT).getCounter()); + metrics.put("publish_size", getMetricRegistry().getMetricCounter(CounterType.PUBLISH_EVENT).getCounter()); + metrics.put("disconnect_size", getMetricRegistry().getMetricCounter(CounterType.DIS_CONNECT_EVENT).getCounter()); + metrics.put("un_subscribe_size", getMetricRegistry().getMetricCounter(CounterType.UN_SUBSCRIBE_EVENT).getCounter()); + metrics.put("un_close_size", getMetricRegistry().getMetricCounter(CounterType.CLOSE_EVENT).getCounter()); + TrafficCounter trafficCounter = ContextHolder.getReceiveContext().getTrafficHandlerLoader().get().trafficCounter(); + metrics.put("read_size", FormatUtils.formatByte(trafficCounter.cumulativeReadBytes())); + metrics.put("read_second_size", FormatUtils.formatByte(trafficCounter.currentReadBytes())); + metrics.put("write_size", FormatUtils.formatByte(trafficCounter.cumulativeWrittenBytes())); + metrics.put("write_second_size", FormatUtils.formatByte(trafficCounter.currentWrittenBytes())); + return metrics; + } + + + + + default Map getEventMetric() { + Map metrics = new HashMap<>(); + metrics.put("connect_size", getMetricRegistry().getMetricCounter(CounterType.CONNECT_EVENT).getCounter()); + metrics.put("subscribe_size", getMetricRegistry().getMetricCounter(CounterType.SUBSCRIBE_EVENT).getCounter()); + metrics.put("publish_size", getMetricRegistry().getMetricCounter(CounterType.PUBLISH_EVENT).getCounter()); + metrics.put("disconnect_size", getMetricRegistry().getMetricCounter(CounterType.DIS_CONNECT_EVENT).getCounter()); + metrics.put("un_subscribe_size", getMetricRegistry().getMetricCounter(CounterType.UN_SUBSCRIBE_EVENT).getCounter()); + metrics.put("close_size", getMetricRegistry().getMetricCounter(CounterType.CLOSE_EVENT).getCounter()); + return metrics; + } + + default String scrape() { + if (getMetricBean().getMeterRegistry() instanceof PrometheusMeterRegistry) { + return ((PrometheusMeterRegistry) getMetricBean().getMeterRegistry()).scrape(TextFormat.CONTENT_TYPE_OPENMETRICS_100); + } else { + return null; + } + } + + + default List createMetricRegistry(MetricBean metricBean) { + List metricCounters = new ArrayList<>(); + metricCounters.add(new EventCounter(metricBean,CounterType.CONNECT_EVENT)); + metricCounters.add(new EventCounter(metricBean,CounterType.PUBLISH_EVENT)); + metricCounters.add(new EventCounter(metricBean,CounterType.SUBSCRIBE_EVENT)); + metricCounters.add(new EventCounter(metricBean,CounterType.UN_SUBSCRIBE_EVENT)); + metricCounters.add(new EventCounter(metricBean,CounterType.DIS_CONNECT_EVENT)); + metricCounters.add(new EventCounter(metricBean,CounterType.CLOSE_EVENT)); + metricCounters.add(new TotalCounter(metricBean,CounterType.CONNECT)); + metricCounters.add(new TotalCounter(metricBean,CounterType.SUBSCRIBE)); + return metricCounters; + } + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/metric/MetricManagerHolder.java b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/MetricManagerHolder.java new file mode 100644 index 0000000000000000000000000000000000000000..60c46d9330d6a40d92d10a701423150c662fc8f9 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/MetricManagerHolder.java @@ -0,0 +1,28 @@ +package io.github.quickmsg.common.metric; + +import lombok.Getter; + +import java.util.Optional; + +/** + * @author luxurong + */ +@Getter +public class MetricManagerHolder { + + public static MetricManager metricManager = null; + + public static MetricManager setMetricManager(MetricManager metricManager){ + MetricManagerHolder.metricManager = metricManager; + return metricManager; + } + + public static Optional getMetricRegistry(){ + return Optional.of(metricManager).map(MetricManager::getMetricRegistry); + } + + public static MetricManager getMetricManager(){ + return metricManager; + } + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/metric/MetricRegistry.java b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/MetricRegistry.java new file mode 100644 index 0000000000000000000000000000000000000000..d376aace34e6a7a54bca3c1a18852e0f9728f43f --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/MetricRegistry.java @@ -0,0 +1,13 @@ +package io.github.quickmsg.common.metric; + + +/** + * @author luxurong + */ +public interface MetricRegistry { + + MetricCounter getMetricCounter(CounterType counterType); + + + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/metric/TotalCounter.java b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/TotalCounter.java new file mode 100644 index 0000000000000000000000000000000000000000..d7402b11d18f1d800502d5fe779afc325a4634db --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/TotalCounter.java @@ -0,0 +1,26 @@ +package io.github.quickmsg.common.metric; + +/** + * @author luxurong + */ +public class TotalCounter extends WholeCounter { + + private final CounterType counterType; + + public TotalCounter(MetricBean metricBean, CounterType counterType) { + super(metricBean); + this.counterType = counterType; + initCount(); + } + + + @Override + public void callMeter(long counter) { + getMetricBean().getMeterRegistry().gauge(getCounterType().getDesc(), counter); + } + + @Override + public CounterType getCounterType() { + return this.counterType; + } +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/metric/WholeCounter.java b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/WholeCounter.java new file mode 100644 index 0000000000000000000000000000000000000000..e41d2ba2e8ff732bce79b29fdea2cc5dd2a4d11b --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/WholeCounter.java @@ -0,0 +1,50 @@ +package io.github.quickmsg.common.metric; + +import java.util.concurrent.atomic.AtomicLong; + +/** + * @author luxurong + */ +public abstract class WholeCounter implements MetricCounter { + + + private final AtomicLong count = new AtomicLong(); + + private final MetricBean metricBean; + + protected WholeCounter(MetricBean metricBean) { + this.metricBean = metricBean; + } + + public void initCount() { + getMetricBean().getMeterRegistry().gauge(getCounterType().getDesc(), count); + } + + @Override + public MetricBean getMetricBean() { + return this.metricBean; + } + + @Override + public void increment() { + callMeter(count.incrementAndGet()); + } + + @Override + public void decrement() { + callMeter(count.decrementAndGet()); + } + + @Override + public void reset() { + count.set(0); + } + + + @Override + public long getCounter() { + return count.get(); + } + + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/metric/WindowCounter.java b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/WindowCounter.java new file mode 100644 index 0000000000000000000000000000000000000000..9231fd978f021bfa8e47b0120491d9f8975d330f --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/WindowCounter.java @@ -0,0 +1,70 @@ +package io.github.quickmsg.common.metric; + +import reactor.core.scheduler.Scheduler; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.LongAdder; + +/** + * @author luxurong + */ +public abstract class WindowCounter implements MetricCounter, Runnable { + + private final LongAdder sumCountAdder = new LongAdder(); + + private final LongAdder windowCountAdder = new LongAdder(); + + + private final MetricBean metricBean; + + + @Override + public MetricBean getMetricBean() { + return this.metricBean; + } + + public WindowCounter(MetricBean metricBean, Integer time, TimeUnit timeUnit, Scheduler scheduler) { + this.metricBean = metricBean; + scheduler.schedulePeriodically(this, time, time, timeUnit); + scheduler.start(); + } + + @Override + public void reset() { + sumCountAdder.reset(); + windowCountAdder.reset(); + } + + public void run() { + windowCountAdder.reset(); + } + + @Override + public long getCounter() { + return this.sumCountAdder.sum(); + } + + + public long getAllCount() { + return this.sumCountAdder.sum(); + } + + + @Override + public void increment() { + sumCountAdder.increment(); + callMeter(sumCountAdder.sum()); + } + + @Override + public void decrement() { + throw new UnsupportedOperationException("WindowCounter not support decrement"); + } + + + public long getWindowCount() { + return windowCountAdder.sum(); + } + + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/metric/local/EmptyMetricCounter.java b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/local/EmptyMetricCounter.java new file mode 100644 index 0000000000000000000000000000000000000000..943f7b36e78941545d0d63a8e8b09f890d0f9865 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/local/EmptyMetricCounter.java @@ -0,0 +1,50 @@ +package io.github.quickmsg.common.metric.local; + +import io.github.quickmsg.common.metric.CounterType; +import io.github.quickmsg.common.metric.MetricBean; +import io.github.quickmsg.common.metric.WholeCounter; + +/** + * @author luxurong + */ +public class EmptyMetricCounter extends WholeCounter { + + private final static EmptyMetricCounter metricCounter = new EmptyMetricCounter(); + + private EmptyMetricCounter(){ + super(null); + } + + public static EmptyMetricCounter instance(){ + return metricCounter; + } + + protected EmptyMetricCounter(MetricBean metricBean) { + super(metricBean); + } + + @Override + public void callMeter(long counter) { + + } + + @Override + public CounterType getCounterType() { + return null; + } + + @Override + public void increment() { + + } + + @Override + public void decrement() { + + } + + @Override + public void reset() { + + } +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/metric/local/LocalMetricBean.java b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/local/LocalMetricBean.java new file mode 100644 index 0000000000000000000000000000000000000000..825c3319a1dfe3ac1cf172da39a9ec2f8361f8a7 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/local/LocalMetricBean.java @@ -0,0 +1,25 @@ +package io.github.quickmsg.common.metric.local; + +import io.github.quickmsg.common.metric.MetricBean; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.logging.LoggingMeterRegistry; + +/** + * @author luxurong + */ +public class LocalMetricBean implements MetricBean { + + + public LocalMetricBean() { + } + + @Override + public MetricBean Close() { + return this; + } + + @Override + public MeterRegistry getMeterRegistry() { + return null; + } +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/metric/local/LocalMetricManager.java b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/local/LocalMetricManager.java new file mode 100644 index 0000000000000000000000000000000000000000..173220b70b9af43131e6c5a614984ca50795ef8c --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/metric/local/LocalMetricManager.java @@ -0,0 +1,44 @@ +package io.github.quickmsg.common.metric.local; + +import io.github.quickmsg.common.config.BootstrapConfig; +import io.github.quickmsg.common.metric.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * @author luxurong + */ +public class LocalMetricManager implements MetricManager { + + public LocalMetricManager() { + } + + + @Override + public MetricRegistry getMetricRegistry() { + return new AbstractMetricRegistry(createMetricRegistry(getMetricBean())) { + @Override + public MetricCounter getMetricCounter(CounterType counterType) { + return EmptyMetricCounter.instance(); + } + }; + } + + + @Override + public MetricBean getMetricBean() { + return new LocalMetricBean(); + } + + @Override + public BootstrapConfig.MeterConfig getMeterConfig() { + return null; + } + + @Override + public List createMetricRegistry(MetricBean metricBean) { + return Collections.emptyList(); + } +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/protocol/Protocol.java b/smqtt-common/src/main/java/io/github/quickmsg/common/protocol/Protocol.java index dea03b615d6f8730c07f174be7b796334f73bdd4..e80148c68d2f52d12a2560b775e11c57138a11bc 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/protocol/Protocol.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/protocol/Protocol.java @@ -1,6 +1,8 @@ package io.github.quickmsg.common.protocol; import io.github.quickmsg.common.channel.MqttChannel; +import io.github.quickmsg.common.message.SmqttMessage; +import io.netty.handler.codec.mqtt.MqttMessage; import io.netty.handler.codec.mqtt.MqttMessageType; import reactor.core.publisher.Mono; import reactor.util.context.ContextView; @@ -10,17 +12,18 @@ import java.util.List; /** * @author luxurong */ -public interface Protocol { +public interface Protocol { /** * 解析协议添加上下文 * - * @param message 消息类型 - * @param mqttChannel 通道 - * @return 空操作符 + * @param message {@link SmqttMessage} + * @param mqttChannel {@link MqttChannel} + * @return Mono + * @see MqttMessage */ - default Mono doParseProtocol(T message, MqttChannel mqttChannel) { + default Mono doParseProtocol(SmqttMessage message, MqttChannel mqttChannel) { return Mono.deferContextual(contextView -> this.parseProtocol(message, mqttChannel, contextView)); } @@ -28,18 +31,19 @@ public interface Protocol { /** * 处理协议 * - * @param message 消息 - * @param mqttChannel 通道 - * @param contextView 上下文视图 - * @return 空操作符 + * @param message {@link SmqttMessage} + * @param mqttChannel {@link MqttChannel} + * @param contextView {@link ContextView} + * @see MqttMessage + * @return Mono */ - Mono parseProtocol(T message, MqttChannel mqttChannel, ContextView contextView); + Mono parseProtocol(SmqttMessage message, MqttChannel mqttChannel, ContextView contextView); /** * 获取此协议支持的消息类型 * - * @return List + * @return {@link MqttMessageType} */ List getMqttMessageTypes(); diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/protocol/ProtocolAdaptor.java b/smqtt-common/src/main/java/io/github/quickmsg/common/protocol/ProtocolAdaptor.java index 071a2631f9e41a57edb2e588407e59562784627e..20c74c675b5e60dd45388b0ed0de37f9dfdd4f5d 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/protocol/ProtocolAdaptor.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/protocol/ProtocolAdaptor.java @@ -5,6 +5,7 @@ import io.github.quickmsg.common.channel.MqttChannel; import io.github.quickmsg.common.config.Configuration; import io.github.quickmsg.common.context.ReceiveContext; import io.github.quickmsg.common.interceptor.MessageProxy; +import io.github.quickmsg.common.message.SmqttMessage; import io.github.quickmsg.common.spi.DynamicLoader; import io.netty.handler.codec.mqtt.MqttMessage; @@ -23,12 +24,13 @@ public interface ProtocolAdaptor { * 分发某种协议下 消息类型 * * @param mqttChannel {@link MqttChannel} - * @param mqttMessage {@link MqttMessage} + * @param mqttMessage {@link SmqttMessage} * @param receiveContext {@link ReceiveContext} * @param {@link Configuration} */ @Intercept - void chooseProtocol(MqttChannel mqttChannel, MqttMessage mqttMessage, ReceiveContext receiveContext); + void chooseProtocol(MqttChannel mqttChannel, SmqttMessage mqttMessage, ReceiveContext receiveContext); + /** diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/protocol/ProtocolAdaptorWrapper.java b/smqtt-common/src/main/java/io/github/quickmsg/common/protocol/ProtocolAdaptorWrapper.java deleted file mode 100644 index f0e43440992203db8ea11f668c2c6f0acb828faf..0000000000000000000000000000000000000000 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/protocol/ProtocolAdaptorWrapper.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.github.quickmsg.common.protocol; - -import io.github.quickmsg.common.channel.MqttChannel; -import io.github.quickmsg.common.config.Configuration; -import io.github.quickmsg.common.context.ReceiveContext; -import io.github.quickmsg.common.protocol.ProtocolAdaptor; -import io.netty.handler.codec.mqtt.MqttMessage; -import io.netty.handler.codec.mqtt.MqttPublishMessage; -import reactor.core.scheduler.Schedulers; - -/** - * @author luxurong - */ -public class ProtocolAdaptorWrapper implements ProtocolAdaptor { - - private final ProtocolAdaptor protocolAdaptor; - - public ProtocolAdaptorWrapper(ProtocolAdaptor protocolAdaptor) { - this.protocolAdaptor = protocolAdaptor; - } - - - @Override - public void chooseProtocol(MqttChannel mqttChannel, MqttMessage mqttMessage, ReceiveContext receiveContext) { - if (receiveContext.getConfiguration().getClusterConfig().getClustered() && mqttMessage instanceof MqttPublishMessage) { - receiveContext.getClusterRegistry().spreadPublishMessage(((MqttPublishMessage) mqttMessage).copy()).subscribeOn(Schedulers.single()).subscribe(); - } - protocolAdaptor.chooseProtocol(mqttChannel, mqttMessage, receiveContext); - } - -} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/retry/AbsAck.java b/smqtt-common/src/main/java/io/github/quickmsg/common/retry/AbsAck.java new file mode 100644 index 0000000000000000000000000000000000000000..706690bdcfb4be23dcb13a0ae52b91a0b1acbb2f --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/retry/AbsAck.java @@ -0,0 +1,78 @@ +package io.github.quickmsg.common.retry; + +import io.netty.util.Timeout; +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.TimeUnit; + +/** + * @author luxurong + */ +@Slf4j(topic = "ack") +public abstract class AbsAck implements Ack { + + private final int maxRetrySize; + + private int count = 1; + + private volatile boolean died = false; + + private final Runnable runnable; + + private final AckManager ackManager; + + private final int period; + + + private final Runnable cleaner; + + + + protected AbsAck(int maxRetrySize, int period, Runnable runnable, AckManager ackManager, Runnable cleaner) { + this.maxRetrySize = maxRetrySize; + this.period = period; + this.runnable = runnable; + this.ackManager = ackManager; + this.cleaner= cleaner; + } + + @Override + public void run(Timeout timeout) throws Exception { + if (++count <= maxRetrySize+1 && !died ) { + try { + log.info("task retry send ..........."); + runnable.run(); + ackManager.addAck(this); + } catch (Exception e) { + log.error("Ack error ", e); + } + + } + else { + cleaner.run(); + } + } + + @Override + public void stop() { + died = true; + log.info("retry task stop ..........."); + ackManager.deleteAck(getId()); + } + + + @Override + public void start() { + this.ackManager.addAck(this); + } + + @Override + public int getTimed() { + return this.period * this.count; + } + + @Override + public TimeUnit getTimeUnit() { + return TimeUnit.SECONDS; + } +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/retry/Ack.java b/smqtt-common/src/main/java/io/github/quickmsg/common/retry/Ack.java new file mode 100644 index 0000000000000000000000000000000000000000..26fba301b7c42a421b2f262a08e0617ec5612b3d --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/retry/Ack.java @@ -0,0 +1,23 @@ +package io.github.quickmsg.common.retry; + +import io.netty.util.TimerTask; + +import java.util.concurrent.TimeUnit; + +/** + * @author luxurong + */ +public interface Ack extends TimerTask { + + int getTimed(); + + TimeUnit getTimeUnit(); + + long getId(); + + void start(); + + void stop(); + + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/retry/AckManager.java b/smqtt-common/src/main/java/io/github/quickmsg/common/retry/AckManager.java new file mode 100644 index 0000000000000000000000000000000000000000..1135cbabc413a7a3a7cc7cb8d3d3589b0e4a8eed --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/retry/AckManager.java @@ -0,0 +1,16 @@ +package io.github.quickmsg.common.retry; + +/** + * @author luxurong + */ +public interface AckManager { + + void addAck(Ack ack); + + Ack getAck(Long id); + + void deleteAck(Long id); + + + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/retry/RetryAck.java b/smqtt-common/src/main/java/io/github/quickmsg/common/retry/RetryAck.java new file mode 100644 index 0000000000000000000000000000000000000000..86ccf1e0433cbc8c146d9c7da256c42dd69198a7 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/retry/RetryAck.java @@ -0,0 +1,21 @@ +package io.github.quickmsg.common.retry; + +/** + * @author luxurong + */ + +public class RetryAck extends AbsAck { + + private final long id; + + + public RetryAck(long id, int maxRetrySize, int period, Runnable runnable, AckManager ackManager, Runnable consumer) { + super(maxRetrySize, period, runnable, ackManager,consumer); + this.id = id; + } + + @Override + public long getId() { + return id; + } +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/retry/TimeAckManager.java b/smqtt-common/src/main/java/io/github/quickmsg/common/retry/TimeAckManager.java new file mode 100644 index 0000000000000000000000000000000000000000..cea9942ad252e100af2703f4fc30974559fab30b --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/retry/TimeAckManager.java @@ -0,0 +1,36 @@ +package io.github.quickmsg.common.retry; + +import io.netty.util.HashedWheelTimer; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +/** + * @author luxurong + */ +public class TimeAckManager extends HashedWheelTimer implements AckManager { + + private final Map ackMap = new ConcurrentHashMap<>(); + + public TimeAckManager(long tickDuration, TimeUnit unit, int ticksPerWheel) { + super( tickDuration, unit, ticksPerWheel); + } + + @Override + public void addAck(Ack ack) { + ackMap.put(ack.getId(),ack); + this.newTimeout(ack,ack.getTimed(),ack.getTimeUnit()); + } + + @Override + public Ack getAck(Long id) { + return ackMap.get(id); + } + + @Override + public void deleteAck(Long id) { + ackMap.remove(id); + } + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/rule/DslExecutor.java b/smqtt-common/src/main/java/io/github/quickmsg/common/rule/DslExecutor.java new file mode 100644 index 0000000000000000000000000000000000000000..6924c1543e14ca73ec562bca8d80a2700c6a8586 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/rule/DslExecutor.java @@ -0,0 +1,21 @@ +package io.github.quickmsg.common.rule; + +/** + * @author luxurong + */ +public interface DslExecutor { + + /** + * 执行 + * @param object 请求参数 += */ + void executeRule(Object... object); + + + /** + * 执行 + * @return boolean 是否需要执行 + */ + Boolean isExecute(); + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/rule/RuleChainDefinition.java b/smqtt-common/src/main/java/io/github/quickmsg/common/rule/RuleChainDefinition.java new file mode 100644 index 0000000000000000000000000000000000000000..7cd48ddc3a1d97842d6102d93431e67290121c0e --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/rule/RuleChainDefinition.java @@ -0,0 +1,22 @@ +package io.github.quickmsg.common.rule; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +import java.util.List; + +/** + * @author luxurong + */ +@Getter +@Setter +@ToString +public class RuleChainDefinition { + + private String ruleName; + + private List chain; + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/rule/RuleDefinition.java b/smqtt-common/src/main/java/io/github/quickmsg/common/rule/RuleDefinition.java new file mode 100644 index 0000000000000000000000000000000000000000..f5983b587e69b4833a5cd032724d863a212254e5 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/rule/RuleDefinition.java @@ -0,0 +1,24 @@ +package io.github.quickmsg.common.rule; + +import io.github.quickmsg.common.enums.RuleType; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +/** + * @author luxurong + */ +@Getter +@Setter +@ToString +public class RuleDefinition { + + + private String ruleName; + + private RuleType ruleType; + + private String script; + + +} \ No newline at end of file diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/rule/source/Source.java b/smqtt-common/src/main/java/io/github/quickmsg/common/rule/source/Source.java new file mode 100644 index 0000000000000000000000000000000000000000..da009845ee0684735cd83669e3f2830787080873 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/rule/source/Source.java @@ -0,0 +1,36 @@ +package io.github.quickmsg.common.rule.source; + +/** + * @author luxurong + */ +public enum Source { + /** + * kafka + */ + KAFKA, + /** + * rocketMq + */ + ROCKET_MQ, + /** + * RABBIT_MQ + */ + RABBIT_MQ, + /** + * 数据库 + */ + DATA_BASE, + /** + * hBase + */ + H_BASE, + + /** + * http + */ + HTTP, + /** + * mqtt转发 + */ + MQTT +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/rule/source/SourceBean.java b/smqtt-common/src/main/java/io/github/quickmsg/common/rule/source/SourceBean.java new file mode 100644 index 0000000000000000000000000000000000000000..7cdf5c25edddede4c87686ceb2eeb3e72eabd8ef --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/rule/source/SourceBean.java @@ -0,0 +1,49 @@ +package io.github.quickmsg.common.rule.source; + +import io.github.quickmsg.common.spi.DynamicLoader; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @author luxurong + */ +public interface SourceBean { + + + List SOURCE_BEAN_LIST = DynamicLoader.findAll(SourceBean.class) + .collect(Collectors.toList()); + + + /** + * 是否支持source + * + * @param source {@link Source} + * @return Boolean + */ + Boolean support(Source source); + + + /** + * 启动source + * + * @param sourceParam 请求参数 + * @return Boolean + */ + Boolean bootstrap(Map sourceParam); + + + /** + * 转发数据 + * + * @param object {@link Map} + */ + void transmit(Object object); + + /** + * 关闭资源 + */ + void close(); + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/rule/source/SourceDefinition.java b/smqtt-common/src/main/java/io/github/quickmsg/common/rule/source/SourceDefinition.java new file mode 100644 index 0000000000000000000000000000000000000000..68fd643106dabadc2945568838c2bd61763df791 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/rule/source/SourceDefinition.java @@ -0,0 +1,20 @@ +package io.github.quickmsg.common.rule.source; + +import lombok.Data; + +import java.util.Map; + +/** + * @author luxurong + */ +@Data +public class SourceDefinition { + + private Source source; + + private String sourceName; + + private String replace; + + private Map sourceAttributes; +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/spi/AppServiceLoader.java b/smqtt-common/src/main/java/io/github/quickmsg/common/spi/AppServiceLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..0ca072db1911adb95aaabf5bc97a48c7c409988c --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/spi/AppServiceLoader.java @@ -0,0 +1,7 @@ +package io.github.quickmsg.common.spi; + +/** + * @author luxurong + */ +public class AppServiceLoader { +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/spi/CacheLoader.java b/smqtt-common/src/main/java/io/github/quickmsg/common/spi/CacheLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..13f74c7a9de941dc83ebdf0b142378b7ec71d16b --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/spi/CacheLoader.java @@ -0,0 +1,42 @@ +package io.github.quickmsg.common.spi; + +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +/** + * @author luxurong + */ +@Slf4j +public class CacheLoader { + + public Map, Map> cacheBean = new ConcurrentHashMap<>(); + + @SuppressWarnings("unchecked") + public T getBeanByType(String type, Class tClass) { + Map beans = cacheBean.computeIfAbsent(tClass, this::loadAll); + return (T) beans.get(type); + } + + private Map loadAll(Class aClass) { + ServiceLoader load = ServiceLoader.load(aClass); + return StreamSupport.stream(load.spliterator(), false) + .collect(Collectors.toMap(this::getKey, Function.identity())); + } + + private String getKey(T t) { + Spi spi = t.getClass().getAnnotation(Spi.class); + if (spi == null) { + log.warn("class {} not contain spi annotation ", t); + } + return spi == null ? "default" : spi.type(); + } + + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/spi/Spi.java b/smqtt-common/src/main/java/io/github/quickmsg/common/spi/Spi.java new file mode 100644 index 0000000000000000000000000000000000000000..7137a78a1e105ff5910f014408367b4849217444 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/spi/Spi.java @@ -0,0 +1,16 @@ +package io.github.quickmsg.common.spi; + +import java.lang.annotation.*; + +/** + * @author luxurong + */ +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +public @interface Spi { + + String type(); + +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/topic/SubscribeTopic.java b/smqtt-common/src/main/java/io/github/quickmsg/common/topic/SubscribeTopic.java new file mode 100644 index 0000000000000000000000000000000000000000..8262e24d340f5eaaba7987f340b024b7395db225 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/topic/SubscribeTopic.java @@ -0,0 +1,66 @@ +package io.github.quickmsg.common.topic; + +import io.github.quickmsg.common.channel.MqttChannel; +import io.netty.handler.codec.mqtt.MqttQoS; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +import java.util.Objects; + +/** + * @author luxurong + */ + +@Getter +@Setter +public class SubscribeTopic { + + private final String topicFilter; + + private final MqttQoS qoS; + + private final MqttChannel mqttChannel; + + public SubscribeTopic(String topicFilter, MqttQoS qoS, MqttChannel mqttChannel) { + this.topicFilter = topicFilter; + this.qoS = qoS; + this.mqttChannel = mqttChannel; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SubscribeTopic that = (SubscribeTopic) o; + return Objects.equals(topicFilter, that.topicFilter) && + Objects.equals(mqttChannel, that.mqttChannel); + } + + @Override + public int hashCode() { + return Objects.hash(topicFilter, mqttChannel); + } + + public SubscribeTopic compareQos(MqttQoS mqttQoS) { + MqttQoS minQos = MqttQoS.valueOf(Math.min(mqttQoS.value(), qoS.value())); + return new SubscribeTopic(topicFilter, minQos, mqttChannel); + } + + public void linkSubscribe() { + mqttChannel.getTopics().add(this); + } + + public void unLinkSubscribe() { + mqttChannel.getTopics().remove(this); + } + + @Override + public String toString() { + return "SubscribeTopic{" + + "topicFilter='" + topicFilter + '\'' + + ", qoS=" + qoS + + ", mqttChannel=" + mqttChannel + + '}'; + } +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/topic/TopicRegistry.java b/smqtt-common/src/main/java/io/github/quickmsg/common/topic/TopicRegistry.java index 1e403ab594dbf2ec548bc56be457d3ef8d9d3e70..9eccb0b6297704809e5733cb1c083472e6f8f22e 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/topic/TopicRegistry.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/topic/TopicRegistry.java @@ -1,10 +1,9 @@ package io.github.quickmsg.common.topic; import io.github.quickmsg.common.channel.MqttChannel; -import io.github.quickmsg.common.message.SubscribeChannelContext; import io.github.quickmsg.common.spi.DynamicLoader; +import io.netty.handler.codec.mqtt.MqttQoS; -import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; @@ -20,10 +19,19 @@ public interface TopicRegistry { /** * 绑定主题跟channel关系 * - * @param topic 订阅主题 + * @param topicFilter 订阅主题 * @param mqttChannel {@link MqttChannel} + * @param qos {@link MqttQoS} */ - void registryTopicConnection(String topic, MqttChannel mqttChannel); + void registrySubscribeTopic(String topicFilter, MqttChannel mqttChannel, MqttQoS qos); + + + /** + * 绑定主题跟channel关系 + * + * @param subscribeTopic {@link SubscribeTopic} + */ + void registrySubscribeTopic(SubscribeTopic subscribeTopic); /** @@ -35,42 +43,44 @@ public interface TopicRegistry { /** - * 清除订阅消息 + * registryTopicConnection + * 取消订阅关系 * - * @param topics topics - * @param mqttChannel {@link MqttChannel} + * @param subscribeTopic {@link SubscribeTopic} */ - void clear(Set topics, MqttChannel mqttChannel); + void removeSubscribeTopic(SubscribeTopic subscribeTopic); + /** * 获取topic的channels * * @param topicName topic name - * @return {@link Set} + * @param qos {@link MqttQoS} + * @return {@link SubscribeTopic} */ - Set getChannelListByTopic(String topicName); + Set getSubscribesByTopic(String topicName, MqttQoS qos); /** - * 绑定主题跟channel关系 + * 绑定订阅关系 * - * @param mqttTopicSubscriptions {@link SubscribeChannelContext} + * @param subscribeTopics {@link SubscribeTopic} */ - void registryTopicConnection(List mqttTopicSubscriptions); + void registrySubscribesTopic(Set subscribeTopics); /** * 获取所有topic信息 * - * @return {@link MqttChannel} + * @return {@link MqttChannel} */ - Map> getAllTopics(); + Map> getAllTopics(); /** * 获取总数 * - * @return counts + * @return counts */ Integer counts(); diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/utils/BannerUtils.java b/smqtt-common/src/main/java/io/github/quickmsg/common/utils/BannerUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..f3f143f3d42ccf07916980a84320f90ab6f029c8 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/utils/BannerUtils.java @@ -0,0 +1,37 @@ +package io.github.quickmsg.common.utils; + + +import lombok.extern.slf4j.Slf4j; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; + + +/** + * banner + * + * @author zhaopeng + */ +@Slf4j +public class BannerUtils { + + /** + * 打印banner + */ + public static void banner() { + try (InputStream is = BannerUtils.class.getResourceAsStream("/banner.txt")) { + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + String line = ""; + while ((line = br.readLine()) != null) { + System.out.println(line); + } + } catch (Exception e) { + log.error("banner file not exists"); + } + } + + +} + + diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/utils/CsvReader.java b/smqtt-common/src/main/java/io/github/quickmsg/common/utils/CsvReader.java new file mode 100644 index 0000000000000000000000000000000000000000..6d4fcd55b8da08d1e6083acff8003496d1d2829c --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/utils/CsvReader.java @@ -0,0 +1,48 @@ +package io.github.quickmsg.common.utils; + +import lombok.extern.slf4j.Slf4j; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author luxurong + */ +@Slf4j +public class CsvReader { + + public static List> readCsvValues(String filePath) { + File csv = new File(filePath); + BufferedReader br = null; + try { + br = new BufferedReader(new InputStreamReader(new FileInputStream(csv), StandardCharsets.UTF_8)); + } catch (Exception e) { + e.printStackTrace(); + } + if (br != null) { + String line = ""; + List> records = new ArrayList<>(); + try { + while ((line = br.readLine()) != null) { + List lines=buildLineList(line); + records.add(lines); + } + return records; + } catch (IOException e) { + log.error("read auth error"); + e.printStackTrace(); + } + } + return Collections.emptyList(); + } + + private static List buildLineList(String line) { + return Arrays.stream(line.split(",")) + .collect(Collectors.toList()); + } +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/utils/FileExtension.java b/smqtt-common/src/main/java/io/github/quickmsg/common/utils/FileExtension.java new file mode 100644 index 0000000000000000000000000000000000000000..38da8d51944e3eb0b9548665f5b9ebdfe6731f86 --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/utils/FileExtension.java @@ -0,0 +1,13 @@ +package io.github.quickmsg.common.utils; + +/** + * @author luxurong + */ +public class FileExtension { + + public static final String PROPERTIES_SYMBOL = ".properties"; + + public static final String YAML_SYMBOL_1 = ".yaml"; + + public static final String YAML_SYMBOL_2 = ".yml"; +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/utils/FormatUtils.java b/smqtt-common/src/main/java/io/github/quickmsg/common/utils/FormatUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..871919db8d78d9902894e7b34aeecaa228c4ca1a --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/utils/FormatUtils.java @@ -0,0 +1,57 @@ +package io.github.quickmsg.common.utils; + +import java.text.DecimalFormat; + +/** + * @author luxurong + */ +public class FormatUtils { + + /** + * 单位转换 + * + * @param byteNumber number + * @return desc + */ + public static String formatByte(long byteNumber) { + double format = 1024.0; + double kbNumber = byteNumber / format; + if (kbNumber < format) { + return new DecimalFormat("#.##KB").format(kbNumber); + } + double mbNumber = kbNumber / format; + if (mbNumber < format) { + return new DecimalFormat("#.##MB").format(mbNumber); + } + double gbNumber = mbNumber / format; + if (gbNumber < format) { + return new DecimalFormat("#.##GB").format(gbNumber); + } + double tbNumber = gbNumber / format; + return new DecimalFormat("#.##TB").format(tbNumber); + } + + /** + * 单位转换 + * + * @param byteNumber number + * @return desc + */ + public static String formatByte(double byteNumber) { + double format = 1024.0; + double kbNumber = byteNumber / format; + if (kbNumber < format) { + return new DecimalFormat("#.##KB").format(kbNumber); + } + double mbNumber = kbNumber / format; + if (mbNumber < format) { + return new DecimalFormat("#.##MB").format(mbNumber); + } + double gbNumber = mbNumber / format; + if (gbNumber < format) { + return new DecimalFormat("#.##GB").format(gbNumber); + } + double tbNumber = gbNumber / format; + return new DecimalFormat("#.##TB").format(tbNumber); + } +} diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/utils/IPUtils.java b/smqtt-common/src/main/java/io/github/quickmsg/common/utils/IPUtils.java index b5b4486201a962069ac357379a044eee7840884d..00942a89166b219c73755f678ee27e2cce913239 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/utils/IPUtils.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/utils/IPUtils.java @@ -9,7 +9,6 @@ import java.util.Enumeration; * IP帮助类 * * @author zhaopeng - * @date 2021/06/24 */ public class IPUtils { @@ -23,10 +22,10 @@ public class IPUtils { Enumeration allNetInterfaces = NetworkInterface.getNetworkInterfaces(); InetAddress ip = null; while (allNetInterfaces.hasMoreElements()) { - NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement(); + NetworkInterface netInterface = allNetInterfaces.nextElement(); Enumeration addresses = netInterface.getInetAddresses(); while (addresses.hasMoreElements()) { - ip = (InetAddress) addresses.nextElement(); + ip = addresses.nextElement(); if (ip != null && (ip instanceof Inet4Address)) { String retIp = ip.getHostAddress(); if (!"127.0.0.1".equals(retIp)) { diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/utils/JacksonUtil.java b/smqtt-common/src/main/java/io/github/quickmsg/common/utils/JacksonUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..38e2a5bf8964a4cc22dc39b7484b35837e95ffee --- /dev/null +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/utils/JacksonUtil.java @@ -0,0 +1,104 @@ +package io.github.quickmsg.common.utils; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + + +/** + * jackson工具类 + * + * @author zhaopeng + */ +@Slf4j +public class JacksonUtil { + + private static ObjectMapper mapper = new ObjectMapper(); + + static { + mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + mapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true); + + + } + + public static String bean2Json(Object data) { + try { + return mapper.writeValueAsString(data); + } catch (JsonProcessingException e) { + log.error("JacksonUtil bean2Json {} error", data, e); + return ""; + } + } + + public static T json2Bean(String jsonData, Class beanType) { + try { + return mapper.readValue(jsonData, beanType); + } catch (Exception e) { + log.error("JacksonUtil json {} error", jsonData, e); + return null; + } + } + + + public static List json2List(String jsonData, Class beanType) { + try { + JavaType javaType = mapper.getTypeFactory().constructParametricType(List.class, beanType); + return mapper.readValue(jsonData, javaType); + } catch (Exception e) { + log.error("JacksonUtil json2List error", e); + return Collections.emptyList(); + } + } + + public static Map json2Map(String jsonData, Class keyType, Class valueType) { + if (jsonData == null || "".equals(jsonData)) { + return Collections.emptyMap(); + } else { + try { + JavaType javaType = mapper.getTypeFactory().constructMapType(Map.class, keyType, valueType); + return mapper.readValue(jsonData, javaType); + } catch (Exception e) { + log.error("JacksonUtil json2Map error", e); + return Collections.emptyMap(); + } + } + } + + public static String map2Json(Map map) { + try { + return mapper.writeValueAsString(map); + } catch (JsonProcessingException e) { + log.error("JacksonUtil map2Json error", e); + return ""; + } + } + + public static Object dynamic(String s) { + if (s.startsWith("{") && s.endsWith("}")) { + return JacksonUtil.json2Map(s, String.class, Object.class); + } else if (s.startsWith("[") && s.endsWith("]")) { + return json2List(s, Map.class); + } else { + return s; + } + } + + public static String dynamicJson(Object object) { + if (object instanceof String) { + return String.valueOf(object); + } else { + return JacksonUtil.bean2Json(object); + } + } + + +} \ No newline at end of file diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/utils/MessageUtils.java b/smqtt-common/src/main/java/io/github/quickmsg/common/utils/MessageUtils.java index ca936ec5bba84491c3648a7e779788f29b129457..03c2c81eec62f7706ca618f51185e053285c5072 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/utils/MessageUtils.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/utils/MessageUtils.java @@ -1,10 +1,7 @@ package io.github.quickmsg.common.utils; import io.netty.buffer.ByteBuf; -import io.netty.handler.codec.mqtt.MqttFixedHeader; -import io.netty.handler.codec.mqtt.MqttMessage; -import io.netty.handler.codec.mqtt.MqttPublishMessage; -import io.netty.handler.codec.mqtt.MqttPublishVariableHeader; +import io.netty.handler.codec.mqtt.*; import lombok.extern.slf4j.Slf4j; /** @@ -26,6 +23,18 @@ public class MessageUtils { } } + public static void safeRelease(MqttMessage mqttMessage,Integer count) { + if (mqttMessage.payload() instanceof ByteBuf) { + ByteBuf byteBuf = ((ByteBuf) mqttMessage.payload()); + if (count > 0) { + byteBuf.release(count); + if (log.isDebugEnabled()) { + log.info("netty success release mqttMessage {} count {} ", byteBuf, count); + } + } + } + } + public static void safeRelease(ByteBuf buf) { int count = buf.refCnt(); if (count > 0) { @@ -36,26 +45,36 @@ public class MessageUtils { } } + public static void safeRelease(ByteBuf buf,Integer count) { + if (count > 0) { + buf.release(count); + if (log.isDebugEnabled()) { + log.info("netty success release byteBuf {} count {} ", buf, count); + } + } + } + /** * 生成发布消息 * * @param messageId 消息id - * @param message 消息 - * @return MqttPublishMessage + * @param message {@link MqttPublishMessage} + * @param mqttQoS {@link MqttQoS} + * @return {@link MqttPublishMessage} */ - public static MqttPublishMessage wrapPublishMessage(MqttPublishMessage message, int messageId) { + public static MqttPublishMessage wrapPublishMessage(MqttPublishMessage message, MqttQoS mqttQoS, int messageId) { MqttPublishVariableHeader mqttPublishVariableHeader = message.variableHeader(); MqttFixedHeader mqttFixedHeader = message.fixedHeader(); - MqttFixedHeader newFixedHeader = new MqttFixedHeader(mqttFixedHeader.messageType(), false, mqttFixedHeader.qosLevel(), false, mqttFixedHeader.remainingLength()); - MqttPublishVariableHeader newHeader = new MqttPublishVariableHeader(mqttPublishVariableHeader.topicName(), messageId); + MqttFixedHeader newFixedHeader = new MqttFixedHeader(mqttFixedHeader.messageType(), false, mqttQoS, false, mqttFixedHeader.remainingLength()); + MqttPublishVariableHeader newHeader = new MqttPublishVariableHeader(mqttPublishVariableHeader.topicName(), messageId, mqttPublishVariableHeader.properties()); return new MqttPublishMessage(newFixedHeader, newHeader, message.payload().copy()); } /** - * 获取&释放消息字节数组 + * 获取释放消息字节数组 * * @param byteBuf 消息ByteBuf * @return 字节数组 @@ -64,13 +83,12 @@ public class MessageUtils { byte[] bytes = new byte[byteBuf.readableBytes()]; byteBuf.readBytes(bytes); byteBuf.resetReaderIndex(); - MessageUtils.safeRelease(byteBuf); return bytes; } /** - * 获取&释放消息字节数组 + * 获取释放消息字节数组 * * @param byteBuf 消息ByteBuf * @return 字节数组 @@ -84,4 +102,6 @@ public class MessageUtils { } + + } diff --git a/smqtt-common/src/main/java/io/github/quickmsg/common/utils/TopicRegexUtils.java b/smqtt-common/src/main/java/io/github/quickmsg/common/utils/TopicRegexUtils.java index 101d11e2e34ac8ce331b580ce9625f7b4c52e1aa..4b0fd2ef1d809da60cbdd359876a300879bb5102 100644 --- a/smqtt-common/src/main/java/io/github/quickmsg/common/utils/TopicRegexUtils.java +++ b/smqtt-common/src/main/java/io/github/quickmsg/common/utils/TopicRegexUtils.java @@ -5,6 +5,8 @@ package io.github.quickmsg.common.utils; */ public class TopicRegexUtils { + public static final TopicRegexUtils instance = new TopicRegexUtils(); + public static String regexTopic(String topic) { if (topic.startsWith("$")) { topic = "\\" + topic; @@ -15,5 +17,11 @@ public class TopicRegexUtils { .replaceAll("#", "(.+)") + "$"; } + public boolean match(String sourcesTopic, String targetTopic) { + if (sourcesTopic == null || "".equals(sourcesTopic) || targetTopic == null || "".equals(targetTopic)) { + return false; + } + return sourcesTopic.matches(TopicRegexUtils.regexTopic(targetTopic)); + } } diff --git a/smqtt-core/pom.xml b/smqtt-core/pom.xml index a72cb08f47e9fb629ac37225dabdfac45d97bd10..bfa21c355f8fc9e3f1a6ae1d79960e226e71a634 100644 --- a/smqtt-core/pom.xml +++ b/smqtt-core/pom.xml @@ -5,7 +5,7 @@ smqtt io.github.quickmsg - 1.0.5 + 1.1.7 4.0.0 smqtt-core @@ -14,7 +14,22 @@ io.github.quickmsg smqtt-common - 1.0.5 + 1.1.7 + + + io.github.quickmsg + smqtt-rule-dsl + 1.1.7 + + + io.github.quickmsg + smqtt-metric-influxdb + 1.1.7 + + + io.github.quickmsg + smqtt-metric-prometheus + 1.1.7 diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/Bootstrap.java b/smqtt-core/src/main/java/io/github/quickmsg/core/Bootstrap.java index d9c8dd982826c42de3cd2050224f19b6857572e4..ac2f762cb3e811754e19f928accc7d488ca444eb 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/Bootstrap.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/Bootstrap.java @@ -1,17 +1,20 @@ package io.github.quickmsg.core; -import io.github.quickmsg.common.auth.PasswordAuthentication; -import io.github.quickmsg.common.cluster.ClusterConfig; +import ch.qos.logback.classic.Level; +import io.github.quickmsg.common.config.AclConfig; +import io.github.quickmsg.common.config.AuthConfig; +import io.github.quickmsg.common.config.BootstrapConfig; import io.github.quickmsg.common.config.SslContext; -import io.github.quickmsg.common.environment.EnvContext; +import io.github.quickmsg.common.rule.RuleChainDefinition; +import io.github.quickmsg.common.rule.source.SourceDefinition; import io.github.quickmsg.common.transport.Transport; +import io.github.quickmsg.common.utils.BannerUtils; import io.github.quickmsg.common.utils.LoggerLevel; import io.github.quickmsg.core.http.HttpConfiguration; import io.github.quickmsg.core.http.HttpTransportFactory; import io.github.quickmsg.core.mqtt.MqttConfiguration; import io.github.quickmsg.core.mqtt.MqttTransportFactory; import io.github.quickmsg.core.websocket.WebSocketMqttTransportFactory; -import io.netty.channel.ChannelOption; import io.netty.channel.WriteBufferWaterMark; import lombok.Builder; import lombok.Getter; @@ -20,10 +23,7 @@ import lombok.extern.slf4j.Slf4j; import reactor.core.publisher.Mono; import reactor.core.publisher.Sinks; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; import java.util.function.Consumer; /** @@ -37,72 +37,78 @@ public class Bootstrap { private static final Sinks.One START_ONLY_MQTT = Sinks.one(); - private static final Integer DEFAULT_WEBSOCKET_MQTT_PORT = 9997; + private BootstrapConfig.TcpConfig tcpConfig; + private BootstrapConfig.HttpConfig httpConfig; - @Builder.Default - private Boolean isWebsocket = false; - - @Builder.Default - private Integer websocketPort = 0; - - @Builder.Default - private EnvContext envContext = EnvContext.empty(); - - private final List> transports = new ArrayList<>(); - - private Integer port; - - private Integer lowWaterMark; + private BootstrapConfig.WebsocketConfig websocketConfig; - private Integer highWaterMark; + private BootstrapConfig.ClusterConfig clusterConfig; - private Boolean ssl; + private BootstrapConfig.RedisConfig redisConfig; - private SslContext sslContext; + private BootstrapConfig.DatabaseConfig databaseConfig; - private Boolean wiretap; + private BootstrapConfig.MeterConfig meterConfig; - private Integer bossThreadSize; + private List ruleChainDefinitions; - private Integer workThreadSize; + private List sourceDefinitions; - private HttpOptions httpOptions; + private AclConfig aclConfig; - private String host; + private AuthConfig authConfig; - private PasswordAuthentication reactivePasswordAuth; - - private Consumer, ?>> options; - - private Consumer, ?>> childOptions; + private final List> transports = new ArrayList<>(); - private ClusterConfig clusterConfig; + @Builder.Default + private Consumer started = bootstrap -> { + }; - private Consumer started; + @Builder.Default + private Level rootLevel = Level.INFO; + @SuppressWarnings("Unchecked") private MqttConfiguration initMqttConfiguration() { + MqttConfiguration mqttConfiguration = defaultConfiguration(); - Optional.ofNullable(options).ifPresent(mqttConfiguration::setOptions); - Optional.ofNullable(childOptions).ifPresent(mqttConfiguration::setChildOptions); - Optional.ofNullable(reactivePasswordAuth).ifPresent(mqttConfiguration::setReactivePasswordAuth); - Optional.ofNullable(port).ifPresent(mqttConfiguration::setPort); - Optional.ofNullable(lowWaterMark).ifPresent(mqttConfiguration::setLowWaterMark); - Optional.ofNullable(highWaterMark).ifPresent(mqttConfiguration::setHighWaterMark); - Optional.ofNullable(wiretap).ifPresent(mqttConfiguration::setWiretap); - Optional.ofNullable(bossThreadSize).ifPresent(mqttConfiguration::setBossThreadSize); - Optional.ofNullable(workThreadSize).ifPresent(mqttConfiguration::setWorkThreadSize); - Optional.ofNullable(ssl).ifPresent(mqttConfiguration::setSsl); - Optional.ofNullable(sslContext).ifPresent(mqttConfiguration::setSslContext); + Optional.ofNullable(tcpConfig.getConnectModel()).ifPresent(mqttConfiguration::setConnectModel); + Optional.ofNullable(tcpConfig.getNotKickSecond()).ifPresent(mqttConfiguration::setNotKickSecond); + Optional.ofNullable(tcpConfig.getPort()).ifPresent(mqttConfiguration::setPort); + Optional.ofNullable(tcpConfig.getLowWaterMark()).ifPresent(mqttConfiguration::setLowWaterMark); + Optional.ofNullable(tcpConfig.getHighWaterMark()).ifPresent(mqttConfiguration::setHighWaterMark); + Optional.ofNullable(tcpConfig.getWiretap()).ifPresent(mqttConfiguration::setWiretap); + Optional.ofNullable(tcpConfig.getBossThreadSize()).ifPresent(mqttConfiguration::setBossThreadSize); + Optional.ofNullable(tcpConfig.getWorkThreadSize()).ifPresent(mqttConfiguration::setWorkThreadSize); + Optional.ofNullable(tcpConfig.getBusinessThreadSize()).ifPresent(mqttConfiguration::setBusinessThreadSize); + Optional.ofNullable(tcpConfig.getBusinessQueueSize()).ifPresent(mqttConfiguration::setBusinessQueueSize); + Optional.ofNullable(tcpConfig.getChannelReadWriteSize()).ifPresent(mqttConfiguration::setChannelReadWriteSize); + Optional.ofNullable(tcpConfig.getGlobalReadWriteSize()).ifPresent(mqttConfiguration::setGlobalReadWriteSize); + Optional.ofNullable(tcpConfig.getSsl()).map(SslContext::getEnable).ifPresent(mqttConfiguration::setSsl); + Optional.ofNullable(tcpConfig.getSsl()).ifPresent(mqttConfiguration::setSslContext); + Optional.ofNullable(tcpConfig.getSsl()).ifPresent(mqttConfiguration::setSslContext); + Optional.ofNullable(tcpConfig.getMessageMaxSize()).ifPresent(mqttConfiguration::setMessageMaxSize); Optional.ofNullable(clusterConfig).ifPresent(mqttConfiguration::setClusterConfig); - Optional.ofNullable(envContext).ifPresent(mqttConfiguration::setEnvContext); - if (isWebsocket) { - mqttConfiguration.setWebSocketPort(websocketPort); + Optional.ofNullable(meterConfig).ifPresent(mqttConfiguration::setMeterConfig); + Optional.ofNullable(aclConfig).ifPresent(mqttConfiguration::setAclConfig); + Optional.ofNullable(authConfig).ifPresent(mqttConfiguration::setAuthConfig); + + if (websocketConfig != null && websocketConfig.isEnable()) { + mqttConfiguration.setWebSocketPort(websocketConfig.getPort()); + mqttConfiguration.setWebSocketPath(websocketConfig.getPath()); } - if (wiretap != null && wiretap) { + if (tcpConfig.getWiretap() != null && tcpConfig.getWiretap()) { LoggerLevel.wiretap(); } + mqttConfiguration.setOptions(tcpConfig.getOptions()); + mqttConfiguration.setChildOptions(tcpConfig.getChildOptions()); + mqttConfiguration.setRuleChainDefinitions(ruleChainDefinitions); + mqttConfiguration.setSourceDefinitions(sourceDefinitions); + Map environmentMap = new HashMap<>(); + environmentMap.put(BootstrapConfig.RedisConfig.class, this.redisConfig); + environmentMap.put(BootstrapConfig.DatabaseConfig.class, this.databaseConfig); + mqttConfiguration.setEnvironmentMap(environmentMap); return mqttConfiguration; } @@ -124,7 +130,6 @@ public class Bootstrap { log.info("bootstrap server start error", err); START_ONLY_MQTT.tryEmitEmpty(); }) - .doOnSuccess(started) .subscribe(); START_ONLY_MQTT.asMono().block(); } @@ -136,37 +141,48 @@ public class Bootstrap { * @return Mono */ public Mono start() { + BannerUtils.banner(); MqttConfiguration mqttConfiguration = initMqttConfiguration(); MqttTransportFactory mqttTransportFactory = new MqttTransportFactory(); + LoggerLevel.root(rootLevel); + return mqttTransportFactory.createTransport(mqttConfiguration) .start() .doOnError(Throwable::printStackTrace) .doOnSuccess(transports::add) .then(startWs(mqttConfiguration)) .then(startHttp()) - .thenReturn(this); + .thenReturn(this) + .doOnSuccess(started); } private Mono startWs(MqttConfiguration mqttConfiguration) { - return this.isWebsocket ? new WebSocketMqttTransportFactory().createTransport(mqttConfiguration) + return this.websocketConfig != null && websocketConfig.isEnable() ? new WebSocketMqttTransportFactory().createTransport(mqttConfiguration) .start() .doOnSuccess(transports::add).doOnError(throwable -> log.error("start websocket error", throwable)).then() : Mono.empty(); } private Mono startHttp() { - return httpOptions != null ? new HttpTransportFactory().createTransport(this.buildHttpConfiguration()) + return httpConfig != null && httpConfig.isEnable() ? new HttpTransportFactory().createTransport(this.buildHttpConfiguration()) .start() .doOnSuccess(transports::add).doOnError(throwable -> log.error("start http error", throwable)).then() : Mono.empty(); } - private HttpConfiguration buildHttpConfiguration() { HttpConfiguration httpConfiguration = new HttpConfiguration(); - Optional.ofNullable(this.httpOptions.accessLog).ifPresent(httpConfiguration::setAccessLog); - Optional.ofNullable(this.httpOptions.sslContext).ifPresent(httpConfiguration::setSslContext); - Optional.ofNullable(this.httpOptions.httpPort).ifPresent(httpConfiguration::setPort); + httpConfiguration.setAccessLog(this.httpConfig.isAccessLog()); + httpConfiguration.setSslContext(this.httpConfig.getSsl()); + BootstrapConfig.HttpAdmin httpAdmin = this.httpConfig.getAdmin(); + if (httpAdmin != null && httpAdmin.isEnable()) { + httpConfiguration.setEnableAdmin(true); + httpConfiguration.setUsername(httpAdmin.getUsername()); + httpConfiguration.setPassword(httpAdmin.getPassword()); + + } else { + httpConfiguration.setEnableAdmin(false); + } return httpConfiguration; } @@ -183,12 +199,17 @@ public class Bootstrap { @Builder.Default private Boolean ssl = false; - private SslContext sslContext; @Builder.Default private Boolean accessLog = false; + private Boolean enableAdmin; + + private String username; + + private String password; + } public Bootstrap doOnStarted(Consumer started) { diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/DefaultTopicRegistry.java b/smqtt-core/src/main/java/io/github/quickmsg/core/DefaultTopicRegistry.java deleted file mode 100644 index b373fb62b1273cdc7664c87274158355d51974e3..0000000000000000000000000000000000000000 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/DefaultTopicRegistry.java +++ /dev/null @@ -1,89 +0,0 @@ -package io.github.quickmsg.core; - -import io.github.quickmsg.common.channel.MqttChannel; -import io.github.quickmsg.common.message.SubscribeChannelContext; -import io.github.quickmsg.common.topic.TopicRegistry; -import io.github.quickmsg.common.utils.TopicRegexUtils; - -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.atomic.LongAdder; -import java.util.stream.Collectors; - -/** - * @author luxurong - */ -public class DefaultTopicRegistry implements TopicRegistry { - - private Map> topicChannels = new ConcurrentHashMap<>(); - - - private LongAdder longAdder = new LongAdder(); - - - @Override - public void registryTopicConnection(String topic, MqttChannel mqttChannel) { - longAdder.increment(); - CopyOnWriteArraySet channels = topicChannels.computeIfAbsent(topic, t -> new CopyOnWriteArraySet<>()); - channels.add(mqttChannel); - mqttChannel.getTopics().add(topic); - } - - - @Override - public void clear(MqttChannel mqttChannel) { - longAdder.decrement(); - Set topics = mqttChannel.getTopics(); - this.clear(topics, mqttChannel); - } - - @Override - public void clear(Set topics, MqttChannel mqttChannel) { - Optional.ofNullable(topics) - .ifPresent(ts -> { - for (String topic : ts) { - Optional.ofNullable(topicChannels.get(topic)) - .ifPresent(set -> set.remove(mqttChannel)); - } - }); - - } - - @Override - public Set getChannelListByTopic(String topicName) { - Set matchKey = new HashSet<>(); - for (String topic : topicChannels.keySet()) { - if (topicName.matches(TopicRegexUtils.regexTopic((topic)))) { - matchKey.add(topic); - } - } - if (matchKey.size() > 0) { - return matchKey.stream().flatMap(key -> topicChannels.get(key).stream()).collect(Collectors.toSet()); - } else { - return Collections.emptySet(); - } - - - } - - @Override - public void registryTopicConnection(List mqttTopicSubscriptions) { - for (SubscribeChannelContext channelContext : mqttTopicSubscriptions) { - this.registryTopicConnection(channelContext.getTopic(), channelContext.getMqttChannel()); - } - - } - - @Override - public Map> getAllTopics() { - return this.topicChannels; - } - - @Override - public Integer counts() { - return (int) longAdder.sum(); - } - - -} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/DefaultTransport.java b/smqtt-core/src/main/java/io/github/quickmsg/core/DefaultTransport.java index 646a0f83944486f875dbb8d7b1872603ecd87f22..ea797d41a4e62b392af5b453f19e5aff44cd588d 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/DefaultTransport.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/DefaultTransport.java @@ -1,6 +1,7 @@ package io.github.quickmsg.core; import io.github.quickmsg.common.Receiver; +import io.github.quickmsg.common.context.ContextHolder; import io.github.quickmsg.common.context.ReceiveContext; import io.github.quickmsg.common.transport.Transport; import io.github.quickmsg.core.mqtt.MqttConfiguration; @@ -26,8 +27,6 @@ public class DefaultTransport implements Transport { private DisposableServer disposableServer; - public volatile static ReceiveContext receiveContext; - public DefaultTransport(MqttConfiguration configuration, Receiver receiver) { this.configuration = configuration; this.receiver = receiver; @@ -38,7 +37,7 @@ public class DefaultTransport implements Transport { @Override public Mono start() { return Mono.deferContextual(contextView -> - receiver.bind()) + receiver.bind()) .doOnNext(this::bindSever) .thenReturn(this) .doOnSuccess(defaultTransport -> log.info("server start success host {} port {}", disposableServer.host(), disposableServer.port())) @@ -48,12 +47,14 @@ public class DefaultTransport implements Transport { @Override + @SuppressWarnings("unchecked") public ReceiveContext buildReceiveContext(MqttConfiguration mqttConfiguration) { synchronized (this) { - if (DefaultTransport.receiveContext == null) { - DefaultTransport.receiveContext = new MqttReceiveContext(mqttConfiguration, this); + if (ContextHolder.getReceiveContext() == null) { + MqttReceiveContext receiveContext = new MqttReceiveContext(mqttConfiguration, this); + ContextHolder.setReceiveContext(receiveContext); } - return DefaultTransport.receiveContext; + return (ReceiveContext) ContextHolder.getReceiveContext(); } } diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/acl/JCasBinAclManager.java b/smqtt-core/src/main/java/io/github/quickmsg/core/acl/JCasBinAclManager.java new file mode 100644 index 0000000000000000000000000000000000000000..b3e8179bf99c6970ac73cdaf4922c47fa3dbb362 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/acl/JCasBinAclManager.java @@ -0,0 +1,128 @@ +package io.github.quickmsg.core.acl; + +import io.github.quickmsg.common.acl.AclAction; +import io.github.quickmsg.common.acl.AclManager; +import io.github.quickmsg.common.acl.AclPolicy; +import io.github.quickmsg.common.acl.AclType; +import io.github.quickmsg.common.acl.filter.AclFunction; +import io.github.quickmsg.common.acl.model.PolicyModel; +import io.github.quickmsg.common.channel.MqttChannel; +import io.github.quickmsg.common.config.AclConfig; +import lombok.extern.slf4j.Slf4j; +import org.casbin.adapter.JDBCAdapter; +import org.casbin.jcasbin.main.Enforcer; +import org.casbin.jcasbin.model.Model; +import org.casbin.jcasbin.persist.file_adapter.FileAdapter; +import org.casbin.jcasbin.util.BuiltInFunctions; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author luxurong + */ +@Slf4j +public class JCasBinAclManager implements AclManager { + + private Enforcer enforcer; + + private final Map> filterAclTopicActions = new ConcurrentHashMap<>(); + + private final String REQUEST_SUBJECT_TEMPLATE = "%s:%s"; + + + private boolean isOpen; + + public JCasBinAclManager(AclConfig aclConfig) { + + if (aclConfig != null) { + Model model = new Model(); + model.addDef("r", "r", "sub, obj, act"); + model.addDef("p", "p", " sub, obj, act, eft"); + model.addDef("g", "g", "_, _"); + model.addDef("e", "e", "some(where (p.eft == allow)) && !some(where (p.eft == deny))"); + model.addDef("m", "m", "r.act == p.act && keyMatch2(r.obj,p.obj) && filter(r.sub, p.sub)"); + if (aclConfig.getAclPolicy() == AclPolicy.JDBC) { + AclConfig.JdbcAclConfig jdbcAclConfig = aclConfig.getJdbcAclConfig(); + Objects.requireNonNull(jdbcAclConfig); + try { + enforcer = new Enforcer(model, new JDBCAdapter(jdbcAclConfig.getDriver(), jdbcAclConfig.getUrl(), + jdbcAclConfig.getUsername(), jdbcAclConfig.getPassword())); + this.loadAclCache(); + } catch (Exception e) { + log.error("init acl jdbc error {}", aclConfig, e); + } + } else if (aclConfig.getAclPolicy() == AclPolicy.FILE) { + enforcer = new Enforcer(model, new FileAdapter(aclConfig.getFilePath())); + this.loadAclCache(); + } else { + isOpen = false; + enforcer = new Enforcer(); + } + } + } + + private void loadAclCache() { + enforcer.addFunction("filter", new AclFunction()); + List objects = enforcer.getAllObjects(); + List actions = enforcer.getAllActions(); + for (int i = 0; i < objects.size(); i++) { + Set allObjects = filterAclTopicActions.computeIfAbsent(actions.get(i), a -> new HashSet<>()); + allObjects.add(objects.get(i)); + } + isOpen = true; + } + + @Override + public boolean check(MqttChannel mqttChannel, String source, AclAction action) { + if (isOpen) { + try { + + boolean isCheckAcl = Optional.ofNullable(filterAclTopicActions.get(action.name())) + .map(objects -> objects.stream().anyMatch(topic -> BuiltInFunctions.keyMatch2(source, topic))) + .orElse(false); + if (isCheckAcl) { + String subject = String.format(REQUEST_SUBJECT_TEMPLATE, mqttChannel.getClientIdentifier() + , mqttChannel.getAddress().split(":")[0]); + return Optional.ofNullable(enforcer) + .map(ef -> ef.enforce(subject, source, action.name())) + .orElse(true); + } + + } catch (Exception e) { + log.error("acl check error", e); + } + } + return true; + } + + @Override + public boolean add(String sub, String source, AclAction action, AclType type) { + return isOpen ? Optional.ofNullable(enforcer) + .map(ef -> enforcer.addNamedPolicy("p", sub, source, action.name(), type.getDesc())) + .orElse(true) : false; + } + + @Override + public boolean delete(String sub, String source, AclAction action, AclType type) { + return isOpen ? Optional.ofNullable(enforcer) + .map(ef -> enforcer.removeNamedPolicy("p", sub, source, action.name(), type.getDesc())) + .orElse(true) : false; + } + + @Override + public List> get(PolicyModel policyModel) { + if (!isOpen) { + return Collections.emptyList(); + } + return Optional.ofNullable(enforcer) + .map(ef -> enforcer + .getFilteredNamedPolicy("p", 0, + policyModel.getSubject(), policyModel.getSource(), + policyModel.getAction() == null || AclAction.ALL == policyModel.getAction() ? "" : policyModel.getAction().name(), + policyModel.getAclType() == null || AclType.ALL == policyModel.getAclType() ? "" : policyModel.getAclType().getDesc()) + ) + .orElse(Collections.emptyList()); + } + +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/auth/AuthManagerFactory.java b/smqtt-core/src/main/java/io/github/quickmsg/core/auth/AuthManagerFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..38146bd3e2e9a926141c7f8741f15f9f684323c2 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/auth/AuthManagerFactory.java @@ -0,0 +1,33 @@ +package io.github.quickmsg.core.auth; + +import io.github.quickmsg.common.auth.AuthManager; +import io.github.quickmsg.common.config.AuthConfig; + +/** + * @author luxurong + */ +public class AuthManagerFactory { + + private final AuthConfig authConfig; + + public AuthManagerFactory(AuthConfig authConfig) { + this.authConfig = authConfig; + } + + public AuthManager getAuthManager() { + if (authConfig == null) { + return new NoneAuthManager(); + } + if (authConfig.getHttp() != null) { + return new HttpAuthManager(authConfig); + } else if (authConfig.getFile() != null) { + return new FileAuthManager(authConfig); + } else if (authConfig.getFixed() != null) { + return new FixedAuthManager(authConfig); + } else if (authConfig.getSql() != null) { + return new SqlAuthManager(authConfig); + } else { + return new NoneAuthManager(); + } + } +} \ No newline at end of file diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/auth/FileAuthManager.java b/smqtt-core/src/main/java/io/github/quickmsg/core/auth/FileAuthManager.java new file mode 100644 index 0000000000000000000000000000000000000000..f93a7949c4fc73f261b2282bd8d0314ecd2e5eeb --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/auth/FileAuthManager.java @@ -0,0 +1,42 @@ +package io.github.quickmsg.core.auth; + +import io.github.quickmsg.common.auth.AuthBean; +import io.github.quickmsg.common.auth.AuthManager; +import io.github.quickmsg.common.config.AuthConfig; +import io.github.quickmsg.common.utils.CsvReader; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * @author luxurong + */ +public class FileAuthManager implements AuthManager { + + private final AuthConfig authConfig; + + private Map authBeanMap = new HashMap<>(); + + public FileAuthManager(AuthConfig authConfig) { + this.authConfig = authConfig; + List> values = CsvReader.readCsvValues(authConfig.getFile()); + for (List es : values) { + AuthBean authBean = new AuthBean(); + authBean.setClientId(es.get(0)); + authBean.setUsername(es.get(1)); + authBean.setPassword(es.get(2)); + authBeanMap.put(authBean.getClientId(),authBean); + } + } + + @Override + public Boolean auth(String userName, byte[] passwordInBytes, String clientIdentifier) { + return Optional.ofNullable(authBeanMap.get(clientIdentifier)) + .map(authBean -> authBean.getUsername().equals(userName) && authBean.getPassword().equals(new String(passwordInBytes))) + .orElse(false); + } + + +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/auth/FixedAuthManager.java b/smqtt-core/src/main/java/io/github/quickmsg/core/auth/FixedAuthManager.java new file mode 100644 index 0000000000000000000000000000000000000000..fcb00635dbb31201594ab99f1e388e1caa52c682 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/auth/FixedAuthManager.java @@ -0,0 +1,22 @@ +package io.github.quickmsg.core.auth; + +import io.github.quickmsg.common.auth.AuthManager; +import io.github.quickmsg.common.config.AuthConfig; + +/** + * @author luxurong + */ +public class FixedAuthManager implements AuthManager { + + private final AuthConfig authConfig; + + public FixedAuthManager(AuthConfig authConfig) { + this.authConfig = authConfig; + } + + @Override + public Boolean auth(String userName, byte[] passwordInBytes, String clientIdentifier) { + return authConfig.getFixed().getUsername().equals(userName) + && authConfig.getFixed().getPassword().equals(new String(passwordInBytes)); + } +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/auth/HttpAuthManager.java b/smqtt-core/src/main/java/io/github/quickmsg/core/auth/HttpAuthManager.java new file mode 100644 index 0000000000000000000000000000000000000000..eb403962b037b110b4b38781506ff4231b6f1188 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/auth/HttpAuthManager.java @@ -0,0 +1,52 @@ +package io.github.quickmsg.core.auth; + +import io.github.quickmsg.common.auth.AuthManager; +import io.github.quickmsg.common.config.AuthConfig; +import io.github.quickmsg.common.utils.JacksonUtil; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpResponseStatus; +import reactor.core.publisher.Mono; +import reactor.netty.ByteBufFlux; +import reactor.netty.http.client.HttpClient; + +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +/** + * @author luxurong + */ +public class HttpAuthManager implements AuthManager { + + private final AuthConfig authConfig; + + private final HttpClient client; + + public HttpAuthManager(AuthConfig authConfig) { + this.authConfig = authConfig; + AuthConfig.HttpAuthConfig httpAuthConfig = authConfig.getHttp(); + this.client = HttpClient.create().host(httpAuthConfig.getHost()).port(httpAuthConfig.getPort()) + .headers(headers -> { + headers.add(HttpHeaderNames.CONTENT_TYPE.toString(), "application/json;utf-8"); + Optional.ofNullable(httpAuthConfig.getHeaders()) + .ifPresent(addHeaders -> addHeaders.forEach(headers::add)); + }); + } + @Override + public Boolean auth(String userName, byte[] passwordInBytes, String clientIdentifier) { + AuthConfig.HttpAuthConfig httpAuthConfig = authConfig.getHttp(); + Map params = new HashMap<>(); + params.put("clientIdentifier", clientIdentifier); + params.put("username", userName); + params.put("password", new String(passwordInBytes, StandardCharsets.UTF_8)); + params.putAll(httpAuthConfig.getParams()); + return client.post().uri(httpAuthConfig.getPath()) + .send(ByteBufFlux.fromString(Mono.just(JacksonUtil.map2Json(params)))) + .response() + .map(response -> HttpResponseStatus.OK.code() == response.status().code()) + .block(Duration.ofSeconds(3)); + } + +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/auth/NoneAuthManager.java b/smqtt-core/src/main/java/io/github/quickmsg/core/auth/NoneAuthManager.java new file mode 100644 index 0000000000000000000000000000000000000000..bdf6a6b4006694f7e12bca7a77d0dd4b1a449082 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/auth/NoneAuthManager.java @@ -0,0 +1,13 @@ +package io.github.quickmsg.core.auth; + +import io.github.quickmsg.common.auth.AuthManager; + +/** + * @author luxurong + */ +public class NoneAuthManager implements AuthManager { + @Override + public Boolean auth(String userName, byte[] passwordInBytes, String clientIdentifier) { + return true; + } +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/auth/SqlAuthManager.java b/smqtt-core/src/main/java/io/github/quickmsg/core/auth/SqlAuthManager.java new file mode 100644 index 0000000000000000000000000000000000000000..02e065e125e357fbafec6cd47336886fce3cae2d --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/auth/SqlAuthManager.java @@ -0,0 +1,71 @@ +package io.github.quickmsg.core.auth; + +import io.github.quickmsg.common.auth.AuthManager; +import io.github.quickmsg.common.config.AuthConfig; +import io.github.quickmsg.source.db.config.HikariCPConnectionProvider; +import lombok.extern.slf4j.Slf4j; + +import java.nio.charset.StandardCharsets; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Properties; + +/** + * @author luxurong + */ +@Slf4j +public class SqlAuthManager implements AuthManager { + + private AuthConfig authConfig; + + public SqlAuthManager(AuthConfig authConfig) { + this.authConfig = authConfig; + // 初始化数据库连接池 + Properties properties = new Properties(); + properties.put("jdbcUrl", authConfig.getSql().getUrl()); + properties.put("username", authConfig.getSql().getUsername()); + properties.put("password", authConfig.getSql().getPassword()); + + HikariCPConnectionProvider + .singleTon() + .init(properties); + } + + public Boolean auth(String userName, byte[] passwordInBytes, String clientIdentifier) { + Connection conn = null; + PreparedStatement ps = null; + ResultSet rs = null; + try { + conn = HikariCPConnectionProvider.singleTon().getConnection(); + ps = conn.prepareStatement(authConfig.getSql().getAuthSql()); + ps.setString(1, userName); + ps.setString(2, new String(passwordInBytes, StandardCharsets.UTF_8)); + ps.setString(3, clientIdentifier); + + rs = ps.executeQuery(); + if (rs.next()) { + return true; + } + } catch (SQLException e) { + log.error("auth error clientIdentifier={}", clientIdentifier, e); + } finally { + try { + if (rs != null) { + rs.close(); + } + if (ps != null) { + ps.close(); + } + if (conn != null) { + conn.close(); + } + } catch (SQLException e) { + log.error("close error clientIdentifier={}", clientIdentifier, e); + } + } + + return false; + } +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/cluster/ClusterReceiver.java b/smqtt-core/src/main/java/io/github/quickmsg/core/cluster/ClusterReceiver.java index 23dbf09e4f5e7c445de0c41654e9404e56878c9e..7a8dd806b6a3edf8c18fd632050c4f7e9a864a9e 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/cluster/ClusterReceiver.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/cluster/ClusterReceiver.java @@ -1,19 +1,23 @@ package io.github.quickmsg.core.cluster; import io.github.quickmsg.common.channel.MockMqttChannel; -import io.github.quickmsg.common.cluster.ClusterConfig; -import io.github.quickmsg.common.cluster.ClusterMessage; +import io.github.quickmsg.common.channel.MqttChannel; +import io.github.quickmsg.common.config.BootstrapConfig; +import io.github.quickmsg.common.message.*; import io.github.quickmsg.common.cluster.ClusterRegistry; -import io.github.quickmsg.common.message.MqttMessageBuilder; import io.github.quickmsg.common.protocol.ProtocolAdaptor; +import io.github.quickmsg.common.utils.JacksonUtil; import io.github.quickmsg.core.mqtt.MqttReceiveContext; import io.netty.buffer.PooledByteBufAllocator; -import io.netty.handler.codec.mqtt.MqttPublishMessage; +import io.netty.handler.codec.mqtt.MqttMessage; import io.netty.handler.codec.mqtt.MqttQoS; import lombok.extern.slf4j.Slf4j; import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import java.nio.charset.StandardCharsets; import java.time.Duration; +import java.util.Optional; /** * @author luxurong @@ -29,10 +33,10 @@ public class ClusterReceiver { } public void registry() { - ClusterConfig clusterConfig = mqttReceiveContext.getConfiguration().getClusterConfig(); + BootstrapConfig.ClusterConfig clusterConfig = mqttReceiveContext.getConfiguration().getClusterConfig(); ClusterRegistry clusterRegistry = mqttReceiveContext.getClusterRegistry(); ProtocolAdaptor protocolAdaptor = mqttReceiveContext.getProtocolAdaptor(); - if (clusterConfig.getClustered()) { + if (clusterConfig.isEnable()) { if (clusterRegistry instanceof InJvmClusterRegistry) { Flux.interval(Duration.ofSeconds(2)) .subscribe(index -> log.warn("please set smqtt-registry dependency ")); @@ -41,22 +45,36 @@ public class ClusterReceiver { clusterRegistry.registry(clusterConfig); //begin listen cluster message clusterRegistry.handlerClusterMessage() - .subscribe(clusterMessage -> protocolAdaptor - .chooseProtocol(MockMqttChannel. - DEFAULT_MOCK_CHANNEL, - getMqttMessage(clusterMessage), - mqttReceiveContext)); + .doOnError(throwable -> log.error("cluster accept",throwable)) + .onErrorResume(e-> Mono.empty()) + .subscribe(clusterMessage -> { + if(clusterMessage.getClusterEvent() == ClusterMessage.ClusterEvent.PUBLISH){ + HeapMqttMessage heapMqttMessage = (HeapMqttMessage)clusterMessage.getMessage(); + protocolAdaptor + .chooseProtocol(MockMqttChannel.wrapClientIdentifier(heapMqttMessage.getClientIdentifier()), + getMqttMessage(heapMqttMessage), + mqttReceiveContext); + } + else { + CloseMqttMessage closeMqttMessage =(CloseMqttMessage) clusterMessage.getMessage(); + Optional.ofNullable(mqttReceiveContext.getChannelRegistry().get(closeMqttMessage.getClientIdentifier())) + .ifPresent(mqttChannel -> mqttChannel.close().subscribe()); + + } + + }); } } } - private MqttPublishMessage getMqttMessage(ClusterMessage clusterMessage) { - return MqttMessageBuilder + private SmqttMessage getMqttMessage(HeapMqttMessage heapMqttMessage) { + return new SmqttMessage<>(MqttMessageBuilder .buildPub(false, - MqttQoS.valueOf(clusterMessage.getQos()), + MqttQoS.valueOf(heapMqttMessage.getQos()), 0, - clusterMessage.getTopic(), - PooledByteBufAllocator.DEFAULT.buffer().writeBytes(clusterMessage.getMessage())); + heapMqttMessage.getTopic(), + PooledByteBufAllocator.DEFAULT.buffer().writeBytes(JacksonUtil.dynamicJson(heapMqttMessage.getMessage()).getBytes(StandardCharsets.UTF_8)), + heapMqttMessage.getProperties()), System.currentTimeMillis(), Boolean.TRUE); } } diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/cluster/ClusterSender.java b/smqtt-core/src/main/java/io/github/quickmsg/core/cluster/ClusterSender.java deleted file mode 100644 index 544a55f5077ffd95429ba746a06edb8ba48c1aee..0000000000000000000000000000000000000000 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/cluster/ClusterSender.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.github.quickmsg.core.cluster; - -import io.github.quickmsg.core.mqtt.MqttReceiveContext; -import io.netty.handler.codec.mqtt.MqttMessage; -import io.netty.handler.codec.mqtt.MqttPublishMessage; -import reactor.core.scheduler.Scheduler; - -import java.util.function.Function; - -/** - * @author luxurong - */ -public class ClusterSender implements Function { - - private final MqttReceiveContext mqttReceiveContext; - - private final Scheduler scheduler; - - public ClusterSender(Scheduler scheduler, MqttReceiveContext mqttReceiveContext) { - this.scheduler = scheduler; - this.mqttReceiveContext = mqttReceiveContext; - } - - @Override - public MqttMessage apply(MqttMessage mqttMessage) { - if (mqttMessage instanceof MqttPublishMessage) { - ((MqttPublishMessage) mqttMessage).retain(); - if (mqttReceiveContext.getConfiguration().getClusterConfig().getClustered()) { - mqttReceiveContext.getClusterRegistry().spreadPublishMessage(((MqttPublishMessage) mqttMessage).copy()).subscribeOn(scheduler).subscribe(); - } - } - return mqttMessage; - } - -} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/cluster/InJvmClusterRegistry.java b/smqtt-core/src/main/java/io/github/quickmsg/core/cluster/InJvmClusterRegistry.java index f52e348643c41ccf0c5c042c3662a9f86effaf2a..a627b0ac721dfe1abf6f67852f9193aa9756b6ca 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/cluster/InJvmClusterRegistry.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/cluster/InJvmClusterRegistry.java @@ -1,10 +1,11 @@ package io.github.quickmsg.core.cluster; -import io.github.quickmsg.common.cluster.ClusterConfig; -import io.github.quickmsg.common.cluster.ClusterMessage; +import io.github.quickmsg.common.config.BootstrapConfig; +import io.github.quickmsg.common.message.ClusterMessage; +import io.github.quickmsg.common.message.HeapMqttMessage; import io.github.quickmsg.common.cluster.ClusterNode; import io.github.quickmsg.common.cluster.ClusterRegistry; -import io.github.quickmsg.common.enums.ClusterEvent; +import io.github.quickmsg.common.enums.ClusterStatus; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -18,7 +19,7 @@ public class InJvmClusterRegistry implements ClusterRegistry { @Override - public void registry(ClusterConfig c) { + public void registry(BootstrapConfig.ClusterConfig c) { } @@ -28,7 +29,7 @@ public class InJvmClusterRegistry implements ClusterRegistry { } @Override - public Flux clusterEvent() { + public Flux clusterEvent() { return Flux.empty(); } diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/counter/SideWindowCounter.java b/smqtt-core/src/main/java/io/github/quickmsg/core/counter/SideWindowCounter.java deleted file mode 100644 index e1834e26f0e1be43b1f987fd0e60645d1c794879..0000000000000000000000000000000000000000 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/counter/SideWindowCounter.java +++ /dev/null @@ -1,54 +0,0 @@ -package io.github.quickmsg.core.counter; - -import lombok.extern.slf4j.Slf4j; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Sinks; -import reactor.core.scheduler.Scheduler; -import reactor.core.scheduler.Schedulers; - -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.LongAdder; - -/** - * @author luxurong - */ -@Slf4j -public class SideWindowCounter implements WindowCounter, Runnable { - - private LongAdder longAdder = new LongAdder(); - - private Sinks.Many sinks = Sinks.many().multicast().onBackpressureBuffer(); - - public SideWindowCounter(Integer time, TimeUnit timeUnit, String threadName) { - this(+time, timeUnit, Schedulers.newSingle(threadName)); - } - - public SideWindowCounter(Integer time, TimeUnit timeUnit, Scheduler scheduler) { - scheduler.schedulePeriodically(this, 0L, time, timeUnit); - scheduler.start(); - } - - - @Override - public void run() { - long sum = longAdder.sum(); - log.info("request buffer size {}", sum); - sinks.tryEmitNext(sum); - longAdder = new LongAdder(); - } - - @Override - public Long count() { - return longAdder.sum(); - } - - @Override - public void apply(Integer request) { - longAdder.add(request); - } - - @Override - public Flux interval() { - return sinks.asFlux(); - } -} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/counter/WindowCounter.java b/smqtt-core/src/main/java/io/github/quickmsg/core/counter/WindowCounter.java deleted file mode 100644 index 4c69b2d6596944ea1052796d6266a8128f3953d7..0000000000000000000000000000000000000000 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/counter/WindowCounter.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.github.quickmsg.core.counter; - -import reactor.core.publisher.Flux; - -/** - * @author luxurong - */ -public interface WindowCounter { - - /** - * 汇总 - * - * @return {@link Flux } - */ - Long count(); - - - /** - * 添加汇总值 - * - * @param request 一次请求的数 - */ - void apply(Integer request); - - - /** - * 周期性获取统计值 - * - * @return {@link Flux} - */ - Flux interval(); - -} - diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/AbstractHttpActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/AbstractHttpActor.java index 1aff33140ce0cc74d9858e6ffea112d686705277..01fce5579390a5ad63a7d043ebae4c102f4030c0 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/http/AbstractHttpActor.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/AbstractHttpActor.java @@ -1,9 +1,9 @@ package io.github.quickmsg.core.http; import io.github.quickmsg.common.channel.MockMqttChannel; -import io.github.quickmsg.common.protocol.ProtocolAdaptorWrapper; +import io.github.quickmsg.common.context.ContextHolder; +import io.github.quickmsg.common.message.SmqttMessage; import io.github.quickmsg.common.http.HttpActor; -import io.github.quickmsg.common.protocol.ProtocolAdaptor; import io.github.quickmsg.core.DefaultTransport; import io.netty.handler.codec.mqtt.MqttPublishMessage; @@ -12,18 +12,17 @@ import io.netty.handler.codec.mqtt.MqttPublishMessage; */ public abstract class AbstractHttpActor implements HttpActor { - private final ProtocolAdaptor protocolAdaptor = new ProtocolAdaptorWrapper(DefaultTransport.receiveContext.getProtocolAdaptor()); - /** * 发送mqtt消息 * * @param mqttPublishMessage publish消息 */ public void sendMqttMessage(MqttPublishMessage mqttPublishMessage) { - getProtocolAdaptor().chooseProtocol(MockMqttChannel.DEFAULT_MOCK_CHANNEL, mqttPublishMessage, DefaultTransport.receiveContext); - } - - public ProtocolAdaptor getProtocolAdaptor() { - return this.protocolAdaptor; + ContextHolder + .getReceiveContext() + .getProtocolAdaptor() + .chooseProtocol(MockMqttChannel.DEFAULT_MOCK_CHANNEL, + new SmqttMessage<>(mqttPublishMessage,System.currentTimeMillis(),Boolean.FALSE), + ContextHolder.getReceiveContext()); } } diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/HttpConfiguration.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/HttpConfiguration.java index 2dfac95bf00700df4869c8e3a525466c36fbe6e3..12fc2b003a703d0bb4a7593d0ae6078fcd258284 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/http/HttpConfiguration.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/HttpConfiguration.java @@ -1,7 +1,8 @@ package io.github.quickmsg.core.http; -import io.github.quickmsg.common.cluster.ClusterConfig; +import io.github.quickmsg.common.config.BootstrapConfig; import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.config.ConnectModel; import io.github.quickmsg.common.config.SslContext; import lombok.Data; @@ -12,7 +13,7 @@ import lombok.Data; public class HttpConfiguration implements Configuration { - private Integer port = 0; + private Integer port = 60000; private Boolean wiretap = false; @@ -26,15 +27,42 @@ public class HttpConfiguration implements Configuration { private Boolean accessLog = false; - private Boolean enableAdmin = false; + private Boolean enableAdmin = false; - private String username; + private String username; - private String password; + private String password; + private Integer messageMaxSize; + private BootstrapConfig.MeterConfig meterConfig; + @Override + public ConnectModel getConnectModel() { + return null; + } + + @Override + public Integer getBusinessThreadSize() { + return 0; + } + + @Override + public Integer getBusinessQueueSize() { + return 0; + } + + @Override + public String getGlobalReadWriteSize() { + return null; + } + + @Override + public String getChannelReadWriteSize() { + return null; + } + @Override public Integer getLowWaterMark() { return 0; @@ -46,7 +74,7 @@ public class HttpConfiguration implements Configuration { } @Override - public ClusterConfig getClusterConfig() { + public BootstrapConfig.ClusterConfig getClusterConfig() { throw new UnsupportedOperationException("getClusterConfig"); } diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/HttpReceiver.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/HttpReceiver.java index 79250347e9917982c13d476801947820296d2a38..f047e5330ccece9d99b5730c86d9f0f07ca0a95c 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/http/HttpReceiver.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/HttpReceiver.java @@ -4,6 +4,7 @@ import io.github.quickmsg.common.Receiver; import io.github.quickmsg.core.ssl.AbstractSslHandler; import io.netty.buffer.PooledByteBufAllocator; import io.netty.channel.ChannelOption; +import io.netty.handler.codec.json.JsonObjectDecoder; import reactor.core.publisher.Mono; import reactor.netty.DisposableServer; import reactor.netty.http.server.HttpServer; @@ -23,6 +24,7 @@ public class HttpReceiver extends AbstractSslHandler implements Receiver { httpServer.secure(sslContextSpec -> this.secure(sslContextSpec, configuration)); } return httpServer.port(configuration.getPort()) + .doOnConnection(connection -> connection.addHandler(new JsonObjectDecoder())) .route( new HttpRouterAcceptor(configuration)) .accessLog(configuration.getAccessLog()) .childOption(ChannelOption.TCP_NODELAY, true) diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/HttpRouterAcceptor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/HttpRouterAcceptor.java index f526005cd01df170d383da7466d446e58890ec61..24c9125c4296918652c722e7cfdc089f92d17e11 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/http/HttpRouterAcceptor.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/HttpRouterAcceptor.java @@ -1,9 +1,11 @@ package io.github.quickmsg.core.http; +import io.github.quickmsg.common.annotation.AllowCors; import io.github.quickmsg.common.annotation.Header; import io.github.quickmsg.common.annotation.Headers; import io.github.quickmsg.common.annotation.Router; import io.github.quickmsg.common.http.HttpActor; +import io.netty.handler.codec.http.HttpHeaderNames; import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; import reactor.netty.http.server.HttpServerRequest; @@ -11,7 +13,6 @@ import reactor.netty.http.server.HttpServerResponse; import reactor.netty.http.server.HttpServerRoutes; import java.util.Arrays; -import java.util.Optional; import java.util.function.BiFunction; import java.util.function.Consumer; @@ -47,6 +48,10 @@ public class HttpRouterAcceptor implements Consumer { httpServerRoutes .delete(router.value(), handler); break; + case OPTIONS: + httpServerRoutes + .options(router.value(), handler); + break; case GET: default: httpServerRoutes @@ -59,14 +64,21 @@ public class HttpRouterAcceptor implements Consumer { private Publisher doRequest(HttpServerRequest httpServerRequest, HttpServerResponse httpServerResponse, HttpActor httpActor, Router router) { Header header = httpActor.getClass().getAnnotation(Header.class); Headers headers = httpActor.getClass().getAnnotation(Headers.class); + AllowCors allowCors = httpActor.getClass().getAnnotation(AllowCors.class); if (router.resource() && !httpConfiguration.getEnableAdmin()) { return Mono.empty(); - } - else{ - Optional.ofNullable(header) - .ifPresent(hd -> httpServerResponse.addHeader(hd.key(), hd.value())); - Optional.ofNullable(headers) - .ifPresent(hds -> Arrays.stream(hds.headers()).forEach(hd -> httpServerResponse.addHeader(hd.key(), hd.value()))); + } else { + if (header != null) { + httpServerResponse.addHeader(header.key(), header.value()); + } + if (headers != null) { + Arrays.stream(headers.headers()).forEach(hd -> httpServerResponse.addHeader(hd.key(), hd.value())); + } + if (allowCors != null) { + httpServerResponse.addHeader(HttpHeaderNames.ACCESS_CONTROL_ALLOW_HEADERS, "*"); + httpServerResponse.addHeader(HttpHeaderNames.ACCESS_CONTROL_ALLOW_METHODS, "*"); + httpServerResponse.addHeader(HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN, "*"); + } return httpActor.doRequest(httpServerRequest, httpServerResponse, httpConfiguration); } } diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/acl/AclAddPolicyActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/acl/AclAddPolicyActor.java new file mode 100644 index 0000000000000000000000000000000000000000..f8fa40bb5b43d691879782f59e62fd4aedccd659 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/acl/AclAddPolicyActor.java @@ -0,0 +1,47 @@ +package io.github.quickmsg.core.http.acl; + +import io.github.quickmsg.common.acl.AclAction; +import io.github.quickmsg.common.acl.model.PolicyModel; +import io.github.quickmsg.common.annotation.AllowCors; +import io.github.quickmsg.common.annotation.Header; +import io.github.quickmsg.common.annotation.Router; +import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.context.ContextHolder; +import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.core.http.AbstractHttpActor; +import lombok.extern.slf4j.Slf4j; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; + +import java.nio.charset.StandardCharsets; + +/** + * @author luxurong + */ + +@Router(value = "/smqtt/acl/policy/add", type = HttpType.POST) +@Slf4j +@Header(key = "Content-Type", value = "application/json") +@AllowCors +public class AclAddPolicyActor extends AbstractHttpActor { + + @Override + public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration configuration) { + return request + .receive() + .asString(StandardCharsets.UTF_8) + .map(this.toJson(PolicyModel.class)) + .doOnNext(policyModel -> { + if (policyModel.getAction() == AclAction.ALL) { + ContextHolder.getReceiveContext().getAclManager().add + (policyModel.getSubject(), policyModel.getSource(), AclAction.SUBSCRIBE,policyModel.getAclType()); + ContextHolder.getReceiveContext().getAclManager().add(policyModel.getSubject(), policyModel.getSource(), AclAction.PUBLISH,policyModel.getAclType()); + } else { + ContextHolder.getReceiveContext().getAclManager().add(policyModel.getSubject(), policyModel.getSource(), policyModel.getAction(),policyModel.getAclType()); + } + } + ).then(response.sendString(Mono.just("success")).then()); + } +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/acl/AclDeletePolicyActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/acl/AclDeletePolicyActor.java new file mode 100644 index 0000000000000000000000000000000000000000..1fe8112fd155efa64fff5fb82e5df57967005d6f --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/acl/AclDeletePolicyActor.java @@ -0,0 +1,39 @@ +package io.github.quickmsg.core.http.acl; + +import io.github.quickmsg.common.acl.model.PolicyModel; +import io.github.quickmsg.common.annotation.AllowCors; +import io.github.quickmsg.common.annotation.Header; +import io.github.quickmsg.common.annotation.Router; +import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.context.ContextHolder; +import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.core.http.AbstractHttpActor; +import lombok.extern.slf4j.Slf4j; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; + +import java.nio.charset.StandardCharsets; + +/** + * @author luxurong + */ + +@Router(value = "/smqtt/acl/policy/delete", type = HttpType.POST) +@Slf4j +@Header(key = "Content-Type", value = "application/json") +@AllowCors +public class AclDeletePolicyActor extends AbstractHttpActor { + + @Override + public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration configuration) { + return request + .receive() + .asString(StandardCharsets.UTF_8) + .map(this.toJson(PolicyModel.class)) + .doOnNext(policyModel -> + ContextHolder.getReceiveContext().getAclManager().delete(policyModel.getSubject(), policyModel.getSource(), policyModel.getAction(),policyModel.getAclType()) + ).then(response.sendString(Mono.just("success")).then()); + } +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/acl/AclQueryPolicyActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/acl/AclQueryPolicyActor.java new file mode 100644 index 0000000000000000000000000000000000000000..52b544a33b1260adcd0d162dfefb7b67c010a752 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/acl/AclQueryPolicyActor.java @@ -0,0 +1,50 @@ +package io.github.quickmsg.core.http.acl; + +import io.github.quickmsg.common.acl.AclType; +import io.github.quickmsg.common.acl.model.PolicyModel; +import io.github.quickmsg.common.annotation.AllowCors; +import io.github.quickmsg.common.annotation.Header; +import io.github.quickmsg.common.annotation.Router; +import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.context.ContextHolder; +import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.common.utils.JacksonUtil; +import io.github.quickmsg.core.http.AbstractHttpActor; +import lombok.extern.slf4j.Slf4j; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; + +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @author luxurong + */ + +@Router(value = "/smqtt/acl/policy/query", type = HttpType.POST) +@Slf4j +@Header(key = "Content-Type", value = "application/json") +@AllowCors +public class AclQueryPolicyActor extends AbstractHttpActor { + + @Override + public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration configuration) { + return request.receive().asString(StandardCharsets.UTF_8).map(this.toJson(PolicyModel.class)).doOnNext(policyModel -> { + List> collect = ContextHolder.getReceiveContext().getAclManager().get(policyModel).stream().map(item -> { + Map map = new HashMap<>(); + map.put("subject", item.size() >= 3 ? item.get(0) : null); + map.put("source", item.size() >= 3 ? item.get(1) : null); + map.put("action", item.size() >= 3 ? item.get(2) : null); + map.put("aclType", item.size() >= 4 ? AclType.fromDesc(item.get(3)).name() : null); + return map; + }).collect(Collectors.toList()); + response.sendString(Mono.just(JacksonUtil.bean2Json(collect))).then().subscribe(); + }).then(); + } + +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/AllowCorsHttpActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/AllowCorsHttpActor.java new file mode 100644 index 0000000000000000000000000000000000000000..b560901231097ddf9c1e6b150b228fb829fbd3f9 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/AllowCorsHttpActor.java @@ -0,0 +1,24 @@ +package io.github.quickmsg.core.http.actors; + +import io.github.quickmsg.common.annotation.AllowCors; +import io.github.quickmsg.common.annotation.Router; +import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.common.http.HttpActor; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; + +/** + * @author luxurong + */ + +@Router(value = "/**", type = HttpType.OPTIONS) +@AllowCors +public class AllowCorsHttpActor implements HttpActor { + @Override + public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration configuration) { + return Mono.empty(); + } +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/CloseConnectionActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/CloseConnectionActor.java new file mode 100644 index 0000000000000000000000000000000000000000..d86ab71395b3cf15f84975d828eaef3eb2b81f66 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/CloseConnectionActor.java @@ -0,0 +1,66 @@ +package io.github.quickmsg.core.http.actors; + +import io.github.quickmsg.common.annotation.AllowCors; +import io.github.quickmsg.common.annotation.Header; +import io.github.quickmsg.common.annotation.Router; +import io.github.quickmsg.common.channel.MqttChannel; +import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.context.ContextHolder; +import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.common.utils.JacksonUtil; +import io.github.quickmsg.core.http.AbstractHttpActor; +import io.github.quickmsg.core.http.HttpConfiguration; +import io.github.quickmsg.core.http.model.LoginDo; +import io.github.quickmsg.core.http.model.LoginVm; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; + +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @author luxurong + */ +@Router(value = "/smqtt/close/connection", type = HttpType.POST) +@Slf4j +@Header(key = "Content-Type", value = "application/json") +@AllowCors +public class CloseConnectionActor extends AbstractHttpActor { + + @Override + public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration httpConfiguration) { + return request + .receive() + .asString(StandardCharsets.UTF_8) + .map(this.toJson(Close.class)) + .doOnNext(close -> { + if(CollectionUtils.isNotEmpty(close.getIds())){ + close.getIds().forEach(id->{ + MqttChannel mqttChannel=ContextHolder.getReceiveContext() + .getChannelRegistry() + .get(id); + if(mqttChannel!=null){ + mqttChannel.close().subscribe(); + } + }); + } + }).then(); + } + + + @Data + public static class Close{ + private List ids; + } + + + +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/ClusterActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/ClusterActor.java index 1da62550b5f7098aa1c2ea46db49a12749ec245e..75310572785cc95d6ba733e1bf873cd81069f995 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/ClusterActor.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/ClusterActor.java @@ -1,13 +1,14 @@ package io.github.quickmsg.core.http.actors; -import com.alibaba.fastjson.JSON; +import io.github.quickmsg.common.annotation.AllowCors; import io.github.quickmsg.common.annotation.Header; import io.github.quickmsg.common.annotation.Router; import io.github.quickmsg.common.config.Configuration; -import io.github.quickmsg.common.http.HttpActor; +import io.github.quickmsg.common.context.ContextHolder; import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.common.http.HttpActor; +import io.github.quickmsg.common.utils.JacksonUtil; import io.github.quickmsg.core.DefaultTransport; -import io.github.quickmsg.core.http.HttpConfiguration; import lombok.extern.slf4j.Slf4j; import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; @@ -20,6 +21,7 @@ import reactor.netty.http.server.HttpServerResponse; @Router(value = "/smqtt/cluster", type = HttpType.POST) @Slf4j @Header(key = "Content-Type", value = "application/json") +@AllowCors public class ClusterActor implements HttpActor { @@ -27,6 +29,6 @@ public class ClusterActor implements HttpActor { public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration httpConfiguration) { return request .receive() - .then(response.sendString(Mono.just(JSON.toJSONString(DefaultTransport.receiveContext.getClusterRegistry().getClusterNode()))).then()); + .then(response.sendString(Mono.just(JacksonUtil.bean2Json(ContextHolder.getReceiveContext().getClusterRegistry().getClusterNode()))).then()); } } diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/ConnectionActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/ConnectionActor.java index 8186476bb0a38a524889f6536043012d1eb60f70..e53deb889106020f1f9a5917f42214ff44cef24e 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/ConnectionActor.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/ConnectionActor.java @@ -1,25 +1,29 @@ package io.github.quickmsg.core.http.actors; -import com.alibaba.fastjson.JSON; +import io.github.quickmsg.common.annotation.AllowCors; import io.github.quickmsg.common.annotation.Header; import io.github.quickmsg.common.annotation.Router; import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.context.ContextHolder; import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.common.utils.JacksonUtil; import io.github.quickmsg.core.DefaultTransport; import io.github.quickmsg.core.http.AbstractHttpActor; -import io.github.quickmsg.core.http.HttpConfiguration; import lombok.extern.slf4j.Slf4j; import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; import reactor.netty.http.server.HttpServerRequest; import reactor.netty.http.server.HttpServerResponse; +import java.util.stream.Collectors; + /** * @author luxurong */ @Router(value = "/smqtt/connection", type = HttpType.POST) @Slf4j @Header(key = "Content-Type", value = "application/json") +@AllowCors public class ConnectionActor extends AbstractHttpActor { @Override @@ -27,7 +31,14 @@ public class ConnectionActor extends AbstractHttpActor { return request .receive() .then(response - .sendString(Mono.just(JSON.toJSONString(DefaultTransport.receiveContext.getChannelRegistry().getChannels()))) + .sendString(Mono.just(JacksonUtil.bean2Json( + ContextHolder.getReceiveContext().getChannelRegistry().getChannels() + .stream() + .map(record -> { + record.setAddress(record.getAddress()); + return record; + }).collect(Collectors.toList()) + ))) .then()); } diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/CounterHttpActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/CounterHttpActor.java new file mode 100644 index 0000000000000000000000000000000000000000..052b5b1937746e612f9e6b263472934adc197e62 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/CounterHttpActor.java @@ -0,0 +1,36 @@ +package io.github.quickmsg.core.http.actors; + +import io.github.quickmsg.common.annotation.AllowCors; +import io.github.quickmsg.common.annotation.Header; +import io.github.quickmsg.common.annotation.Router; +import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.common.http.HttpActor; +import io.github.quickmsg.common.metric.MetricManagerHolder; +import io.github.quickmsg.common.spi.DynamicLoader; +import io.github.quickmsg.common.utils.JacksonUtil; +import lombok.extern.slf4j.Slf4j; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; + +/** + * @author luxurong + */ + +@Router(value = "/smqtt/monitor/counter", type = HttpType.GET) +@Slf4j +@Header(key = "Content-Type", value = "application/json") +@AllowCors +public class CounterHttpActor implements HttpActor { + + @Override + public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration configuration) { + return request + .receive() + .then(response + .sendString(Mono.just(JacksonUtil.bean2Json(MetricManagerHolder.getMetricManager().getCounterMetric()))) + .then()); + } +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/CpuHttpActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/CpuHttpActor.java new file mode 100644 index 0000000000000000000000000000000000000000..e6f53204efcd2ad4702eb145294afb9e324f73b0 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/CpuHttpActor.java @@ -0,0 +1,37 @@ +package io.github.quickmsg.core.http.actors; + +import io.github.quickmsg.common.annotation.AllowCors; +import io.github.quickmsg.common.annotation.Header; +import io.github.quickmsg.common.annotation.Router; +import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.common.http.HttpActor; +import io.github.quickmsg.common.metric.MetricManagerHolder; +import io.github.quickmsg.common.spi.DynamicLoader; +import io.github.quickmsg.common.utils.JacksonUtil; +import lombok.extern.slf4j.Slf4j; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; + +/** + * @author luxurong + */ + +@Router(value = "/smqtt/monitor/cpu", type = HttpType.GET) +@Slf4j +@Header(key = "Content-Type", value = "application/json") +@AllowCors +public class CpuHttpActor implements HttpActor { + + + @Override + public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration configuration) { + return request + .receive() + .then(response + .sendString(Mono.just(JacksonUtil.bean2Json(MetricManagerHolder.getMetricManager().getCpuMetric()))) + .then()); + } +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/EventHttpActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/EventHttpActor.java new file mode 100644 index 0000000000000000000000000000000000000000..12f7615ceb881b5d732b22026c181ab114dfbceb --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/EventHttpActor.java @@ -0,0 +1,36 @@ +package io.github.quickmsg.core.http.actors; + +import io.github.quickmsg.common.annotation.AllowCors; +import io.github.quickmsg.common.annotation.Header; +import io.github.quickmsg.common.annotation.Router; +import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.common.http.HttpActor; +import io.github.quickmsg.common.metric.MetricManagerHolder; +import io.github.quickmsg.common.utils.JacksonUtil; +import lombok.extern.slf4j.Slf4j; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; + +/** + * @author luxurong + */ + +@Router(value = "/smqtt/monitor/event", type = HttpType.GET) +@Slf4j +@Header(key = "Content-Type", value = "application/json") +@AllowCors +public class EventHttpActor implements HttpActor { + + + @Override + public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration configuration) { + return request + .receive() + .then(response + .sendString(Mono.just(JacksonUtil.bean2Json(MetricManagerHolder.getMetricManager().getEventMetric()))) + .then()); + } +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/IsClusterActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/IsClusterActor.java new file mode 100644 index 0000000000000000000000000000000000000000..5d08930fde0405db7b74b9679627ec041cfadac0 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/IsClusterActor.java @@ -0,0 +1,31 @@ +package io.github.quickmsg.core.http.actors; + +import io.github.quickmsg.common.annotation.AllowCors; +import io.github.quickmsg.common.annotation.Router; +import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.context.ContextHolder; +import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.common.http.HttpActor; +import io.github.quickmsg.core.DefaultTransport; +import lombok.extern.slf4j.Slf4j; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; + +/** + * @author luxurong + */ +@Router(value = "/smqtt/is/cluster", type = HttpType.GET) +@Slf4j +@AllowCors +public class IsClusterActor implements HttpActor { + + + @Override + public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration httpConfiguration) { + return request + .receive() + .then(response.sendString(Mono.just(String.valueOf(ContextHolder.getReceiveContext().getConfiguration().getClusterConfig().isEnable()))).then()); + } +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/JvmHttpActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/JvmHttpActor.java new file mode 100644 index 0000000000000000000000000000000000000000..9623452d11c1f81279ea3c95db00c82647469056 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/JvmHttpActor.java @@ -0,0 +1,36 @@ +package io.github.quickmsg.core.http.actors; + +import io.github.quickmsg.common.annotation.AllowCors; +import io.github.quickmsg.common.annotation.Header; +import io.github.quickmsg.common.annotation.Router; +import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.common.http.HttpActor; +import io.github.quickmsg.common.metric.MetricManagerHolder; +import io.github.quickmsg.common.spi.DynamicLoader; +import io.github.quickmsg.common.utils.JacksonUtil; +import lombok.extern.slf4j.Slf4j; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; + +/** + * @author luxurong + */ + +@Router(value = "/smqtt/monitor/jvm", type = HttpType.GET) +@Slf4j +@Header(key = "Content-Type", value = "application/json") +@AllowCors +public class JvmHttpActor implements HttpActor { + + @Override + public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration configuration) { + return request + .receive() + .then(response + .sendString(Mono.just(JacksonUtil.bean2Json(MetricManagerHolder.getMetricManager().getJvmMetric()))) + .then()); + } +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/PrometheusActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/PrometheusActor.java new file mode 100644 index 0000000000000000000000000000000000000000..fdddf84c311ac939b999317ac0d7b8d63c428bd2 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/PrometheusActor.java @@ -0,0 +1,36 @@ +package io.github.quickmsg.core.http.actors; + +import io.github.quickmsg.common.annotation.AllowCors; +import io.github.quickmsg.common.annotation.Header; +import io.github.quickmsg.common.annotation.Router; +import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.common.http.HttpActor; +import io.github.quickmsg.common.metric.MetricManagerHolder; +import lombok.extern.slf4j.Slf4j; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; + +/** + * 监控指标 + * + * @author easy + */ +@Router(value = "/smqtt/meter", type = HttpType.GET) +@Slf4j +@Header(key = "Content-Type", value = "text/plain; version=0.0.4;charset=utf-8") +@AllowCors +public class PrometheusActor implements HttpActor { + + + @Override + public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration configuration) { + return request + .receive() + .then(response + .sendString(Mono.just(MetricManagerHolder.getMetricManager().scrape())) + .then()); + } +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/PublishActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/PublishActor.java index 2a93ffe70c3a0bf7c322d7caa3dac2f6e077b426..bf32bdf55fcf635401cb24864d584f6455fadf9d 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/PublishActor.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/PublishActor.java @@ -1,30 +1,36 @@ package io.github.quickmsg.core.http.actors; +import io.github.quickmsg.common.annotation.AllowCors; import io.github.quickmsg.common.annotation.Router; import io.github.quickmsg.common.config.Configuration; import io.github.quickmsg.common.enums.HttpType; import io.github.quickmsg.common.message.HttpPublishMessage; import io.github.quickmsg.core.http.AbstractHttpActor; -import io.github.quickmsg.core.http.HttpConfiguration; import lombok.extern.slf4j.Slf4j; import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; import reactor.netty.http.server.HttpServerRequest; import reactor.netty.http.server.HttpServerResponse; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + /** * @author luxurong */ @Router(value = "/smqtt/publish", type = HttpType.POST) @Slf4j +@AllowCors public class PublishActor extends AbstractHttpActor { @Override public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration httpConfiguration) { + Charset charset = Charset.defaultCharset(); + log.info("Charset is {}",charset); return request .receive() - .asString() + .asString(StandardCharsets.UTF_8) .map(this.toJson(HttpPublishMessage.class)) .doOnNext(message -> { this.sendMqttMessage(message.getPublishMessage()); diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/SubscribeActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/SubscribeActor.java index 72e11f8eff1275f4c1584e4803e513c53a1b96ed..e7eed84fdf7c6df2b3a95b644c074c125ba7ad22 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/SubscribeActor.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/SubscribeActor.java @@ -1,13 +1,14 @@ package io.github.quickmsg.core.http.actors; -import com.alibaba.fastjson.JSON; +import io.github.quickmsg.common.annotation.AllowCors; import io.github.quickmsg.common.annotation.Header; import io.github.quickmsg.common.annotation.Router; import io.github.quickmsg.common.config.Configuration; -import io.github.quickmsg.common.http.HttpActor; +import io.github.quickmsg.common.context.ContextHolder; import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.common.http.HttpActor; +import io.github.quickmsg.common.utils.JacksonUtil; import io.github.quickmsg.core.DefaultTransport; -import io.github.quickmsg.core.http.HttpConfiguration; import lombok.extern.slf4j.Slf4j; import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; @@ -20,6 +21,7 @@ import reactor.netty.http.server.HttpServerResponse; @Router(value = "/smqtt/subscribe", type = HttpType.POST) @Slf4j @Header(key = "Content-Type", value = "application/json") +@AllowCors public class SubscribeActor implements HttpActor { @Override @@ -27,7 +29,7 @@ public class SubscribeActor implements HttpActor { return request .receive() .then(response - .sendString(Mono.just(JSON.toJSONString(DefaultTransport.receiveContext.getTopicRegistry().getAllTopics()))) + .sendString(Mono.just(JacksonUtil.bean2Json(ContextHolder.getReceiveContext().getTopicRegistry().getAllTopics()))) .then()); } } diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/resource/FaviconResourceActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/resource/FaviconResourceActor.java new file mode 100644 index 0000000000000000000000000000000000000000..db9e128d1b33e38a7fd4787f5ca8e908cab0ae55 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/resource/FaviconResourceActor.java @@ -0,0 +1,28 @@ +package io.github.quickmsg.core.http.actors.resource; + +import io.github.quickmsg.common.annotation.AllowCors; +import io.github.quickmsg.common.annotation.Router; +import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.common.http.HttpActor; +import io.github.quickmsg.common.utils.ClassPathLoader; +import lombok.extern.slf4j.Slf4j; +import org.reactivestreams.Publisher; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; + +/** + * @author luxurong + */ +@Router(type = HttpType.GET, value = "/favicon.ico",resource = true) +@Slf4j +@AllowCors +public class FaviconResourceActor implements HttpActor { + private final static String DEFAULT_STATIC_PATH = "/static/"; + + @Override + public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration httpConfiguration) { + String path = DEFAULT_STATIC_PATH + "favicon.ico"; + return response.send(ClassPathLoader.readClassPathFile(path)).then(); + } +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/resource/LoginResourceActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/resource/LoginResourceActor.java index ce4d18d883bb715a2c82f06511e74f391b8733ad..1ecd6a7fcc72167a90a55d462aa00fdf5b68c9a8 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/resource/LoginResourceActor.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/resource/LoginResourceActor.java @@ -1,21 +1,22 @@ package io.github.quickmsg.core.http.actors.resource; -import com.alibaba.fastjson.JSON; +import io.github.quickmsg.common.annotation.AllowCors; import io.github.quickmsg.common.annotation.Header; import io.github.quickmsg.common.annotation.Router; import io.github.quickmsg.common.config.Configuration; import io.github.quickmsg.common.enums.HttpType; import io.github.quickmsg.common.http.HttpActor; +import io.github.quickmsg.common.utils.JacksonUtil; import io.github.quickmsg.core.http.HttpConfiguration; import io.github.quickmsg.core.http.model.LoginDo; import io.github.quickmsg.core.http.model.LoginVm; -import io.netty.handler.codec.http.HttpResponseStatus; import lombok.extern.slf4j.Slf4j; import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; import reactor.netty.http.server.HttpServerRequest; import reactor.netty.http.server.HttpServerResponse; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -26,26 +27,28 @@ import java.util.Optional; @Router(value = "/auth/login", type = HttpType.POST,resource = true) @Slf4j @Header(key = "Content-Type", value = "application/json") +@AllowCors public class LoginResourceActor implements HttpActor { @Override public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration httpConfiguration) { return request .receive() - .asString() + .asString(StandardCharsets.UTF_8) .map(this.toJson(LoginDo.class)) .doOnNext(loginDo -> { + Map res = new HashMap<>(2); if (this.validateLogin(loginDo,(HttpConfiguration)httpConfiguration)) { LoginVm loginVm = new LoginVm(); loginVm.setAccessToken("jhbsadhjbajhdbjhabdsjhahjbsdjhbajsdbjhahjsdb"); loginVm.setExpiresIn(System.currentTimeMillis() + 100000000000000L); - Map res = new HashMap<>(1); res.put("data", loginVm); - response.sendString(Mono.just(JSON.toJSONString(res))).then().subscribe(); + res.put("success",true); } else { - response.status(HttpResponseStatus.UNAUTHORIZED); - response.send().then().subscribe(); + res.put("success",false); } + + response.sendString(Mono.just(JacksonUtil.map2Json(res))).then().subscribe(); }).then(); } diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/rule/RuleAddActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/rule/RuleAddActor.java new file mode 100644 index 0000000000000000000000000000000000000000..194a82d8ecc1d4372f72678d856e7bb60409e41b --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/rule/RuleAddActor.java @@ -0,0 +1,42 @@ +package io.github.quickmsg.core.http.actors.rule; + +import io.github.quickmsg.common.annotation.AllowCors; +import io.github.quickmsg.common.annotation.Header; +import io.github.quickmsg.common.annotation.Router; +import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.common.rule.RuleChainDefinition; +import io.github.quickmsg.core.http.AbstractHttpActor; +import lombok.extern.slf4j.Slf4j; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; + +import java.nio.charset.StandardCharsets; + + +/** + * 规则添加 + * + * @author zhaopeng + */ +@Router(value = "/smqtt/ruleAdd", type = HttpType.POST) +@Slf4j +@Header(key = "Content-Type", value = "application/json") +@AllowCors +public class RuleAddActor extends AbstractHttpActor { + + @Override + public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration httpConfiguration) { + return request + .receive() + .asString(StandardCharsets.UTF_8) + .map(this.toList(RuleChainDefinition.class)) + .doOnNext(message -> { + // todo + log.info("http request url {} body {}", request.path(), message); + }).then(response.sendString(Mono.just("success")).then()); + } + +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/rule/RuleDeleteActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/rule/RuleDeleteActor.java new file mode 100644 index 0000000000000000000000000000000000000000..8531e8a06a842ab6a37d8a14ca704632da7c4058 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/rule/RuleDeleteActor.java @@ -0,0 +1,41 @@ +package io.github.quickmsg.core.http.actors.rule; + +import io.github.quickmsg.common.annotation.AllowCors; +import io.github.quickmsg.common.annotation.Header; +import io.github.quickmsg.common.annotation.Router; +import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.common.rule.RuleChainDefinition; +import io.github.quickmsg.core.http.AbstractHttpActor; +import lombok.extern.slf4j.Slf4j; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; + +import java.nio.charset.StandardCharsets; + + +/** + * 规则删除 + * + * @author zhaopeng + */ +@Router(value = "/smqtt/ruleDelete", type = HttpType.POST) +@Slf4j +@Header(key = "Content-Type", value = "application/json") +@AllowCors +public class RuleDeleteActor extends AbstractHttpActor { + + @Override + public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration httpConfiguration) { + return request + .receive() + .asString(StandardCharsets.UTF_8) + .map(this.toList(RuleChainDefinition.class)) + .doOnNext(message -> { + // todo + log.info("http request url {} body {}", request.path(), message); + }).then(response.sendString(Mono.just("success")).then()); + } +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/rule/RuleQueryActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/rule/RuleQueryActor.java new file mode 100644 index 0000000000000000000000000000000000000000..edd93c1ee99694fc3d256589269d400dc693ac65 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/rule/RuleQueryActor.java @@ -0,0 +1,86 @@ +package io.github.quickmsg.core.http.actors.rule; + +import io.github.quickmsg.common.annotation.AllowCors; +import io.github.quickmsg.common.annotation.Header; +import io.github.quickmsg.common.annotation.Router; +import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.common.enums.RuleType; +import io.github.quickmsg.common.rule.RuleChainDefinition; +import io.github.quickmsg.common.rule.RuleDefinition; +import io.github.quickmsg.common.utils.JacksonUtil; +import io.github.quickmsg.core.http.AbstractHttpActor; +import lombok.extern.slf4j.Slf4j; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; + +import java.util.ArrayList; +import java.util.List; + + +/** + * 规则查询 + * + * @author zhaopeng + */ +@Router(value = "/smqtt/ruleQuery", type = HttpType.POST) +@Slf4j +@Header(key = "Content-Type", value = "application/json") +@AllowCors +public class RuleQueryActor extends AbstractHttpActor { + + @Override + public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration httpConfiguration) { + List list = new ArrayList(); + + RuleChainDefinition ruleChainDefinition = new RuleChainDefinition(); + ruleChainDefinition.setRuleName("A1"); + + List chain = new ArrayList(); + + RuleDefinition ruleDefinition = new RuleDefinition(); + ruleDefinition.setRuleName("R1"); + ruleDefinition.setRuleType(RuleType.KAFKA); + ruleDefinition.setScript("exe"); + + RuleDefinition ruleDefinition2 = new RuleDefinition(); + ruleDefinition2.setRuleName("R2"); + ruleDefinition2.setRuleType(RuleType.KAFKA); + ruleDefinition2.setScript("exe2"); + + chain.add(ruleDefinition); + chain.add(ruleDefinition2); + ruleChainDefinition.setChain(chain); + + RuleChainDefinition ruleChainDefinition2 = new RuleChainDefinition(); + ruleChainDefinition2.setRuleName("AA1"); + + List chain2 = new ArrayList(); + + RuleDefinition ruleDefinition22 = new RuleDefinition(); + ruleDefinition22.setRuleName("R1"); + ruleDefinition22.setRuleType(RuleType.KAFKA); + ruleDefinition22.setScript("exe"); + + RuleDefinition ruleDefinition222 = new RuleDefinition(); + ruleDefinition222.setRuleName("R2"); + ruleDefinition222.setRuleType(RuleType.KAFKA); + ruleDefinition222.setScript("exe2"); + + chain2.add(ruleDefinition22); + chain2.add(ruleDefinition222); + ruleChainDefinition2.setChain(chain2); + + list.add(ruleChainDefinition); + list.add(ruleChainDefinition2); + + return request + .receive() + .then(response + .sendString(Mono.just(JacksonUtil.bean2Json(list))) + .then()); + } + +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/rule/RuleTypeActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/rule/RuleTypeActor.java new file mode 100644 index 0000000000000000000000000000000000000000..786ae68497a212d49ed42a7b0c35983d8a1083f3 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/rule/RuleTypeActor.java @@ -0,0 +1,42 @@ +package io.github.quickmsg.core.http.actors.rule; + +import io.github.quickmsg.common.annotation.AllowCors; +import io.github.quickmsg.common.annotation.Header; +import io.github.quickmsg.common.annotation.Router; +import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.common.enums.RuleType; +import io.github.quickmsg.common.utils.JacksonUtil; +import io.github.quickmsg.core.http.AbstractHttpActor; +import lombok.extern.slf4j.Slf4j; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; + +import java.util.Arrays; +import java.util.List; + + +/** + * 规则枚举 + * + * @author zhaopeng + */ +@Router(value = "/smqtt/ruleType", type = HttpType.GET) +@Slf4j +@Header(key = "Content-Type", value = "application/json") +@AllowCors +public class RuleTypeActor extends AbstractHttpActor { + + @Override + public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration httpConfiguration) { + List list = Arrays.asList(RuleType.values()); + return request + .receive() + .then(response + .sendString(Mono.just(JacksonUtil.bean2Json(list))) + .then()); + } + +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/rule/RuleUpdateActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/rule/RuleUpdateActor.java new file mode 100644 index 0000000000000000000000000000000000000000..7bc1cc4a0c49fdd6e970403901b99a22f5a661d1 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/rule/RuleUpdateActor.java @@ -0,0 +1,42 @@ +package io.github.quickmsg.core.http.actors.rule; + +import io.github.quickmsg.common.annotation.AllowCors; +import io.github.quickmsg.common.annotation.Header; +import io.github.quickmsg.common.annotation.Router; +import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.common.rule.RuleChainDefinition; +import io.github.quickmsg.core.http.AbstractHttpActor; +import lombok.extern.slf4j.Slf4j; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; + +import java.nio.charset.StandardCharsets; + + +/** + * 规则更新 + * + * @author zhaopeng + */ +@Router(value = "/smqtt/ruleUpdate", type = HttpType.POST) +@Slf4j +@Header(key = "Content-Type", value = "application/json") +@AllowCors +public class RuleUpdateActor extends AbstractHttpActor { + + @Override + public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration httpConfiguration) { + return request + .receive() + .asString(StandardCharsets.UTF_8) + .map(this.toList(RuleChainDefinition.class)) + .doOnNext(message -> { + // todo + log.info("http request url {} body {}", request.path(), message); + }).then(response.sendString(Mono.just("success")).then()); + } + +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/source/SourceAddActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/source/SourceAddActor.java new file mode 100644 index 0000000000000000000000000000000000000000..9916f0b55378bf644161c438db96051519fce7a7 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/source/SourceAddActor.java @@ -0,0 +1,42 @@ +package io.github.quickmsg.core.http.actors.source; + +import io.github.quickmsg.common.annotation.AllowCors; +import io.github.quickmsg.common.annotation.Header; +import io.github.quickmsg.common.annotation.Router; +import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.common.rule.source.SourceDefinition; +import io.github.quickmsg.core.http.AbstractHttpActor; +import lombok.extern.slf4j.Slf4j; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; + +import java.nio.charset.StandardCharsets; + + +/** + * 数据源添加 + * + * @author zhaopeng + */ +@Router(value = "/smqtt/sourceAdd", type = HttpType.POST) +@Slf4j +@Header(key = "Content-Type", value = "application/json") +@AllowCors +public class SourceAddActor extends AbstractHttpActor { + + @Override + public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration httpConfiguration) { + return request + .receive() + .asString(StandardCharsets.UTF_8) + .map(this.toList(SourceDefinition.class)) + .doOnNext(message -> { + // todo + log.info("http request url {} body {}", request.path(), message); + }).then(response.sendString(Mono.just("success")).then()); + } + +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/source/SourceDeleteActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/source/SourceDeleteActor.java new file mode 100644 index 0000000000000000000000000000000000000000..03fe809a71b4bdabd390df8ebf88975342adb56d --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/source/SourceDeleteActor.java @@ -0,0 +1,41 @@ +package io.github.quickmsg.core.http.actors.source; + +import io.github.quickmsg.common.annotation.AllowCors; +import io.github.quickmsg.common.annotation.Header; +import io.github.quickmsg.common.annotation.Router; +import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.common.rule.source.SourceDefinition; +import io.github.quickmsg.core.http.AbstractHttpActor; +import lombok.extern.slf4j.Slf4j; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; + +import java.nio.charset.StandardCharsets; + + +/** + * 数据源删除 + * + * @author zhaopeng + */ +@Router(value = "/smqtt/sourceDelete", type = HttpType.POST) +@Slf4j +@Header(key = "Content-Type", value = "application/json") +@AllowCors +public class SourceDeleteActor extends AbstractHttpActor { + + @Override + public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration httpConfiguration) { + return request + .receive() + .asString(StandardCharsets.UTF_8) + .map(this.toList(SourceDefinition.class)) + .doOnNext(message -> { + // todo + log.info("http request url {} body {}", request.path(), message); + }).then(response.sendString(Mono.just("success")).then()); + } +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/source/SourceQueryActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/source/SourceQueryActor.java new file mode 100644 index 0000000000000000000000000000000000000000..c29fe97ef978aeecbeae0102dc0b405407ee1141 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/source/SourceQueryActor.java @@ -0,0 +1,66 @@ +package io.github.quickmsg.core.http.actors.source; + +import io.github.quickmsg.common.annotation.AllowCors; +import io.github.quickmsg.common.annotation.Header; +import io.github.quickmsg.common.annotation.Router; +import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.common.rule.source.Source; +import io.github.quickmsg.common.rule.source.SourceDefinition; +import io.github.quickmsg.common.utils.JacksonUtil; +import io.github.quickmsg.core.http.AbstractHttpActor; +import lombok.extern.slf4j.Slf4j; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +/** + * 数据源查询 + * + * @author zhaopeng + */ +@Router(value = "/smqtt/sourceQuery", type = HttpType.POST) +@Slf4j +@Header(key = "Content-Type", value = "application/json") +@AllowCors +public class SourceQueryActor extends AbstractHttpActor { + + @Override + public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration httpConfiguration) { + SourceDefinition sourceDefinition = new SourceDefinition(); + sourceDefinition.setSourceName("S1"); + sourceDefinition.setSource(Source.KAFKA); + + Map sourceAttributes = new HashMap<>(); + sourceAttributes.put("host", "110"); + + sourceDefinition.setSourceAttributes(sourceAttributes); + + SourceDefinition sourceDefinition2 = new SourceDefinition(); + sourceDefinition2.setSourceName("S1"); + sourceDefinition2.setSource(Source.KAFKA); + + Map sourceAttributes2 = new HashMap<>(); + sourceAttributes2.put("host", "111"); + + sourceDefinition2.setSourceAttributes(sourceAttributes2); + + List list = new ArrayList<>(); + list.add(sourceDefinition); + list.add(sourceDefinition2); + + return request + .receive() + .then(response + .sendString(Mono.just(JacksonUtil.bean2Json(list))) + .then()); + } + +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/source/SourceTypeActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/source/SourceTypeActor.java new file mode 100644 index 0000000000000000000000000000000000000000..d6cc601a8c322ca2bd0dc7ea4c1818ead96b6b93 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/source/SourceTypeActor.java @@ -0,0 +1,42 @@ +package io.github.quickmsg.core.http.actors.source; + +import io.github.quickmsg.common.annotation.AllowCors; +import io.github.quickmsg.common.annotation.Header; +import io.github.quickmsg.common.annotation.Router; +import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.common.rule.source.Source; +import io.github.quickmsg.common.utils.JacksonUtil; +import io.github.quickmsg.core.http.AbstractHttpActor; +import lombok.extern.slf4j.Slf4j; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; + +import java.util.Arrays; +import java.util.List; + + +/** + * 数据源枚举 + * + * @author zhaopeng + */ +@Router(value = "/smqtt/sourceType", type = HttpType.GET) +@Slf4j +@Header(key = "Content-Type", value = "application/json") +@AllowCors +public class SourceTypeActor extends AbstractHttpActor { + + @Override + public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration httpConfiguration) { + List list = Arrays.asList(Source.values()); + return request + .receive() + .then(response + .sendString(Mono.just(JacksonUtil.bean2Json(list))) + .then()); + } + +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/source/SourceUpdateActor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/source/SourceUpdateActor.java new file mode 100644 index 0000000000000000000000000000000000000000..0d18d3d8ab8f1fcda4caa3351fb499e823b316dd --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/actors/source/SourceUpdateActor.java @@ -0,0 +1,42 @@ +package io.github.quickmsg.core.http.actors.source; + +import io.github.quickmsg.common.annotation.AllowCors; +import io.github.quickmsg.common.annotation.Header; +import io.github.quickmsg.common.annotation.Router; +import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.enums.HttpType; +import io.github.quickmsg.common.rule.source.SourceDefinition; +import io.github.quickmsg.core.http.AbstractHttpActor; +import lombok.extern.slf4j.Slf4j; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +import reactor.netty.http.server.HttpServerRequest; +import reactor.netty.http.server.HttpServerResponse; + +import java.nio.charset.StandardCharsets; + + +/** + * 数据源更新 + * + * @author zhaopeng + */ +@Router(value = "/smqtt/sourceUpdate", type = HttpType.POST) +@Slf4j +@Header(key = "Content-Type", value = "application/json") +@AllowCors +public class SourceUpdateActor extends AbstractHttpActor { + + @Override + public Publisher doRequest(HttpServerRequest request, HttpServerResponse response, Configuration httpConfiguration) { + return request + .receive() + .asString(StandardCharsets.UTF_8) + .map(this.toList(SourceDefinition.class)) + .doOnNext(message -> { + // todo + log.info("http request url {} body {}", request.path(), message); + }).then(response.sendString(Mono.just("success")).then()); + } + +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/model/LoginVm.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/model/LoginVm.java index cca34e019f9a3302cfaa786d3e8a9325e04e6ee4..fc87a0075b892dc3cef44b621571157d7f7cb404 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/http/model/LoginVm.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/model/LoginVm.java @@ -1,6 +1,6 @@ package io.github.quickmsg.core.http.model; -import com.alibaba.fastjson.annotation.JSONField; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; /** @@ -9,10 +9,10 @@ import lombok.Data; @Data public class LoginVm { - @JSONField(name = "access_token") + @JsonProperty("access_token") private String accessToken; - @JSONField(name = "expires_in") + @JsonProperty("expires_in") private long expiresIn; diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/http/model/Msg.java b/smqtt-core/src/main/java/io/github/quickmsg/core/http/model/Msg.java new file mode 100644 index 0000000000000000000000000000000000000000..7f42e589f22be61e3ea7a849ad1ebad0d733ca1c --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/http/model/Msg.java @@ -0,0 +1,32 @@ +package io.github.quickmsg.core.http.model; + +import lombok.Builder; +import lombok.Data; +import lombok.ToString; + +/** + * 消息 + * + * @author zhaopeng + */ +@Data +@Builder +@ToString +public class Msg { + /** + * 成功 + */ + private Boolean success; + /** + * 状态码 + */ + private Integer code; + /** + * 消息 + */ + private String msg; + /** + * 数据 + */ + private T data; +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/inteceptor/CounterInterceptor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/inteceptor/CounterInterceptor.java deleted file mode 100644 index ddd5793975cf9bb159c44e62908486d687fdd445..0000000000000000000000000000000000000000 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/inteceptor/CounterInterceptor.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.github.quickmsg.core.inteceptor; - -import io.github.quickmsg.common.interceptor.Interceptor; -import io.github.quickmsg.common.interceptor.Invocation; -import io.github.quickmsg.core.metric.MetricManager; -import io.netty.handler.codec.mqtt.MqttMessage; -import io.netty.handler.codec.mqtt.MqttPublishMessage; -import lombok.extern.slf4j.Slf4j; - -/** - * @author luxurong - */ -@Slf4j -public class CounterInterceptor implements Interceptor { - - - @Override - public Object intercept(Invocation invocation) { - Object[] args = invocation.getArgs(); - MqttMessage mqttMessage = (MqttMessage) args[1]; - if (mqttMessage instanceof MqttPublishMessage) { - MetricManager.registryMetric((MqttPublishMessage) mqttMessage); - } - return invocation.proceed(); - } - - @Override - public int sort() { - return 999; - } -} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/metric/MetricManager.java b/smqtt-core/src/main/java/io/github/quickmsg/core/metric/MetricManager.java deleted file mode 100644 index 03ce43acbf4f718738efcadbb2ca22b9cc2de12d..0000000000000000000000000000000000000000 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/metric/MetricManager.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.github.quickmsg.core.metric; - -import io.github.quickmsg.core.counter.SideWindowCounter; -import io.github.quickmsg.core.counter.WindowCounter; -import io.netty.handler.codec.mqtt.MqttPublishMessage; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; - -import java.util.concurrent.TimeUnit; - -/** - * @author luxurong - */ -@Getter -@Slf4j -public class MetricManager { - - private static WindowCounter transportBufferSize = new SideWindowCounter(1, TimeUnit.MINUTES, "TRANSPORT-BUFFER-SIZE"); - - public static void registryMetric(MqttPublishMessage mqttPublishMessage) { - transportBufferSize.apply(mqttPublishMessage.payload().readableBytes()); - } - -} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/mqtt/AbstractReceiveContext.java b/smqtt-core/src/main/java/io/github/quickmsg/core/mqtt/AbstractReceiveContext.java index cad0f45890347181f4b18113a6d25b8989a813f9..0cc9a6e90565b4e612d4f4203a327f881d68bda4 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/mqtt/AbstractReceiveContext.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/mqtt/AbstractReceiveContext.java @@ -1,26 +1,46 @@ package io.github.quickmsg.core.mqtt; -import io.github.quickmsg.common.auth.PasswordAuthentication; +import io.github.quickmsg.common.retry.TimeAckManager; +import io.github.quickmsg.common.acl.AclManager; +import io.github.quickmsg.common.auth.AuthManager; import io.github.quickmsg.common.channel.ChannelRegistry; +import io.github.quickmsg.common.channel.traffic.TrafficHandlerLoader; import io.github.quickmsg.common.cluster.ClusterRegistry; -import io.github.quickmsg.common.config.AbstractConfiguration; -import io.github.quickmsg.common.config.Configuration; +import io.github.quickmsg.common.config.*; import io.github.quickmsg.common.context.ReceiveContext; +import io.github.quickmsg.common.enums.Event; +import io.github.quickmsg.common.message.EventRegistry; import io.github.quickmsg.common.message.MessageRegistry; +import io.github.quickmsg.common.metric.local.LocalMetricManager; +import io.github.quickmsg.common.metric.MetricManager; +import io.github.quickmsg.common.metric.MetricManagerHolder; import io.github.quickmsg.common.protocol.ProtocolAdaptor; +import io.github.quickmsg.common.rule.DslExecutor; import io.github.quickmsg.common.topic.TopicRegistry; import io.github.quickmsg.common.transport.Transport; -import io.github.quickmsg.core.DefaultChannelRegistry; -import io.github.quickmsg.core.DefaultMessageRegistry; -import io.github.quickmsg.core.DefaultProtocolAdaptor; -import io.github.quickmsg.core.DefaultTopicRegistry; +import io.github.quickmsg.core.acl.JCasBinAclManager; +import io.github.quickmsg.core.auth.AuthManagerFactory; import io.github.quickmsg.core.cluster.InJvmClusterRegistry; +import io.github.quickmsg.core.mqtt.traffic.CacheTrafficHandlerLoader; +import io.github.quickmsg.core.mqtt.traffic.LazyTrafficHandlerLoader; +import io.github.quickmsg.core.spi.DefaultChannelRegistry; +import io.github.quickmsg.core.spi.DefaultMessageRegistry; +import io.github.quickmsg.core.spi.DefaultProtocolAdaptor; +import io.github.quickmsg.core.spi.DefaultTopicRegistry; +import io.github.quickmsg.dsl.RuleDslParser; +import io.github.quickmsg.metric.InfluxDbMetricFactory; +import io.github.quickmsg.metric.PrometheusMetricFactory; +import io.github.quickmsg.rule.source.SourceManager; +import io.netty.handler.traffic.GlobalChannelTrafficShapingHandler; +import io.netty.handler.traffic.GlobalTrafficShapingHandler; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; +import reactor.core.scheduler.Schedulers; import reactor.netty.resources.LoopResources; import java.util.Optional; +import java.util.concurrent.TimeUnit; /** * @author luxurong @@ -44,39 +64,80 @@ public abstract class AbstractReceiveContext implements private final MessageRegistry messageRegistry; - private final PasswordAuthentication passwordAuthentication; - private final ClusterRegistry clusterRegistry; + private final EventRegistry eventRegistry; + + private final DslExecutor dslExecutor; + + private final MetricManager metricManager; + + private final TrafficHandlerLoader trafficHandlerLoader; + + private final TimeAckManager timeAckManager; + + private final AclManager aclManager; + + private final AuthManager authManager; + public AbstractReceiveContext(T configuration, Transport transport) { + AbstractConfiguration abstractConfiguration = castConfiguration(configuration); + RuleDslParser ruleDslParser = new RuleDslParser(abstractConfiguration.getRuleChainDefinitions()); this.configuration = configuration; this.transport = transport; + this.dslExecutor = ruleDslParser.parseRule(); + this.eventRegistry = eventRegistry(); this.protocolAdaptor = protocolAdaptor(); this.channelRegistry = channelRegistry(); this.topicRegistry = topicRegistry(); this.loopResources = LoopResources.create("smqtt-cluster-io", configuration.getBossThreadSize(), configuration.getWorkThreadSize(), true); + this.trafficHandlerLoader = trafficHandlerLoader(); this.messageRegistry = messageRegistry(); this.clusterRegistry = clusterRegistry(); - this.passwordAuthentication = basicAuthentication(); - AbstractConfiguration abstractConfiguration = castConfiguration(configuration); - this.channelRegistry.startUp(abstractConfiguration.getEnvContext()); - this.messageRegistry.startUp(abstractConfiguration.getEnvContext()); + this.channelRegistry.startUp(abstractConfiguration.getEnvironmentMap()); + this.messageRegistry.startUp(abstractConfiguration.getEnvironmentMap()); + this.metricManager = metricManager(abstractConfiguration.getMeterConfig()); + this.aclManager = new JCasBinAclManager(abstractConfiguration.getAclConfig()); + this.authManager = authManagerFactory().provider(abstractConfiguration.getAuthConfig()).getAuthManager(); + Optional.ofNullable(abstractConfiguration.getSourceDefinitions()).ifPresent(sourceDefinitions -> sourceDefinitions.forEach(SourceManager::loadSource)); + this.timeAckManager = new TimeAckManager(20, TimeUnit.MILLISECONDS, 50); } - private MessageRegistry messageRegistry() { - return Optional.ofNullable(MessageRegistry.INSTANCE) - .orElse(new DefaultMessageRegistry()); + private TrafficHandlerLoader trafficHandlerLoader() { + if (configuration.getGlobalReadWriteSize() == null && configuration.getChannelReadWriteSize() == null) { + return new CacheTrafficHandlerLoader(new GlobalTrafficShapingHandler(this.loopResources.onServer(true).next(), 60 * 1000)); + } else if (configuration.getChannelReadWriteSize() == null) { + String[] limits = configuration.getGlobalReadWriteSize().split(","); + return new CacheTrafficHandlerLoader(new GlobalTrafficShapingHandler(this.loopResources.onServer(true), Long.parseLong(limits[1]), Long.parseLong(limits[0]), 60 * 1000)); + } else if (configuration.getGlobalReadWriteSize() == null) { + String[] limits = configuration.getChannelReadWriteSize().split(","); + return new LazyTrafficHandlerLoader(() -> new GlobalTrafficShapingHandler(this.loopResources.onServer(true), Long.parseLong(limits[1]), Long.parseLong(limits[0]), 60 * 1000)); + } else { + String[] globalLimits = configuration.getGlobalReadWriteSize().split(","); + String[] channelLimits = configuration.getChannelReadWriteSize().split(","); + return new CacheTrafficHandlerLoader(new GlobalChannelTrafficShapingHandler(this.loopResources.onServer(true), Long.parseLong(globalLimits[1]), Long.parseLong(globalLimits[0]), Long.parseLong(channelLimits[1]), Long.parseLong(channelLimits[0]), 60 * 1000)); + } } - private PasswordAuthentication basicAuthentication() { - AbstractConfiguration abstractConfiguration = castConfiguration(configuration); - return Optional.ofNullable(PasswordAuthentication.INSTANCE) - .orElse(abstractConfiguration.getReactivePasswordAuth()); + public AuthManagerProvider authManagerFactory() { + return AuthManagerFactory::new; + } + + public interface AuthManagerProvider { + AuthManagerFactory provider(AuthConfig authConfig); + + } + + private EventRegistry eventRegistry() { + return Event::sender; + } + + private MessageRegistry messageRegistry() { + return Optional.ofNullable(MessageRegistry.INSTANCE).orElseGet(DefaultMessageRegistry::new); } private ChannelRegistry channelRegistry() { - return Optional.ofNullable(ChannelRegistry.INSTANCE) - .orElse(new DefaultChannelRegistry()); + return Optional.ofNullable(ChannelRegistry.INSTANCE).orElseGet(DefaultChannelRegistry::new); } private TopicRegistry topicRegistry() { @@ -85,14 +146,26 @@ public abstract class AbstractReceiveContext implements } private ProtocolAdaptor protocolAdaptor() { - return Optional.ofNullable(ProtocolAdaptor.INSTANCE) - .orElse(new DefaultProtocolAdaptor()) - .proxy(); + return Optional.ofNullable(ProtocolAdaptor.INSTANCE).orElse(new DefaultProtocolAdaptor(Schedulers.newBoundedElastic(configuration.getBusinessThreadSize(), configuration.getBusinessQueueSize(), "business-io"))).proxy(); } private ClusterRegistry clusterRegistry() { - return Optional.ofNullable(ClusterRegistry.INSTANCE) - .orElse(new InJvmClusterRegistry()); + return Optional.ofNullable(ClusterRegistry.INSTANCE).orElseGet(InJvmClusterRegistry::new); + } + + + private MetricManager metricManager(BootstrapConfig.MeterConfig meterConfig) { + ConfigCheck.checkMeterConfig(meterConfig); + return MetricManagerHolder.setMetricManager(Optional.ofNullable(meterConfig).map(config -> { + switch (config.getMeterType()) { + case INFLUXDB: + return new InfluxDbMetricFactory(config).getMetricManager(); + case PROMETHEUS: + return new PrometheusMetricFactory(config).getMetricManager(); + default: + return new LocalMetricManager(); + } + }).orElseGet(LocalMetricManager::new)); } diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/mqtt/MqttConfiguration.java b/smqtt-core/src/main/java/io/github/quickmsg/core/mqtt/MqttConfiguration.java index 634ea538301e6075ddf58744a96000aeae68891e..e4ee90bdb5bb628b75b643e20cd3d83b3b7415a5 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/mqtt/MqttConfiguration.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/mqtt/MqttConfiguration.java @@ -1,18 +1,13 @@ package io.github.quickmsg.core.mqtt; -import io.github.quickmsg.common.auth.PasswordAuthentication; -import io.github.quickmsg.common.cluster.ClusterConfig; -import io.github.quickmsg.common.config.AbstractConfiguration; -import io.github.quickmsg.common.config.SslContext; -import io.github.quickmsg.common.environment.EnvContext; +import io.github.quickmsg.common.config.*; +import io.github.quickmsg.common.rule.RuleChainDefinition; +import io.github.quickmsg.common.rule.source.SourceDefinition; import io.github.quickmsg.core.ssl.AbstractSslHandler; -import io.netty.channel.ChannelOption; import lombok.Data; -import reactor.netty.tcp.TcpServerConfig; +import java.util.List; import java.util.Map; -import java.util.Optional; -import java.util.function.Consumer; /** * @author luxurong @@ -20,10 +15,12 @@ import java.util.function.Consumer; @Data public class MqttConfiguration extends AbstractSslHandler implements AbstractConfiguration { - private Integer port = 0; + private Integer port = 1883; private Integer webSocketPort = 0; + private String webSocketPath = "/"; + private Integer lowWaterMark; private Integer highWaterMark; @@ -34,26 +31,40 @@ public class MqttConfiguration extends AbstractSslHandler implements AbstractCon private SslContext sslContext; - private PasswordAuthentication reactivePasswordAuth = (u, p) -> true; + private ConnectModel connectModel; + private Integer notKickSecond; + private Integer bossThreadSize = Runtime.getRuntime().availableProcessors(); - private Integer workThreadSize = Runtime.getRuntime().availableProcessors(); + private Integer workThreadSize = Runtime.getRuntime().availableProcessors() * 2; + + private Integer businessThreadSize = Runtime.getRuntime().availableProcessors() ; + + private Integer businessQueueSize = 100000; + + private String globalReadWriteSize; + + private String channelReadWriteSize; + + private Map options; + + private Map childOptions; + + private BootstrapConfig.ClusterConfig clusterConfig; + + private BootstrapConfig.MeterConfig meterConfig; + + private List ruleChainDefinitions; - private Consumer, ?>> options; + private List sourceDefinitions; - private Consumer, ?>> childOptions; + private AclConfig aclConfig; - private ClusterConfig clusterConfig = ClusterConfig.defaultClusterConfig(); + private AuthConfig authConfig; - private EnvContext envContext; + private Map environmentMap; - @Override - public Consumer getTcpServerConfig() { - return tcpServerConfig -> { - Optional.ofNullable(options).ifPresent(options -> options.accept(tcpServerConfig.options())); - Optional.ofNullable(childOptions).ifPresent(options -> options.accept(tcpServerConfig.childOptions())); - }; - } + private Integer messageMaxSize = 4194304; } diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/mqtt/MqttReceiveContext.java b/smqtt-core/src/main/java/io/github/quickmsg/core/mqtt/MqttReceiveContext.java index 6ceb69b16f088d7bedb6faed3a9850908ae76dda..b8045200744c3d5f38c4e218f2358efab6d265d7 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/mqtt/MqttReceiveContext.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/mqtt/MqttReceiveContext.java @@ -1,17 +1,12 @@ package io.github.quickmsg.core.mqtt; import io.github.quickmsg.common.channel.MqttChannel; +import io.github.quickmsg.common.message.SmqttMessage; import io.github.quickmsg.common.transport.Transport; import io.github.quickmsg.core.cluster.ClusterReceiver; -import io.github.quickmsg.core.cluster.ClusterSender; import io.netty.handler.codec.mqtt.MqttMessage; import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; -import reactor.netty.Connection; - -import java.time.Duration; /** * @author luxurong @@ -21,13 +16,10 @@ import java.time.Duration; public class MqttReceiveContext extends AbstractReceiveContext { - private final ClusterSender clusterSender; - private final ClusterReceiver clusterReceiver; public MqttReceiveContext(MqttConfiguration configuration, Transport transport) { super(configuration, transport); - this.clusterSender = new ClusterSender(Schedulers.newParallel("cluster-transport"), this); this.clusterReceiver = new ClusterReceiver(this); clusterReceiver.registry(); } @@ -38,15 +30,17 @@ public class MqttReceiveContext extends AbstractReceiveContext this.accept(mqttChannel, mqttMessage)); + .onErrorContinue((throwable, o) -> { + log.error("on message error {}",o,throwable); + }) + .filter(mqttMessage -> mqttMessage.decoderResult().isSuccess()) + .subscribe(mqttMessage -> this.accept(mqttChannel, new SmqttMessage<>(mqttMessage,System.currentTimeMillis(),Boolean.FALSE))); } @Override - public void accept(MqttChannel mqttChannel, MqttMessage mqttMessage) { - log.info("accept channel] {} message {}", mqttChannel.getConnection(), mqttMessage); + public void accept(MqttChannel mqttChannel, SmqttMessage mqttMessage) { this.getProtocolAdaptor().chooseProtocol(mqttChannel, mqttMessage, this); } diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/mqtt/MqttReceiver.java b/smqtt-core/src/main/java/io/github/quickmsg/core/mqtt/MqttReceiver.java index e5b210f90a558b113936042df082204cba2ba31f..f302dae0c64dd2287003b8c0d7873eef65896bf7 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/mqtt/MqttReceiver.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/mqtt/MqttReceiver.java @@ -27,22 +27,24 @@ public class MqttReceiver extends AbstractSslHandler implements Receiver { private TcpServer newTcpServer(ContextView context) { MqttReceiveContext receiveContext = context.get(MqttReceiveContext.class); MqttConfiguration mqttConfiguration = receiveContext.getConfiguration(); - TcpServer server = TcpServer.create(); - if (mqttConfiguration.getSsl()) { - server.secure(sslContextSpec -> this.secure(sslContextSpec, mqttConfiguration)); - } + TcpServer server = initTcpServer(mqttConfiguration); return server.port(mqttConfiguration.getPort()) - .doOnBind(mqttConfiguration.getTcpServerConfig()) .wiretap(mqttConfiguration.getWiretap()) .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(mqttConfiguration.getLowWaterMark(), mqttConfiguration.getHighWaterMark())) .childOption(ChannelOption.TCP_NODELAY, true) .childOption(ChannelOption.SO_KEEPALIVE, true) .childOption(ChannelOption.SO_REUSEADDR, true) + .metrics(mqttConfiguration.getMeterConfig() != null) + .option(ChannelOption.SO_REUSEADDR, true) .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) + .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) .runOn(receiveContext.getLoopResources()) .doOnConnection(connection -> { - connection.addHandler(new MqttDecoder()).addHandler(MqttEncoder.INSTANCE); - receiveContext.apply(MqttChannel.init(connection)); + connection + .addHandler(MqttEncoder.INSTANCE) + .addHandler(new MqttDecoder(mqttConfiguration.getMessageMaxSize())) + .addHandler(receiveContext.getTrafficHandlerLoader().get()); + receiveContext.apply(MqttChannel.init(connection,receiveContext.getTimeAckManager())); }); } } \ No newline at end of file diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/mqtt/traffic/CacheTrafficHandlerLoader.java b/smqtt-core/src/main/java/io/github/quickmsg/core/mqtt/traffic/CacheTrafficHandlerLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..1eb6e54ca5e96881a5533e3e368c238ca10b0c07 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/mqtt/traffic/CacheTrafficHandlerLoader.java @@ -0,0 +1,22 @@ +package io.github.quickmsg.core.mqtt.traffic; + +import io.github.quickmsg.common.channel.traffic.TrafficHandlerLoader; +import io.netty.handler.traffic.AbstractTrafficShapingHandler; + +/** + * @author luxurong + */ +public class CacheTrafficHandlerLoader implements TrafficHandlerLoader { + + + private final AbstractTrafficShapingHandler trafficShapingHandler; + + public CacheTrafficHandlerLoader(AbstractTrafficShapingHandler trafficShapingHandler) { + this.trafficShapingHandler = trafficShapingHandler; + } + + @Override + public AbstractTrafficShapingHandler get() { + return this.trafficShapingHandler; + } +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/mqtt/traffic/LazyTrafficHandlerLoader.java b/smqtt-core/src/main/java/io/github/quickmsg/core/mqtt/traffic/LazyTrafficHandlerLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..5f354148dd95501b0ce000db966cae7e6f33b4f0 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/mqtt/traffic/LazyTrafficHandlerLoader.java @@ -0,0 +1,27 @@ +package io.github.quickmsg.core.mqtt.traffic; + +import io.github.quickmsg.common.channel.traffic.TrafficHandlerLoader; +import io.netty.handler.traffic.AbstractTrafficShapingHandler; +import io.netty.handler.traffic.ChannelTrafficShapingHandler; +import io.netty.handler.traffic.GlobalChannelTrafficShapingHandler; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.function.Supplier; + +/** + * @author luxurong + */ +public class LazyTrafficHandlerLoader implements TrafficHandlerLoader { + + private final Supplier shapingHandlerSupplier; + + public LazyTrafficHandlerLoader(Supplier shapingHandlerSupplier) { + this.shapingHandlerSupplier = shapingHandlerSupplier; + } + + @Override + public AbstractTrafficShapingHandler get() { + return this.shapingHandlerSupplier.get(); + } + +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/CommonProtocol.java b/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/CommonProtocol.java index aea9c00fce29edb93c4060e189cd2a580fa53082..125aa237fdbcda8e5d6cce8a97cf4cd63102370c 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/CommonProtocol.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/CommonProtocol.java @@ -1,20 +1,31 @@ package io.github.quickmsg.core.protocol; +import io.github.quickmsg.common.retry.Ack; import io.github.quickmsg.common.channel.MqttChannel; import io.github.quickmsg.common.context.ReceiveContext; +import io.github.quickmsg.common.enums.ChannelStatus; +import io.github.quickmsg.common.message.MessageRegistry; import io.github.quickmsg.common.message.MqttMessageBuilder; +import io.github.quickmsg.common.message.SessionMessage; +import io.github.quickmsg.common.message.SmqttMessage; +import io.github.quickmsg.common.metric.CounterType; +import io.github.quickmsg.common.metric.MetricManagerHolder; import io.github.quickmsg.common.protocol.Protocol; +import io.github.quickmsg.common.topic.SubscribeTopic; import io.github.quickmsg.common.topic.TopicRegistry; import io.github.quickmsg.common.utils.MessageUtils; import io.netty.handler.codec.mqtt.MqttMessage; import io.netty.handler.codec.mqtt.MqttMessageIdVariableHeader; import io.netty.handler.codec.mqtt.MqttMessageType; +import io.netty.handler.codec.mqtt.MqttPublishMessage; import lombok.extern.slf4j.Slf4j; import reactor.core.publisher.Mono; +import reactor.netty.Connection; import reactor.util.context.ContextView; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -38,20 +49,28 @@ public class CommonProtocol implements Protocol { @Override - public Mono parseProtocol(MqttMessage message, MqttChannel mqttChannel, ContextView contextView) { + public Mono parseProtocol(SmqttMessage smqttMessage, MqttChannel mqttChannel, ContextView contextView) { + ReceiveContext receiveContext = contextView.get(ReceiveContext.class); + MqttMessage message = smqttMessage.getMessage(); switch (message.fixedHeader().messageType()) { case PINGREQ: return mqttChannel.write(MqttMessageBuilder.buildPongMessage(), false); case DISCONNECT: - return Mono.fromRunnable(()->{ + return Mono.fromRunnable(() -> { + MetricManagerHolder.metricManager.getMetricRegistry().getMetricCounter(CounterType.DIS_CONNECT_EVENT).increment(); mqttChannel.setWill(null); - mqttChannel.getConnection().dispose(); + Connection connection; + if (!(connection = mqttChannel.getConnection()).isDisposed()) { + connection.dispose(); + } }); case PUBREC: MqttMessageIdVariableHeader messageIdVariableHeader = (MqttMessageIdVariableHeader) message.variableHeader(); int messageId = messageIdVariableHeader.messageId(); - return mqttChannel.cancelRetry(MqttMessageType.PUBLISH, messageId) - .then(mqttChannel.write(MqttMessageBuilder.buildPublishRel(messageId), true)); + return Mono.fromRunnable(() -> { + Optional.ofNullable(receiveContext.getTimeAckManager().getAck(mqttChannel.generateId(MqttMessageType.PUBLISH, messageId))) + .ifPresent(Ack::stop); + }).then(mqttChannel.write(MqttMessageBuilder.buildPublishRel(messageId), true)); case PUBREL: MqttMessageIdVariableHeader relMessageIdVariableHeader = (MqttMessageIdVariableHeader) message.variableHeader(); int id = relMessageIdVariableHeader.messageId(); @@ -62,21 +81,30 @@ public class CommonProtocol implements Protocol { */ return mqttChannel.removeQos2Msg(id) .map(msg -> { - ReceiveContext receiveContext = contextView.get(ReceiveContext.class); TopicRegistry topicRegistry = receiveContext.getTopicRegistry(); - Set mqttChannels = topicRegistry.getChannelListByTopic(msg.variableHeader().topicName()); + MessageRegistry messageRegistry = receiveContext.getMessageRegistry(); + Set subscribeTopics = topicRegistry.getSubscribesByTopic(msg.variableHeader().topicName(), msg.fixedHeader().qosLevel()); return Mono.when( - mqttChannels.stream() - .map(channel -> channel.write(MessageUtils.wrapPublishMessage(msg, channel.generateMessageId()), true)) - .collect(Collectors.toList())) - .then(mqttChannel.cancelRetry(MqttMessageType.PUBREC, id)) + subscribeTopics.stream() + .filter(subscribeTopic -> filterOfflineSession(subscribeTopic.getMqttChannel(), messageRegistry, MessageUtils.wrapPublishMessage(msg, subscribeTopic.getQoS(), subscribeTopic.getMqttChannel().generateMessageId()))) + .map(subscribeTopic -> subscribeTopic.getMqttChannel() + .write(MessageUtils.wrapPublishMessage(msg, subscribeTopic.getQoS(), + subscribeTopic.getMqttChannel().generateMessageId()), subscribeTopic.getQoS().value() > 0) + ).collect(Collectors.toList())) + .then(Mono.fromRunnable(() -> { + Optional.ofNullable(receiveContext.getTimeAckManager().getAck(mqttChannel.generateId(MqttMessageType.PUBREC, id))) + .ifPresent(Ack::stop); + })) .then(mqttChannel.write(MqttMessageBuilder.buildPublishComp(id), false)); - }).orElse(mqttChannel.write(MqttMessageBuilder.buildPublishComp(id), false)); + }).orElseGet(() -> mqttChannel.write(MqttMessageBuilder.buildPublishComp(id), false)); case PUBCOMP: MqttMessageIdVariableHeader messageIdVariableHeader1 = (MqttMessageIdVariableHeader) message.variableHeader(); int compId = messageIdVariableHeader1.messageId(); - return mqttChannel.cancelRetry(MqttMessageType.PUBREL, compId); + return Mono.fromRunnable(() -> { + Optional.ofNullable(receiveContext.getTimeAckManager().getAck(mqttChannel.generateId(MqttMessageType.PUBREL, compId))) + .ifPresent(Ack::stop); + }); case PINGRESP: default: return Mono.empty(); @@ -88,4 +116,22 @@ public class CommonProtocol implements Protocol { public List getMqttMessageTypes() { return MESSAGE_TYPE_LIST; } + + /** + * 过滤离线会话消息 + * + * @param mqttChannel {@link MqttChannel} + * @param messageRegistry {@link MessageRegistry} + * @param mqttMessage {@link MqttPublishMessage} + * @return boolean + */ + private boolean filterOfflineSession(MqttChannel mqttChannel, MessageRegistry messageRegistry, MqttPublishMessage mqttMessage) { + if (mqttChannel.getStatus() == ChannelStatus.ONLINE) { + return true; + } else { + messageRegistry + .saveSessionMessage(SessionMessage.of(mqttChannel.getClientIdentifier(), mqttMessage)); + return false; + } + } } diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/ConnectAckProtocol.java b/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/ConnectAckProtocol.java index 39c078ac4f54d26da01e678bbc120865b38792ce..967349443a6baeeea0b0d8bf54379dca3014568f 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/ConnectAckProtocol.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/ConnectAckProtocol.java @@ -1,8 +1,10 @@ package io.github.quickmsg.core.protocol; import io.github.quickmsg.common.channel.MqttChannel; +import io.github.quickmsg.common.message.SmqttMessage; import io.github.quickmsg.common.protocol.Protocol; import io.netty.handler.codec.mqtt.MqttConnAckMessage; +import io.netty.handler.codec.mqtt.MqttMessage; import io.netty.handler.codec.mqtt.MqttMessageType; import reactor.core.publisher.Mono; import reactor.util.context.ContextView; @@ -24,7 +26,8 @@ public class ConnectAckProtocol implements Protocol { @Override - public Mono parseProtocol(MqttConnAckMessage message, MqttChannel mqttChannel, ContextView contextView) { + public Mono parseProtocol(SmqttMessage smqttMessage, MqttChannel mqttChannel, ContextView contextView) { + MqttMessage message = smqttMessage.getMessage(); return mqttChannel.cancelRetry(MqttMessageType.CONNECT,-1); } diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/ConnectProtocol.java b/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/ConnectProtocol.java index 68349816cb0954c7922b84098829f5d2d702f60b..4b90cd7f48c61e2583f530dcc196a126460a7039 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/ConnectProtocol.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/ConnectProtocol.java @@ -1,13 +1,21 @@ package io.github.quickmsg.core.protocol; -import io.github.quickmsg.common.auth.PasswordAuthentication; +import io.github.quickmsg.common.acl.AclAction; +import io.github.quickmsg.common.acl.AclManager; +import io.github.quickmsg.common.auth.AuthManager; import io.github.quickmsg.common.channel.ChannelRegistry; import io.github.quickmsg.common.channel.MqttChannel; +import io.github.quickmsg.common.config.AuthConfig; +import io.github.quickmsg.common.config.ConnectModel; import io.github.quickmsg.common.context.ReceiveContext; import io.github.quickmsg.common.enums.ChannelStatus; -import io.github.quickmsg.common.message.MessageRegistry; -import io.github.quickmsg.common.message.MqttMessageBuilder; +import io.github.quickmsg.common.enums.Event; +import io.github.quickmsg.common.message.*; +import io.github.quickmsg.common.metric.CounterType; +import io.github.quickmsg.common.metric.MetricManager; +import io.github.quickmsg.common.metric.MetricManagerHolder; import io.github.quickmsg.common.protocol.Protocol; +import io.github.quickmsg.common.topic.SubscribeTopic; import io.github.quickmsg.common.topic.TopicRegistry; import io.github.quickmsg.core.mqtt.MqttReceiveContext; import io.netty.buffer.Unpooled; @@ -21,6 +29,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; /** * @author luxurong @@ -37,115 +46,129 @@ public class ConnectProtocol implements Protocol { MESSAGE_TYPE_LIST.add(MqttMessageType.CONNECT); } - @Override - public Mono parseProtocol(MqttConnectMessage message, MqttChannel mqttChannel, ContextView contextView) { - MqttReceiveContext mqttReceiveContext = (MqttReceiveContext) contextView.get(ReceiveContext.class); - MqttConnectVariableHeader mqttConnectVariableHeader = message.variableHeader(); - MqttConnectPayload mqttConnectPayload = message.payload(); - String clientIdentifier = mqttConnectPayload.clientIdentifier(); - ChannelRegistry channelRegistry = mqttReceiveContext.getChannelRegistry(); - TopicRegistry topicRegistry = mqttReceiveContext.getTopicRegistry(); - PasswordAuthentication passwordAuthentication = mqttReceiveContext.getPasswordAuthentication(); - if (channelRegistry.exists(clientIdentifier) - && channelRegistry.get(clientIdentifier).getStatus() == ChannelStatus.OFFLINE) { - return mqttChannel.write( - MqttMessageBuilder.buildConnectAck(MqttConnectReturnCode.CONNECTION_REFUSED_IDENTIFIER_REJECTED), - false).then(mqttChannel.close()); - } - if (MqttVersion.MQTT_3_1_1.protocolLevel() != (byte) mqttConnectVariableHeader.version()) { - return mqttChannel.write( - MqttMessageBuilder.buildConnectAck(MqttConnectReturnCode.CONNECTION_REFUSED_UNACCEPTABLE_PROTOCOL_VERSION), - false).then(mqttChannel.close()); - } - if (passwordAuthentication.auth(mqttConnectPayload.userName(), mqttConnectPayload.passwordInBytes())) { - /*cancel defer close not authenticate channel */ - mqttChannel.getCloseDisposable().dispose(); - mqttChannel.setClientIdentifier(mqttConnectPayload.clientIdentifier()); - if (mqttConnectVariableHeader.isWillFlag()) { - mqttChannel.setWill(MqttChannel.Will.builder() - .isRetain(mqttConnectVariableHeader.isWillRetain()) - .willTopic(mqttConnectPayload.willTopic()) - .willMessage(mqttConnectPayload.willMessageInBytes()) - .mqttQoS(MqttQoS.valueOf(mqttConnectVariableHeader.willQos())) - .build()); - } - mqttChannel.setAuthTime(System.currentTimeMillis()); - mqttChannel.setKeepalive(mqttConnectVariableHeader.keepAliveTimeSeconds()); - mqttChannel.setSessionPersistent(!mqttConnectVariableHeader.isCleanSession()); - mqttChannel.setStatus(ChannelStatus.ONLINE); - mqttChannel.setUsername(mqttConnectPayload.userName()); - /*registry unread event close channel */ - - mqttChannel.getConnection() - .onReadIdle(mqttConnectVariableHeader.keepAliveTimeSeconds() * MILLI_SECOND_PERIOD << 1, - () -> close(mqttChannel, mqttReceiveContext)); - - /*registry will message send */ - mqttChannel.registryClose(channel -> Optional.ofNullable(mqttChannel.getWill()) - .ifPresent(will -> - topicRegistry.getChannelListByTopic(will.getWillTopic()) - .forEach(mqttChannel1 -> { - mqttChannel1.write( - MqttMessageBuilder - .buildPub(false, - will.getMqttQoS(), - will.getMqttQoS() == MqttQoS.AT_MOST_ONCE - ? 0 : mqttChannel1.generateMessageId(), - will.getWillTopic(), - Unpooled.wrappedBuffer(will.getWillMessage()) - ), will.getMqttQoS().value() > 0 - ).subscribe(); - }))); - - Optional.ofNullable(channelRegistry.get(clientIdentifier)) - .ifPresent(sessionChannel -> { - doSession(sessionChannel, mqttChannel, channelRegistry, topicRegistry, mqttReceiveContext.getMessageRegistry()); - }); - - // registry close mqtt channel event - mqttChannel.registryClose(channel -> this.close(mqttChannel, mqttReceiveContext)); - - channelRegistry.registry(clientIdentifier, mqttChannel); - - return mqttChannel.write(MqttMessageBuilder.buildConnectAck(MqttConnectReturnCode.CONNECTION_ACCEPTED), false); - - } else { - return mqttChannel.write( - MqttMessageBuilder.buildConnectAck(MqttConnectReturnCode.CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD), - false).then(mqttChannel.close()); - } + private static void accept(MqttChannel mqttChannel1) { +// metric.getMetricCounter(CounterEnum.CONNECT_COUNTER).decrement(); } - private void close(MqttChannel mqttChannel, MqttReceiveContext mqttReceiveContext) { - if (mqttChannel.isSessionPersistent()) { - mqttChannel.setStatus(ChannelStatus.OFFLINE); - mqttChannel.close().subscribe(); - } else { - mqttReceiveContext.getTopicRegistry().clear(mqttChannel); - mqttReceiveContext.getChannelRegistry().close(mqttChannel); + @Override + public Mono parseProtocol(SmqttMessage smqttMessage, MqttChannel mqttChannel, ContextView contextView) { + try { + MqttConnectMessage message = smqttMessage.getMessage(); + MetricManagerHolder.metricManager.getMetricRegistry().getMetricCounter(CounterType.CONNECT_EVENT).increment(); + MqttReceiveContext mqttReceiveContext = (MqttReceiveContext) contextView.get(ReceiveContext.class); + EventRegistry eventRegistry = mqttReceiveContext.getEventRegistry(); + MqttConnectVariableHeader mqttConnectVariableHeader = message.variableHeader(); + MqttConnectPayload mqttConnectPayload = message.payload(); + String clientIdentifier = mqttConnectPayload.clientIdentifier(); + ChannelRegistry channelRegistry = mqttReceiveContext.getChannelRegistry(); + TopicRegistry topicRegistry = mqttReceiveContext.getTopicRegistry(); + MetricManager metricManager = mqttReceiveContext.getMetricManager(); + byte mqttVersion = (byte) mqttConnectVariableHeader.version(); + AuthManager authManager = mqttReceiveContext.getAuthManager(); + /*check clientIdentifier exist*/ + MqttChannel existMqttChannel = channelRegistry.get(clientIdentifier); + if (mqttReceiveContext.getConfiguration().getConnectModel() == ConnectModel.UNIQUE) { + if (existMqttChannel != null && existMqttChannel.getStatus() == ChannelStatus.ONLINE) { + return mqttChannel.write( + MqttMessageBuilder.buildConnectAck(MqttConnectReturnCode.CONNECTION_REFUSED_IDENTIFIER_REJECTED, mqttVersion), + false).then(mqttChannel.close()); + } + } else { + if (existMqttChannel != null && existMqttChannel.getStatus() == ChannelStatus.ONLINE) { + if (System.currentTimeMillis() - existMqttChannel.getConnectTime() > (mqttReceiveContext.getConfiguration().getNotKickSecond() * 1000)) { + existMqttChannel.close().subscribe(); + } else { + return mqttChannel.write( + MqttMessageBuilder.buildConnectAck(MqttConnectReturnCode.CONNECTION_REFUSED_IDENTIFIER_REJECTED, mqttVersion), + false).then(mqttChannel.close()); + } + } + } + /*protocol version support*/ + if (MqttVersion.MQTT_3_1.protocolLevel() != mqttVersion && + MqttVersion.MQTT_3_1_1.protocolLevel() != mqttVersion + && MqttVersion.MQTT_5.protocolLevel() != mqttVersion) { + return mqttChannel.write( + MqttMessageBuilder.buildConnectAck(MqttConnectReturnCode.CONNECTION_REFUSED_UNACCEPTABLE_PROTOCOL_VERSION, mqttVersion), + false).then(mqttChannel.close()); + } + /*password check*/ + if (authManager.auth(mqttConnectPayload.userName(),mqttConnectPayload.passwordInBytes(), clientIdentifier)) { + /*cancel defer close not authenticate channel */ + mqttChannel.disposableClose(); + mqttChannel.setClientIdentifier(mqttConnectPayload.clientIdentifier()); + if (mqttConnectVariableHeader.isWillFlag()) { + mqttChannel.setWill(MqttChannel.Will.builder() + .isRetain(mqttConnectVariableHeader.isWillRetain()) + .willTopic(mqttConnectPayload.willTopic()) + .willMessage(mqttConnectPayload.willMessageInBytes()) + .mqttQoS(MqttQoS.valueOf(mqttConnectVariableHeader.willQos())) + .build()); + } + mqttChannel.setAuthTime(System.currentTimeMillis()); + mqttChannel.setConnectTime(System.currentTimeMillis()); + mqttChannel.setKeepalive(mqttConnectVariableHeader.keepAliveTimeSeconds()); + mqttChannel.setSessionPersistent(!mqttConnectVariableHeader.isCleanSession()); + mqttChannel.setStatus(ChannelStatus.ONLINE); + mqttChannel.setUsername(mqttConnectPayload.userName()); + /*registry unread event close channel */ + + mqttChannel.getConnection().onReadIdle((long) mqttConnectVariableHeader.keepAliveTimeSeconds() * MILLI_SECOND_PERIOD << 1, + () -> close(metricManager, mqttChannel, mqttReceiveContext, eventRegistry)); + + CloseMqttMessage closeMqttMessage = new CloseMqttMessage(); + closeMqttMessage.setClientIdentifier(clientIdentifier); + ClusterMessage clusterMessage = new ClusterMessage(closeMqttMessage); + mqttReceiveContext.getClusterRegistry().spreadPublishMessage(clusterMessage) + .subscribe(); + + /*registry will message send */ + mqttChannel.registryClose(channel -> Optional.ofNullable(mqttChannel.getWill()) + .ifPresent(will -> + topicRegistry.getSubscribesByTopic(will.getWillTopic(), will.getMqttQoS()) + .forEach(subscribeTopic -> { + MqttChannel subscribeChannel = subscribeTopic.getMqttChannel(); + subscribeChannel.write( + MqttMessageBuilder + .buildPub(false, + subscribeTopic.getQoS(), + subscribeTopic.getQoS() == MqttQoS.AT_MOST_ONCE + ? 0 : subscribeChannel.generateMessageId(), + will.getWillTopic(), + Unpooled.wrappedBuffer(will.getWillMessage()) + ), subscribeTopic.getQoS().value() > 0 + ).subscribe(); + }))); + /* do session message*/ + doSession(mqttChannel, channelRegistry, topicRegistry); + + + /* registry new channel*/ + channelRegistry.registry(mqttChannel.getClientIdentifier(), mqttChannel); + + /* registry close mqtt channel event*/ + mqttChannel.registryClose(channel -> this.close(metricManager, mqttChannel, mqttReceiveContext, eventRegistry)); + + metricManager.getMetricRegistry().getMetricCounter(CounterType.CONNECT).increment(); + + mqttChannel.registryClose(channel -> metricManager.getMetricRegistry().getMetricCounter(CounterType.CONNECT).decrement()); + + eventRegistry.registry(Event.CONNECT, mqttChannel, message, mqttReceiveContext); + + return mqttChannel.write(MqttMessageBuilder.buildConnectAck(MqttConnectReturnCode.CONNECTION_ACCEPTED, mqttVersion), false) + .then(Mono.fromRunnable(() -> sendOfflineMessage(mqttReceiveContext.getMessageRegistry(), mqttChannel))); + } else { + return mqttChannel.write( + MqttMessageBuilder.buildConnectAck(MqttConnectReturnCode.CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD, mqttVersion), + false).then(mqttChannel.close()); + } + } catch (Exception e) { + log.error("connect error ", e); } - + return Mono.empty(); } - /** - * 处理session消息 - * - * @param sessionChannel session channel - * @param mqttChannel new channel - * @param channelRegistry channel注册 - * @param topicRegistry 主题注册 - * @param messageRegistry 消息注册 - */ - private void doSession(MqttChannel sessionChannel, - MqttChannel mqttChannel, - ChannelRegistry channelRegistry, - TopicRegistry topicRegistry, - MessageRegistry messageRegistry) { - Set topics = sessionChannel.getTopics(); - mqttChannel.setTopics(topics); - topicRegistry.clear(sessionChannel); - topics.forEach(topic -> topicRegistry.registryTopicConnection(topic, mqttChannel)); - channelRegistry.close(sessionChannel); + private void sendOfflineMessage(MessageRegistry messageRegistry, MqttChannel mqttChannel) { Optional.ofNullable(messageRegistry.getSessionMessage(mqttChannel.getClientIdentifier())) .ifPresent(sessionMessages -> { sessionMessages.forEach(sessionMessage -> { @@ -158,6 +181,48 @@ public class ConnectProtocol implements Protocol { }); } + private void close(MetricManager metricManager, MqttChannel mqttChannel, MqttReceiveContext mqttReceiveContext, EventRegistry eventRegistry) { + + log.info(" 【{}】【{}】 【{}】", + Thread.currentThread().getName(), + "CLOSE", + mqttChannel); + mqttChannel.setStatus(ChannelStatus.OFFLINE); + if (!mqttChannel.isSessionPersistent()) { + mqttReceiveContext.getTopicRegistry().clear(mqttChannel); + mqttReceiveContext.getChannelRegistry().close(mqttChannel); + } + eventRegistry.registry(Event.CLOSE, mqttChannel, null, mqttReceiveContext); + metricManager.getMetricRegistry().getMetricCounter(CounterType.CLOSE_EVENT).increment(); + mqttChannel.close().subscribe(); + } + + /** + * session + * + * @param mqttChannel new channel {@link MqttChannel} + * @param channelRegistry {@link ChannelRegistry} + * @param topicRegistry {@link TopicRegistry} + */ + private void doSession(MqttChannel mqttChannel, + ChannelRegistry channelRegistry, + TopicRegistry topicRegistry) { + Optional.ofNullable(channelRegistry.get(mqttChannel.getClientIdentifier())) + .ifPresent(sessionChannel -> { + Set topics = sessionChannel.getTopics().stream().map(subscribeTopic -> + new SubscribeTopic( + subscribeTopic.getTopicFilter(), + subscribeTopic.getQoS(), + mqttChannel)) + .collect(Collectors.toSet()); + // registry new chanel + topicRegistry.registrySubscribesTopic(topics); + // remove old channel + channelRegistry.close(sessionChannel); + topicRegistry.clear(sessionChannel); + }); + } + @Override public List getMqttMessageTypes() { diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/PublishAckProtocol.java b/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/PublishAckProtocol.java index 26cdd8312f6d50d7ba8d51357a616a77f73fcd15..c8ba575a4b3ac99a864514a4cd58b607835370b5 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/PublishAckProtocol.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/PublishAckProtocol.java @@ -1,6 +1,9 @@ package io.github.quickmsg.core.protocol; +import io.github.quickmsg.common.retry.Ack; import io.github.quickmsg.common.channel.MqttChannel; +import io.github.quickmsg.common.context.ReceiveContext; +import io.github.quickmsg.common.message.SmqttMessage; import io.github.quickmsg.common.protocol.Protocol; import io.netty.handler.codec.mqtt.MqttMessageIdVariableHeader; import io.netty.handler.codec.mqtt.MqttMessageType; @@ -10,6 +13,7 @@ import reactor.util.context.ContextView; import java.util.ArrayList; import java.util.List; +import java.util.Optional; /** * @author luxurong @@ -25,10 +29,15 @@ public class PublishAckProtocol implements Protocol { @Override - public Mono parseProtocol(MqttPubAckMessage message, MqttChannel mqttChannel, ContextView contextView) { - MqttMessageIdVariableHeader idVariableHeader = message.variableHeader(); - int messageId = idVariableHeader.messageId(); - return mqttChannel.cancelRetry(MqttMessageType.PUBLISH,messageId); + public Mono parseProtocol(SmqttMessage smqttMessage, MqttChannel mqttChannel, ContextView contextView) { + return Mono.fromRunnable(()->{ + ReceiveContext receiveContext = contextView.get(ReceiveContext.class); + MqttPubAckMessage message = smqttMessage.getMessage(); + MqttMessageIdVariableHeader idVariableHeader = message.variableHeader(); + int messageId = idVariableHeader.messageId(); + Optional.ofNullable(receiveContext.getTimeAckManager().getAck(mqttChannel.generateId(MqttMessageType.PUBLISH,messageId))) + .ifPresent(Ack::stop); + }); } @Override diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/PublishProtocol.java b/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/PublishProtocol.java index d56922a716c6e6e229785d229b420308748bcdac..2d9112359bb6bb7c9d655e3940d04b7584ce2b01 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/PublishProtocol.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/PublishProtocol.java @@ -1,13 +1,15 @@ package io.github.quickmsg.core.protocol; +import io.github.quickmsg.common.acl.AclAction; +import io.github.quickmsg.common.acl.AclManager; import io.github.quickmsg.common.channel.MqttChannel; import io.github.quickmsg.common.context.ReceiveContext; import io.github.quickmsg.common.enums.ChannelStatus; -import io.github.quickmsg.common.message.MessageRegistry; -import io.github.quickmsg.common.message.MqttMessageBuilder; -import io.github.quickmsg.common.message.RetainMessage; -import io.github.quickmsg.common.message.SessionMessage; +import io.github.quickmsg.common.message.*; +import io.github.quickmsg.common.metric.CounterType; +import io.github.quickmsg.common.metric.MetricManagerHolder; import io.github.quickmsg.common.protocol.Protocol; +import io.github.quickmsg.common.topic.SubscribeTopic; import io.github.quickmsg.common.topic.TopicRegistry; import io.github.quickmsg.common.utils.MessageUtils; import io.netty.handler.codec.mqtt.MqttMessageType; @@ -41,13 +43,22 @@ public class PublishProtocol implements Protocol { @Override - public Mono parseProtocol(MqttPublishMessage message, MqttChannel mqttChannel, ContextView contextView) { + public Mono parseProtocol(SmqttMessage smqttMessage, MqttChannel mqttChannel, ContextView contextView) { + ReceiveContext receiveContext = contextView.get(ReceiveContext.class); try { - ReceiveContext receiveContext = contextView.get(ReceiveContext.class); + MetricManagerHolder.metricManager.getMetricRegistry().getMetricCounter(CounterType.PUBLISH_EVENT).increment(); + MqttPublishMessage message = smqttMessage.getMessage(); + AclManager aclManager = receiveContext.getAclManager(); + if (!mqttChannel.getIsMock() && !aclManager.check(mqttChannel, message.variableHeader().topicName(), AclAction.PUBLISH)) { + log.warn("mqtt【{}】publish topic 【{}】 acl not authorized ", mqttChannel.getConnection(), message.variableHeader().topicName()); + return Mono.empty(); + } + TopicRegistry topicRegistry = receiveContext.getTopicRegistry(); MqttPublishVariableHeader variableHeader = message.variableHeader(); MessageRegistry messageRegistry = receiveContext.getMessageRegistry(); - Set mqttChannels = topicRegistry.getChannelListByTopic(variableHeader.topicName()); + Set mqttChannels = topicRegistry.getSubscribesByTopic(variableHeader.topicName(), + message.fixedHeader().qosLevel()); // http mock if (mqttChannel.getIsMock()) { return send(mqttChannels, message, messageRegistry, filterRetainMessage(message, messageRegistry)); @@ -62,7 +73,8 @@ public class PublishProtocol implements Protocol { case EXACTLY_ONCE: if (!mqttChannel.existQos2Msg(variableHeader.packetId())) { return mqttChannel - .cacheQos2Msg(variableHeader.packetId(), MessageUtils.wrapPublishMessage(message, 0)) + .cacheQos2Msg(variableHeader.packetId(), + MessageUtils.wrapPublishMessage(message, message.fixedHeader().qosLevel(), 0)) .then(mqttChannel.write(MqttMessageBuilder.buildPublishRec(variableHeader.packetId()), true)); } default: @@ -78,20 +90,21 @@ public class PublishProtocol implements Protocol { /** * 通用发送消息 * - * @param mqttChannels topic 匹配channels - * @param message 消息体 - * @param messageRegistry 消息中心 - * @param other 其他操作 + * @param subscribeTopics {@link SubscribeTopic} + * @param message {@link MqttPublishMessage} + * @param messageRegistry {@link MessageRegistry} + * @param other {@link Mono} * @return Mono */ - private Mono send(Set mqttChannels, MqttPublishMessage message, MessageRegistry messageRegistry, Mono other) { + private Mono send(Set subscribeTopics, MqttPublishMessage message, MessageRegistry messageRegistry, Mono other) { return Mono.when( - mqttChannels.stream() - .filter(channel -> filterOfflineSession(channel, messageRegistry, message)) - .map(channel -> - channel.write(MessageUtils.wrapPublishMessage(message, - channel.generateMessageId()), - message.fixedHeader().qosLevel().value() > 0) + subscribeTopics.stream() + .filter(subscribeTopic -> filterOfflineSession(subscribeTopic.getMqttChannel(), messageRegistry, message)) + .map(subscribeTopic -> + subscribeTopic.getMqttChannel().write(MessageUtils.wrapPublishMessage(message, + subscribeTopic.getQoS(), + subscribeTopic.getMqttChannel().generateMessageId()), + subscribeTopic.getQoS().value() > 0) ) .collect(Collectors.toList())).then(other); @@ -101,9 +114,9 @@ public class PublishProtocol implements Protocol { /** * 过滤离线会话消息 * - * @param mqttChannel topic匹配的channel - * @param messageRegistry 消息注册中心 - * @param mqttMessage 消息 + * @param mqttChannel {@link MqttChannel} + * @param messageRegistry {@link MessageRegistry} + * @param mqttMessage {@link MqttPublishMessage} * @return boolean */ private boolean filterOfflineSession(MqttChannel mqttChannel, MessageRegistry messageRegistry, MqttPublishMessage mqttMessage) { @@ -120,8 +133,8 @@ public class PublishProtocol implements Protocol { /** * 过滤保留消息 * - * @param message 消息体 - * @param messageRegistry 消息中心 + * @param message {@link MqttPublishMessage} + * @param messageRegistry {@link MessageRegistry} * @return Mono */ private Mono filterRetainMessage(MqttPublishMessage message, MessageRegistry messageRegistry) { diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/SubscribeAckProtocol.java b/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/SubscribeAckProtocol.java index 2b1b4a6b762007049a1d80e487d67b0c45316714..a42940e6298b41bd831ae7443c06fb57bd8434e6 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/SubscribeAckProtocol.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/SubscribeAckProtocol.java @@ -1,8 +1,10 @@ package io.github.quickmsg.core.protocol; import io.github.quickmsg.common.channel.MqttChannel; +import io.github.quickmsg.common.message.SmqttMessage; import io.github.quickmsg.common.protocol.Protocol; import io.netty.handler.codec.mqtt.MqttMessageType; +import io.netty.handler.codec.mqtt.MqttPublishMessage; import io.netty.handler.codec.mqtt.MqttSubAckMessage; import reactor.core.publisher.Mono; import reactor.util.context.ContextView; @@ -23,7 +25,8 @@ public class SubscribeAckProtocol implements Protocol { } @Override - public Mono parseProtocol(MqttSubAckMessage message, MqttChannel mqttChannel, ContextView contextView) { + public Mono parseProtocol(SmqttMessage smqttMessage, MqttChannel mqttChannel, ContextView contextView) { + MqttSubAckMessage message = smqttMessage.getMessage(); return mqttChannel.cancelRetry(MqttMessageType.SUBSCRIBE,message.variableHeader().messageId()); } diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/SubscribeProtocol.java b/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/SubscribeProtocol.java index 0081a622b56e8eb8d8f685d966ecba6b7d028bc6..8d5fae32351c144d0e58219c30724912557e6ca0 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/SubscribeProtocol.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/SubscribeProtocol.java @@ -1,19 +1,27 @@ package io.github.quickmsg.core.protocol; +import io.github.quickmsg.common.acl.AclAction; +import io.github.quickmsg.common.acl.AclManager; import io.github.quickmsg.common.channel.MqttChannel; import io.github.quickmsg.common.context.ReceiveContext; import io.github.quickmsg.common.message.MessageRegistry; import io.github.quickmsg.common.message.MqttMessageBuilder; -import io.github.quickmsg.common.message.SubscribeChannelContext; +import io.github.quickmsg.common.message.SmqttMessage; +import io.github.quickmsg.common.metric.CounterType; +import io.github.quickmsg.common.metric.MetricManagerHolder; import io.github.quickmsg.common.protocol.Protocol; +import io.github.quickmsg.common.topic.SubscribeTopic; import io.github.quickmsg.common.topic.TopicRegistry; import io.netty.handler.codec.mqtt.MqttMessageType; +import io.netty.handler.codec.mqtt.MqttSubAckMessage; import io.netty.handler.codec.mqtt.MqttSubscribeMessage; +import org.apache.commons.collections.CollectionUtils; import reactor.core.publisher.Mono; import reactor.util.context.ContextView; import java.util.ArrayList; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; /** @@ -25,22 +33,24 @@ public class SubscribeProtocol implements Protocol { private static List MESSAGE_TYPE_LIST = new ArrayList<>(); @Override - public Mono parseProtocol(MqttSubscribeMessage message, MqttChannel mqttChannel, ContextView contextView) { + public Mono parseProtocol(SmqttMessage smqttMessage, MqttChannel mqttChannel, ContextView contextView) { + MqttSubscribeMessage message = smqttMessage.getMessage(); + MetricManagerHolder.metricManager.getMetricRegistry().getMetricCounter(CounterType.SUBSCRIBE_EVENT).increment(); return Mono.fromRunnable(() -> { ReceiveContext receiveContext = contextView.get(ReceiveContext.class); TopicRegistry topicRegistry = receiveContext.getTopicRegistry(); MessageRegistry messageRegistry = receiveContext.getMessageRegistry(); - List mqttTopicSubscriptions = + AclManager aclManager = receiveContext.getAclManager(); + Set mqttTopicSubscriptions = message.payload().topicSubscriptions() .stream() .peek(mqttTopicSubscription -> this.loadRetainMessage(messageRegistry, mqttChannel, mqttTopicSubscription.topicName())) - .map(mqttTopicSubscription -> - SubscribeChannelContext.builder() - .mqttChannel(mqttChannel) - .mqttQoS(mqttTopicSubscription.qualityOfService()) - .topic(mqttTopicSubscription.topicName()).build()) - .collect(Collectors.toList()); - topicRegistry.registryTopicConnection(mqttTopicSubscriptions); + .map(mqttTopicSubscription -> new SubscribeTopic(mqttTopicSubscription.topicName(), mqttTopicSubscription.qualityOfService(), mqttChannel)) + .filter(subscribeTopic -> aclManager.check(mqttChannel, subscribeTopic.getTopicFilter(), AclAction.SUBSCRIBE)) + .collect(Collectors.toSet()); + if(CollectionUtils.isNotEmpty(mqttTopicSubscriptions)){ + topicRegistry.registrySubscribesTopic(mqttTopicSubscriptions); + } }).then(mqttChannel.write( MqttMessageBuilder.buildSubAck( message.variableHeader().messageId(), @@ -50,8 +60,7 @@ public class SubscribeProtocol implements Protocol { .map(mqttTopicSubscription -> mqttTopicSubscription.qualityOfService() .value()) - .collect(Collectors.toList())), - false)); + .collect(Collectors.toList())), false)); } private void loadRetainMessage(MessageRegistry messageRegistry, MqttChannel mqttChannel, String topicName) { diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/UnSubscribeAckProtocol.java b/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/UnSubscribeAckProtocol.java index f0f8826e1a7275bcc8c690fcf8ee7aeeb05ba5c4..488b16c2454a8228240cd7191c5b1917b99d2107 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/UnSubscribeAckProtocol.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/UnSubscribeAckProtocol.java @@ -1,6 +1,7 @@ package io.github.quickmsg.core.protocol; import io.github.quickmsg.common.channel.MqttChannel; +import io.github.quickmsg.common.message.SmqttMessage; import io.github.quickmsg.common.protocol.Protocol; import io.netty.handler.codec.mqtt.MqttMessageType; import io.netty.handler.codec.mqtt.MqttUnsubAckMessage; @@ -22,8 +23,9 @@ public class UnSubscribeAckProtocol implements Protocol { } @Override - public Mono parseProtocol(MqttUnsubAckMessage message, MqttChannel mqttChannel, ContextView contextView) { - return mqttChannel.cancelRetry(MqttMessageType.UNSUBSCRIBE,message.variableHeader().messageId()); + public Mono parseProtocol(SmqttMessage smqttMessage, MqttChannel mqttChannel, ContextView contextView) { + MqttUnsubAckMessage message = smqttMessage.getMessage(); + return mqttChannel.cancelRetry(MqttMessageType.UNSUBSCRIBE, message.variableHeader().messageId()); } @Override diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/UnSubscribeProtocol.java b/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/UnSubscribeProtocol.java index 1636594dfd6aef7d4cf752fe3f69652fb8d96668..5fcb001f0b639f36eb9c3ed9388bbb8c42fd773a 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/UnSubscribeProtocol.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/protocol/UnSubscribeProtocol.java @@ -3,15 +3,20 @@ package io.github.quickmsg.core.protocol; import io.github.quickmsg.common.channel.MqttChannel; import io.github.quickmsg.common.context.ReceiveContext; import io.github.quickmsg.common.message.MqttMessageBuilder; +import io.github.quickmsg.common.message.SmqttMessage; +import io.github.quickmsg.common.metric.CounterType; +import io.github.quickmsg.common.metric.MetricManagerHolder; import io.github.quickmsg.common.protocol.Protocol; +import io.github.quickmsg.common.topic.SubscribeTopic; import io.github.quickmsg.common.topic.TopicRegistry; import io.netty.handler.codec.mqtt.MqttMessageType; +import io.netty.handler.codec.mqtt.MqttQoS; +import io.netty.handler.codec.mqtt.MqttUnsubAckMessage; import io.netty.handler.codec.mqtt.MqttUnsubscribeMessage; import reactor.core.publisher.Mono; import reactor.util.context.ContextView; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; /** @@ -27,11 +32,18 @@ public class UnSubscribeProtocol implements Protocol { @Override - public Mono parseProtocol(MqttUnsubscribeMessage message, MqttChannel mqttChannel, ContextView contextView) { + public Mono parseProtocol(SmqttMessage smqttMessage , MqttChannel mqttChannel, ContextView contextView) { + MqttUnsubscribeMessage message = smqttMessage.getMessage(); return Mono.fromRunnable(() -> { + MetricManagerHolder.metricManager.getMetricRegistry().getMetricCounter(CounterType.UN_SUBSCRIBE_EVENT).increment(); ReceiveContext receiveContext = contextView.get(ReceiveContext.class); TopicRegistry topicRegistry = receiveContext.getTopicRegistry(); - topicRegistry.clear(new HashSet<>(message.payload().topics()), mqttChannel); + message.payload() + .topics() + .stream() + // 随机设置一个MqttQoS 用于删除topic订阅 + .map(topic -> new SubscribeTopic(topic, MqttQoS.AT_MOST_ONCE, mqttChannel)) + .forEach(topicRegistry::removeSubscribeTopic); }).then(mqttChannel.write(MqttMessageBuilder.buildUnsubAck(message.variableHeader().messageId()), false)); } diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/DefaultChannelRegistry.java b/smqtt-core/src/main/java/io/github/quickmsg/core/spi/DefaultChannelRegistry.java similarity index 90% rename from smqtt-core/src/main/java/io/github/quickmsg/core/DefaultChannelRegistry.java rename to smqtt-core/src/main/java/io/github/quickmsg/core/spi/DefaultChannelRegistry.java index f9a9e154a16b8ee479399a9f6ede9ae68b4d0471..6ca8eb9d12f80ac74ffdc8debd6813149f2daf65 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/DefaultChannelRegistry.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/spi/DefaultChannelRegistry.java @@ -1,7 +1,8 @@ -package io.github.quickmsg.core; +package io.github.quickmsg.core.spi; import io.github.quickmsg.common.channel.ChannelRegistry; import io.github.quickmsg.common.channel.MqttChannel; +import io.github.quickmsg.common.config.BootstrapConfig; import io.github.quickmsg.common.enums.ChannelStatus; import io.github.quickmsg.common.environment.EnvContext; import lombok.extern.slf4j.Slf4j; @@ -26,7 +27,7 @@ public class DefaultChannelRegistry implements ChannelRegistry { } @Override - public void startUp(EnvContext envContext) { + public void startUp(Map environmentMap) { } @@ -34,7 +35,6 @@ public class DefaultChannelRegistry implements ChannelRegistry { public void close(MqttChannel mqttChannel) { Optional.ofNullable(mqttChannel.getClientIdentifier()) .ifPresent(channelMap::remove); - mqttChannel.close().subscribe(); } @Override diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/DefaultMessageRegistry.java b/smqtt-core/src/main/java/io/github/quickmsg/core/spi/DefaultMessageRegistry.java similarity index 97% rename from smqtt-core/src/main/java/io/github/quickmsg/core/DefaultMessageRegistry.java rename to smqtt-core/src/main/java/io/github/quickmsg/core/spi/DefaultMessageRegistry.java index 2d0c4cb10c0176f94921cea0d90453ab0a052ea5..256d8170f42227019a8c1ec680095a9ecc04b99f 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/DefaultMessageRegistry.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/spi/DefaultMessageRegistry.java @@ -1,4 +1,4 @@ -package io.github.quickmsg.core; +package io.github.quickmsg.core.spi; import io.github.quickmsg.common.message.MessageRegistry; import io.github.quickmsg.common.message.RetainMessage; diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/DefaultProtocolAdaptor.java b/smqtt-core/src/main/java/io/github/quickmsg/core/spi/DefaultProtocolAdaptor.java similarity index 59% rename from smqtt-core/src/main/java/io/github/quickmsg/core/DefaultProtocolAdaptor.java rename to smqtt-core/src/main/java/io/github/quickmsg/core/spi/DefaultProtocolAdaptor.java index 59057f0ee5e59e05d4735a42573aba88542b6090..8aa07c618d6f5e22633e82dc508b774446c41523 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/DefaultProtocolAdaptor.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/spi/DefaultProtocolAdaptor.java @@ -1,16 +1,19 @@ -package io.github.quickmsg.core; +package io.github.quickmsg.core.spi; import io.github.quickmsg.common.channel.MqttChannel; import io.github.quickmsg.common.config.Configuration; import io.github.quickmsg.common.context.ReceiveContext; +import io.github.quickmsg.common.message.SmqttMessage; import io.github.quickmsg.common.protocol.Protocol; import io.github.quickmsg.common.protocol.ProtocolAdaptor; import io.github.quickmsg.common.spi.DynamicLoader; -import io.github.quickmsg.common.utils.MessageUtils; import io.netty.handler.codec.mqtt.MqttMessage; import io.netty.handler.codec.mqtt.MqttMessageType; import lombok.extern.slf4j.Slf4j; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Scheduler; import reactor.core.scheduler.Schedulers; +import reactor.netty.ReactorNetty; import java.util.HashMap; import java.util.Map; @@ -24,8 +27,13 @@ public class DefaultProtocolAdaptor implements ProtocolAdaptor { private Map> types = new HashMap<>(); + + private final Scheduler scheduler; + + @SuppressWarnings("unchecked") - public DefaultProtocolAdaptor() { + public DefaultProtocolAdaptor(Scheduler scheduler) { + this.scheduler = Optional.ofNullable(scheduler).orElse(Schedulers.boundedElastic()); DynamicLoader.findAll(Protocol.class) .forEach(protocol -> protocol.getMqttMessageTypes().forEach(type -> { @@ -36,17 +44,22 @@ public class DefaultProtocolAdaptor implements ProtocolAdaptor { } @Override - public void chooseProtocol(MqttChannel mqttChannel, MqttMessage mqttMessage, ReceiveContext receiveContext) { + public void chooseProtocol(MqttChannel mqttChannel, SmqttMessage smqttMessage, ReceiveContext receiveContext) { + MqttMessage mqttMessage = smqttMessage.getMessage(); + log.info(" 【{}】【{}】 【{}】", + Thread.currentThread().getName(), + mqttMessage.fixedHeader().messageType(), + mqttChannel); Optional.ofNullable(types.get(mqttMessage.fixedHeader().messageType())) .ifPresent(protocol -> protocol - .doParseProtocol(mqttMessage, mqttChannel) + .doParseProtocol(smqttMessage, mqttChannel) .contextWrite(context -> context.putNonNull(ReceiveContext.class, receiveContext)) - .subscribeOn(Schedulers.parallel()) + .subscribeOn(scheduler) .subscribe(aVoid -> { }, error -> { - log.error("channel {} chooseProtocol:", mqttChannel, error); - MessageUtils.safeRelease(mqttMessage); - }, () -> MessageUtils.safeRelease(mqttMessage))); + log.error("channel {} chooseProtocol: {} error {}", mqttChannel, mqttMessage, error.getMessage()); + ReactorNetty.safeRelease(mqttMessage.payload()); + }, () -> ReactorNetty.safeRelease(mqttMessage.payload()))); } diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/spi/DefaultTopicRegistry.java b/smqtt-core/src/main/java/io/github/quickmsg/core/spi/DefaultTopicRegistry.java new file mode 100644 index 0000000000000000000000000000000000000000..66ff8243ea64854ba2a75f2eb10c13ff9b4352bc --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/spi/DefaultTopicRegistry.java @@ -0,0 +1,103 @@ +package io.github.quickmsg.core.spi; + +import io.github.quickmsg.common.channel.MqttChannel; +import io.github.quickmsg.common.topic.SubscribeTopic; +import io.github.quickmsg.common.topic.TopicRegistry; +import io.github.quickmsg.core.topic.FixedTopicFilter; +import io.github.quickmsg.core.topic.TopicFilter; +import io.github.quickmsg.core.topic.TreeTopicFilter; +import io.netty.handler.codec.mqtt.MqttQoS; +import lombok.extern.slf4j.Slf4j; + +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author luxurong + */ +@Slf4j +public class DefaultTopicRegistry implements TopicRegistry { + + + private static final String ONE_SYMBOL = "+"; + + private static final String MORE_SYMBOL = "#"; + + + private TopicFilter fixedTopicFilter; + + private TopicFilter treeTopicFilter; + + public DefaultTopicRegistry() { + this.fixedTopicFilter = new FixedTopicFilter(); + this.treeTopicFilter = new TreeTopicFilter(); + } + + + @Override + public void registrySubscribeTopic(String topicFilter, MqttChannel mqttChannel, MqttQoS qos) { + this.registrySubscribeTopic(new SubscribeTopic(topicFilter, qos, mqttChannel)); + } + + @Override + public void registrySubscribeTopic(SubscribeTopic subscribeTopic) { + if (subscribeTopic.getTopicFilter().contains(ONE_SYMBOL) || subscribeTopic.getTopicFilter().contains(MORE_SYMBOL)) { + treeTopicFilter.addSubscribeTopic(subscribeTopic); + } else { + fixedTopicFilter.addSubscribeTopic(subscribeTopic); + } + } + + + @Override + public void clear(MqttChannel mqttChannel) { + Set topics = mqttChannel.getTopics(); + if(log.isDebugEnabled()){ + log.info("mqttChannel channel {} clear topics {}",mqttChannel,topics); + } + topics.forEach(this::removeSubscribeTopic); + } + + + @Override + public void removeSubscribeTopic(SubscribeTopic subscribeTopic) { + if (subscribeTopic.getTopicFilter().contains(ONE_SYMBOL) || subscribeTopic.getTopicFilter().contains(MORE_SYMBOL)) { + treeTopicFilter.removeSubscribeTopic(subscribeTopic); + } else { + fixedTopicFilter.removeSubscribeTopic(subscribeTopic); + } + } + + + @Override + public Set getSubscribesByTopic(String topicName, MqttQoS qos) { + Set subscribeTopics = fixedTopicFilter.getSubscribeByTopic(topicName, qos); + subscribeTopics.addAll(treeTopicFilter.getSubscribeByTopic(topicName, qos)); + return subscribeTopics; + } + + @Override + public void registrySubscribesTopic(Set mqttTopicSubscriptions) { + mqttTopicSubscriptions.forEach(this::registrySubscribeTopic); + } + + + @Override + public Map> getAllTopics() { + Set subscribeTopics = fixedTopicFilter.getAllSubscribesTopic(); + subscribeTopics.addAll(treeTopicFilter.getAllSubscribesTopic()); + return subscribeTopics + .stream() + .collect(Collectors.groupingBy( + SubscribeTopic::getTopicFilter, + Collectors.mapping(SubscribeTopic::getMqttChannel, Collectors.toSet()))); + } + + @Override + public Integer counts() { + return fixedTopicFilter.count() + treeTopicFilter.count(); + } + + +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/ssl/AbstractSslHandler.java b/smqtt-core/src/main/java/io/github/quickmsg/core/ssl/AbstractSslHandler.java index aaa67714ad12ff2bc3eec7a92938cc8d0480da2a..c2678b2d6bd2fda2d0f3ff9a659033a41d59b57a 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/ssl/AbstractSslHandler.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/ssl/AbstractSslHandler.java @@ -2,12 +2,18 @@ package io.github.quickmsg.core.ssl; import io.github.quickmsg.common.config.Configuration; import io.github.quickmsg.common.config.SslContext; +import io.github.quickmsg.core.mqtt.MqttConfiguration; +import io.netty.channel.ChannelOption; import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.util.SelfSignedCertificate; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import reactor.netty.tcp.SslProvider; +import reactor.netty.tcp.TcpServer; +import reactor.netty.tcp.TcpSslContextSpec; import java.io.File; +import java.util.Map; /** * @author luxurong @@ -18,25 +24,44 @@ public class AbstractSslHandler { public void secure(SslProvider.SslContextSpec sslContextSpec, Configuration configuration) { try { if (configuration.getSsl()) { - File cert; - File key; SslContext sslContext = configuration.getSslContext(); + SslContextBuilder sslContextBuilder ; if (sslContext != null) { - cert = new File(sslContext.getCrt()); - key = new File(sslContext.getKey()); - + sslContextBuilder = SslContextBuilder.forServer(new File(sslContext.getCrt()), new File(sslContext.getKey())); + if(StringUtils.isNotEmpty(sslContext.getCa())){ + sslContextBuilder= sslContextBuilder.trustManager(new File(sslContext.getCa())); + } } else { SelfSignedCertificate ssc = new SelfSignedCertificate(); - cert = ssc.certificate(); - key = ssc.privateKey(); + sslContextBuilder = SslContextBuilder.forServer(ssc.certificate(),ssc.privateKey()); } - SslContextBuilder sslContextBuilder = SslContextBuilder.forServer(cert, key); sslContextSpec.sslContext(sslContextBuilder); } - } catch (Exception e) { log.error(" ssl read error", e); } } + + + public TcpServer initTcpServer(MqttConfiguration mqttConfiguration) { + TcpServer server = TcpServer.create(); + if (mqttConfiguration.getSsl()) { + server = server.secure(sslContextSpec -> this.secure(sslContextSpec, mqttConfiguration)); + } + if (mqttConfiguration.getOptions() != null) { + for (Map.Entry entry : mqttConfiguration.getOptions().entrySet()) { + server = server.option(ChannelOption.valueOf(entry.getKey()), entry.getValue()); + } + } + if (mqttConfiguration.getChildOptions() != null) { + for (Map.Entry entry : mqttConfiguration.getChildOptions().entrySet()) { + server = server.childOption(ChannelOption.valueOf(entry.getKey()), entry.getValue()); + } + } + server = server.metrics(true); + return server; + } + + } diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/topic/FixedTopicFilter.java b/smqtt-core/src/main/java/io/github/quickmsg/core/topic/FixedTopicFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..d85a6fb694b607e94ae222b80357fe4492d4d04e --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/topic/FixedTopicFilter.java @@ -0,0 +1,68 @@ +package io.github.quickmsg.core.topic; + +import io.github.quickmsg.common.channel.MqttChannel; +import io.github.quickmsg.common.metric.CounterType; +import io.github.quickmsg.common.metric.MetricManagerHolder; +import io.github.quickmsg.common.topic.SubscribeTopic; +import io.netty.handler.codec.mqtt.MqttQoS; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.atomic.LongAdder; +import java.util.stream.Collectors; + +/** + * @author luxurong + */ +public class FixedTopicFilter implements TopicFilter { + + private final LongAdder subscribeNumber = new LongAdder(); + + private final Map> topicChannels = new ConcurrentHashMap<>(); + + + @Override + public Set getSubscribeByTopic(String topic, MqttQoS mqttQoS) { + CopyOnWriteArraySet channels = topicChannels.computeIfAbsent(topic, t -> new CopyOnWriteArraySet<>()); + return channels.stream().map(tp -> tp.compareQos(mqttQoS)).collect(Collectors.toSet()); + } + + @Override + public void addSubscribeTopic(String topicFilter, MqttChannel mqttChannel, MqttQoS mqttQoS) { + this.addSubscribeTopic(new SubscribeTopic(topicFilter, mqttQoS, mqttChannel)); + } + + @Override + public void addSubscribeTopic(SubscribeTopic subscribeTopic) { + CopyOnWriteArraySet channels = topicChannels.computeIfAbsent(subscribeTopic.getTopicFilter(), t -> new CopyOnWriteArraySet<>()); + if (channels.add(subscribeTopic)) { + subscribeNumber.add(1); + subscribeTopic.linkSubscribe(); + MetricManagerHolder.metricManager.getMetricRegistry().getMetricCounter(CounterType.SUBSCRIBE).increment(); + } + } + + @Override + public void removeSubscribeTopic(SubscribeTopic subscribeTopic) { + CopyOnWriteArraySet channels = topicChannels.computeIfAbsent(subscribeTopic.getTopicFilter(), t -> new CopyOnWriteArraySet<>()); + if (channels.remove(subscribeTopic)) { + subscribeNumber.add(-1); + subscribeTopic.unLinkSubscribe(); + MetricManagerHolder.metricManager.getMetricRegistry().getMetricCounter(CounterType.SUBSCRIBE).decrement(); + + } + } + + @Override + public int count() { + return (int) subscribeNumber.sum(); + } + + @Override + public Set getAllSubscribesTopic() { + return topicChannels.values().stream().flatMap(Collection::stream).collect(Collectors.toSet()); + } +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/topic/TopicFilter.java b/smqtt-core/src/main/java/io/github/quickmsg/core/topic/TopicFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..d370483b1c44c8c70c5312c1ffa349e234f210c4 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/topic/TopicFilter.java @@ -0,0 +1,66 @@ +package io.github.quickmsg.core.topic; + +import io.github.quickmsg.common.channel.MqttChannel; +import io.github.quickmsg.common.topic.SubscribeTopic; +import io.netty.handler.codec.mqtt.MqttQoS; + +import java.util.Set; + +/** + * @author luxurong + */ +public interface TopicFilter { + + /** + * 获取订阅topic + * + * @param topic topic + * @param mqttQoS {@link MqttQoS} + * @return {@link SubscribeTopic} + */ + Set getSubscribeByTopic(String topic, MqttQoS mqttQoS); + + + /** + * 保存订阅topic + * + * @param topicFilter topicFilter + * @param mqttQoS {@link MqttQoS} + * @param mqttChannel {@link MqttChannel} + */ + void addSubscribeTopic(String topicFilter, MqttChannel mqttChannel, MqttQoS mqttQoS); + + + /** + * 保存订阅topic + * + * @param subscribeTopic {@link SubscribeTopic} + */ + void addSubscribeTopic(SubscribeTopic subscribeTopic); + + + /** + * 保存订阅topic + * + * @param subscribeTopic {@link SubscribeTopic} + */ + void removeSubscribeTopic(SubscribeTopic subscribeTopic); + + + /** + * 获取订阅总数 + * + * @return 总数 + */ + int count(); + + + /** + * 获取订所有订阅topic + * + * @return {@link SubscribeTopic} + */ + Set getAllSubscribesTopic(); + + +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/topic/TreeNode.java b/smqtt-core/src/main/java/io/github/quickmsg/core/topic/TreeNode.java new file mode 100644 index 0000000000000000000000000000000000000000..d862bf62ced6a36074facde70ce957d36d4f8c7b --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/topic/TreeNode.java @@ -0,0 +1,137 @@ +package io.github.quickmsg.core.topic; + +import io.github.quickmsg.common.topic.SubscribeTopic; +import lombok.Getter; +import lombok.Setter; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.stream.Collectors; + +/** + * @author luxurong + */ +@Getter +@Setter +public class TreeNode { + + private final String topic; + + private int subscribeTopicNumber; + + + private Set subscribes = new CopyOnWriteArraySet<>(); + + private Map childNodes = new ConcurrentHashMap<>(); + + public TreeNode(String topic) { + this.topic = topic; + } + + private final String ONE_SYMBOL = "+"; + + private final String MORE_SYMBOL = "#"; + + public boolean addSubscribeTopic(SubscribeTopic subscribeTopic) { + String[] topics = subscribeTopic.getTopicFilter().split("/"); + return addIndex(subscribeTopic, topics, 0); + } + + + private boolean addTreeSubscribe(SubscribeTopic subscribeTopic) { + return subscribes.add(subscribeTopic); + } + + + private boolean addIndex(SubscribeTopic subscribeTopic, String[] topics, Integer index) { + String lastTopic = topics[index]; + TreeNode treeNode = childNodes.computeIfAbsent(lastTopic, tp -> new TreeNode(lastTopic)); + if (index == topics.length - 1) { + return treeNode.addTreeSubscribe(subscribeTopic); + } else { + return treeNode.addIndex(subscribeTopic, topics, index + 1); + } + } + + + public List getSubscribeByTopic(String topicFilter) { + String[] topics = topicFilter.split("/"); + return searchTree(topics); + } + + + private List searchTree(String[] topics) { + LinkedList subscribeTopicList = new LinkedList<>(); + loadTreeSubscribes(this, subscribeTopicList, topics, 0); + return subscribeTopicList; + } + + private void loadTreeSubscribes(TreeNode treeNode, LinkedList subscribeTopics, String[] topics, Integer index) { + String lastTopic = topics[index]; + TreeNode moreTreeNode = treeNode.getChildNodes().get(MORE_SYMBOL); + if (moreTreeNode != null) { + subscribeTopics.addAll(moreTreeNode.getSubscribes()); + } + if (index == topics.length - 1) { + TreeNode localTreeNode = treeNode.getChildNodes().get(lastTopic); + if (localTreeNode != null) { + Set subscribes = localTreeNode.getSubscribes(); + if (subscribes != null && subscribes.size() > 0) { + subscribeTopics.addAll(subscribes); + } + } + localTreeNode = treeNode.getChildNodes().get(ONE_SYMBOL); + if (localTreeNode != null) { + Set subscribes = localTreeNode.getSubscribes(); + if (subscribes != null && subscribes.size() > 0) { + subscribeTopics.addAll(subscribes); + } + } + + } else { + TreeNode oneTreeNode = treeNode.getChildNodes().get(ONE_SYMBOL); + if (oneTreeNode != null) { + loadTreeSubscribes(oneTreeNode, subscribeTopics, topics, index + 1); + } + TreeNode node = treeNode.getChildNodes().get(lastTopic); + if (node != null) { + loadTreeSubscribes(node, subscribeTopics, topics, index + 1); + } + } + + } + + public boolean removeSubscribeTopic(SubscribeTopic subscribeTopic) { + TreeNode node = this; + String[] topics = subscribeTopic.getTopicFilter().split("/"); + for (String topic : topics) { + if (node != null) { + node = node.getChildNodes().get(topic); + } + } + if (node != null) { + Set subscribeTopics = node.getSubscribes(); + if (subscribeTopics != null) { + return subscribeTopics.remove(subscribeTopic); + } + } + return false; + } + + public Set getAllSubscribesTopic() { + return getTreeSubscribesTopic(this); + } + + private Set getTreeSubscribesTopic(TreeNode node) { + Set allSubscribeTopics = new HashSet<>(); + allSubscribeTopics.addAll(node.getSubscribes()); + allSubscribeTopics.addAll(node.getChildNodes() + .values() + .stream() + .flatMap(treeNode -> treeNode.getTreeSubscribesTopic(treeNode).stream()) + .collect(Collectors.toSet())); + return allSubscribeTopics; + } + +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/topic/TreeTopicFilter.java b/smqtt-core/src/main/java/io/github/quickmsg/core/topic/TreeTopicFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..40c9c2a8c7d3cbe5cdf620a721f9e63e28291412 --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/topic/TreeTopicFilter.java @@ -0,0 +1,63 @@ +package io.github.quickmsg.core.topic; + +import io.github.quickmsg.common.channel.MqttChannel; +import io.github.quickmsg.common.metric.CounterType; +import io.github.quickmsg.common.metric.MetricManagerHolder; +import io.github.quickmsg.common.topic.SubscribeTopic; +import io.netty.handler.codec.mqtt.MqttQoS; + +import java.util.Set; +import java.util.concurrent.atomic.LongAdder; +import java.util.stream.Collectors; + +/** + * @author luxurong + */ +public class TreeTopicFilter implements TopicFilter { + + private TreeNode rootTreeNode = new TreeNode("root"); + + private LongAdder subscribeNumber = new LongAdder(); + + + @Override + public Set getSubscribeByTopic(String topic, MqttQoS mqttQoS) { + return rootTreeNode.getSubscribeByTopic(topic).stream().map(tp -> tp.compareQos(mqttQoS)).collect(Collectors.toSet()); + } + + @Override + public void addSubscribeTopic(String topicFilter, MqttChannel mqttChannel, MqttQoS mqttQoS) { + this.addSubscribeTopic(new SubscribeTopic(topicFilter, mqttQoS, mqttChannel)); + } + + @Override + public void addSubscribeTopic(SubscribeTopic subscribeTopic) { + if (rootTreeNode.addSubscribeTopic(subscribeTopic)) { + subscribeNumber.add(1); + MetricManagerHolder.metricManager.getMetricRegistry().getMetricCounter(CounterType.SUBSCRIBE).increment(); + + subscribeTopic.linkSubscribe(); + } + } + + @Override + public void removeSubscribeTopic(SubscribeTopic subscribeTopic) { + if (rootTreeNode.removeSubscribeTopic(subscribeTopic)) { + subscribeNumber.add(-1); + MetricManagerHolder.metricManager.getMetricRegistry().getMetricCounter(CounterType.SUBSCRIBE).decrement(); + subscribeTopic.unLinkSubscribe(); + } + } + + @Override + public int count() { + return (int) subscribeNumber.sum(); + } + + @Override + public Set getAllSubscribesTopic() { + return rootTreeNode.getAllSubscribesTopic(); + } + + +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/topic/WildCarTopic.java b/smqtt-core/src/main/java/io/github/quickmsg/core/topic/WildCarTopic.java new file mode 100644 index 0000000000000000000000000000000000000000..602e3606655590a1334aae08a517f5d67e4e754b --- /dev/null +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/topic/WildCarTopic.java @@ -0,0 +1,17 @@ +package io.github.quickmsg.core.topic; + +/** + * @author luxurong + */ +public enum WildCarTopic { + + /** + * 单层 + */ + ONE(), + + /** + * 多层 + */ + MORE() +} diff --git a/smqtt-core/src/main/java/io/github/quickmsg/core/websocket/WebSocketMqttReceiver.java b/smqtt-core/src/main/java/io/github/quickmsg/core/websocket/WebSocketMqttReceiver.java index c9a5e3b7586599e3b5919392920708bbb9471fb8..5f350a3cd3c4ae2e9ea1e4da7e5efccae14975ef 100644 --- a/smqtt-core/src/main/java/io/github/quickmsg/core/websocket/WebSocketMqttReceiver.java +++ b/smqtt-core/src/main/java/io/github/quickmsg/core/websocket/WebSocketMqttReceiver.java @@ -34,29 +34,26 @@ public class WebSocketMqttReceiver extends AbstractSslHandler implements Receive private TcpServer newTcpServer(ContextView context) { MqttReceiveContext receiveContext = context.get(MqttReceiveContext.class); MqttConfiguration mqttConfiguration = receiveContext.getConfiguration(); - TcpServer server = TcpServer.create(); - if (mqttConfiguration.getSsl()) { - server.secure(sslContextSpec -> this.secure(sslContextSpec, mqttConfiguration)); - } + TcpServer server = initTcpServer(mqttConfiguration); return server .port(mqttConfiguration.getWebSocketPort()) - .doOnBind(mqttConfiguration.getTcpServerConfig()) .wiretap(mqttConfiguration.getWiretap()) .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(mqttConfiguration.getLowWaterMark(), mqttConfiguration.getHighWaterMark())) .childOption(ChannelOption.TCP_NODELAY, true) .childOption(ChannelOption.SO_KEEPALIVE, true) .childOption(ChannelOption.SO_REUSEADDR, true) .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) + .metrics(mqttConfiguration.getMeterConfig() != null) .runOn(receiveContext.getLoopResources()) .doOnConnection(connection -> { - connection.addHandler(new HttpServerCodec()) - .addHandler(new HttpObjectAggregator(65536)) - .addHandler(new WebSocketServerProtocolHandler("/", "mqtt, mqttv3.1, mqttv3.1.1")) - .addHandler(new WebSocketFrameToByteBufDecoder()) - .addHandler(new ByteBufToWebSocketFrameEncoder()) - .addHandler(new MqttDecoder()) - .addHandler(MqttEncoder.INSTANCE); - receiveContext.apply(MqttChannel.init(connection)); + connection.addHandlerLast(new HttpServerCodec()) + .addHandlerLast(new HttpObjectAggregator(65536)) + .addHandlerLast(new WebSocketServerProtocolHandler(mqttConfiguration.getWebSocketPath(), "mqtt, mqttv3.1, mqttv3.1.1")) + .addHandlerLast(new WebSocketFrameToByteBufDecoder()) + .addHandlerLast(new ByteBufToWebSocketFrameEncoder()) + .addHandlerLast(new MqttDecoder(mqttConfiguration.getMessageMaxSize())) + .addHandlerLast(MqttEncoder.INSTANCE); + receiveContext.apply(MqttChannel.init(connection, receiveContext.getTimeAckManager())); }); } diff --git a/smqtt-core/src/main/resources/META-INF/services/io.github.quickmsg.common.http.HttpActor b/smqtt-core/src/main/resources/META-INF/services/io.github.quickmsg.common.http.HttpActor index 81d75834e7b089ca1e311a390de42df975dcbd4a..ced9898a2c6fa7d41482d099ac29db5ed26b904e 100644 --- a/smqtt-core/src/main/resources/META-INF/services/io.github.quickmsg.common.http.HttpActor +++ b/smqtt-core/src/main/resources/META-INF/services/io.github.quickmsg.common.http.HttpActor @@ -4,4 +4,26 @@ io.github.quickmsg.core.http.actors.ClusterActor io.github.quickmsg.core.http.actors.SubscribeActor io.github.quickmsg.core.http.actors.resource.IndexResourceActor io.github.quickmsg.core.http.actors.resource.StaticResourceActor -io.github.quickmsg.core.http.actors.resource.LoginResourceActor \ No newline at end of file +io.github.quickmsg.core.http.actors.resource.LoginResourceActor +io.github.quickmsg.core.http.actors.JvmHttpActor +io.github.quickmsg.core.http.actors.CounterHttpActor +io.github.quickmsg.core.http.actors.CpuHttpActor +io.github.quickmsg.core.http.actors.IsClusterActor +io.github.quickmsg.core.http.actors.AllowCorsHttpActor +io.github.quickmsg.core.http.actors.resource.FaviconResourceActor +io.github.quickmsg.core.http.actors.rule.RuleAddActor +io.github.quickmsg.core.http.actors.rule.RuleQueryActor +io.github.quickmsg.core.http.actors.rule.RuleDeleteActor +io.github.quickmsg.core.http.actors.rule.RuleUpdateActor +io.github.quickmsg.core.http.actors.source.SourceAddActor +io.github.quickmsg.core.http.actors.source.SourceDeleteActor +io.github.quickmsg.core.http.actors.source.SourceQueryActor +io.github.quickmsg.core.http.actors.source.SourceUpdateActor +io.github.quickmsg.core.http.actors.rule.RuleTypeActor +io.github.quickmsg.core.http.actors.source.SourceTypeActor +io.github.quickmsg.core.http.actors.PrometheusActor +io.github.quickmsg.core.http.actors.EventHttpActor +io.github.quickmsg.core.http.acl.AclAddPolicyActor +io.github.quickmsg.core.http.acl.AclDeletePolicyActor +io.github.quickmsg.core.http.acl.AclQueryPolicyActor +io.github.quickmsg.core.http.actors.CloseConnectionActor \ No newline at end of file diff --git a/smqtt-core/src/main/resources/META-INF/services/io.github.quickmsg.common.interceptor.Interceptor b/smqtt-core/src/main/resources/META-INF/services/io.github.quickmsg.common.interceptor.Interceptor deleted file mode 100644 index a8201e8ac0f9a66a54991701492c7bb1eabc0e85..0000000000000000000000000000000000000000 --- a/smqtt-core/src/main/resources/META-INF/services/io.github.quickmsg.common.interceptor.Interceptor +++ /dev/null @@ -1 +0,0 @@ -io.github.quickmsg.core.inteceptor.CounterInterceptor \ No newline at end of file diff --git a/smqtt-core/src/main/resources/logback.xml b/smqtt-core/src/main/resources/logback.xml index e680a30ed6224d6a14f68ef47870697b81248e51..23ed1884e2eade6cbf8a502bcb237a92382d8444 100644 --- a/smqtt-core/src/main/resources/logback.xml +++ b/smqtt-core/src/main/resources/logback.xml @@ -1,3 +1,19 @@ + + @@ -7,17 +23,30 @@ - - testFile.log - false + + + logs/smqtt.%d{yyyy-MM-dd}.log + 30 + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n -` - - - + + + + logs/ack.%d{yyyy-MM-dd}.log + 30 + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + @@ -26,9 +55,16 @@ - + + + + + + + + \ No newline at end of file diff --git a/smqtt-metric/pom.xml b/smqtt-metric/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..77be3ab64a42f6d2773164a4b3d4e71fea14b1c3 --- /dev/null +++ b/smqtt-metric/pom.xml @@ -0,0 +1,25 @@ + + + + 4.0.0 + + + + smqtt + io.github.quickmsg + 1.1.7 + + + smqtt-metric + + pom + + + + smqtt-metric-influxdb + smqtt-metric-prometheus + + + + diff --git a/smqtt-metric/smqtt-metric-influxdb/pom.xml b/smqtt-metric/smqtt-metric-influxdb/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..7d21b17c1bfb50ccdd1e53779d330205d6c5295b --- /dev/null +++ b/smqtt-metric/smqtt-metric-influxdb/pom.xml @@ -0,0 +1,22 @@ + + + + smqtt-metric + io.github.quickmsg + 1.1.7 + + 4.0.0 + + smqtt-metric-influxdb + + + + io.github.quickmsg + smqtt-common + 1.1.7 + + + + \ No newline at end of file diff --git a/smqtt-metric/smqtt-metric-influxdb/src/main/java/io/github/quickmsg/metric/InfluxDbMetricBean.java b/smqtt-metric/smqtt-metric-influxdb/src/main/java/io/github/quickmsg/metric/InfluxDbMetricBean.java new file mode 100644 index 0000000000000000000000000000000000000000..28362b88c9f780525d35400d76b0c2be44227332 --- /dev/null +++ b/smqtt-metric/smqtt-metric-influxdb/src/main/java/io/github/quickmsg/metric/InfluxDbMetricBean.java @@ -0,0 +1,93 @@ +package io.github.quickmsg.metric; + +import io.github.quickmsg.common.config.BootstrapConfig; +import io.github.quickmsg.common.metric.MetricBean; +import io.github.quickmsg.common.metric.MetricConstant; +import io.micrometer.core.instrument.Clock; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Metrics; +import io.micrometer.core.instrument.Tags; +import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics; +import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics; +import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics; +import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics; +import io.micrometer.core.instrument.binder.system.ProcessorMetrics; +import io.micrometer.influx.InfluxConfig; +import io.micrometer.influx.InfluxMeterRegistry; + +import java.time.Duration; +import java.util.Objects; + +/** + * @author luxurong + */ +public class InfluxDbMetricBean implements MetricBean, InfluxConfig { + + + private final BootstrapConfig.MeterConfig meterConfig; + + public final MeterRegistry meterRegistry; + + public InfluxDbMetricBean(BootstrapConfig.MeterConfig meterConfig) { + this.meterConfig = meterConfig; + checkConfig(meterConfig); + this.meterRegistry = new InfluxMeterRegistry(this, Clock.SYSTEM); + Metrics.globalRegistry.config().commonTags(getTags()); + Metrics.globalRegistry.add(meterRegistry); + new ClassLoaderMetrics().bindTo(Metrics.globalRegistry); + new JvmMemoryMetrics().bindTo(Metrics.globalRegistry); + new JvmGcMetrics().bindTo(Metrics.globalRegistry); + new ProcessorMetrics().bindTo(Metrics.globalRegistry); + new JvmThreadMetrics().bindTo(Metrics.globalRegistry); + } + + private void checkConfig(BootstrapConfig.MeterConfig meterConfig) { + Objects.requireNonNull(meterConfig.getInfluxdb()); + Objects.requireNonNull(meterConfig.getInfluxdb().getDb()); + Objects.requireNonNull(meterConfig.getInfluxdb().getUri()); + Objects.requireNonNull(meterConfig.getInfluxdb().getPassword()); + Objects.requireNonNull(meterConfig.getInfluxdb().getUserName()); + } + + @Override + public Duration step() { + return Duration.ofSeconds(Math.max(meterConfig.getInfluxdb().getStep(), 10)); + } + + @Override + public String db() { + return meterConfig.getInfluxdb().getDb(); + } + + @Override + public String uri() { + return meterConfig.getInfluxdb().getUri(); + } + + @Override + public String get(String k) { + return null; + } + + @Override + public String userName() { + return meterConfig.getInfluxdb().getUserName(); + } + + @Override + public String password() { + return meterConfig.getInfluxdb().getPassword(); + } + + @Override + public MetricBean Close() { + meterRegistry.close(); + return this; + } + + @Override + public MeterRegistry getMeterRegistry() { + return this.meterRegistry; + } + +} diff --git a/smqtt-metric/smqtt-metric-influxdb/src/main/java/io/github/quickmsg/metric/InfluxDbMetricFactory.java b/smqtt-metric/smqtt-metric-influxdb/src/main/java/io/github/quickmsg/metric/InfluxDbMetricFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..8d5e1bcf08bd99721c516faf2d6633e9b4655612 --- /dev/null +++ b/smqtt-metric/smqtt-metric-influxdb/src/main/java/io/github/quickmsg/metric/InfluxDbMetricFactory.java @@ -0,0 +1,22 @@ +package io.github.quickmsg.metric; + +import io.github.quickmsg.common.config.BootstrapConfig; +import io.github.quickmsg.common.metric.MetricFactory; +import io.github.quickmsg.common.metric.MetricManager; + +/** + * @author luxurong + */ +public class InfluxDbMetricFactory implements MetricFactory { + + private final MetricManager metricManager; + + public InfluxDbMetricFactory(BootstrapConfig.MeterConfig config) { + this.metricManager = new InfluxDbMetricManager(config); + } + + @Override + public MetricManager getMetricManager() { + return this.metricManager; + } +} diff --git a/smqtt-metric/smqtt-metric-influxdb/src/main/java/io/github/quickmsg/metric/InfluxDbMetricManager.java b/smqtt-metric/smqtt-metric-influxdb/src/main/java/io/github/quickmsg/metric/InfluxDbMetricManager.java new file mode 100644 index 0000000000000000000000000000000000000000..2be88af862f06a3809bb275d9d48e90f66ea8824 --- /dev/null +++ b/smqtt-metric/smqtt-metric-influxdb/src/main/java/io/github/quickmsg/metric/InfluxDbMetricManager.java @@ -0,0 +1,42 @@ +package io.github.quickmsg.metric; + +import io.github.quickmsg.common.config.BootstrapConfig; +import io.github.quickmsg.common.metric.*; + +/** + * @author luxurong + */ +public class InfluxDbMetricManager implements MetricManager { + + private final BootstrapConfig.MeterConfig config; + + private final MetricBean metricBean; + + private final MetricRegistry metricRegistry; + + public InfluxDbMetricManager(BootstrapConfig.MeterConfig config) { + this.config = config; + this.metricBean = new InfluxDbMetricBean(this.config); + this.metricRegistry = new InfluxDbMetricRegistry(createMetricRegistry(metricBean)); + + } + + + + @Override + public MetricRegistry getMetricRegistry() { + return this.metricRegistry; + } + + @Override + public MetricBean getMetricBean() { + return this.metricBean; + } + + @Override + public BootstrapConfig.MeterConfig getMeterConfig() { + return this.config; + } + + +} diff --git a/smqtt-metric/smqtt-metric-influxdb/src/main/java/io/github/quickmsg/metric/InfluxDbMetricRegistry.java b/smqtt-metric/smqtt-metric-influxdb/src/main/java/io/github/quickmsg/metric/InfluxDbMetricRegistry.java new file mode 100644 index 0000000000000000000000000000000000000000..786c7a1fe11efd9785481a53f36312995753767e --- /dev/null +++ b/smqtt-metric/smqtt-metric-influxdb/src/main/java/io/github/quickmsg/metric/InfluxDbMetricRegistry.java @@ -0,0 +1,17 @@ +package io.github.quickmsg.metric; + +import io.github.quickmsg.common.metric.AbstractMetricRegistry; +import io.github.quickmsg.common.metric.MetricCounter; + +import java.util.List; + +/** + * @author luxurong + */ +public class InfluxDbMetricRegistry extends AbstractMetricRegistry { + + + public InfluxDbMetricRegistry(List counters) { + super(counters); + } +} diff --git a/smqtt-metric/smqtt-metric-prometheus/pom.xml b/smqtt-metric/smqtt-metric-prometheus/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..4ccf1fdd9bb357ac36f027c1aad6bc4670a16712 --- /dev/null +++ b/smqtt-metric/smqtt-metric-prometheus/pom.xml @@ -0,0 +1,26 @@ + + + + smqtt-metric + io.github.quickmsg + 1.1.7 + + 4.0.0 + + smqtt-metric-prometheus + + + + io.micrometer + micrometer-registry-prometheus + + + io.github.quickmsg + smqtt-common + 1.1.7 + + + + \ No newline at end of file diff --git a/smqtt-metric/smqtt-metric-prometheus/src/main/java/io/github/quickmsg/metric/PrometheusMetricBean.java b/smqtt-metric/smqtt-metric-prometheus/src/main/java/io/github/quickmsg/metric/PrometheusMetricBean.java new file mode 100644 index 0000000000000000000000000000000000000000..5f5cd349dccc9a93aa47f92b007d59640da4b773 --- /dev/null +++ b/smqtt-metric/smqtt-metric-prometheus/src/main/java/io/github/quickmsg/metric/PrometheusMetricBean.java @@ -0,0 +1,46 @@ +package io.github.quickmsg.metric; + +import io.github.quickmsg.common.metric.MetricBean; +import io.github.quickmsg.common.metric.MetricConstant; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Metrics; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics; +import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics; +import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics; +import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics; +import io.micrometer.core.instrument.binder.system.ProcessorMetrics; +import io.micrometer.prometheus.PrometheusConfig; +import io.micrometer.prometheus.PrometheusMeterRegistry; + +import java.util.Collections; + +/** + * @author luxurong + */ +public class PrometheusMetricBean implements MetricBean { + + public final PrometheusMeterRegistry prometheusMeterRegistry; + + public PrometheusMetricBean() { + prometheusMeterRegistry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT); + Metrics.globalRegistry.config().commonTags(getTags()); + Metrics.globalRegistry.add(prometheusMeterRegistry); + new ClassLoaderMetrics().bindTo(Metrics.globalRegistry); + new JvmMemoryMetrics().bindTo(Metrics.globalRegistry); + new JvmGcMetrics().bindTo(Metrics.globalRegistry); + new ProcessorMetrics().bindTo(Metrics.globalRegistry); + new JvmThreadMetrics().bindTo(Metrics.globalRegistry); + } + + @Override + public MetricBean Close() { + prometheusMeterRegistry.close(); + return this; + } + + @Override + public MeterRegistry getMeterRegistry() { + return this.prometheusMeterRegistry; + } +} diff --git a/smqtt-metric/smqtt-metric-prometheus/src/main/java/io/github/quickmsg/metric/PrometheusMetricFactory.java b/smqtt-metric/smqtt-metric-prometheus/src/main/java/io/github/quickmsg/metric/PrometheusMetricFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..03b88691440a454d2b925cc7fa4db4def00aa252 --- /dev/null +++ b/smqtt-metric/smqtt-metric-prometheus/src/main/java/io/github/quickmsg/metric/PrometheusMetricFactory.java @@ -0,0 +1,22 @@ +package io.github.quickmsg.metric; + +import io.github.quickmsg.common.config.BootstrapConfig; +import io.github.quickmsg.common.metric.MetricFactory; +import io.github.quickmsg.common.metric.MetricManager; + +/** + * @author luxurong + */ +public class PrometheusMetricFactory implements MetricFactory { + + private final MetricManager metricManager; + + public PrometheusMetricFactory(BootstrapConfig.MeterConfig config) { + this.metricManager = new PrometheusMetricManager(config); + } + + @Override + public MetricManager getMetricManager() { + return this.metricManager; + } +} diff --git a/smqtt-metric/smqtt-metric-prometheus/src/main/java/io/github/quickmsg/metric/PrometheusMetricManager.java b/smqtt-metric/smqtt-metric-prometheus/src/main/java/io/github/quickmsg/metric/PrometheusMetricManager.java new file mode 100644 index 0000000000000000000000000000000000000000..be43331194a6ed3c773da621e9fc974b90f8eae1 --- /dev/null +++ b/smqtt-metric/smqtt-metric-prometheus/src/main/java/io/github/quickmsg/metric/PrometheusMetricManager.java @@ -0,0 +1,40 @@ +package io.github.quickmsg.metric; + +import io.github.quickmsg.common.config.BootstrapConfig; +import io.github.quickmsg.common.metric.MetricBean; +import io.github.quickmsg.common.metric.MetricManager; +import io.github.quickmsg.common.metric.MetricRegistry; + +/** + * @author luxurong + */ +public class PrometheusMetricManager implements MetricManager { + + private final BootstrapConfig.MeterConfig config; + + private final MetricBean metricBean; + + private final MetricRegistry metricRegistry; + + public PrometheusMetricManager(BootstrapConfig.MeterConfig config) { + this.config = config; + this.metricBean = new PrometheusMetricBean(); + this.metricRegistry = new PrometheusMetricRegistry(createMetricRegistry(metricBean)); + } + + + @Override + public MetricRegistry getMetricRegistry() { + return this.metricRegistry; + } + + @Override + public MetricBean getMetricBean() { + return this.metricBean; + } + + @Override + public BootstrapConfig.MeterConfig getMeterConfig() { + return this.config; + } +} diff --git a/smqtt-metric/smqtt-metric-prometheus/src/main/java/io/github/quickmsg/metric/PrometheusMetricRegistry.java b/smqtt-metric/smqtt-metric-prometheus/src/main/java/io/github/quickmsg/metric/PrometheusMetricRegistry.java new file mode 100644 index 0000000000000000000000000000000000000000..ae245f66a9446860baedc4a9b18c01b53f043400 --- /dev/null +++ b/smqtt-metric/smqtt-metric-prometheus/src/main/java/io/github/quickmsg/metric/PrometheusMetricRegistry.java @@ -0,0 +1,16 @@ +package io.github.quickmsg.metric; + +import io.github.quickmsg.common.metric.AbstractMetricRegistry; +import io.github.quickmsg.common.metric.MetricCounter; + +import java.util.List; + +/** + * @author luxurong + */ +public class PrometheusMetricRegistry extends AbstractMetricRegistry { + + protected PrometheusMetricRegistry(List metricCounters) { + super(metricCounters); + } +} diff --git a/smqtt-persistent/pom.xml b/smqtt-persistent/pom.xml index bb46a2165a7caee2d21bd2b50331d2e225cc290a..9d54f746b9ed6c5d67c9e610fa63986072984065 100644 --- a/smqtt-persistent/pom.xml +++ b/smqtt-persistent/pom.xml @@ -5,7 +5,7 @@ smqtt io.github.quickmsg - 1.0.5 + 1.1.7 4.0.0 pom diff --git a/smqtt-persistent/smqtt-persistent-db/pom.xml b/smqtt-persistent/smqtt-persistent-db/pom.xml index 279ae0791da0ba462004d958009acc9b30f5b43d..11fb413d9f34b503edbebf9ba8e02c3bb76b865d 100644 --- a/smqtt-persistent/smqtt-persistent-db/pom.xml +++ b/smqtt-persistent/smqtt-persistent-db/pom.xml @@ -5,12 +5,12 @@ smqtt-persistent io.github.quickmsg - 1.0.5 + 1.1.7 4.0.0 smqtt-persistent-db - 1.0.5 + 1.1.7 3.14.11 @@ -20,7 +20,7 @@ io.github.quickmsg smqtt-common - 1.0.5 + 1.1.7 compile @@ -43,9 +43,9 @@ - com.alibaba - druid - 1.2.6 + com.zaxxer + HikariCP + 4.0.3 diff --git a/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/DbConnectionHolder.java b/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/DbConnectionHolder.java index b2d3a5e3e766d1e3fdae997267e7ca5a83e0bb6b..ea016e650fd77c11a40ff21e981fb2b70c5cc18d 100644 --- a/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/DbConnectionHolder.java +++ b/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/DbConnectionHolder.java @@ -1,6 +1,6 @@ package io.github.quickmsg.persistent; -import io.github.quickmsg.persistent.config.DruidConnectionProvider; +import io.github.quickmsg.persistent.config.HikariCPConnectionProvider; import lombok.extern.slf4j.Slf4j; import org.jooq.DSLContext; import org.jooq.impl.DSL; @@ -19,17 +19,17 @@ public class DbConnectionHolder { /** * 获取DSLContext * - * @return {@link Mono} + * @return {@link Mono} */ public static Mono getConnection() throws SQLException { - Connection connection = DruidConnectionProvider.singleTon().getConnection(); + Connection connection = HikariCPConnectionProvider.singleTon().getConnection(); return Optional.ofNullable(connection).map(Mono::just).orElse(Mono.empty()); } /** * 获取DSLContext * - * @return {@link Mono} + * @return {@link Mono} */ public static Mono getDslContext() throws SQLException { return getConnection().map(DSL::using); diff --git a/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/config/DruidConnectionProvider.java b/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/config/HikariCPConnectionProvider.java similarity index 55% rename from smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/config/DruidConnectionProvider.java rename to smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/config/HikariCPConnectionProvider.java index 07849a32c53a9baddc7b96e02d67a11e0d315831..0da34f945f4a6b06f4383ae10a0b77be919d8996 100644 --- a/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/config/DruidConnectionProvider.java +++ b/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/config/HikariCPConnectionProvider.java @@ -1,9 +1,8 @@ package io.github.quickmsg.persistent.config; -import com.alibaba.druid.pool.DruidDataSource; -import com.alibaba.druid.pool.DruidDataSourceFactory; +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; import lombok.extern.slf4j.Slf4j; -import reactor.core.publisher.Mono; import java.sql.Connection; import java.sql.SQLException; @@ -15,18 +14,18 @@ import java.util.concurrent.atomic.AtomicInteger; * @author zhaopeng */ @Slf4j -public class DruidConnectionProvider implements ConnectionProvider { +public class HikariCPConnectionProvider implements ConnectionProvider { - private DruidConnectionProvider() { + private HikariCPConnectionProvider() { } - private static DruidConnectionProvider connectionProvider = new DruidConnectionProvider(); + private static HikariCPConnectionProvider connectionProvider = new HikariCPConnectionProvider(); - public static DruidConnectionProvider singleTon() { + public static HikariCPConnectionProvider singleTon() { return connectionProvider; } - private DruidDataSource druidDataSource; + private HikariDataSource hikariDataSource; private AtomicInteger startUp = new AtomicInteger(0); @@ -34,7 +33,8 @@ public class DruidConnectionProvider implements ConnectionProvider { public void init(Properties properties) { if (startUp.compareAndSet(0, 1)) { try { - this.druidDataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties); + HikariConfig config = new HikariConfig(properties); + this.hikariDataSource = new HikariDataSource(config); } catch (Exception e) { e.printStackTrace(); } @@ -44,7 +44,7 @@ public class DruidConnectionProvider implements ConnectionProvider { @Override public Connection getConnection() { try { - return druidDataSource.getConnection(); + return hikariDataSource.getConnection(); } catch (SQLException e) { log.error("getConnection error", e); return null; @@ -53,7 +53,9 @@ public class DruidConnectionProvider implements ConnectionProvider { @Override public void shutdown() { - druidDataSource.close(); + if (hikariDataSource != null) { + hikariDataSource.close(); + } } } \ No newline at end of file diff --git a/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/registry/DbMessageRegistry.java b/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/registry/DbMessageRegistry.java index de2355614603933e914b8eaa0f2a68c146c6eb9d..92992c29dee58d8e71718b6cf1bbaf86452e9a35 100644 --- a/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/registry/DbMessageRegistry.java +++ b/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/registry/DbMessageRegistry.java @@ -1,12 +1,11 @@ package io.github.quickmsg.persistent.registry; -import io.github.quickmsg.common.bootstrap.BootstrapKey; -import io.github.quickmsg.common.environment.EnvContext; +import io.github.quickmsg.common.config.BootstrapConfig; import io.github.quickmsg.common.message.MessageRegistry; import io.github.quickmsg.common.message.RetainMessage; import io.github.quickmsg.common.message.SessionMessage; import io.github.quickmsg.common.utils.TopicRegexUtils; -import io.github.quickmsg.persistent.config.DruidConnectionProvider; +import io.github.quickmsg.persistent.config.HikariCPConnectionProvider; import io.github.quickmsg.persistent.tables.Tables; import io.netty.util.CharsetUtil; import liquibase.Liquibase; @@ -38,22 +37,32 @@ public class DbMessageRegistry implements MessageRegistry { private static final String DEFAULT_LIQUIBASE_PATH = "classpath:liquibase/smqtt_db.xml"; + public final static String DB_PREFIX = "db."; @Override - public void startUp(EnvContext envContext) { - Map environments = envContext.getEnvironments(); + public void startUp(Map environmentMap) { + BootstrapConfig.DatabaseConfig dbConfig = (BootstrapConfig.DatabaseConfig) environmentMap.get(BootstrapConfig.DatabaseConfig.class); Properties properties = new Properties(); - for (String key : environments.keySet()) { - // 过滤以db.开头的数据库参数配置 - if (key.startsWith(BootstrapKey.DB_PREFIX)) { - properties.put(key.replaceAll(BootstrapKey.DB_PREFIX, ""), environments.get(key)); - } - } - DruidConnectionProvider + properties.put("jdbcUrl", dbConfig.getJdbcUrl()); + properties.put("username", dbConfig.getUsername()); + properties.put("password", dbConfig.getPassword()); + properties.put("dataSource.cachePrepStmts", dbConfig.getDataSourceCachePrepStmts()); + properties.put("dataSource.prepStmtCacheSize", dbConfig.getDataSourcePrepStmtCacheSize()); + properties.put("dataSource.prepStmtCacheSqlLimit", dbConfig.getDataSourcePrepStmtCacheSqlLimit()); + properties.put("dataSource.useServerPrepStmts", dbConfig.getDataSourceUseServerPrepStmts()); + properties.put("dataSource.useLocalSessionState", dbConfig.getDataSourceUseLocalSessionState()); + properties.put("dataSource.rewriteBatchedStatements", dbConfig.getDataSourceRewriteBatchedStatements()); + properties.put("dataSource.cacheResultSetMetadata", dbConfig.getDataSourceCacheResultSetMetadata()); + properties.put("dataSource.cacheServerConfiguration", dbConfig.getDataSourceCacheServerConfiguration()); + properties.put("dataSource.elideSetAutoCommits", dbConfig.getDataSourceElideSetAutoCommits()); + properties.put("dataSource.maintainTimeStats", dbConfig.getDataSourceMaintainTimeStats()); + + // to add more + HikariCPConnectionProvider .singleTon() .init(properties); ClassLoaderResourceAccessor classLoaderResourceAccessor = new ClassLoaderResourceAccessor(this.getClass().getClassLoader()); - try (Connection connection = DruidConnectionProvider.singleTon().getConnection()) { + try (Connection connection = HikariCPConnectionProvider.singleTon().getConnection()) { Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection)); Liquibase liquibase = new Liquibase(DEFAULT_LIQUIBASE_PATH, classLoaderResourceAccessor, database); liquibase.update(DEFAULT_DATABASE_NAME); @@ -64,7 +73,7 @@ public class DbMessageRegistry implements MessageRegistry { @Override public List getSessionMessage(String clientIdentifier) { - try (Connection connection = DruidConnectionProvider.singleTon().getConnection()) { + try (Connection connection = HikariCPConnectionProvider.singleTon().getConnection()) { DSLContext dslContext = DSL.using(connection); List list = dslContext @@ -103,7 +112,7 @@ public class DbMessageRegistry implements MessageRegistry { boolean retain = sessionMessage.isRetain(); byte[] body = sessionMessage.getBody(); - try (Connection connection = DruidConnectionProvider.singleTon().getConnection()) { + try (Connection connection = HikariCPConnectionProvider.singleTon().getConnection()) { DSLContext dslContext = DSL.using(connection); String bodyMsg = new String(body, CharsetUtil.UTF_8); dslContext.insertInto(Tables.SMQTT_SESSION) @@ -125,7 +134,7 @@ public class DbMessageRegistry implements MessageRegistry { String topic = retainMessage.getTopic(); int qos = retainMessage.getQos(); - try (Connection connection = DruidConnectionProvider.singleTon().getConnection()) { + try (Connection connection = HikariCPConnectionProvider.singleTon().getConnection()) { DSLContext dslContext = DSL.using(connection); if (retainMessage.getBody() == null || retainMessage.getBody().length == 0) { // 消息为空, 删除话题 @@ -163,7 +172,7 @@ public class DbMessageRegistry implements MessageRegistry { @Override public List getRetainMessage(String topic) { - try (Connection connection = DruidConnectionProvider.singleTon().getConnection()) { + try (Connection connection = HikariCPConnectionProvider.singleTon().getConnection()) { DSLContext dslContext = DSL.using(connection); return dslContext .selectFrom(Tables.SMQTT_RETAIN) diff --git a/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/DefaultCatalog.java b/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/DefaultCatalog.java index 12de3347ab153aa616e4049a8bfc2da92785b13f..2de7d205f8f2056a4723a9048fbb7ad83661c344 100644 --- a/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/DefaultCatalog.java +++ b/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/DefaultCatalog.java @@ -19,19 +19,13 @@ public class DefaultCatalog extends CatalogImpl { private static final long serialVersionUID = 1L; - /** - * The reference instance of DEFAULT_CATALOG - */ + public static final DefaultCatalog DEFAULT_CATALOG = new DefaultCatalog(); - /** - * The schema smqtt. - */ + public final Smqtt SMQTT = Smqtt.SMQTT; - /** - * No further instances allowed - */ + private DefaultCatalog() { super(""); } diff --git a/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/Smqtt.java b/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/Smqtt.java index 1c81c734b1ce1cce041d6d845c2aa8e608cb7950..010bb68d5d33942b02dee6b72aac2224097e81f5 100644 --- a/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/Smqtt.java +++ b/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/Smqtt.java @@ -25,34 +25,21 @@ public class Smqtt extends SchemaImpl { private static final long serialVersionUID = 1L; - /** - * The reference instance of smqtt - */ + public static final Smqtt SMQTT = new Smqtt(); - /** - * The table smqtt.databasechangelog. - */ public final Databasechangelog DATABASECHANGELOG = Databasechangelog.DATABASECHANGELOG; - /** - * The table smqtt.databasechangeloglock. - */ + public final Databasechangeloglock DATABASECHANGELOGLOCK = Databasechangeloglock.DATABASECHANGELOGLOCK; - /** - * The table smqtt.smqtt_retain. - */ + public final SmqttRetain SMQTT_RETAIN = SmqttRetain.SMQTT_RETAIN; - /** - * The table smqtt.smqtt_session. - */ + public final SmqttSession SMQTT_SESSION = SmqttSession.SMQTT_SESSION; - /** - * No further instances allowed - */ + private Smqtt() { super("smqtt", null); } diff --git a/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/Tables.java b/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/Tables.java index c9d652d85fd57d38cc9ba48043670352da93ec59..dc24425ddce2ec62c6cb233277e00200935576e4 100644 --- a/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/Tables.java +++ b/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/Tables.java @@ -16,23 +16,15 @@ import io.github.quickmsg.persistent.tables.tables.SmqttSession; @SuppressWarnings({ "all", "unchecked", "rawtypes" }) public class Tables { - /** - * The table smqtt.databasechangelog. - */ + public static final Databasechangelog DATABASECHANGELOG = Databasechangelog.DATABASECHANGELOG; - /** - * The table smqtt.databasechangeloglock. - */ + public static final Databasechangeloglock DATABASECHANGELOGLOCK = Databasechangeloglock.DATABASECHANGELOGLOCK; - /** - * The table smqtt.smqtt_retain. - */ + public static final SmqttRetain SMQTT_RETAIN = SmqttRetain.SMQTT_RETAIN; - /** - * The table smqtt.smqtt_session. - */ + public static final SmqttSession SMQTT_SESSION = SmqttSession.SMQTT_SESSION; } diff --git a/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/tables/Databasechangelog.java b/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/tables/Databasechangelog.java index 7c5f295e64eb9d4b2f36d560483c08cbad2b1d84..ad30eb481caa2b9d4a9d4efcb292e5ab6ead1efc 100644 --- a/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/tables/Databasechangelog.java +++ b/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/tables/Databasechangelog.java @@ -31,87 +31,55 @@ public class Databasechangelog extends TableImpl { private static final long serialVersionUID = 1L; - /** - * The reference instance of smqtt.databasechangelog - */ + public static final Databasechangelog DATABASECHANGELOG = new Databasechangelog(); - /** - * The class holding records for this type - */ + @Override public Class getRecordType() { return DatabasechangelogRecord.class; } - /** - * The column smqtt.databasechangelog.ID. - */ + public final TableField ID = createField(DSL.name("ID"), SQLDataType.VARCHAR(255).nullable(false), this, ""); - /** - * The column smqtt.databasechangelog.AUTHOR. - */ + public final TableField AUTHOR = createField(DSL.name("AUTHOR"), SQLDataType.VARCHAR(255).nullable(false), this, ""); - /** - * The column smqtt.databasechangelog.FILENAME. - */ + public final TableField FILENAME = createField(DSL.name("FILENAME"), SQLDataType.VARCHAR(255).nullable(false), this, ""); - /** - * The column smqtt.databasechangelog.DATEEXECUTED. - */ + public final TableField DATEEXECUTED = createField(DSL.name("DATEEXECUTED"), SQLDataType.LOCALDATETIME(0).nullable(false), this, ""); - /** - * The column smqtt.databasechangelog.ORDEREXECUTED. - */ + public final TableField ORDEREXECUTED = createField(DSL.name("ORDEREXECUTED"), SQLDataType.INTEGER.nullable(false), this, ""); - /** - * The column smqtt.databasechangelog.EXECTYPE. - */ + public final TableField EXECTYPE = createField(DSL.name("EXECTYPE"), SQLDataType.VARCHAR(10).nullable(false), this, ""); - /** - * The column smqtt.databasechangelog.MD5SUM. - */ + public final TableField MD5SUM = createField(DSL.name("MD5SUM"), SQLDataType.VARCHAR(35).defaultValue(DSL.inline("NULL", SQLDataType.VARCHAR)), this, ""); - /** - * The column smqtt.databasechangelog.DESCRIPTION. - */ + public final TableField DESCRIPTION = createField(DSL.name("DESCRIPTION"), SQLDataType.VARCHAR(255).defaultValue(DSL.inline("NULL", SQLDataType.VARCHAR)), this, ""); - /** - * The column smqtt.databasechangelog.COMMENTS. - */ + public final TableField COMMENTS = createField(DSL.name("COMMENTS"), SQLDataType.VARCHAR(255).defaultValue(DSL.inline("NULL", SQLDataType.VARCHAR)), this, ""); - /** - * The column smqtt.databasechangelog.TAG. - */ + public final TableField TAG = createField(DSL.name("TAG"), SQLDataType.VARCHAR(255).defaultValue(DSL.inline("NULL", SQLDataType.VARCHAR)), this, ""); - /** - * The column smqtt.databasechangelog.LIQUIBASE. - */ + public final TableField LIQUIBASE = createField(DSL.name("LIQUIBASE"), SQLDataType.VARCHAR(20).defaultValue(DSL.inline("NULL", SQLDataType.VARCHAR)), this, ""); - /** - * The column smqtt.databasechangelog.CONTEXTS. - */ + public final TableField CONTEXTS = createField(DSL.name("CONTEXTS"), SQLDataType.VARCHAR(255).defaultValue(DSL.inline("NULL", SQLDataType.VARCHAR)), this, ""); - /** - * The column smqtt.databasechangelog.LABELS. - */ + public final TableField LABELS = createField(DSL.name("LABELS"), SQLDataType.VARCHAR(255).defaultValue(DSL.inline("NULL", SQLDataType.VARCHAR)), this, ""); - /** - * The column smqtt.databasechangelog.DEPLOYMENT_ID. - */ + public final TableField DEPLOYMENT_ID = createField(DSL.name("DEPLOYMENT_ID"), SQLDataType.VARCHAR(10).defaultValue(DSL.inline("NULL", SQLDataType.VARCHAR)), this, ""); private Databasechangelog(Name alias, Table aliased) { @@ -122,23 +90,17 @@ public class Databasechangelog extends TableImpl { super(alias, null, aliased, parameters, DSL.comment(""), TableOptions.table()); } - /** - * Create an aliased smqtt.databasechangelog table reference - */ + public Databasechangelog(String alias) { this(DSL.name(alias), DATABASECHANGELOG); } - /** - * Create an aliased smqtt.databasechangelog table reference - */ + public Databasechangelog(Name alias) { this(alias, DATABASECHANGELOG); } - /** - * Create a smqtt.databasechangelog table reference - */ + public Databasechangelog() { this(DSL.name("databasechangelog"), null); } @@ -162,17 +124,13 @@ public class Databasechangelog extends TableImpl { return new Databasechangelog(alias, this); } - /** - * Rename this table - */ + @Override public Databasechangelog rename(String name) { return new Databasechangelog(DSL.name(name), null); } - /** - * Rename this table - */ + @Override public Databasechangelog rename(Name name) { return new Databasechangelog(name, null); diff --git a/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/tables/Databasechangeloglock.java b/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/tables/Databasechangeloglock.java index 4ff6008bf53cf8143b7bab0dd5d62898e2e48296..faabcc7bebcf0bf363aed7a887b3b1813622cc86 100644 --- a/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/tables/Databasechangeloglock.java +++ b/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/tables/Databasechangeloglock.java @@ -35,37 +35,24 @@ public class Databasechangeloglock extends TableImplsmqtt.databasechangeloglock - */ + public static final Databasechangeloglock DATABASECHANGELOGLOCK = new Databasechangeloglock(); - /** - * The class holding records for this type - */ @Override public Class getRecordType() { return DatabasechangeloglockRecord.class; } - /** - * The column smqtt.databasechangeloglock.ID. - */ + public final TableField ID = createField(DSL.name("ID"), SQLDataType.INTEGER.nullable(false), this, ""); - /** - * The column smqtt.databasechangeloglock.LOCKED. - */ + public final TableField LOCKED = createField(DSL.name("LOCKED"), SQLDataType.BIT.nullable(false), this, ""); - /** - * The column smqtt.databasechangeloglock.LOCKGRANTED. - */ + public final TableField LOCKGRANTED = createField(DSL.name("LOCKGRANTED"), SQLDataType.LOCALDATETIME(0).defaultValue(DSL.inline("NULL", SQLDataType.LOCALDATETIME)), this, ""); - /** - * The column smqtt.databasechangeloglock.LOCKEDBY. - */ + public final TableField LOCKEDBY = createField(DSL.name("LOCKEDBY"), SQLDataType.VARCHAR(255).defaultValue(DSL.inline("NULL", SQLDataType.VARCHAR)), this, ""); private Databasechangeloglock(Name alias, Table aliased) { @@ -76,23 +63,17 @@ public class Databasechangeloglock extends TableImplsmqtt.databasechangeloglock table reference - */ + public Databasechangeloglock(String alias) { this(DSL.name(alias), DATABASECHANGELOGLOCK); } - /** - * Create an aliased smqtt.databasechangeloglock table reference - */ + public Databasechangeloglock(Name alias) { this(alias, DATABASECHANGELOGLOCK); } - /** - * Create a smqtt.databasechangeloglock table reference - */ + public Databasechangeloglock() { this(DSL.name("databasechangeloglock"), null); } @@ -126,17 +107,13 @@ public class Databasechangeloglock extends TableImpl { private static final long serialVersionUID = 1L; - /** - * The reference instance of smqtt.smqtt_retain - */ + public static final SmqttRetain SMQTT_RETAIN = new SmqttRetain(); - /** - * The class holding records for this type - */ + @Override public Class getRecordType() { return SmqttRetainRecord.class; } - /** - * The column smqtt.smqtt_retain.topic. 话题 - */ public final TableField TOPIC = createField(DSL.name("topic"), SQLDataType.VARCHAR(255).defaultValue(DSL.inline("NULL", SQLDataType.VARCHAR)), this, "话题"); - /** - * The column smqtt.smqtt_retain.qos. qos - */ public final TableField QOS = createField(DSL.name("qos"), SQLDataType.INTEGER.defaultValue(DSL.inline("NULL", SQLDataType.INTEGER)), this, "qos"); - /** - * The column smqtt.smqtt_retain.body. 消息内容 - */ + public final TableField BODY = createField(DSL.name("body"), SQLDataType.VARCHAR(255).defaultValue(DSL.inline("NULL", SQLDataType.VARCHAR)), this, "消息内容"); - /** - * The column smqtt.smqtt_retain.create_time. 记录保存时间 - */ + public final TableField CREATE_TIME = createField(DSL.name("create_time"), SQLDataType.LOCALDATETIME(0).defaultValue(DSL.inline("NULL", SQLDataType.LOCALDATETIME)), this, "记录保存时间"); - /** - * The column smqtt.smqtt_retain.update_time. 记录更新时间 - */ + public final TableField UPDATE_TIME = createField(DSL.name("update_time"), SQLDataType.LOCALDATETIME(0).defaultValue(DSL.inline("NULL", SQLDataType.LOCALDATETIME)), this, "记录更新时间"); private SmqttRetain(Name alias, Table aliased) { @@ -81,23 +65,17 @@ public class SmqttRetain extends TableImpl { super(alias, null, aliased, parameters, DSL.comment(""), TableOptions.table()); } - /** - * Create an aliased smqtt.smqtt_retain table reference - */ + public SmqttRetain(String alias) { this(DSL.name(alias), SMQTT_RETAIN); } - /** - * Create an aliased smqtt.smqtt_retain table reference - */ + public SmqttRetain(Name alias) { this(alias, SMQTT_RETAIN); } - /** - * Create a smqtt.smqtt_retain table reference - */ + public SmqttRetain() { this(DSL.name("smqtt_retain"), null); } @@ -126,17 +104,13 @@ public class SmqttRetain extends TableImpl { return new SmqttRetain(alias, this); } - /** - * Rename this table - */ + @Override public SmqttRetain rename(String name) { return new SmqttRetain(DSL.name(name), null); } - /** - * Rename this table - */ + @Override public SmqttRetain rename(Name name) { return new SmqttRetain(name, null); diff --git a/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/tables/SmqttSession.java b/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/tables/SmqttSession.java index fd85aeb1dc34e27785e07d9367ff575b03319a93..8e46bde625398231e4431754155509ddfb98050c 100644 --- a/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/tables/SmqttSession.java +++ b/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/tables/SmqttSession.java @@ -44,34 +44,22 @@ public class SmqttSession extends TableImpl { return SmqttSessionRecord.class; } - /** - * The column smqtt.smqtt_session.topic. 话题 - */ + public final TableField TOPIC = createField(DSL.name("topic"), SQLDataType.VARCHAR(255).defaultValue(DSL.inline("NULL", SQLDataType.VARCHAR)), this, "话题"); - /** - * The column smqtt.smqtt_session.client_id. 客户端ID - */ + public final TableField CLIENT_ID = createField(DSL.name("client_id"), SQLDataType.VARCHAR(255).defaultValue(DSL.inline("NULL", SQLDataType.VARCHAR)), this, "客户端ID"); - /** - * The column smqtt.smqtt_session.qos. qos - */ + public final TableField QOS = createField(DSL.name("qos"), SQLDataType.INTEGER.defaultValue(DSL.inline("NULL", SQLDataType.INTEGER)), this, "qos"); - /** - * The column smqtt.smqtt_session.retain. retain - */ + public final TableField RETAIN = createField(DSL.name("retain"), SQLDataType.BIT.defaultValue(DSL.inline("NULL", SQLDataType.BIT)), this, "retain"); - /** - * The column smqtt.smqtt_session.body. 消息内容 - */ + public final TableField BODY = createField(DSL.name("body"), SQLDataType.VARCHAR(255).defaultValue(DSL.inline("NULL", SQLDataType.VARCHAR)), this, "消息内容"); - /** - * The column smqtt.smqtt_session.create_time. 记录保存时间 - */ + public final TableField CREATE_TIME = createField(DSL.name("create_time"), SQLDataType.LOCALDATETIME(0).defaultValue(DSL.inline("NULL", SQLDataType.LOCALDATETIME)), this, "记录保存时间"); private SmqttSession(Name alias, Table aliased) { @@ -82,23 +70,17 @@ public class SmqttSession extends TableImpl { super(alias, null, aliased, parameters, DSL.comment(""), TableOptions.table()); } - /** - * Create an aliased smqtt.smqtt_session table reference - */ + public SmqttSession(String alias) { this(DSL.name(alias), SMQTT_SESSION); } - /** - * Create an aliased smqtt.smqtt_session table reference - */ + public SmqttSession(Name alias) { this(alias, SMQTT_SESSION); } - /** - * Create a smqtt.smqtt_session table reference - */ + public SmqttSession() { this(DSL.name("smqtt_session"), null); } @@ -122,17 +104,13 @@ public class SmqttSession extends TableImpl { return new SmqttSession(alias, this); } - /** - * Rename this table - */ + @Override public SmqttSession rename(String name) { return new SmqttSession(DSL.name(name), null); } - /** - * Rename this table - */ + @Override public SmqttSession rename(Name name) { return new SmqttSession(name, null); diff --git a/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/tables/records/DatabasechangelogRecord.java b/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/tables/records/DatabasechangelogRecord.java index 34ab72f1a14ee1fdb31bd9efb6d8de30e6ee5b39..16535eae5685fcfb27455f5d8b7838754a2af710 100644 --- a/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/tables/records/DatabasechangelogRecord.java +++ b/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/tables/records/DatabasechangelogRecord.java @@ -22,198 +22,142 @@ public class DatabasechangelogRecord extends TableRecordImplsmqtt.databasechangelog.ID. - */ + public void setId(String value) { set(0, value); } - /** - * Getter for smqtt.databasechangelog.ID. - */ + public String getId() { return (String) get(0); } - /** - * Setter for smqtt.databasechangelog.AUTHOR. - */ + public void setAuthor(String value) { set(1, value); } - /** - * Getter for smqtt.databasechangelog.AUTHOR. - */ + public String getAuthor() { return (String) get(1); } - /** - * Setter for smqtt.databasechangelog.FILENAME. - */ + public void setFilename(String value) { set(2, value); } - /** - * Getter for smqtt.databasechangelog.FILENAME. - */ + public String getFilename() { return (String) get(2); } - /** - * Setter for smqtt.databasechangelog.DATEEXECUTED. - */ + public void setDateexecuted(LocalDateTime value) { set(3, value); } - /** - * Getter for smqtt.databasechangelog.DATEEXECUTED. - */ + public LocalDateTime getDateexecuted() { return (LocalDateTime) get(3); } - /** - * Setter for smqtt.databasechangelog.ORDEREXECUTED. - */ + public void setOrderexecuted(Integer value) { set(4, value); } - /** - * Getter for smqtt.databasechangelog.ORDEREXECUTED. - */ + public Integer getOrderexecuted() { return (Integer) get(4); } - /** - * Setter for smqtt.databasechangelog.EXECTYPE. - */ + public void setExectype(String value) { set(5, value); } - /** - * Getter for smqtt.databasechangelog.EXECTYPE. - */ + public String getExectype() { return (String) get(5); } - /** - * Setter for smqtt.databasechangelog.MD5SUM. - */ + public void setMd5sum(String value) { set(6, value); } - /** - * Getter for smqtt.databasechangelog.MD5SUM. - */ + public String getMd5sum() { return (String) get(6); } - /** - * Setter for smqtt.databasechangelog.DESCRIPTION. - */ + public void setDescription(String value) { set(7, value); } - /** - * Getter for smqtt.databasechangelog.DESCRIPTION. - */ + public String getDescription() { return (String) get(7); } - /** - * Setter for smqtt.databasechangelog.COMMENTS. - */ + public void setComments(String value) { set(8, value); } - /** - * Getter for smqtt.databasechangelog.COMMENTS. - */ + public String getComments() { return (String) get(8); } - /** - * Setter for smqtt.databasechangelog.TAG. - */ + public void setTag(String value) { set(9, value); } - /** - * Getter for smqtt.databasechangelog.TAG. - */ + public String getTag() { return (String) get(9); } - /** - * Setter for smqtt.databasechangelog.LIQUIBASE. - */ + public void setLiquibase(String value) { set(10, value); } - /** - * Getter for smqtt.databasechangelog.LIQUIBASE. - */ + public String getLiquibase() { return (String) get(10); } - /** - * Setter for smqtt.databasechangelog.CONTEXTS. - */ + public void setContexts(String value) { set(11, value); } - /** - * Getter for smqtt.databasechangelog.CONTEXTS. - */ + public String getContexts() { return (String) get(11); } - /** - * Setter for smqtt.databasechangelog.LABELS. - */ + public void setLabels(String value) { set(12, value); } - /** - * Getter for smqtt.databasechangelog.LABELS. - */ + public String getLabels() { return (String) get(12); } - /** - * Setter for smqtt.databasechangelog.DEPLOYMENT_ID. - */ + public void setDeploymentId(String value) { set(13, value); } - /** - * Getter for smqtt.databasechangelog.DEPLOYMENT_ID. - */ + public String getDeploymentId() { return (String) get(13); } @@ -549,16 +493,12 @@ public class DatabasechangelogRecord extends TableRecordImplsmqtt.databasechangeloglock.ID. - */ + public void setId(Integer value) { set(0, value); } - /** - * Getter for smqtt.databasechangeloglock.ID. - */ + public Integer getId() { return (Integer) get(0); } - /** - * Setter for smqtt.databasechangeloglock.LOCKED. - */ + public void setLocked(Boolean value) { set(1, value); } - /** - * Getter for smqtt.databasechangeloglock.LOCKED. - */ + public Boolean getLocked() { return (Boolean) get(1); } - /** - * Setter for smqtt.databasechangeloglock.LOCKGRANTED. - */ + public void setLockgranted(LocalDateTime value) { set(2, value); } - /** - * Getter for smqtt.databasechangeloglock.LOCKGRANTED. - */ + public LocalDateTime getLockgranted() { return (LocalDateTime) get(2); } - /** - * Setter for smqtt.databasechangeloglock.LOCKEDBY. - */ + public void setLockedby(String value) { set(3, value); } - /** - * Getter for smqtt.databasechangeloglock.LOCKEDBY. - */ + public String getLockedby() { return (String) get(3); } @@ -199,16 +183,12 @@ public class DatabasechangeloglockRecord extends UpdatableRecordImpl implem private static final long serialVersionUID = 1L; - /** - * Setter for smqtt.smqtt_retain.topic. 话题 - */ public void setTopic(String value) { set(0, value); } - /** - * Getter for smqtt.smqtt_retain.topic. 话题 - */ + public String getTopic() { return (String) get(0); } - /** - * Setter for smqtt.smqtt_retain.qos. qos - */ + public void setQos(Integer value) { set(1, value); } - /** - * Getter for smqtt.smqtt_retain.qos. qos - */ + public Integer getQos() { return (Integer) get(1); } - /** - * Setter for smqtt.smqtt_retain.body. 消息内容 - */ + public void setBody(String value) { set(2, value); } - /** - * Getter for smqtt.smqtt_retain.body. 消息内容 - */ + public String getBody() { return (String) get(2); } - /** - * Setter for smqtt.smqtt_retain.create_time. 记录保存时间 - */ public void setCreateTime(LocalDateTime value) { set(3, value); } - /** - * Getter for smqtt.smqtt_retain.create_time. 记录保存时间 - */ public LocalDateTime getCreateTime() { return (LocalDateTime) get(3); } - /** - * Setter for smqtt.smqtt_retain.update_time. 记录更新时间 - */ + public void setUpdateTime(LocalDateTime value) { set(4, value); } - /** - * Getter for smqtt.smqtt_retain.update_time. 记录更新时间 - */ + public LocalDateTime getUpdateTime() { return (LocalDateTime) get(4); } @@ -225,16 +202,12 @@ public class SmqttRetainRecord extends TableRecordImpl implem // Constructors // ------------------------------------------------------------------------- - /** - * Create a detached SmqttRetainRecord - */ + public SmqttRetainRecord() { super(SmqttRetain.SMQTT_RETAIN); } - /** - * Create a detached, initialised SmqttRetainRecord - */ + public SmqttRetainRecord(String topic, Integer qos, String body, LocalDateTime createTime, LocalDateTime updateTime) { super(SmqttRetain.SMQTT_RETAIN); diff --git a/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/tables/records/SmqttSessionRecord.java b/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/tables/records/SmqttSessionRecord.java index b4d79ff6cdf3e4d5c637f8774e83b049d174f56a..8904fe4687cad8881d4a1d647d069072dd8682e8 100644 --- a/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/tables/records/SmqttSessionRecord.java +++ b/smqtt-persistent/smqtt-persistent-db/src/main/java/io/github/quickmsg/persistent/tables/tables/records/SmqttSessionRecord.java @@ -22,86 +22,62 @@ public class SmqttSessionRecord extends TableRecordImpl impl private static final long serialVersionUID = 1L; - /** - * Setter for smqtt.smqtt_session.topic. 话题 - */ + public void setTopic(String value) { set(0, value); } - /** - * Getter for smqtt.smqtt_session.topic. 话题 - */ + public String getTopic() { return (String) get(0); } - /** - * Setter for smqtt.smqtt_session.client_id. 客户端ID - */ + public void setClientId(String value) { set(1, value); } - /** - * Getter for smqtt.smqtt_session.client_id. 客户端ID - */ + public String getClientId() { return (String) get(1); } - /** - * Setter for smqtt.smqtt_session.qos. qos - */ + public void setQos(Integer value) { set(2, value); } - /** - * Getter for smqtt.smqtt_session.qos. qos - */ + public Integer getQos() { return (Integer) get(2); } - /** - * Setter for smqtt.smqtt_session.retain. retain - */ + public void setRetain(Boolean value) { set(3, value); } - /** - * Getter for smqtt.smqtt_session.retain. retain - */ + public Boolean getRetain() { return (Boolean) get(3); } - /** - * Setter for smqtt.smqtt_session.body. 消息内容 - */ + public void setBody(String value) { set(4, value); } - /** - * Getter for smqtt.smqtt_session.body. 消息内容 - */ + public String getBody() { return (String) get(4); } - /** - * Setter for smqtt.smqtt_session.create_time. 记录保存时间 - */ + public void setCreateTime(LocalDateTime value) { set(5, value); } - /** - * Getter for smqtt.smqtt_session.create_time. 记录保存时间 - */ + public LocalDateTime getCreateTime() { return (LocalDateTime) get(5); } @@ -261,16 +237,12 @@ public class SmqttSessionRecord extends TableRecordImpl impl // Constructors // ------------------------------------------------------------------------- - /** - * Create a detached SmqttSessionRecord - */ + public SmqttSessionRecord() { super(SmqttSession.SMQTT_SESSION); } - /** - * Create a detached, initialised SmqttSessionRecord - */ + public SmqttSessionRecord(String topic, String clientId, Integer qos, Boolean retain, String body, LocalDateTime createTime) { super(SmqttSession.SMQTT_SESSION); diff --git a/smqtt-persistent/smqtt-persistent-redis/pom.xml b/smqtt-persistent/smqtt-persistent-redis/pom.xml index b8e9f2652a77cb4d83ce55c5afb032a9ce4debea..077a62f68991827cf553135dbf9e91a79efb7058 100644 --- a/smqtt-persistent/smqtt-persistent-redis/pom.xml +++ b/smqtt-persistent/smqtt-persistent-redis/pom.xml @@ -5,12 +5,12 @@ smqtt-persistent io.github.quickmsg - 1.0.5 + 1.1.7 4.0.0 smqtt-persistent-redis - 1.0.5 + 1.1.7 3.15.6 @@ -20,7 +20,7 @@ io.github.quickmsg smqtt-common - 1.0.5 + 1.1.7 compile @@ -35,10 +35,5 @@ commons-lang3 - - com.alibaba - fastjson - - \ No newline at end of file diff --git a/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/message/RetainMessageEntity.java b/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/message/RetainMessageEntity.java index 665844072d578f210605d7e4cdbed48bf693f11a..086c987049d3960ec93cd0f42d93a0d164b7b89d 100644 --- a/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/message/RetainMessageEntity.java +++ b/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/message/RetainMessageEntity.java @@ -1,6 +1,6 @@ package io.github.quickmsg.persistent.message; -import com.alibaba.fastjson.annotation.JSONField; +import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Builder; import lombok.Data; @@ -24,9 +24,11 @@ public class RetainMessageEntity implements Serializable { private byte[] body; - @JSONField(format = "yyyy-MM-dd HH:mm:ss") + private String userProperties; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date createTime; - @JSONField(format = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date updateTime; } diff --git a/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/message/SessionMessageEntity.java b/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/message/SessionMessageEntity.java index 35f639f04ff5881e6248cf51256e9ae0ae5ca386..5a979bf46992e740061139a042d8d48e1224a0e8 100644 --- a/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/message/SessionMessageEntity.java +++ b/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/message/SessionMessageEntity.java @@ -1,6 +1,6 @@ package io.github.quickmsg.persistent.message; -import com.alibaba.fastjson.annotation.JSONField; +import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Builder; import lombok.Data; @@ -25,7 +25,9 @@ public class SessionMessageEntity implements Serializable { private Boolean retain; + private String userProperties; + private byte[] body; - @JSONField(format = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date createTime; } diff --git a/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/registry/RedisMessageRegistry.java b/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/registry/RedisMessageRegistry.java index 8f2066d15fb22cef51e139e08d05a963384943b3..a24f5a978ac3192ed52b45a166feac363b035337 100644 --- a/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/registry/RedisMessageRegistry.java +++ b/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/registry/RedisMessageRegistry.java @@ -1,6 +1,7 @@ package io.github.quickmsg.persistent.registry; import io.github.quickmsg.common.bootstrap.BootstrapKey; +import io.github.quickmsg.common.config.BootstrapConfig; import io.github.quickmsg.common.environment.EnvContext; import io.github.quickmsg.common.message.MessageRegistry; import io.github.quickmsg.common.message.RetainMessage; @@ -36,13 +37,13 @@ public class RedisMessageRegistry implements MessageRegistry { private RedissonClient redissonClient = null; @Override - public void startUp(EnvContext envContext) { + public void startUp(Map environmentMap) { try { - Map environments = envContext.getEnvironments(); + BootstrapConfig.RedisConfig redisConfig = (BootstrapConfig.RedisConfig) environmentMap.get(BootstrapConfig.RedisConfig.class); // 获取客户端策略 - ClientStrategy clientStrategy = ClientFactory.getClientStrategy(environments.get(BootstrapKey.Redis.REDIS_MODE)); + ClientStrategy clientStrategy = ClientFactory.getClientStrategy(redisConfig.getMode()); // 获取redisson客户端 - redissonClient = clientStrategy.getRedissonClient(environments); + redissonClient = clientStrategy.getRedissonClient(redisConfig); } catch (Exception e) { log.error("startUp error message", e); } diff --git a/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/strategy/ClientStrategy.java b/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/strategy/ClientStrategy.java index 4ea12b7f58873d4b8d129b6d435858735e069f9e..fbdccf4e93b4a74d194bd4b5be338ec5a6c2694e 100644 --- a/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/strategy/ClientStrategy.java +++ b/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/strategy/ClientStrategy.java @@ -1,5 +1,6 @@ package io.github.quickmsg.persistent.strategy; +import io.github.quickmsg.common.config.BootstrapConfig; import org.redisson.api.RedissonClient; import java.util.Map; @@ -15,8 +16,8 @@ public interface ClientStrategy { /** * 获取redisson客户端 * - * @param environments 參數map + * @param redisConfig * @return {@link RedissonClient} */ - RedissonClient getRedissonClient(Map environments); + RedissonClient getRedissonClient(BootstrapConfig.RedisConfig redisConfig); } diff --git a/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/strategy/ClusterClientStrategy.java b/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/strategy/ClusterClientStrategy.java index 0dbc0f725d5edcdaaacef0e47669c53f3aeaff4c..4233b0cc009a7d6889c619d91eb0e93768613d4e 100644 --- a/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/strategy/ClusterClientStrategy.java +++ b/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/strategy/ClusterClientStrategy.java @@ -1,6 +1,7 @@ package io.github.quickmsg.persistent.strategy; import io.github.quickmsg.common.bootstrap.BootstrapKey; +import io.github.quickmsg.common.config.BootstrapConfig; import org.apache.commons.lang3.StringUtils; import org.redisson.Redisson; import org.redisson.api.RedissonClient; @@ -21,25 +22,25 @@ import java.util.Map; public class ClusterClientStrategy implements ClientStrategy { @Override - public RedissonClient getRedissonClient(Map environments) { + public RedissonClient getRedissonClient(BootstrapConfig.RedisConfig redisConfig) { Config config = new Config(); - String[] nodes = environments.get(BootstrapKey.RedisCluster.REDIS_CLUSTER_NODES).split(","); + String[] nodes = redisConfig.getCluster().getNodes().split(","); List newNodes = new ArrayList(nodes.length); Arrays.stream(nodes).forEach((index) -> newNodes.add(index.startsWith("redis://") ? index : "redis://" + index)); ClusterServersConfig serverConfig = config.useClusterServers() .addNodeAddress(newNodes.toArray(new String[0])) - .setTimeout(Integer.parseInt(environments.get(BootstrapKey.Redis.REDIS_TIMEOUT))) - .setConnectTimeout(Integer.parseInt(environments.get(BootstrapKey.Redis.REDIS_POOL_CONN_TIMEOUT))) - .setScanInterval(Integer.parseInt(environments.get(BootstrapKey.RedisCluster.REDIS_CLUSTER_SCAN_INTERVAL))) - .setReadMode(getReadMode(environments.get(BootstrapKey.RedisCluster.REDIS_CLUSTER_READ_MODE))) - .setRetryAttempts(Integer.parseInt(environments.get(BootstrapKey.RedisCluster.REDIS_CLUSTER_RETRY_ATTEMPTS))) - .setMasterConnectionPoolSize(Integer.parseInt(environments.get(BootstrapKey.RedisCluster.REDIS_CLUSTER_MASTER_CONNECTION_POOL_SIZE))) - .setSlaveConnectionPoolSize(Integer.parseInt(environments.get(BootstrapKey.RedisCluster.REDIS_CLUSTER_SLAVE_CONNECTION_POOL_SIZE))) - .setRetryInterval(Integer.parseInt(environments.get(BootstrapKey.RedisCluster.REDIS_CLUSTER_RETRY_INTERVAL))); + .setTimeout(redisConfig.getTimeout()) + .setConnectTimeout(redisConfig.getPoolConnTimeout()) + .setScanInterval(redisConfig.getCluster().getScanInterval()) + .setReadMode(getReadMode(redisConfig.getCluster().getReadMode())) + .setRetryAttempts(redisConfig.getCluster().getRetryAttempts()) + .setMasterConnectionPoolSize(redisConfig.getCluster().getMasterConnectionPoolSize()) + .setSlaveConnectionPoolSize(redisConfig.getCluster().getSlaveConnectionPoolSize()) + .setRetryInterval(redisConfig.getCluster().getRetryInterval()); - if (StringUtils.isNotBlank(environments.get(BootstrapKey.Redis.REDIS_PASSWORD))) { - serverConfig.setPassword(environments.get(BootstrapKey.Redis.REDIS_PASSWORD)); + if (StringUtils.isNotBlank(redisConfig.getPassword())) { + serverConfig.setPassword(redisConfig.getPassword()); } return Redisson.create(config); } diff --git a/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/strategy/SentinelClientStrategy.java b/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/strategy/SentinelClientStrategy.java index d24ebde853966b7a1d075c52bb8175803192ea70..b20a53cf6b6af525f56c5732ef443f3882109f33 100644 --- a/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/strategy/SentinelClientStrategy.java +++ b/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/strategy/SentinelClientStrategy.java @@ -1,6 +1,7 @@ package io.github.quickmsg.persistent.strategy; import io.github.quickmsg.common.bootstrap.BootstrapKey; +import io.github.quickmsg.common.config.BootstrapConfig; import io.github.quickmsg.persistent.message.SessionMessageEntity; import org.apache.commons.lang3.StringUtils; import org.redisson.Redisson; @@ -22,10 +23,10 @@ public class SentinelClientStrategy implements ClientStrategy { @Override - public RedissonClient getRedissonClient(Map environments) { + public RedissonClient getRedissonClient(BootstrapConfig.RedisConfig redisConfig) { Config config = new Config(); - String[] nodes = environments.get(BootstrapKey.RedisSentinel.REDIS_SENTINEL_NODES).split(","); + String[] nodes = redisConfig.getSentinel().getNodes().split(","); List newNodes = new ArrayList(nodes.length); Arrays.stream(nodes).forEach((index) -> newNodes.add( @@ -33,14 +34,14 @@ public class SentinelClientStrategy implements ClientStrategy { SentinelServersConfig serverConfig = config.useSentinelServers() .addSentinelAddress(newNodes.toArray(new String[0])) - .setDatabase(Integer.parseInt(environments.get(BootstrapKey.Redis.REDIS_DATABASE))) - .setTimeout(Integer.parseInt(environments.get(BootstrapKey.Redis.REDIS_TIMEOUT))) - .setConnectTimeout(Integer.parseInt(environments.get(BootstrapKey.Redis.REDIS_POOL_CONN_TIMEOUT))) - .setMasterName(environments.get(BootstrapKey.RedisSentinel.REDIS_SENTINEL_MASTER)) - .setTimeout(Integer.parseInt(environments.get(BootstrapKey.Redis.REDIS_TIMEOUT))); - - if (StringUtils.isNotBlank(environments.get(BootstrapKey.Redis.REDIS_PASSWORD))) { - serverConfig.setPassword(environments.get(BootstrapKey.Redis.REDIS_PASSWORD)); + .setDatabase(redisConfig.getDatabase()) + .setTimeout(redisConfig.getTimeout()) + .setConnectTimeout(redisConfig.getPoolConnTimeout()) + .setMasterName(redisConfig.getSentinel().getMaster()) + .setTimeout(redisConfig.getTimeout()); + + if (StringUtils.isNotBlank(redisConfig.getPassword())) { + serverConfig.setPassword(redisConfig.getPassword()); } return Redisson.create(config); diff --git a/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/strategy/SingleClientStrategy.java b/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/strategy/SingleClientStrategy.java index 08d5193aca5361943f9e9816ed83ce78dedadbcf..7be45db11a2d90f88a3d895f718185b688620170 100644 --- a/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/strategy/SingleClientStrategy.java +++ b/smqtt-persistent/smqtt-persistent-redis/src/main/java/io/github/quickmsg/persistent/strategy/SingleClientStrategy.java @@ -1,6 +1,7 @@ package io.github.quickmsg.persistent.strategy; import io.github.quickmsg.common.bootstrap.BootstrapKey; +import io.github.quickmsg.common.config.BootstrapConfig; import org.apache.commons.lang3.StringUtils; import org.redisson.Redisson; import org.redisson.api.RedissonClient; @@ -19,19 +20,19 @@ public class SingleClientStrategy implements ClientStrategy { @Override - public RedissonClient getRedissonClient(Map environments) { + public RedissonClient getRedissonClient(BootstrapConfig.RedisConfig redisConfig) { Config config = new Config(); - String node = environments.get(BootstrapKey.RedisSingle.REDIS_SINGLE_ADDRESS); + String node = redisConfig.getSingle().getAddress(); node = node.startsWith("redis://") ? node : "redis://" + node; SingleServerConfig serverConfig = config.useSingleServer() .setAddress(node) - .setDatabase(Integer.parseInt(environments.get(BootstrapKey.Redis.REDIS_DATABASE))) - .setTimeout(Integer.parseInt(environments.get(BootstrapKey.Redis.REDIS_TIMEOUT))) - .setConnectionMinimumIdleSize(Integer.parseInt(environments.get(BootstrapKey.Redis.REDIS_POOL_MIN_IDLE))) - .setConnectTimeout(Integer.parseInt(environments.get(BootstrapKey.Redis.REDIS_POOL_CONN_TIMEOUT))) - .setConnectionPoolSize(Integer.parseInt(environments.get(BootstrapKey.Redis.REDIS_POOL_SIZE))); - if (StringUtils.isNotBlank(environments.get(BootstrapKey.Redis.REDIS_PASSWORD))) { - serverConfig.setPassword(environments.get(BootstrapKey.Redis.REDIS_PASSWORD)); + .setDatabase(redisConfig.getDatabase()) + .setTimeout(redisConfig.getTimeout()) + .setConnectionMinimumIdleSize(redisConfig.getPoolMinIdle()) + .setConnectTimeout(redisConfig.getPoolConnTimeout()) + .setConnectionPoolSize(redisConfig.getPoolSize()); + if (StringUtils.isNotBlank(redisConfig.getPassword())) { + serverConfig.setPassword(redisConfig.getPassword()); } return Redisson.create(config); } diff --git a/smqtt-registry/pom.xml b/smqtt-registry/pom.xml index e98fd517aad0bdee9834089c985978fdc5730f2b..bc1c802025e7dd8d18f5649c6c4a21ba5c91ba1b 100644 --- a/smqtt-registry/pom.xml +++ b/smqtt-registry/pom.xml @@ -5,7 +5,7 @@ smqtt io.github.quickmsg - 1.0.5 + 1.1.7 4.0.0 pom diff --git a/smqtt-registry/smqtt-registry-scube/pom.xml b/smqtt-registry/smqtt-registry-scube/pom.xml index 4ef11f2a4b0aed8482ba23a28f6b5b907a2e20d9..84db89af57c5ffc17008931197f432c2fbc4abd7 100644 --- a/smqtt-registry/smqtt-registry-scube/pom.xml +++ b/smqtt-registry/smqtt-registry-scube/pom.xml @@ -5,7 +5,7 @@ smqtt-registry io.github.quickmsg - 1.0.5 + 1.1.7 4.0.0 smqtt-registry-scube @@ -14,7 +14,7 @@ - 2.6.7 + 2.6.11 2.13.2 1.7.30 @@ -41,17 +41,23 @@ scalecube-cluster ${scalecube-cluster.version} + + io.scalecube + scalecube-transport-netty + ${scalecube-cluster.version} + + io.github.quickmsg smqtt-common - 1.0.5 + 1.1.7 + provided junit junit test - diff --git a/smqtt-registry/smqtt-registry-scube/src/main/java/io/github/quickmsg/registry/ScubeClusterRegistry.java b/smqtt-registry/smqtt-registry-scube/src/main/java/io/github/quickmsg/registry/ScubeClusterRegistry.java index 0b9ef763a5c36eac3333a12f9518681723c52965..8d074abe03148b64d24950478d0e5ac6cf56378b 100644 --- a/smqtt-registry/smqtt-registry-scube/src/main/java/io/github/quickmsg/registry/ScubeClusterRegistry.java +++ b/smqtt-registry/smqtt-registry-scube/src/main/java/io/github/quickmsg/registry/ScubeClusterRegistry.java @@ -1,10 +1,11 @@ package io.github.quickmsg.registry; -import io.github.quickmsg.common.cluster.ClusterConfig; -import io.github.quickmsg.common.cluster.ClusterMessage; import io.github.quickmsg.common.cluster.ClusterNode; import io.github.quickmsg.common.cluster.ClusterRegistry; -import io.github.quickmsg.common.enums.ClusterEvent; +import io.github.quickmsg.common.config.BootstrapConfig; +import io.github.quickmsg.common.enums.ClusterStatus; +import io.github.quickmsg.common.message.ClusterMessage; +import io.github.quickmsg.common.message.HeapMqttMessage; import io.scalecube.cluster.Cluster; import io.scalecube.cluster.ClusterImpl; import io.scalecube.cluster.ClusterMessageHandler; @@ -12,12 +13,15 @@ import io.scalecube.cluster.Member; import io.scalecube.cluster.membership.MembershipEvent; import io.scalecube.cluster.transport.api.Message; import io.scalecube.net.Address; +import io.scalecube.reactor.RetryNonSerializedEmitFailureHandler; +import io.scalecube.transport.netty.tcp.TcpTransportFactory; import lombok.extern.slf4j.Slf4j; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.publisher.Sinks; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -30,21 +34,30 @@ public class ScubeClusterRegistry implements ClusterRegistry { private Sinks.Many messageMany = Sinks.many().multicast().onBackpressureBuffer(); - private Sinks.Many eventMany = Sinks.many().multicast().onBackpressureBuffer(); + private Sinks.Many eventMany = Sinks.many().multicast().onBackpressureBuffer(); private Cluster cluster; @Override - public void registry(ClusterConfig clusterConfig) { + public void registry(BootstrapConfig.ClusterConfig clusterConfig) { this.cluster = new ClusterImpl() - .config(opts -> opts.memberAlias(clusterConfig.getNodeName())) + .config(opts -> + opts.memberAlias(clusterConfig.getNode()) + .externalHost(Optional.ofNullable(clusterConfig.getExternal()) + .map(BootstrapConfig.ClusterExternal::getHost) + .orElse(null)) + .externalPort(Optional.ofNullable(clusterConfig.getExternal()) + .map(BootstrapConfig.ClusterExternal::getPort) + .orElse(null)) + ) + .transportFactory(TcpTransportFactory::new) .transport(transportConfig -> transportConfig.port(clusterConfig.getPort())) .membership(opts -> opts.seedMembers(Arrays.stream(clusterConfig - .getClusterUrl() + .getUrl() .split(",")) .map(Address::from) - .collect(Collectors.toList()))) + .collect(Collectors.toList())).namespace(clusterConfig.getNamespace())) .handler(cluster -> new ClusterHandler()) .startAwait(); } @@ -56,7 +69,9 @@ public class ScubeClusterRegistry implements ClusterRegistry { @Override public List getClusterNode() { - return cluster.members().stream().map(this::clusterNode).collect(Collectors.toList()); + return Optional.ofNullable(cluster) + .map(cs -> cs.members().stream().map(this::clusterNode).collect(Collectors.toList())) + .orElse(Collections.emptyList()); } private ClusterNode clusterNode(Member member) { @@ -71,8 +86,15 @@ public class ScubeClusterRegistry implements ClusterRegistry { @Override public Mono spreadMessage(ClusterMessage clusterMessage) { log.info("cluster send message {} ", clusterMessage); - return Optional.ofNullable(cluster) - .map(cs -> cs.spreadGossip(Message.withData(clusterMessage).build()).then()).orElse(Mono.empty()); + return Mono.when( + cluster.otherMembers() + .stream() + .map(member -> + Optional.ofNullable(cluster) + .map(cs -> + cs.send(member, Message.withData(clusterMessage).build()).then() + ).orElse(Mono.empty())) + .collect(Collectors.toList())); } @Override @@ -82,7 +104,7 @@ public class ScubeClusterRegistry implements ClusterRegistry { } @Override - public Flux clusterEvent() { + public Flux clusterEvent() { return eventMany.asFlux(); } @@ -92,13 +114,13 @@ public class ScubeClusterRegistry implements ClusterRegistry { @Override public void onMessage(Message message) { log.info("cluster accept message {} ", message); - messageMany.tryEmitNext(message.data()); + messageMany.emitNext(message.data(),new RetryNonSerializedEmitFailureHandler()); } @Override public void onGossip(Message message) { log.info("cluster accept message {} ", message); - messageMany.tryEmitNext(message.data()); + messageMany.emitNext(message.data(),new RetryNonSerializedEmitFailureHandler()); } @Override @@ -107,16 +129,16 @@ public class ScubeClusterRegistry implements ClusterRegistry { log.info("cluster onMembershipEvent {} {}", member, event); switch (event.type()) { case ADDED: - eventMany.tryEmitNext(ClusterEvent.ADDED); + eventMany.tryEmitNext(ClusterStatus.ADDED); break; case LEAVING: - eventMany.tryEmitNext(ClusterEvent.LEAVING); + eventMany.tryEmitNext(ClusterStatus.LEAVING); break; case REMOVED: - eventMany.tryEmitNext(ClusterEvent.REMOVED); + eventMany.tryEmitNext(ClusterStatus.REMOVED); break; case UPDATED: - eventMany.tryEmitNext(ClusterEvent.UPDATED); + eventMany.tryEmitNext(ClusterStatus.UPDATED); break; default: break; diff --git a/smqtt-rule/pom.xml b/smqtt-rule/pom.xml index b0d569337a8e14a83cb6d78fb898a0928b2bf0e8..885850d2f7caaea7c9c0cc17e636f359c62972c4 100644 --- a/smqtt-rule/pom.xml +++ b/smqtt-rule/pom.xml @@ -1,13 +1,33 @@ - 4.0.0 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 - io.github.quickmsg - smqtt-rule - 1.0.5 - pom - smqtt-rule + + smqtt + io.github.quickmsg + 1.1.7 + + smqtt-rule + + smqtt-rule-dsl + smqtt-rule-engine + smqtt-rule-source + + pom + smqtt-rule + + + + org.apache.maven.plugins + maven-deploy-plugin + 2.7 + + true + + + + diff --git a/smqtt-rule/smqtt-rule-dsl/pom.xml b/smqtt-rule/smqtt-rule-dsl/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..2da6db3bc5bd920dda3a267d74c9f60af15f7102 --- /dev/null +++ b/smqtt-rule/smqtt-rule-dsl/pom.xml @@ -0,0 +1,40 @@ + + + + smqtt-rule + io.github.quickmsg + 1.1.7 + + 4.0.0 + + smqtt-rule-dsl + + + + io.github.quickmsg + smqtt-common + 1.1.7 + provided + + + smqtt-rule-engine + io.github.quickmsg + 1.1.7 + + + + + + org.apache.maven.plugins + maven-deploy-plugin + 2.7 + + true + + + + + + \ No newline at end of file diff --git a/smqtt-rule/smqtt-rule-dsl/src/main/java/io/github/quickmsg/dsl/RuleDsl.java b/smqtt-rule/smqtt-rule-dsl/src/main/java/io/github/quickmsg/dsl/RuleDsl.java new file mode 100644 index 0000000000000000000000000000000000000000..9fcb5280c6e3185a6396284d63bd54409a1a30e1 --- /dev/null +++ b/smqtt-rule/smqtt-rule-dsl/src/main/java/io/github/quickmsg/dsl/RuleDsl.java @@ -0,0 +1,22 @@ +package io.github.quickmsg.dsl; + +import io.github.quickmsg.common.enums.RuleType; +import lombok.Data; + +import java.util.List; + +/** + * @author luxurong + */ +@Data +public class RuleDsl { + + private String name; + + private List rules; + + private RuleType ruleType; + + private String action; + +} diff --git a/smqtt-rule/smqtt-rule-dsl/src/main/java/io/github/quickmsg/dsl/RuleDslExecutor.java b/smqtt-rule/smqtt-rule-dsl/src/main/java/io/github/quickmsg/dsl/RuleDslExecutor.java new file mode 100644 index 0000000000000000000000000000000000000000..97dd63e91cbded837d55b3fd1b4258574b2c65e3 --- /dev/null +++ b/smqtt-rule/smqtt-rule-dsl/src/main/java/io/github/quickmsg/dsl/RuleDslExecutor.java @@ -0,0 +1,39 @@ +package io.github.quickmsg.dsl; + +import io.github.quickmsg.common.channel.MqttChannel; +import io.github.quickmsg.common.context.ReceiveContext; +import io.github.quickmsg.common.message.HeapMqttMessage; +import io.github.quickmsg.common.rule.DslExecutor; +import io.github.quickmsg.rule.RuleChain; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; + +/** + * @author luxurong + */ + +public class RuleDslExecutor implements DslExecutor { + + private final RuleChain ruleChain; + + public RuleDslExecutor(RuleChain ruleChain) { + this.ruleChain = ruleChain; + } + + @Override + public void executeRule(Object... object) { + Mono.deferContextual(ruleChain::executeRule) + .contextWrite(context -> context + .put(MqttChannel.class, object[0]) + .put(HeapMqttMessage.class, object[1]) + .put(ReceiveContext.class, object[2])) + .subscribeOn(Schedulers.parallel()) + .subscribe(); + } + + + @Override + public Boolean isExecute() { + return ruleChain.getRuleNodeList().size() > 0; + } +} diff --git a/smqtt-rule/smqtt-rule-dsl/src/main/java/io/github/quickmsg/dsl/RuleDslParser.java b/smqtt-rule/smqtt-rule-dsl/src/main/java/io/github/quickmsg/dsl/RuleDslParser.java new file mode 100644 index 0000000000000000000000000000000000000000..b7011dd383704b76ad3b9b884a35471abb303c37 --- /dev/null +++ b/smqtt-rule/smqtt-rule-dsl/src/main/java/io/github/quickmsg/dsl/RuleDslParser.java @@ -0,0 +1,30 @@ +package io.github.quickmsg.dsl; + +import io.github.quickmsg.common.rule.RuleChainDefinition; +import io.github.quickmsg.rule.RuleChain; + +import java.util.List; + +/** + * @author luxurong + */ +public class RuleDslParser { + + private RuleChain ruleChain = RuleChain.INSTANCE; + + + private final List ruleChainDefinitions; + + public RuleDslParser(List ruleChainDefinitions) { + this.ruleChainDefinitions = ruleChainDefinitions; + } + + public RuleDslExecutor parseRule() { + if (ruleChainDefinitions != null && ruleChainDefinitions.size() > 0) { + ruleChainDefinitions.stream().map(RuleChainDefinition::getChain).forEach(ruleChain::addRules); + } + return new RuleDslExecutor(ruleChain); + } + + +} diff --git a/smqtt-rule/smqtt-rule-engine/pom.xml b/smqtt-rule/smqtt-rule-engine/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..a675d2abe44e295e35c896d3e3c2c79f11828681 --- /dev/null +++ b/smqtt-rule/smqtt-rule-engine/pom.xml @@ -0,0 +1,79 @@ + + + + 4.0.0 + + + smqtt-rule + io.github.quickmsg + 1.1.7 + + + smqtt-rule-engine + + smqtt-rule-engine + + + + io.github.quickmsg + smqtt-common + 1.1.7 + provided + + + + io.github.quickmsg + smqtt-rule-source-kafka + 1.1.7 + + + + io.github.quickmsg + smqtt-rule-source-http + 1.1.7 + + + + io.github.quickmsg + smqtt-rule-source-rocketmq + 1.1.7 + + + + io.github.quickmsg + smqtt-rule-source-rabbitmq + 1.1.7 + + + + io.github.quickmsg + smqtt-rule-source-db + 1.1.7 + + + + io.github.quickmsg + smqtt-rule-source-mqtt + 1.1.7 + + + + org.projectlombok + lombok + + + + org.apache.commons + commons-jexl3 + 3.2.1 + + + + junit + junit + 4.11 + test + + + diff --git a/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/RuleChain.java b/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/RuleChain.java new file mode 100644 index 0000000000000000000000000000000000000000..dd7268b60322d2483f24af9190eeb612c4c2e4f2 --- /dev/null +++ b/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/RuleChain.java @@ -0,0 +1,68 @@ +package io.github.quickmsg.rule; + +import io.github.quickmsg.common.rule.RuleDefinition; +import io.github.quickmsg.common.rule.source.Source; +import io.github.quickmsg.rule.node.*; +import lombok.Getter; +import reactor.core.publisher.Mono; +import reactor.util.context.ContextView; + +import java.util.LinkedList; +import java.util.List; + +/** + * @author luxurong + */ +@Getter +public class RuleChain { + + private RuleChain() { + } + + public final static RuleChain INSTANCE = new RuleChain(); + + private LinkedList ruleNodeList = new LinkedList<>(); + + public void addRules(List definitions) { + RuleNode rootNode = this.parseNode(definitions.get(0)); + RuleNode preNode = rootNode; + for (int i = 1; i < definitions.size(); i++) { + RuleNode node = this.parseNode(definitions.get(i)); + preNode.setNextRuleNode(node); + preNode = node; + } + ruleNodeList.addLast(rootNode); + } + + + private RuleNode parseNode(RuleDefinition definition) { + switch (definition.getRuleType()) { + case HTTP: + return new TransmitRuleNode(Source.HTTP, definition.getScript()); + case PREDICATE: + return new PredicateRuleNode(definition.getScript()); + case KAFKA: + return new TransmitRuleNode(Source.KAFKA, definition.getScript()); + case TOPIC: + return new TopicRuleNode(definition.getScript()); + case LOG: + return new LoggerRuleNode(definition.getScript()); + case ROCKET_MQ: + return new TransmitRuleNode(Source.ROCKET_MQ, definition.getScript()); + case RABBIT_MQ: + return new TransmitRuleNode(Source.RABBIT_MQ, definition.getScript()); + case DATA_BASE: + return new DatabaseRuleNode(definition.getScript()); + case MQTT: + return new TransmitRuleNode(Source.MQTT, definition.getScript()); + default: + return new EmptyNode(); + } + } + + + public Mono executeRule(ContextView contextView) { + return Mono.fromRunnable(() -> ruleNodeList.forEach(ruleNode -> ruleNode.execute(contextView))); + } + +} diff --git a/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/RuleExecute.java b/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/RuleExecute.java new file mode 100644 index 0000000000000000000000000000000000000000..45877c613673236f55622f1cb47bfb49917b34cd --- /dev/null +++ b/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/RuleExecute.java @@ -0,0 +1,58 @@ +package io.github.quickmsg.rule; + +import io.github.quickmsg.common.utils.TopicRegexUtils; +import org.apache.commons.jexl3.*; +import reactor.util.context.ContextView; + +import java.util.function.Consumer; + +/** + * @author luxurong + */ +public interface RuleExecute { + + JexlEngine J_EXL_ENGINE = new JexlBuilder().create(); + + JxltEngine T_J_EXL_ENGINE = new JexlBuilder().create().createJxltEngine(); + + + /** + * 执行 + * + * @param context 上下文容器 + * \ + */ + void execute(ContextView context); + + + /** + * 执行脚本 + * + * @param script 脚本 + * @param mapContextConsumer 设置参数 + * @return Object 返回值 + */ + default Object triggerScript(String script, Consumer mapContextConsumer) { + JexlExpression e = J_EXL_ENGINE.createExpression(script); + MapContext context = new MapContext(); + mapContextConsumer.accept(context); + context.set("TopicUtils", TopicRegexUtils.instance); + return e.evaluate(context); + } + + /** + * 执行模版 + * + * @param script 模版 + * @param mapContextConsumer 设置参数 + * @return Object 返回值 + */ + default Object triggerTemplate(String script, Consumer mapContextConsumer) { + J_EXL_ENGINE.createJxltEngine(); + JxltEngine.Expression expression = T_J_EXL_ENGINE.createExpression(script); + MapContext context = new MapContext(); + mapContextConsumer.accept(context); + return expression.evaluate(context); + } + +} diff --git a/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/RuleNode.java b/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/RuleNode.java new file mode 100644 index 0000000000000000000000000000000000000000..08741b32a8842b3dd9d0036b73dc0e6cffdd97d0 --- /dev/null +++ b/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/RuleNode.java @@ -0,0 +1,38 @@ +package io.github.quickmsg.rule; + +import reactor.util.context.ContextView; + +import java.util.Optional; + +/** + * @author luxurong + */ +public interface RuleNode extends RuleExecute { + + /*** + * 获取下一个RuleNode + * @return {@link RuleNode} + */ + RuleNode getNextRuleNode(); + + + /*** + * 设置下一个RuleNode + * @param ruleNode {@link RuleNode} + */ + void setNextRuleNode(RuleNode ruleNode); + + + /** + * 执行下个Node + * + * @param context {@link ContextView} + */ + default void executeNext(ContextView context) { + Optional.ofNullable(getNextRuleNode()) + .ifPresent(ruleNode -> ruleNode.execute(context)); + } + + + +} diff --git a/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/node/DatabaseRuleNode.java b/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/node/DatabaseRuleNode.java new file mode 100644 index 0000000000000000000000000000000000000000..63e168c3b1aa9bcd4535ca81dcaa4fde6d9aac80 --- /dev/null +++ b/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/node/DatabaseRuleNode.java @@ -0,0 +1,52 @@ +package io.github.quickmsg.rule.node; + +import io.github.quickmsg.common.message.HeapMqttMessage; +import io.github.quickmsg.common.rule.source.Source; +import io.github.quickmsg.rule.RuleNode; +import io.github.quickmsg.rule.source.SourceManager; +import reactor.util.context.ContextView; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +/** + * @author luxurong + */ +public class DatabaseRuleNode implements RuleNode { + + private final String script; + + private RuleNode ruleNode; + + public DatabaseRuleNode(String script) { + this.script = script; + } + + @Override + public RuleNode getNextRuleNode() { + return this.ruleNode; + } + + + @Override + public void setNextRuleNode(RuleNode ruleNode) { + this.ruleNode = ruleNode; + } + + @Override + public void execute(ContextView contextView) { + HeapMqttMessage heapMqttMessage = contextView.get(HeapMqttMessage.class); + Map param = new HashMap<>(); + if (script != null) { + Object obj = triggerTemplate(script, context -> heapMqttMessage.getKeyMap().forEach(context::set)); + param.put("sql", String.valueOf(obj)); + Optional.ofNullable(SourceManager.getSourceBean(Source.DATA_BASE)) + .ifPresent(sourceBean -> sourceBean.transmit(param)); + } + executeNext(contextView); + } +} + + + diff --git a/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/node/EmptyNode.java b/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/node/EmptyNode.java new file mode 100644 index 0000000000000000000000000000000000000000..7b4823bce7baa45fc42686dbbfd013e346213e3f --- /dev/null +++ b/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/node/EmptyNode.java @@ -0,0 +1,25 @@ +package io.github.quickmsg.rule.node; + +import io.github.quickmsg.rule.RuleNode; +import reactor.util.context.ContextView; + +/** + * @author luxurong + */ +public class EmptyNode implements RuleNode { + + + @Override + public RuleNode getNextRuleNode() { + return null; + } + + @Override + public void setNextRuleNode(RuleNode ruleNode) { + + } + + @Override + public void execute(ContextView contextView) { + } +} diff --git a/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/node/LoggerRuleNode.java b/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/node/LoggerRuleNode.java new file mode 100644 index 0000000000000000000000000000000000000000..8df0adaa42dd897776d2c22d96ff71250a5d447d --- /dev/null +++ b/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/node/LoggerRuleNode.java @@ -0,0 +1,49 @@ +package io.github.quickmsg.rule.node; + +import io.github.quickmsg.common.message.HeapMqttMessage; +import io.github.quickmsg.common.utils.JacksonUtil; +import io.github.quickmsg.rule.RuleNode; +import lombok.extern.slf4j.Slf4j; +import reactor.util.context.ContextView; + +import java.util.Optional; + +/** + * @author luxurong + */ +@Slf4j +public class LoggerRuleNode implements RuleNode { + + private final static String DEFAULT_LOG_TEMPLATE = "logger rule accept msg : %s"; + + private RuleNode ruleNode; + + private final String script; + + public LoggerRuleNode(String script) { + this.script = script; + } + + + @Override + public RuleNode getNextRuleNode() { + return this.ruleNode; + } + + @Override + public void execute(ContextView contextView) { + HeapMqttMessage heapMqttMessage = contextView.get(HeapMqttMessage.class); + String logInfo = Optional.ofNullable(script) + .map(sc -> + String.valueOf(triggerScript(script, context -> heapMqttMessage.getKeyMap().forEach(context::set))) + ).orElseGet(() -> String.format(DEFAULT_LOG_TEMPLATE, JacksonUtil.map2Json(heapMqttMessage.getKeyMap()))); + log.info(logInfo); + executeNext(contextView); + } + + + @Override + public void setNextRuleNode(RuleNode ruleNode) { + this.ruleNode = ruleNode; + } +} diff --git a/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/node/PredicateRuleNode.java b/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/node/PredicateRuleNode.java new file mode 100644 index 0000000000000000000000000000000000000000..471d975da93f3b77542b360067b91513dab39090 --- /dev/null +++ b/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/node/PredicateRuleNode.java @@ -0,0 +1,42 @@ +package io.github.quickmsg.rule.node; + +import io.github.quickmsg.common.message.HeapMqttMessage; +import io.github.quickmsg.rule.RuleNode; +import reactor.util.context.ContextView; + +/** + * @author luxurong + */ +public class PredicateRuleNode implements RuleNode { + + private final String script; + + private RuleNode ruleNode; + + + public PredicateRuleNode(String script) { + this.script = script; + } + + @Override + public RuleNode getNextRuleNode() { + return this.ruleNode; + } + + + @Override + public void setNextRuleNode(RuleNode ruleNode) { + this.ruleNode = ruleNode; + } + + @Override + + public void execute(ContextView contextView) { + if ((Boolean) triggerScript(script, context -> { + HeapMqttMessage mqttMessage = contextView.get(HeapMqttMessage.class); + mqttMessage.getKeyMap().forEach(context::set); + })) { + executeNext(contextView); + } + } +} diff --git a/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/node/TopicRuleNode.java b/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/node/TopicRuleNode.java new file mode 100644 index 0000000000000000000000000000000000000000..5ae3de0957170a6c97557ceb50046c5f2cc51fe5 --- /dev/null +++ b/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/node/TopicRuleNode.java @@ -0,0 +1,69 @@ +package io.github.quickmsg.rule.node; + +import io.github.quickmsg.common.channel.MockMqttChannel; +import io.github.quickmsg.common.context.ReceiveContext; +import io.github.quickmsg.common.message.HeapMqttMessage; +import io.github.quickmsg.common.message.MqttMessageBuilder; +import io.github.quickmsg.common.message.SmqttMessage; +import io.github.quickmsg.common.protocol.ProtocolAdaptor; +import io.github.quickmsg.common.utils.JacksonUtil; +import io.github.quickmsg.rule.RuleNode; +import io.netty.buffer.PooledByteBufAllocator; +import io.netty.handler.codec.mqtt.MqttPublishMessage; +import io.netty.handler.codec.mqtt.MqttQoS; +import lombok.extern.slf4j.Slf4j; +import reactor.util.context.ContextView; + +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +/** + * @author luxurong + */ +@Slf4j +public class TopicRuleNode implements RuleNode { + + private final String topic; + + private RuleNode ruleNode; + + public TopicRuleNode(String topic) { + Objects.requireNonNull(topic); + this.topic = topic; + } + + @Override + public RuleNode getNextRuleNode() { + return this.ruleNode; + } + + + @Override + public void setNextRuleNode(RuleNode ruleNode) { + this.ruleNode = ruleNode; + } + + @Override + public void execute(ContextView contextView) { + ReceiveContext receiveContext = contextView.get(ReceiveContext.class); + HeapMqttMessage heapMqttMessage = contextView.get(HeapMqttMessage.class); + log.info("rule engine TopicRuleNode request {}", heapMqttMessage); + ProtocolAdaptor protocolAdaptor = receiveContext.getProtocolAdaptor(); + protocolAdaptor.chooseProtocol(MockMqttChannel.wrapClientIdentifier(heapMqttMessage.getClientIdentifier()), + new SmqttMessage<>(getMqttMessage(heapMqttMessage),heapMqttMessage.getTimestamp(),Boolean.TRUE), receiveContext); + executeNext(contextView); + } + + + private MqttPublishMessage getMqttMessage(HeapMqttMessage heapMqttMessage) { + return MqttMessageBuilder + .buildPub(false, + MqttQoS.valueOf(heapMqttMessage.getQos()), + 0, + this.topic, + PooledByteBufAllocator.DEFAULT.buffer().writeBytes(JacksonUtil.dynamicJson(heapMqttMessage.getMessage()).getBytes(StandardCharsets.UTF_8)), + heapMqttMessage.getProperties()); + } + + +} diff --git a/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/node/TransmitRuleNode.java b/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/node/TransmitRuleNode.java new file mode 100644 index 0000000000000000000000000000000000000000..5a0036d8c0b8e0e7e42045656573eeabd65ed07f --- /dev/null +++ b/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/node/TransmitRuleNode.java @@ -0,0 +1,62 @@ +package io.github.quickmsg.rule.node; + +import io.github.quickmsg.common.message.HeapMqttMessage; +import io.github.quickmsg.common.rule.source.Source; +import io.github.quickmsg.common.rule.source.SourceBean; +import io.github.quickmsg.common.utils.JacksonUtil; +import io.github.quickmsg.rule.RuleNode; +import io.github.quickmsg.rule.source.SourceManager; +import lombok.extern.slf4j.Slf4j; +import reactor.util.context.ContextView; + +import java.util.Map; + +/** + * 转发节点 + * + * @author luxurong + */ +@Slf4j +public class TransmitRuleNode implements RuleNode { + + private final Source source; + + private final String script; + + private RuleNode ruleNode; + + + public TransmitRuleNode(Source source, String script) { + this.source = source; + this.script = script; + } + + @Override + public void execute(ContextView contextView) { + HeapMqttMessage heapMqttMessage = contextView.get(HeapMqttMessage.class); + Object param; + if (script != null) { + param = triggerScript(script, context -> heapMqttMessage.getKeyMap().forEach(context::set)); + } else { + param = heapMqttMessage.getKeyMap(); + } + SourceBean sourceBean = SourceManager.getSourceBean(source); + if (sourceBean != null) { + sourceBean.transmit(param); + executeNext(contextView); + + } + } + + @Override + public RuleNode getNextRuleNode() { + return this.ruleNode; + } + + + @Override + public void setNextRuleNode(RuleNode ruleNode) { + this.ruleNode = ruleNode; + } + +} diff --git a/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/source/SourceFactory.java b/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/source/SourceFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..b9d79a1e021ad3c40304e2b3eb8eb395ed8cb38b --- /dev/null +++ b/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/source/SourceFactory.java @@ -0,0 +1,12 @@ +package io.github.quickmsg.rule.source; + +import io.github.quickmsg.common.rule.source.Source; + +/** + * @author luxurong + */ +public interface SourceFactory { + + SourceLoader instance(Source source); + +} diff --git a/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/source/SourceLoader.java b/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/source/SourceLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..77c660f03d61314a14e6d9426da0b513c2f67eba --- /dev/null +++ b/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/source/SourceLoader.java @@ -0,0 +1,18 @@ +package io.github.quickmsg.rule.source; + +import io.github.quickmsg.common.rule.source.Source; + +/** + * @author luxurong + */ +public class SourceLoader { + + private final Source source; + + public SourceLoader(Source source) { + this.source = source; + } + + + +} diff --git a/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/source/SourceManager.java b/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/source/SourceManager.java new file mode 100644 index 0000000000000000000000000000000000000000..a1ba4fe34e5a022e92016d9f9de27e3f2c0cc182 --- /dev/null +++ b/smqtt-rule/smqtt-rule-engine/src/main/java/io/github/quickmsg/rule/source/SourceManager.java @@ -0,0 +1,31 @@ +package io.github.quickmsg.rule.source; + +import io.github.quickmsg.common.rule.source.Source; +import io.github.quickmsg.common.rule.source.SourceDefinition; +import io.github.quickmsg.common.rule.source.SourceBean; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author luxurong + */ +public class SourceManager { + + private static final Map CACHE_BEANS = new ConcurrentHashMap<>(); + + + public static SourceBean getSourceBean(Source source){ + return CACHE_BEANS.get(source); + } + + public static void loadSource(SourceDefinition sourceDefinition){ + SourceBean.SOURCE_BEAN_LIST.forEach(sourceBean -> { + if (sourceBean.support(sourceDefinition.getSource())) { + if (sourceBean.bootstrap(sourceDefinition.getSourceAttributes())) { + CACHE_BEANS.put(sourceDefinition.getSource(), sourceBean); + } + } + }); + } +} diff --git a/smqtt-rule/smqtt-rule-engine/src/main/resources/META-INF/services/io.github.quickmsg.common.rule.source.SourceBean b/smqtt-rule/smqtt-rule-engine/src/main/resources/META-INF/services/io.github.quickmsg.common.rule.source.SourceBean new file mode 100644 index 0000000000000000000000000000000000000000..4ffea9081da5608a72fa567f2fae6461c553dea1 --- /dev/null +++ b/smqtt-rule/smqtt-rule-engine/src/main/resources/META-INF/services/io.github.quickmsg.common.rule.source.SourceBean @@ -0,0 +1,6 @@ +io.github.quickmsg.source.mqtt.KafkaSourceBean +io.github.quickmsg.source.rocketmq.RocketmqSourceBean +io.github.quickmsg.source.rabbitmq.RabbitmqSourceBean +io.github.quickmsg.http.HttpSourceBean +io.github.quickmsg.source.db.DbSourceBean +io.github.quickmsg.source.mqtt.MqttSourceBean \ No newline at end of file diff --git a/smqtt-rule/smqtt-rule-source/pom.xml b/smqtt-rule/smqtt-rule-source/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..17ee4da0c735ddfe6a8432f58ef288f04f551cd8 --- /dev/null +++ b/smqtt-rule/smqtt-rule-source/pom.xml @@ -0,0 +1,42 @@ + + + + 4.0.0 + pom + + + smqtt-rule + io.github.quickmsg + 1.1.7 + + + smqtt-rule-source + smqtt-rule-source + + + smqtt-rule-source-kafka + smqtt-rule-source-http + smqtt-rule-source-rocketmq + smqtt-rule-source-rabbitmq + smqtt-rule-source-db + smqtt-rule-source-mqtt + + + + + junit + junit + 4.11 + test + + + io.github.quickmsg + smqtt-common + 1.1.7 + provided + + + + + diff --git a/smqtt-rule/smqtt-rule-source/smqtt-rule-source-db/pom.xml b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-db/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..42b2f14f17305b3f6045db8ad61a8e40c0563d01 --- /dev/null +++ b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-db/pom.xml @@ -0,0 +1,51 @@ + + + + smqtt-rule-source + io.github.quickmsg + 1.1.7 + + 4.0.0 + + io.github.quickmsg + smqtt-rule-source-db + 1.1.7 + + + 3.14.11 + + + + + org.jooq + jooq + ${jooq.version} + + + + org.jooq + jooq-meta + ${jooq.version} + + + + org.jooq + jooq-codegen + ${jooq.version} + + + + com.zaxxer + HikariCP + 4.0.3 + + + + mysql + mysql-connector-java + + + + \ No newline at end of file diff --git a/smqtt-rule/smqtt-rule-source/smqtt-rule-source-db/src/main/java/io/github/quickmsg/source/db/DbSourceBean.java b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-db/src/main/java/io/github/quickmsg/source/db/DbSourceBean.java new file mode 100644 index 0000000000000000000000000000000000000000..dd2dd29844cd07a1596012499eca31265bfc0a9e --- /dev/null +++ b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-db/src/main/java/io/github/quickmsg/source/db/DbSourceBean.java @@ -0,0 +1,75 @@ +package io.github.quickmsg.source.db; + +import io.github.quickmsg.common.rule.source.Source; +import io.github.quickmsg.common.rule.source.SourceBean; +import io.github.quickmsg.source.db.config.HikariCPConnectionProvider; +import lombok.extern.slf4j.Slf4j; +import org.jooq.DSLContext; +import org.jooq.impl.DSL; + +import java.sql.Connection; +import java.util.Map; +import java.util.Properties; + + +/** + * 数据源 + * + * @author zhaopeng + */ +@Slf4j +public class DbSourceBean implements SourceBean { + + + @Override + public Boolean support(Source source) { + return source == Source.DATA_BASE; + } + + + /** + * 初始化数据库连接 + * + * @param sourceParam 参数 + * @return Boolean + */ + @Override + public Boolean bootstrap(Map sourceParam) { + Properties properties = new Properties(); + for (String key : sourceParam.keySet()) { + properties.put(key.replaceAll("-", "."), sourceParam.get(key).toString()); + } + + try { + HikariCPConnectionProvider + .singleTon() + .init(properties); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 转发数据 + * + * @param object 对象 + */ + @Override + public void transmit(Object object) { + try (Connection connection = HikariCPConnectionProvider.singleTon().getConnection()) { + DSLContext dslContext = DSL.using(connection); + dslContext.execute(object.toString()); + } catch (Exception e) { + log.error("execute sql error", e); + } + } + + + @Override + public void close() { + HikariCPConnectionProvider.singleTon().shutdown(); + } + +} diff --git a/smqtt-rule/smqtt-rule-source/smqtt-rule-source-db/src/main/java/io/github/quickmsg/source/db/config/ConnectionProvider.java b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-db/src/main/java/io/github/quickmsg/source/db/config/ConnectionProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..b6f9f65f0b0851342d6c69cf0ca018150d822a48 --- /dev/null +++ b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-db/src/main/java/io/github/quickmsg/source/db/config/ConnectionProvider.java @@ -0,0 +1,33 @@ +package io.github.quickmsg.source.db.config; + +import java.sql.Connection; +import java.util.Properties; + +/** + * @author luxurong + */ +public interface ConnectionProvider { + + + /** + * 初始化 + * + * @param properties 配置 + */ + void init(Properties properties); + + /** + * 获取链接 + * + * @return {@link Connection} + */ + Connection getConnection(); + + + /** + * 关闭链接 + */ + void shutdown(); + + +} diff --git a/smqtt-rule/smqtt-rule-source/smqtt-rule-source-db/src/main/java/io/github/quickmsg/source/db/config/HikariCPConnectionProvider.java b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-db/src/main/java/io/github/quickmsg/source/db/config/HikariCPConnectionProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..fb50f06506b02860c39919d38906bcfbba2c9b23 --- /dev/null +++ b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-db/src/main/java/io/github/quickmsg/source/db/config/HikariCPConnectionProvider.java @@ -0,0 +1,61 @@ +package io.github.quickmsg.source.db.config; + +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import lombok.extern.slf4j.Slf4j; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Properties; +import java.util.concurrent.atomic.AtomicInteger; + + +/** + * @author zhaopeng + */ +@Slf4j +public class HikariCPConnectionProvider implements ConnectionProvider { + + private HikariCPConnectionProvider() { + } + + private static HikariCPConnectionProvider connectionProvider = new HikariCPConnectionProvider(); + + public static HikariCPConnectionProvider singleTon() { + return connectionProvider; + } + + private HikariDataSource hikariDataSource; + + private AtomicInteger startUp = new AtomicInteger(0); + + @Override + public void init(Properties properties) { + if (startUp.compareAndSet(0, 1)) { + try { + HikariConfig config = new HikariConfig(properties); + this.hikariDataSource = new HikariDataSource(config); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + @Override + public Connection getConnection() { + try { + return hikariDataSource.getConnection(); + } catch (SQLException e) { + log.error("getConnection error", e); + return null; + } + } + + @Override + public void shutdown() { + if (hikariDataSource != null) { + hikariDataSource.close(); + } + } + +} \ No newline at end of file diff --git a/smqtt-rule/smqtt-rule-source/smqtt-rule-source-http/pom.xml b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-http/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..4ae4b3acee6442d17014de65773e2428596bae35 --- /dev/null +++ b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-http/pom.xml @@ -0,0 +1,29 @@ + + + + 4.0.0 + + io.github.quickmsg + smqtt-rule-source-http + 1.1.7 + + smqtt-rule-source-http + + https://github.com/quickmsg/smqtt + + + smqtt-rule-source + io.github.quickmsg + 1.1.7 + + + + + io.github.quickmsg + smqtt-common + 1.1.7 + provided + + + diff --git a/smqtt-rule/smqtt-rule-source/smqtt-rule-source-http/src/main/java/io/github/quickmsg/http/HttpParam.java b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-http/src/main/java/io/github/quickmsg/http/HttpParam.java new file mode 100644 index 0000000000000000000000000000000000000000..375e18aa8caefe1bc3618610b82eb8ee40b666c8 --- /dev/null +++ b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-http/src/main/java/io/github/quickmsg/http/HttpParam.java @@ -0,0 +1,20 @@ +package io.github.quickmsg.http; + +import lombok.Data; + +import java.util.List; +import java.util.Map; + +/** + * @author luxurong + */ +@Data +public class HttpParam { + + private String url; + + private Map additions; + + private Map headers; + +} diff --git a/smqtt-rule/smqtt-rule-source/smqtt-rule-source-http/src/main/java/io/github/quickmsg/http/HttpSourceBean.java b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-http/src/main/java/io/github/quickmsg/http/HttpSourceBean.java new file mode 100644 index 0000000000000000000000000000000000000000..fb33643ad2d3cac72a56471594491dc9d4548d93 --- /dev/null +++ b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-http/src/main/java/io/github/quickmsg/http/HttpSourceBean.java @@ -0,0 +1,62 @@ +package io.github.quickmsg.http; + +import io.github.quickmsg.common.rule.source.Source; +import io.github.quickmsg.common.rule.source.SourceBean; +import io.github.quickmsg.common.utils.JacksonUtil; +import io.netty.buffer.PooledByteBufAllocator; +import io.netty.handler.codec.http.HttpHeaderNames; +import lombok.extern.slf4j.Slf4j; +import reactor.core.publisher.Mono; +import reactor.netty.http.client.HttpClient; + +import java.util.Map; + +/** + * @author luxurong + */ +@Slf4j +public class HttpSourceBean implements SourceBean { + + private HttpParam httpParam; + + private HttpClient httpClient; + + + @Override + public Boolean support(Source source) { + return source == Source.HTTP; + } + + @Override + @SuppressWarnings("all") + public Boolean bootstrap(Map sourceParam) { + httpParam = new HttpParam(); + httpParam.setUrl(String.valueOf(sourceParam.get("url"))); + httpParam.setHeaders((Map) sourceParam.get("headers")); + httpParam.setAdditions((Map) sourceParam.get("additions")); + httpClient = HttpClient.create().headers(heads -> { + httpParam.getHeaders().forEach(heads::add); + heads.add(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=utf-8"); + }); + return true; + } + + + @Override + public void transmit(Object object) { + httpClient + .post() + .uri(httpParam.getUrl()) + .send(Mono.just(PooledByteBufAllocator.DEFAULT.directBuffer().writeBytes(JacksonUtil.dynamicJson(object).getBytes()))) + .response() + .log() + .subscribe(); + } + + @Override + public void close() { + httpClient.configuration().connectionProvider().dispose(); + } + + +} diff --git a/smqtt-rule/smqtt-rule-source/smqtt-rule-source-kafka/pom.xml b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-kafka/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..998640c809e2a72af9254df97dde53f753fcdfae --- /dev/null +++ b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-kafka/pom.xml @@ -0,0 +1,26 @@ + + + + smqtt-rule-source + io.github.quickmsg + 1.1.7 + + 4.0.0 + + smqtt-rule-source-kafka + 1.1.7 + + https://github.com/quickmsg/smqtt + + + + + org.apache.kafka + kafka-clients + 2.8.0 + + + + \ No newline at end of file diff --git a/smqtt-rule/smqtt-rule-source/smqtt-rule-source-kafka/src/main/java/io/github/quickmsg/source/mqtt/KafkaSourceBean.java b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-kafka/src/main/java/io/github/quickmsg/source/mqtt/KafkaSourceBean.java new file mode 100644 index 0000000000000000000000000000000000000000..cddf70f7952b70f5c68dbcae19c27103b15fee75 --- /dev/null +++ b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-kafka/src/main/java/io/github/quickmsg/source/mqtt/KafkaSourceBean.java @@ -0,0 +1,77 @@ +package io.github.quickmsg.source.mqtt; + +import io.github.quickmsg.common.rule.source.Source; +import io.github.quickmsg.common.rule.source.SourceBean; +import io.github.quickmsg.common.utils.JacksonUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.clients.producer.ProducerRecord; + +import java.util.Map; +import java.util.Optional; +import java.util.Properties; + +/** + * kafka source bean + * + * @author zhaopeng + */ +@Slf4j +public class KafkaSourceBean implements SourceBean { + + private KafkaProducer producer; + + private String topic; + + @Override + public Boolean support(Source source) { + return source == Source.KAFKA; + } + + + /** + * 初始化kafka + * + * @param sourceParam 参数 + * @return Boolean + */ + @Override + public Boolean bootstrap(Map sourceParam) { + try { + // 配置信息 + Properties props = new Properties(); + for (String key : sourceParam.keySet()) { + props.put(key.replaceAll("-", "."), sourceParam.get(key)); + } + topic = Optional.ofNullable(sourceParam.get("topic")).map(String::valueOf).orElse("smqtt"); + // 创建生产者实例 + producer = new KafkaProducer<>(props); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 转发数据 + * + * @param object 对象 + */ + @Override + public void transmit(Object object) { + if (producer != null) { + ProducerRecord record = new ProducerRecord<>(topic, JacksonUtil.dynamicJson(object)); + producer.send(record); + } + } + + + @Override + public void close() { + if (producer != null) { + producer.close(); + } + } + +} diff --git a/smqtt-rule/smqtt-rule-source/smqtt-rule-source-mqtt/pom.xml b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-mqtt/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..bd168d84dbef75538c127edf4cb9fee2ba7e71f7 --- /dev/null +++ b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-mqtt/pom.xml @@ -0,0 +1,47 @@ + + + + smqtt-rule-source + io.github.quickmsg + 1.1.7 + + 4.0.0 + + io.github.quickmsg + smqtt-rule-source-mqtt + 1.1.7 + + + + com.hivemq + hivemq-mqtt-client + 1.2.2 + + + netty-buffer + io.netty + + + netty-codec + io.netty + + + netty-common + io.netty + + + netty-handler + io.netty + + + netty-transport + io.netty + + + + + + + \ No newline at end of file diff --git a/smqtt-rule/smqtt-rule-source/smqtt-rule-source-mqtt/src/main/java/io/github/quickmsg/source/mqtt/MqttSourceBean.java b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-mqtt/src/main/java/io/github/quickmsg/source/mqtt/MqttSourceBean.java new file mode 100644 index 0000000000000000000000000000000000000000..9bd4268ea5fa06da15342b0274b947a8510fe558 --- /dev/null +++ b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-mqtt/src/main/java/io/github/quickmsg/source/mqtt/MqttSourceBean.java @@ -0,0 +1,158 @@ +package io.github.quickmsg.source.mqtt; + +import com.hivemq.client.mqtt.MqttClient; +import com.hivemq.client.mqtt.datatypes.MqttQos; +import com.hivemq.client.mqtt.mqtt3.Mqtt3AsyncClient; +import com.hivemq.client.mqtt.mqtt3.lifecycle.Mqtt3ClientDisconnectedContext; +import com.hivemq.client.mqtt.mqtt3.message.connect.Mqtt3ConnectBuilder; +import com.hivemq.client.mqtt.mqtt3.message.connect.connack.Mqtt3ConnAck; +import io.github.quickmsg.common.rule.source.Source; +import io.github.quickmsg.common.rule.source.SourceBean; +import io.github.quickmsg.common.utils.JacksonUtil; +import io.netty.util.internal.StringUtil; +import lombok.extern.slf4j.Slf4j; + +import java.time.LocalTime; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + + +/** + * mqtt + * + * @author zhaopeng + */ +@Slf4j +public class MqttSourceBean implements SourceBean { + + private Mqtt3AsyncClient client; + + @Override + public Boolean support(Source source) { + return source == Source.MQTT; + } + + /** + * 初始化 + * + * @param sourceParam 参数 + * @return boolean + */ + @Override + public Boolean bootstrap(Map sourceParam) { + try { + String clientId = sourceParam.get("clientId").toString(); + String host = sourceParam.get("host").toString(); + Integer port = Integer.parseInt(sourceParam.get("port").toString()); + + client = MqttClient.builder() + .useMqttVersion3() + .identifier(clientId) + .serverHost(host) + .serverPort(port) + .addDisconnectedListener(context -> { + context.getReconnector() + .reconnect(true) // always reconnect (includes calling disconnect) + .delay(2L * context.getReconnector().getAttempts(), TimeUnit.SECONDS); // linear scaling delay + }) + .addDisconnectedListener(context -> { + final Mqtt3ClientDisconnectedContext context3 = (Mqtt3ClientDisconnectedContext) context; + String userName = sourceParam.get("userName").toString(); + String passWord = sourceParam.get("passWord").toString(); + if (!StringUtil.isNullOrEmpty(userName) && !StringUtil.isNullOrEmpty(passWord)) { + context3.getReconnector() + .connectWith() + .simpleAuth() + .username(userName) + .password(passWord.getBytes()) + .applySimpleAuth() + .applyConnect(); + } + }) + .addConnectedListener(context -> log.info("mqtt client connected " + LocalTime.now())) + .addDisconnectedListener(context -> log.error("mqtt client disconnected " + LocalTime.now())) + .buildAsync(); + + Mqtt3ConnectBuilder.Send> completableFutureSend = client.connectWith(); + + if (sourceParam.get("userName") != null && sourceParam.get("passWord") != null) { + String userName = sourceParam.get("userName").toString(); + String passWord = sourceParam.get("passWord").toString(); + if (!StringUtil.isNullOrEmpty(userName) && !StringUtil.isNullOrEmpty(passWord)) { + completableFutureSend.simpleAuth() + .username(userName) + .password(passWord.getBytes()) + .applySimpleAuth(); + } + } + + completableFutureSend + .send() + .whenComplete((connAck, throwable) -> { + if (throwable != null) { + // handle failure + log.error("mqtt client connect error", throwable); + } else { + // setup subscribes or start publishing + } + }); + + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 转发数据 + * + * @param param 对象 + */ + @Override + public void transmit(Object param) { + Map object = (Map)param; + String topic = (String) object.get("topic"); + Object msg = object.get("msg"); + String bytes = msg instanceof Map ? JacksonUtil.map2Json((Map) msg) : msg.toString(); + Boolean retain = (Boolean) object.get("retain"); + Integer qos = Optional.ofNullable((Integer) object.get("qos")).orElse(0); + client.publishWith() + .topic(topic) + .payload(bytes.getBytes()) + .qos(Objects.requireNonNull(MqttQos.fromCode(qos))) + .retain(retain) + .send() + .whenComplete((publish, throwable) -> { + if (throwable != null) { + // handle failure to publish + log.error("mqtt client publish error", throwable); + } + }); + } + + + @Override + public void close() { + if (client != null) { + client.disconnect(); + } + } + + private static CompletableFuture getOAuthToken() { + return CompletableFuture.supplyAsync(() -> { + try { + for (int i = 0; i < 5; i++) { + TimeUnit.SECONDS.sleep(1); + System.out.println("OAuth server is slow to respond ..."); + } + } catch (final InterruptedException e) { + e.printStackTrace(); + } + return new byte[]{1, 2, 3}; + }); + } +} diff --git a/smqtt-rule/smqtt-rule-source/smqtt-rule-source-rabbitmq/pom.xml b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-rabbitmq/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..baef3c49154053ce7a4bcb76b61609e4c8b59bd2 --- /dev/null +++ b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-rabbitmq/pom.xml @@ -0,0 +1,24 @@ + + + + smqtt-rule-source + io.github.quickmsg + 1.1.7 + + 4.0.0 + + io.github.quickmsg + smqtt-rule-source-rabbitmq + 1.1.7 + + + + com.rabbitmq + amqp-client + 3.6.5 + + + + \ No newline at end of file diff --git a/smqtt-rule/smqtt-rule-source/smqtt-rule-source-rabbitmq/src/main/java/io/github/quickmsg/source/rabbitmq/RabbitmqSourceBean.java b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-rabbitmq/src/main/java/io/github/quickmsg/source/rabbitmq/RabbitmqSourceBean.java new file mode 100644 index 0000000000000000000000000000000000000000..5796ca9f792f67d26d22c5d2d8f695edef353f0c --- /dev/null +++ b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-rabbitmq/src/main/java/io/github/quickmsg/source/rabbitmq/RabbitmqSourceBean.java @@ -0,0 +1,121 @@ +package io.github.quickmsg.source.rabbitmq; + +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import io.github.quickmsg.common.rule.source.Source; +import io.github.quickmsg.common.rule.source.SourceBean; +import io.github.quickmsg.common.utils.JacksonUtil; +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; +import java.util.Map; + +/** + * rabbitmq source + * + * @author leafseelight + */ +@Slf4j +public class RabbitmqSourceBean implements SourceBean { + + /** + * 连接对象 + */ + private Connection connection = null; + /** + * 缓存消息队列 + */ + private Map channelHashMap = new HashMap<>(); + + /** + * 队列名称 + */ + private String queueName; + + @Override + public Boolean support(Source source) { + return source == Source.RABBIT_MQ; + } + + /** + * 初始化rocketmq + * + * @param sourceParam 参数 + * @return Boolean + */ + @Override + public Boolean bootstrap(Map sourceParam) { + try { + //创建连接工厂 + ConnectionFactory factory = new ConnectionFactory(); + factory.setAutomaticRecoveryEnabled(true); + factory.setTopologyRecoveryEnabled(true); + factory.setNetworkRecoveryInterval(3000); + //设置RabbitMQ相关信息 + factory.setHost(sourceParam.get("host").toString()); + factory.setPort(Integer.parseInt(sourceParam.get("port").toString())); + factory.setUsername(sourceParam.get("userName").toString()); + factory.setPassword(sourceParam.get("passWord").toString()); + //创建一个新的连接 + connection = factory.newConnection(); + queueName = sourceParam.get("queueName").toString(); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 转发数据 + * @param object 对象 + */ + @Override + public void transmit(Object object) { + corePublish(queueName, JacksonUtil.dynamicJson(object)); + } + + /** + * 核心执行内容 + * + * @param queueName 队列名 + * @param json body + */ + public void corePublish(String queueName, String json) { + try { + Channel cacheChannel = channelHashMap.get(queueName); + Channel channel = null; + if (cacheChannel == null) { + //创建一个通道 + channel = connection.createChannel(); + channelHashMap.put(queueName, channel); + } else { + channel = cacheChannel; + } + // 声明一个队列 + channel.queueDeclare(queueName, false, false, false, null); + // 发送消息到队列中 + channel.basicPublish("", queueName, null, json.getBytes("UTF-8")); + }catch (Exception e){ + log.error("RabbitMq转发异常",e); + } + } + + + @Override + public void close() { + try { + //关闭通道和连接 + for (Map.Entry stringChannelEntry : channelHashMap.entrySet()) { + Channel channel = stringChannelEntry.getValue(); + channel.close(); + } + connection.close(); + } catch (Exception e) { + log.error("#Close.Exception: {}", e.getMessage()); + } + } + + +} diff --git a/smqtt-rule/smqtt-rule-source/smqtt-rule-source-rocketmq/pom.xml b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-rocketmq/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..1122356b9af7560d281ae750408e64182d382d8a --- /dev/null +++ b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-rocketmq/pom.xml @@ -0,0 +1,30 @@ + + + + smqtt-rule-source + io.github.quickmsg + 1.1.7 + + 4.0.0 + + io.github.quickmsg + smqtt-rule-source-rocketmq + 1.1.7 + + + + org.apache.rocketmq + rocketmq-client + 4.9.1 + + + netty-all + io.netty + + + + + + \ No newline at end of file diff --git a/smqtt-rule/smqtt-rule-source/smqtt-rule-source-rocketmq/src/main/java/io/github/quickmsg/source/rocketmq/RocketmqSourceBean.java b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-rocketmq/src/main/java/io/github/quickmsg/source/rocketmq/RocketmqSourceBean.java new file mode 100644 index 0000000000000000000000000000000000000000..c58dc31bf164ad351400628b1359601006de7d3e --- /dev/null +++ b/smqtt-rule/smqtt-rule-source/smqtt-rule-source-rocketmq/src/main/java/io/github/quickmsg/source/rocketmq/RocketmqSourceBean.java @@ -0,0 +1,90 @@ +package io.github.quickmsg.source.rocketmq; + +import io.github.quickmsg.common.rule.source.Source; +import io.github.quickmsg.common.rule.source.SourceBean; +import io.github.quickmsg.common.utils.JacksonUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.common.message.Message; + +import java.util.Map; +import java.util.Optional; + +/** + * rocketmq source + * + * @author zhaopeng + */ +@Slf4j +public class RocketmqSourceBean implements SourceBean { + + /** + * 生产者 + */ + private DefaultMQProducer producer; + + private String topic; + + private String tags; + + @Override + public Boolean support(Source source) { + return source == Source.ROCKET_MQ; + } + + + /** + * 初始化rocketmq + * + * @param sourceParam 参数 + * @return Boolean + */ + @Override + public Boolean bootstrap(Map sourceParam) { + try { + topic = Optional.ofNullable(sourceParam.get("topic")).map(String::valueOf).orElse("smqtt"); + tags = sourceParam.get("tags").toString(); + producer = new DefaultMQProducer(sourceParam.get("producerGroup").toString()); + // 设置NameServer地址 + producer.setNamesrvAddr(sourceParam.get("namesrvAddr").toString()); + // 设置生产者实例名称 + producer.setInstanceName(sourceParam.get("instanceName").toString()); + // 启动生产者 + producer.start(); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 转发数据 + * + * @param object 对象 + */ + @Override + public void transmit(Object object) { + String json = JacksonUtil.dynamicJson(object); + if (producer != null) { + Message message = new Message(topic, tags, json.getBytes()); + //发送消息v + try { + SendResult sendResult = producer.send(message); + log.info("rocketMq send status {}", sendResult.getSendStatus()); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + + @Override + public void close() { + if (producer != null) { + producer.shutdown(); + } + } + +} diff --git a/smqtt-spring-boot-starter/pom.xml b/smqtt-spring-boot-starter/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..ef8d771b17fbd0c497f4c20ecd17b91c7291e1e6 --- /dev/null +++ b/smqtt-spring-boot-starter/pom.xml @@ -0,0 +1,62 @@ + + + + 4.0.0 + + + smqtt + io.github.quickmsg + 1.1.7 + + + smqtt-spring-boot-starter + + smqtt-spring-boot-starter + + + UTF-8 + + + + + org.springframework.boot + spring-boot-actuator-autoconfigure + 2.5.4 + provided + + + org.springframework.boot + spring-boot-configuration-processor + 2.5.4 + provided + + + io.github.quickmsg + smqtt-core + 1.1.7 + + + smqtt-registry-scube + io.github.quickmsg + 1.1.7 + + + smqtt-ui + io.github.quickmsg + 1.1.7 + + + io.projectreactor.netty + reactor-netty + 1.0.10 + + + io.projectreactor + reactor-core + 3.4.9 + + + + + diff --git a/smqtt-spring-boot-starter/src/main/java/io/github/quickmsg/starter/AutoMqttConfiguration.java b/smqtt-spring-boot-starter/src/main/java/io/github/quickmsg/starter/AutoMqttConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..a04bde8900e1aec3453db5fa86e0cff66586935f --- /dev/null +++ b/smqtt-spring-boot-starter/src/main/java/io/github/quickmsg/starter/AutoMqttConfiguration.java @@ -0,0 +1,70 @@ +package io.github.quickmsg.starter; + +import ch.qos.logback.classic.Level; +import io.github.quickmsg.common.config.ConnectModel; +import io.github.quickmsg.common.utils.IPUtils; +import io.github.quickmsg.core.Bootstrap; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author luxurong + */ +@Slf4j +@Configuration +@EnableConfigurationProperties(SpringBootstrapConfig.class) +public class AutoMqttConfiguration { + + + /** + * 配置异常切面 + * + * @param springBootstrapConfig {@link SpringBootstrapConfig} + * @return {@link Bootstrap} + */ + @Bean + public Bootstrap startServer(@Autowired SpringBootstrapConfig springBootstrapConfig) { + check(springBootstrapConfig); + return Bootstrap.builder() + .rootLevel(Level.toLevel(springBootstrapConfig.getLogLevel())) + .tcpConfig(springBootstrapConfig.getTcp()) + .httpConfig(springBootstrapConfig.getHttp()) + .websocketConfig(springBootstrapConfig.getWs()) + .clusterConfig(springBootstrapConfig.getCluster()) + .redisConfig(springBootstrapConfig.getRedis()) + .databaseConfig(springBootstrapConfig.getDb()) + .ruleChainDefinitions(springBootstrapConfig.getRules()) + .sourceDefinitions(springBootstrapConfig.getSources()) + .meterConfig(springBootstrapConfig.getMeter()) + .aclConfig(springBootstrapConfig.getAcl()) + .authConfig(springBootstrapConfig.getAuth()) + .meterConfig(springBootstrapConfig.getMeter()) + .build() + .start() + .doOnSuccess(this::printUiUrl).block(); + } + + private void check(SpringBootstrapConfig springBootstrapConfig) { + if (springBootstrapConfig.getTcp().getConnectModel() == null) { + springBootstrapConfig.getTcp().setConnectModel(ConnectModel.UNIQUE); + } + } + + public void printUiUrl(Bootstrap bootstrap) { + String start = "\n-------------------------------------------------------------\n\t"; + start += String.format("Smqtt mqtt connect url %s:%s \n\t", IPUtils.getIP(), bootstrap.getTcpConfig().getPort()); + if (bootstrap.getHttpConfig() != null && bootstrap.getHttpConfig().isEnable()) { + Integer port = 60000; + start += String.format("Smqtt-Admin UI is running AccessURLs:\n\t" + + "Http Local url: http://localhost:%s/smqtt/admin" + "\n\t" + + "Http External url: http://%s:%s/smqtt/admin" + "\n" + + "-------------------------------------------------------------", port, IPUtils.getIP(), port); + } + log.info(start); + } + + +} diff --git a/smqtt-spring-boot-starter/src/main/java/io/github/quickmsg/starter/EnableMqttServer.java b/smqtt-spring-boot-starter/src/main/java/io/github/quickmsg/starter/EnableMqttServer.java new file mode 100644 index 0000000000000000000000000000000000000000..d6c8da779cadb6a88e5ab9a94e04a314576b5913 --- /dev/null +++ b/smqtt-spring-boot-starter/src/main/java/io/github/quickmsg/starter/EnableMqttServer.java @@ -0,0 +1,20 @@ +package io.github.quickmsg.starter; + +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.Import; + +import java.lang.annotation.*; + +/** + * @author luxurong + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Import(AutoMqttConfiguration.class) +@Documented +@EnableAutoConfiguration +public @interface EnableMqttServer { + + + +} diff --git a/smqtt-spring-boot-starter/src/main/java/io/github/quickmsg/starter/SpringBootstrapConfig.java b/smqtt-spring-boot-starter/src/main/java/io/github/quickmsg/starter/SpringBootstrapConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..623ed9638039027d02d1ae843c2f3bcd9ffbfe62 --- /dev/null +++ b/smqtt-spring-boot-starter/src/main/java/io/github/quickmsg/starter/SpringBootstrapConfig.java @@ -0,0 +1,97 @@ +package io.github.quickmsg.starter; + +import ch.qos.logback.classic.Level; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.github.quickmsg.common.config.AclConfig; +import io.github.quickmsg.common.config.AuthConfig; +import io.github.quickmsg.common.config.BootstrapConfig; +import io.github.quickmsg.common.rule.RuleChainDefinition; +import io.github.quickmsg.common.rule.source.SourceDefinition; +import io.github.quickmsg.core.Bootstrap; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +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.List; + +/** + * @author luxurong + */ + +@Configuration +@ConfigurationProperties(prefix = "smqtt") +@Getter +@Setter +@ToString +@EnableAutoConfiguration +@Component +public class SpringBootstrapConfig { + + /** + * sfl4j日志级别 + * + * @see Level + */ + private String logLevel; + + /** + * tcp配置 + */ + private BootstrapConfig.TcpConfig tcp; + + /** + * http配置 + */ + private BootstrapConfig.HttpConfig http; + + /** + * websocket配置 + */ + private BootstrapConfig.WebsocketConfig ws; + + /** + * 集群配置配置 + */ + private BootstrapConfig.ClusterConfig cluster; + + /** + * meter配置 + */ + private BootstrapConfig.MeterConfig meter; + + + /** + * 数据库配置 + */ + private BootstrapConfig.DatabaseConfig db; + /** + * redis配置 + */ + private BootstrapConfig.RedisConfig redis; + /** + * 规则定义 + */ + private List rules; + + /** + * 规则定义 + */ + private List sources; + + /** + * acl + */ + private AclConfig acl; + + /** + * auth + */ + private AuthConfig auth; + + +} diff --git a/smqtt-ui/mvn b/smqtt-ui/mvn new file mode 100644 index 0000000000000000000000000000000000000000..0d265559e5443f9bcd1f2b4986694f553b435d34 --- /dev/null +++ b/smqtt-ui/mvn @@ -0,0 +1 @@ +ֹ(Y/N)? ֹ(Y/N)? ֹ(Y/N)? ֹ(Y/N)? ֹ(Y/N)? \ No newline at end of file diff --git a/smqtt-ui/package.json b/smqtt-ui/package.json index 2ec8c6fa3452cbf73b3265ea095077d72b3f3cbe..2b0ae7ef9594cd20efb6fdefa68e9b94d06fd188 100644 --- a/smqtt-ui/package.json +++ b/smqtt-ui/package.json @@ -18,10 +18,10 @@ "enquire.js": "^2.1.6", "highlight.js": "^10.2.1", "js-cookie": "^2.2.1", + "lodash.clonedeep": "^4.5.0", "mockjs": "^1.1.0", "moment": "^2.29.1", "nprogress": "^0.2.0", - "viser-vue": "^2.4.8", "vue": "^2.6.11", "vue-i18n": "^8.18.2", "vue-router": "^3.3.4", @@ -33,7 +33,6 @@ "@vue/cli-plugin-babel": "^4.4.0", "@vue/cli-plugin-eslint": "^4.4.0", "@vue/cli-service": "^4.4.0", - "@vuepress/plugin-back-to-top": "^1.5.2", "babel-eslint": "^10.1.0", "babel-plugin-transform-remove-console": "^6.9.4", "babel-polyfill": "^6.26.0", @@ -42,12 +41,10 @@ "eslint": "^6.7.2", "eslint-plugin-vue": "^6.2.2", "fast-deep-equal": "^3.1.3", - "gh-pages": "^3.1.0", "less-loader": "^6.1.1", "style-resources-loader": "^1.3.2", "vue-cli-plugin-style-resources-loader": "^0.1.4", "vue-template-compiler": "^2.6.11", - "vuepress": "^1.5.2", "webpack-theme-color-replacer": "1.3.18", "whatwg-fetch": "^3.0.0" }, diff --git a/smqtt-ui/pom.xml b/smqtt-ui/pom.xml index fd06bef02854fb8ea78fd10673c5613a36e45b77..45ba7225ee4e816b38decab08f9cf0dce1a1c323 100644 --- a/smqtt-ui/pom.xml +++ b/smqtt-ui/pom.xml @@ -5,7 +5,7 @@ smqtt io.github.quickmsg - 1.0.5 + 1.1.7 4.0.0 smqtt-ui diff --git a/smqtt-ui/public/favicon.ico b/smqtt-ui/public/favicon.ico index 47bf70b9def4bdda7fd3cb9fdbba9e794c2bfb7f..bd1a5761c470114fa41b4e397e9942a7413156fb 100644 Binary files a/smqtt-ui/public/favicon.ico and b/smqtt-ui/public/favicon.ico differ diff --git a/smqtt-ui/src/assets/img/cluster.png b/smqtt-ui/src/assets/img/cluster.png new file mode 100644 index 0000000000000000000000000000000000000000..889e59c20fc11d12d12ffff74c3f27cfb30e3145 Binary files /dev/null and b/smqtt-ui/src/assets/img/cluster.png differ diff --git a/smqtt-ui/src/assets/img/cpu.png b/smqtt-ui/src/assets/img/cpu.png new file mode 100644 index 0000000000000000000000000000000000000000..1d2c56c175268d76db2eeb0afc15fdaa25978601 Binary files /dev/null and b/smqtt-ui/src/assets/img/cpu.png differ diff --git a/smqtt-ui/src/assets/img/csys.png b/smqtt-ui/src/assets/img/csys.png new file mode 100644 index 0000000000000000000000000000000000000000..75a2a664caa00fdaaf665467b68fb8da3b796078 Binary files /dev/null and b/smqtt-ui/src/assets/img/csys.png differ diff --git a/smqtt-ui/src/assets/img/idle.png b/smqtt-ui/src/assets/img/idle.png new file mode 100644 index 0000000000000000000000000000000000000000..5a1e68c48c0ffc1704d2df8da084d21ac323182e Binary files /dev/null and b/smqtt-ui/src/assets/img/idle.png differ diff --git a/smqtt-ui/src/assets/img/iowait.png b/smqtt-ui/src/assets/img/iowait.png new file mode 100644 index 0000000000000000000000000000000000000000..e5529d4eafc7202427f76c3289bb8e2f0174a959 Binary files /dev/null and b/smqtt-ui/src/assets/img/iowait.png differ diff --git a/smqtt-ui/src/assets/img/jvm.png b/smqtt-ui/src/assets/img/jvm.png new file mode 100644 index 0000000000000000000000000000000000000000..b6d4ae849aa70e6428aad2c9bbe303bb00fa261f Binary files /dev/null and b/smqtt-ui/src/assets/img/jvm.png differ diff --git a/smqtt-ui/src/assets/img/logo.png b/smqtt-ui/src/assets/img/logo.png index 62bfe39aaad240dc0daa7dd5f48a80d1feedc002..c4279e8e86f8d02a483e0e068a371be453f67ef1 100644 Binary files a/smqtt-ui/src/assets/img/logo.png and b/smqtt-ui/src/assets/img/logo.png differ diff --git a/smqtt-ui/src/assets/img/path.png b/smqtt-ui/src/assets/img/path.png new file mode 100644 index 0000000000000000000000000000000000000000..80ccea2ce2e3d457dce1958f4620b55a1e92bdf3 Binary files /dev/null and b/smqtt-ui/src/assets/img/path.png differ diff --git a/smqtt-ui/src/assets/img/starttime.png b/smqtt-ui/src/assets/img/starttime.png new file mode 100644 index 0000000000000000000000000000000000000000..ee3472f382d06465aa4b58f847411b649a1ddcde Binary files /dev/null and b/smqtt-ui/src/assets/img/starttime.png differ diff --git a/smqtt-ui/src/assets/img/threadcount.png b/smqtt-ui/src/assets/img/threadcount.png new file mode 100644 index 0000000000000000000000000000000000000000..2b3163cd8c691f729cf613493882e4cafd6cea2f Binary files /dev/null and b/smqtt-ui/src/assets/img/threadcount.png differ diff --git a/smqtt-ui/src/assets/img/user.png b/smqtt-ui/src/assets/img/user.png new file mode 100644 index 0000000000000000000000000000000000000000..f5a803c8b4880e97399c9166fb0ef16b22c12984 Binary files /dev/null and b/smqtt-ui/src/assets/img/user.png differ diff --git a/smqtt-ui/src/assets/img/version.png b/smqtt-ui/src/assets/img/version.png new file mode 100644 index 0000000000000000000000000000000000000000..da12d8d11c8177f8617999b8e817ecf322dce4c5 Binary files /dev/null and b/smqtt-ui/src/assets/img/version.png differ diff --git a/smqtt-ui/src/components/card/ChartCard.vue b/smqtt-ui/src/components/card/ChartCard.vue deleted file mode 100644 index a47b8d74c592b4950f7fd00e3ddb988677e60874..0000000000000000000000000000000000000000 --- a/smqtt-ui/src/components/card/ChartCard.vue +++ /dev/null @@ -1,78 +0,0 @@ - - - - - diff --git a/smqtt-ui/src/components/chart/Bar.vue b/smqtt-ui/src/components/chart/Bar.vue deleted file mode 100644 index 7d2bf822095e0150cafccceca3bfd399364de5ef..0000000000000000000000000000000000000000 --- a/smqtt-ui/src/components/chart/Bar.vue +++ /dev/null @@ -1,59 +0,0 @@ - - - - - diff --git a/smqtt-ui/src/components/chart/MiniArea.vue b/smqtt-ui/src/components/chart/MiniArea.vue deleted file mode 100644 index 2e043a7166c22c7aff87e97ad49701086c1b3e41..0000000000000000000000000000000000000000 --- a/smqtt-ui/src/components/chart/MiniArea.vue +++ /dev/null @@ -1,67 +0,0 @@ - - - - - diff --git a/smqtt-ui/src/components/chart/MiniBar.vue b/smqtt-ui/src/components/chart/MiniBar.vue deleted file mode 100644 index 022af803b8c0cdd5c15fc532fb5dc174e69a37cf..0000000000000000000000000000000000000000 --- a/smqtt-ui/src/components/chart/MiniBar.vue +++ /dev/null @@ -1,59 +0,0 @@ - - - - - diff --git a/smqtt-ui/src/components/chart/MiniProgress.vue b/smqtt-ui/src/components/chart/MiniProgress.vue deleted file mode 100644 index b005e1ceeb5dbd538f03f1b75217be17ea87ed25..0000000000000000000000000000000000000000 --- a/smqtt-ui/src/components/chart/MiniProgress.vue +++ /dev/null @@ -1,56 +0,0 @@ - - - - - diff --git a/smqtt-ui/src/components/chart/Radar.vue b/smqtt-ui/src/components/chart/Radar.vue deleted file mode 100644 index 88393fb3f2c7ae53a4bd8a6852551e7831363bde..0000000000000000000000000000000000000000 --- a/smqtt-ui/src/components/chart/Radar.vue +++ /dev/null @@ -1,80 +0,0 @@ - - - - - diff --git a/smqtt-ui/src/components/chart/RankingList.vue b/smqtt-ui/src/components/chart/RankingList.vue deleted file mode 100644 index 81f6127ddcda6c2daf2cc38fd0052dc9d83f5aae..0000000000000000000000000000000000000000 --- a/smqtt-ui/src/components/chart/RankingList.vue +++ /dev/null @@ -1,59 +0,0 @@ - - - - - diff --git a/smqtt-ui/src/components/chart/Trend.vue b/smqtt-ui/src/components/chart/Trend.vue deleted file mode 100644 index 43ebdf5672cbf1f795b6684341273e11464c78d6..0000000000000000000000000000000000000000 --- a/smqtt-ui/src/components/chart/Trend.vue +++ /dev/null @@ -1,79 +0,0 @@ - - - - - diff --git a/smqtt-ui/src/components/chart/index.less b/smqtt-ui/src/components/chart/index.less deleted file mode 100644 index 1a755974a52a08cb044c53b0949a84ee839405a3..0000000000000000000000000000000000000000 --- a/smqtt-ui/src/components/chart/index.less +++ /dev/null @@ -1,9 +0,0 @@ -.mini-chart{ - position: relative; - width: 100%; - .chart-content{ - position: absolute; - bottom: -28px; - width: 100%; - } -} diff --git a/smqtt-ui/src/components/form/FormRow.vue b/smqtt-ui/src/components/form/FormRow.vue deleted file mode 100644 index def3f63081ce76968c3a3456e986a103afd8f643..0000000000000000000000000000000000000000 --- a/smqtt-ui/src/components/form/FormRow.vue +++ /dev/null @@ -1,51 +0,0 @@ - - - - - diff --git a/smqtt-ui/src/components/input/IInput.vue b/smqtt-ui/src/components/input/IInput.vue deleted file mode 100644 index 45d2f6d63a36fbf48cedaf706fa2eca19dc71bd0..0000000000000000000000000000000000000000 --- a/smqtt-ui/src/components/input/IInput.vue +++ /dev/null @@ -1,66 +0,0 @@ - - - diff --git a/smqtt-ui/src/components/menu/SideMenu.vue b/smqtt-ui/src/components/menu/SideMenu.vue index 5275ca88525823e1eb3f25ed45cc86cd6e181c73..cbb9c1e47a58a793c88fdc9767169e2ec7472df4 100644 --- a/smqtt-ui/src/components/menu/SideMenu.vue +++ b/smqtt-ui/src/components/menu/SideMenu.vue @@ -1,7 +1,7 @@