msg.js 38.8 KB
Newer Older
DCloud_JSON's avatar
DCloud_JSON 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13
const {
  db,
  dbCmd,
  $,
  getConversationId,
  checkParam
} = require('uni-im-utils')

const dbUniImMsg = db.collection('uni-im-msg')
const dbUniImConversation = db.collection('uni-im-conversation')
const dbUniImGroupMember = db.collection('uni-im-group-member')
const dbUniImFriend = db.collection('uni-im-friend')

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
14
// 获取 uni-im 配置
DCloud_JSON's avatar
DCloud_JSON 已提交
15 16
const createConfig = require("uni-config-center");
const uniImConfig = createConfig({
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
17
  pluginId: 'uni-im', // 插件 id
DCloud_JSON's avatar
DCloud_JSON 已提交
18
})
19
const conversation_grade = uniImConfig.config('conversation_grade')
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
20
const { invokeExts } = require('uni-im-ext')
DCloud_JSON's avatar
DCloud_JSON 已提交
21 22
// 发送消息方法(含:单聊和群聊)
async function sendMsg(params) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
23 24 25 26 27 28 29 30 31
  
  // 执行扩展点 beforeSendMsg
  let [beforeSendMsgRes] = await invokeExts('before-send-msg', params, this)
  // console.error('beforeSendMsgRes:', beforeSendMsgRes)
  if (beforeSendMsgRes === false) {
    throw new Error('扩展点 beforeSendMsgRes 出错')
  }


DCloud_JSON's avatar
DCloud_JSON 已提交
32 33 34
  await _beforeSendMsgActions.call(this, params)

  let {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
35
    // 指定接收消息的用户 id
DCloud_JSON's avatar
DCloud_JSON 已提交
36
    to_uid,
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
37
    // 指定接收消息的群 id
DCloud_JSON's avatar
DCloud_JSON 已提交
38 39 40 41 42 43 44
    group_id,
    // 消息内容
    body,
    // 消息类型
    type,
    // 是否为失败 重试
    isRetries,
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
45
    // 接收消息的客户端的 DCloud appid
DCloud_JSON's avatar
DCloud_JSON 已提交
46
    appId,
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
47
    // 回复关联的消息的 id
DCloud_JSON's avatar
DCloud_JSON 已提交
48 49 50 51 52 53
    about_msg_id,
    call_uid,
    action,
    // 是否为静默消息
    is_mute
  } = params
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
54 55

  // 清除旧版三方系统客户端直传的 call_uid 参数
DCloud_JSON's avatar
DCloud_JSON 已提交
56 57 58 59 60 61 62 63 64 65 66 67 68 69
  call_uid = []

  // 校验参数是否合法
  checkParam(params, {
    required: ["body", "type", "appId"],
    type: {
      to_uid: ["String"],
      group_id: ["String"],
      body: ["String", "Object", "Array"],
      type: ["String"],
      isRetries: ["Boolean"],
      appId: ["String"],
      about_msg_id: ['String'],
      action: ['String'],
70 71
      is_mute: ['Boolean'],
      chat_source: ['Object']
DCloud_JSON's avatar
DCloud_JSON 已提交
72 73 74
    }
  })

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
75
  // 存在 action 时,如果不是其他云函数或者触发器调用时,且调用者也不是系统时,拦截非法操作。
DCloud_JSON's avatar
DCloud_JSON 已提交
76 77 78 79 80 81 82
  if (action && this.getClientInfo().source != 'function' && this.current_uid != 'system') {
    throw new Error('非法操作')
  }

  // 调用扩展点 valid-msg
  let result = await invokeExts('validate-msg', params, this)
  let isValid = result.find(valid => typeof valid !== 'undefined')
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
83 84

  if (!isValid && is_mute !== undefined && this.current_uid !== 'system') {
DCloud_JSON's avatar
DCloud_JSON 已提交
85 86 87 88 89
    throw new Error('非法操作')
  }

  // 补充特殊校验
  if (!to_uid && !group_id) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
90
    throw new Error('接收消息的用户 id 和群 id 最少指定一个') // alert:否则表示将消息群发
DCloud_JSON's avatar
DCloud_JSON 已提交
91 92
  }

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
93
  // 其他云函数或者触发器调用时,消息类型才能用 system
DCloud_JSON's avatar
DCloud_JSON 已提交
94 95 96 97 98
  if (this.getClientInfo().source != 'function' && type == 'system') {
    throw new Error('非法消息类型')
  }

  if (type == 'text' && typeof body != 'string') {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
99
    throw new Error('错误:type 为 text 类型,但 body 的类型确不是 string')
DCloud_JSON's avatar
DCloud_JSON 已提交
100 101
  }

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
102
  // 发送者身份 id
DCloud_JSON's avatar
DCloud_JSON 已提交
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
  const from_uid = this.current_uid

  await _checkConversationGrade.call(this, {
    from_uid,
    to_uid,
    group_id,
  })

  // TODO: 群聊时,需要校验当前用户是否为群成员,后续会优化性能问题
  if (this.current_uid != 'system' && group_id) {
    let {
      data: [member]
    } = await dbUniImGroupMember
      .where({
        group_id,
        user_id: this.current_uid
      })
      .get()
    // console.log('member', member);
    if (!member) {
      throw new Error('非群成员不能发起会话')
    } else if (!['creator', 'admin'].includes(...member.role) && member.mute_type > 0) {
      throw new Error('你已被禁言')
    }
  }

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
129 130 131 132 133 134 135
  let nickname = "系统消息",avatar_file = "";
  if (from_uid && from_uid != 'system') {
    const { data: [userInfo] } = await db.collection('uni-id-users').doc(from_uid).get()
    if (userInfo) {
      nickname = userInfo.nickname
      avatar_file = userInfo.avatar_file
    } else {
DCloud_JSON's avatar
DCloud_JSON 已提交
136 137 138 139 140
      return {
        "code": 30202,
        "errCode": "uni-id-check-token-failed",
        "errMsg": "请重新登录"
      }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
141 142 143 144 145
    }
  }

  // 生成会话 id
  const conversation_id = getConversationId({group_id,from_uid,to_uid})
