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
  // 查询群信息
  let groupInfo;
  if (msgData.group_id) {
    const res = await db.collection('uni-im-group')
      .doc(msgData.group_id)
      .field({
        type: true,
        name: true
      })
      .get()
432
    console.error('groupInfo------', res.data[0]);
433 434 435
    groupInfo = res.data[0]
  }
  
DCloud_JSON's avatar
DCloud_JSON 已提交
436 437 438 439 440 441 442

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

      if (!check) {
526 527 528 529 530 531 532 533
        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 已提交
534
        if (has) {
535 536 537
          check = true
        }
      }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
538 539

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    const { nickname, avatar_file } = msgData
738 739
    let title
    let content
740
    if(groupInfo){
741 742 743 744 745 746
      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 已提交
747 748 749 750 751 752 753 754 755 756 757 758 759
    // 定义推送参数
    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 已提交
760

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776
    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 已提交
777

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796
    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 已提交
797

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

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

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

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

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

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

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

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

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

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

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

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1126 1127 1128 1129 1130 1131 1132 1133 1134 1135
    // 查询消息列表
    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 已提交
1136 1137 1138
}

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

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

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

async function _isReadableMsg(msg) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222
    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 已提交
1223

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

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