yimultiscreenserver-sdk-web
Version:
YiMultiScreenServer SDK for Web
157 lines • 7.17 kB
JavaScript
import { MQTTLogic } from "../MQTTLogic";
import { MsgClientType } from "../message/MsgClientType";
import { MsgType } from "../message/MsgType";
import { WillMessage } from "../message/WillMessage";
import { Utils } from '../../../util/Utils';
import { SDKLog } from "../../../util/SDKLog";
import { SessionDestroyReason } from "../message/SessionDestroyReason";
export class ControllerMQTTImpl extends MQTTLogic {
constructor(clientId, callback) {
super(clientId);
this.MYSELF_DISCONNECT_CALLBACK_GAP_MS = 500; // 0.5s
this.callback = callback;
this.accountId = -1;
this.isSkipDisconnectCallbackOnce = false;
this.lastDisconnectTime = 0;
}
// Override
// 控制端需要覆写实现下父类的connect方法
// 因为控制端需要处理两种场景:1.先登录账户,再连接display;2.先连接display,再登录账户
async connect(displayCode) {
if (this.isConnected) {
// 此时就是场景1。用户先登录账户,再连接display
// 必须先断开连接,因为登录账户时connect使用的option不包括will message
// 所以要重新使用新的带有will message的option连接
this.isSkipDisconnectCallbackOnce = true;
this.unsubscribeAccountTopic(this.accountId);
await super.disconnect(displayCode)
.then((result) => {
this.isConnected = false;
})
.catch((error) => {
//不关注error
});
}
super.connect(displayCode);
// 连接成功后,再次订阅上account相关的topic消息
if (-1 != this.accountId) {
this.subscribeAccountTopic(this.accountId);
}
}
// Override
// 控制端需要覆写实现下父类的disconnect方法
// 因为控制端需要处理: 同时处于登录&连接display状态时,用户断开display后,如何处理账号topic消息的监听
async disconnect(displayCode) {
// 用户断开display时,原逻辑是彻底断开mqtt连接,但此时用户还处于登录状态
return new Promise((resolve, reject) => {
super.disconnect(displayCode)
.then((result) => {
resolve(result);
})
.catch(reject);
// 有必要判断此时是否订阅了账号topic消息,如果订阅了,则断开后需要重新连接上mqtt服务
if (-1 != this.accountId) {
// 说明此时用户还处于登录状态,重新连接上mqtt服务订阅上账号相关的topic消息
this.subscribeAccountTopic(this.accountId);
}
});
}
/**
* 控制端单独增加的公开方法,用于控制端成功完成账号登录后,监听该账号topic下消息
* @param accountId 登录后拿到的账号唯一ID
*/
subscribeAccountTopic(accountId) {
this.accountId = accountId;
if (!this.isConnected) {
super.connectWithOptions(super.createMqttOptions());
}
let account = Utils.getTopicPrefix(MsgType.ACCOUNT) + accountId;
let bindDevice = Utils.getTopicPrefix(MsgType.BIND_DEVICE) + accountId;
let topics = [account, bindDevice];
super.getClient()?.subscribe(topics);
}
/**
* 控制端单独增加的公开方法,用于控制端成功退出账号或注销账号后,解除对指定账号的topic消息监听
* @param accountId 登录后拿到的账号唯一ID
*/
unsubscribeAccountTopic(accountId) {
this.accountId = -1;
if (!this.isConnected) {
return;
}
let account = Utils.getTopicPrefix(MsgType.ACCOUNT) + accountId;
let bindDevice = Utils.getTopicPrefix(MsgType.BIND_DEVICE) + accountId;
let topics = [account, bindDevice];
super.getClient()?.unsubscribe(topics);
}
isMessageFromSelf(message) {
return MsgClientType.CONTROLLER == message.sender;
}
isMessageForMe(message) {
return (MsgClientType.ANY == message.receiver
|| MsgClientType.CONTROLLER == message.receiver);
}
createMySelfWill(displayCode, clientId) {
let ret = new WillMessage(MsgClientType.CONTROLLER, MsgClientType.ANY);
ret.senderClientId = clientId;
ret.timestamp = Date.now();
return ret;
}
subscribeInterestTopic(displayCode) {
let will = Utils.getTopicPrefix(MsgType.WILL) + displayCode;
let report = Utils.getTopicPrefix(MsgType.REPORT) + displayCode;
let cast = Utils.getTopicPrefix(MsgType.CAST) + displayCode;
let topics = [will, report, cast];
super.getClient()?.subscribe(topics);
}
unsubscribeAllTopics(displayCode) {
let will = Utils.getTopicPrefix(MsgType.WILL) + displayCode;
let report = Utils.getTopicPrefix(MsgType.REPORT) + displayCode;
let cast = Utils.getTopicPrefix(MsgType.CAST) + displayCode;
let topics = [will, report, cast];
super.getClient()?.unsubscribe(topics);
}
onWillMessageArrived(message) {
// must be display or server died
if (MsgClientType.DISPLAY == message.sender) {
this.callback.onDisplayDied();
}
else if (MsgClientType.SERVER == message.sender) {
this.callback.onServerDied();
}
}
onDisplayReportMessageArrived(message) {
this.callback.onDisplayReport(message.displayReport);
}
onCastSessionMessageArrived(message) {
this.callback.onCastSession(message.castSession, message.action, message.mediaPayload, message.destroyReason ?? SessionDestroyReason.NONE);
}
onDataMessageArrived(message) {
// we don't care about data msg
}
onUserHasBeenKickedMessageArrived(message) {
this.callback.onUserHasBeenKicked(message.user);
}
onAccountBindDeviceMessageArrived(message) {
this.callback.onAccountBindDevice(message.accountBindDevice, message.bindDeviceAction);
}
onConnectionLost(cause) {
let now = Date.now();
if (now - this.lastDisconnectTime <= this.MYSELF_DISCONNECT_CALLBACK_GAP_MS) {
// 自身断开连接回调做一个时间防抖,一定时长内连续触发我们都予以跳过
// 因为实操中发现前端使用的mtqq库会多次回调connectionLost
SDKLog.d(this.TAG, "一定时长内连续触发connectionLost回调,跳过");
return;
}
this.lastDisconnectTime = now;
if (this.isSkipDisconnectCallbackOnce) {
// 此时,场景是用户先登录连接了mqtt,再connect display
// 我们在connect时会先断开mqtt再重连,如果这次断开触发回调会导致上层不符合预期
SDKLog.d(this.TAG, "先登录再connect display,sdk主动触发一次重连,跳过这次回调");
this.isSkipDisconnectCallbackOnce = false;
return;
}
this.callback.onMySelfDisconnected(cause);
}
}
//# sourceMappingURL=ControllerMQTTImpl.js.map