DCloud_JSON's avatar
DCloud_JSON 已提交
146 147 148 149 150 151 152
  // 现在的时间戳
  const nowTimestamp = Date.now()
  // 构建基本消息内容
  const msgData = {
    body,
    type,
    from_uid,
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
153 154 155 156
    // 消息发送者昵称
    nickname,
    // 消息发送者头像文件
    avatar_file,
DCloud_JSON's avatar
DCloud_JSON 已提交
157
    to_uid,
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
158
    // 是否已读,默认为:false
DCloud_JSON's avatar
DCloud_JSON 已提交
159
    is_read: false,
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
160
    // 创建时间
DCloud_JSON's avatar
DCloud_JSON 已提交
161 162 163 164 165
    create_time: nowTimestamp,
    // 更新时间,默认为创建时间
    update_time: nowTimestamp,
    conversation_id,
    group_id,
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
166
    appid: appId, // 接收消息的 appid(撤回消息时会用到)
DCloud_JSON's avatar
DCloud_JSON 已提交
167 168 169 170 171 172
    about_msg_id,
    call_uid, // @某些人
    action,
    reader_list: [], // 已读消息的用户列表
    is_mute // 是否为静默消息
  }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
173

DCloud_JSON's avatar
DCloud_JSON 已提交
174 175 176 177 178

  if (type === 'rich-text') {
    let callUid = []
    for (let node of msgData.body) {
      if (node.name == 'span' && node.attrs && node.attrs.class == 'nickname' && node.attrs.user_id) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
179
        // 保护用户昵称,移除。客户端将通过 node.attrs.user_id,获取用户昵称
DCloud_JSON's avatar
DCloud_JSON 已提交
180 181 182 183 184 185 186
        delete node.children
        callUid.push(node.attrs.user_id)
      }
    }
    if (callUid.length) {
      msgData.call_uid = callUid
    }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
187 188 189
  } else if (type === 'order') {
    // 发送订单消息时,需要 call 此订单的用户
    msgData.call_uid = msgData.body.user_id || []
DCloud_JSON's avatar
DCloud_JSON 已提交
190 191 192
  }

  // 创建新会话或者更新已有会话。
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
193
  // 拿到消息接收者的 isMute 状态(仅私聊有效)
194
  let {isMute,groupInfo} = await _createOrUpdateConversation.call(this, conversation_id, msgData, params.chat_source)
DCloud_JSON's avatar
DCloud_JSON 已提交
195 196 197 198 199 200 201 202 203 204 205 206 207
  // console.log({
  // 	...msgData,
  // 	conversation_id
  // });

  // 如果是扩展的消息类型,由扩展模块决定是否要保存入库
  let noPersistent = false
  const { msgTypes } = require('uni-im-ext')
  let msgType = await msgTypes.get(type)
  if (msgType && msgType.noPersistent) {
    noPersistent = msgType.noPersistent(msgData)
  }

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
208 209 210 211 212 213 214 215 216 217
  // todo:临时增加私有代码逻辑,后续会迁移到扩展模块中
  if (type === 'system' && action === 'set-group-member-ext-plugin-order-info') {
    // 群成员设置插件排序信息,不需要保存至数据库
    noPersistent = true
  }

  // 如果是无需保存至数据库的消息,因缺失 _id ,将影响客户端对该消息接收状态的判断,所以这里需要创建临时 _id
  if (noPersistent) {
    msgData._id = 'temp_' + Math.random().toString(36).substr(2) + Date.now()
  }
DCloud_JSON's avatar
DCloud_JSON 已提交
218
  // 将消息内容存到数据库,“点击重发按钮的”和“不需要保存的扩展消息”除外
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
219
  else if (!isRetries || !msgData._id) {
DCloud_JSON's avatar
DCloud_JSON 已提交
220 221 222 223 224 225 226 227 228 229
    const __text = _extractTextFromMsg(msgData)
    if (__text) {
      msgData.__text = __text
      // console.log(' msgData.__text', msgData.__text);
    }

    let res = await dbUniImMsg.add({
      ...msgData,
      conversation_id
    })
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
230

DCloud_JSON's avatar
DCloud_JSON 已提交
231 232 233 234 235 236 237
    msgData._id = res.id
    // console.error('uni-im-msg msgData:',msgData, res);

    // 调用扩展点 send-msg
    // 这里需要 clone,因为是异步调用,而下面的代码马上就要修改 msgData
    let { ...clonedMsg } = msgData
    this.addPromise(invokeExts('send-msg', clonedMsg, this))
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
238 239

    // 客户端不需要返回__text 字段
DCloud_JSON's avatar
DCloud_JSON 已提交
240 241
    delete msgData.__text
  } else {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
242
    // console.error('跳过添加 msg 到数据库!~~~~~~~~~')
DCloud_JSON's avatar
DCloud_JSON 已提交
243
  }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
244 245 246

  // 不可见/静音消息一定是 isMute
  if (!_isReadableMsg(msgData) || msgData.is_mute) {
DCloud_JSON's avatar
DCloud_JSON 已提交
247 248 249 250
    isMute = true
  }

  // 处理产生的推送
251
  let res = await _processPush.call(this, {msgData,isMute,appId,groupInfo})
DCloud_JSON's avatar
DCloud_JSON 已提交
252 253 254 255 256 257 258

  if (!res.data) {
    res.data = {}
  }

  // 返回云端消息记录创建的时间
  res.data.create_time = msgData.create_time
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
259
  // 返回云端消息记录的 id
DCloud_JSON's avatar
DCloud_JSON 已提交
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
  res.data._id = msgData._id
  return res
}


