WuKongIMFlutterSDK/lib/db/message.dart

1028 lines
39 KiB
Dart

import 'dart:convert';
import 'package:sqflite/sqflite.dart';
import 'package:wukongimfluttersdk/db/channel.dart';
import 'package:wukongimfluttersdk/db/const.dart';
import 'package:wukongimfluttersdk/db/reaction.dart';
import 'package:wukongimfluttersdk/entity/msg.dart';
import 'package:wukongimfluttersdk/type/const.dart';
import 'package:wukongimfluttersdk/wkim.dart';
import '../entity/channel.dart';
import '../entity/channel_member.dart';
import 'channel_member.dart';
import 'wk_db_helper.dart';
class MessageDB {
MessageDB._privateConstructor();
static final MessageDB _instance = MessageDB._privateConstructor();
static MessageDB get shared => _instance;
final String extraCols =
"IFNULL(${WKDBConst.tableMessageExtra}.readed,0) as readed,IFNULL(${WKDBConst.tableMessageExtra}.readed_count,0) as readed_count,IFNULL(${WKDBConst.tableMessageExtra}.unread_count,0) as unread_count,IFNULL(${WKDBConst.tableMessageExtra}.revoke,0) as revoke,IFNULL(${WKDBConst.tableMessageExtra}.revoker,'') as revoker,IFNULL(${WKDBConst.tableMessageExtra}.extra_version,0) as extra_version,IFNULL(${WKDBConst.tableMessageExtra}.is_mutual_deleted,0) as is_mutual_deleted,IFNULL(${WKDBConst.tableMessageExtra}.need_upload,0) as need_upload,IFNULL(${WKDBConst.tableMessageExtra}.content_edit,'') as content_edit,IFNULL(${WKDBConst.tableMessageExtra}.edited_at,0) as edited_at,IFNULL(${WKDBConst.tableMessageExtra}.is_pinned,0) as is_pinned";
final String messageCols =
"${WKDBConst.tableMessage}.client_seq,${WKDBConst.tableMessage}.message_id,${WKDBConst.tableMessage}.message_seq,${WKDBConst.tableMessage}.channel_id,${WKDBConst.tableMessage}.channel_type,${WKDBConst.tableMessage}.timestamp,${WKDBConst.tableMessage}.topic_id,${WKDBConst.tableMessage}.from_uid,${WKDBConst.tableMessage}.type,${WKDBConst.tableMessage}.content,${WKDBConst.tableMessage}.status,${WKDBConst.tableMessage}.voice_status,${WKDBConst.tableMessage}.created_at,${WKDBConst.tableMessage}.updated_at,${WKDBConst.tableMessage}.searchable_word,${WKDBConst.tableMessage}.client_msg_no,${WKDBConst.tableMessage}.setting,${WKDBConst.tableMessage}.order_seq,${WKDBConst.tableMessage}.extra,${WKDBConst.tableMessage}.is_deleted,${WKDBConst.tableMessage}.flame,${WKDBConst.tableMessage}.flame_second,${WKDBConst.tableMessage}.viewed,${WKDBConst.tableMessage}.viewed_at,${WKDBConst.tableMessage}.expire_time,${WKDBConst.tableMessage}.expire_timestamp";
Future<bool> isExist(String clientMsgNo) async {
bool isExist = false;
if (WKDBHelper.shared.getDB() == null) {
return isExist;
}
List<Map<String, Object?>> list = await WKDBHelper.shared.getDB()!.query(
WKDBConst.tableMessage,
where: "client_msg_no=?",
whereArgs: [clientMsgNo]);
if (list.isNotEmpty) {
isExist = true;
}
return isExist;
}
Future<int> insert(WKMsg msg) async {
if (msg.clientSeq != 0) {
updateMsg(msg);
return msg.clientSeq;
}
if (msg.clientMsgNO != '') {
bool exist = await isExist(msg.clientMsgNO);
if (exist) {
msg.isDeleted = 1;
msg.clientMsgNO = WKIM.shared.messageManager.generateClientMsgNo();
}
}
return await WKDBHelper.shared.getDB()!.insert(
WKDBConst.tableMessage, getMap(msg),
conflictAlgorithm: ConflictAlgorithm.replace);
}
Future<int> updateMsg(WKMsg msg) async {
if (WKDBHelper.shared.getDB() == null) {
return 0;
}
return await WKDBHelper.shared.getDB()!.update(
WKDBConst.tableMessage, getMap(msg),
where: "client_seq=?", whereArgs: [msg.clientSeq]);
}
Future<int> updateMsgWithField(dynamic map, int clientSeq) async {
if (WKDBHelper.shared.getDB() == null) {
return 0;
}
return await WKDBHelper.shared.getDB()!.update(WKDBConst.tableMessage, map,
where: "client_seq=?", whereArgs: [clientSeq]);
}
Future<int> updateMsgWithFieldAndClientMsgNo(
dynamic map, String clientMsgNO) async {
if (WKDBHelper.shared.getDB() == null) {
return 0;
}
return await WKDBHelper.shared.getDB()!.update(WKDBConst.tableMessage, map,
where: "client_msg_no=?", whereArgs: [clientMsgNO]);
}
Future<WKMsg?> queryWithClientMsgNo(String clientMsgNo) async {
WKMsg? wkMsg;
String sql =
"select $messageCols,$extraCols from ${WKDBConst.tableMessage} LEFT JOIN ${WKDBConst.tableMessageExtra} ON ${WKDBConst.tableMessage}.message_id=${WKDBConst.tableMessageExtra}.message_id WHERE ${WKDBConst.tableMessage}.client_msg_no=?";
if (WKDBHelper.shared.getDB() == null) {
return wkMsg;
}
List<Map<String, Object?>> list =
await WKDBHelper.shared.getDB()!.rawQuery(sql, [clientMsgNo]);
if (list.isNotEmpty) {
wkMsg = WKDBConst.serializeWKMsg(list[0]);
}
if (wkMsg != null) {
wkMsg.reactionList =
await ReactionDB.shared.queryWithMessageId(wkMsg.messageID);
}
return wkMsg;
}
Future<WKMsg?> queryWithClientSeq(int clientSeq) async {
WKMsg? wkMsg;
String sql =
"select $messageCols,$extraCols from ${WKDBConst.tableMessage} LEFT JOIN ${WKDBConst.tableMessageExtra} ON ${WKDBConst.tableMessage}.message_id=${WKDBConst.tableMessageExtra}.message_id WHERE ${WKDBConst.tableMessage}.client_seq=?";
if (WKDBHelper.shared.getDB() == null) {
return wkMsg;
}
List<Map<String, Object?>> list =
await WKDBHelper.shared.getDB()!.rawQuery(sql, [clientSeq]);
if (list.isNotEmpty) {
wkMsg = WKDBConst.serializeWKMsg(list[0]);
}
if (wkMsg != null) {
wkMsg.reactionList =
await ReactionDB.shared.queryWithMessageId(wkMsg.messageID);
}
return wkMsg;
}
Future<List<WKMsg>> queryWithMessageIds(List<String> messageIds) async {
String sql =
"select $messageCols,$extraCols from ${WKDBConst.tableMessage} LEFT JOIN ${WKDBConst.tableMessageExtra} ON ${WKDBConst.tableMessage}.message_id=${WKDBConst.tableMessageExtra}.message_id WHERE ${WKDBConst.tableMessage}.message_id in (${WKDBConst.getPlaceholders(messageIds.length)})";
List<WKMsg> list = [];
if (WKDBHelper.shared.getDB() == null) {
return list;
}
List<Map<String, Object?>> results =
await WKDBHelper.shared.getDB()!.rawQuery(sql, messageIds);
if (results.isNotEmpty) {
for (Map<String, Object?> data in results) {
list.add(WKDBConst.serializeWKMsg(data));
}
}
return list;
}
Future<int> queryMaxOrderSeq(String channelID, int channelType) async {
int maxOrderSeq = 0;
if (WKDBHelper.shared.getDB() == null) {
return maxOrderSeq;
}
String sql =
"select max(order_seq) order_seq from ${WKDBConst.tableMessage} where channel_id =? and channel_type=? and type<>99 and type<>0 and is_deleted=0";
List<Map<String, Object?>> list = await WKDBHelper.shared
.getDB()!
.rawQuery(sql, [channelID, channelType]);
if (list.isNotEmpty) {
dynamic data = list[0];
maxOrderSeq = WKDBConst.readInt(data, 'order_seq');
}
return maxOrderSeq;
}
Future<int> getMaxMessageSeq(String channelID, int channelType) async {
String sql =
"SELECT max(message_seq) message_seq FROM ${WKDBConst.tableMessage} WHERE channel_id=? AND channel_type=?";
int messageSeq = 0;
if (WKDBHelper.shared.getDB() == null) {
return messageSeq;
}
List<Map<String, Object?>> list = await WKDBHelper.shared
.getDB()!
.rawQuery(sql, [channelID, channelType]);
if (list.isNotEmpty) {
dynamic data = list[0];
messageSeq = WKDBConst.readInt(data, 'message_seq');
}
return messageSeq;
}
Future<int> getOrderSeq(
String channelID, int channelType, int maxOrderSeq, int limit) async {
int minOrderSeq = 0;
if (WKDBHelper.shared.getDB() == null) {
return minOrderSeq;
}
String sql =
"select order_seq from ${WKDBConst.tableMessage} where channel_id=? and channel_type=? and type<>99 and order_seq <=? order by order_seq desc limit ?";
List<Map<String, Object?>> list = await WKDBHelper.shared
.getDB()!
.rawQuery(sql, [channelID, channelType, maxOrderSeq, limit]);
if (list.isNotEmpty) {
dynamic data = list[0];
minOrderSeq = WKDBConst.readInt(data, 'order_seq');
}
return minOrderSeq;
}
Future<List<WKMsg>> getMessages(String channelId, int channelType,
int oldestOrderSeq, bool contain, int pullMode, int limit) async {
List<WKMsg> msgList = [];
String sql;
var args = [];
if (oldestOrderSeq <= 0) {
sql =
"SELECT * FROM (SELECT $messageCols,$extraCols FROM ${WKDBConst.tableMessage} LEFT JOIN ${WKDBConst.tableMessageExtra} on ${WKDBConst.tableMessage}.message_id=${WKDBConst.tableMessageExtra}.message_id WHERE ${WKDBConst.tableMessage}.channel_id=? and ${WKDBConst.tableMessage}.channel_type=? and ${WKDBConst.tableMessage}.type<>0 and ${WKDBConst.tableMessage}.type<>99) where is_deleted=0 and is_mutual_deleted=0 order by order_seq desc limit 0,?";
args.add(channelId);
args.add(channelType);
args.add(limit);
} else {
if (pullMode == 0) {
if (contain) {
sql =
"SELECT * FROM (SELECT $messageCols,$extraCols FROM ${WKDBConst.tableMessage} LEFT JOIN ${WKDBConst.tableMessageExtra} on ${WKDBConst.tableMessage}.message_id=${WKDBConst.tableMessageExtra}.message_id WHERE ${WKDBConst.tableMessage}.channel_id=? and ${WKDBConst.tableMessage}.channel_type=? and ${WKDBConst.tableMessage}.type<>0 and ${WKDBConst.tableMessage}.type<>99 AND ${WKDBConst.tableMessage}.order_seq<=?) where is_deleted=0 and is_mutual_deleted=0 order by order_seq desc limit 0,?";
} else {
sql =
"SELECT * FROM (SELECT $messageCols,$extraCols FROM ${WKDBConst.tableMessage} LEFT JOIN ${WKDBConst.tableMessageExtra} on ${WKDBConst.tableMessage}.message_id=${WKDBConst.tableMessageExtra}.message_id WHERE ${WKDBConst.tableMessage}.channel_id=? and ${WKDBConst.tableMessage}.channel_type=? and ${WKDBConst.tableMessage}.type<>0 and ${WKDBConst.tableMessage}.type<>99 AND ${WKDBConst.tableMessage}.order_seq<?) where is_deleted=0 and is_mutual_deleted=0 order by order_seq desc limit 0,?";
}
} else {
if (contain) {
sql =
"SELECT * FROM (SELECT $messageCols,$extraCols FROM ${WKDBConst.tableMessage} LEFT JOIN ${WKDBConst.tableMessageExtra} on ${WKDBConst.tableMessage}.message_id=${WKDBConst.tableMessageExtra}.message_id WHERE ${WKDBConst.tableMessage}.channel_id=? and ${WKDBConst.tableMessage}.channel_type=? and ${WKDBConst.tableMessage}.type<>0 and ${WKDBConst.tableMessage}.type<>99 AND ${WKDBConst.tableMessage}.order_seq>=?) where is_deleted=0 and is_mutual_deleted=0 order by order_seq asc limit 0,?";
} else {
sql =
"SELECT * FROM (SELECT $messageCols,$extraCols FROM ${WKDBConst.tableMessage} LEFT JOIN ${WKDBConst.tableMessageExtra} on ${WKDBConst.tableMessage}.message_id=${WKDBConst.tableMessageExtra}.message_id WHERE ${WKDBConst.tableMessage}.channel_id=? and ${WKDBConst.tableMessage}.channel_type=? and ${WKDBConst.tableMessage}.type<>0 and ${WKDBConst.tableMessage}.type<>99 AND ${WKDBConst.tableMessage}.order_seq>?) where is_deleted=0 and is_mutual_deleted=0 order by order_seq asc limit 0,?";
}
}
args.add(channelId);
args.add(channelType);
args.add(oldestOrderSeq);
args.add(limit);
}
List<String> messageIds = [];
List<String> replyMsgIds = [];
List<String> fromUIDs = [];
List<Map<String, Object?>> results =
await WKDBHelper.shared.getDB()!.rawQuery(sql, args);
if (results.isNotEmpty) {
WKChannel? wkChannel =
await ChannelDB.shared.query(channelId, channelType);
for (Map<String, Object?> data in results) {
WKMsg wkMsg = WKDBConst.serializeWKMsg(data);
wkMsg.setChannelInfo(wkChannel);
if (wkMsg.messageID != '') {
messageIds.add(wkMsg.messageID);
}
if (wkMsg.messageContent != null &&
wkMsg.messageContent!.reply != null &&
wkMsg.messageContent!.reply!.messageId != '') {
replyMsgIds.add(wkMsg.messageContent!.reply!.messageId);
}
if (wkMsg.fromUID != '') {
bool isAdd = true;
for (int i = 0; i < fromUIDs.length; i++) {
if (fromUIDs[i] == wkMsg.fromUID) {
isAdd = false;
break;
}
}
if (isAdd) {
fromUIDs.add(wkMsg.fromUID);
}
}
if (pullMode == 0) {
msgList.insert(0, wkMsg);
} else {
msgList.add(wkMsg);
}
}
}
//扩展消息
List<WKMsgReaction> list =
await ReactionDB.shared.queryWithMessageIds(messageIds);
if (list.isNotEmpty) {
for (int i = 0, size = msgList.length; i < size; i++) {
for (int j = 0, len = list.length; j < len; j++) {
if (list[j].messageID == msgList[i].messageID) {
if (msgList[i].reactionList == null) {
msgList[i].reactionList = [];
}
msgList[i].reactionList!.add(list[j]);
}
}
}
}
// 发送者成员信息
if (channelType == WKChannelType.group) {
List<WKChannelMember> memberList = await ChannelMemberDB.shared
.queryMemberWithUIDs(channelId, channelType, fromUIDs);
if (memberList.isNotEmpty) {
for (WKChannelMember member in memberList) {
for (int i = 0, size = msgList.length; i < size; i++) {
if (msgList[i].fromUID != '' &&
msgList[i].fromUID == member.memberUID) {
msgList[i].setMemberOfFrom(member);
}
}
}
}
}
//消息发送者信息
List<WKChannel> wkChannels = await ChannelDB.shared
.queryWithChannelIdsAndChannelType(fromUIDs, WKChannelType.personal);
if (wkChannels.isNotEmpty) {
for (WKChannel wkChannel in wkChannels) {
for (int i = 0, size = msgList.length; i < size; i++) {
if (msgList[i].fromUID != '' &&
msgList[i].fromUID == wkChannel.channelID) {
msgList[i].setFrom(wkChannel);
}
}
}
}
// 查询编辑内容
if (replyMsgIds.isNotEmpty) {
List<WKMsgExtra> msgExtraList =
await queryMsgExtrasWithMsgIds(replyMsgIds);
if (msgExtraList.isNotEmpty) {
for (WKMsgExtra extra in msgExtraList) {
for (int i = 0, size = msgList.length; i < size; i++) {
if (msgList[i].messageContent != null &&
msgList[i].messageContent!.reply != null &&
extra.messageID ==
msgList[i].messageContent!.reply!.messageId) {
msgList[i].messageContent!.reply!.revoke = extra.revoke;
}
if (extra.contentEdit != '' &&
msgList[i].messageContent != null &&
msgList[i].messageContent!.reply != null &&
msgList[i].messageContent!.reply!.messageId != '' &&
extra.messageID ==
msgList[i].messageContent!.reply!.messageId) {
msgList[i].messageContent!.reply!.editAt = extra.editedAt;
msgList[i].messageContent!.reply!.contentEdit = extra.contentEdit;
var json = jsonEncode(extra.contentEdit);
var type = WKDBConst.readInt(json, 'type');
msgList[i].messageContent!.reply!.contentEditMsgModel =
WKIM.shared.messageManager.getMessageModel(type, json);
break;
}
}
}
}
}
return msgList;
}
var requestCount = 0;
void getOrSyncHistoryMessages(
String channelId,
int channelType,
int oldestOrderSeq,
bool contain,
int pullMode,
int limit,
final Function(List<WKMsg>) iGetOrSyncHistoryMsgBack,
final Function() syncBack) async {
//获取原始数据
List<WKMsg> list = await getMessages(
channelId, channelType, oldestOrderSeq, contain, pullMode, limit);
//业务判断数据
List<WKMsg> tempList = [];
for (int i = 0, size = list.length; i < size; i++) {
tempList.add(list[i]);
}
//先通过message_seq排序
if (tempList.isNotEmpty) {
tempList.sort((a, b) => a.messageSeq.compareTo(b.messageSeq));
}
//获取最大和最小messageSeq
int minMessageSeq = 0;
int maxMessageSeq = 0;
for (int i = 0, size = tempList.length; i < size; i++) {
if (tempList[i].messageSeq != 0) {
if (minMessageSeq == 0) minMessageSeq = tempList[i].messageSeq;
if (tempList[i].messageSeq > maxMessageSeq) {
maxMessageSeq = tempList[i].messageSeq;
}
if (tempList[i].messageSeq < minMessageSeq) {
minMessageSeq = tempList[i].messageSeq;
}
}
}
//是否同步消息
bool isSyncMsg = false;
int startMsgSeq = 0;
int endMsgSeq = 0;
//判断页与页之间是否连续
int oldestMsgSeq;
//如果获取到的messageSeq为0说明oldestOrderSeq这条消息是本地消息则获取他上一条或下一条消息的messageSeq做为判断
if (oldestOrderSeq % 1000 != 0) {
oldestMsgSeq =
await getMsgSeq(channelId, channelType, oldestOrderSeq, pullMode);
} else {
oldestMsgSeq = oldestOrderSeq ~/ 1000;
}
if (pullMode == 0) {
//下拉获取消息
if (oldestMsgSeq == 1) {
iGetOrSyncHistoryMsgBack([]);
return;
}
if (maxMessageSeq != 0 &&
oldestMsgSeq != 0 &&
oldestMsgSeq - maxMessageSeq > 1) {
isSyncMsg = true;
if (contain) {
startMsgSeq = oldestMsgSeq;
} else {
startMsgSeq = oldestMsgSeq - 1;
}
endMsgSeq = maxMessageSeq;
}
} else {
//上拉获取消息
if (minMessageSeq != 0 &&
oldestMsgSeq != 0 &&
minMessageSeq - oldestMsgSeq > 1) {
isSyncMsg = true;
if (contain) {
startMsgSeq = oldestMsgSeq;
} else {
startMsgSeq = oldestMsgSeq + 1;
}
endMsgSeq = minMessageSeq;
}
}
if (!isSyncMsg) {
//判断当前页是否连续
for (int i = 0, size = tempList.length; i < size; i++) {
int nextIndex = i + 1;
if (nextIndex < tempList.length) {
if (tempList[nextIndex].messageSeq != 0 &&
tempList[i].messageSeq != 0 &&
tempList[nextIndex].messageSeq - tempList[i].messageSeq > 1) {
//判断该条消息是否被删除
int num = await getDeletedCount(tempList[i].messageSeq,
tempList[nextIndex].messageSeq, channelId, channelType);
if (num <
(tempList[nextIndex].messageSeq - tempList[i].messageSeq) - 1) {
isSyncMsg = true;
int max = tempList[nextIndex].messageSeq;
int min = tempList[i].messageSeq;
if (tempList[nextIndex].messageSeq < tempList[i].messageSeq) {
max = tempList[i].messageSeq;
min = tempList[nextIndex].messageSeq;
}
if (pullMode == 0) {
// 下拉
if (max > startMsgSeq) {
startMsgSeq = max;
}
if (endMsgSeq == 0 || min < endMsgSeq) {
endMsgSeq = min;
}
} else {
if (startMsgSeq == 0 || min < startMsgSeq) {
startMsgSeq = min;
}
if (max > endMsgSeq) {
endMsgSeq = max;
}
}
}
}
}
}
}
if (!isSyncMsg) {
if (minMessageSeq == 1) {
requestCount = 0;
iGetOrSyncHistoryMsgBack(list);
return;
}
}
//计算最后一页后是否还存在消息
int syncLimit = limit;
if (!isSyncMsg && tempList.length < limit) {
isSyncMsg = true;
if (contain) {
startMsgSeq = oldestMsgSeq;
} else {
if (pullMode == 0) {
startMsgSeq = oldestMsgSeq - 1;
} else {
startMsgSeq = oldestMsgSeq + 1;
}
}
endMsgSeq = 0;
}
if (startMsgSeq == 0 && endMsgSeq == 0 && tempList.length < limit) {
isSyncMsg = true;
endMsgSeq = oldestMsgSeq;
startMsgSeq = 0;
}
if (isSyncMsg &&
(startMsgSeq != endMsgSeq || (startMsgSeq == 0 && endMsgSeq == 0)) &&
requestCount < 5) {
if (requestCount == 0) {
syncBack();
}
//同步消息
requestCount++;
WKIM.shared.messageManager.setSyncChannelMsgListener(
channelId, channelType, startMsgSeq, endMsgSeq, syncLimit, pullMode,
(syncChannelMsg) {
if (syncChannelMsg != null) {
if (oldestMsgSeq == 0 ||
(syncChannelMsg.messages != null &&
syncChannelMsg.messages!.length < limit)) {
requestCount = 5;
}
getOrSyncHistoryMessages(channelId, channelType, oldestOrderSeq,
contain, pullMode, limit, iGetOrSyncHistoryMsgBack, syncBack);
} else {
requestCount = 0;
iGetOrSyncHistoryMsgBack(list);
}
});
} else {
requestCount = 0;
iGetOrSyncHistoryMsgBack(list);
}
}
Future<int> getDeletedCount(int minMessageSeq, int maxMessageSeq,
String channelID, int channelType) async {
String sql =
"select count(*) num from ${WKDBConst.tableMessage} where channel_id=? and channel_type=? and message_seq>? and message_seq<? and is_deleted=1";
int num = 0;
if (WKDBHelper.shared.getDB() == null) {
return num;
}
List<Map<String, Object?>> list = await WKDBHelper.shared
.getDB()!
.rawQuery(sql, [channelID, channelType, minMessageSeq, maxMessageSeq]);
if (list.isNotEmpty) {
dynamic data = list[0];
num = WKDBConst.readInt(data, 'num');
}
return num;
}
Future<int> getMsgSeq(String channelID, int channelType, int oldestOrderSeq,
int pullMode) async {
String sql;
int messageSeq = 0;
if (pullMode == 1) {
sql =
"select message_seq from ${WKDBConst.tableMessage} where channel_id=? and channel_type=? and order_seq>? and message_seq<>0 order by message_seq desc limit 1";
} else {
sql =
"select message_seq from ${WKDBConst.tableMessage} where channel_id=? and channel_type=? and order_seq<? and message_seq<>0 order by message_seq asc limit 1";
}
if (WKDBHelper.shared.getDB() == null) {
return messageSeq;
}
List<Map<String, Object?>> list = await WKDBHelper.shared
.getDB()!
.rawQuery(sql, [channelID, channelType, oldestOrderSeq]);
if (list.isNotEmpty) {
dynamic data = list[0];
messageSeq = WKDBConst.readInt(data, 'message_seq');
}
return messageSeq;
}
Future<bool> insertMsgList(List<WKMsg> list) async {
if (list.isEmpty) return true;
if (list.length == 1) {
insert(list[0]);
return true;
}
List<WKMsg> saveList = [];
for (int i = 0, size = list.length; i < size; i++) {
bool isExist = false;
for (int j = 0, len = saveList.length; j < len; j++) {
if (list[i].clientMsgNO == saveList[j].clientMsgNO) {
isExist = true;
break;
}
}
if (isExist) {
list[i].clientMsgNO = WKIM.shared.messageManager.generateClientMsgNo();
list[i].isDeleted = 1;
}
saveList.add(list[i]);
}
List<String> clientMsgNos = [];
List<WKMsg> existMsgList = [];
for (int i = 0, size = saveList.length; i < size; i++) {
if (clientMsgNos.length == 200) {
List<WKMsg> tempList = await queryWithClientMsgNos(clientMsgNos);
if (tempList.isNotEmpty) {
existMsgList.addAll(tempList);
}
clientMsgNos.clear();
}
if (saveList[i].clientMsgNO != '') {}
clientMsgNos.add(saveList[i].clientMsgNO);
}
if (clientMsgNos.isNotEmpty) {
List<WKMsg> tempList = await queryWithClientMsgNos(clientMsgNos);
if (tempList.isNotEmpty) {
existMsgList.addAll(tempList);
}
clientMsgNos.clear();
}
for (WKMsg msg in saveList) {
for (WKMsg tempMsg in existMsgList) {
if (tempMsg.clientMsgNO != '' &&
msg.clientMsgNO != '' &&
tempMsg.clientMsgNO == msg.clientMsgNO) {
msg.isDeleted = 1;
msg.clientMsgNO = WKIM.shared.messageManager.generateClientMsgNo();
break;
}
}
}
// insertMsgList(saveList);
List<Map<String, Object>> cvList = [];
for (WKMsg wkMsg in saveList) {
cvList.add(getMap(wkMsg));
}
if (cvList.isNotEmpty) {
WKDBHelper.shared.getDB()!.transaction((txn) async {
for (int i = 0; i < cvList.length; i++) {
txn.insert(WKDBConst.tableMessage, cvList[i],
conflictAlgorithm: ConflictAlgorithm.replace);
}
});
}
return true;
}
Future<List<WKMsg>> queryWithClientMsgNos(List<String> clientMsgNos) async {
List<WKMsg> msgs = [];
if (WKDBHelper.shared.getDB() == null) {
return msgs;
}
List<Map<String, Object?>> results = await WKDBHelper.shared.getDB()!.query(
WKDBConst.tableMessage,
where:
"client_msg_no in (${WKDBConst.getPlaceholders(clientMsgNos.length)})",
whereArgs: clientMsgNos);
if (results.isNotEmpty) {
for (Map<String, Object?> data in results) {
msgs.add(WKDBConst.serializeWKMsg(data));
}
}
return msgs;
}
Future<bool> insertMsgExtras(List<WKMsgExtra> list) async {
if (list.isEmpty) {
return true;
}
List<Map<String, Object>> insertCVList = [];
for (int i = 0, size = list.length; i < size; i++) {
insertCVList.add(getExtraMap(list[i]));
}
WKDBHelper.shared.getDB()!.transaction((txn) async {
if (insertCVList.isNotEmpty) {
for (int i = 0; i < insertCVList.length; i++) {
txn.insert(WKDBConst.tableMessageExtra, insertCVList[i],
conflictAlgorithm: ConflictAlgorithm.replace);
}
}
});
return true;
}
Future<bool> insertOrUpdateMsgExtras(List<WKMsgExtra> list) async {
List<String> msgIds = [];
for (int i = 0, size = list.length; i < size; i++) {
if (list[i].messageID != '') {
msgIds.add(list[i].messageID);
}
}
List<WKMsgExtra> existList = await queryMsgExtrasWithMsgIds(msgIds);
List<Map<String, Object>> insertCVList = [];
List<Map<String, Object>> updateCVList = [];
for (int i = 0, size = list.length; i < size; i++) {
bool isAdd = true;
for (WKMsgExtra extra in existList) {
if (list[i].messageID == extra.messageID) {
updateCVList.add(getExtraMap(list[i]));
isAdd = false;
break;
}
}
if (isAdd) {
insertCVList.add(getExtraMap(list[i]));
}
}
if (insertCVList.isNotEmpty || updateCVList.isNotEmpty) {
WKDBHelper.shared.getDB()!.transaction((txn) async {
if (insertCVList.isNotEmpty) {
for (int i = 0; i < insertCVList.length; i++) {
txn.insert(WKDBConst.tableMessageExtra, insertCVList[i],
conflictAlgorithm: ConflictAlgorithm.replace);
}
}
if (updateCVList.isNotEmpty) {
for (int i = 0; i < updateCVList.length; i++) {
txn.update(WKDBConst.tableMessageExtra, updateCVList[0],
where: "message_id=?",
whereArgs: [updateCVList[i]['message_id']]);
}
}
});
}
return true;
}
Future<int> queryMaxExtraVersionWithChannel(
String channelID, int channelType) async {
int extraVersion = 0;
String sql =
"select max(extra_version) extra_version from ${WKDBConst.tableMessageExtra} where channel_id =? and channel_type=?";
List<Map<String, Object?>> list = await WKDBHelper.shared
.getDB()!
.rawQuery(sql, [channelID, channelType]);
if (list.isNotEmpty) {
dynamic data = list[0];
extraVersion = WKDBConst.readInt(data, 'extra_version');
}
return extraVersion;
}
Future<List<WKMsgExtra>> queryMsgExtraWithNeedUpload(int needUpload) async {
String sql =
"select * from ${WKDBConst.tableMessageExtra} where need_upload=?";
List<WKMsgExtra> list = [];
List<Map<String, Object?>> results =
await WKDBHelper.shared.getDB()!.rawQuery(sql, [needUpload]);
if (results.isNotEmpty) {
for (Map<String, Object?> data in results) {
list.add(WKDBConst.serializeMsgExtra(data));
}
}
return list;
}
Future<WKMsgExtra?> queryMsgExtraWithMsgID(String messageID) async {
WKMsgExtra? msgExtra;
if (WKDBHelper.shared.getDB() == null) {
return msgExtra;
}
List<Map<String, Object?>> list = await WKDBHelper.shared.getDB()!.query(
WKDBConst.tableMessageExtra,
where: "message_id=?",
whereArgs: [messageID]);
if (list.isNotEmpty) {
msgExtra = WKDBConst.serializeMsgExtra(list[0]);
}
return msgExtra;
}
Future<List<WKMsgExtra>> queryMsgExtrasWithMsgIds(List<String> msgIds) async {
List<WKMsgExtra> list = [];
if (WKDBHelper.shared.getDB() == null) {
return list;
}
List<Map<String, Object?>> results = await WKDBHelper.shared.getDB()!.query(
WKDBConst.tableMessageExtra,
where: "message_id in (${WKDBConst.getPlaceholders(msgIds.length)})",
whereArgs: msgIds);
if (results.isNotEmpty) {
for (Map<String, Object?> data in results) {
list.add(WKDBConst.serializeMsgExtra(data));
}
}
return list;
}
updateSendingMsgFail() {
if (WKDBHelper.shared.getDB() == null) {
return;
}
var map = <String, Object>{};
map['status'] = WKSendMsgResult.sendFail;
WKDBHelper.shared
.getDB()!
.update(WKDBConst.tableMessage, map, where: 'status=0');
}
Future<WKMsg?> queryMaxOrderSeqMsgWithChannel(
String channelID, int channelType) async {
WKMsg? wkMsg;
String sql =
"select * from ${WKDBConst.tableMessage} where channel_id=? and channel_type=? and is_deleted=0 and type<>0 and type<>99 order by order_seq desc limit 1";
List<Map<String, Object?>> list = await WKDBHelper.shared
.getDB()!
.rawQuery(sql, [channelID, channelType]);
if (list.isNotEmpty) {
dynamic data = list[0];
if (data != null) {
wkMsg = WKDBConst.serializeWKMsg(data);
}
}
if (wkMsg != null) {
wkMsg.reactionList =
await ReactionDB.shared.queryWithMessageId(wkMsg.messageID);
}
return wkMsg;
}
Future<int> deleteWithMessageIDs(List<String> msgIds) async {
if (WKDBHelper.shared.getDB() == null) {
return 0;
}
var map = <String, Object>{};
map['is_deleted'] = 1;
return await WKDBHelper.shared.getDB()!.update(WKDBConst.tableMessage, map,
where: "message_id in (${WKDBConst.getPlaceholders(msgIds.length)})",
whereArgs: msgIds);
}
Future<int> deleteWithChannel(String channelId, int channelType) async {
if (WKDBHelper.shared.getDB() == null) {
return 0;
}
var map = <String, Object>{};
map['is_deleted'] = 1;
return await WKDBHelper.shared.getDB()!.update(WKDBConst.tableMessage, map,
where: "channel_id=? and channel_type=?",
whereArgs: [channelId, channelType]);
}
Future<List<WKMessageSearchResult>> search(String keyword) async {
List<WKMessageSearchResult> list = [];
var sql =
"select distinct c.*, count(*) message_count, case count(*) WHEN 1 then m.client_seq else ''END client_seq, CASE count(*) WHEN 1 THEN m.searchable_word else '' end searchable_word from ${WKDBConst.tableChannel} c LEFT JOIN ${WKDBConst.tableMessage} m ON m.channel_id = c.channel_id and m.channel_type = c.channel_type WHERE m.is_deleted=0 and searchable_word LIKE ? GROUP BY c.channel_id, c.channel_type ORDER BY m.created_at DESC limit 100";
List<Map<String, Object?>> results =
await WKDBHelper.shared.getDB()!.rawQuery(sql, ['%$keyword%']);
for (Map<String, Object?> data in results) {
var channel = WKDBConst.serializeChannel(data);
var message = WKMessageSearchResult();
message.channel = channel;
message.messageCount = WKDBConst.readInt(data, 'message_count');
message.searchableWord = WKDBConst.readString(data, 'searchable_word');
list.add(message);
}
return list;
}
Future<List<WKMsg>> searchWithChannel(
String keyword, String channelId, int channelType) async {
List<WKMsg> list = [];
var sql =
"select * from (select $messageCols,$extraCols from ${WKDBConst.tableMessage} left join ${WKDBConst.tableMessageExtra} on ${WKDBConst.tableMessage}.message_id= ${WKDBConst.tableMessageExtra}.message_id where ${WKDBConst.tableMessage}.searchable_word like ? and ${WKDBConst.tableMessage}.channel_id=? and ${WKDBConst.tableMessage}.channel_type=?) where is_deleted=0 and revoke=0";
List<Map<String, Object?>> results = await WKDBHelper.shared
.getDB()!
.rawQuery(sql, ['%$keyword%', channelId, channelType]);
List<String> fromUIDs = [];
WKChannel? channel =
await WKIM.shared.channelManager.getChannel(channelId, channelType);
for (Map<String, Object?> data in results) {
var msg = WKDBConst.serializeWKMsg(data);
if (channel != null) {
msg.setChannelInfo(channel);
}
if (msg.fromUID != '') {
fromUIDs.add(msg.fromUID);
}
list.add(msg);
}
if (fromUIDs.isNotEmpty) {
List<String> uniqueList = fromUIDs.toSet().toList();
List<WKChannel> wkChannels = await ChannelDB.shared
.queryWithChannelIdsAndChannelType(
uniqueList, WKChannelType.personal);
if (wkChannels.isNotEmpty) {
for (WKChannel channel in wkChannels) {
for (WKMsg msg in list) {
if (msg.fromUID == channel.channelID) {
msg.setFrom(channel);
break;
}
}
}
}
if (channelType == WKChannelType.group) {
List<WKChannelMember> members = await ChannelMemberDB.shared
.queryMemberWithUIDs(channelId, channelType, uniqueList);
if (members.isNotEmpty) {
for (WKChannelMember member in members) {
for (WKMsg msg in list) {
if (msg.fromUID == member.memberUID) {
msg.setMemberOfFrom(member);
break;
}
}
}
}
}
}
return list;
}
Future<List<WKMsg>> searchMsgWithChannelAndContentTypes(
String channelID,
int channelType,
int oldestOrderSeq,
int limit,
List<int> contentTypes) async {
var sql = "";
List<WKMsg> list = [];
List<Object?> arguments = [];
if (oldestOrderSeq <= 0) {
arguments = [channelID, channelType, contentTypes];
sql =
"select * from (select $messageCols,$extraCols from ${WKDBConst.tableMessage} left join ${WKDBConst.tableMessageExtra} on ${WKDBConst.tableMessage}.message_id=${WKDBConst.tableMessageExtra}.message_id where ${WKDBConst.tableMessage}.channel_id=? and ${WKDBConst.tableMessage}.channel_type=? and ${WKDBConst.tableMessage}.type<>0 and ${WKDBConst.tableMessage}.type<>99 and ${WKDBConst.tableMessage}.type in (${WKDBConst.getPlaceholders(contentTypes.length)})) where is_deleted=0 and revoke=0 order by order_seq desc limit 0,$limit";
} else {
arguments = [channelID, channelType, oldestOrderSeq, contentTypes];
sql =
"select * from (select $messageCols,$extraCols from ${WKDBConst.tableMessage} left join ${WKDBConst.tableMessageExtra} on ${WKDBConst.tableMessage}.message_id=${WKDBConst.tableMessageExtra}.message_id where ${WKDBConst.tableMessage}.channel_id=? and ${WKDBConst.tableMessage}.channel_type=? and ${WKDBConst.tableMessage}.order_seq<? and ${WKDBConst.tableMessage}.type<>0 and ${WKDBConst.tableMessage}.type<>99 and ${WKDBConst.tableMessage}.type in (${WKDBConst.getPlaceholders(contentTypes.length)})) where is_deleted=0 and revoke=0 order by order_seq desc limit 0,$limit";
}
List<Map<String, Object?>> results =
await WKDBHelper.shared.getDB()!.rawQuery(sql, arguments);
List<String> fromUIDs = [];
WKChannel? channel =
await WKIM.shared.channelManager.getChannel(channelID, channelType);
for (Map<String, Object?> data in results) {
var msg = WKDBConst.serializeWKMsg(data);
if (channel != null) {
msg.setChannelInfo(channel);
}
if (msg.fromUID != '') {
fromUIDs.add(msg.fromUID);
}
list.add(msg);
}
if (fromUIDs.isNotEmpty) {
List<String> uniqueList = fromUIDs.toSet().toList();
List<WKChannel> wkChannels = await ChannelDB.shared
.queryWithChannelIdsAndChannelType(
uniqueList, WKChannelType.personal);
if (wkChannels.isNotEmpty) {
for (WKChannel channel in wkChannels) {
for (WKMsg msg in list) {
if (msg.fromUID == channel.channelID) {
msg.setFrom(channel);
break;
}
}
}
}
if (channelType == WKChannelType.group) {
List<WKChannelMember> members = await ChannelMemberDB.shared
.queryMemberWithUIDs(channelID, channelType, uniqueList);
if (members.isNotEmpty) {
for (WKChannelMember member in members) {
for (WKMsg msg in list) {
if (msg.fromUID == member.memberUID) {
msg.setMemberOfFrom(member);
break;
}
}
}
}
}
}
return list;
}
dynamic getMap(WKMsg msg) {
var map = <String, Object>{};
map['message_id'] = msg.messageID;
map['message_seq'] = msg.messageSeq;
map['order_seq'] = msg.orderSeq;
map['timestamp'] = msg.timestamp;
map['from_uid'] = msg.fromUID;
map['channel_id'] = msg.channelID;
map['channel_type'] = msg.channelType;
map['is_deleted'] = msg.isDeleted;
map['type'] = msg.contentType;
map['content'] = msg.content;
map['status'] = msg.status;
map['voice_status'] = msg.voiceStatus;
map['client_msg_no'] = msg.clientMsgNO;
map['viewed'] = msg.viewed;
map['viewed_at'] = msg.viewedAt;
map['topic_id'] = msg.topicID;
map['expire_time'] = msg.expireTime;
map['expire_timestamp'] = msg.expireTimestamp;
if (msg.messageContent != null) {
map['searchable_word'] = msg.messageContent!.searchableWord();
} else {
map['searchable_word'] = '';
}
// 这里有错误数据,需要清理
var len = msg.localExtraMap?.toString().length ?? 0;
if (len < 1000000) {
map['extra'] = msg.localExtraMap?.toString() ?? "";
} else {
map['extra'] = '';
}
map['setting'] = msg.setting.encode();
return map;
}
dynamic getExtraMap(WKMsgExtra extra) {
var map = <String, Object>{};
map['channel_id'] = extra.channelID;
map['channel_type'] = extra.channelType;
map['readed'] = extra.readed;
map['readed_count'] = extra.readedCount;
map['unread_count'] = extra.unreadCount;
map['revoke'] = extra.revoke;
map['revoker'] = extra.revoker;
map['extra_version'] = extra.extraVersion;
map['is_mutual_deleted'] = extra.isMutualDeleted;
map['content_edit'] = extra.contentEdit;
map['edited_at'] = extra.editedAt;
map['need_upload'] = extra.needUpload;
map['message_id'] = extra.messageID;
map['is_pinned'] = extra.isPinned;
return map;
}
}