msg.js 38.7 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 136 137 138 139 140 141
  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 {
      console.error('用户信息不存在',from_uid);
    }
  }

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

DCloud_JSON's avatar
DCloud_JSON 已提交
170 171 172 173 174

  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 已提交
175
        // 保护用户昵称,移除。客户端将通过 node.attrs.user_id,获取用户昵称
DCloud_JSON's avatar
DCloud_JSON 已提交
176 177 178 179 180 181 182
        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 已提交
183 184 185
  } else if (type === 'order') {
    // 发送订单消息时,需要 call 此订单的用户
    msgData.call_uid = msgData.body.user_id || []
DCloud_JSON's avatar
DCloud_JSON 已提交
186 187 188
  }

  // 创建新会话或者更新已有会话。
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
189
  // 拿到消息接收者的 isMute 状态(仅私聊有效)
190
  let {isMute,groupInfo} = await _createOrUpdateConversation.call(this, conversation_id, msgData, params.chat_source)
DCloud_JSON's avatar
DCloud_JSON 已提交
191 192 193 194 195 196 197 198 199 200 201 202 203
  // 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 已提交
204 205 206 207 208 209 210 211 212 213
  // 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 已提交
214
  // 将消息内容存到数据库,“点击重发按钮的”和“不需要保存的扩展消息”除外
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
215
  else if (!isRetries || !msgData._id) {
DCloud_JSON's avatar
DCloud_JSON 已提交
216 217 218 219 220 221 222 223 224 225
    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 已提交
226

DCloud_JSON's avatar
DCloud_JSON 已提交
227 228 229 230 231 232 233
    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 已提交
234 235

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

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

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

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

  // 返回云端消息记录创建的时间
  res.data.create_time = msgData.create_time
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
255
  // 返回云端消息记录的 id
DCloud_JSON's avatar
DCloud_JSON 已提交
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
  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)
279
  if (msgType && msgType.beforeSendMsg) {
DCloud_JSON's avatar
DCloud_JSON 已提交
280
    await msgType.beforeSendMsg(params, this.current_uid)
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
281
    console.error('############----->beforeSendMsg', params)
DCloud_JSON's avatar
DCloud_JSON 已提交
282 283 284 285 286 287 288 289 290
    return
  }
}

async function _checkConversationGrade({
  from_uid,
  to_uid,
  group_id,
}) {
291 292 293 294 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
  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 已提交
321
  // 客服模式下,如果配置的客服 id。则只能向客服发起会话
322
  async function chatToCustomerService (){
323 324 325 326 327 328 329 330
    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 已提交
331 332 333
    }
    return true
  }
334
  
DCloud_JSON's avatar
DCloud_JSON 已提交
335
  // 只能是好友关系,或者群成员才能发送
336
  async function chatToFriendOrGroupMember(){
DCloud_JSON's avatar
DCloud_JSON 已提交
337 338 339 340 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
    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 已提交
372
  // 文本 => 文本的前 30 个字
DCloud_JSON's avatar
DCloud_JSON 已提交
373 374 375 376 377 378 379 380 381 382
  // 其他 => 消息类型
  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 已提交
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
      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 已提交
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
    }
  } else {
    last_msg_note = {
      image: "[图片]",
      sound: "语音",
      video: "[视频]",
      file: "[文件]",
      location: "[位置]",
      system: "[系统消息]",
      code: "[代码]",
      'rich-text': "[图文消息]",
    } [type] || `[${type}]`
  }
  return last_msg_note
}

415
async function _createOrUpdateConversation(conversation_id, msgData, chat_source) {
DCloud_JSON's avatar
DCloud_JSON 已提交
416 417
  // 设置会话 最后一条消息 的描述
  let last_msg_note = _getLastMsgNote(msgData)
418 419 420 421 422 423 424 425 426 427 428 429 430
  // 查询群信息
  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 已提交
431 432 433 434 435 436 437

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

      if (!check) {
521 522 523 524 525 526 527 528
        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 已提交
529
        if (has) {
530 531 532
          check = true
        }
      }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
533 534

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

DCloud_JSON's avatar
DCloud_JSON 已提交
539 540 541 542 543 544 545 546 547 548
    // 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 已提交
549 550 551 552 553
      create_time: msgData.create_time,
      last_msg_create_time: msgData.create_time,
      pinned: false,
      hidden: false,
      mute: false
DCloud_JSON's avatar
DCloud_JSON 已提交
554 555 556
    }
    if (msgData.group_id) {
      senderConversation.leave = false
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
557
      senderConversation.has_unread_group_notification = null
558
      senderConversation.group_type = groupInfo.type
DCloud_JSON's avatar
DCloud_JSON 已提交
559 560 561
      // 群聊只为当前用户创建会话
      await dbUniImConversation.add(senderConversation)
    } else {
562 563 564 565 566 567 568 569 570 571 572
      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 已提交
573
      }
574
      await dbUniImConversation.add(newConversation)
DCloud_JSON's avatar
DCloud_JSON 已提交
575 576 577 578 579 580 581 582 583 584 585 586 587
    }
  } 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 已提交
588

DCloud_JSON's avatar
DCloud_JSON 已提交
589
    // TODO:部分情况下不需要更新未读消息数,后续会改成都通过is_mute字段来判断
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
590
    if (
DCloud_JSON's avatar
DCloud_JSON 已提交
591
      // 加群消息
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
592
      msgData.action === "join-group"
DCloud_JSON's avatar
DCloud_JSON 已提交
593 594
      ||
      // 禁言通知
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
595
      msgData.action === 'update-group-info-mute_all_members'
DCloud_JSON's avatar
DCloud_JSON 已提交
596 597 598
      ||
      // 本身是一条静默消息
      msgData.is_mute === true
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
599
    ) {
DCloud_JSON's avatar
DCloud_JSON 已提交
600 601
      delete updateObj.unread_count
    }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