// 执行发送消息前的操作
async function _beforeSendMsgActions(params) {
  if (params.type === 'revoke_msg') {
    let res = await _revokeMsg.call(this, params.body.msg_id)
    let {
      appid,
      group_id,
      to_uid
    } = res
    params.appId = appid
    params.group_id = group_id
    params.to_uid = to_uid
    return
  }

  // 如果是扩展的消息类型,由扩展模块执行前置操作
  const { msgTypes } = require('uni-im-ext')
  let msgType = await msgTypes.get(params.type)
283
  if (msgType && msgType.beforeSendMsg) {
DCloud_JSON's avatar
DCloud_JSON 已提交
284
    await msgType.beforeSendMsg(params, this.current_uid)
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
285
    console.error('############----->beforeSendMsg', params)
DCloud_JSON's avatar
DCloud_JSON 已提交
286 287 288 289 290 291 292 293 294
    return
  }
}

async function _checkConversationGrade({
  from_uid,
  to_uid,
  group_id,
}) {
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
  if(!conversation_grade){
    return true
  }
  /** 读取配置的对话等级,校验是否有权发送消息
   * 	0	-	任何人可以发起会话
   *	100	-	客服 or 好友或者群成员
   *	200	-	必须是好友或者群成员
   *  300 -  仅限:系统管理员参与的、群成员与群管理员,发起私聊
   **/
  switch (conversation_grade) {
    case 100:
      // 客服 or 好友或者群成员
      try {
        await chatToCustomerService()
      } catch (error) {
        console.error(error)
        await chatToFriendOrGroupMember()
      }
      break;
    case 200:
      // 必须是好友或者群成员
      await chatToFriendOrGroupMember()
      break;
    case 300:
      // 放到创建会话时处理
      break;
    default:
      throw new Error('未知的对话等级,配置conversation_grade的值不正确')
      break;
  }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
325
  // 客服模式下,如果配置的客服 id。则只能向客服发起会话
326
  async function chatToCustomerService (){
327 328 329 330 331 332 333 334
    const customer_service_uids = uniImConfig.config('customer_service_uids') || []
    if (typeof customer_service_uids == 'string') {
      customer_service_uids = [customer_service_uids]
    }
    if (
      !(customer_service_uids.includes(from_uid) || customer_service_uids.includes(to_uid))
    ) {
      throw new Error('非法通讯,会话双方用户 id,均不属于 uni-im-co 中配置的 customer_service_uids')
DCloud_JSON's avatar
DCloud_JSON 已提交
335 336 337
    }
    return true
  }
338
  
DCloud_JSON's avatar
DCloud_JSON 已提交
339
  // 只能是好友关系,或者群成员才能发送
340
  async function chatToFriendOrGroupMember(){
DCloud_JSON's avatar
DCloud_JSON 已提交
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
    if (group_id) {
      let {
        data: [has]
      } = await dbUniImGroupMember
        .where({
          group_id,
          user_id: this.current_uid
        })
        .get()
      if (!has) {
        throw new Error('非群成员不能发起会话')
      }
    }
    if (to_uid) {
      let {
        data: [has]
      } = await dbUniImFriend
        .where({
          friend_uid: to_uid,
          user_id: this.current_uid
        })
        .get()
      if (!has) {
        throw new Error('非好友不能发起会话')
      }
    }
    return true
  }
}

function _getLastMsgNote({
  body,
  type,
  action,
}) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
376
  // 文本 => 文本的前 30 个字
DCloud_JSON's avatar
DCloud_JSON 已提交
377 378 379 380 381 382 383 384 385 386
  // 其他 => 消息类型
  let last_msg_note = '[多媒体]'
  if (type == 'text') {
    last_msg_note = body.toString()
    last_msg_note = last_msg_note.replace(/[\r\n]/g, "");
    last_msg_note = last_msg_note.slice(0, 30)
  } else if (type === 'userinfo-card') {
    last_msg_note = `${body.name} 的名片`
  } else if (type === 'system') {
    switch (action) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
      case 'group-join':
        last_msg_note = '加入群聊'
        break;
      case 'group-exit':
        last_msg_note = '退出群聊'
        break;
      case 'group-expel':
        last_msg_note = '被踢出群聊'
        break;
      default:
        // 更新群资料
        if (action.includes("update-group-info-")) {
          const { fieldsName } = body;
          last_msg_note = `[${fieldsName + '更新'}]`;
        }
        break;
DCloud_JSON's avatar
DCloud_JSON 已提交
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
    }
  } else {
    last_msg_note = {
      image: "[图片]",
      sound: "语音",
      video: "[视频]",
      file: "[文件]",
      location: "[位置]",
      system: "[系统消息]",
      code: "[代码]",
      'rich-text': "[图文消息]",
    } [type] || `[${type}]`
  }
  return last_msg_note
}

