|
|
|
|
import 'dart:convert';
|
|
|
|
|
|
|
|
|
|
import 'package:bytedesk_kefu/bytedesk_kefu.dart';
|
|
|
|
|
import 'package:bytedesk_kefu/model/message.dart';
|
|
|
|
|
import 'package:bytedesk_kefu/model/thread.dart';
|
|
|
|
|
import 'package:bytedesk_kefu/model/user.dart';
|
|
|
|
|
// TODO: 条件引入web,格式类似:import 'src/configure_imp.dart' if (dart.library.html) 'src/configure_web.dart' as conf;
|
|
|
|
|
// ignore: uri_does_not_exist
|
|
|
|
|
import 'package:bytedesk_kefu/mqtt/lib/mqtt_browser_client.dart';
|
|
|
|
|
import 'package:bytedesk_kefu/mqtt/lib/mqtt_client.dart';
|
|
|
|
|
import 'package:bytedesk_kefu/mqtt/lib/mqtt_server_client.dart';
|
|
|
|
|
import 'package:bytedesk_kefu/util/bytedesk_constants.dart';
|
|
|
|
|
import 'package:bytedesk_kefu/model/messageProvider.dart';
|
|
|
|
|
import 'package:bytedesk_kefu/util/bytedesk_events.dart';
|
|
|
|
|
import 'package:bytedesk_kefu/util/bytedesk_extraparam.dart';
|
|
|
|
|
import 'package:bytedesk_kefu/util/bytedesk_utils.dart';
|
|
|
|
|
import 'package:bytedesk_kefu/util/bytedesk_uuid.dart';
|
|
|
|
|
import 'package:sp_util/sp_util.dart';
|
|
|
|
|
// FIXME: proto文件重新生成兼容null-safty报错
|
|
|
|
|
// ignore: import_of_legacy_library_into_null_safe
|
|
|
|
|
import 'package:bytedesk_kefu/protobuf/message.pb.dart' as protomsg;
|
|
|
|
|
// ignore: import_of_legacy_library_into_null_safe
|
|
|
|
|
import 'package:bytedesk_kefu/protobuf/thread.pb.dart' as protothread;
|
|
|
|
|
// ignore: import_of_legacy_library_into_null_safe
|
|
|
|
|
import 'package:bytedesk_kefu/protobuf/user.pb.dart' as protouser;
|
|
|
|
|
import 'package:flutter/services.dart';
|
|
|
|
|
// import 'package:fluttertoast/fluttertoast.dart';
|
|
|
|
|
// import 'package:vibration/vibration.dart';
|
|
|
|
|
|
|
|
|
|
class BytedeskMqtt {
|
|
|
|
|
//
|
|
|
|
|
var mqttClient;
|
|
|
|
|
String? clientId;
|
|
|
|
|
int keepAlivePeriod = 20;
|
|
|
|
|
// final key = Key.fromUtf8('16BytesLengthKey');
|
|
|
|
|
// final iv = IV.fromUtf8('A-16-Byte-String');
|
|
|
|
|
MessageProvider messageProvider = new MessageProvider();
|
|
|
|
|
List<String> midList = [];
|
|
|
|
|
// bool _isConnected = false;
|
|
|
|
|
String? currentUid;
|
|
|
|
|
String? client;
|
|
|
|
|
|
|
|
|
|
// 单例模式
|
|
|
|
|
static final BytedeskMqtt _singleton = BytedeskMqtt._internal();
|
|
|
|
|
factory BytedeskMqtt() {
|
|
|
|
|
return _singleton;
|
|
|
|
|
}
|
|
|
|
|
BytedeskMqtt._internal();
|
|
|
|
|
|
|
|
|
|
void connect() async {
|
|
|
|
|
// eventbus发送广播,连接中...
|
|
|
|
|
bytedeskEventBus
|
|
|
|
|
.fire(ConnectionEventBus(BytedeskConstants.USER_STATUS_CONNECTING));
|
|
|
|
|
//
|
|
|
|
|
currentUid = SpUtil.getString(BytedeskConstants.uid);
|
|
|
|
|
client = BytedeskUtils.getClient();
|
|
|
|
|
clientId = "$currentUid/$client";
|
|
|
|
|
|
|
|
|
|
//注意:必须要先判断web,否则在web运行会报错:
|
|
|
|
|
// Unsupported operation: Platform._operatingSystem
|
|
|
|
|
if (BytedeskUtils.isWeb) {
|
|
|
|
|
if (BytedeskConstants.isDebug) {
|
|
|
|
|
mqttClient = MqttBrowserClient.withPort(
|
|
|
|
|
'ws://127.0.0.1/websocket', clientId!, 3885);
|
|
|
|
|
} else {
|
|
|
|
|
mqttClient = MqttBrowserClient.withPort(
|
|
|
|
|
BytedeskConstants.webSocketWssUrl, clientId!, 443);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (BytedeskConstants.isWebSocketWss) {
|
|
|
|
|
mqttClient =
|
|
|
|
|
MqttServerClient(BytedeskConstants.webSocketWssUrl, clientId!);
|
|
|
|
|
mqttClient.useWebSocket = true;
|
|
|
|
|
mqttClient.port = 443;
|
|
|
|
|
|
|
|
|
|
/// You can also supply your own websocket protocol list or disable this feature using the websocketProtocols
|
|
|
|
|
/// setter, read the API docs for further details here, the vast majority of brokers will support the client default
|
|
|
|
|
/// list so in most cases you can ignore this. Mosquito needs the single default setting.
|
|
|
|
|
// mqttClient.websocketProtocols = MqttClientConstants.protocolsSingleDefault;
|
|
|
|
|
} else {
|
|
|
|
|
mqttClient = MqttServerClient(BytedeskConstants.mqttHost, clientId!);
|
|
|
|
|
mqttClient.port = BytedeskConstants.mqttPort;
|
|
|
|
|
mqttClient.secure = BytedeskConstants.isSecure;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 启用3.1.1版本协议,否则clientId限制最大长度为23
|
|
|
|
|
mqttClient.setProtocolV311();
|
|
|
|
|
|
|
|
|
|
/// Set logging on if needed, defaults to off
|
|
|
|
|
// mqttClient.logging(on: BytedeskConstants.isDebug);
|
|
|
|
|
mqttClient.logging(on: false); // BytedeskConstants.isDebug
|
|
|
|
|
/// If you intend to use a keep alive value in your connect message that is not the default(60s)
|
|
|
|
|
/// you must set it here
|
|
|
|
|
mqttClient.keepAlivePeriod = keepAlivePeriod;
|
|
|
|
|
mqttClient.autoReconnect = true; // FIXME:
|
|
|
|
|
// mqttClient.onAutoReconnect = _onAutoReconnect; // FIXME:
|
|
|
|
|
mqttClient.onDisconnected = _onDisconnected;
|
|
|
|
|
mqttClient.onConnected = _onConnected;
|
|
|
|
|
mqttClient.onSubscribed = _onSubscribed;
|
|
|
|
|
mqttClient.onUnsubscribed = _onUnSubscribed;
|
|
|
|
|
mqttClient.onSubscribeFail = _onSubscribeFailed;
|
|
|
|
|
|
|
|
|
|
/// Set a ping received callback if needed, called whenever a ping response(pong) is received from the broker.
|
|
|
|
|
mqttClient.pongCallback = _onPong;
|
|
|
|
|
|
|
|
|
|
/// Create a connection message to use or use the default one. The default one sets the
|
|
|
|
|
/// client identifier, any supplied username/password, the default keepalive interval(60s)
|
|
|
|
|
/// and clean session, an example of a specific one below.
|
|
|
|
|
|
|
|
|
|
final MqttConnectMessage connMessage = MqttConnectMessage()
|
|
|
|
|
.withClientIdentifier(clientId!)
|
|
|
|
|
.authenticateAs('username', 'password'); // TODO: 服务器暂时不需要auth,随便填写
|
|
|
|
|
// .keepAliveFor(keepAlivePeriod); // Must agree with the keep alive set above or not set
|
|
|
|
|
// 取消客户端设置,直接在服务器端统一内容格式推送
|
|
|
|
|
// .withWillTopic('protobuf/lastWill/mqtt') // If you set this you must set a will message
|
|
|
|
|
// .withWillMessage('My Will message')
|
|
|
|
|
// .startClean() // Non persistent session for testing
|
|
|
|
|
// .withWillQos(MqttQos.atLeastOnce);
|
|
|
|
|
BytedeskUtils.printLog('mqttClient connecting....');
|
|
|
|
|
mqttClient.connectionMessage = connMessage;
|
|
|
|
|
|
|
|
|
|
/// Connect the client, any errors here are communicated by raising of the appropriate exception. Note
|
|
|
|
|
/// in some circumstances the broker will just disconnect us, see the spec about this, we however eill
|
|
|
|
|
/// never send malformed messages.
|
|
|
|
|
try {
|
|
|
|
|
await mqttClient.connect();
|
|
|
|
|
} on Exception catch (e) {
|
|
|
|
|
BytedeskUtils.printLog('mqttClient exception - $e');
|
|
|
|
|
mqttClient.disconnect();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Check we are connected
|
|
|
|
|
if (mqttClient.connectionStatus.state == MqttConnectionState.connected) {
|
|
|
|
|
BytedeskUtils.printLog('mqttClient connected');
|
|
|
|
|
} else {
|
|
|
|
|
/// Use status here rather than state if you also want the broker return code.
|
|
|
|
|
BytedeskUtils.printLog(
|
|
|
|
|
'ERROR mqttClient connection failed - disconnecting, status is ${mqttClient.connectionStatus}');
|
|
|
|
|
mqttClient.disconnect();
|
|
|
|
|
// exit(-1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The client has a change notifier object(see the Observable class) which we then listen to to get
|
|
|
|
|
/// notifications of published updates to each subscribed topic.
|
|
|
|
|
// mqttClient.updates!.listen((List<MqttReceivedMessage<MqttMessage>> c) {
|
|
|
|
|
// final MqttPublishMessage recMess = c[0].payload;
|
|
|
|
|
// final String pt =
|
|
|
|
|
// MqttPublishPayload.bytesToStringAsString(recMess.payload.message);
|
|
|
|
|
// // BytedeskUtils.printLog('Change notification:: topic is <${c[0].topic}>, payload is <-- $pt -->');
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
/// 收到的消息
|
|
|
|
|
// if (mqttClient != null && mqttClient.published != null) {
|
|
|
|
|
//
|
|
|
|
|
mqttClient.published!.listen((MqttPublishMessage messageBinary) {
|
|
|
|
|
// BytedeskUtils.printLog('Published notification:: topic is ${messageBinary.variableHeader.topicName}, with Qos ${messageBinary.header.qos}');
|
|
|
|
|
//
|
|
|
|
|
protomsg.Message messageProto =
|
|
|
|
|
protomsg.Message.fromBuffer(messageBinary.payload.message);
|
|
|
|
|
// FIXME: 自己发送的消息显示两条?此处根据mid去个重
|
|
|
|
|
var mid = messageProto.mid;
|
|
|
|
|
if (midList.contains(mid)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
midList.add(mid);
|
|
|
|
|
//
|
|
|
|
|
var uid = messageProto.user.uid;
|
|
|
|
|
var username = messageProto.user.username;
|
|
|
|
|
var nickname = messageProto.user.nickname;
|
|
|
|
|
var avatar = messageProto.user.avatar;
|
|
|
|
|
//
|
|
|
|
|
var content = '';
|
|
|
|
|
var type = messageProto.type;
|
|
|
|
|
var timestamp = messageProto.timestamp;
|
|
|
|
|
var client = messageProto.client;
|
|
|
|
|
//
|
|
|
|
|
BytedeskUtils.printLog('bytedesk_mqtt.dart receive type:' +
|
|
|
|
|
type +
|
|
|
|
|
' client:' +
|
|
|
|
|
client +
|
|
|
|
|
' mid:' +
|
|
|
|
|
mid);
|
|
|
|
|
// 非会话消息,如:会议通知等, 另行处理
|
|
|
|
|
if (type == BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_NOTICE) {
|
|
|
|
|
// TODO: 待处理
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
//
|
|
|
|
|
User user = new User(
|
|
|
|
|
uid: uid, username: username, nickname: nickname, avatar: avatar);
|
|
|
|
|
//
|
|
|
|
|
Thread thread = new Thread(
|
|
|
|
|
tid: messageProto.thread.tid,
|
|
|
|
|
type: messageProto.thread.type,
|
|
|
|
|
// uid: '',
|
|
|
|
|
nickname: messageProto.thread.nickname,
|
|
|
|
|
avatar: messageProto.thread.avatar,
|
|
|
|
|
content: messageProto.thread.content,
|
|
|
|
|
timestamp: messageProto.thread.timestamp,
|
|
|
|
|
unreadCount: messageProto.thread.unreadCount,
|
|
|
|
|
topic: messageProto.thread.topic,
|
|
|
|
|
client: client);
|
|
|
|
|
Message message = new Message(
|
|
|
|
|
mid: mid,
|
|
|
|
|
content: content,
|
|
|
|
|
imageUrl: content,
|
|
|
|
|
nickname: nickname,
|
|
|
|
|
avatar: avatar,
|
|
|
|
|
type: type,
|
|
|
|
|
timestamp: timestamp,
|
|
|
|
|
status: 'stored',
|
|
|
|
|
isSend: uid == currentUid ? 1 : 0,
|
|
|
|
|
currentUid: currentUid,
|
|
|
|
|
thread: thread,
|
|
|
|
|
user: user,
|
|
|
|
|
client: client);
|
|
|
|
|
// 是否发送消息回执
|
|
|
|
|
// var autoReply = false;
|
|
|
|
|
var sendReceipt = false;
|
|
|
|
|
// var webRTCVideoInvite = false;
|
|
|
|
|
// var webRTCAudioInvite = false;
|
|
|
|
|
switch (type) {
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_TEXT:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// autoReply = true;
|
|
|
|
|
sendReceipt = true;
|
|
|
|
|
// TODO: 判断是否加密,暂时不需要
|
|
|
|
|
message.content = messageProto.text.content;
|
|
|
|
|
BytedeskUtils.printLog('receive text:' + message.content!);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_IMAGE:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// autoReply = true;
|
|
|
|
|
sendReceipt = true;
|
|
|
|
|
message.imageUrl = messageProto.image.imageUrl;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_VOICE:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// autoReply = true;
|
|
|
|
|
sendReceipt = true;
|
|
|
|
|
message.voiceUrl = messageProto.voice.voiceUrl;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_FILE:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// autoReply = true;
|
|
|
|
|
sendReceipt = true;
|
|
|
|
|
message.fileUrl = messageProto.file.fileUrl;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_VIDEO:
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_SHORT_VIDEO:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// autoReply = true;
|
|
|
|
|
sendReceipt = true;
|
|
|
|
|
message.videoUrl = messageProto.video.videoOrShortUrl;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_THREAD:
|
|
|
|
|
{
|
|
|
|
|
message.content = messageProto.text.content;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_THREAD_REENTRY:
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_COMMODITY:
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_CONNECT:
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_DISCONNECT:
|
|
|
|
|
{
|
|
|
|
|
message.content = messageProto.text.content;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_QUEUE:
|
|
|
|
|
{
|
|
|
|
|
message.content = messageProto.text.content;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_QUEUE_ACCEPT:
|
|
|
|
|
{
|
|
|
|
|
// 替换 'joinQueueThread'
|
|
|
|
|
message.content = '接入队列会话'; // TODO: 国际化
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_AGENT_CLOSE:
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_VISITOR_CLOSE:
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_AUTO_CLOSE:
|
|
|
|
|
{
|
|
|
|
|
message.content = messageProto.text.content;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_TICKET:
|
|
|
|
|
{
|
|
|
|
|
// TODO: 工单消息
|
|
|
|
|
message.content = messageProto.text.content;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_FEEDBACK:
|
|
|
|
|
{
|
|
|
|
|
// TODO: 意见反馈
|
|
|
|
|
message.content = messageProto.text.content;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_CHANNEL:
|
|
|
|
|
{
|
|
|
|
|
// TODO: 渠道消息
|
|
|
|
|
message.content = messageProto.text.content;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_PREVIEW:
|
|
|
|
|
{
|
|
|
|
|
// 对方正在输入
|
|
|
|
|
String uid = messageProto.user.uid;
|
|
|
|
|
String previewContent = messageProto.preview.content;
|
|
|
|
|
if (uid != currentUid) {
|
|
|
|
|
bytedeskEventBus
|
|
|
|
|
.fire(ReceiveMessagePreviewEventBus(previewContent));
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_RECEIPT:
|
|
|
|
|
{
|
|
|
|
|
// 消息回执
|
|
|
|
|
var midR = messageProto.receipt.mid;
|
|
|
|
|
var statusR = messageProto.receipt.status;
|
|
|
|
|
messageProvider.update(midR, statusR);
|
|
|
|
|
// 通知界面更新聊天记录状态
|
|
|
|
|
bytedeskEventBus.fire(ReceiveMessageReceiptEventBus(midR, statusR));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_RECALL:
|
|
|
|
|
{
|
|
|
|
|
// 消息撤回
|
|
|
|
|
String mid = messageProto.recall.mid;
|
|
|
|
|
bytedeskEventBus.fire(DeleteMessageEventBus(mid));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_TRANSFER:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_TRANSFER_ACCEPT:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_TRANSFER_REJECT:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_INVITE:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_INVITE_ACCEPT:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_INVITE_REJECT:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_INVITE_RATE:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_RATE_RESULT:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_WEBRTC_INVITE_VIDEO:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_WEBRTC_INVITE_AUDIO:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_WEBRTC_CANCEL:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_WEBRTC_OFFER_VIDEO:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_WEBRTC_OFFER_AUDIO:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_WEBRTC_ANSWER:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_WEBRTC_CANDIDATE:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_WEBRTC_ACCEPT:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_WEBRTC_REJECT:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_WEBRTC_READY:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_WEBRTC_BUSY:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_WEBRTC_CLOSE:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_CREATE:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_UPDATE:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_ANNOUNCEMENT:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_INVITE:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_INVITE_ACCEPT:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_INVITE_REJECT:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_APPLY:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_APPLY_APPROVE:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_APPLY_DENY:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_KICK:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_MUTE:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_TRANSFER:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_TRANSFER_ACCEPT:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_TRANSFER_REJECT:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_WITHDRAW:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_DISMISS:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_LOCATION:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_LINK:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_EVENT:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_CUSTOM:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case BytedeskConstants.MESSAGE_TYPE_RED_PACKET:
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
BytedeskUtils.printLog('other message type:' + type);
|
|
|
|
|
}
|
|
|
|
|
// 客服端使用
|
|
|
|
|
// if (autoReply) {
|
|
|
|
|
// //
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
if (sendReceipt && message.isSend == 0) {
|
|
|
|
|
// 发送送达回执
|
|
|
|
|
sendReceiptReceivedMessage(mid, thread);
|
|
|
|
|
}
|
|
|
|
|
//
|
|
|
|
|
// final encrypter = Encrypter(AES(key, mode: AESMode.cbc));
|
|
|
|
|
// final decrypted = encrypter.decrypt64(messageProto.text.content, iv: iv);
|
|
|
|
|
// BytedeskUtils.printLog('content: ' + decrypted);
|
|
|
|
|
//
|
|
|
|
|
// 忽略连接信息
|
|
|
|
|
if (message.content == 'visitorConnect' ||
|
|
|
|
|
message.content == 'visitorDisconnect') {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// 插入本地数据库
|
|
|
|
|
// if (messageProvider != null) {
|
|
|
|
|
messageProvider.insert(message);
|
|
|
|
|
// }
|
|
|
|
|
// 通知界面显示聊天记录
|
|
|
|
|
bytedeskEventBus.fire(ReceiveMessageEventBus(message));
|
|
|
|
|
// 接收消息播放提示音,放到SDK外实现,迁移到demo中
|
|
|
|
|
if (BytedeskKefu.getPlayAudioOnReceiveMessage()! && message.isSend == 0) {
|
|
|
|
|
// BytedeskUtils.printLog('play audio');
|
|
|
|
|
SystemSound.play(SystemSoundType.click);
|
|
|
|
|
}
|
|
|
|
|
// 振动,放到SDK外实现,迁移到demo中
|
|
|
|
|
if (BytedeskKefu.getVibrateOnReceiveMessage()! && message.isSend == 0) {
|
|
|
|
|
// BytedeskUtils.printLog('should vibrate');
|
|
|
|
|
vibrate();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
//
|
|
|
|
|
// } else {
|
|
|
|
|
// BytedeskUtils.printLog('mqttClient.published is null');
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FIXME: ld: library not found for -lvibration
|
|
|
|
|
void vibrate() async {
|
|
|
|
|
// if (await Vibration.hasVibrator()) {
|
|
|
|
|
// Vibration.vibrate();
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void subscribe(String topic) {
|
|
|
|
|
// BytedeskUtils.printLog('Subscribing to the hello topic');
|
|
|
|
|
mqttClient.subscribe(topic, MqttQos.exactlyOnce);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void unsubscribe(String topic) {
|
|
|
|
|
mqttClient.unsubscribe(topic);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void sendTextMessage(String content, Thread currentThread) {
|
|
|
|
|
publish(content, BytedeskConstants.MESSAGE_TYPE_TEXT, currentThread, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void sendImageMessage(String content, Thread currentThread) {
|
|
|
|
|
publish(content, BytedeskConstants.MESSAGE_TYPE_IMAGE, currentThread, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void sendFileMessage(String content, Thread currentThread) {
|
|
|
|
|
publish(content, BytedeskConstants.MESSAGE_TYPE_FILE, currentThread, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void sendVoiceMessage(String content, Thread currentThread) {
|
|
|
|
|
publish(content, BytedeskConstants.MESSAGE_TYPE_VOICE, currentThread, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void sendVideoMessage(String content, Thread currentThread) {
|
|
|
|
|
publish(content, BytedeskConstants.MESSAGE_TYPE_VIDEO, currentThread, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 商品消息
|
|
|
|
|
void sendCommodityMessage(String content, Thread currentThread) {
|
|
|
|
|
publish(
|
|
|
|
|
content, BytedeskConstants.MESSAGE_TYPE_COMMODITY, currentThread, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 消息预知
|
|
|
|
|
void sendPreviewMessage(String previewContent, Thread currentThread) {
|
|
|
|
|
publish(previewContent, BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_PREVIEW,
|
|
|
|
|
currentThread, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 消息撤回
|
|
|
|
|
void sendRecallMessage(String mid, Thread currentThread) {
|
|
|
|
|
ExtraParam extraParam = new ExtraParam();
|
|
|
|
|
extraParam.recallMid = mid;
|
|
|
|
|
publish(mid, BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_RECALL,
|
|
|
|
|
currentThread, extraParam);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 送达回执
|
|
|
|
|
void sendReceiptReceivedMessage(String mid, Thread currentThread) {
|
|
|
|
|
sendReceiptMessage(
|
|
|
|
|
mid, BytedeskConstants.MESSAGE_STATUS_RECEIVED, currentThread);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 已读回执
|
|
|
|
|
void sendReceiptReadMessage(String mid, Thread currentThread) {
|
|
|
|
|
sendReceiptMessage(
|
|
|
|
|
mid, BytedeskConstants.MESSAGE_STATUS_READ, currentThread);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void sendReceiptMessage(String mid, String status, Thread currentThread) {
|
|
|
|
|
ExtraParam extraParam = new ExtraParam();
|
|
|
|
|
extraParam.receiptMid = mid;
|
|
|
|
|
extraParam.receiptStatus = status;
|
|
|
|
|
publish('content', BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_RECEIPT,
|
|
|
|
|
currentThread, extraParam);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void publish(String content, String type, Thread currentThread,
|
|
|
|
|
ExtraParam? extraParam) {
|
|
|
|
|
// if (currentThread == null) {
|
|
|
|
|
// BytedeskUtils.printLog('连接客服失败,请退出页面重新进入。注意: 请在App启动的时候,调用init接口');
|
|
|
|
|
// Fluttertoast.showToast(msg: '连接客服失败,请退出页面重新进入');
|
|
|
|
|
// return;
|
|
|
|
|
// }
|
|
|
|
|
// https://pub.dev/packages/encrypt#aes
|
|
|
|
|
// final encrypter = Encrypter(AES(key, mode: AESMode.cbc));
|
|
|
|
|
// final encrypted = encrypter.encrypt(content, iv: iv);
|
|
|
|
|
// BytedeskUtils.printLog(encrypted.base64);
|
|
|
|
|
// final decrypted = encrypter.decrypt(encrypted, iv: iv);
|
|
|
|
|
// BytedeskUtils.printLog(decrypted);
|
|
|
|
|
// thread
|
|
|
|
|
protothread.Thread thread = new protothread.Thread();
|
|
|
|
|
thread.tid = currentThread.tid!;
|
|
|
|
|
thread.type = currentThread.type!;
|
|
|
|
|
thread.topic = currentThread.topic!;
|
|
|
|
|
thread.nickname = currentThread.nickname!;
|
|
|
|
|
thread.avatar = currentThread.avatar!;
|
|
|
|
|
thread.client = currentThread.client!;
|
|
|
|
|
thread.timestamp = BytedeskUtils.formatedDateNow(); // 没有必要填写,服务器端会填充
|
|
|
|
|
thread.unreadCount = 0;
|
|
|
|
|
var extra = {'top': false, 'undisturb': false};
|
|
|
|
|
thread.extra = jsonEncode(extra);
|
|
|
|
|
// user
|
|
|
|
|
protouser.User user = new protouser.User();
|
|
|
|
|
user.uid = SpUtil.getString(BytedeskConstants.uid)!;
|
|
|
|
|
user.username = SpUtil.getString(BytedeskConstants.username)!;
|
|
|
|
|
user.nickname = SpUtil.getString(BytedeskConstants.nickname)!;
|
|
|
|
|
user.avatar = SpUtil.getString(BytedeskConstants.avatar)!;
|
|
|
|
|
// msg
|
|
|
|
|
protomsg.Message messageProto = new protomsg.Message();
|
|
|
|
|
messageProto.mid = BytedeskUuid.uuid();
|
|
|
|
|
messageProto.type = type;
|
|
|
|
|
messageProto.timestamp = BytedeskUtils.formatedDateNow();
|
|
|
|
|
messageProto.client = BytedeskUtils.getClient(); //BytedeskConstants.client;
|
|
|
|
|
messageProto.version = '1';
|
|
|
|
|
messageProto.encrypted = false;
|
|
|
|
|
// 用来在发送之前显示到界面
|
|
|
|
|
Message message = new Message();
|
|
|
|
|
message.mid = messageProto.mid;
|
|
|
|
|
message.type = messageProto.type;
|
|
|
|
|
message.timestamp = messageProto.timestamp;
|
|
|
|
|
message.client = messageProto.client;
|
|
|
|
|
message.nickname = user.nickname;
|
|
|
|
|
message.avatar = user.avatar;
|
|
|
|
|
message.topic = thread.topic;
|
|
|
|
|
message.status = BytedeskConstants.MESSAGE_STATUS_SENDING;
|
|
|
|
|
message.isSend = 1;
|
|
|
|
|
message.currentUid = currentUid;
|
|
|
|
|
message.answersJson = '';
|
|
|
|
|
message.thread = currentThread;
|
|
|
|
|
message.user =
|
|
|
|
|
User(uid: user.uid, avatar: user.avatar, nickname: user.nickname);
|
|
|
|
|
// 判断是否应该插入本地并显示
|
|
|
|
|
bool shouldInsertLocal = false;
|
|
|
|
|
// 发送protobuf
|
|
|
|
|
if (type == BytedeskConstants.MESSAGE_TYPE_TEXT) {
|
|
|
|
|
protomsg.Text text = new protomsg.Text();
|
|
|
|
|
text.content = content;
|
|
|
|
|
messageProto.text = text;
|
|
|
|
|
//
|
|
|
|
|
thread.content = content;
|
|
|
|
|
//
|
|
|
|
|
shouldInsertLocal = true;
|
|
|
|
|
message.content = content;
|
|
|
|
|
} else if (type == BytedeskConstants.MESSAGE_TYPE_IMAGE) {
|
|
|
|
|
protomsg.Image image = new protomsg.Image();
|
|
|
|
|
image.imageUrl = content;
|
|
|
|
|
messageProto.image = image;
|
|
|
|
|
//
|
|
|
|
|
thread.content = '[图片]';
|
|
|
|
|
//
|
|
|
|
|
shouldInsertLocal = true;
|
|
|
|
|
message.imageUrl = content;
|
|
|
|
|
} else if (type == BytedeskConstants.MESSAGE_TYPE_VOICE) {
|
|
|
|
|
protomsg.Voice voice = new protomsg.Voice();
|
|
|
|
|
voice.voiceUrl = content;
|
|
|
|
|
// voice.length
|
|
|
|
|
// voice.format
|
|
|
|
|
messageProto.voice = voice;
|
|
|
|
|
//
|
|
|
|
|
thread.content = '[语音]';
|
|
|
|
|
//
|
|
|
|
|
shouldInsertLocal = true;
|
|
|
|
|
message.voiceUrl = content;
|
|
|
|
|
} else if (type == BytedeskConstants.MESSAGE_TYPE_FILE) {
|
|
|
|
|
protomsg.File file = new protomsg.File();
|
|
|
|
|
file.fileUrl = content;
|
|
|
|
|
messageProto.file = file;
|
|
|
|
|
//
|
|
|
|
|
thread.content = '[文件]';
|
|
|
|
|
//
|
|
|
|
|
shouldInsertLocal = true;
|
|
|
|
|
message.fileUrl = content;
|
|
|
|
|
} else if (type == BytedeskConstants.MESSAGE_TYPE_VIDEO ||
|
|
|
|
|
type == BytedeskConstants.MESSAGE_TYPE_SHORT_VIDEO) {
|
|
|
|
|
protomsg.Video video = new protomsg.Video();
|
|
|
|
|
video.videoOrShortUrl = content;
|
|
|
|
|
messageProto.video = video;
|
|
|
|
|
//
|
|
|
|
|
thread.content = '[视频]';
|
|
|
|
|
//
|
|
|
|
|
shouldInsertLocal = true;
|
|
|
|
|
message.videoUrl = content;
|
|
|
|
|
} else if (type == BytedeskConstants.MESSAGE_TYPE_COMMODITY) {
|
|
|
|
|
protomsg.Text text = new protomsg.Text();
|
|
|
|
|
text.content = content;
|
|
|
|
|
messageProto.text = text;
|
|
|
|
|
//
|
|
|
|
|
thread.content = '[商品]';
|
|
|
|
|
//
|
|
|
|
|
shouldInsertLocal = true;
|
|
|
|
|
message.content = content;
|
|
|
|
|
} else if (type == BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_PREVIEW) {
|
|
|
|
|
protomsg.Preview preview = new protomsg.Preview();
|
|
|
|
|
preview.content = content;
|
|
|
|
|
messageProto.preview = preview;
|
|
|
|
|
} else if (type == BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_RECEIPT) {
|
|
|
|
|
// 发送消息回执
|
|
|
|
|
protomsg.Receipt receipt = new protomsg.Receipt();
|
|
|
|
|
receipt.mid = extraParam!.receiptMid!;
|
|
|
|
|
receipt.status = extraParam.receiptStatus!;
|
|
|
|
|
//
|
|
|
|
|
messageProto.receipt = receipt;
|
|
|
|
|
} else if (type == BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_RECALL) {
|
|
|
|
|
//
|
|
|
|
|
protomsg.Recall recall = new protomsg.Recall();
|
|
|
|
|
recall.mid = extraParam!.recallMid!;
|
|
|
|
|
//
|
|
|
|
|
messageProto.recall = recall;
|
|
|
|
|
} else if (type == BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_TRANSFER) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_TRANSFER_ACCEPT) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_TRANSFER_REJECT) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type == BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_INVITE) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_INVITE_ACCEPT) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_INVITE_REJECT) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_INVITE_RATE) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_RATE_RESULT) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_WEBRTC_INVITE_VIDEO) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_WEBRTC_INVITE_AUDIO) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_WEBRTC_CANCEL) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_WEBRTC_OFFER_VIDEO) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_WEBRTC_OFFER_AUDIO) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_WEBRTC_ANSWER) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_WEBRTC_CANDIDATE) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_WEBRTC_ACCEPT) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_WEBRTC_REJECT) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_WEBRTC_READY) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_WEBRTC_BUSY) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_WEBRTC_CLOSE) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_CREATE) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_UPDATE) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_ANNOUNCEMENT) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_INVITE) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_INVITE_ACCEPT) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_INVITE_REJECT) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_APPLY) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_APPLY_APPROVE) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_APPLY_DENY) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type == BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_KICK) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type == BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_MUTE) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_TRANSFER) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_TRANSFER_ACCEPT) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_TRANSFER_REJECT) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_WITHDRAW) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type ==
|
|
|
|
|
BytedeskConstants.MESSAGE_TYPE_NOTIFICATION_GROUP_DISMISS) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type == BytedeskConstants.MESSAGE_TYPE_LOCATION) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type == BytedeskConstants.MESSAGE_TYPE_LINK) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type == BytedeskConstants.MESSAGE_TYPE_EVENT) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type == BytedeskConstants.MESSAGE_TYPE_CUSTOM) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else if (type == BytedeskConstants.MESSAGE_TYPE_RED_PACKET) {
|
|
|
|
|
//
|
|
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
// 其他类型消息
|
|
|
|
|
BytedeskUtils.printLog('other type:' + type);
|
|
|
|
|
}
|
|
|
|
|
//
|
|
|
|
|
messageProto.user = user;
|
|
|
|
|
messageProto.thread = thread;
|
|
|
|
|
// 先通知界面本地显示聊天记录,然后再发送
|
|
|
|
|
if (shouldInsertLocal) {
|
|
|
|
|
// 插入本地数据库
|
|
|
|
|
// if (messageProvider != null) {
|
|
|
|
|
messageProvider.insert(message);
|
|
|
|
|
// }
|
|
|
|
|
bytedeskEventBus.fire(ReceiveMessageEventBus(message));
|
|
|
|
|
midList.add(message.mid!);
|
|
|
|
|
}
|
|
|
|
|
//
|
|
|
|
|
final MqttClientPayloadBuilder builder = MqttClientPayloadBuilder();
|
|
|
|
|
// 注意:此函数为自行添加,原先库中没有
|
|
|
|
|
builder.addProtobuf(messageProto.writeToBuffer());
|
|
|
|
|
mqttClient.publishMessage(
|
|
|
|
|
currentThread.topic, MqttQos.exactlyOnce, builder.payload);
|
|
|
|
|
// 播放发送消息提示音,放到SDK外实现,迁移到demo中
|
|
|
|
|
if (BytedeskKefu.getPlayAudioOnSendMessage()!) {
|
|
|
|
|
//
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 断开长连接
|
|
|
|
|
void disconnect() {
|
|
|
|
|
if (mqttClient != null) {
|
|
|
|
|
mqttClient.disconnect();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The subscribed callback
|
|
|
|
|
void _onSubscribed(String? topic) {
|
|
|
|
|
// BytedeskUtils.printLog('Subscription confirmed for topic $topic');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The unsubscribed callback
|
|
|
|
|
void _onUnSubscribed(String? topic) {
|
|
|
|
|
// BytedeskUtils.printLog('UnSubscription confirmed for topic $topic');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The subscribed callback
|
|
|
|
|
void _onSubscribeFailed(String? topic) {
|
|
|
|
|
// BytedeskUtils.printLog('Subscribe Failed confirmed for topic $topic');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The unsolicited disconnect callback
|
|
|
|
|
void _onDisconnected() {
|
|
|
|
|
// _isConnected = false;
|
|
|
|
|
// BytedeskUtils.printLog('OnDisconnected client callback - Client disconnection');
|
|
|
|
|
// eventbus发广播,通知长连接断开
|
|
|
|
|
bytedeskEventBus
|
|
|
|
|
.fire(ConnectionEventBus(BytedeskConstants.USER_STATUS_DISCONNECTED));
|
|
|
|
|
// if (mqttClient.connectionStatus.returnCode == MqttConnectReturnCode.solicited) {
|
|
|
|
|
// BytedeskUtils.printLog('OnDisconnected callback is solicited, this is correct');
|
|
|
|
|
// }
|
|
|
|
|
// 延时10s执行重连
|
|
|
|
|
Future.delayed(Duration(seconds: 10), () {
|
|
|
|
|
// BytedeskUtils.printLog('start reconnecting');
|
|
|
|
|
// reconnect();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The unsolicited disconnect callback
|
|
|
|
|
// void _onAutoReconnect() {
|
|
|
|
|
// // BytedeskUtils.printLog('EXAMPLE::onAutoReconnect client callback - Client auto reconnection sequence will start');
|
|
|
|
|
// // connect();
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
/// The successful connect callback
|
|
|
|
|
void _onConnected() {
|
|
|
|
|
// _isConnected = true;
|
|
|
|
|
// BytedeskUtils.printLog('OnConnected client callback - Client connection was sucessful');
|
|
|
|
|
// TODO: eventbus发广播,通知长连接建立
|
|
|
|
|
bytedeskEventBus
|
|
|
|
|
.fire(ConnectionEventBus(BytedeskConstants.USER_STATUS_CONNECTED));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Pong callback
|
|
|
|
|
void _onPong() {
|
|
|
|
|
// BytedeskUtils.printLog('Ping response client callback invoked');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isConnected() {
|
|
|
|
|
// return _isConnected;
|
|
|
|
|
return mqttClient.connectionStatus.state == MqttConnectionState.connected;
|
|
|
|
|
}
|
|
|
|
|
}
|