602
    
DCloud_JSON's avatar
DCloud_JSON 已提交
603 604 605 606 607 608 609 610
    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 已提交
611 612 613 614 615
    
    // 如果有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 已提交
616 617 618 619 620

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

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

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

function _extractTextFromMsg(msgData) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
    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 已提交
667
        }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
668
        __text = getTextOfNodeList(msgData.body).replace(/[\s\n]+/g, " ")
DCloud_JSON's avatar
DCloud_JSON 已提交
669 670
    }

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

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
680
    return __text
DCloud_JSON's avatar
DCloud_JSON 已提交
681 682 683
}

function _checkForLongMsg(msgData) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
684 685 686
    let bodyStr = JSON.stringify(msgData.body)
    if (bodyStr > 50000) {
        throw new Error('单次消息最长字符长度不得超过 50000')
DCloud_JSON's avatar
DCloud_JSON 已提交
687
    }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
    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 已提交
704

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
705 706
        msgData.LongMsg = true
    }
DCloud_JSON's avatar
DCloud_JSON 已提交
707 708 709
}

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

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
712
    let { 
DCloud_JSON's avatar
DCloud_JSON 已提交
713
    data: [aboutMsg]
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
714 715 716
    } = await dbUniImMsg.doc(msgData.about_msg_id).get()
    if (!aboutMsg) {
        throw new Error('方法的 about_msg_id')
DCloud_JSON's avatar
DCloud_JSON 已提交
717
    }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
718 719 720 721 722
    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 已提交
723 724
}

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

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

    const { nickname, avatar_file } = msgData
733 734 735 736 737 738 739 740 741
    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 已提交
742 743 744 745 746 747 748 749 750 751 752 753 754
    // 定义推送参数
    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 已提交
755

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771
    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 已提交
772

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791
    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 已提交
792

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
793 794 795 796 797 798 799 800 801
        // 单聊,直接调用 before 中封装好的消息推送方法
        pushParam.user_id = msgData.to_uid
        if (isMute) {
            console.log('消息接收者设置了免打扰,或本身就是一条静音消息,应用离线时,此消息不会有系统通知')
            pushParam.settings = {
                strategy: {
                    default: 3
                }
            }
DCloud_JSON's avatar
DCloud_JSON 已提交
802
        }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
803 804 805 806 807 808 809 810 811 812 813
        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 已提交
814
        }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
815 816 817 818 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
        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 已提交
846
        }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
847 848 849 850 851 852 853 854 855 856 857
        function sendMsgToGroup() {
            return uniCloud.importObject('uni-im-co').sendMsgToGroup({
                pushParam,
                appId
            })
        }
        res = {
            errCode: 0
        }
    } else {
        throw new Error('接受者标识,不能为空')
DCloud_JSON's avatar
DCloud_JSON 已提交
858
    }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
859
    return res
DCloud_JSON's avatar
DCloud_JSON 已提交
860 861 862
}

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

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
881 882
    // console.log('sendMsgToGroup=========', {
    // 	pushParam,
DCloud_JSON's avatar
DCloud_JSON 已提交
883 884 885 886
    // 	before_id,
    // 	push_clientids
    // });

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

    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 不能为空')
900
        }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
901 902 903 904 905 906
        let getMemberwhere = {
            group_id,
            mute: mute? true : dbCmd.neq(true),
            leave: dbCmd.neq(true),
            // 需要排除自己
            user_id: dbCmd.neq(pushParam.payload.data.from_uid)
907
        }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
908 909 910 911 912 913 914

        if (before_id) {
            getMemberwhere._id = dbCmd.gt(before_id)
        }
        // console.log({
        // 	getMemberwhere
        // });
915
        let res = await dbUniImConversation
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
916 917 918 919 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
           .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 已提交
988

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
        // 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 已提交
1006
        }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1007 1008
    } else {
        console.log('不需要查库,继续发送任务', push_clientids.length);
DCloud_JSON's avatar
DCloud_JSON 已提交
1009 1010
    }

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

    // 下一批推送的设备 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 已提交
1037
        }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1038 1039 1040
        // 执行推送
        let sendPushMsgRes = await this.sendPushMsg(pushParam, appId)
        // console.error(sendPushMsgRes)
DCloud_JSON's avatar
DCloud_JSON 已提交
1041
    }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058

    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 已提交
1059
        })
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076
    } 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 已提交
1077
        })
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100
    } 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 已提交
1101 1102 1103 1104
    }
}

async function getMsgList({
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1105 1106 1107
    conversation_ids,
    minUpdateTime,
    limit
DCloud_JSON's avatar
DCloud_JSON 已提交
1108
}) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119
    // 校验 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 已提交
1120

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1121 1122 1123 1124 1125 1126 1127 1128 1129 1130
    // 查询消息列表
    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 已提交
1131 1132 1133
}

async function _revokeMsg(msgId) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1134
    //1. 先查到这条消息
DCloud_JSON's avatar
DCloud_JSON 已提交
1135
    let {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1136 1137 1138 1139
      data: [msgData]
    } = await dbUniImMsg.doc(msgId).get()
    if (!msgData) {
        throw new Error('无效的消息 id')
DCloud_JSON's avatar
DCloud_JSON 已提交
1140
    }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1141 1142 1143 1144 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
    // 如果不是 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 已提交
1179 1180 1181
        }
    }

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

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

async function _isReadableMsg(msg) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217
    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 已提交
1218

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1219
    return true
DCloud_JSON's avatar
DCloud_JSON 已提交
1220 1221 1222
}

module.exports = {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1223 1224 1225 1226
    sendMsg,
    sendMsgToGroup,
    getMsgList
}