419
async function _createOrUpdateConversation(conversation_id, msgData, chat_source) {
DCloud_JSON's avatar
DCloud_JSON 已提交
420 421
  // 设置会话 最后一条消息 的描述
  let last_msg_note = _getLastMsgNote(msgData)
422 423 424 425 426 427 428 429 430 431 432 433 434
  // 查询群信息
  let groupInfo;
  if (msgData.group_id) {
    const res = await db.collection('uni-im-group')
      .doc(msgData.group_id)
      .field({
        type: true,
        name: true
      })
      .get()
    groupInfo = res.data[0]
  }
  
DCloud_JSON's avatar
DCloud_JSON 已提交
435 436 437 438 439 440 441

  // 查询当前用户的此会话
  const {
    data: conversationList
  } = await dbUniImConversation
    .where(
      dbCmd.and([
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
442
        { id: conversation_id },
DCloud_JSON's avatar
DCloud_JSON 已提交
443
        dbCmd.or([
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
444 445
          { user_id: msgData.from_uid },
          { group_id: dbCmd.exists(false) }
DCloud_JSON's avatar
DCloud_JSON 已提交
446 447 448 449 450 451 452 453 454 455
        ])
      ])
    )
    .get()
  // console.log('conversation', conversation);
  // 消息发送者的会话
  let senderConversation = conversationList.find(item => item.user_id == msgData.from_uid)
  // 消息接收者的会话(此数据仅私聊时存在)
  let receiverConversation = conversationList.find(item => item.user_id == msgData.to_uid)
  const isMute = (receiverConversation ? receiverConversation.mute : false)
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
456 457 458 459
  if (msgData.type === 'read_msg'){
    // todo:临时方案,拦截已读动作更新会话
   // console.error('已读动作无需更新会话') 
  }
DCloud_JSON's avatar
DCloud_JSON 已提交
460
  // 不存在,需要先创建会话记录
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
461
  else if (!senderConversation) {
462
    // 除了云函数之间(包括触发器)调用 和 特殊角色用户,需验证是否绑定了手机号码
463
    const check_mobile = uniImConfig.config('check_mobile')
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
464
    if (
465
      check_mobile &&
466 467 468
      this.getClientInfo().source != 'function' &&
      !this.current_user_role.includes('uni-im-admin') &&
      !this.current_user_role.includes('staff')
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
469
    ) {
470 471
      // 验证账号是否绑定了手机号
      let getUserInfoRes = await db.collection('uni-id-users')
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
472 473 474 475 476 477 478
        .doc(this.current_uid)
        .field({
          mobile_confirmed: 1
        })
        .get()
      if (!getUserInfoRes.data[0].mobile_confirmed) {
        throw new Error('账号未绑定手机号无法发送消息,请完成绑定后退出并重新登录本系统后重试。')
479 480
      }
    }
481 482 483 484 485
    const clientInfo = this.getClientInfo()
    if( conversation_grade === 300 && msgData.to_uid && clientInfo.source != 'function' && this.current_uid != 'system'){
      // 仅限:系统管理员参与的 或 群成员向群管理员 发起私聊
      let check = false
      // 消息发送者是系统管理员
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
486
      if (this.current_user_role.includes('staff')) {
487 488
        check = true
        // console.error('createOrUpdateConversation staff~~~~~');
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
489
      } else if (chat_source && chat_source.group_id) {
490 491 492 493 494
        // console.error('createOrUpdateConversation group_id~~~~~');
        // 临时会话来源群,判断双方是否有一个是群管理员
        let {
          data: [member],
        } = await dbUniImGroupMember
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
495 496 497 498 499 500 501
          .where({
            group_id: chat_source.group_id,
            user_id: dbCmd.in([msgData.from_uid, msgData.to_uid]),
            role: dbCmd.in(['admin'])
          })
          .get()
        if (member) {
502 503 504
          check = true
          // console.error('createOrUpdateConversation member~~~~~', member);
        }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
505
      } else {
506 507 508 509
        // 判断消息接收者是否为系统管理员(staff)
        let {
          data: [receiver],
        } = await db.collection('uni-id-users')
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
510 511 512 513 514 515 516
          .doc(msgData.to_uid)
          .field({
            role: 1,
            nickname: 1,
            avatar_file: 1,
          })
          .get()
517
        // console.error('createOrUpdateConversation receiver~~~~~', receiver);
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
518
        if (receiver && receiver.role && receiver.role.includes('staff')) {
519 520 521 522
          // console.error('createOrUpdateConversation receiver.staff~~~~~');
          check = true
        }
      }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
523 524

      if (!check) {
525 526 527 528 529 530 531 532
        let {
          data: [has]
        } = await dbUniImFriend
          .where({
            friend_uid: msgData.to_uid,
            user_id: this.current_uid
          })
          .get()
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
533
        if (has) {
534 535 536
          check = true
        }
      }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
537 538

      if (!check) {
539 540 541 542
        throw new Error('仅限:好友之间、系统管理员参与的、群成员与群管理员,发起私聊')
      }
    }

DCloud_JSON's avatar
DCloud_JSON 已提交
543 544 545 546 547 548 549 550 551 552
    // 1.消息发送者 会话数据
    senderConversation = {
      id: conversation_id,
      type: msgData.group_id ? 2 : 1,
      user_id: msgData.from_uid,
      friend_uid: msgData.to_uid,
      group_id: msgData.group_id,
      unread_count: 0,
      last_msg_note,
      update_time: msgData.create_time,
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
553 554 555 556 557
      create_time: msgData.create_time,
      last_msg_create_time: msgData.create_time,
      pinned: false,
      hidden: false,
      mute: false
DCloud_JSON's avatar
DCloud_JSON 已提交
558 559 560
    }
    if (msgData.group_id) {
      senderConversation.leave = false
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
561
      senderConversation.has_unread_group_notification = null
562
      senderConversation.group_type = groupInfo.type
DCloud_JSON's avatar
DCloud_JSON 已提交
563 564 565
      // 群聊只为当前用户创建会话
      await dbUniImConversation.add(senderConversation)
    } else {
566 567 568 569 570 571 572 573 574 575 576
      const newConversation = [senderConversation]
      // 如果不是:用户自己给自己发消息
      if (msgData.to_uid != msgData.from_uid) {
        // 2.消息接收者 会话数据
        receiverConversation = {
          ...senderConversation,
          unread_count: 1,
          user_id: msgData.to_uid,
          friend_uid: msgData.from_uid
        }
        newConversation.push(receiverConversation)
DCloud_JSON's avatar
DCloud_JSON 已提交
577
      }
578
      await dbUniImConversation.add(newConversation)
DCloud_JSON's avatar
DCloud_JSON 已提交
579 580 581 582 583 584 585 586 587 588 589 590 591
    }
  } else {
    // 会话已存在,更新相关内容
    let updateObj = {
      last_msg_note,
      update_time: msgData.create_time,
      hidden: false
    }

    // 如果不是:用户自己给自己发消息,则需要增加未读消息数
    if (msgData.from_uid != msgData.to_uid) {
      updateObj.unread_count = dbCmd.inc(1)
    }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
592

DCloud_JSON's avatar
DCloud_JSON 已提交
593
    // TODO:部分情况下不需要更新未读消息数,后续会改成都通过is_mute字段来判断
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
594
    if (
DCloud_JSON's avatar
DCloud_JSON 已提交
595
      // 加群消息
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
596
      msgData.action === "join-group"
DCloud_JSON's avatar
DCloud_JSON 已提交
597 598
      ||
      // 禁言通知
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
599
      msgData.action === 'update-group-info-mute_all_members'
DCloud_JSON's avatar
DCloud_JSON 已提交
600 601 602
      ||
      // 本身是一条静默消息
      msgData.is_mute === true
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
603
    ) {
DCloud_JSON's avatar
DCloud_JSON 已提交
604 605
      delete updateObj.unread_count
    }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
606
    
DCloud_JSON's avatar
DCloud_JSON 已提交
607 608 609 610 611 612 613 614
    if (!(await _isReadableMsg(msgData))) {
      // “非可见消息”不更新“最后一次对话消息概述”
      delete updateObj.last_msg_note
    }
    if (_isMuteMsg(msgData) || !(await _isReadableMsg(msgData))) {
      // “静音消息”不更新“未读消息数”
      delete updateObj.unread_count
    }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
615 616 617 618 619
    
    // 如果有last_msg_note,增加一个last_msg_create_time字段
    if (updateObj.last_msg_note) {
      updateObj.last_msg_create_time = msgData.create_time
    }
DCloud_JSON's avatar
DCloud_JSON 已提交
620 621 622 623 624

    // 所有接收者的会话表更新
    let res = await dbUniImConversation
      .where({
        id: conversation_id,
625 626
        user_id: dbCmd.neq(msgData.from_uid),
        leave: dbCmd.neq(true)
DCloud_JSON's avatar
DCloud_JSON 已提交
627 628 629 630
      })
      .update(updateObj)
    // console.log(res);

631
    // 更新发送者的会话( 发送者的消息未读数不需要 +1 )
DCloud_JSON's avatar
DCloud_JSON 已提交
632 633 634 635
    delete updateObj.unread_count
    res = await dbUniImConversation
      .where({
        id: conversation_id,
636
        user_id: msgData.from_uid
DCloud_JSON's avatar
DCloud_JSON 已提交
637 638 639 640
      })
      .update(updateObj)
    // console.log(res);
  }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
641

DCloud_JSON's avatar
DCloud_JSON 已提交
642 643
  // 返回消息接收者的isMute状态(仅私聊有效)
  return {
644 645
    isMute,
    groupInfo
DCloud_JSON's avatar
DCloud_JSON 已提交
646 647 648 649
  }
}

