├── .gitignore
├── .mvn
└── wrapper
│ ├── MavenWrapperDownloader.java
│ └── maven-wrapper.properties
├── README.md
├── images
└── Mqtt-server-arch.jpg
├── lib
└── protobuf-java-3.1.0.jar
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ └── braincs
│ │ └── mqttprotobufserver
│ │ ├── MqttProtobufServerApplication.java
│ │ ├── controller
│ │ └── MQTTRestController.java
│ │ ├── mqtt
│ │ ├── IMQTTPublisher.java
│ │ ├── IMQTTSubscriber.java
│ │ ├── MQTTPublisher.java
│ │ ├── MQTTSubscriber.java
│ │ └── MqttConfig.java
│ │ └── utils
│ │ └── FileUtil.java
├── proto
│ └── mqtt.proto
└── resources
│ ├── application.properties
│ └── static
│ └── static
│ └── test.png
└── test
└── java
└── com
└── braincs
└── mqttprotobufserver
└── MqttProtobufServerApplicationTests.java
/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | /target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 |
5 | ### STS ###
6 | .apt_generated
7 | .classpath
8 | .factorypath
9 | .project
10 | .settings
11 | .springBeans
12 | .sts4-cache
13 |
14 | ### IntelliJ IDEA ###
15 | .idea
16 | *.iws
17 | *.iml
18 | *.ipr
19 |
20 | ### NetBeans ###
21 | /nbproject/private/
22 | /nbbuild/
23 | /dist/
24 | /nbdist/
25 | /.nb-gradle/
26 | /build/
27 |
28 | ### VS Code ###
29 | .vscode/
30 | ### JetBrains template
31 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
32 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
33 |
34 | # User-specific stuff
35 | .idea/**/workspace.xml
36 | .idea/**/tasks.xml
37 | .idea/**/usage.statistics.xml
38 | .idea/**/dictionaries
39 | .idea/**/shelf
40 |
41 | # Sensitive or high-churn files
42 | .idea/**/dataSources/
43 | .idea/**/dataSources.ids
44 | .idea/**/dataSources.local.xml
45 | .idea/**/sqlDataSources.xml
46 | .idea/**/dynamic.xml
47 | .idea/**/uiDesigner.xml
48 | .idea/**/dbnavigator.xml
49 |
50 | # Gradle
51 | .idea/**/gradle.xml
52 | .idea/**/libraries
53 |
54 | # Gradle and Maven with auto-import
55 | # When using Gradle or Maven with auto-import, you should exclude module files,
56 | # since they will be recreated, and may cause churn. Uncomment if using
57 | # auto-import.
58 | # .idea/modules.xml
59 | # .idea/*.iml
60 | # .idea/modules
61 |
62 | # CMake
63 | cmake-build-*/
64 |
65 | # Mongo Explorer plugin
66 | .idea/**/mongoSettings.xml
67 |
68 | # File-based project format
69 |
70 | # IntelliJ
71 | out/
72 |
73 | # mpeltonen/sbt-idea plugin
74 | .idea_modules/
75 |
76 | # JIRA plugin
77 | atlassian-ide-plugin.xml
78 |
79 | # Cursive Clojure plugin
80 | .idea/replstate.xml
81 |
82 | # Crashlytics plugin (for Android Studio and IntelliJ)
83 | com_crashlytics_export_strings.xml
84 | crashlytics.properties
85 | crashlytics-build.properties
86 | fabric.properties
87 |
88 | # Editor-based Rest Client
89 | .idea/httpRequests
90 | ### Maven template
91 | target/
92 | pom.xml.tag
93 | pom.xml.releaseBackup
94 | pom.xml.versionsBackup
95 | pom.xml.next
96 | release.properties
97 | dependency-reduced-pom.xml
98 | buildNumber.properties
99 | .mvn/timing.properties
100 | .mvn/wrapper/maven-wrapper.jar
101 | /tmp/
102 |
--------------------------------------------------------------------------------
/.mvn/wrapper/MavenWrapperDownloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | Licensed to the Apache Software Foundation (ASF) under one
3 | or more contributor license agreements. See the NOTICE file
4 | distributed with this work for additional information
5 | regarding copyright ownership. The ASF licenses this file
6 | to you under the Apache License, Version 2.0 (the
7 | "License"); you may not use this file except in compliance
8 | with the License. You may obtain a copy of the License at
9 |
10 | https://www.apache.org/licenses/LICENSE-2.0
11 |
12 | Unless required by applicable law or agreed to in writing,
13 | software distributed under the License is distributed on an
14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | KIND, either express or implied. See the License for the
16 | specific language governing permissions and limitations
17 | under the License.
18 | */
19 |
20 | import java.io.File;
21 | import java.io.FileInputStream;
22 | import java.io.FileOutputStream;
23 | import java.io.IOException;
24 | import java.net.URL;
25 | import java.nio.channels.Channels;
26 | import java.nio.channels.ReadableByteChannel;
27 | import java.util.Properties;
28 |
29 | public class MavenWrapperDownloader {
30 |
31 | /**
32 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
33 | */
34 | private static final String DEFAULT_DOWNLOAD_URL =
35 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar";
36 |
37 | /**
38 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
39 | * use instead of the default one.
40 | */
41 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
42 | ".mvn/wrapper/maven-wrapper.properties";
43 |
44 | /**
45 | * Path where the maven-wrapper.jar will be saved to.
46 | */
47 | private static final String MAVEN_WRAPPER_JAR_PATH =
48 | ".mvn/wrapper/maven-wrapper.jar";
49 |
50 | /**
51 | * Name of the property which should be used to override the default download url for the wrapper.
52 | */
53 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
54 |
55 | public static void main(String args[]) {
56 | System.out.println("- Downloader started");
57 | File baseDirectory = new File(args[0]);
58 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
59 |
60 | // If the maven-wrapper.properties exists, read it and check if it contains a custom
61 | // wrapperUrl parameter.
62 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
63 | String url = DEFAULT_DOWNLOAD_URL;
64 | if (mavenWrapperPropertyFile.exists()) {
65 | FileInputStream mavenWrapperPropertyFileInputStream = null;
66 | try {
67 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
68 | Properties mavenWrapperProperties = new Properties();
69 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
70 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
71 | } catch (IOException e) {
72 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
73 | } finally {
74 | try {
75 | if (mavenWrapperPropertyFileInputStream != null) {
76 | mavenWrapperPropertyFileInputStream.close();
77 | }
78 | } catch (IOException e) {
79 | // Ignore ...
80 | }
81 | }
82 | }
83 | System.out.println("- Downloading from: : " + url);
84 |
85 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
86 | if (!outputFile.getParentFile().exists()) {
87 | if (!outputFile.getParentFile().mkdirs()) {
88 | System.out.println(
89 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'");
90 | }
91 | }
92 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
93 | try {
94 | downloadFileFromURL(url, outputFile);
95 | System.out.println("Done");
96 | System.exit(0);
97 | } catch (Throwable e) {
98 | System.out.println("- Error downloading");
99 | e.printStackTrace();
100 | System.exit(1);
101 | }
102 | }
103 |
104 | private static void downloadFileFromURL(String urlString, File destination) throws Exception {
105 | URL website = new URL(urlString);
106 | ReadableByteChannel rbc;
107 | rbc = Channels.newChannel(website.openStream());
108 | FileOutputStream fos = new FileOutputStream(destination);
109 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
110 | fos.close();
111 | rbc.close();
112 | }
113 |
114 | }
115 |
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Architecture
2 |
3 | 
4 |
5 | Server side 构成
6 |
7 | - broker (mqtt核心:用于消息的发送管理)
8 | - Application Server用于处理RestFul的请求,转发为Mqtt消息
9 | - Publisher **本质是Mqtt client**用于发布server端消息
10 | - Subscriber **本质是Mqtt client**用于订阅client端消息,并显示
11 | - Client side
12 | - Publisher用于发布client端消息
13 | - Subscriber用于订阅server端的消息
14 | - Client 用于发送RestFul 请求给Application Server触发消息pub/sub
15 |
16 | **总结**:从结构上Broker算是Mqtt的本质上的Server端,从业务上讲封装了Mqtt Client pub/sub的Application server和Broker共同构成了业务上的Server端
17 |
18 | ## 安装mosquitto及基本使用
19 |
20 | ### 安装
21 |
22 | ```bash
23 | # Install Mosquitto Broker
24 | sudo apt-get update
25 | sudo apt-get install mosquitto
26 |
27 | # Install the Clients
28 | sudo apt-get install mosquitto-clients
29 |
30 | ```
31 |
32 | ### 开启、停止查看状态
33 |
34 | ```bash
35 | # 查看状态
36 | sudo service mosquitto status
37 |
38 | # 使用默认配置打开mosquitto, 使用-v打开log功能
39 | sudo mosquitto -c /etc/mosquitto/mosquitto.conf -v
40 |
41 | # 停止
42 | sudo service mosquitto stop
43 |
44 | #开启
45 | sudo service mosquitto start
46 | ```
47 |
48 | ### 使用mosquitto测试pub/sub
49 |
50 | `注意` pub和sub的clientid不能相同,相同会刷屏。
51 |
52 | ```bash
53 | # 简单测试发布。 -h host -t topic -m message
54 | mosquitto_pub -h localhost -t mqtt-test -m 'hello mqtt'
55 |
56 | # 简单测试订阅。
57 | mosquitto_sub -h localhost -t mqtt-test
58 |
59 | # 发布设置用户密码 -u user -P password
60 | mosquitto_pub -u admin -P admin -h localhost -t mqtt/loop/message -m 'test mqtt'
61 | mosquitto_sub -u admin -P admin -h localhost -t mqtt/loop/message
62 |
63 | # 指定发布clientid -i (id to use for this client)
64 | mosquitto_sub -u admin -P admin -i shuai-ubuntu-test -h localhost -t mqtt/loop/message
65 | mosquitto_pub -u admin -P admin -i shuai-ubuntu-test-client -h localhost -t mqtt/loop/message -m 'test mqtt client'
66 | ```
67 |
68 | ### 查看broker的log
69 |
70 | mosquitto的默认log 地址是:/var/log/mosquitto/xxx.log
71 |
72 | ```bash
73 | tailf /var/log/mosquitto/mosquitto.log
74 | ```
75 |
76 |
77 |
78 | ## 构建Java-Mqtt-Server(Springboot + Mqtt)
79 |
80 | ### requirement依赖
81 |
82 | 1. mosquitto broker
83 |
84 | 可以使用Eclipse公开的broker,据说底层也是mosquitto。地址为`iot.eclipse.org`
85 |
86 | 可以部署安装mosquitto(本文方案)
87 |
88 | 2. springboot (2.1.5.RELEASE)
89 |
90 | 3. Eclipse Paho
91 |
92 | 4. curl/postman
93 |
94 | ### 构建springboot项目
95 |
96 | #### 1. 使用idea springboot initializer 初始化springboot工程
97 |
98 | 使用springboot版本**2.1.5.RELEASE**
99 |
100 | #### 2. pom中添加
101 |
102 | ```xml
103 |
104 | org.springframework.boot
105 | spring-boot-starter-integration
106 |
107 |
108 | org.springframework.integration
109 | spring-integration-stream
110 |
111 |
112 |
113 | org.springframework.integration
114 | spring-integration-mqtt
115 |
116 |
117 | org.projectlombok
118 | lombok
119 | 1.16.10
120 | provided
121 |
122 | ```
123 |
124 | #### 3. MQTT Configuration
125 |
126 | * 配置broker地址,
127 | * 端口号,
128 | * 是否使用ssl,
129 | * 用户名
130 | * 密码
131 |
132 | ~~~java
133 | public abstract class MQTTConfig {
134 |
135 | protected final String broker = "10.156.2.132";
136 | protected final int qos = 2;
137 | protected Boolean hasSSL = false; /* By default SSL is disabled */
138 | protected Integer port = 1883; /* Default port */
139 | protected final String userName = "admin";
140 | protected final String password = "admin";
141 | protected final String TCP = "tcp://";
142 | protected final String SSL = "ssl://";
143 |
144 | /**
145 | * Custom Configuration
146 | *
147 | * @param broker
148 | * @param port
149 | * @param ssl
150 | * @param withUserNamePass
151 | */
152 | protected abstract void config(String broker, Integer port, Boolean ssl, Boolean withUserNamePass);
153 |
154 | /**
155 | * Default Configuration
156 | */
157 | protected abstract void config();
158 | }
159 |
160 | ~~~
161 |
162 |
163 |
164 | #### 4. Publisher推送者
165 |
166 | 定义接口
167 |
168 | ```java
169 | public interface IMQTTPublisher {
170 | /**
171 | * Publish message
172 | *
173 | * @param topic
174 | * @param String Message
175 | */
176 | public void publishMessage(String topic, String message);
177 |
178 | /**
179 | * Disconnect MQTT Client
180 | */
181 | public void disconnect();
182 | }
183 |
184 | ```
185 |
186 | 定义类
187 |
188 | ```java
189 |
190 | import org.eclipse.paho.client.mqttv3.*;
191 | import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
192 | import org.slf4j.Logger;
193 | import org.slf4j.LoggerFactory;
194 | import org.springframework.stereotype.Component;
195 |
196 | @Component
197 | public class MQTTPublisher extends MQTTConfig implements MqttCallback, IMQTTPublisher {
198 |
199 | private String brokerUrl = null;
200 |
201 | final private String colon = ":";
202 | final private String clientId = "mqtt_server_pub";
203 |
204 | private MqttClient mqttClient = null;
205 | private MqttConnectOptions connectionOptions = null;
206 | private MemoryPersistence persistence = null;
207 |
208 | private static final Logger logger = LoggerFactory.getLogger(MQTTPublisher.class);
209 |
210 | /**
211 | * Private default constructor
212 | */
213 | private MQTTPublisher() {
214 | this.config();
215 | }
216 |
217 | /**
218 | * Private constructor
219 | */
220 | private MQTTPublisher(String broker, Integer port, Boolean ssl, Boolean withUserNamePass) {
221 | this.config(broker, port, ssl, withUserNamePass);
222 | }
223 |
224 | /**
225 | * Factory method to get instance of MQTTPublisher
226 | *
227 | * @return MQTTPublisher
228 | */
229 | public static MQTTPublisher getInstance() {
230 | return new MQTTPublisher();
231 | }
232 |
233 | /**
234 | * Factory method to get instance of MQTTPublisher
235 | *
236 | * @param broker
237 | * @param port
238 | * @param ssl
239 | * @param withUserNamePass
240 | * @return MQTTPublisher
241 | */
242 | public static MQTTPublisher getInstance(String broker, Integer port, Boolean ssl, Boolean withUserNamePass) {
243 | return new MQTTPublisher(broker, port, ssl, withUserNamePass);
244 | }
245 |
246 | /*
247 | * (non-Javadoc)
248 | *
249 | * @see
250 | * com.bjitgroup.jasmysp.mqtt.publisher.MQTTPublisherBase#configurePublisher()
251 | */
252 | @Override
253 | protected void config() {
254 |
255 | this.brokerUrl = this.TCP + this.broker + colon + this.port;
256 | this.persistence = new MemoryPersistence();
257 | this.connectionOptions = new MqttConnectOptions();
258 | try {
259 | this.mqttClient = new MqttClient(brokerUrl, clientId, persistence);
260 | this.connectionOptions.setCleanSession(true);
261 | this.mqttClient.connect(this.connectionOptions);
262 | this.mqttClient.setCallback(this);
263 | } catch (MqttException me) {
264 | logger.error("ERROR", me);
265 | }
266 | }
267 |
268 | /*
269 | * (non-Javadoc)
270 | *
271 | * @see
272 | * com.bjitgroup.jasmysp.mqtt.publisher.MQTTPublisherBase#configurePublisher(
273 | * java.lang.String, java.lang.Integer, java.lang.Boolean, java.lang.Boolean)
274 | */
275 | @Override
276 | protected void config(String broker, Integer port, Boolean ssl, Boolean withUserNamePass) {
277 |
278 | String protocal = this.TCP;
279 | if (true == ssl) {
280 | protocal = this.SSL;
281 | }
282 |
283 | this.brokerUrl = protocal + this.broker + colon + port;
284 | this.persistence = new MemoryPersistence();
285 | this.connectionOptions = new MqttConnectOptions();
286 |
287 | try {
288 | this.mqttClient = new MqttClient(brokerUrl, clientId, persistence);
289 | this.connectionOptions.setCleanSession(true);
290 | if (true == withUserNamePass) {
291 | if (password != null) {
292 | this.connectionOptions.setPassword(this.password.toCharArray());
293 | }
294 | if (userName != null) {
295 | this.connectionOptions.setUserName(this.userName);
296 | }
297 | }
298 | this.mqttClient.connect(this.connectionOptions);
299 | this.mqttClient.setCallback(this);
300 | } catch (MqttException me) {
301 | logger.error("ERROR", me);
302 | }
303 | }
304 |
305 |
306 | /*
307 | * (non-Javadoc)
308 | * @see com.monirthought.mqtt.publisher.MQTTPublisherBase#publishMessage(java.lang.String, java.lang.String)
309 | */
310 | @Override
311 | public void publishMessage(String topic, String message) {
312 |
313 | try {
314 | MqttMessage mqttmessage = new MqttMessage(message.getBytes());
315 | mqttmessage.setQos(this.qos);
316 | this.mqttClient.publish(topic, mqttmessage);
317 | } catch (MqttException me) {
318 | logger.error("ERROR", me);
319 | }
320 |
321 | }
322 |
323 | /*
324 | * (non-Javadoc)
325 | * @see org.eclipse.paho.client.mqttv3.MqttCallback#connectionLost(java.lang.Throwable)
326 | */
327 | @Override
328 | public void connectionLost(Throwable arg0) {
329 | logger.info("Connection Lost");
330 |
331 | }
332 |
333 | /*
334 | * (non-Javadoc)
335 | * @see org.eclipse.paho.client.mqttv3.MqttCallback#deliveryComplete(org.eclipse.paho.client.mqttv3.IMqttDeliveryToken)
336 | */
337 | @Override
338 | public void deliveryComplete(IMqttDeliveryToken arg0) {
339 | logger.info("delivery completed");
340 |
341 | }
342 |
343 | /*
344 | * (non-Javadoc)
345 | * @see org.eclipse.paho.client.mqttv3.MqttCallback#messageArrived(java.lang.String, org.eclipse.paho.client.mqttv3.MqttMessage)
346 | */
347 | @Override
348 | public void messageArrived(String arg0, MqttMessage arg1) throws Exception {
349 | // Leave it blank for Publisher
350 |
351 | }
352 |
353 | /*
354 | * (non-Javadoc)
355 | * @see com.monirthought.mqtt.publisher.MQTTPublisherBase#disconnect()
356 | */
357 | @Override
358 | public void disconnect() {
359 | try {
360 | this.mqttClient.disconnect();
361 | } catch (MqttException me) {
362 | logger.error("ERROR", me);
363 | }
364 | }
365 |
366 | }
367 | ```
368 |
369 |
370 |
371 | #### 5. Subscriber 订阅者
372 |
373 | 定义接口
374 |
375 | ```java
376 | import org.slf4j.Logger;
377 | import org.slf4j.LoggerFactory;
378 |
379 | public interface IMQTTSubscriber {
380 | public static final Logger logger = LoggerFactory.getLogger(IMQTTSubscriber.class);
381 |
382 | /**
383 | * Subscribe message
384 | *
385 | * @param topic
386 | * @param jasonMessage
387 | */
388 | public void subscribeMessage(String topic);
389 |
390 | /**
391 | * Disconnect MQTT Client
392 | */
393 | public void disconnect();
394 | }
395 |
396 | ```
397 |
398 | 类定义
399 |
400 | ```java
401 | import org.eclipse.paho.client.mqttv3.*;
402 | import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
403 | import org.slf4j.Logger;
404 | import org.slf4j.LoggerFactory;
405 | import org.springframework.stereotype.Component;
406 |
407 | import java.sql.Timestamp;
408 |
409 | @Component
410 | public class MQTTSubscriber extends MQTTConfig implements MqttCallback, IMQTTSubscriber {
411 |
412 | private String brokerUrl = null;
413 | final private String colon = ":";
414 | final private String clientId = "mqtt_server_sub";
415 |
416 | private MqttClient mqttClient = null;
417 | private MqttConnectOptions connectionOptions = null;
418 | private MemoryPersistence persistence = null;
419 |
420 | private static final Logger logger = LoggerFactory.getLogger(MQTTSubscriber.class);
421 |
422 | public MQTTSubscriber() {
423 | this.config();
424 | }
425 |
426 | /*
427 | * (non-Javadoc)
428 | *
429 | * @see org.eclipse.paho.client.mqttv3.MqttCallback#connectionLost(java.lang.
430 | * Throwable)
431 | */
432 | @Override
433 | public void connectionLost(Throwable cause) {
434 | logger.info("Connection Lost");
435 |
436 | }
437 |
438 | /*
439 | * (non-Javadoc)
440 | *
441 | * @see
442 | * org.eclipse.paho.client.mqttv3.MqttCallback#messageArrived(java.lang.String,
443 | * org.eclipse.paho.client.mqttv3.MqttMessage)
444 | */
445 | @Override
446 | public void messageArrived(String topic, MqttMessage message) throws Exception {
447 | // Called when a message arrives from the server that matches any
448 | // subscription made by the client
449 | String time = new Timestamp(System.currentTimeMillis()).toString();
450 | System.out.println();
451 | System.out.println("***********************************************************************");
452 | System.out.println("Message Arrived at Time: " + time + " Topic: " + topic + " Message: "
453 | + new String(message.getPayload()));
454 | System.out.println("***********************************************************************");
455 | System.out.println();
456 | }
457 |
458 | /*
459 | * (non-Javadoc)
460 | *
461 | * @see
462 | * org.eclipse.paho.client.mqttv3.MqttCallback#deliveryComplete(org.eclipse.paho
463 | * .client.mqttv3.IMqttDeliveryToken)
464 | */
465 | @Override
466 | public void deliveryComplete(IMqttDeliveryToken token) {
467 | // Leave it blank for subscriber
468 |
469 | }
470 |
471 | /*
472 | * (non-Javadoc)
473 | *
474 | * @see
475 | * com.monirthought.mqtt.subscriber.MQTTSubscriberBase#subscribeMessage(java.
476 | * lang.String)
477 | */
478 | @Override
479 | public void subscribeMessage(String topic) {
480 | try {
481 | this.mqttClient.subscribe(topic, this.qos);
482 | } catch (MqttException me) {
483 | me.printStackTrace();
484 | }
485 | }
486 |
487 | /*
488 | * (non-Javadoc)
489 | *
490 | * @see com.monirthought.mqtt.subscriber.MQTTSubscriberBase#disconnect()
491 | */
492 | public void disconnect() {
493 | try {
494 | this.mqttClient.disconnect();
495 | } catch (MqttException me) {
496 | logger.error("ERROR", me);
497 | }
498 | }
499 |
500 | /*
501 | * (non-Javadoc)
502 | *
503 | * @see com.monirthought.config.MQTTConfig#config(java.lang.String,
504 | * java.lang.Integer, java.lang.Boolean, java.lang.Boolean)
505 | */
506 | @Override
507 | protected void config(String broker, Integer port, Boolean ssl, Boolean withUserNamePass) {
508 |
509 | String protocal = this.TCP;
510 | if (true == ssl) {
511 | protocal = this.SSL;
512 | }
513 |
514 | this.brokerUrl = protocal + this.broker + colon + port;
515 | this.persistence = new MemoryPersistence();
516 | this.connectionOptions = new MqttConnectOptions();
517 |
518 | try {
519 | this.mqttClient = new MqttClient(brokerUrl, clientId, persistence);
520 | this.connectionOptions.setCleanSession(true);
521 | if (true == withUserNamePass) {
522 | if (password != null) {
523 | this.connectionOptions.setPassword(this.password.toCharArray());
524 | }
525 | if (userName != null) {
526 | this.connectionOptions.setUserName(this.userName);
527 | }
528 | }
529 | this.mqttClient.connect(this.connectionOptions);
530 | this.mqttClient.setCallback(this);
531 | } catch (MqttException me) {
532 | me.printStackTrace();
533 | }
534 |
535 | }
536 |
537 | /*
538 | * (non-Javadoc)
539 | *
540 | * @see com.monirthought.config.MQTTConfig#config()
541 | */
542 | @Override
543 | protected void config() {
544 |
545 | this.brokerUrl = this.TCP + this.broker + colon + this.port;
546 | this.persistence = new MemoryPersistence();
547 | this.connectionOptions = new MqttConnectOptions();
548 | try {
549 | this.mqttClient = new MqttClient(brokerUrl, clientId, persistence);
550 | this.connectionOptions.setCleanSession(true);
551 | this.mqttClient.connect(this.connectionOptions);
552 | this.mqttClient.setCallback(this);
553 | } catch (MqttException me) {
554 | me.printStackTrace();
555 | }
556 |
557 | }
558 |
559 | }
560 | ```
561 |
562 | #### 6. 构建 RestFul接口
563 |
564 | 构建Controller
565 |
566 | ```java
567 | import lombok.extern.slf4j.Slf4j;
568 | import org.slf4j.Logger;
569 | import org.slf4j.LoggerFactory;
570 | import org.springframework.beans.factory.annotation.Autowired;
571 | import org.springframework.web.bind.annotation.*;
572 |
573 | import javax.annotation.PostConstruct;
574 |
575 | @Slf4j
576 | @RestController
577 | public class DemoRestController {
578 | public static String TOPIC_LOOP_TEST = "mqtt/loop/message";
579 |
580 | @Autowired
581 | IMQTTPublisher publisher;
582 |
583 | @Autowired
584 | IMQTTSubscriber subscriber;
585 |
586 | @PostConstruct
587 | public void init() {
588 | subscriber.subscribeMessage(TOPIC_LOOP_TEST);
589 | }
590 |
591 | @RequestMapping(value = "/mqtt/loop/message", method = RequestMethod.POST)
592 | public String index(@RequestBody String data) {
593 | publisher.publishMessage(TOPIC_LOOP_TEST, data);
594 | return "Success";
595 | }
596 |
597 | }
598 | ```
599 |
600 | #### 7. 使用curl命令进行api调用测试
601 |
602 | ```bash
603 | ❯ curl -X POST "http://127.0.0.1:8080/mqtt/loop/message" -d "test"
604 | Success%
605 |
606 | # springboot 窗口中可以看到自己sub的回显
607 | ***********************************************************************
608 | Message Arrived at Time: 2019-05-21 16:11:13.675 Topic: mqtt/loop/message Message: test=
609 | ***********************************************************************
610 | ```
611 |
612 | 也可以使用postman 调用8080 端口调试。
613 |
614 | ## 构建Java-Mqtt-Server (Springboot + Mqtt +protobuf)
615 |
616 | 在现有基础上添加protobuf包装pub/sub 消息
617 |
618 | #### 1. proto文件
619 |
620 | 将.proto文件放到`src/main/proto/`下
621 |
622 | #### 2. 使用maven生成protobuf java代码
623 |
624 | pom中properties中添加
625 |
626 | ```xml
627 |
628 | 1.8
629 | 1.6.1
630 | 3.3.0
631 |
632 | ```
633 |
634 | pom dependencies中添加
635 |
636 | ```xml
637 |
638 | io.grpc
639 | grpc-netty
640 | ${grpc.version}
641 | provided
642 |
643 |
644 | io.grpc
645 | grpc-protobuf
646 | ${grpc.version}
647 | provided
648 |
649 |
650 | io.grpc
651 | grpc-stub
652 | ${grpc.version}
653 | provided
654 |
655 |
656 | com.google.protobuf
657 | protobuf-java
658 | ${protobuf.version}
659 |
660 | ```
661 |
662 | pom build中添加,pom plugins中添加
663 |
664 | ```xml
665 |
666 |
667 |
668 |
669 | kr.motd.maven
670 | os-maven-plugin
671 | 1.5.0.Final
672 |
673 |
674 |
675 |
676 |
677 | org.springframework.boot
678 | spring-boot-maven-plugin
679 |
680 |
681 |
682 | org.xolstice.maven.plugins
683 | protobuf-maven-plugin
684 | 0.5.0
685 |
686 | com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}
687 | grpc-java
688 | io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}
689 |
690 |
691 |
692 |
693 | compile
694 | compile-custom
695 |
696 |
697 |
698 |
699 |
700 |
701 | ```
702 |
703 |
704 |
705 | 使用IDE中右侧Maven Projects -> Lifecycle ->compile 生成java对应的protobuf文件
706 |
707 | 生成的路径在:`target/generated-sources/protobuf/java/对应的包名下 `
708 |
709 | #### 3. 使用proto封装mqtt message
710 |
711 | 使用Proto中的newBuilder构建builder。使用builder中的set方法设置proto中的参数,例如:
712 |
713 | ```java
714 | KylinProto.Group.Builder builder = KylinProto.Group.newBuilder();
715 | KylinProto.Group group = builder.setThreshold(85.f)
716 | .setTop(1)
717 | .setGroup(group_name).build();
718 | publisher.publish(topic, group.toByteArray(), 2, false);
719 |
720 | ```
721 |
722 |
--------------------------------------------------------------------------------
/images/Mqtt-server-arch.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/braincs/mqtt-protobuf-server/d20dcfdcc75e149b986a06729577b4dfc4327f63/images/Mqtt-server-arch.jpg
--------------------------------------------------------------------------------
/lib/protobuf-java-3.1.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/braincs/mqtt-protobuf-server/d20dcfdcc75e149b986a06729577b4dfc4327f63/lib/protobuf-java-3.1.0.jar
--------------------------------------------------------------------------------
/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # https://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Maven2 Start Up Batch script
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # M2_HOME - location of maven2's installed home dir
31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
32 | # e.g. to debug Maven itself, use
33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35 | # ----------------------------------------------------------------------------
36 |
37 | if [ -z "$MAVEN_SKIP_RC" ] ; then
38 |
39 | if [ -f /etc/mavenrc ] ; then
40 | . /etc/mavenrc
41 | fi
42 |
43 | if [ -f "$HOME/.mavenrc" ] ; then
44 | . "$HOME/.mavenrc"
45 | fi
46 |
47 | fi
48 |
49 | # OS specific support. $var _must_ be set to either true or false.
50 | cygwin=false;
51 | darwin=false;
52 | mingw=false
53 | case "`uname`" in
54 | CYGWIN*) cygwin=true ;;
55 | MINGW*) mingw=true;;
56 | Darwin*) darwin=true
57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
59 | if [ -z "$JAVA_HOME" ]; then
60 | if [ -x "/usr/libexec/java_home" ]; then
61 | export JAVA_HOME="`/usr/libexec/java_home`"
62 | else
63 | export JAVA_HOME="/Library/Java/Home"
64 | fi
65 | fi
66 | ;;
67 | esac
68 |
69 | if [ -z "$JAVA_HOME" ] ; then
70 | if [ -r /etc/gentoo-release ] ; then
71 | JAVA_HOME=`java-config --jre-home`
72 | fi
73 | fi
74 |
75 | if [ -z "$M2_HOME" ] ; then
76 | ## resolve links - $0 may be a link to maven's home
77 | PRG="$0"
78 |
79 | # need this for relative symlinks
80 | while [ -h "$PRG" ] ; do
81 | ls=`ls -ld "$PRG"`
82 | link=`expr "$ls" : '.*-> \(.*\)$'`
83 | if expr "$link" : '/.*' > /dev/null; then
84 | PRG="$link"
85 | else
86 | PRG="`dirname "$PRG"`/$link"
87 | fi
88 | done
89 |
90 | saveddir=`pwd`
91 |
92 | M2_HOME=`dirname "$PRG"`/..
93 |
94 | # make it fully qualified
95 | M2_HOME=`cd "$M2_HOME" && pwd`
96 |
97 | cd "$saveddir"
98 | # echo Using m2 at $M2_HOME
99 | fi
100 |
101 | # For Cygwin, ensure paths are in UNIX format before anything is touched
102 | if $cygwin ; then
103 | [ -n "$M2_HOME" ] &&
104 | M2_HOME=`cygpath --unix "$M2_HOME"`
105 | [ -n "$JAVA_HOME" ] &&
106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
107 | [ -n "$CLASSPATH" ] &&
108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
109 | fi
110 |
111 | # For Mingw, ensure paths are in UNIX format before anything is touched
112 | if $mingw ; then
113 | [ -n "$M2_HOME" ] &&
114 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
115 | [ -n "$JAVA_HOME" ] &&
116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
117 | # TODO classpath?
118 | fi
119 |
120 | if [ -z "$JAVA_HOME" ]; then
121 | javaExecutable="`which javac`"
122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
123 | # readlink(1) is not available as standard on Solaris 10.
124 | readLink=`which readlink`
125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
126 | if $darwin ; then
127 | javaHome="`dirname \"$javaExecutable\"`"
128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
129 | else
130 | javaExecutable="`readlink -f \"$javaExecutable\"`"
131 | fi
132 | javaHome="`dirname \"$javaExecutable\"`"
133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
134 | JAVA_HOME="$javaHome"
135 | export JAVA_HOME
136 | fi
137 | fi
138 | fi
139 |
140 | if [ -z "$JAVACMD" ] ; then
141 | if [ -n "$JAVA_HOME" ] ; then
142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
143 | # IBM's JDK on AIX uses strange locations for the executables
144 | JAVACMD="$JAVA_HOME/jre/sh/java"
145 | else
146 | JAVACMD="$JAVA_HOME/bin/java"
147 | fi
148 | else
149 | JAVACMD="`which java`"
150 | fi
151 | fi
152 |
153 | if [ ! -x "$JAVACMD" ] ; then
154 | echo "Error: JAVA_HOME is not defined correctly." >&2
155 | echo " We cannot execute $JAVACMD" >&2
156 | exit 1
157 | fi
158 |
159 | if [ -z "$JAVA_HOME" ] ; then
160 | echo "Warning: JAVA_HOME environment variable is not set."
161 | fi
162 |
163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
164 |
165 | # traverses directory structure from process work directory to filesystem root
166 | # first directory with .mvn subdirectory is considered project base directory
167 | find_maven_basedir() {
168 |
169 | if [ -z "$1" ]
170 | then
171 | echo "Path not specified to find_maven_basedir"
172 | return 1
173 | fi
174 |
175 | basedir="$1"
176 | wdir="$1"
177 | while [ "$wdir" != '/' ] ; do
178 | if [ -d "$wdir"/.mvn ] ; then
179 | basedir=$wdir
180 | break
181 | fi
182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
183 | if [ -d "${wdir}" ]; then
184 | wdir=`cd "$wdir/.."; pwd`
185 | fi
186 | # end of workaround
187 | done
188 | echo "${basedir}"
189 | }
190 |
191 | # concatenates all lines of a file
192 | concat_lines() {
193 | if [ -f "$1" ]; then
194 | echo "$(tr -s '\n' ' ' < "$1")"
195 | fi
196 | }
197 |
198 | BASE_DIR=`find_maven_basedir "$(pwd)"`
199 | if [ -z "$BASE_DIR" ]; then
200 | exit 1;
201 | fi
202 |
203 | ##########################################################################################
204 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
205 | # This allows using the maven wrapper in projects that prohibit checking in binary data.
206 | ##########################################################################################
207 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
208 | if [ "$MVNW_VERBOSE" = true ]; then
209 | echo "Found .mvn/wrapper/maven-wrapper.jar"
210 | fi
211 | else
212 | if [ "$MVNW_VERBOSE" = true ]; then
213 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
214 | fi
215 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
216 | while IFS="=" read key value; do
217 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
218 | esac
219 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
220 | if [ "$MVNW_VERBOSE" = true ]; then
221 | echo "Downloading from: $jarUrl"
222 | fi
223 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
224 |
225 | if command -v wget > /dev/null; then
226 | if [ "$MVNW_VERBOSE" = true ]; then
227 | echo "Found wget ... using wget"
228 | fi
229 | wget "$jarUrl" -O "$wrapperJarPath"
230 | elif command -v curl > /dev/null; then
231 | if [ "$MVNW_VERBOSE" = true ]; then
232 | echo "Found curl ... using curl"
233 | fi
234 | curl -o "$wrapperJarPath" "$jarUrl"
235 | else
236 | if [ "$MVNW_VERBOSE" = true ]; then
237 | echo "Falling back to using Java to download"
238 | fi
239 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
240 | if [ -e "$javaClass" ]; then
241 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
242 | if [ "$MVNW_VERBOSE" = true ]; then
243 | echo " - Compiling MavenWrapperDownloader.java ..."
244 | fi
245 | # Compiling the Java class
246 | ("$JAVA_HOME/bin/javac" "$javaClass")
247 | fi
248 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
249 | # Running the downloader
250 | if [ "$MVNW_VERBOSE" = true ]; then
251 | echo " - Running MavenWrapperDownloader.java ..."
252 | fi
253 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
254 | fi
255 | fi
256 | fi
257 | fi
258 | ##########################################################################################
259 | # End of extension
260 | ##########################################################################################
261 |
262 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
263 | if [ "$MVNW_VERBOSE" = true ]; then
264 | echo $MAVEN_PROJECTBASEDIR
265 | fi
266 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
267 |
268 | # For Cygwin, switch paths to Windows format before running java
269 | if $cygwin; then
270 | [ -n "$M2_HOME" ] &&
271 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
272 | [ -n "$JAVA_HOME" ] &&
273 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
274 | [ -n "$CLASSPATH" ] &&
275 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
276 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
277 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
278 | fi
279 |
280 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
281 |
282 | exec "$JAVACMD" \
283 | $MAVEN_OPTS \
284 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
285 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
286 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
287 |
--------------------------------------------------------------------------------
/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM https://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven2 Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM set title of command window
39 | title %0
40 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
42 |
43 | @REM set %HOME% to equivalent of $HOME
44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
45 |
46 | @REM Execute a user defined script before this one
47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
51 | :skipRcPre
52 |
53 | @setlocal
54 |
55 | set ERROR_CODE=0
56 |
57 | @REM To isolate internal variables from possible post scripts, we use another setlocal
58 | @setlocal
59 |
60 | @REM ==== START VALIDATION ====
61 | if not "%JAVA_HOME%" == "" goto OkJHome
62 |
63 | echo.
64 | echo Error: JAVA_HOME not found in your environment. >&2
65 | echo Please set the JAVA_HOME variable in your environment to match the >&2
66 | echo location of your Java installation. >&2
67 | echo.
68 | goto error
69 |
70 | :OkJHome
71 | if exist "%JAVA_HOME%\bin\java.exe" goto init
72 |
73 | echo.
74 | echo Error: JAVA_HOME is set to an invalid directory. >&2
75 | echo JAVA_HOME = "%JAVA_HOME%" >&2
76 | echo Please set the JAVA_HOME variable in your environment to match the >&2
77 | echo location of your Java installation. >&2
78 | echo.
79 | goto error
80 |
81 | @REM ==== END VALIDATION ====
82 |
83 | :init
84 |
85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
86 | @REM Fallback to current working directory if not found.
87 |
88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
90 |
91 | set EXEC_DIR=%CD%
92 | set WDIR=%EXEC_DIR%
93 | :findBaseDir
94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
95 | cd ..
96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
97 | set WDIR=%CD%
98 | goto findBaseDir
99 |
100 | :baseDirFound
101 | set MAVEN_PROJECTBASEDIR=%WDIR%
102 | cd "%EXEC_DIR%"
103 | goto endDetectBaseDir
104 |
105 | :baseDirNotFound
106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
107 | cd "%EXEC_DIR%"
108 |
109 | :endDetectBaseDir
110 |
111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
112 |
113 | @setlocal EnableExtensions EnableDelayedExpansion
114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
116 |
117 | :endReadAdditionalConfig
118 |
119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
122 |
123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
124 | FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO (
125 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
126 | )
127 |
128 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
129 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data.
130 | if exist %WRAPPER_JAR% (
131 | echo Found %WRAPPER_JAR%
132 | ) else (
133 | echo Couldn't find %WRAPPER_JAR%, downloading it ...
134 | echo Downloading from: %DOWNLOAD_URL%
135 | powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"
136 | echo Finished downloading %WRAPPER_JAR%
137 | )
138 | @REM End of extension
139 |
140 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
141 | if ERRORLEVEL 1 goto error
142 | goto end
143 |
144 | :error
145 | set ERROR_CODE=1
146 |
147 | :end
148 | @endlocal & set ERROR_CODE=%ERROR_CODE%
149 |
150 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
151 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
152 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
153 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
154 | :skipRcPost
155 |
156 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
157 | if "%MAVEN_BATCH_PAUSE%" == "on" pause
158 |
159 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
160 |
161 | exit /B %ERROR_CODE%
162 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 2.1.5.RELEASE
9 |
10 |
11 | com.braincs
12 | mqtt-protobuf-server
13 | 1.0.1-SNAPSHOT
14 | mqtt-protobuf-server
15 | Demo project for mock mqtt protobuf server
16 |
17 |
18 | 1.8
19 | 1.6.1
20 | 3.1.0
21 |
22 |
23 |
24 |
25 | org.springframework.boot
26 | spring-boot-starter-web
27 |
28 |
29 |
30 | org.springframework.boot
31 | spring-boot-starter-test
32 | test
33 |
34 |
35 | org.springframework.boot
36 | spring-boot-starter-integration
37 |
38 |
39 | org.springframework.integration
40 | spring-integration-stream
41 |
42 |
43 |
44 | org.springframework.integration
45 | spring-integration-mqtt
46 |
47 |
48 | org.projectlombok
49 | lombok
50 | 1.16.10
51 | provided
52 |
53 |
54 |
55 |
56 | io.grpc
57 | grpc-netty
58 | ${grpc.version}
59 | provided
60 |
61 |
62 | io.grpc
63 | grpc-protobuf
64 | ${grpc.version}
65 | provided
66 |
67 |
68 | io.grpc
69 | grpc-stub
70 | ${grpc.version}
71 | provided
72 |
73 |
74 | com.google.protobuf
75 | protobuf-java
76 | ${protobuf.version}
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | kr.motd.maven
85 | os-maven-plugin
86 | 1.5.0.Final
87 |
88 |
89 |
90 |
91 |
92 | org.springframework.boot
93 | spring-boot-maven-plugin
94 |
95 |
96 |
97 | org.xolstice.maven.plugins
98 | protobuf-maven-plugin
99 | 0.5.0
100 |
101 | com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}
102 | grpc-java
103 | io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}
104 |
105 |
106 |
107 |
108 | compile
109 | compile-custom
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/src/main/java/com/braincs/mqttprotobufserver/MqttProtobufServerApplication.java:
--------------------------------------------------------------------------------
1 | package com.braincs.mqttprotobufserver;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | //@Configuration
8 | //@EnableConfigurationProperties(MqttProperties.class)
9 | public class MqttProtobufServerApplication {
10 |
11 | public static void main(String[] args) {
12 | SpringApplication.run(MqttProtobufServerApplication.class, args);
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/braincs/mqttprotobufserver/controller/MQTTRestController.java:
--------------------------------------------------------------------------------
1 | package com.braincs.mqttprotobufserver.controller;
2 |
3 | import com.braincs.kylinprotocol.pb.KylinProto;
4 | import com.braincs.mqttprotobufserver.mqtt.IMQTTPublisher;
5 | import com.braincs.mqttprotobufserver.mqtt.IMQTTSubscriber;
6 | import com.google.protobuf.InvalidProtocolBufferException;
7 | import lombok.extern.slf4j.Slf4j;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.web.bind.annotation.*;
12 |
13 | import javax.annotation.PostConstruct;
14 |
15 | @Slf4j
16 | @RestController
17 | public class MQTTRestController {
18 |
19 | @Autowired
20 | IMQTTPublisher publisher;
21 |
22 | @Autowired
23 | IMQTTSubscriber subscriber;
24 |
25 |
26 | private boolean isOpen = false;
27 | public static String IP_PREFIX = "panel/m5/";
28 | public static String CLIENTID = "12345";
29 | //region topics
30 | public static String TOPIC_LOOP_TEST = "mqtt/loop/message";
31 | public static String TOPIC_PANEL_SATAUS = IP_PREFIX + CLIENTID + "/out/start";//status 主题
32 | public static String TOPIC_PANEL_CHECK = IP_PREFIX + CLIENTID + "/in/check";
33 | ;//check 主题
34 | public static String TOPIC_PANEL_RECOGNIZE = IP_PREFIX + CLIENTID + "/in/recognize";//recognize 主题
35 | public static String TOPIC_PANEL_ADD_GROUP = IP_PREFIX + CLIENTID + "/out/add_group";//group 主题
36 | public static String TOPIC_PANEL_ADD_GROUP_RES = IP_PREFIX + CLIENTID + "/in/add_group/+";//group 主题
37 | public static String TOPIC_PANEL_DEL_GROUP = IP_PREFIX + CLIENTID + "/out/del_group/";//group 主题
38 | public static String TOPIC_PANEL_DEL_GROUP_RES = IP_PREFIX + CLIENTID + "/in/del_group/+";//group 主题
39 | public static String TOPIC_PANEL_ADD_FACE = IP_PREFIX + CLIENTID + "/out/add_face";//add_face 主题
40 | public static String TOPIC_PANEL_ADD_FACE_RES = IP_PREFIX + CLIENTID + "/in/add_face/+/+";//add_face 返回主题
41 | public static String TOPIC_PANEL_DEL_FACE = IP_PREFIX + CLIENTID + "/out/del_face/+/+";//del_face 主题
42 | public static String TOPIC_PANEL_DEL_FACE_RES = IP_PREFIX + CLIENTID + "/in/del_face/+/+";//del_face 返回主题
43 | public static String TOPIC_PANEL_SNAPSHOT = IP_PREFIX + CLIENTID + "/out/snapshot";//snapshot 主题
44 | public static String TOPIC_PANEL_SNAPSHOT_RES = IP_PREFIX + CLIENTID + "/in/snapshot";//snapshot result 主题
45 |
46 | //endregion
47 |
48 | //region last_will
49 | public static String LAST_WILL_PANEL_SATAUS = IP_PREFIX + CLIENTID + "/out/stop";//status 遗言
50 | public static String LAST_WILL_PANEL_CHECK = IP_PREFIX + CLIENTID + "/in/disconnect";//check 遗言
51 | //endregion
52 |
53 | @PostConstruct
54 | public void init() {
55 | subscriber.subscribeMessage(TOPIC_LOOP_TEST);
56 | subscriber.subscribeMessage(TOPIC_PANEL_CHECK);
57 | subscriber.subscribeMessage(TOPIC_PANEL_RECOGNIZE);
58 | subscriber.subscribeMessage(TOPIC_PANEL_ADD_GROUP_RES);
59 | subscriber.subscribeMessage(TOPIC_PANEL_DEL_GROUP_RES);
60 | subscriber.subscribeMessage(TOPIC_PANEL_ADD_FACE_RES);
61 | subscriber.subscribeMessage(TOPIC_PANEL_DEL_FACE_RES);
62 | subscriber.subscribeMessage(TOPIC_PANEL_SNAPSHOT_RES);
63 | }
64 |
65 | private static final Logger logger = LoggerFactory.getLogger(MQTTRestController.class);
66 |
67 | @RequestMapping(value = "/mqtt/loop/message", method = RequestMethod.POST)
68 | public String index(@RequestBody String data) {
69 | publisher.publishMessage(TOPIC_LOOP_TEST, data);
70 | return "Success";
71 | }
72 |
73 | @RequestMapping(value = "/start", method = RequestMethod.POST)
74 | public String status(@RequestParam String modeStr, @RequestParam int health_check_interval) {
75 | int mode = 1;
76 | if (modeStr.contains("capture")) {
77 | mode = 0;
78 | }
79 | // else if (modeStr.contains("recognize")) {
80 | // mode = 1;
81 | // }
82 | String res = "mode = " + mode + ", health_check_interval = " + health_check_interval;
83 | System.out.println(res);
84 | //construct message via protobuf
85 | isOpen = !isOpen;
86 | KylinProto.Start.Builder builder = KylinProto.Start.newBuilder();
87 | KylinProto.Start start = builder.setIsOpen(isOpen)
88 | .setHealthCheckInterval(health_check_interval)
89 | .setMode(KylinProto.Start.Mode.recognize)
90 | .build();
91 |
92 | try {
93 | KylinProto.Start parseStart = KylinProto.Start.parseFrom(start.toByteArray());
94 | boolean isOpen = parseStart.getIsOpen();
95 | KylinProto.Start.Mode startMode = parseStart.getMode();
96 | int healthCheckInterval = parseStart.getHealthCheckInterval();
97 | System.out.println("isOpen: " + isOpen + ", Mode: " + startMode.name() + ", interval: " + healthCheckInterval);
98 |
99 | } catch (InvalidProtocolBufferException e) {
100 | e.printStackTrace();
101 | }
102 |
103 | publisher.publish(TOPIC_PANEL_SATAUS, start.toByteArray(), 2, false);
104 | // publisher.publish(TOPIC_PANEL_SATAUS, res.getBytes(), 2, false);
105 | // publisher.publishMessage(TOPIC_PANEL_SATAUS, res);
106 | return "Success";
107 | }
108 |
109 | @RequestMapping(value = "/group/add", method = RequestMethod.POST)
110 | public String groupAdd(@RequestParam String url,
111 | @RequestParam String group_name,
112 | @RequestParam float threshold,
113 | @RequestParam int top) {
114 | // System.out.println("url = " + url);
115 | // System.out.println("group_name = " + group_name);
116 | System.out.println("--收到 groupAdd RestFul请求--");
117 | String[] split = url.split("@");
118 | String topic = split[split.length - 1];
119 | topic = topic + "/out/add_group";
120 | System.out.println("topic = " + topic);
121 |
122 | KylinProto.Group.Builder builder = KylinProto.Group.newBuilder();
123 | KylinProto.Group group = builder.setThreshold(threshold)
124 | .setTop(top)
125 | .setGroup(group_name).build();
126 | System.out.println("pub group: " + group.toString());
127 |
128 | publisher.publish(topic, group.toByteArray(), 2, false);
129 | return "Success";
130 | }
131 |
132 |
133 | @RequestMapping(value = "/group/delete", method = RequestMethod.DELETE)
134 | public String groupDelete(@RequestParam String url, @RequestParam String group_name) {
135 | System.out.println("--收到 groupDelete RestFul请求--");
136 |
137 | // System.out.println("url = " + url);
138 | // System.out.println("group_name = " + group_name);
139 | String[] split = url.split("@");
140 | String topic = split[split.length - 1];
141 | topic = topic + "/out/del_group/" + group_name;
142 |
143 | System.out.println("pub del_group topic: " + topic);
144 | publisher.publishMessage(topic, "del_group:group_name");
145 | return "Success";
146 | }
147 |
148 | @RequestMapping(value = "/face/add", method = RequestMethod.POST)
149 | public String faceAdd(@RequestParam String url,
150 | @RequestParam String group_name,
151 | @RequestParam String cert_no,
152 | @RequestParam String name,
153 | @RequestParam String image_url) {
154 | System.out.println("--收到 faceAdd RestFul请求--");
155 |
156 | System.out.println("url = " + url);
157 | System.out.println("group_name = " + group_name + ", cert_no = " + cert_no + ", name = " + name + ", image_url = " + image_url);
158 | String[] split = url.split("@");
159 | String topic = split[split.length - 1];
160 | topic = topic + "/out/add_face";
161 | System.out.println("topic = " + topic);
162 | KylinProto.Face.Builder builder = KylinProto.Face.newBuilder();
163 | KylinProto.Face face = builder.setGroup(group_name)
164 | .setFace(cert_no)
165 | .setName(name)
166 | .setUrl(image_url).build();
167 | System.out.println("pub face: " + face.toString());
168 |
169 | publisher.publish(topic, face.toByteArray(), 2, false);
170 | return "Success";
171 | }
172 |
173 | @RequestMapping(value = "/face/delete", method = RequestMethod.DELETE)
174 | public String faceDelete(@RequestParam String url, @RequestParam String group_name, @RequestParam String cert_no) {
175 | System.out.println("--收到 faceDelete RestFul请求--");
176 |
177 | // System.out.println("url = " + url);
178 | // System.out.println("group_name = " + group_name + ", cert_no = " + cert_no);
179 | String[] split = url.split("@");
180 | String topic = split[split.length - 1];
181 | topic = topic + "/out/del_face/" + group_name + "/" + cert_no;
182 | System.out.println("pub del_face topic: " + topic);
183 |
184 | publisher.publishMessage(topic, "del_face:" + group_name + "/" + cert_no);
185 | return "Success";
186 | }
187 |
188 | @RequestMapping(value = "/snapshot", method = RequestMethod.POST)
189 | public String snapshot(@RequestParam String url) {
190 | // System.out.println("url = " + url);
191 | // System.out.println("group_name = " + group_name);
192 | System.out.println("--收到 snapshot RestFul请求--");
193 |
194 | String[] split = url.split("@");
195 | String topic = split[split.length - 1];
196 | topic = topic + "/out/snapshot";
197 | System.out.println("pub snapshot topic: " + topic);
198 | publisher.publishMessage(topic, "snapshot");
199 | return "Success";
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/src/main/java/com/braincs/mqttprotobufserver/mqtt/IMQTTPublisher.java:
--------------------------------------------------------------------------------
1 | package com.braincs.mqttprotobufserver.mqtt;
2 |
3 | public interface IMQTTPublisher {
4 | /**
5 | * Publish message
6 | *
7 | * @param topic
8 | * @param String Message
9 | */
10 | public void publishMessage(String topic, String message);
11 |
12 | /**
13 | * publish message to topic with qos
14 | * @param topic to deliver the message to, for example "finance/stock/ibm"
15 | * @param message message to sub
16 | * @param qos the Quality of Service to deliver the message at. Valid values
17 | * are 0, 1 or 2.
18 | * @param retained whether or not this message should be retained by the server.
19 | */
20 | public void publish(String topic, byte[] message, int qos, boolean retained);
21 | /**
22 | * Disconnect MQTT Client
23 | */
24 | public void disconnect();
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/braincs/mqttprotobufserver/mqtt/IMQTTSubscriber.java:
--------------------------------------------------------------------------------
1 | package com.braincs.mqttprotobufserver.mqtt;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | public interface IMQTTSubscriber {
7 | public static final Logger logger = LoggerFactory.getLogger(IMQTTSubscriber.class);
8 |
9 | /**
10 | * Subscribe message
11 | *
12 | * @param topic
13 | * @param jasonMessage
14 | */
15 | public void subscribeMessage(String topic);
16 |
17 | /**
18 | * Disconnect MQTT Client
19 | */
20 | public void disconnect();
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/braincs/mqttprotobufserver/mqtt/MQTTPublisher.java:
--------------------------------------------------------------------------------
1 | package com.braincs.mqttprotobufserver.mqtt;
2 |
3 | import org.eclipse.paho.client.mqttv3.*;
4 | import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.stereotype.Component;
8 |
9 | @Component
10 | public class MQTTPublisher extends MQTTConfig implements MqttCallback, IMQTTPublisher {
11 |
12 | private String brokerUrl = null;
13 |
14 | final private String colon = ":";
15 | final private String clientId = "mqtt_server_pub";
16 |
17 | private MqttClient mqttClient = null;
18 | private MqttConnectOptions connectionOptions = null;
19 | private MemoryPersistence persistence = null;
20 |
21 | private static final Logger logger = LoggerFactory.getLogger(MQTTPublisher.class);
22 |
23 | /**
24 | * Private default constructor
25 | */
26 | private MQTTPublisher() {
27 | this.config();
28 | }
29 |
30 | /**
31 | * Private constructor
32 | */
33 | private MQTTPublisher(String broker, Integer port, Boolean ssl, Boolean withUserNamePass) {
34 | this.config(broker, port, ssl, withUserNamePass);
35 | }
36 |
37 | /**
38 | * Factory method to get instance of MQTTPublisher
39 | *
40 | * @return MQTTPublisher
41 | */
42 | public static MQTTPublisher getInstance() {
43 | return new MQTTPublisher();
44 | }
45 |
46 | /**
47 | * Factory method to get instance of MQTTPublisher
48 | *
49 | * @param broker
50 | * @param port
51 | * @param ssl
52 | * @param withUserNamePass
53 | * @return MQTTPublisher
54 | */
55 | public static MQTTPublisher getInstance(String broker, Integer port, Boolean ssl, Boolean withUserNamePass) {
56 | return new MQTTPublisher(broker, port, ssl, withUserNamePass);
57 | }
58 |
59 | /*
60 | * (non-Javadoc)
61 | *
62 | * @see
63 | * com.bjitgroup.jasmysp.mqtt.publisher.MQTTPublisherBase#configurePublisher()
64 | */
65 | @Override
66 | protected void config() {
67 |
68 | this.brokerUrl = this.TCP + this.broker + colon + this.port;
69 | this.persistence = new MemoryPersistence();
70 | this.connectionOptions = new MqttConnectOptions();
71 | try {
72 | this.mqttClient = new MqttClient(brokerUrl, clientId, persistence);
73 | this.connectionOptions.setCleanSession(true);
74 | this.mqttClient.connect(this.connectionOptions);
75 | this.mqttClient.setCallback(this);
76 | } catch (MqttException me) {
77 | logger.error("ERROR", me);
78 | }
79 | }
80 |
81 | /*
82 | * (non-Javadoc)
83 | *
84 | * @see
85 | * com.bjitgroup.jasmysp.mqtt.publisher.MQTTPublisherBase#configurePublisher(
86 | * java.lang.String, java.lang.Integer, java.lang.Boolean, java.lang.Boolean)
87 | */
88 | @Override
89 | protected void config(String broker, Integer port, Boolean ssl, Boolean withUserNamePass) {
90 |
91 | String protocal = this.TCP;
92 | if (true == ssl) {
93 | protocal = this.SSL;
94 | }
95 |
96 | this.brokerUrl = protocal + this.broker + colon + port;
97 | this.persistence = new MemoryPersistence();
98 | this.connectionOptions = new MqttConnectOptions();
99 |
100 | try {
101 | this.mqttClient = new MqttClient(brokerUrl, clientId, persistence);
102 | this.connectionOptions.setCleanSession(true);
103 | if (true == withUserNamePass) {
104 | if (password != null) {
105 | this.connectionOptions.setPassword(this.password.toCharArray());
106 | }
107 | if (userName != null) {
108 | this.connectionOptions.setUserName(this.userName);
109 | }
110 | }
111 | this.mqttClient.connect(this.connectionOptions);
112 | this.mqttClient.setCallback(this);
113 | } catch (MqttException me) {
114 | logger.error("ERROR", me);
115 | }
116 | }
117 |
118 |
119 | /*
120 | * (non-Javadoc)
121 | * @see com.monirthought.mqtt.publisher.MQTTPublisherBase#publishMessage(java.lang.String, java.lang.String)
122 | */
123 | @Override
124 | public void publishMessage(String topic, String message) {
125 |
126 | try {
127 | MqttMessage mqttmessage = new MqttMessage(message.getBytes());
128 | mqttmessage.setQos(this.qos);
129 | this.mqttClient.publish(topic, mqttmessage);
130 | } catch (MqttException me) {
131 | logger.error("ERROR", me);
132 | }
133 |
134 | }
135 |
136 | public void publish(String topic, byte[] message, int qos, boolean retained){
137 | try {
138 | this.mqttClient.publish(topic, message, qos, retained );
139 | } catch (MqttException e) {
140 | e.printStackTrace();
141 | }
142 | }
143 | /*
144 | * (non-Javadoc)
145 | * @see org.eclipse.paho.client.mqttv3.MqttCallback#connectionLost(java.lang.Throwable)
146 | */
147 | @Override
148 | public void connectionLost(Throwable arg0) {
149 | logger.info("Connection Lost");
150 |
151 | }
152 |
153 | /*
154 | * (non-Javadoc)
155 | * @see org.eclipse.paho.client.mqttv3.MqttCallback#deliveryComplete(org.eclipse.paho.client.mqttv3.IMqttDeliveryToken)
156 | */
157 | @Override
158 | public void deliveryComplete(IMqttDeliveryToken arg0) {
159 | logger.info("delivery completed");
160 |
161 | }
162 |
163 | /*
164 | * (non-Javadoc)
165 | * @see org.eclipse.paho.client.mqttv3.MqttCallback#messageArrived(java.lang.String, org.eclipse.paho.client.mqttv3.MqttMessage)
166 | */
167 | @Override
168 | public void messageArrived(String arg0, MqttMessage arg1) throws Exception {
169 | // Leave it blank for Publisher
170 |
171 | }
172 |
173 | /*
174 | * (non-Javadoc)
175 | * @see com.monirthought.mqtt.publisher.MQTTPublisherBase#disconnect()
176 | */
177 | @Override
178 | public void disconnect() {
179 | try {
180 | this.mqttClient.disconnect();
181 | } catch (MqttException me) {
182 | logger.error("ERROR", me);
183 | }
184 | }
185 |
186 | }
187 |
--------------------------------------------------------------------------------
/src/main/java/com/braincs/mqttprotobufserver/mqtt/MQTTSubscriber.java:
--------------------------------------------------------------------------------
1 | package com.braincs.mqttprotobufserver.mqtt;
2 |
3 | import com.braincs.kylinprotocol.pb.KylinProto;
4 | import com.braincs.mqttprotobufserver.utils.FileUtil;
5 | import org.eclipse.paho.client.mqttv3.*;
6 | import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import org.springframework.stereotype.Component;
10 |
11 | import java.sql.Timestamp;
12 | import java.text.SimpleDateFormat;
13 | import java.util.Date;
14 |
15 | @Component
16 | public class MQTTSubscriber extends MQTTConfig implements MqttCallback, IMQTTSubscriber {
17 |
18 | private String brokerUrl = null;
19 | final private String colon = ":";
20 | final private String clientId = "mqtt_server_sub";
21 | private final String folder = "/Users/changshuai/IdeaProjects/mqtt-protobuf-server/tmp";
22 | private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
23 | private MqttClient mqttClient = null;
24 | private MqttConnectOptions connectionOptions = null;
25 | private MemoryPersistence persistence = null;
26 |
27 | private static final Logger logger = LoggerFactory.getLogger(MQTTSubscriber.class);
28 |
29 | public MQTTSubscriber() {
30 | this.config();
31 | }
32 |
33 | /*
34 | * (non-Javadoc)
35 | *
36 | * @see org.eclipse.paho.client.mqttv3.MqttCallback#connectionLost(java.lang.
37 | * Throwable)
38 | */
39 | @Override
40 | public void connectionLost(Throwable cause) {
41 | logger.info("Connection Lost");
42 |
43 | }
44 |
45 | /*
46 | * (non-Javadoc)
47 | *
48 | * @see
49 | * org.eclipse.paho.client.mqttv3.MqttCallback#messageArrived(java.lang.String,
50 | * org.eclipse.paho.client.mqttv3.MqttMessage)
51 | */
52 | @Override
53 | public void messageArrived(String topic, MqttMessage message) throws Exception {
54 | // Called when a message arrives from the server that matches any
55 | // subscription made by the client
56 | System.out.println();
57 | System.out.println("***********************************************************************");
58 | String time = new Timestamp(System.currentTimeMillis()).toString();
59 | if (topic.endsWith("/in/recognize")) {
60 | System.out.println("Message Arrived at Time: " + time + " Topic: " + topic);
61 | KylinProto.Recognize recognize = KylinProto.Recognize.parseFrom(message.getPayload());
62 | byte[] data = recognize.getCrop().toByteArray();
63 | String dateStr = this.format.format(new Date());
64 | String saveFile = FileUtil.save(folder, "recognize_" + dateStr + ".jpg", data);
65 | System.out.println("saved success : " + saveFile);
66 | } else if (topic.endsWith("/in/snapshot")) {
67 | System.out.println("Message Arrived at Time: " + time + " Topic: " + topic);
68 | KylinProto.SnapShot snapShot = KylinProto.SnapShot.parseFrom(message.getPayload());
69 | byte[] data = snapShot.getImage().toByteArray();
70 | String dateStr = this.format.format(new Date());
71 | String saveFile = FileUtil.save(folder, "snapshot_" + dateStr + ".jpg", data);
72 | System.out.println("saved success : " + saveFile);
73 | } else if (topic.endsWith("/in/check")){
74 | System.out.println("Message Arrived at Time: " + time + " Topic: " + topic);
75 | KylinProto.Status status = KylinProto.Status.parseFrom(message.getPayload());
76 | System.out.println("received status : " + status.toString());
77 | } else {
78 | System.out.println("Message Arrived at Time: " + time + " Topic: " + topic + " Message: "
79 | + new String(message.getPayload()));
80 | }
81 | System.out.println("***********************************************************************");
82 | System.out.println();
83 | }
84 |
85 | /*
86 | * (non-Javadoc)
87 | *
88 | * @see
89 | * org.eclipse.paho.client.mqttv3.MqttCallback#deliveryComplete(org.eclipse.paho
90 | * .client.mqttv3.IMqttDeliveryToken)
91 | */
92 | @Override
93 | public void deliveryComplete(IMqttDeliveryToken token) {
94 | // Leave it blank for subscriber
95 |
96 | }
97 |
98 | /*
99 | * (non-Javadoc)
100 | *
101 | * @see
102 | * com.monirthought.mqtt.subscriber.MQTTSubscriberBase#subscribeMessage(java.
103 | * lang.String)
104 | */
105 | @Override
106 | public void subscribeMessage(String topic) {
107 | try {
108 | this.mqttClient.subscribe(topic, this.qos);
109 | } catch (MqttException me) {
110 | me.printStackTrace();
111 | }
112 | }
113 |
114 | /*
115 | * (non-Javadoc)
116 | *
117 | * @see com.monirthought.mqtt.subscriber.MQTTSubscriberBase#disconnect()
118 | */
119 | public void disconnect() {
120 | try {
121 | this.mqttClient.disconnect();
122 | } catch (MqttException me) {
123 | logger.error("ERROR", me);
124 | }
125 | }
126 |
127 | /*
128 | * (non-Javadoc)
129 | *
130 | * @see com.monirthought.config.MQTTConfig#config(java.lang.String,
131 | * java.lang.Integer, java.lang.Boolean, java.lang.Boolean)
132 | */
133 | @Override
134 | protected void config(String broker, Integer port, Boolean ssl, Boolean withUserNamePass) {
135 |
136 | String protocal = this.TCP;
137 | if (true == ssl) {
138 | protocal = this.SSL;
139 | }
140 |
141 | this.brokerUrl = protocal + this.broker + colon + port;
142 | this.persistence = new MemoryPersistence();
143 | this.connectionOptions = new MqttConnectOptions();
144 |
145 | try {
146 | this.mqttClient = new MqttClient(brokerUrl, clientId, persistence);
147 | this.connectionOptions.setCleanSession(true);
148 | if (true == withUserNamePass) {
149 | if (password != null) {
150 | this.connectionOptions.setPassword(this.password.toCharArray());
151 | }
152 | if (userName != null) {
153 | this.connectionOptions.setUserName(this.userName);
154 | }
155 | }
156 | this.mqttClient.connect(this.connectionOptions);
157 | this.mqttClient.setCallback(this);
158 | } catch (MqttException me) {
159 | me.printStackTrace();
160 | }
161 |
162 | }
163 |
164 | /*
165 | * (non-Javadoc)
166 | *
167 | * @see com.monirthought.config.MQTTConfig#config()
168 | */
169 | @Override
170 | protected void config() {
171 |
172 | this.brokerUrl = this.TCP + this.broker + colon + this.port;
173 | this.persistence = new MemoryPersistence();
174 | this.connectionOptions = new MqttConnectOptions();
175 | try {
176 | this.mqttClient = new MqttClient(brokerUrl, clientId, persistence);
177 | this.connectionOptions.setCleanSession(true);
178 | this.mqttClient.connect(this.connectionOptions);
179 | this.mqttClient.setCallback(this);
180 | } catch (MqttException me) {
181 | me.printStackTrace();
182 | }
183 |
184 | }
185 |
186 | }
--------------------------------------------------------------------------------
/src/main/java/com/braincs/mqttprotobufserver/mqtt/MqttConfig.java:
--------------------------------------------------------------------------------
1 | package com.braincs.mqttprotobufserver.mqtt;
2 |
3 | public abstract class MQTTConfig {
4 |
5 | protected final String broker = "10.156.2.132";
6 | protected final int qos = 2;
7 | protected Boolean hasSSL = false; /* By default SSL is disabled */
8 | protected Integer port = 1883; /* Default port */
9 | protected final String userName = "admin";
10 | protected final String password = "admin";
11 | protected final String TCP = "tcp://";
12 | protected final String SSL = "ssl://";
13 |
14 | /**
15 | * Custom Configuration
16 | *
17 | * @param broker
18 | * @param port
19 | * @param ssl
20 | * @param withUserNamePass
21 | */
22 | protected abstract void config(String broker, Integer port, Boolean ssl, Boolean withUserNamePass);
23 |
24 | /**
25 | * Default Configuration
26 | */
27 | protected abstract void config();
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/braincs/mqttprotobufserver/utils/FileUtil.java:
--------------------------------------------------------------------------------
1 | package com.braincs.mqttprotobufserver.utils;
2 |
3 | import java.io.File;
4 | import java.io.FileNotFoundException;
5 | import java.io.FileOutputStream;
6 | import java.io.IOException;
7 |
8 | public class FileUtil {
9 | public static String save(String path, String name, byte[] data) {
10 | File parent = new File(path);
11 | if (!parent.exists() ){//&& parent.isDirectory()
12 | parent.mkdirs();
13 | }
14 | FileOutputStream fos = null;
15 | File dstFile = new File(path, name);
16 | try{
17 | if (!dstFile.exists()){
18 | dstFile.createNewFile();
19 | }
20 | fos = new FileOutputStream(dstFile);
21 | fos.write(data);
22 | fos.close();
23 | } catch (IOException e) {
24 | e.printStackTrace();
25 | } finally {
26 | try {
27 | if (fos != null) {
28 | fos.close();
29 | }
30 | } catch (IOException e) {
31 | e.printStackTrace();
32 | }
33 | }
34 | return dstFile.getAbsolutePath();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/proto/mqtt.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | option java_package = "com.braincs.kylinprotocol.pb";
3 | option java_outer_classname = "KylinProto";
4 | package pb;
5 |
6 | message Rect {
7 | int32 left = 1;
8 | int32 top = 2;
9 | int32 width = 3;
10 | int32 height = 4;
11 | }
12 |
13 | message RectF {
14 | float left = 1;
15 | float top = 2;
16 | float width = 3;
17 | float height = 4;
18 | }
19 |
20 | message Response {
21 | int32 success = 1;
22 | string err = 2;
23 | }
24 |
25 | message Start {
26 | enum Mode {
27 | capture = 0;
28 | recognize = 1;
29 | }
30 | Mode mode = 1;
31 | bool is_open = 2;
32 | int32 health_check_interval = 3;
33 | }
34 |
35 | message Group {
36 | string group = 1;
37 | int32 top = 2;
38 | float threshold = 3;
39 | }
40 |
41 | message Face {
42 | string group = 1;
43 | string face = 2;
44 | string name = 3;
45 |
46 | string url = 10;
47 | bytes image = 100;
48 | }
49 |
50 | message Capture {
51 | int32 track = 1;
52 | int32 seq_num = 2;
53 |
54 | int64 timestamp = 10;
55 | float quality = 11;
56 |
57 | bytes crop = 100;
58 | RectF crop_rect = 101;
59 |
60 | bytes full = 200;
61 | }
62 |
63 | message Recognize {
64 | message Result {
65 | string face = 1;
66 | string name = 2;
67 |
68 | float score = 11;
69 | }
70 | repeated Result top = 1;
71 | string group = 2;
72 |
73 | bytes crop = 100;
74 | bytes full = 101;
75 | }
76 |
77 | message SnapShot {
78 | bytes image = 100;
79 | }
80 |
81 | message Upgrade {
82 | int32 timeout = 1;
83 | string url = 10;
84 | }
85 |
86 | message UpgradeProgress {
87 | int32 progress = 1;
88 | }
89 |
90 | message Status {
91 | string version = 1;
92 | string algorithm = 2;
93 |
94 | string local_ip = 10;
95 | }
--------------------------------------------------------------------------------
/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | # mqtt configs
2 | #mqtt.config.username=admin
3 | #mqtt.config.password=admin
4 | #mqtt.config.host=tcp://127.0.0.1:1883
5 | #mqtt.config.clientid=panel
6 | #mqtt.config.topic=start
7 | #mqtt.config.timeout=10
8 | #mqtt.config.keepalive=20
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/main/resources/static/static/test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/braincs/mqtt-protobuf-server/d20dcfdcc75e149b986a06729577b4dfc4327f63/src/main/resources/static/static/test.png
--------------------------------------------------------------------------------
/src/test/java/com/braincs/mqttprotobufserver/MqttProtobufServerApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.braincs.mqttprotobufserver;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | @RunWith(SpringRunner.class)
9 | @SpringBootTest
10 | public class MqttProtobufServerApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------