1
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
|
||||
package="io.dcloud.uni_modules.xMqttS">
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
</manifest>
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"minSdkVersion": "21",
|
||||
"dependencies":[
|
||||
"com.github.hannesa2:paho.mqtt.android:4.2.4"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
import MqttMessage from "org.eclipse.paho.client.mqttv3.MqttMessage";
|
||||
import MqttException from "org.eclipse.paho.client.mqttv3.MqttException";
|
||||
import MqttConnectOptions from "org.eclipse.paho.client.mqttv3.MqttConnectOptions";
|
||||
import MqttCallbackExtended from "org.eclipse.paho.client.mqttv3.MqttCallbackExtended";
|
||||
import IMqttToken from "org.eclipse.paho.client.mqttv3.IMqttToken";
|
||||
import IMqttMessageListener from "org.eclipse.paho.client.mqttv3.IMqttMessageListener";
|
||||
import IMqttDeliveryToken from "org.eclipse.paho.client.mqttv3.IMqttDeliveryToken";
|
||||
import IMqttActionListener from "org.eclipse.paho.client.mqttv3.IMqttActionListener";
|
||||
import DisconnectedBufferOptions from "org.eclipse.paho.client.mqttv3.DisconnectedBufferOptions";
|
||||
import MqttAndroidClient from "info.mqtt.android.service.MqttAndroidClient";
|
||||
import QoS from "info.mqtt.android.service.QoS";
|
||||
import MqttCallback from "org.eclipse.paho.client.mqttv3.MqttCallback";
|
||||
import Kotlin from 'kotlin.jvm.internal.Intrinsics.Kotlin';
|
||||
import Context from 'android.content.Context';
|
||||
import Intent from 'android.content.Intent';
|
||||
import MqttService from 'org.eclipse.paho.android.service.MqttService';
|
||||
import Service from 'android.app.Service';
|
||||
import IBinder from 'android.os.IBinder';
|
||||
import Build from 'android.os.Build';
|
||||
import {
|
||||
CONNECT_STATUS, MQTT_EVENT_TYPE, MQTT_EVENT_CALL, MQTT_EVENT_PUBLISH, MQTT_SUBSCRIBE, MQTT_EVENTS_CALL,
|
||||
MQTT_PUBLISH_TOPIC, MQTT_CONNECT_OPTS
|
||||
} from "../interface.uts"
|
||||
|
||||
|
||||
// <service android:name="org.eclipse.paho.android.service.MqttService"></service>
|
||||
|
||||
// mqtt测试服务器
|
||||
// https://console.hivemq.cloud/
|
||||
// https://github.com/hannesa2/paho.mqtt.android/blob/master/extendedSample/src/main/java/info/mqtt/android/extsample/MainActivity.kt
|
||||
|
||||
|
||||
// let context = UTSAndroid.getAppContext()! as Context
|
||||
// let serviceIntent = new Intent(UTSAndroid.getUniActivity()!, UTSAndroid.getJavaClass(MqttService));
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// context.startForegroundService(serviceIntent); // 对于 Android Oreo 及以上版本
|
||||
// } else {
|
||||
// context.startService(serviceIntent); // 对于 Android Oreo 以下版本
|
||||
// }
|
||||
|
||||
|
||||
|
||||
export class xMqtt {
|
||||
mqtt : MqttAndroidClient | null = null;
|
||||
mqttConnectOptions : MqttConnectOptions | null = null;
|
||||
connectStatus : CONNECT_STATUS = 'wait'
|
||||
events = new Map<string, MQTT_EVENTS_CALL>();
|
||||
constructor() { }
|
||||
/**
|
||||
* @param ulr {string} 连接地址
|
||||
* @param clientIdStr {string} 客户端id
|
||||
* @param username {string|null} 用户名称,如果不需要,设置为null即可
|
||||
* @param password {string|null} 登录密码,如果不需要,设置为null即可
|
||||
*/
|
||||
create(opts : MQTT_CONNECT_OPTS) : xMqtt {
|
||||
|
||||
let serverUri = opts.protocol + opts.server + ":" + opts.port.toString() + opts.path
|
||||
let clientId = opts.clientId
|
||||
this.mqttConnectOptions = new MqttConnectOptions() as MqttConnectOptions;
|
||||
if (this.mqttConnectOptions == null) return this;
|
||||
// 失败时,是否自动连接服务器。
|
||||
this.mqttConnectOptions!.isAutomaticReconnect = opts.reconnect
|
||||
|
||||
// 连接时是否清除会话
|
||||
this.mqttConnectOptions!.isCleanSession = false
|
||||
//超时
|
||||
this.mqttConnectOptions!.connectionTimeout = (opts.timeout * 100).toInt()
|
||||
//活跃间隔
|
||||
this.mqttConnectOptions!.setKeepAliveInterval(opts.keepAliveInterval.toInt())
|
||||
// 帐号名称
|
||||
if (opts.userName != '') {
|
||||
this.mqttConnectOptions!.setUserName(opts.userName!)
|
||||
}
|
||||
// 帐号密码
|
||||
if (opts.passWord != null) {
|
||||
this.mqttConnectOptions!.setPassword(opts.passWord!.toCharArray())
|
||||
}
|
||||
|
||||
this.mqtt = new MqttAndroidClient(UTSAndroid.getAppContext()!, serverUri, clientId);
|
||||
this.connectStatus = 'wait'
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* @param type {MQTT_EVENT_TYPE} 事件名称
|
||||
* @param call {MQTT_EVENT_CALL} 事件回调
|
||||
*/
|
||||
@UTSJS.keepAlive
|
||||
addEventListener(type : MQTT_EVENT_TYPE, call : MQTT_EVENT_CALL) : string {
|
||||
let id = Date.now().toString() + (Math.random() * 100).toString()
|
||||
this.events.set(id,
|
||||
{
|
||||
type,
|
||||
value: call
|
||||
} as MQTT_EVENTS_CALL
|
||||
)
|
||||
|
||||
return id;
|
||||
}
|
||||
/**
|
||||
* @param id {string} addEventListener返回的事件id
|
||||
*/
|
||||
removeEventListener(id : string) : xMqtt {
|
||||
this.events.delete(id)
|
||||
return this;
|
||||
}
|
||||
private buildCallEvents(type : MQTT_EVENT_TYPE, toppic : string | null, str : string) {
|
||||
this.events.forEach((value : MQTT_EVENTS_CALL, key : string) => {
|
||||
if (value.type == type) {
|
||||
value.value(type, toppic, str)
|
||||
}
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 连接mqtt服务器
|
||||
*/
|
||||
connect() : xMqtt {
|
||||
let t = this;
|
||||
if (this.mqtt == null) return this;
|
||||
try {
|
||||
class mqttCallBack implements MqttCallback {
|
||||
// 连接丢失
|
||||
override connectionLost(cause : kotlin.Throwable | null) {
|
||||
// console.log('Mqtt:Connection lost')
|
||||
t.connectStatus = 'dissconnect'
|
||||
t.buildCallEvents('dissconnect', null, '连接断开')
|
||||
}
|
||||
// 首次连接时收到的消息
|
||||
override messageArrived(topic : string, message : MqttMessage) {
|
||||
// console.log('Mqtt:', new String(message.getPayload()))
|
||||
}
|
||||
// 发布的消息是否已到达
|
||||
override deliveryComplete(token : IMqttDeliveryToken) {
|
||||
// console.log('Message delivered')
|
||||
}
|
||||
}
|
||||
class connectListen implements IMqttActionListener {
|
||||
// 连接成功
|
||||
override onSuccess(asyncActionToken : IMqttToken) {
|
||||
// console.log('Connected to MQTT broker',asyncActionToken)
|
||||
t.connectStatus = 'open'
|
||||
t.buildCallEvents('open', null, '连接成功')
|
||||
}
|
||||
// 连接失败
|
||||
override onFailure(asyncActionToken : IMqttToken, exception : kotlin.Throwable) {
|
||||
// console.log('Connected to MQTT Failed', exception)
|
||||
t.connectStatus = 'error'
|
||||
t.buildCallEvents('error', null, '连接失败')
|
||||
}
|
||||
}
|
||||
this.connectStatus = 'opening'
|
||||
this.mqtt!.setCallback(new mqttCallBack());
|
||||
this.mqtt!.connect(this.mqttConnectOptions!, null, new connectListen());
|
||||
} catch (e : kotlin.Throwable) {
|
||||
//TODO handle the exception
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
/**
|
||||
* 推送消息
|
||||
* @param call {MQTT_EVENT_PUBLISH}
|
||||
*/
|
||||
publish(msg : MQTT_PUBLISH_TOPIC, call : MQTT_EVENT_PUBLISH) : xMqtt {
|
||||
if (this.mqtt == null) return this;
|
||||
let topic = msg.topic
|
||||
let message = msg.message
|
||||
let mqttMessage = new MqttMessage(message.toByteArray());
|
||||
// 设置消息服务质量等级0,1,2
|
||||
mqttMessage.setQos(msg.qos.toInt());
|
||||
// 设置消息是否需要被服务器持久化
|
||||
mqttMessage.setRetained(msg.retained);
|
||||
|
||||
class messageListen implements IMqttActionListener {
|
||||
override onSuccess(asyncActionToken : IMqttToken) {
|
||||
console.log(topic, '发布成功')
|
||||
call(true)
|
||||
}
|
||||
override onFailure(asyncActionToken : IMqttToken, exception : kotlin.Throwable) {
|
||||
console.log(topic, '发布失败', exception)
|
||||
call(false)
|
||||
}
|
||||
}
|
||||
this.mqtt!.publish(topic, mqttMessage, null, new messageListen());
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 订阅
|
||||
* @param data {MQTT_SUBSCRIBE[]} 订阅的消息数组
|
||||
*/
|
||||
subscribe(data : MQTT_SUBSCRIBE[]) : xMqtt {
|
||||
let t = this;
|
||||
if (this.mqtt == null) return this;
|
||||
let msglisten = [] as IMqttMessageListener[];
|
||||
let tops = [] as string[]
|
||||
let qos = new IntArray(data.length.toInt())
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
class messageListen implements IMqttMessageListener {
|
||||
override messageArrived(topic : string, message : MqttMessage) {
|
||||
// 处理消息
|
||||
let data = message.getPayload();
|
||||
|
||||
t.buildCallEvents('message', topic, String(data))
|
||||
}
|
||||
}
|
||||
msglisten.push(new messageListen())
|
||||
tops.push(data[i].topic)
|
||||
qos.set(i.toInt(), data[i].qos.toInt())
|
||||
}
|
||||
|
||||
let token : IMqttToken = this.mqtt!.subscribe(tops.toTypedArray(), qos, msglisten.toTypedArray())
|
||||
if (token.isComplete()) {
|
||||
console.log("订阅成功")
|
||||
}
|
||||
return this;
|
||||
|
||||
}
|
||||
/**
|
||||
* 取消订阅
|
||||
* @param topics {string[]} 主题数组
|
||||
*/
|
||||
unsubscribe(topics : string[]) : xMqtt {
|
||||
let t = this;
|
||||
if (this.mqtt == null || topics.length == 0) return this;
|
||||
this.mqtt!.unsubscribe(topics.toTypedArray())
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 断开连接
|
||||
*/
|
||||
disconnect() : xMqtt {
|
||||
if (this.mqtt == null) return this;
|
||||
this.mqtt!.disconnect()
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"x_mqtt_s": "./lib/x_mqtt_s.har"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
import {
|
||||
CONNECT_STATUS, MQTT_EVENT_TYPE, MQTT_EVENT_CALL, MQTT_EVENT_PUBLISH, MQTT_SUBSCRIBE, MQTT_EVENTS_CALL,
|
||||
MQTT_PUBLISH_TOPIC, MQTT_CONNECT_OPTS
|
||||
} from "../interface.uts"
|
||||
import { x_xMqtt } from "x_mqtt_s"
|
||||
|
||||
export class xMqtt {
|
||||
mqtt : x_xMqtt | null = null;
|
||||
mqttConnectOptions : MQTT_CONNECT_OPTS | null = null;
|
||||
connectStatus : CONNECT_STATUS = 'wait'
|
||||
events = new Map<string, MQTT_EVENTS_CALL>();
|
||||
constructor() { }
|
||||
/**
|
||||
* @param ulr {string} 连接地址
|
||||
* @param clientIdStr {string} 客户端id
|
||||
* @param username {string|null} 用户名称,如果不需要,设置为null即可
|
||||
* @param password {string|null} 登录密码,如果不需要,设置为null即可
|
||||
*/
|
||||
create(opts : MQTT_CONNECT_OPTS) : xMqtt {
|
||||
this.mqttConnectOptions = opts;
|
||||
this.mqtt = new x_xMqtt(UTSHarmony.getCurrentWindow()!.getUIContext(), this.mqttConnectOptions!)
|
||||
this.mqtt!.setCallBack((type: string, topic: string | null, str: string)=>{
|
||||
console.log('88888',str)
|
||||
this.buildCallEvents(type as MQTT_EVENT_TYPE,topic,str)
|
||||
})
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* @param type {MQTT_EVENT_TYPE} 事件名称
|
||||
* @param call {MQTT_EVENT_CALL} 事件回调
|
||||
*/
|
||||
addEventListener(type:MQTT_EVENT_TYPE,call:MQTT_EVENT_CALL):string{
|
||||
let id = Date.now().toString()+(Math.random()*100).toString()
|
||||
this.events.set(id,
|
||||
{
|
||||
type,
|
||||
value:call
|
||||
} as MQTT_EVENTS_CALL
|
||||
)
|
||||
|
||||
return id;
|
||||
}
|
||||
/**
|
||||
* @param id {string} addEventListener返回的事件id
|
||||
*/
|
||||
removeEventListener(id:string):xMqtt{
|
||||
this.events.delete(id)
|
||||
return this;
|
||||
}
|
||||
private buildCallEvents(type:MQTT_EVENT_TYPE,toppic:string|null,str:string){
|
||||
this.events.forEach((value:MQTT_EVENTS_CALL,key:string)=>{
|
||||
if(value.type == type){
|
||||
value.value(type,toppic,str)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
connect():xMqtt{
|
||||
this.mqtt!.connect();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 订阅
|
||||
* @param data {MQTT_SUBSCRIBE[]} 订阅的消息数组
|
||||
*/
|
||||
subscribe(data:MQTT_SUBSCRIBE[]):xMqtt{
|
||||
this.mqtt!.subscribe(data)
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 推送消息
|
||||
* @param message {MQTT_EVENT_PUBLISH}
|
||||
* @param call ()=>void 推送消息成功时的回调【web端永为真】
|
||||
*/
|
||||
publish(message:MQTT_PUBLISH_TOPIC,call:MQTT_EVENT_PUBLISH):xMqtt{
|
||||
this.mqtt!.publish(message,call)
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 取消订阅
|
||||
* @param topics {string[]} 主题数组
|
||||
*/
|
||||
unsubscribe(topics:string[]):xMqtt{
|
||||
this.mqtt!.unsubscribe(topics)
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 断开连接
|
||||
*/
|
||||
disconnect():xMqtt{
|
||||
if(this.mqtt == null) return this;
|
||||
this.mqtt!.disconnect()
|
||||
return this;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPITypes</key>
|
||||
<array/>
|
||||
<key>NSPrivacyCollectedDataTypes</key>
|
||||
<array/>
|
||||
<key>NSPrivacyTracking</key>
|
||||
<false/>
|
||||
<key>NSPrivacyTrackingDomains</key>
|
||||
<array/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,212 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>files</key>
|
||||
<dict>
|
||||
<key>Headers/unimoduleXMqttS-Swift.h</key>
|
||||
<data>
|
||||
us3c7FdOtvvpxAdVgLk4pWNuwOA=
|
||||
</data>
|
||||
<key>Headers/unimoduleXMqttS.h</key>
|
||||
<data>
|
||||
FH2SRnQAHIO8AbDZPa5/Bz/CcdA=
|
||||
</data>
|
||||
<key>Info.plist</key>
|
||||
<data>
|
||||
UQNJ7jyX3QAsqknIpAm6FCxq3WA=
|
||||
</data>
|
||||
<key>Modules/module.modulemap</key>
|
||||
<data>
|
||||
GNmBhr+kPC7jCw5hmJ/XWlcQ90o=
|
||||
</data>
|
||||
<key>Modules/unimoduleXMqttS.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo</key>
|
||||
<data>
|
||||
5PJpCvFI3hp5mYermg/rG/zQlIk=
|
||||
</data>
|
||||
<key>Modules/unimoduleXMqttS.swiftmodule/x86_64-apple-ios-simulator.abi.json</key>
|
||||
<data>
|
||||
j8wYwGynekAGd/D50u+hNETt9Uw=
|
||||
</data>
|
||||
<key>Modules/unimoduleXMqttS.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface</key>
|
||||
<data>
|
||||
DlWqI5eYTqgv8qwdIj208giOfrE=
|
||||
</data>
|
||||
<key>Modules/unimoduleXMqttS.swiftmodule/x86_64-apple-ios-simulator.swiftdoc</key>
|
||||
<data>
|
||||
1K+l3rq/J9hvut58H8vgiWTjR/I=
|
||||
</data>
|
||||
<key>Modules/unimoduleXMqttS.swiftmodule/x86_64-apple-ios-simulator.swiftinterface</key>
|
||||
<data>
|
||||
DlWqI5eYTqgv8qwdIj208giOfrE=
|
||||
</data>
|
||||
<key>Modules/unimoduleXMqttS.swiftmodule/x86_64-apple-ios-simulator.swiftmodule</key>
|
||||
<data>
|
||||
nUELKkTPB2lwDB0G0YefuZFhBZ8=
|
||||
</data>
|
||||
<key>config.json</key>
|
||||
<data>
|
||||
86zzbbpH14xDJT7XFihyGwNWXhM=
|
||||
</data>
|
||||
</dict>
|
||||
<key>files2</key>
|
||||
<dict>
|
||||
<key>Headers/unimoduleXMqttS-Swift.h</key>
|
||||
<dict>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
Md5kS0WFiaXtbeTSKO/8du82DglwsOS5TY+BDmh79tI=
|
||||
</data>
|
||||
</dict>
|
||||
<key>Headers/unimoduleXMqttS.h</key>
|
||||
<dict>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
XAsze1m7Z4PhyI2gj+RafZVS4xyqWjgvqraTawdVPMY=
|
||||
</data>
|
||||
</dict>
|
||||
<key>Modules/module.modulemap</key>
|
||||
<dict>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
SM0R5ohUl4WWA6FqKV7y4wdGy+fRoO/nHbdNP7N7xdo=
|
||||
</data>
|
||||
</dict>
|
||||
<key>Modules/unimoduleXMqttS.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo</key>
|
||||
<dict>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
BVFOw0ORUqXAggKQ8xJIR5bEa9t+1V0HfJITJkZG1yQ=
|
||||
</data>
|
||||
</dict>
|
||||
<key>Modules/unimoduleXMqttS.swiftmodule/x86_64-apple-ios-simulator.abi.json</key>
|
||||
<dict>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
NKt0ctJcSMY3hJt34jWIJU6abzw2KGbtnpNeGTT2cOE=
|
||||
</data>
|
||||
</dict>
|
||||
<key>Modules/unimoduleXMqttS.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface</key>
|
||||
<dict>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
yjSDkB3gJt5oO5/gvlxhx+RCJpV1ImEsfQ02JY3k8gA=
|
||||
</data>
|
||||
</dict>
|
||||
<key>Modules/unimoduleXMqttS.swiftmodule/x86_64-apple-ios-simulator.swiftdoc</key>
|
||||
<dict>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
6rl/O8hn+LP0gdZdxwkODD88w3vBOthyKojL1GlpeH0=
|
||||
</data>
|
||||
</dict>
|
||||
<key>Modules/unimoduleXMqttS.swiftmodule/x86_64-apple-ios-simulator.swiftinterface</key>
|
||||
<dict>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
yjSDkB3gJt5oO5/gvlxhx+RCJpV1ImEsfQ02JY3k8gA=
|
||||
</data>
|
||||
</dict>
|
||||
<key>Modules/unimoduleXMqttS.swiftmodule/x86_64-apple-ios-simulator.swiftmodule</key>
|
||||
<dict>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
trB/R39AmC8X7aLYvod7ARDXu7T+ztP6Fm8XVQfjcD0=
|
||||
</data>
|
||||
</dict>
|
||||
<key>config.json</key>
|
||||
<dict>
|
||||
<key>hash2</key>
|
||||
<data>
|
||||
UHsnIaXxl3l3rh1rB45DjCJk/E1Wnk5h+/9qtjl7vfQ=
|
||||
</data>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>rules</key>
|
||||
<dict>
|
||||
<key>^.*</key>
|
||||
<true/>
|
||||
<key>^.*\.lproj/</key>
|
||||
<dict>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1000</real>
|
||||
</dict>
|
||||
<key>^.*\.lproj/locversion.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1100</real>
|
||||
</dict>
|
||||
<key>^Base\.lproj/</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>1010</real>
|
||||
</dict>
|
||||
<key>^version.plist$</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>rules2</key>
|
||||
<dict>
|
||||
<key>.*\.dSYM($|/)</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>11</real>
|
||||
</dict>
|
||||
<key>^(.*/)?\.DS_Store$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>2000</real>
|
||||
</dict>
|
||||
<key>^.*</key>
|
||||
<true/>
|
||||
<key>^.*\.lproj/</key>
|
||||
<dict>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1000</real>
|
||||
</dict>
|
||||
<key>^.*\.lproj/locversion.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1100</real>
|
||||
</dict>
|
||||
<key>^Base\.lproj/</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>1010</real>
|
||||
</dict>
|
||||
<key>^Info\.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^PkgInfo$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^embedded\.provisionprofile$</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^version\.plist$</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,22 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
||||
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
||||
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
||||
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
||||
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
||||
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
||||
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
||||
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
||||
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
||||
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
||||
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
||||
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
||||
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
||||
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,285 @@
|
||||
import {
|
||||
CONNECT_STATUS, MQTT_EVENT_TYPE, MQTT_EVENT_CALL, MQTT_EVENT_PUBLISH, MQTT_SUBSCRIBE, MQTT_EVENTS_CALL,
|
||||
MQTT_PUBLISH_TOPIC, MQTT_CONNECT_OPTS
|
||||
} from "../interface.uts"
|
||||
import {
|
||||
CocoaMQTT, CocoaMQTTWebSocket, CocoaMQTT5Delegate, CocoaMQTT5, MqttConnectProperties,
|
||||
CocoaMQTTDISCONNECTReasonCode,
|
||||
CocoaMQTTAUTHReasonCode,
|
||||
MqttDecodeUnsubAck,
|
||||
MqttDecodeSubAck,
|
||||
CocoaMQTT5Message,
|
||||
MqttDecodePublish,
|
||||
MqttDecodePubAck,
|
||||
MqttDecodePubRec,
|
||||
MqttDecodeConnAck,
|
||||
CocoaMQTTCONNACKReasonCode,
|
||||
CocoaMQTTConnState,
|
||||
CocoaMQTTQoS, MqttPublishProperties, CocoaMQTTError, CocoaMQTTMessage
|
||||
|
||||
} from "CocoaMQTT"
|
||||
|
||||
// https://github.com/anatoliykant/SwiftMQTT
|
||||
import { UInt16 } from 'Swift';
|
||||
import { Bundle, CFArray, SecPKCS12Import } from 'Foundation';
|
||||
import { kCFStreamSSLCertificates } from 'CFNetwork';
|
||||
import { NSObject } from 'ObjectiveC';
|
||||
|
||||
|
||||
// https://github.com/emqx/CocoaMQTT
|
||||
// https://cocoapods.org/pods/CocoaMQTT
|
||||
// 文档:https://www.emqx.com/en/blog/ios-mqtt5-client
|
||||
|
||||
|
||||
class MQTTDELETED implements CocoaMQTT5Delegate {
|
||||
// 授权状态
|
||||
mqtt5(mqtt5 : CocoaMQTT5, @argumentLabel("didReceiveAuthReasonCode") reasonCode : CocoaMQTTAUTHReasonCode) {
|
||||
console.log(4)
|
||||
}
|
||||
// 连接丢失状态
|
||||
mqtt5(mqtt5 : CocoaMQTT5, @argumentLabel("didReceiveDisconnectReasonCode") reasonCode : CocoaMQTTDISCONNECTReasonCode) {
|
||||
console.log(3)
|
||||
}
|
||||
// 取消订阅 MqttDecodeUnsubAck
|
||||
mqtt5(mqtt5 : CocoaMQTT5, @argumentLabel("didUnsubscribeTopics") topics : string[], unsubAckData : any) {
|
||||
console.log(2)
|
||||
}
|
||||
// 订阅 MqttDecodeSubAck
|
||||
mqtt5(mqtt5 : CocoaMQTT5, @argumentLabel("didSubscribeTopics") success : NSDictionary, failed : string[], subAckData : any) {
|
||||
console.log(1)
|
||||
}
|
||||
// 收到消息 MqttDecodePublish
|
||||
mqtt5(mqtt5 : CocoaMQTT5, @argumentLabel("didReceiveMessage") message : CocoaMQTT5Message, id : number, publishData : any) {
|
||||
console.log(8)
|
||||
}
|
||||
// 重复发送消息 MqttDecodePubRec
|
||||
mqtt5(mqtt5 : CocoaMQTT5, @argumentLabel("didPublishRec") id : number, pubRecData : any) {
|
||||
console.log(8)
|
||||
}
|
||||
// 推送消息异常 MqttDecodePubAck
|
||||
mqtt5(mqtt5 : CocoaMQTT5, @argumentLabel("didPublishAck") id : number, pubAckData : any) {
|
||||
console.log(8)
|
||||
}
|
||||
// 推送消息
|
||||
mqtt5(mqtt5 : CocoaMQTT5, @argumentLabel("didPublishMessage") message : CocoaMQTT5Message, id : number) {
|
||||
console.log(8)
|
||||
}
|
||||
|
||||
// 推送消息 MqttDecodeConnAck
|
||||
mqtt5(mqtt5 : CocoaMQTT5, @argumentLabel("didConnectAck") ack : CocoaMQTTCONNACKReasonCode, connAckData : any) {
|
||||
console.log(8)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
let xmqtt : CocoaMQTT | null = null
|
||||
const connectDeleted : MQTTDELETED | null = null;
|
||||
export class xMqtt {
|
||||
mqtt : CocoaMQTT | null = null;
|
||||
mqttConnectOptions : MqttConnectProperties | null = null;
|
||||
connectStatus : CONNECT_STATUS = 'wait'
|
||||
events = new Map<string, MQTT_EVENTS_CALL>();
|
||||
constructor() { }
|
||||
|
||||
|
||||
/**
|
||||
* @param type {MQTT_EVENT_TYPE} 事件名称
|
||||
* @param call {MQTT_EVENT_CALL} 事件回调
|
||||
*/
|
||||
@UTSJS.keepAlive
|
||||
addEventListener(type : MQTT_EVENT_TYPE, call : MQTT_EVENT_CALL) : string {
|
||||
let id = Date.now().toString() + (Math.random() * 100).toString()
|
||||
this.events.set(id,
|
||||
{
|
||||
type,
|
||||
value: call
|
||||
} as MQTT_EVENTS_CALL
|
||||
)
|
||||
|
||||
return id;
|
||||
}
|
||||
/**
|
||||
* @param id {string} addEventListener返回的事件id
|
||||
*/
|
||||
removeEventListener(id : string) : xMqtt {
|
||||
this.events.delete(id)
|
||||
return this;
|
||||
}
|
||||
|
||||
private buildCallEvents(type : MQTT_EVENT_TYPE, toppic : string | null, str : string) {
|
||||
this.events.forEach((value : MQTT_EVENTS_CALL, key : string) => {
|
||||
if (value.type == type) {
|
||||
value.value(type, toppic, str)
|
||||
}
|
||||
})
|
||||
}
|
||||
create(opts : MQTT_CONNECT_OPTS) : xMqtt {
|
||||
let t = this;
|
||||
|
||||
let clientID = opts.clientId!
|
||||
let websocket = CocoaMQTTWebSocket(uri = opts.path)
|
||||
let mqtt5 = new CocoaMQTT(clientID = clientID, host = opts.server, port = opts.port!.toUInt16(), socket = websocket)
|
||||
mqtt5.willMessage = new CocoaMQTTMessage(topic = "/will", string = "dieout")
|
||||
|
||||
// let connectProperties = MqttConnectProperties()
|
||||
// connectProperties.topicAliasMaximum = 0
|
||||
// connectProperties.sessionExpiryInterval = 0
|
||||
// connectProperties.receiveMaximum = 100
|
||||
// connectProperties.maximumPacketSize = 5000
|
||||
// mqtt5.connectProperties = connectProperties
|
||||
mqtt5.username = opts.userName
|
||||
mqtt5.password = opts.passWord
|
||||
mqtt5.keepAlive = opts.keepAliveInterval.toUInt16()
|
||||
mqtt5.enableSSL = opts.useSSL
|
||||
mqtt5.autoReconnect = opts.reconnect
|
||||
mqtt5.allowUntrustCACertificate = true
|
||||
let sslCart = opts.certName==null?"":(opts.certName)
|
||||
let isP12 = false;
|
||||
// let sslSettings = new Map<string, NSObject>()
|
||||
if (sslCart != "" && opts.useSSL) {
|
||||
isP12 = sslCart.lastIndexOf(".p12") > -1;
|
||||
if (isP12) {
|
||||
let passwordSsl = opts.certPassword == null ? "" : (opts.certPassword)
|
||||
if (passwordSsl != "") {
|
||||
let crtpath = Bundle.main.path(forResource = String(sslCart.substring(0, sslCart.lastIndexOf("."))), ofType = "p12")
|
||||
let temsslSettings = getClientCertFromP12File(resourcePath = crtpath == null ? "" : (crtpath!), certPassword = String(passwordSsl))
|
||||
if (temsslSettings != null) {
|
||||
mqtt5.sslSettings = temsslSettings!
|
||||
} else {
|
||||
console.error("提供的P12证书有误或者文件不存在.")
|
||||
}
|
||||
} else {
|
||||
console.error("提供了p12证书,但未提供证书密码.")
|
||||
}
|
||||
} else {
|
||||
let crtpath = Bundle.main.path(forResource = String(sslCart.substring(0, sslCart.lastIndexOf("."))), ofType = "crt")
|
||||
|
||||
// ca文件.
|
||||
let temsslSettings = getClientCertFromCrtFile(resourcePath = crtpath == null ? "" : (crtpath!))
|
||||
if (temsslSettings != null) {
|
||||
// console.log(temsslSettings)
|
||||
mqtt5.sslSettings = temsslSettings!
|
||||
} else {
|
||||
console.error("提供的Ca证书有误或者文件不存在.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mqtt5.cleanSession = true
|
||||
// mqtt5.delegate = new MQTTDELETED()
|
||||
mqtt5.didDisconnect = (client : CocoaMQTT, errorcode ?: any) => {
|
||||
let code = errorcode as CocoaMQTTError | null
|
||||
|
||||
if (errorcode instanceof CocoaMQTTError) {
|
||||
t.connectStatus = 'error'
|
||||
t.buildCallEvents('error', null, '连接错误')
|
||||
|
||||
} else {
|
||||
t.connectStatus = 'error'
|
||||
t.buildCallEvents('error', null, '地址错误,或者没有网络。')
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mqtt5.didConnectAck = (client : CocoaMQTT, cack ?: any) => {
|
||||
t.connectStatus = 'open'
|
||||
t.buildCallEvents('open', null, '已连接')
|
||||
|
||||
|
||||
console.log('success')
|
||||
}
|
||||
mqtt5.didChangeState = (client : CocoaMQTT, state : CocoaMQTTConnState) => {
|
||||
if (state == CocoaMQTTConnState.connecting) {
|
||||
console.log('连接中')
|
||||
}
|
||||
if (state == CocoaMQTTConnState.connected) {
|
||||
console.log('连接成功')
|
||||
}
|
||||
if (state == CocoaMQTTConnState.disconnected) {
|
||||
console.log('连接失败')
|
||||
t.connectStatus = 'dissconnect'
|
||||
t.buildCallEvents('dissconnect', null, '已断开连接')
|
||||
}
|
||||
}
|
||||
|
||||
mqtt5.didReceiveMessage = (client : CocoaMQTT, message : CocoaMQTTMessage, id : UInt16) => {
|
||||
let topic = message.topic
|
||||
let msg = message.string
|
||||
t.connectStatus = 'message'
|
||||
t.buildCallEvents('message', topic, msg == null ? '' : (msg!))
|
||||
}
|
||||
|
||||
|
||||
|
||||
this.mqtt = mqtt5;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
connect() : xMqtt {
|
||||
if (this.mqtt == null) return this;
|
||||
this.mqtt!.connect()
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 推送消息
|
||||
* @param call {MQTT_EVENT_PUBLISH}
|
||||
*/
|
||||
publish(msg : MQTT_PUBLISH_TOPIC, call : MQTT_EVENT_PUBLISH) : xMqtt {
|
||||
if (this.mqtt == null) return this;
|
||||
let topic = msg.topic
|
||||
let message = msg.message
|
||||
let qos : CocoaMQTTQoS = CocoaMQTTQoS.qos0
|
||||
if (msg.qos == 1) {
|
||||
qos = CocoaMQTTQoS.qos1
|
||||
} else if (msg.qos == 2) {
|
||||
qos = CocoaMQTTQoS.qos2
|
||||
}
|
||||
this.mqtt!.publish(new CocoaMQTTMessage(topic = topic!, string = message!, qos = qos, retained = msg.retained))
|
||||
call(true)
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 订阅
|
||||
* @param data {MQTT_SUBSCRIBE[]} 订阅的消息数组
|
||||
*/
|
||||
subscribe(data : MQTT_SUBSCRIBE[]) : xMqtt {
|
||||
let t = this;
|
||||
if (this.mqtt == null) return this;
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let qos : CocoaMQTTQoS = CocoaMQTTQoS.qos0
|
||||
if (data[i].qos == 1) {
|
||||
qos = CocoaMQTTQoS.qos1
|
||||
} else if (data[i].qos == 2) {
|
||||
qos = CocoaMQTTQoS.qos2
|
||||
}
|
||||
this.mqtt!.subscribe(data[i].topic, qos = qos)
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消订阅
|
||||
* @param topics {string[]} 主题数组
|
||||
*/
|
||||
unsubscribe(topics : string[]) : xMqtt {
|
||||
if (this.mqtt == null) return this;
|
||||
for (let i = 0; i < topics.length; i++) {
|
||||
this.mqtt!.unsubscribe(topics[i])
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 断开连接
|
||||
*/
|
||||
disconnect() : xMqtt {
|
||||
if (this.mqtt == null) return this;
|
||||
this.mqtt!.disconnect()
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"deploymentTarget": "12",
|
||||
"dependencies-pods": [
|
||||
{
|
||||
"name": "CocoaMQTT/WebSockets",
|
||||
"version": "2.1.6"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
import {
|
||||
CONNECT_STATUS, MQTT_EVENT_TYPE, MQTT_EVENT_CALL, MQTT_EVENT_PUBLISH, MQTT_SUBSCRIBE, MQTT_EVENTS_CALL,
|
||||
MQTT_PUBLISH_TOPIC, MQTT_CONNECT_OPTS
|
||||
} from "../interface.uts"
|
||||
import {
|
||||
CocoaMQTT, CocoaMQTTWebSocket, CocoaMQTT5Delegate, CocoaMQTT5, MqttConnectProperties,
|
||||
CocoaMQTTDISCONNECTReasonCode,
|
||||
CocoaMQTTAUTHReasonCode,
|
||||
MqttDecodeUnsubAck,
|
||||
MqttDecodeSubAck,
|
||||
CocoaMQTT5Message,
|
||||
MqttDecodePublish,
|
||||
MqttDecodePubAck,
|
||||
MqttDecodePubRec,
|
||||
MqttDecodeConnAck,
|
||||
CocoaMQTTCONNACKReasonCode,
|
||||
CocoaMQTTConnState,
|
||||
CocoaMQTTQoS, MqttPublishProperties, CocoaMQTTError, CocoaMQTTMessage
|
||||
|
||||
} from "CocoaMQTT"
|
||||
|
||||
// https://github.com/anatoliykant/SwiftMQTT
|
||||
import { UInt16 } from 'Swift';
|
||||
import { Bundle, CFArray, NSDictionary, SecPKCS12Import } from 'Foundation';
|
||||
import { kCFStreamSSLCertificates } from 'CFNetwork';
|
||||
import { NSObject } from 'ObjectiveC';
|
||||
|
||||
|
||||
// https://github.com/emqx/CocoaMQTT
|
||||
// https://cocoapods.org/pods/CocoaMQTT
|
||||
// 文档:https://www.emqx.com/en/blog/ios-mqtt5-client
|
||||
|
||||
|
||||
|
||||
export class xMqtt {
|
||||
mqtt:XMqttHelp = new XMqttHelp();
|
||||
mqttConnectOptions : MqttConnectProperties | null = null;
|
||||
connectStatus : CONNECT_STATUS = 'wait'
|
||||
constructor() { }
|
||||
/**
|
||||
* @param type {MQTT_EVENT_TYPE} 事件名称
|
||||
* @param call {MQTT_EVENT_CALL} 事件回调
|
||||
*/
|
||||
@UTSJS.keepAlive
|
||||
addEventListener(type : MQTT_EVENT_TYPE, call : MQTT_EVENT_CALL) : string {
|
||||
@escaping
|
||||
return this.mqtt.addEventListener(
|
||||
type,
|
||||
callback = call);
|
||||
}
|
||||
/**
|
||||
* @param id {string} addEventListener返回的事件id
|
||||
*/
|
||||
removeEventListener(id : string) : xMqtt {
|
||||
this.mqtt.removeEventListener(id)
|
||||
return this;
|
||||
}
|
||||
|
||||
private buildCallEvents() {
|
||||
@escaping
|
||||
this.mqtt.setCallBack(()=>{
|
||||
this.connectStatus = this.mqtt.getStatus();
|
||||
console.log(this.connectStatus)
|
||||
})
|
||||
}
|
||||
create(opts : MQTT_CONNECT_OPTS) : xMqtt {
|
||||
let optsjson = JSON.parseObject(JSON.stringify(opts)!)!;
|
||||
const realJson = {...optsjson,allowUntrustCACertificate:opts.allowUntrustCACertificate==true,protocol:opts.useSSL?'wss':'ws'}
|
||||
this.mqtt.create(realJson.toMap() as NSDictionary)
|
||||
this.buildCallEvents()
|
||||
return this;
|
||||
}
|
||||
connect() : xMqtt {
|
||||
// if (this.mqtt.getStatus()!='dissconnect'&&this.mqtt.getStatus()!='error') return this;
|
||||
this.mqtt.connect()
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 推送消息
|
||||
* @param call {MQTT_EVENT_PUBLISH}
|
||||
*/
|
||||
publish(msg : MQTT_PUBLISH_TOPIC, call : MQTT_EVENT_PUBLISH) : xMqtt {
|
||||
// if (this.mqtt.getStatus() != 'open' && this.mqtt.getStatus() != 'message') return this;
|
||||
@escaping
|
||||
this.mqtt.publish(
|
||||
msg.topic,
|
||||
message = msg.message,
|
||||
qos = msg.qos.toInt(),
|
||||
retained=msg.retained,
|
||||
completion = (ok:boolean)=>{
|
||||
console.log('ok',ok)
|
||||
call(ok)
|
||||
}
|
||||
)
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 订阅
|
||||
* @param data {MQTT_SUBSCRIBE[]} 订阅的消息数组
|
||||
*/
|
||||
subscribe(data : MQTT_SUBSCRIBE[]) : xMqtt {
|
||||
// if (this.mqtt.getStatus() != 'open' && this.mqtt.getStatus() != 'message') return this;
|
||||
let d:NSDictionary[] = [];
|
||||
data.forEach(el=>{
|
||||
let p = JSON.parseObject(JSON.stringify(el)!)!.toMap();
|
||||
let qos = p.get('qos')! as number
|
||||
p.set('qos',qos.toInt())
|
||||
d.push(p as NSDictionary)
|
||||
})
|
||||
this.mqtt.subscribe(d)
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消订阅
|
||||
* @param topics {string[]} 主题数组
|
||||
*/
|
||||
unsubscribe(topics : string[]) : xMqtt {
|
||||
// if (this.mqtt.getStatus() != 'open' && this.mqtt.getStatus() != 'message') return this;
|
||||
this.mqtt.unsubscribe(topics)
|
||||
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 断开连接
|
||||
*/
|
||||
disconnect() : xMqtt {
|
||||
this.mqtt.disconnect();
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
|
||||
</plist>
|
||||
@@ -0,0 +1,122 @@
|
||||
import Foundation
|
||||
import Security
|
||||
// UTS内置对象的引用
|
||||
import DCloudUTSFoundation
|
||||
func getClientCertFromP12File(resourcePath: String, certPassword: String) -> [String: NSObject]? {
|
||||
do {
|
||||
// 读取证书文件数据
|
||||
let p12Data = try Data(contentsOf: URL(fileURLWithPath: resourcePath))
|
||||
|
||||
// 创建密钥字典用于读取p12文件
|
||||
let key = kSecImportExportPassphrase as String
|
||||
let options : NSDictionary = [key: certPassword]
|
||||
|
||||
var items : CFArray?
|
||||
let securityError = SecPKCS12Import(p12Data as NSData, options, &items)
|
||||
|
||||
guard securityError == errSecSuccess else {
|
||||
if securityError == errSecAuthFailed {
|
||||
console.log("ERROR: SecPKCS12Import returned errSecAuthFailed. Incorrect password?")
|
||||
} else {
|
||||
console.log("Failed to open the certificate file", resourcePath)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let theArray = items, CFArrayGetCount(theArray) > 0 else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let dictionary = (theArray as NSArray).object(at: 0)
|
||||
guard let identity = (dictionary as AnyObject).value(forKey: kSecImportItemIdentity as String) as? NSObject else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return [
|
||||
"useCertificateChainValidation": NSNumber(value: true),
|
||||
"useSSLCertificateVerification": NSNumber(value: true),
|
||||
"clientCertificate": identity
|
||||
]
|
||||
} catch {
|
||||
console.log("读取证书文件失败", resourcePath)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// 将PEM格式的证书转换为DER格式
|
||||
func convertPEMToDER(pemString: String) -> Data? {
|
||||
// 移除所有空格和换行符
|
||||
var cleanedString = pemString.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
|
||||
// 检查是否包含PEM证书的头尾标记
|
||||
let beginCertPattern = "-----BEGIN CERTIFICATE-----"
|
||||
let endCertPattern = "-----END CERTIFICATE-----"
|
||||
|
||||
// 如果没有找到标准的PEM头尾标记,记录日志并尝试直接解码
|
||||
if !cleanedString.contains(beginCertPattern) || !cleanedString.contains(endCertPattern) {
|
||||
console.log("警告: PEM证书格式不标准,缺少标准头尾标记")
|
||||
// 尝试直接解码,假设整个字符串都是Base64编码
|
||||
let noWhitespace = cleanedString.replacingOccurrences(of: "\\s", with: "", options: .regularExpression)
|
||||
return Data(base64Encoded: noWhitespace)
|
||||
}
|
||||
|
||||
// 提取BEGIN和END标记之间的内容
|
||||
guard let startRange = cleanedString.range(of: beginCertPattern),
|
||||
let endRange = cleanedString.range(of: endCertPattern) else {
|
||||
console.log("无法定位PEM证书的头尾标记位置")
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取BEGIN标记之后的内容
|
||||
let afterBeginIndex = cleanedString.index(after: startRange.upperBound)
|
||||
// 获取END标记之前的内容
|
||||
let beforeEndIndex = endRange.lowerBound
|
||||
|
||||
// 提取Base64编码部分
|
||||
let base64Content = String(cleanedString[afterBeginIndex..<beforeEndIndex])
|
||||
|
||||
// 移除所有空格和换行
|
||||
let noWhitespace = base64Content.replacingOccurrences(of: "\\s", with: "", options: .regularExpression)
|
||||
|
||||
// 解码Base64
|
||||
guard let data = Data(base64Encoded: noWhitespace) else {
|
||||
console.log("Base64解码失败,证书内容可能损坏")
|
||||
return nil
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
func getClientCertFromCrtFile(resourcePath: String) -> [String: NSObject]? {
|
||||
|
||||
do {
|
||||
// 读取证书文件数据
|
||||
let pemData = try Data(contentsOf: URL(fileURLWithPath: resourcePath))
|
||||
// 将证书数据转换为字符串
|
||||
guard let pemString = String(data: pemData, encoding: .utf8) else {
|
||||
console.log("将证书数据转换为字符串失败")
|
||||
return nil
|
||||
}
|
||||
// 将PEM格式转换为DER格式
|
||||
guard let derData = convertPEMToDER(pemString: pemString) else {
|
||||
console.log("转换PEM到DER格式失败")
|
||||
return nil
|
||||
}
|
||||
// 创建SecCertificate对象
|
||||
guard let certificate = SecCertificateCreateWithData(nil, derData as CFData) else {
|
||||
console.log("创建SecCertificate对象失败")
|
||||
return nil
|
||||
}
|
||||
|
||||
return [
|
||||
"useCertificateChainValidation": NSNumber(value: true),
|
||||
"useSSLCertificateVerification": NSNumber(value: true),
|
||||
"kCFStreamSSLCertificates": [certificate] as NSArray
|
||||
]
|
||||
} catch {
|
||||
console.log("读取证书文件失败",resourcePath)
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,294 @@
|
||||
import Foundation
|
||||
import CocoaMQTT
|
||||
import DCloudUTSFoundation
|
||||
|
||||
// 证书加载工具预计由同目录的 xMqttCerHelp.swift 提供
|
||||
// getClientCertFromP12File(resourcePath: String, certPassword: String) -> [String: Any]?
|
||||
// getClientCertFromCrtFile(resourcePath: String) -> [String: Any]?
|
||||
|
||||
@objc public class XMqttHelp: NSObject {
|
||||
|
||||
@objc public enum ConnectStatus: Int {
|
||||
case wait
|
||||
case opening
|
||||
case open
|
||||
case error
|
||||
case dissconnect
|
||||
case message
|
||||
}
|
||||
|
||||
public typealias EventType = String // 'open' | 'error' | 'dissconnect' | 'message'
|
||||
public typealias MQTTEventCallback = @convention(block) (_ type: EventType, _ topic: String?, _ payload: String) -> Void
|
||||
public typealias VoidCallback = @convention(block) () -> Void
|
||||
|
||||
private var mqtt: CocoaMQTT?
|
||||
@objc public private(set) var connectStatus: ConnectStatus = .wait
|
||||
private var anyStateCallback: VoidCallback?
|
||||
|
||||
private struct EventItem {
|
||||
let type: EventType
|
||||
let callback: MQTTEventCallback
|
||||
}
|
||||
private var events = [String: EventItem]()
|
||||
private var pendingSubs = [(topic: String, qos: CocoaMQTTQoS)]()
|
||||
|
||||
@objc public override init() {
|
||||
super.init()
|
||||
}
|
||||
|
||||
// opts keys 对齐 index.uts: protocol, server, port, path, clientId, userName, passWord, keepAliveInterval, reconnect, useSSL, certName, certPassword
|
||||
@objc public func create(_ opts: NSDictionary) -> XMqttHelp {
|
||||
let proto = ((opts["protocol"] as? String) ?? "wss").lowercased() // ws | wss
|
||||
let server = (opts["server"] as? String) ?? ""
|
||||
let port = (opts["port"] as? NSNumber)?.uint16Value ?? 0
|
||||
let path = (opts["path"] as? String) ?? "/mqtt"
|
||||
let clientId = (opts["clientId"] as? String) ?? ("iOS-" + UUID().uuidString)
|
||||
let userName = opts["userName"] as? String
|
||||
let passWord = opts["passWord"] as? String
|
||||
let keepAlive = (opts["keepAliveInterval"] as? NSNumber)?.uint16Value ?? 60
|
||||
let reconnect = (opts["reconnect"] as? NSNumber)?.boolValue ?? true
|
||||
var useSSL = (opts["useSSL"] as? NSNumber)?.boolValue ?? (proto == "wss")
|
||||
let certName = opts["certName"] as? String
|
||||
let certPassword = opts["certPassword"] as? String
|
||||
let allowUntrust = (opts["allowUntrustCACertificate"] as? NSNumber)?.boolValue ?? false
|
||||
var headers = opts["headers"] as? [String: String] ?? [:]
|
||||
let subProtocols = opts["protocols"] as? [String] ?? ["mqtt"]
|
||||
let connectTimeoutMs = (opts["connectTimeoutMs"] as? NSNumber)?.intValue ?? 30000
|
||||
|
||||
let websocket = CocoaMQTTWebSocket(uri: path)
|
||||
// if !subProtocols.isEmpty {
|
||||
// // 通过请求头携带子协议,等效于 Sec-WebSocket-Protocol
|
||||
// headers["sec-websocket-protocol"] = subProtocols.joined(separator: ", ")
|
||||
// }
|
||||
// 常见要求:补 Host 与 Origin
|
||||
headers["Host"] = server
|
||||
if headers["Origin"] == nil {
|
||||
headers["Origin"] = "https://\(server)"
|
||||
}
|
||||
// 标准版本
|
||||
headers["Sec-WebSocket-Version"] = "13"
|
||||
headers["sec-websocket-protocol"] = "mqtt"
|
||||
headers["upgrade"] = "websocket"
|
||||
headers["connection"] = "Upgrade"
|
||||
websocket.headers = headers
|
||||
// 显式打开 wss(CocoaMQTT 2.1.x 部分版本需要)
|
||||
// 存在则赋值,不存在编译器会报错;若报错我再回退此行
|
||||
#if compiler(>=5.0)
|
||||
// 尝试兼容的属性名
|
||||
// @available: 部分版本属性名为 enableSSL 或 isSecure
|
||||
// 这里使用可选链避免编译期错误不可行,因此直接尝试常见属性名
|
||||
// 如果你的 CocoaMQTT 版本不支持,将移除此行由 mqtt.enableSSL 控制
|
||||
#endif
|
||||
let mqtt = CocoaMQTT(clientID: clientId, host: server, port: port, socket: websocket)
|
||||
mqtt.username = userName
|
||||
mqtt.password = passWord
|
||||
mqtt.keepAlive = keepAlive
|
||||
mqtt.enableSSL = useSSL
|
||||
mqtt.autoReconnect = reconnect
|
||||
mqtt.cleanSession = true
|
||||
mqtt.willMessage = CocoaMQTTMessage(topic: "/will", string: "dieout")
|
||||
|
||||
console.log("[XMqttHelp] connect url => \(proto)://\(server):\(port)\(path), ssl=\(useSSL), headers=\(headers)")
|
||||
|
||||
// 证书策略(可选)
|
||||
if useSSL, let name = certName, !name.isEmpty {
|
||||
if name.lowercased().hasSuffix(".p12") {
|
||||
if let pwd = certPassword, !pwd.isEmpty {
|
||||
let base = (name as NSString).deletingPathExtension
|
||||
if let path = Bundle.main.path(forResource: base, ofType: "p12"),
|
||||
let settings = getClientCertFromP12File(resourcePath: path, certPassword: pwd) {
|
||||
mqtt.sslSettings = settings
|
||||
} else {
|
||||
console.log("[XMqttHelp] p12 证书无效或找不到: \(name)")
|
||||
}
|
||||
} else {
|
||||
console.log("[XMqttHelp] p12 证书未提供密码")
|
||||
}
|
||||
} else if name.lowercased().hasSuffix(".crt") {
|
||||
let base = (name as NSString).deletingPathExtension
|
||||
if let path = Bundle.main.path(forResource: base, ofType: "crt"),
|
||||
let settings = getClientCertFromCrtFile(resourcePath: path) {
|
||||
mqtt.sslSettings = settings
|
||||
} else {
|
||||
console.log("[XMqttHelp] crt 证书无效或找不到: \(name)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 自签证书信任(调试可开,生产建议禁用或使用证书绑定)
|
||||
mqtt.allowUntrustCACertificate = allowUntrust
|
||||
|
||||
// 指定 SNI 主机名,避免非标准端口下的握手失败
|
||||
if useSSL {
|
||||
var ssl = mqtt.sslSettings ?? [:]
|
||||
ssl[kCFStreamSSLPeerName as String] = server as NSString
|
||||
mqtt.sslSettings = ssl
|
||||
}
|
||||
|
||||
// 事件回调
|
||||
weak var weakSelf = self
|
||||
mqtt.didDisconnect = { [weak weakSelf] _, error in
|
||||
guard let self = weakSelf else { return }
|
||||
self.connectStatus = .error
|
||||
self.notifyStateChange()
|
||||
self.buildCallEvents(type: "error", topic: nil, payload: (error as? CocoaMQTTError) != nil ? "连接错误" : "地址错误,或者没有网络。")
|
||||
}
|
||||
mqtt.didConnectAck = { [weak weakSelf] _, _ in
|
||||
guard let self = weakSelf else { return }
|
||||
self.connectStatus = .open
|
||||
self.notifyStateChange()
|
||||
self.buildCallEvents(type: "open", topic: nil, payload: "已连接")
|
||||
// 补发未完成的订阅
|
||||
if !self.pendingSubs.isEmpty {
|
||||
for item in self.pendingSubs {
|
||||
self.mqtt?.subscribe(item.topic, qos: item.qos)
|
||||
console.log("[XMqttHelp] re-subscribe => \(item.topic) qos=\(item.qos.rawValue)")
|
||||
}
|
||||
self.pendingSubs.removeAll()
|
||||
}
|
||||
}
|
||||
mqtt.didChangeState = { [weak weakSelf] _, state in
|
||||
guard let self = weakSelf else { return }
|
||||
switch state {
|
||||
case .connecting:
|
||||
console.log("[XMqttHelp] 连接中")
|
||||
case .connected:
|
||||
console.log("[XMqttHelp] 连接成功")
|
||||
case .disconnected:
|
||||
self.connectStatus = .dissconnect
|
||||
self.notifyStateChange()
|
||||
self.buildCallEvents(type: "dissconnect", topic: nil, payload: "已断开连接")
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
mqtt.didReceiveMessage = { [weak weakSelf] _, message, _ in
|
||||
guard let self = weakSelf else { return }
|
||||
self.connectStatus = .message
|
||||
self.notifyStateChange()
|
||||
let payload = message.string ?? (String(data: Data(message.payload), encoding: .utf8) ?? "")
|
||||
self.buildCallEvents(type: "message", topic: message.topic, payload: payload)
|
||||
}
|
||||
|
||||
self.mqtt = mqtt
|
||||
self.connectStatus = .wait
|
||||
self.notifyStateChange()
|
||||
|
||||
// 连接超时保护
|
||||
if connectTimeoutMs > 0 {
|
||||
let deadline = DispatchTime.now() + .milliseconds(connectTimeoutMs)
|
||||
DispatchQueue.main.asyncAfter(deadline: deadline) { [weak self] in
|
||||
guard let self = self else { return }
|
||||
if self.connectStatus == .opening {
|
||||
console.log("[XMqttHelp] 连接超时: \(connectTimeoutMs)ms")
|
||||
_ = self.disconnect()
|
||||
self.connectStatus = .error
|
||||
self.notifyStateChange()
|
||||
self.buildCallEvents(type: "error", topic: nil, payload: "连接超时")
|
||||
}
|
||||
}
|
||||
}
|
||||
return self
|
||||
}
|
||||
|
||||
@objc public func connect() -> XMqttHelp {
|
||||
guard let mqtt = self.mqtt else { return self }
|
||||
self.connectStatus = .opening
|
||||
self.notifyStateChange()
|
||||
mqtt.connect()
|
||||
return self
|
||||
}
|
||||
|
||||
@objc public func publish(_ topic: String, message: String, qos: Int, retained: Bool, completion: @escaping @convention(block) (_ ok: Bool) -> Void) -> XMqttHelp {
|
||||
guard let mqtt = self.mqtt else { completion(false); return self }
|
||||
let q: CocoaMQTTQoS = (qos == 2) ? .qos2 : ((qos == 1) ? .qos1 : .qos0)
|
||||
let msg = CocoaMQTTMessage(topic: topic, string: message, qos: q, retained: retained)
|
||||
mqtt.publish(msg)
|
||||
completion(true)
|
||||
return self
|
||||
}
|
||||
|
||||
@objc public func subscribe(_ topics: [NSDictionary]) -> XMqttHelp {
|
||||
guard let mqtt = self.mqtt else { return self }
|
||||
for item in topics {
|
||||
guard let topic = item["topic"] as? String else { continue }
|
||||
let qosVal = (item["qos"] as? NSNumber)?.intValue ?? 0
|
||||
let q: CocoaMQTTQoS = (qosVal == 2) ? .qos2 : ((qosVal == 1) ? .qos1 : .qos0)
|
||||
console.log(self.connectStatus == .open,"opeing status")
|
||||
if self.connectStatus == .open {
|
||||
mqtt.subscribe(topic, qos: q)
|
||||
console.log("[XMqttHelp] subscribe => \(topic) qos=\(q.rawValue)")
|
||||
} else {
|
||||
self.pendingSubs.append((topic, q))
|
||||
console.log("[XMqttHelp] cache subscribe (not open) => \(topic) qos=\(q.rawValue)")
|
||||
}
|
||||
}
|
||||
return self
|
||||
}
|
||||
|
||||
@objc public func unsubscribe(_ topics: [String]) -> XMqttHelp {
|
||||
guard let mqtt = self.mqtt else { return self }
|
||||
for t in topics { mqtt.unsubscribe(t) }
|
||||
return self
|
||||
}
|
||||
|
||||
@objc public func disconnect() -> XMqttHelp {
|
||||
guard let mqtt = self.mqtt else { return self }
|
||||
mqtt.disconnect()
|
||||
return self
|
||||
}
|
||||
|
||||
// 注册任意状态变化的回调(无参数)
|
||||
@objc public func setCallBack(_ cb: @escaping VoidCallback) {
|
||||
self.anyStateCallback = cb
|
||||
}
|
||||
|
||||
|
||||
// 规范命名,提供同等功能(可选使用)
|
||||
@objc public func getStatus() -> String {
|
||||
return self.statusString(self.connectStatus)
|
||||
}
|
||||
|
||||
// 事件系统:与 index.uts 的 addEventListener/removeEventListener 对齐
|
||||
@objc @discardableResult
|
||||
public func addEventListener(_ type: EventType, callback: @escaping MQTTEventCallback) -> String {
|
||||
let id = String(format: "%.0f-%d", Date().timeIntervalSince1970 * 1000, Int.random(in: 0...9999))
|
||||
events[id] = EventItem(type: type, callback: callback)
|
||||
return id
|
||||
}
|
||||
|
||||
@objc @discardableResult
|
||||
public func removeEventListener(_ id: String) -> XMqttHelp {
|
||||
events.removeValue(forKey: id)
|
||||
return self
|
||||
}
|
||||
|
||||
private func buildCallEvents(type: EventType, topic: String?, payload: String) {
|
||||
for (_, item) in events where item.type == type {
|
||||
item.callback(type, topic, payload)
|
||||
}
|
||||
}
|
||||
|
||||
private func notifyStateChange() {
|
||||
anyStateCallback?()
|
||||
}
|
||||
|
||||
private func statusString(_ status: ConnectStatus) -> String {
|
||||
switch status {
|
||||
case .wait:
|
||||
return "wait"
|
||||
case .opening:
|
||||
return "opening"
|
||||
case .open:
|
||||
return "open"
|
||||
case .error:
|
||||
return "error"
|
||||
case .dissconnect:
|
||||
return "dissconnect"
|
||||
case .message:
|
||||
return "message"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
export type CONNECT_STATUS = "opening" | "open" | "dissconnect" | "error" | "wait";
|
||||
export type MQTT_EVENT_TYPE = "open" | "dissconnect" | "error" | "message";
|
||||
export type MQTT_EVENT_CALL = (type : MQTT_EVENT_TYPE, topic : string | null, str : string) => void;
|
||||
export type MQTT_EVENT_PUBLISH = (isSuccess : boolean) => void;
|
||||
export type MQTT_SUBSCRIBE = { topic : string, qos : number };
|
||||
export type MQTT_PUBLISH_TOPIC = {
|
||||
// 订阅的主题
|
||||
topic:string,
|
||||
message:string,
|
||||
// 优先级0,1,2 依此表示至少接收到的消息级别1至少要收到1次
|
||||
qos:number,
|
||||
// 消息是否持久化,就是指推送的消息是否保留在服务器上,供未来订阅者订阅时收到此前发送的消息。
|
||||
retained:boolean
|
||||
};
|
||||
export type MQTT_CONNECT_OPTS = {
|
||||
// web端不会起作用,由软件根据useSSL来判断是ws,wss,app需要指定是ws://,wss://,ssl://等
|
||||
protocol : string,
|
||||
// 连接的路径,如果没有就空值,有就填写比如:'/mqtt'
|
||||
path : string,
|
||||
// 客户端id
|
||||
clientId : string,
|
||||
// 服务器地址
|
||||
server : string,
|
||||
// 服务器端口
|
||||
port : number,
|
||||
// 用户名,没有为空
|
||||
userName : string,
|
||||
// 用户密码,没有为空
|
||||
passWord : string,
|
||||
// 是否使用加密连接,web端true时为wss,否则为ws协议
|
||||
useSSL : boolean,
|
||||
// 保持消息跳动的间隔
|
||||
keepAliveInterval : number,
|
||||
// 连接超时时间
|
||||
timeout : number,
|
||||
// 是否自动重连
|
||||
reconnect : boolean,
|
||||
// ios用,是否启用公共加密连接
|
||||
allowUntrustCACertificate?:boolean,
|
||||
// ios专用的p12证书密码,如果是ca证书则不需要
|
||||
certPassword ?: string,
|
||||
// ios下你放置在插件目录Resources内的证书名称,含后缀 如:ca.crt,ca.p12
|
||||
certName ?: string
|
||||
};
|
||||
|
||||
|
||||
export type MQTT_EVENTS_CALL = {
|
||||
type : MQTT_EVENT_TYPE,
|
||||
value : MQTT_EVENT_CALL
|
||||
};
|
||||
@@ -0,0 +1,158 @@
|
||||
export { CONNECT_STATUS,MQTT_EVENT_TYPE,MQTT_EVENT_CALL,MQTT_EVENT_PUBLISH,MQTT_SUBSCRIBE,MQTT_EVENTS_CALL,MQTT_PUBLISH_TOPIC,MQTT_CONNECT_OPTS } from "../interface.uts"
|
||||
import Paho from './mqtt.js'
|
||||
// var client = new Paho.MQTT.Client(location.hostname, Number(location.port), "clientId");
|
||||
// mqtt测试服务器
|
||||
// https://console.hivemq.cloud/
|
||||
// https://github.com/eclipse/paho.mqtt.javascript
|
||||
// https://eclipse.dev/paho/files/jsdoc/Paho.MQTT.Client.html
|
||||
|
||||
type MqttConnectOptions = {
|
||||
userName?:string,
|
||||
password?:string,
|
||||
useSSL?:boolean,
|
||||
keepAliveInterval?:number,
|
||||
timeout?:number,
|
||||
reconnect?:boolean,
|
||||
onSuccess?:any,
|
||||
onFailure?:any
|
||||
}
|
||||
|
||||
|
||||
export class xMqtt {
|
||||
mqtt : MqttAndroidClient | null = null;
|
||||
mqttConnectOptions : MqttConnectOptions | null = null;
|
||||
connectStatus:CONNECT_STATUS = 'wait'
|
||||
events = new Map<string,MQTT_EVENTS_CALL>();
|
||||
constructor(){
|
||||
|
||||
}
|
||||
/**
|
||||
* @param ulr {string} 连接地址
|
||||
* @param clientIdStr {string} 客户端id
|
||||
* @param username {string|null} 用户名称,如果不需要,设置为null即可
|
||||
* @param password {string|null} 登录密码,如果不需要,设置为null即可
|
||||
*/
|
||||
async create(opts:MQTT_CONNECT_OPTS):xMqtt {
|
||||
let t = this;
|
||||
this.mqttConnectOptions = {} as MqttConnectOptions;
|
||||
this.mqttConnectOptions.userName = opts.userName;
|
||||
this.mqttConnectOptions.password = opts.passWord;
|
||||
this.mqttConnectOptions.useSSL = opts.useSSL;
|
||||
this.mqttConnectOptions.keepAliveInterval = opts.keepAliveInterval;
|
||||
this.mqttConnectOptions.timeout = opts.timeout;
|
||||
|
||||
this.mqttConnectOptions.reconnect = opts.reconnect;
|
||||
this.mqtt = new Paho.Client( `${opts.protocol}${opts.server}:${opts.port}${opts.path}`, opts.clientId);
|
||||
this.mqttConnectOptions.onSuccess = ()=>{
|
||||
t.buildCallEvents('open',null,'连接成功')
|
||||
};
|
||||
this.mqttConnectOptions.onFailure = ()=>{
|
||||
t.buildCallEvents('error',null,'连接失败')
|
||||
};
|
||||
|
||||
this.mqtt.onConnectionLost = ()=>{
|
||||
t.buildCallEvents('dissconnect',null,'连接断开')
|
||||
};
|
||||
this.mqtt.onMessageArrived = (evt)=>{
|
||||
|
||||
t.buildCallEvents('message',evt.topic,evt.payloadString)
|
||||
};
|
||||
this.connectStatus = 'wait'
|
||||
this.mqtt.connect(this.mqttConnectOptions)
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type {MQTT_EVENT_TYPE} 事件名称
|
||||
* @param call {MQTT_EVENT_CALL} 事件回调
|
||||
*/
|
||||
addEventListener(type:MQTT_EVENT_TYPE,call:MQTT_EVENT_CALL):string{
|
||||
let id = Date.now().toString()+(Math.random()*100).toString()
|
||||
this.events.set(id,
|
||||
{
|
||||
type,
|
||||
value:call
|
||||
} as MQTT_EVENTS_CALL
|
||||
)
|
||||
|
||||
return id;
|
||||
}
|
||||
/**
|
||||
* @param id {string} addEventListener返回的事件id
|
||||
*/
|
||||
removeEventListener(id:string):xMqtt{
|
||||
this.events.delete(ids[i])
|
||||
return this;
|
||||
}
|
||||
private buildCallEvents(type:MQTT_EVENT_TYPE,toppic:string|null,str:string){
|
||||
this.events.forEach((value:MQTT_EVENTS_CALL,key:string)=>{
|
||||
if(value.type == type){
|
||||
value.value(type,toppic,str)
|
||||
}
|
||||
})
|
||||
}
|
||||
connect():xMqtt{
|
||||
|
||||
this.mqtt?.connect(this.mqttConnectOptions);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 订阅
|
||||
* @param data {MQTT_SUBSCRIBE[]} 订阅的消息数组
|
||||
*/
|
||||
subscribe(data:MQTT_SUBSCRIBE[]):xMqtt{
|
||||
let t = this;
|
||||
if(this.mqtt == null) return this;
|
||||
for(let i=0;i<data.length;i++){
|
||||
|
||||
this.mqtt.subscribe(data[i].topic,{
|
||||
qos:data[i].qos,
|
||||
onSuccess(){
|
||||
console.log("订阅成功")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 推送消息
|
||||
* @param message {MQTT_EVENT_PUBLISH}
|
||||
* @param call ()=>void 推送消息成功时的回调【web端永为真】
|
||||
*/
|
||||
publish(message:MQTT_PUBLISH_TOPIC,call:MQTT_EVENT_PUBLISH):xMqtt{
|
||||
if(this.mqtt == null) return this;
|
||||
this.mqtt!.publish(message.topic,message.message,message.qos,true);
|
||||
call(true)
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 取消订阅
|
||||
* @param topics {string[]} 主题数组
|
||||
*/
|
||||
unsubscribe(topics:string[]):xMqtt{
|
||||
let t = this;
|
||||
if(this.mqtt == null||topics.length==0) return this;
|
||||
for(let i=0;i<topics.length;i++){
|
||||
this.mqtt!.unsubscribe(topics[i],{
|
||||
onSuccess(){
|
||||
console.log("取消订阅成功")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 断开连接
|
||||
*/
|
||||
disconnect():xMqtt{
|
||||
if(this.mqtt == null) return this;
|
||||
this.mqtt!.disconnect()
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
// Ensure a compatible global for UMD and enable CommonJS exports in Mini Program
|
||||
if (typeof global === "undefined") {
|
||||
var global = (typeof globalThis !== "undefined") ? globalThis : (typeof self !== "undefined" ? self : (typeof window !== "undefined" ? window : {}));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013, 2016 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
*******************************************************************************/
|
||||
(function(m,r){
|
||||
var out = r();
|
||||
if (typeof m.Paho === "undefined") m.Paho = {};
|
||||
m.Paho.MQTT = out;
|
||||
})(global,function(){return function(m){function r(a,b,d){b[d++]=a>>8;b[d++]=a%256;return d}function u(a,b,d,k){k=r(b,d,k);D(a,d,k);return k+b}function p(a){for(var b=0,d=0;d<a.length;d++){var k=a.charCodeAt(d);2047<k?(55296<=k&&56319>=k&&(d++,b++),b+=3):127<k?b+=2:b++}return b}
|
||||
function D(a,b,d){for(var k=0;k<a.length;k++){var e=a.charCodeAt(k);if(55296<=e&&56319>=e){var f=a.charCodeAt(++k);if(isNaN(f))throw Error(h(g.MALFORMED_UNICODE,[e,f]));e=(e-55296<<10)+(f-56320)+65536}127>=e?b[d++]=e:(2047>=e?b[d++]=e>>6&31|192:(65535>=e?b[d++]=e>>12&15|224:(b[d++]=e>>18&7|240,b[d++]=e>>12&63|128),b[d++]=e>>6&63|128),b[d++]=e&63|128)}return b}function E(a,b,d){for(var k="",e,f=b;f<b+d;){e=a[f++];if(!(128>e)){var n=a[f++]-128;if(0>n)throw Error(h(g.MALFORMED_UTF,[e.toString(16),n.toString(16),
|
||||
""]));if(224>e)e=64*(e-192)+n;else{var c=a[f++]-128;if(0>c)throw Error(h(g.MALFORMED_UTF,[e.toString(16),n.toString(16),c.toString(16)]));if(240>e)e=4096*(e-224)+64*n+c;else{var l=a[f++]-128;if(0>l)throw Error(h(g.MALFORMED_UTF,[e.toString(16),n.toString(16),c.toString(16),l.toString(16)]));if(248>e)e=262144*(e-240)+4096*n+64*c+l;else throw Error(h(g.MALFORMED_UTF,[e.toString(16),n.toString(16),c.toString(16),l.toString(16)]));}}}65535<e&&(e-=65536,k+=String.fromCharCode(55296+(e>>10)),e=56320+(e&
|
||||
1023));k+=String.fromCharCode(e)}return k}var y=function(a,b){for(var d in a)if(a.hasOwnProperty(d))if(b.hasOwnProperty(d)){if(typeof a[d]!==b[d])throw Error(h(g.INVALID_TYPE,[typeof a[d],d]));}else{d="Unknown property, "+d+". Valid properties are:";for(var k in b)b.hasOwnProperty(k)&&(d=d+" "+k);throw Error(d);}},s=function(a,b){return function(){return a.apply(b,arguments)}},g={OK:{code:0,text:"AMQJSC0000I OK."},CONNECT_TIMEOUT:{code:1,text:"AMQJSC0001E Connect timed out."},SUBSCRIBE_TIMEOUT:{code:2,
|
||||
text:"AMQJS0002E Subscribe timed out."},UNSUBSCRIBE_TIMEOUT:{code:3,text:"AMQJS0003E Unsubscribe timed out."},PING_TIMEOUT:{code:4,text:"AMQJS0004E Ping timed out."},INTERNAL_ERROR:{code:5,text:"AMQJS0005E Internal error. Error Message: {0}, Stack trace: {1}"},CONNACK_RETURNCODE:{code:6,text:"AMQJS0006E Bad Connack return code:{0} {1}."},SOCKET_ERROR:{code:7,text:"AMQJS0007E Socket error:{0}."},SOCKET_CLOSE:{code:8,text:"AMQJS0008I Socket closed."},MALFORMED_UTF:{code:9,text:"AMQJS0009E Malformed UTF data:{0} {1} {2}."},
|
||||
UNSUPPORTED:{code:10,text:"AMQJS0010E {0} is not supported by this browser."},INVALID_STATE:{code:11,text:"AMQJS0011E Invalid state {0}."},INVALID_TYPE:{code:12,text:"AMQJS0012E Invalid type {0} for {1}."},INVALID_ARGUMENT:{code:13,text:"AMQJS0013E Invalid argument {0} for {1}."},UNSUPPORTED_OPERATION:{code:14,text:"AMQJS0014E Unsupported operation."},INVALID_STORED_DATA:{code:15,text:"AMQJS0015E Invalid data in local storage key\x3d{0} value\x3d{1}."},INVALID_MQTT_MESSAGE_TYPE:{code:16,text:"AMQJS0016E Invalid MQTT message type {0}."},
|
||||
MALFORMED_UNICODE:{code:17,text:"AMQJS0017E Malformed Unicode string:{0} {1}."},BUFFER_FULL:{code:18,text:"AMQJS0018E Message buffer is full, maximum buffer size: {0}."}},H={0:"Connection Accepted",1:"Connection Refused: unacceptable protocol version",2:"Connection Refused: identifier rejected",3:"Connection Refused: server unavailable",4:"Connection Refused: bad user name or password",5:"Connection Refused: not authorized"},h=function(a,b){var d=a.text;if(b)for(var k,e,f=0;f<b.length;f++)if(k="{"+
|
||||
f+"}",e=d.indexOf(k),0<e)var g=d.substring(0,e),d=d.substring(e+k.length),d=g+b[f]+d;return d},A=[0,6,77,81,73,115,100,112,3],B=[0,4,77,81,84,84,4],q=function(a,b){this.type=a;for(var d in b)b.hasOwnProperty(d)&&(this[d]=b[d])};q.prototype.encode=function(){var a=(this.type&15)<<4,b=0,d=[],k=0,e;void 0!==this.messageIdentifier&&(b+=2);switch(this.type){case 1:switch(this.mqttVersion){case 3:b+=A.length+3;break;case 4:b+=B.length+3}b+=p(this.clientId)+2;void 0!==this.willMessage&&(b+=p(this.willMessage.destinationName)+
|
||||
2,e=this.willMessage.payloadBytes,e instanceof Uint8Array||(e=new Uint8Array(g)),b+=e.byteLength+2);void 0!==this.userName&&(b+=p(this.userName)+2);void 0!==this.password&&(b+=p(this.password)+2);break;case 8:for(var a=a|2,f=0;f<this.topics.length;f++)d[f]=p(this.topics[f]),b+=d[f]+2;b+=this.requestedQos.length;break;case 10:a|=2;for(f=0;f<this.topics.length;f++)d[f]=p(this.topics[f]),b+=d[f]+2;break;case 6:a|=2;break;case 3:this.payloadMessage.duplicate&&(a|=8);a=a|=this.payloadMessage.qos<<1;this.payloadMessage.retained&&
|
||||
(a|=1);var k=p(this.payloadMessage.destinationName),g=this.payloadMessage.payloadBytes,b=b+(k+2)+g.byteLength;g instanceof ArrayBuffer?g=new Uint8Array(g):g instanceof Uint8Array||(g=new Uint8Array(g.buffer))}var c=b,f=Array(1),h=0;do{var t=c%128,c=c>>7;0<c&&(t|=128);f[h++]=t}while(0<c&&4>h);c=f.length+1;b=new ArrayBuffer(b+c);h=new Uint8Array(b);h[0]=a;h.set(f,1);if(3==this.type)c=u(this.payloadMessage.destinationName,k,h,c);else if(1==this.type){switch(this.mqttVersion){case 3:h.set(A,c);c+=A.length;
|
||||
break;case 4:h.set(B,c),c+=B.length}a=0;this.cleanSession&&(a=2);void 0!==this.willMessage&&(a=a|4|this.willMessage.qos<<3,this.willMessage.retained&&(a|=32));void 0!==this.userName&&(a|=128);void 0!==this.password&&(a|=64);h[c++]=a;c=r(this.keepAliveInterval,h,c)}void 0!==this.messageIdentifier&&(c=r(this.messageIdentifier,h,c));switch(this.type){case 1:c=u(this.clientId,p(this.clientId),h,c);void 0!==this.willMessage&&(c=u(this.willMessage.destinationName,p(this.willMessage.destinationName),h,c),
|
||||
c=r(e.byteLength,h,c),h.set(e,c),c+=e.byteLength);void 0!==this.userName&&(c=u(this.userName,p(this.userName),h,c));void 0!==this.password&&u(this.password,p(this.password),h,c);break;case 3:h.set(g,c);break;case 8:for(f=0;f<this.topics.length;f++)c=u(this.topics[f],d[f],h,c),h[c++]=this.requestedQos[f];break;case 10:for(f=0;f<this.topics.length;f++)c=u(this.topics[f],d[f],h,c)}return b};var F=function(a,b){this._client=a;this._keepAliveInterval=1E3*b;this.isReset=!1;var d=(new q(12)).encode(),c=
|
||||
function(a){return function(){return e.apply(a)}},e=function(){this.isReset?(this.isReset=!1,this._client._trace("Pinger.doPing","send PINGREQ"),m.sendSocketMessage({data:d,success:function(){},fail:function(){},complete:function(){}}),this.timeout=setTimeout(c(this),this._keepAliveInterval)):(this._client._trace("Pinger.doPing","Timed out"),this._client._disconnected(g.PING_TIMEOUT.code,h(g.PING_TIMEOUT)))};this.reset=function(){this.isReset=!0;clearTimeout(this.timeout);0<this._keepAliveInterval&&
|
||||
(this.timeout=setTimeout(c(this),this._keepAliveInterval))};this.cancel=function(){clearTimeout(this.timeout)}},z=function(a,b,d,c){b||(b=30);this.timeout=setTimeout(function(a,b,d){return function(){return a.apply(b,d)}}(d,a,c),1E3*b);this.cancel=function(){clearTimeout(this.timeout)}},c=function(a,b,d,c,e){this._trace("Paho.MQTT.Client",a,b,d,c,e);this.host=b;this.port=d;this.path=c;this.uri=a;this.clientId=e;this._wsuri=null;this._localKey=b+":"+d+("/mqtt"!=c?":"+c:"")+":"+e+":";this._msg_queue=
|
||||
[];this._buffered_msg_queue=[];this._sentMessages={};this._receivedMessages={};this._notify_msg_sent={};this._message_identifier=1;this._sequence=0;for(var f in m.getStorageInfoSync().keys)0!==f.indexOf("Sent:"+this._localKey)&&0!==f.indexOf("Received:"+this._localKey)||this.restore(f)};c.prototype.host=null;c.prototype.port=null;c.prototype.path=null;c.prototype.uri=null;c.prototype.clientId=null;c.prototype.socket=null;c.prototype.connected=!1;c.prototype.maxMessageIdentifier=65536;c.prototype.connectOptions=
|
||||
null;c.prototype.hostIndex=null;c.prototype.onConnected=null;c.prototype.onConnectionLost=null;c.prototype.onMessageDelivered=null;c.prototype.onMessageArrived=null;c.prototype.traceFunction=null;c.prototype._msg_queue=null;c.prototype._buffered_msg_queue=null;c.prototype._connectTimeout=null;c.prototype.sendPinger=null;c.prototype.receivePinger=null;c.prototype._reconnectInterval=1;c.prototype._reconnecting=!1;c.prototype._reconnectTimeout=null;c.prototype.disconnectedPublishing=!1;c.prototype.disconnectedBufferSize=
|
||||
5E3;c.prototype.receiveBuffer=null;c.prototype._traceBuffer=null;c.prototype._MAX_TRACE_ENTRIES=100;c.prototype.connect=function(a){var b=this._traceMask(a,"password");this._trace("Client.connect",b,null,this.connected);if(this.connected)throw Error(h(g.INVALID_STATE,["already connected"]));this._reconnecting&&(this._reconnectTimeout.cancel(),this._reconnectTimeout=null,this._reconnecting=!1);this.connectOptions=a;this._reconnectInterval=1;this._reconnecting=!1;a.uris?(this.hostIndex=0,this._doConnect(a.uris[0])):
|
||||
this._doConnect(this.uri)};c.prototype.subscribe=function(a,b){this._trace("Client.subscribe",a,b);if(!this.connected)throw Error(h(g.INVALID_STATE,["not connected"]));var d=new q(8);d.topics=[a];d.requestedQos=void 0!==b.qos?[b.qos]:[0];b.onSuccess&&(d.onSuccess=function(a){b.onSuccess({invocationContext:b.invocationContext,grantedQos:a})});b.onFailure&&(d.onFailure=function(a){b.onFailure({invocationContext:b.invocationContext,errorCode:a,errorMessage:h(a)})});b.timeout&&(d.timeOut=new z(this,b.timeout,
|
||||
b.onFailure,[{invocationContext:b.invocationContext,errorCode:g.SUBSCRIBE_TIMEOUT.code,errorMessage:h(g.SUBSCRIBE_TIMEOUT)}]));this._requires_ack(d);this._schedule_message(d)};c.prototype.unsubscribe=function(a,b){this._trace("Client.unsubscribe",a,b);if(!this.connected)throw Error(h(g.INVALID_STATE,["not connected"]));var d=new q(10);d.topics=[a];b.onSuccess&&(d.callback=function(){b.onSuccess({invocationContext:b.invocationContext})});b.timeout&&(d.timeOut=new z(this,b.timeout,b.onFailure,[{invocationContext:b.invocationContext,
|
||||
errorCode:g.UNSUBSCRIBE_TIMEOUT.code,errorMessage:h(g.UNSUBSCRIBE_TIMEOUT)}]));this._requires_ack(d);this._schedule_message(d)};c.prototype.send=function(a){this._trace("Client.send",a);var b=new q(3);b.payloadMessage=a;if(this.connected)0<a.qos?this._requires_ack(b):this.onMessageDelivered&&(this._notify_msg_sent[b]=this.onMessageDelivered(b.payloadMessage)),this._schedule_message(b);else if(this._reconnecting&&this.disconnectedPublishing){if(Object.keys(this._sentMessages).length+this._buffered_msg_queue.length>
|
||||
this.disconnectedBufferSize)throw Error(h(g.BUFFER_FULL,[this.disconnectedBufferSize]));0<a.qos?this._requires_ack(b):(b.sequence=++this._sequence,this._buffered_msg_queue.push(b))}else throw Error(h(g.INVALID_STATE,["not connected"]));};c.prototype.disconnect=function(){this._trace("Client.disconnect");this._reconnecting&&(this._reconnectTimeout.cancel(),this._reconnectTimeout=null,this._reconnecting=!1);if(!this.connected)throw Error(h(g.INVALID_STATE,["not connecting or connected"]));var a=new q(14);
|
||||
this._notify_msg_sent[a]=s(this._disconnected,this);this._schedule_message(a)};c.prototype.getTraceLog=function(){if(null!==this._traceBuffer){this._trace("Client.getTraceLog",new Date);this._trace("Client.getTraceLog in flight messages",this._sentMessages.length);for(var a in this._sentMessages)this._trace("_sentMessages ",a,this._sentMessages[a]);for(a in this._receivedMessages)this._trace("_receivedMessages ",a,this._receivedMessages[a]);return this._traceBuffer}};c.prototype.startTrace=function(){null===
|
||||
this._traceBuffer && (this._traceBuffer = []); this._trace("Client.startTrace", new Date, "1.0.3")
|
||||
}; c.prototype.stopTrace = function () { delete this._traceBuffer }; c.prototype._doConnect = function (a) {
|
||||
this.connectOptions.useSSL && (a = a.split(":"), a[0] = "wss", a = a.join(":")); this._wsuri = a; this.connected = !1; m.connectSocket({ url: a, protocols: ['mqtt']});m.onSocketOpen(s(this._on_socket_open,this));m.onSocketMessage(s(this._on_socket_message,this));m.onSocketError(s(this._on_socket_error,this));m.onSocketClose(s(this._on_socket_close,
|
||||
this));this.sendPinger=new F(this,this.connectOptions.keepAliveInterval);this.receivePinger=new F(this,this.connectOptions.keepAliveInterval);this._connectTimeout&&(this._connectTimeout.cancel(),this._connectTimeout=null);this._connectTimeout=new z(this,this.connectOptions.timeout,this._disconnected,[g.CONNECT_TIMEOUT.code,h(g.CONNECT_TIMEOUT)])};c.prototype._schedule_message=function(a){this._msg_queue.push(a);this.connected&&this._process_queue()};c.prototype.store=function(a,b){var d={type:b.type,
|
||||
messageIdentifier:b.messageIdentifier,version:1};switch(b.type){case 3:b.pubRecReceived&&(d.pubRecReceived=!0);d.payloadMessage={};for(var c="",e=b.payloadMessage.payloadBytes,f=0;f<e.length;f++)c=15>=e[f]?c+"0"+e[f].toString(16):c+e[f].toString(16);d.payloadMessage.payloadHex=c;d.payloadMessage.qos=b.payloadMessage.qos;d.payloadMessage.destinationName=b.payloadMessage.destinationName;b.payloadMessage.duplicate&&(d.payloadMessage.duplicate=!0);b.payloadMessage.retained&&(d.payloadMessage.retained=
|
||||
!0);0===a.indexOf("Sent:")&&(void 0===b.sequence&&(b.sequence=++this._sequence),d.sequence=b.sequence);break;default:throw Error(h(g.INVALID_STORED_DATA,[key,d]));}try{m.setStorageSync(a+this._localKey+b.messageIdentifier,JSON.stringify(d))}catch(n){}};c.prototype.restore=function(a){var b=m.getStorageSync(a),d=JSON.parse(b),c=new q(d.type,d);switch(d.type){case 3:for(var b=d.payloadMessage.payloadHex,e=new ArrayBuffer(b.length/2),e=new Uint8Array(e),f=0;2<=b.length;){var n=parseInt(b.substring(0,
|
||||
2),16),b=b.substring(2,b.length);e[f++]=n}b=new v(e);b.qos=d.payloadMessage.qos;b.destinationName=d.payloadMessage.destinationName;d.payloadMessage.duplicate&&(b.duplicate=!0);d.payloadMessage.retained&&(b.retained=!0);c.payloadMessage=b;break;default:throw Error(h(g.INVALID_STORED_DATA,[a,b]));}0===a.indexOf("Sent:"+this._localKey)?(c.payloadMessage.duplicate=!0,this._sentMessages[c.messageIdentifier]=c):0===a.indexOf("Received:"+this._localKey)&&(this._receivedMessages[c.messageIdentifier]=c)};
|
||||
c.prototype._process_queue=function(){for(var a=null,b=this._msg_queue.reverse();a=b.pop();)this._socket_send(a),this._notify_msg_sent[a]&&(this._notify_msg_sent[a](),delete this._notify_msg_sent[a])};c.prototype._requires_ack=function(a){var b=Object.keys(this._sentMessages).length;if(b>this.maxMessageIdentifier)throw Error("Too many messages:"+b);for(;void 0!==this._sentMessages[this._message_identifier];)this._message_identifier++;a.messageIdentifier=this._message_identifier;this._sentMessages[a.messageIdentifier]=
|
||||
a;3===a.type&&this.store("Sent:",a);this._message_identifier===this.maxMessageIdentifier&&(this._message_identifier=1)};c.prototype._on_socket_open=function(a){a=new q(1,this.connectOptions);a.clientId=this.clientId;this._socket_send(a)};c.prototype._on_socket_message=function(a){this._trace("Client._on_socket_message",a.data);a=this._deframeMessages(a.data);for(var b=0;b<a.length;b+=1)this._handleMessage(a[b])};c.prototype._deframeMessages=function(a){a=new Uint8Array(a);var b=[];if(this.receiveBuffer){var d=
|
||||
new Uint8Array(this.receiveBuffer.length+a.length);d.set(this.receiveBuffer);d.set(a,this.receiveBuffer.length);a=d;delete this.receiveBuffer}try{for(d=0;d<a.length;){var c;a:{var e=a,f=d,n=f,m=e[f],l=m>>4,t=m&15,f=f+1,w=void 0,C=0,p=1;do{if(f==e.length){c=[null,n];break a}w=e[f++];C+=(w&127)*p;p*=128}while(0!==(w&128));w=f+C;if(w>e.length)c=[null,n];else{var x=new q(l);switch(l){case 2:e[f++]&1&&(x.sessionPresent=!0);x.returnCode=e[f++];break;case 3:var n=t>>1&3,r=256*e[f]+e[f+1],f=f+2,u=E(e,f,r),
|
||||
f=f+r;0<n&&(x.messageIdentifier=256*e[f]+e[f+1],f+=2);var s=new v(e.subarray(f,w));1==(t&1)&&(s.retained=!0);8==(t&8)&&(s.duplicate=!0);s.qos=n;s.destinationName=u;x.payloadMessage=s;break;case 4:case 5:case 6:case 7:case 11:x.messageIdentifier=256*e[f]+e[f+1];break;case 9:x.messageIdentifier=256*e[f]+e[f+1],f+=2,x.returnCode=e.subarray(f,w)}c=[x,w]}}var z=c[0],d=c[1];if(null!==z)b.push(z);else break}d<a.length&&(this.receiveBuffer=a.subarray(d))}catch(y){c="undefined"==y.hasOwnProperty("stack")?
|
||||
y.stack.toString():"No Error Stack Available";this._disconnected(g.INTERNAL_ERROR.code,h(g.INTERNAL_ERROR,[y.message,c]));return}return b};c.prototype._handleMessage=function(a){this._trace("Client._handleMessage",a);try{switch(a.type){case 2:this._connectTimeout.cancel();this._reconnectTimeout&&this._reconnectTimeout.cancel();if(this.connectOptions.cleanSession){for(var b in this._sentMessages){var d=this._sentMessages[b];m.removeStorageSync("Sent:"+this._localKey+d.messageIdentifier)}this._sentMessages=
|
||||
{};for(b in this._receivedMessages){var c=this._receivedMessages[b];m.removeStorageSync("Received:"+this._localKey+c.messageIdentifier)}this._receivedMessages={}}if(0===a.returnCode)this.connected=!0,this.connectOptions.uris&&(this.hostIndex=this.connectOptions.uris.length);else{this._disconnected(g.CONNACK_RETURNCODE.code,h(g.CONNACK_RETURNCODE,[a.returnCode,H[a.returnCode]]));break}a=[];for(var e in this._sentMessages)this._sentMessages.hasOwnProperty(e)&&a.push(this._sentMessages[e]);if(0<this._buffered_msg_queue.length){e=
|
||||
null;for(var f=this._buffered_msg_queue.reverse();e=f.pop();)a.push(e),this.onMessageDelivered&&(this._notify_msg_sent[e]=this.onMessageDelivered(e.payloadMessage))}a=a.sort(function(a,b){return a.sequence-b.sequence});for(var f=0,n=a.length;f<n;f++)if(d=a[f],3==d.type&&d.pubRecReceived){var p=new q(6,{messageIdentifier:d.messageIdentifier});this._schedule_message(p)}else this._schedule_message(d);if(this.connectOptions.onSuccess)this.connectOptions.onSuccess({invocationContext:this.connectOptions.invocationContext});
|
||||
d=!1;this._reconnecting&&(d=!0,this._reconnectInterval=1,this._reconnecting=!1);this._connected(d,this._wsuri);this._process_queue();break;case 3:this._receivePublish(a);break;case 4:if(d=this._sentMessages[a.messageIdentifier])if(delete this._sentMessages[a.messageIdentifier],m.removeStorageSync("Sent:"+this._localKey+a.messageIdentifier),this.onMessageDelivered)this.onMessageDelivered(d.payloadMessage);break;case 5:if(d=this._sentMessages[a.messageIdentifier])d.pubRecReceived=!0,p=new q(6,{messageIdentifier:a.messageIdentifier}),
|
||||
this.store("Sent:",d),this._schedule_message(p);break;case 6:c=this._receivedMessages[a.messageIdentifier];m.removeStorageSync("Received:"+this._localKey+a.messageIdentifier);c&&(this._receiveMessage(c),delete this._receivedMessages[a.messageIdentifier]);var l=new q(7,{messageIdentifier:a.messageIdentifier});this._schedule_message(l);break;case 7:d=this._sentMessages[a.messageIdentifier];delete this._sentMessages[a.messageIdentifier];m.removeStorageSync("Sent:"+this._localKey+a.messageIdentifier);
|
||||
if(this.onMessageDelivered)this.onMessageDelivered(d.payloadMessage);break;case 9:if(d=this._sentMessages[a.messageIdentifier]){d.timeOut&&d.timeOut.cancel();if(128===a.returnCode[0]){if(d.onFailure)d.onFailure(a.returnCode)}else if(d.onSuccess)d.onSuccess(a.returnCode);delete this._sentMessages[a.messageIdentifier]}break;case 11:if(d=this._sentMessages[a.messageIdentifier])d.timeOut&&d.timeOut.cancel(),d.callback&&d.callback(),delete this._sentMessages[a.messageIdentifier];break;case 13:this.sendPinger.reset();
|
||||
break;case 14:this._disconnected(g.INVALID_MQTT_MESSAGE_TYPE.code,h(g.INVALID_MQTT_MESSAGE_TYPE,[a.type]));break;default:this._disconnected(g.INVALID_MQTT_MESSAGE_TYPE.code,h(g.INVALID_MQTT_MESSAGE_TYPE,[a.type]))}}catch(t){d="undefined"==t.hasOwnProperty("stack")?t.stack.toString():"No Error Stack Available",this._disconnected(g.INTERNAL_ERROR.code,h(g.INTERNAL_ERROR,[t.message,d]))}};c.prototype._on_socket_error=function(a){this._reconnecting||this._disconnected(g.SOCKET_ERROR.code,h(g.SOCKET_ERROR,
|
||||
[a.data]))};c.prototype._on_socket_close=function(){this._reconnecting||this._disconnected(g.SOCKET_CLOSE.code,h(g.SOCKET_CLOSE))};c.prototype._socket_send=function(a){if(1==a.type){var b=this._traceMask(a,"password");this._trace("Client._socket_send",b)}else this._trace("Client._socket_send",a);m.sendSocketMessage({data:a.encode(),success:function(){},fail:function(){},complete:function(){}});this.sendPinger.reset()};c.prototype._receivePublish=function(a){switch(a.payloadMessage.qos){case "undefined":case 0:this._receiveMessage(a);
|
||||
break;case 1:var b=new q(4,{messageIdentifier:a.messageIdentifier});this._schedule_message(b);this._receiveMessage(a);break;case 2:this._receivedMessages[a.messageIdentifier]=a;this.store("Received:",a);a=new q(5,{messageIdentifier:a.messageIdentifier});this._schedule_message(a);break;default:throw Error("Invaild qos\x3d"+wireMmessage.payloadMessage.qos);}};c.prototype._receiveMessage=function(a){if(this.onMessageArrived)this.onMessageArrived(a.payloadMessage)};c.prototype._connected=function(a,b){if(this.onConnected)this.onConnected(a,
|
||||
b)};c.prototype._reconnect=function(){this._trace("Client._reconnect");this.connected||(this._reconnecting=!0,this.sendPinger.cancel(),this.receivePinger.cancel(),128>this._reconnectInterval&&(this._reconnectInterval*=2),this.connectOptions.uris?(this.hostIndex=0,this._doConnect(this.connectOptions.uris[0])):this._doConnect(this.uri))};c.prototype._disconnected=function(a,b){this._trace("Client._disconnected",a,b);if(void 0!==a&&this._reconnecting)this._reconnectTimeout=new z(this,this._reconnectInterval,
|
||||
this._reconnect);else if(this.sendPinger.cancel(),this.receivePinger.cancel(),this._connectTimeout&&(this._connectTimeout.cancel(),this._connectTimeout=null),this._msg_queue=[],this._buffered_msg_queue=[],this._notify_msg_sent={},this.connectOptions.uris&&this.hostIndex<this.connectOptions.uris.length-1)this.hostIndex++,this._doConnect(this.connectOptions.uris[this.hostIndex]);else if(void 0===a&&(a=g.OK.code,b=h(g.OK)),this.connected){this.connected=!1;if(this.onConnectionLost)this.onConnectionLost({errorCode:a,
|
||||
errorMessage:b,reconnect:this.connectOptions.reconnect,uri:this._wsuri});a!==g.OK.code&&this.connectOptions.reconnect&&(this._reconnectInterval=1,this._reconnect())}else if(4===this.connectOptions.mqttVersion&&!1===this.connectOptions.mqttVersionExplicit)this._trace("Failed to connect V4, dropping back to V3"),this.connectOptions.mqttVersion=3,this.connectOptions.uris?(this.hostIndex=0,this._doConnect(this.connectOptions.uris[0])):this._doConnect(this.uri);else if(this.connectOptions.onFailure)this.connectOptions.onFailure({invocationContext:this.connectOptions.invocationContext,
|
||||
errorCode:a,errorMessage:b})};c.prototype._trace=function(){if(this.traceFunction){for(var a in arguments)"undefined"!==typeof arguments[a]&&arguments.splice(a,1,JSON.stringify(arguments[a]));a=Array.prototype.slice.call(arguments).join("");this.traceFunction({severity:"Debug",message:a})}if(null!==this._traceBuffer){a=0;for(var b=arguments.length;a<b;a++)this._traceBuffer.length==this._MAX_TRACE_ENTRIES&&this._traceBuffer.shift(),0===a?this._traceBuffer.push(arguments[a]):"undefined"===typeof arguments[a]?
|
||||
this._traceBuffer.push(arguments[a]):this._traceBuffer.push(" "+JSON.stringify(arguments[a]))}};c.prototype._traceMask=function(a,b){var d={},c;for(c in a)a.hasOwnProperty(c)&&(d[c]=c==b?"******":a[c]);return d};var G=function(a,b,d,k){var e;if("string"!==typeof a)throw Error(h(g.INVALID_TYPE,[typeof a,"host"]));if(2==arguments.length){k=b;e=a;var f=e.match(/^(wss?):\/\/((\[(.+)\])|([^\/]+?))(:(\d+))?(\/.*)$/);if(f)a=f[4]||f[2],b=parseInt(f[7]),d=f[8];else throw Error(h(g.INVALID_ARGUMENT,[a,"host"]));
|
||||
}else{3==arguments.length&&(k=d,d="/mqtt");if("number"!==typeof b||0>b)throw Error(h(g.INVALID_TYPE,[typeof b,"port"]));if("string"!==typeof d)throw Error(h(g.INVALID_TYPE,[typeof d,"path"]));e="ws://"+(-1!==a.indexOf(":")&&"["!==a.slice(0,1)&&"]"!==a.slice(-1)?"["+a+"]":a)+":"+b+d}for(var n=f=0;n<k.length;n++){var m=k.charCodeAt(n);55296<=m&&56319>=m&&n++;f++}if("string"!==typeof k||65535<f)throw Error(h(g.INVALID_ARGUMENT,[k,"clientId"]));var l=new c(e,a,b,d,k);this._getHost=function(){return a};
|
||||
this._setHost=function(){throw Error(h(g.UNSUPPORTED_OPERATION));};this._getPort=function(){return b};this._setPort=function(){throw Error(h(g.UNSUPPORTED_OPERATION));};this._getPath=function(){return d};this._setPath=function(){throw Error(h(g.UNSUPPORTED_OPERATION));};this._getURI=function(){return e};this._setURI=function(){throw Error(h(g.UNSUPPORTED_OPERATION));};this._getClientId=function(){return l.clientId};this._setClientId=function(){throw Error(h(g.UNSUPPORTED_OPERATION));};this._getOnConnected=
|
||||
function(){return l.onConnected};this._setOnConnected=function(a){if("function"===typeof a)l.onConnected=a;else throw Error(h(g.INVALID_TYPE,[typeof a,"onConnected"]));};this._getDisconnectedPublishing=function(){return l.disconnectedPublishing};this._setDisconnectedPublishing=function(a){l.disconnectedPublishing=a};this._getDisconnectedBufferSize=function(){return l.disconnectedBufferSize};this._setDisconnectedBufferSize=function(a){l.disconnectedBufferSize=a};this._getOnConnectionLost=function(){return l.onConnectionLost};
|
||||
this._setOnConnectionLost=function(a){if("function"===typeof a)l.onConnectionLost=a;else throw Error(h(g.INVALID_TYPE,[typeof a,"onConnectionLost"]));};this._getOnMessageDelivered=function(){return l.onMessageDelivered};this._setOnMessageDelivered=function(a){if("function"===typeof a)l.onMessageDelivered=a;else throw Error(h(g.INVALID_TYPE,[typeof a,"onMessageDelivered"]));};this._getOnMessageArrived=function(){return l.onMessageArrived};this._setOnMessageArrived=function(a){if("function"===typeof a)l.onMessageArrived=
|
||||
a;else throw Error(h(g.INVALID_TYPE,[typeof a,"onMessageArrived"]));};this._getTrace=function(){return l.traceFunction};this._setTrace=function(a){if("function"===typeof a)l.traceFunction=a;else throw Error(h(g.INVALID_TYPE,[typeof a,"onTrace"]));};this.connect=function(a){a=a||{};y(a,{timeout:"number",userName:"string",password:"string",willMessage:"object",keepAliveInterval:"number",cleanSession:"boolean",useSSL:"boolean",invocationContext:"object",onSuccess:"function",onFailure:"function",hosts:"object",
|
||||
ports:"object",reconnect:"boolean",mqttVersion:"number",mqttVersionExplicit:"boolean",uris:"object"});void 0===a.keepAliveInterval&&(a.keepAliveInterval=60);if(4<a.mqttVersion||3>a.mqttVersion)throw Error(h(g.INVALID_ARGUMENT,[a.mqttVersion,"connectOptions.mqttVersion"]));void 0===a.mqttVersion?(a.mqttVersionExplicit=!1,a.mqttVersion=4):a.mqttVersionExplicit=!0;if(void 0!==a.password&&void 0===a.userName)throw Error(h(g.INVALID_ARGUMENT,[a.password,"connectOptions.password"]));if(a.willMessage){if(!(a.willMessage instanceof
|
||||
v))throw Error(h(g.INVALID_TYPE,[a.willMessage,"connectOptions.willMessage"]));a.willMessage.stringPayload=null;if("undefined"===typeof a.willMessage.destinationName)throw Error(h(g.INVALID_TYPE,[typeof a.willMessage.destinationName,"connectOptions.willMessage.destinationName"]));}"undefined"===typeof a.cleanSession&&(a.cleanSession=!0);if(a.hosts){if(!(a.hosts instanceof Array))throw Error(h(g.INVALID_ARGUMENT,[a.hosts,"connectOptions.hosts"]));if(1>a.hosts.length)throw Error(h(g.INVALID_ARGUMENT,
|
||||
[a.hosts,"connectOptions.hosts"]));for(var b=!1,c=0;c<a.hosts.length;c++){if("string"!==typeof a.hosts[c])throw Error(h(g.INVALID_TYPE,[typeof a.hosts[c],"connectOptions.hosts["+c+"]"]));if(/^(wss?):\/\/((\[(.+)\])|([^\/]+?))(:(\d+))?(\/.*)$/.test(a.hosts[c]))if(0===c)b=!0;else{if(!b)throw Error(h(g.INVALID_ARGUMENT,[a.hosts[c],"connectOptions.hosts["+c+"]"]));}else if(b)throw Error(h(g.INVALID_ARGUMENT,[a.hosts[c],"connectOptions.hosts["+c+"]"]));}if(b)a.uris=a.hosts;else{if(!a.ports)throw Error(h(g.INVALID_ARGUMENT,
|
||||
[a.ports,"connectOptions.ports"]));if(!(a.ports instanceof Array))throw Error(h(g.INVALID_ARGUMENT,[a.ports,"connectOptions.ports"]));if(a.hosts.length!==a.ports.length)throw Error(h(g.INVALID_ARGUMENT,[a.ports,"connectOptions.ports"]));a.uris=[];for(c=0;c<a.hosts.length;c++){if("number"!==typeof a.ports[c]||0>a.ports[c])throw Error(h(g.INVALID_TYPE,[typeof a.ports[c],"connectOptions.ports["+c+"]"]));var b=a.hosts[c],f=a.ports[c];e="ws://"+(-1!==b.indexOf(":")?"["+b+"]":b)+":"+f+d;a.uris.push(e)}}}l.connect(a)};
|
||||
this.subscribe=function(a,b){if("string"!==typeof a)throw Error("Invalid argument:"+a);b=b||{};y(b,{qos:"number",invocationContext:"object",onSuccess:"function",onFailure:"function",timeout:"number"});if(b.timeout&&!b.onFailure)throw Error("subscribeOptions.timeout specified with no onFailure callback.");if("undefined"!==typeof b.qos&&0!==b.qos&&1!==b.qos&&2!==b.qos)throw Error(h(g.INVALID_ARGUMENT,[b.qos,"subscribeOptions.qos"]));l.subscribe(a,b)};this.unsubscribe=function(a,b){if("string"!==typeof a)throw Error("Invalid argument:"+
|
||||
a);b=b||{};y(b,{invocationContext:"object",onSuccess:"function",onFailure:"function",timeout:"number"});if(b.timeout&&!b.onFailure)throw Error("unsubscribeOptions.timeout specified with no onFailure callback.");l.unsubscribe(a,b)};this.send=function(a,b,c,d){var e;if(0===arguments.length)throw Error("Invalid argument.length");if(1==arguments.length){if(!(a instanceof v)&&"string"!==typeof a)throw Error("Invalid argument:"+typeof a);e=a;if("undefined"===typeof e.destinationName)throw Error(h(g.INVALID_ARGUMENT,
|
||||
[e.destinationName,"Message.destinationName"]));}else e=new v(b),e.destinationName=a,3<=arguments.length&&(e.qos=c),4<=arguments.length&&(e.retained=d);l.send(e)};this.publish=function(a,b,c,d){console.log("Publising message to: ",a);var e;if(0===arguments.length)throw Error("Invalid argument.length");if(1==arguments.length){if(!(a instanceof v)&&"string"!==typeof a)throw Error("Invalid argument:"+typeof a);e=a;if("undefined"===typeof e.destinationName)throw Error(h(g.INVALID_ARGUMENT,[e.destinationName,
|
||||
"Message.destinationName"]));}else e=new v(b),e.destinationName=a,3<=arguments.length&&(e.qos=c),4<=arguments.length&&(e.retained=d);l.send(e)};this.disconnect=function(){l.disconnect()};this.getTraceLog=function(){return l.getTraceLog()};this.startTrace=function(){l.startTrace()};this.stopTrace=function(){l.stopTrace()};this.isConnected=function(){return l.connected}};G.prototype={get host(){return this._getHost()},set host(a){this._setHost(a)},get port(){return this._getPort()},set port(a){this._setPort(a)},
|
||||
get path(){return this._getPath()},set path(a){this._setPath(a)},get clientId(){return this._getClientId()},set clientId(a){this._setClientId(a)},get onConnected(){return this._getOnConnected()},set onConnected(a){this._setOnConnected(a)},get disconnectedPublishing(){return this._getDisconnectedPublishing()},set disconnectedPublishing(a){this._setDisconnectedPublishing(a)},get disconnectedBufferSize(){return this._getDisconnectedBufferSize()},set disconnectedBufferSize(a){this._setDisconnectedBufferSize(a)},
|
||||
get onConnectionLost(){return this._getOnConnectionLost()},set onConnectionLost(a){this._setOnConnectionLost(a)},get onMessageDelivered(){return this._getOnMessageDelivered()},set onMessageDelivered(a){this._setOnMessageDelivered(a)},get onMessageArrived(){return this._getOnMessageArrived()},set onMessageArrived(a){this._setOnMessageArrived(a)},get trace(){return this._getTrace()},set trace(a){this._setTrace(a)}};var v=function(a){var b;if("string"===typeof a||a instanceof ArrayBuffer||a instanceof
|
||||
Int8Array||a instanceof Uint8Array||a instanceof Int16Array||a instanceof Uint16Array||a instanceof Int32Array||a instanceof Uint32Array||a instanceof Float32Array||a instanceof Float64Array)b=a;else throw h(g.INVALID_ARGUMENT,[a,"newPayload"]);this._getPayloadString=function(){return"string"===typeof b?b:E(b,0,b.length)};this._getPayloadBytes=function(){if("string"===typeof b){var a=new ArrayBuffer(p(b)),a=new Uint8Array(a);D(b,a,0);return a}return b};var c;this._getDestinationName=function(){return c};
|
||||
this._setDestinationName=function(a){if("string"===typeof a)c=a;else throw Error(h(g.INVALID_ARGUMENT,[a,"newDestinationName"]));};var k=0;this._getQos=function(){return k};this._setQos=function(a){if(0===a||1===a||2===a)k=a;else throw Error("Invalid argument:"+a);};var e=!1;this._getRetained=function(){return e};this._setRetained=function(a){if("boolean"===typeof a)e=a;else throw Error(h(g.INVALID_ARGUMENT,[a,"newRetained"]));};var f=!1;this._getDuplicate=function(){return f};this._setDuplicate=
|
||||
function(a){f=a}};v.prototype={get payloadString(){return this._getPayloadString()},get payloadBytes(){return this._getPayloadBytes()},get destinationName(){return this._getDestinationName()},set destinationName(a){this._setDestinationName(a)},get topic(){return this._getDestinationName()},set topic(a){this._setDestinationName(a)},get qos(){return this._getQos()},set qos(a){this._setQos(a)},get retained(){return this._getRetained()},set retained(a){this._setRetained(a)},get duplicate(){return this._getDuplicate()},
|
||||
set duplicate(a){this._setDuplicate(a)}};return{Client:G,Message:v}}(wx)});
|
||||
// ESM only export
|
||||
const __PahoMQTT = (typeof global !== 'undefined' && global.Paho && global.Paho.MQTT) ? global.Paho.MQTT : null;
|
||||
export default __PahoMQTT;
|
||||
@@ -0,0 +1,156 @@
|
||||
export { CONNECT_STATUS,MQTT_EVENT_TYPE,MQTT_EVENT_CALL,MQTT_EVENT_PUBLISH,MQTT_SUBSCRIBE,MQTT_EVENTS_CALL,MQTT_PUBLISH_TOPIC,MQTT_CONNECT_OPTS } from "../interface.uts"
|
||||
import PahoMqtt from "./paho-mqtt.min.js"
|
||||
// var client = new Paho.MQTT.Client(location.hostname, Number(location.port), "clientId");
|
||||
// mqtt测试服务器
|
||||
// https://console.hivemq.cloud/
|
||||
// https://github.com/eclipse/paho.mqtt.javascript
|
||||
// https://eclipse.dev/paho/files/jsdoc/Paho.MQTT.Client.html
|
||||
|
||||
type MqttConnectOptions = {
|
||||
userName?:string,
|
||||
password?:string,
|
||||
useSSL?:boolean,
|
||||
keepAliveInterval?:number,
|
||||
timeout?:number,
|
||||
reconnect?:boolean,
|
||||
onSuccess?:any,
|
||||
onFailure?:any
|
||||
}
|
||||
const Paho = PahoMqtt()
|
||||
export class xMqtt {
|
||||
mqtt : MqttAndroidClient | null = null;
|
||||
mqttConnectOptions : MqttConnectOptions | null = null;
|
||||
connectStatus:CONNECT_STATUS = 'wait'
|
||||
events = new Map<string,MQTT_EVENTS_CALL>();
|
||||
constructor(){
|
||||
|
||||
}
|
||||
/**
|
||||
* @param ulr {string} 连接地址
|
||||
* @param clientIdStr {string} 客户端id
|
||||
* @param username {string|null} 用户名称,如果不需要,设置为null即可
|
||||
* @param password {string|null} 登录密码,如果不需要,设置为null即可
|
||||
*/
|
||||
create(opts:MQTT_CONNECT_OPTS):xMqtt {
|
||||
|
||||
let t = this;
|
||||
this.mqtt = new Paho.Client(opts.server,opts.port,opts.path, opts.clientId);
|
||||
this.mqttConnectOptions = {} as MqttConnectOptions;
|
||||
this.mqttConnectOptions.userName = opts.userName;
|
||||
this.mqttConnectOptions.password = opts.passWord;
|
||||
this.mqttConnectOptions.useSSL = opts.useSSL;
|
||||
this.mqttConnectOptions.keepAliveInterval = opts.keepAliveInterval;
|
||||
this.mqttConnectOptions.timeout = opts.timeout;
|
||||
this.mqttConnectOptions.onSuccess = ()=>{
|
||||
console.log('****')
|
||||
t.buildCallEvents('open',null,'连接成功')
|
||||
};
|
||||
this.mqttConnectOptions.onFailure = ()=>{
|
||||
t.buildCallEvents('error',null,'连接失败')
|
||||
};
|
||||
this.mqttConnectOptions.reconnect = opts.reconnect;
|
||||
this.mqtt.onConnectionLost = ()=>{
|
||||
t.buildCallEvents('dissconnect',null,'连接断开')
|
||||
};
|
||||
this.mqtt.onMessageArrived = (evt)=>{
|
||||
|
||||
t.buildCallEvents('message',evt.topic,evt.payloadString)
|
||||
};
|
||||
this.connectStatus = 'wait'
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type {MQTT_EVENT_TYPE} 事件名称
|
||||
* @param call {MQTT_EVENT_CALL} 事件回调
|
||||
*/
|
||||
addEventListener(type:MQTT_EVENT_TYPE,call:MQTT_EVENT_CALL):string{
|
||||
let id = Date.now().toString()+(Math.random()*100).toString()
|
||||
this.events.set(id,
|
||||
{
|
||||
type,
|
||||
value:call
|
||||
} as MQTT_EVENTS_CALL
|
||||
)
|
||||
|
||||
return id;
|
||||
}
|
||||
/**
|
||||
* @param id {string} addEventListener返回的事件id
|
||||
*/
|
||||
removeEventListener(id:string):xMqtt{
|
||||
this.events.delete(id)
|
||||
return this;
|
||||
}
|
||||
private buildCallEvents(type:MQTT_EVENT_TYPE,toppic:string|null,str:string){
|
||||
this.events.forEach((value:MQTT_EVENTS_CALL,key:string)=>{
|
||||
if(value.type == type){
|
||||
value.value(type,toppic,str)
|
||||
}
|
||||
})
|
||||
}
|
||||
connect():xMqtt{
|
||||
|
||||
this.mqtt?.connect(this.mqttConnectOptions);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 订阅
|
||||
* @param data {MQTT_SUBSCRIBE[]} 订阅的消息数组
|
||||
*/
|
||||
subscribe(data:MQTT_SUBSCRIBE[]):xMqtt{
|
||||
let t = this;
|
||||
if(this.mqtt == null) return this;
|
||||
for(let i=0;i<data.length;i++){
|
||||
|
||||
this.mqtt.subscribe(data[i].topic,{
|
||||
qos:data[i].qos,
|
||||
onSuccess(){
|
||||
console.log("订阅成功")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 推送消息
|
||||
* @param message {MQTT_EVENT_PUBLISH}
|
||||
* @param call ()=>void 推送消息成功时的回调【web端永为真】
|
||||
*/
|
||||
publish(message:MQTT_PUBLISH_TOPIC,call:MQTT_EVENT_PUBLISH):xMqtt{
|
||||
if(this.mqtt == null) return this;
|
||||
this.mqtt!.publish(message.topic,message.message,message.qos,true);
|
||||
call(true)
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 取消订阅
|
||||
* @param topics {string[]} 主题数组
|
||||
*/
|
||||
unsubscribe(topics:string[]):xMqtt{
|
||||
let t = this;
|
||||
if(this.mqtt == null||topics.length==0) return this;
|
||||
for(let i=0;i<topics.length;i++){
|
||||
this.mqtt!.unsubscribe(topics[i],{
|
||||
onSuccess(){
|
||||
console.log("取消订阅成功")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 断开连接
|
||||
*/
|
||||
disconnect():xMqtt{
|
||||
if(this.mqtt == null) return this;
|
||||
this.mqtt!.disconnect()
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
+2604
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user