function _extractTextFromMsg(msgData) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670
    let __text = null
    if (["text", "code"].includes(msgData.type)) {
        __text = msgData.body.replace(/[\s\n]+/g, " ")
    } else if (["image", "video", "file"].includes(msgData.type)) {
        __text = msgData.body.name
    } else if (msgData.type == "rich-text") {
        let getTextOfNodeList = (nodesList) => {
            let text = ''
            nodesList.forEach(item => {
                if (item.type == "text") {
                    text += item.text
                }
                if (Array.isArray(item.children)) {
                    text += " " + getTextOfNodeList(item.children)
                    if (item.attrs && item.attrs.class === 'nickname') {
                        // 增加空格,用于区分昵称和消息内容
                        text += " "
                    }
                }
            })
            return text
DCloud_JSON's avatar
DCloud_JSON 已提交
671
        }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
672
        __text = getTextOfNodeList(msgData.body).replace(/[\s\n]+/g, " ")
DCloud_JSON's avatar
DCloud_JSON 已提交
673 674
    }

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
675 676 677 678 679 680 681
    if (__text) {
        // 全部转成小写,以便进行大小写不敏感的匹配
        __text = __text.toLowerCase()
        // 24 位 hex 会被 mongodb 自动转换成 ObjectId,需阻止
        if (__text.match(/^[0-9a-f]{24}$/)) {
            __text = __text + ' '
        }
DCloud_JSON's avatar
DCloud_JSON 已提交
682 683
    }

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
684
    return __text
DCloud_JSON's avatar
DCloud_JSON 已提交
685 686 687
}

function _checkForLongMsg(msgData) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
688 689 690
    let bodyStr = JSON.stringify(msgData.body)
    if (bodyStr > 50000) {
        throw new Error('单次消息最长字符长度不得超过 50000')
DCloud_JSON's avatar
DCloud_JSON 已提交
691
    }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707
    if (bodyStr.length > 250) {
        switch (msgData.type) {
            case 'rich-text':
                msgData.body = "富文本消息"
                break;
            case 'history':
                msgData.body = "转发的聊天记录"
                break;
            case 'text':
                // 截断,但标识消息为长文本消息,客户端收到此标识,会从数据库中拉取完整消息内容
                msgData.body = msgData.body.slice(0, 50)
                break;
            default:
                msgData.body = `[${msgData.type}]类型消息`
                break;
        }
DCloud_JSON's avatar
DCloud_JSON 已提交
708

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
709 710
        msgData.LongMsg = true
    }
DCloud_JSON's avatar
DCloud_JSON 已提交
711 712 713
}

async function _checkForReplyMsg(msgData) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
714
    if (!msgData.about_msg_id) return
DCloud_JSON's avatar
DCloud_JSON 已提交
715

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
716
    let { 
DCloud_JSON's avatar
DCloud_JSON 已提交
717
    data: [aboutMsg]
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
718 719 720
    } = await dbUniImMsg.doc(msgData.about_msg_id).get()
    if (!aboutMsg) {
        throw new Error('方法的 about_msg_id')
DCloud_JSON's avatar
DCloud_JSON 已提交
721
    }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
722 723 724 725 726
    if (!Array.isArray(msgData.call_uid)) {
        msgData.call_uid = []
    }
    msgData.call_uid.push(aboutMsg.from_uid)
    // console.log(987,aboutMsg,msgData.call_uid);
DCloud_JSON's avatar
DCloud_JSON 已提交
727 728
}

729
async function _processPush({ msgData, isMute, appId,groupInfo }) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
730 731 732 733 734 735 736
    // 处理超长文本,push 发送不了的问题
    _checkForLongMsg(msgData)

    // 处理 消息回复 @某人的
    await _checkForReplyMsg(msgData)

    const { nickname, avatar_file } = msgData
737 738 739 740 741 742 743 744 745
    let title
    let content
    if(msgData.group_id){
      title = groupInfo.name
      content = nickname.slice(0, 20) + '' + (msgData.type == 'text'? msgData.body : '[多媒体]')
    }else{
      title = msgData.type == 'system'? '系统消息' : nickname.slice(0, 20)
      content = msgData.type == 'text'? msgData.body : '[多媒体]'
    }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
746 747 748 749 750 751 752 753 754 755 756 757 758
    // 定义推送参数
    const pushParam = {
        payload: {
            type: "uni-im",
            data: msgData,
            title, // "收到 im 消息,在线时显示的标题",
            content, // "在线时显示的副标题",
            avatar_file, // 头像文件对象,
            device_id: this.clientInfo.deviceId // 发送消息的设备(客户端)id,阻止当前用户收到自己发的消息
        },
        title: title.slice(0, 20), // "收到 im 消息,离线时显示的标题",
        content: content.slice(0, 50) //"离线时显示的内容"
    }
DCloud_JSON's avatar
DCloud_JSON 已提交
759

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775
    let res

    if (msgData.from_uid!= 'system' && (msgData.to_uid || msgData.group_id)) {
        // 以"非离线"且免打扰的消息(避免系统通知栏出现消息)同步给当前用户的其他设备(比如 web 和 app、小程序同时登录时;注:发送此消息的“设备”在客户端通过业务代码过滤,这里不排除)
        this.addPromise(
            this.sendPushMsg({
               ...pushParam,
                user_id: msgData.from_uid,
                settings: {
                    strategy: {
                        default: 3
                    }
                }
            }, appId)
        )
    }
DCloud_JSON's avatar
DCloud_JSON 已提交
776

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795
    if (msgData.to_uid) {
        // WS 推送:单聊消息推送给接收方
        if (!isMute &&!_isMuteMsg(msgData) && (await _isReadableMsg(msgData))) {
          this.addPromise(
            new Promise(resolve => {
              // 给500毫秒时间,确保请求大概率能发出去,但不接收响应,防止请求异常导致的等待时间过长
                setTimeout(()=>{
                  invokeExts('push-msg-notify', {
                    to_uids: [msgData.to_uid],
                    msg: {
                      type: 'incr-conversation',
                      conversation_id: msgData.conversation_id,
                    }
                  })
                  resolve()
                }, 500)
            })
          )
        }
DCloud_JSON's avatar
DCloud_JSON 已提交
796

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
797 798 799 800 801 802 803 804 805
        // 单聊,直接调用 before 中封装好的消息推送方法
        pushParam.user_id = msgData.to_uid
        if (isMute) {
            console.log('消息接收者设置了免打扰,或本身就是一条静音消息,应用离线时,此消息不会有系统通知')
            pushParam.settings = {
                strategy: {
                    default: 3
                }
            }
DCloud_JSON's avatar
DCloud_JSON 已提交
806
        }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
807 808 809 810 811 812 813 814 815 816 817
        res = await this.sendPushMsg(pushParam, appId)
        // console.log('sendMessage', JSON.stringify(res))
        /*
        //判断是否已经有客户端接收到消息,注意:收到不等于已读
        let taskData = res.data[Object.keys(res.data)]
        let state = false;
        for (let key in taskData) {
            if (taskData[key] == 'successed_online') {
                state = true
                break
            }
DCloud_JSON's avatar
DCloud_JSON 已提交
818
        }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849
        console.log('state : ============> ' + state);*/
        res.data = {} // 不返回给客户端发送结果
    } else if (msgData.group_id) {
        this.addPromise(
            // 把当前发消息的用户的,在群成员中的活跃时间更新
            db.collection('uni-im-group-member').where({
                group_id: msgData.group_id,
                user_id: msgData.from_uid
            }).update({
                active_time: Date.now()
            })
        )

        // 如果是群聊则调用 sendMsgToGroup 云方法,此方法内部会递归发送(500 个为用户一批)
        if (this.getClientInfo().clientIP == "127.0.0.1") {
            // 如果是本地调试,直接 await 调用(因为本地调试下,云函数互调“不是调用新实例”,必须等待执行结束,注:相比生产环境的速度会更慢。)
            const start = Date.now() // 计时
            let sendMsgToGroupRes = await sendMsgToGroup()
            console.error(
                'sendMsgToGroupRes', sendMsgToGroupRes,
                'sendMsgToGroup 耗时:', Date.now() - start, 'ms',
                '因为本地调试下,云函数互调“不是调用新实例”,必须等待执行结束,注:相比生产环境的速度会更慢。'
            )
        } else {
            sendMsgToGroup()
            // 等待 500 毫秒,给一个请求发出去的时间
            this.addPromise(
                new Promise(resolve => {
                    setTimeout(resolve, 500)
                })
            )
DCloud_JSON's avatar
DCloud_JSON 已提交
850
        }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
851 852 853 854 855 856 857 858 859 860 861
        function sendMsgToGroup() {
            return uniCloud.importObject('uni-im-co').sendMsgToGroup({
                pushParam,
                appId
            })
        }
        res = {
            errCode: 0
        }
    } else {
        throw new Error('接受者标识,不能为空')
DCloud_JSON's avatar
DCloud_JSON 已提交
862
    }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
863
    return res
DCloud_JSON's avatar
DCloud_JSON 已提交
864 865 866
}

async function sendMsgToGroup({
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
867 868 869 870 871 872 873
    pushParam,
    before_id,
    push_clientids = [],
    member = [],
    appId,
    // 默认先给未设置消息免打扰的用户发消息
    mute = false
DCloud_JSON's avatar
DCloud_JSON 已提交
874
}) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
875 876 877 878 879 880 881 882
    // 注意:这是一个递归云对象,用递归的方式处理批量任务
    const limit = 1000
    if (this.getClientInfo().source!= 'function') {
        return {
            errSubject: 'uni-im-co',
            errCode: 0,
            errMsg: '该方法仅支持云对象的方法,或者触发器调用'
        }
DCloud_JSON's avatar
DCloud_JSON 已提交
883 884
    }

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
885 886
    // console.log('sendMsgToGroup=========', {
    // 	pushParam,
DCloud_JSON's avatar
DCloud_JSON 已提交
887 888 889 890
    // 	before_id,
    // 	push_clientids
    // });

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
891 892 893 894 895 896
    if (before_id || push_clientids) {
        // console.log({
        // 	before_id,
        // 	push_clientids
        // });
        // return 123
DCloud_JSON's avatar
DCloud_JSON 已提交
897
    }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
898 899 900 901 902 903

    if (push_clientids.length === 0) {
        // console.log('开始查库', push_clientids.length, push_clientids);
        let group_id = pushParam.payload.data.group_id
        if (!group_id) {
            throw new Error('群 id 不能为空')
904
        }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
905 906 907 908 909 910
        let getMemberwhere = {
            group_id,
            mute: mute? true : dbCmd.neq(true),
            leave: dbCmd.neq(true),
            // 需要排除自己
            user_id: dbCmd.neq(pushParam.payload.data.from_uid)
911
        }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
912 913 914 915 916 917 918

        if (before_id) {
            getMemberwhere._id = dbCmd.gt(before_id)
        }
        // console.log({
        // 	getMemberwhere
        // });
919
        let res = await dbUniImConversation
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991
           .aggregate()
           .match(getMemberwhere)
           .sort({
                _id: 1
            })
           .limit(limit)
           .project({
                user_id: 1,
                mute: 1
            })
           .lookup({
                from: "uni-id-device",
                let: {
                    user_id: '$user_id'
                },
                pipeline: $.pipeline()
                   .match(
                        dbCmd.expr(
                            $.and([
                                $.eq(['$user_id', '$$user_id']),
                                $.gt(['$token_expired', Date.now()])
                            ])
                        )
                    ).project({
                        push_clientid: 1
                    })
                   .done(),
                as: 'push_clientids',
            })
           .end()
        member = res.data
        console.error('符合条件的' + (mute? '【设置消息免打扰的用户】' : '') + '用户数', member.length); //,member
        push_clientids = member.reduce((sum, item) => {
            sum.push(...item.push_clientids.map(i => i.push_clientid))
            return sum
        }, [])
        console.log('查到需要接收消息的设备数:', push_clientids.length);

        // 消息接收者用户 id
        const receiverUids = member.map(user => user.user_id)
        const msgData = pushParam.payload.data

        // console.error('###########msgData.action', msgData.action);
        // 更新:退群、解散群、被踢出群 相关的用户会话
        if (receiverUids.length && ["group-exit", "group-expel", "group-dissolved"].includes(msgData.action)) {
            const updateUids = []
            if (['group-exit', 'group-expel'].includes(msgData.action)) {
                // 主动退群/被踢出群 时,仅退群用户所在“消息推送批次”时更新会话即可
                msgData.body.user_id_list.forEach(uid => {
                    if (receiverUids.includes(uid)) {
                        updateUids.push(uid)
                    }
                })
            } else {
                // 群解散时,所有“本批次”的用户会话都需要更新(注:分批 解散/退出群 的设计模式)
                updateUids.push(...receiverUids)
                // 解散群时,在第一批次时,增加更新操作者(群主)的会话
                if (!before_id) {
                    updateUids.push(msgData.from_uid)
                }
            }

            if (updateUids.length) {
                let res = await dbUniImConversation
                   .where({
                        id: msgData.conversation_id,
                        user_id: dbCmd.in(updateUids)
                    })
                   .update({ "leave": true })
                // console.error('###########更新退群或者被踢出群的用户会话', res,updateUids);
            }
        }
DCloud_JSON's avatar
DCloud_JSON 已提交
992

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
        // WS 推送:群聊消息推送给相关用户
        if (!mute &&!_isMuteMsg(msgData) && (await _isReadableMsg(msgData))) {
          this.addPromise(
            new Promise(resolve => {
              // 给500毫秒时间,确保请求大概率能发出去,但不接收响应,防止请求异常导致的等待时间过长
                setTimeout(()=>{
                  invokeExts('push-msg-notify', {
                    to_uids: receiverUids,
                    msg: {
                      type: 'incr-conversation',
                      conversation_id: msgData.conversation_id,
                    }
                  })
                  resolve()
                }, 500)
            })
          )
DCloud_JSON's avatar
DCloud_JSON 已提交
1010
        }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1011 1012
    } else {
        console.log('不需要查库,继续发送任务', push_clientids.length);
DCloud_JSON's avatar
DCloud_JSON 已提交
1013 1014
    }

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
    if (push_clientids.length === 0) {
        if (mute) {
            // console.log('已没有设置了免打扰的用户需要接收消息');
            return {
                errCode: 0,
                errMsg: '',
            }
        } else {
            // console.log('已没有未设置免打扰的用户需要接收消息,继续查询设置免打扰的用户');
        }
DCloud_JSON's avatar
DCloud_JSON 已提交
1025
    }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040

    // 下一批推送的设备 id
    let next_push_clientids = push_clientids.slice(limit)
    // 当前这一批要推送的设备 id
    push_clientids = push_clientids.slice(0, limit)
    if (push_clientids.length > 0) {
        pushParam.push_clientid = push_clientids
        // console.log("pushParam", pushParam);
        // 如果是给免打扰的用户发消息,需要设置策略,只通过个推通道下发,不考虑设备是否在线
        if (mute || pushParam.payload.data.is_mute) {
            pushParam.settings = {
                strategy: {
                    default: 3
                }
            }
DCloud_JSON's avatar
DCloud_JSON 已提交
1041
        }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1042 1043 1044
        // 执行推送
        let sendPushMsgRes = await this.sendPushMsg(pushParam, appId)
        // console.error(sendPushMsgRes)
DCloud_JSON's avatar
DCloud_JSON 已提交
1045
    }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062

    if (next_push_clientids.length!== 0) {
        // 发起下一批数据的推送
        uniCloud.importObject('uni-im-co').sendMsgToGroup({
            pushParam,
            push_clientids: next_push_clientids,
            member,
            mute
        }, appId)
        // 等待 500 毫秒,给一个请求发出去的时间
        return await new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve({
                    errCode: 0,
                    errMsg: ''
                })
            }, 500)
DCloud_JSON's avatar
DCloud_JSON 已提交
1063
        })
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080
    } else if (member.length == limit) {
        // 成员数等于分页数,则处于递归翻页进行中,且当前批次的数据已经全部推送完毕,继续查询下一批数据
        // console.log('member---*--*', member);
        before_id = member[member.length - 1]._id
        uniCloud.importObject('uni-im-co').sendMsgToGroup({
            pushParam,
            before_id,
            mute
        }, appId)
        // 等待 500 毫秒,给一个请求发出去的时间
        return await new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve({
                    errCode: 0,
                    errMsg: ''
                })
            }, 500)
DCloud_JSON's avatar
DCloud_JSON 已提交
1081
        })
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104
    } else {
        if (!mute) {
            // 如果之前不是给设置了免打扰的用户发消息,接下来需要给设置了免打扰的用户发消息
            uniCloud.importObject('uni-im-co').sendMsgToGroup({
                pushParam,
                mute: true
            }, appId)
            // 等待 500 毫秒,给一个请求发出去的时间
            return await new Promise((resolve, reject) => {
                setTimeout(() => {
                    resolve({
                        errCode: 0,
                        errMsg: ''
                    })
                }, 500)
            })
        } else {
            // console.log('没有更多用户需要接收消息');
            return {
                errCode: 0,
                errMsg: ''
            }
        }
DCloud_JSON's avatar
DCloud_JSON 已提交
1105 1106 1107 1108
    }
}

async function getMsgList({
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1109 1110 1111
    conversation_ids,
    minUpdateTime,
    limit
DCloud_JSON's avatar
DCloud_JSON 已提交
1112
}) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123
    // 校验 conversation_ids 是否为当前用户
    let {
      data: conversationList
    } = await dbUniImConversation.where({
        id: dbCmd.in(conversation_ids),
        user_id: this.current_uid,
        leave: dbCmd.neq(true)
    }).get()
    if (conversationList.length!== conversation_ids.length) {
        throw new Error('无效的会话 id')
    }
DCloud_JSON's avatar
DCloud_JSON 已提交
1124

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1125 1126 1127 1128 1129 1130 1131 1132 1133 1134
    // 查询消息列表
    let res = await dbUniImMsg.where({
        conversation_id: dbCmd.in(conversation_ids),
        update_time: dbCmd.gt(minUpdateTime)
    })
    .orderBy('update_time', 'asc')
    .limit(limit)
    .get()

    return res
DCloud_JSON's avatar
DCloud_JSON 已提交
1135 1136 1137
}

async function _revokeMsg(msgId) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1138
    //1. 先查到这条消息
DCloud_JSON's avatar
DCloud_JSON 已提交
1139
    let {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1140 1141 1142 1143
      data: [msgData]
    } = await dbUniImMsg.doc(msgId).get()
    if (!msgData) {
        throw new Error('无效的消息 id')
DCloud_JSON's avatar
DCloud_JSON 已提交
1144
    }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182
    // 如果不是 im 产品的管理员
    if (!this.current_user_role.includes('uni-im-admin') && this.getClientInfo().source!= 'function') {
        let {
          conversation_id,
          from_uid,
          appid: appId,
          group_id,
          create_time
        } = msgData

        // 判断是不是群主
        let isGroupAdmin = false
        if (group_id) {
            let res = await dbUniImGroupMember
            .where({
                group_id,
                user_id: this.current_uid
            })
            .get()
            let role = res.data[0].role || []
            isGroupAdmin = res.data[0] && role.includes('admin')
        }
        // console.error('isGroupAdmin',isGroupAdmin)

        // 如果不是群主,且消息不是发送者的就无权撤回
        if (!isGroupAdmin) {
            if (from_uid!= this.current_uid) {
                throw new Error('你不是消息的发送者或群管理员,无权操作')
            } else {
                // 消息发送者为“当前用户”时,消息创建时间需要时间小于 2 分钟
                if (Date.now() - create_time > 1000 * 60 * 2) {
                    throw {
                        errSubject: 'uni-im-co',
                        errCode: 10004,
                        errMsg: '消息已超过 2 分钟不能撤回'
                    }
                }
            }
DCloud_JSON's avatar
DCloud_JSON 已提交
1183 1184 1185
        }
    }

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1186 1187
    // 改变云数据库中此消息的撤回状态
    let res = await dbUniImMsg
DCloud_JSON's avatar
DCloud_JSON 已提交
1188 1189
    .doc(msgId)
    .update({
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1190 1191
        is_revoke: true,
        update_time: Date.now()
DCloud_JSON's avatar
DCloud_JSON 已提交
1192
    })
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1193
    return msgData
DCloud_JSON's avatar
DCloud_JSON 已提交
1194 1195 1196
}

function _isMuteMsg(msg) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1197 1198 1199 1200 1201 1202 1203 1204 1205 1206
    return (
        // 加群消息
        msg.action === "join-group"
        ||
        // 禁言通知
        msg.action === 'update-group-info-mute_all_members'
        ||
        // 消息本身是静默消息
        msg.is_mute === true
    )
DCloud_JSON's avatar
DCloud_JSON 已提交
1207 1208 1209
}

async function _isReadableMsg(msg) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221
    if (msg.type === 'revoke_msg') return false
    if (msg.action === 'update-group-info-avatar_file') return false
    if (msg.type === 'clear-conversation-unreadCount') return false

    // 如果是扩展的消息类型,由扩展模块决定消息是否可见
    const { msgTypes } = require('uni-im-ext')
    const msgTypesGetSatrt = Date.now()
    let msgType = await msgTypes.get(msg.type)
    // console.error('msgTypes.get', Date.now() - msgTypesGetSatrt)
    if (msgType && msgType.isReadable) {
        return msgType.isReadable(msg)
    }
DCloud_JSON's avatar
DCloud_JSON 已提交
1222

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1223
    return true
DCloud_JSON's avatar
DCloud_JSON 已提交
1224 1225 1226
}

module.exports = {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1227 1228 1229 1230
    sendMsg,
    sendMsgToGroup,
    getMsgList
}