firer.ts 8.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/**
 *
 * Wechaty: Wechat for Bot. Connecting ChatBots
 *
 * Class PuppetWeb Firer
 *
 * Process the Message to find which event to FIRE
 *
 * Licenst: ISC
 * https://github.com/wechaty/wechaty
 *
 * Firer for Class PuppetWeb
 *
 * here `this` is a PuppetWeb Instance
 *
16 17 18 19 20
 */
// import * as util  from 'util'
// import * as fs    from 'fs'

/* tslint:disable:no-var-requires */
21
const retryPromise  = require('retry-promise').default
22

23 24 25 26
import {
  // RecommendInfo
}                     from '../config'

27
import Contact        from '../contact'
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
28
import Message        from '../message'
29
import log            from '../brolog-env'
30

31 32 33
import FriendRequest  from './friend-request'

/* tslint:disable:variable-name */
34 35 36 37 38 39
const PuppetWebFirer = {
  fireFriendConfirm
  , fireFriendRequest

  , fireRoomJoin
  , fireRoomLeave
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
40
  , fireRoomTopic
41

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
42 43 44
  /**
   * for testing
   */
45
  , checkFriendConfirm
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
46

47 48
  , checkRoomJoin
  , checkRoomLeave
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
49
  , checkRoomTopic
50 51 52
}

const regexConfig = {
Huan (李卓桓)'s avatar
bug fix  
Huan (李卓桓) 已提交
53
  friendConfirm:  /^You have added (.+) as your WeChat contact. Start chatting!$/
54

Huan (李卓桓)'s avatar
bug fix  
Huan (李卓桓) 已提交
55 56
  , roomJoin:     /^"?(.+?)"? invited "(.+)" to the group chat$/
  , roomLeave:    /^You removed "(.+)" from the group chat$/
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
57
  , roomTopic:    /^"?(.+?)"? changed the group name to "(.+)"$/
58 59
}

60
async function fireFriendRequest(m: Message) {
61
  const info = m.rawObj.RecommendInfo
62
  log.verbose('PuppetWebFirer', 'fireFriendRequest(%s)', info)
63 64 65

  const request = new FriendRequest()
  request.receive(info)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
66 67

  await request.contact.ready()
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
  this.emit('friend', request.contact, request)
}

/**
 * try to find FriendRequest Confirmation Message
 */
function checkFriendConfirm(content) {
  const re = regexConfig.friendConfirm
  if (re.test(content)) {
    return true
  } else {
    return false
  }
}

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
83
async function fireFriendConfirm(m) {
84
  const content = m.content()
85
  log.silly('PuppetWebFirer', 'fireFriendConfirm(%s)', content)
86 87 88 89 90 91 92 93

  if (!checkFriendConfirm(content)) {
    return
  }
  const request = new FriendRequest()
  const contact = Contact.load(m.get('from'))
  request.confirm(contact)

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
94
  await contact.ready()
95 96 97 98 99 100
  this.emit('friend', contact)
}

/**
 * try to find 'join' event for Room
 *
101 102 103 104 105 106 107
 * 1.
 *  You've invited "李卓桓" to the group chat
 *  You've invited "李卓桓.PreAngel、Bruce LEE" to the group chat
 * 2.
 *  "李卓桓.PreAngel" invited "Bruce LEE" to the group chat
 *  "凌" invited "庆次、小桔妹" to the group chat
 */
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
108
function checkRoomJoin(content: string): [string[], string] {
109 110
  log.verbose('PuppetWebFirer', 'checkRoomJoin()')

111 112 113 114
  const re = regexConfig.roomJoin

  const found = content.match(re)
  if (!found) {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
115
    throw new Error('checkRoomJoin() not found')
116
  }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
117

118
  const [inviter, inviteeStr] = [ found[1], found[2] ]
119 120 121 122 123

  // "凌" invited "庆次、小桔妹" to the group chat
  const inviteeList = inviteeStr.split(/、/)

  return [inviteeList, inviter] // put invitee at first place
124 125
}

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
126
async function fireRoomJoin(m: Message): Promise<void> {
127
  log.verbose('PuppetWebFirer', 'fireRoomJoin(%s)', m.content())
128

129 130 131
  const room    = m.room()
  const content = m.content()

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
132 133 134
  let inviteeList: string[], inviter: string
  try {
    [inviteeList, inviter] = checkRoomJoin(content)
135 136
  } catch (e) {
    // not a room join message
137 138
    return
  }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
139 140 141 142
  log.silly('PuppetWebFirer', 'fireRoomJoin() inviteeList: %s, inviter: %s'
                            , inviteeList.join(',')
                            , inviter
          )
143

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
144 145
  let inviterContact: Contact
  let inviteeContactList: Contact[] = []
146

147
  try {
148 149 150 151
    if (inviter === "You've") {
      inviterContact = Contact.load(this.userId)
    }

152 153 154 155
    const max = 20
    const backoff = 300
    const timeout = max * (backoff * max) / 2
    // 20 / 300 => 63,000
156 157 158
    // max = (2*totalTime/backoff) ^ (1/2)
    // timeout = 11,250 for {max: 15, backoff: 100}

159
    await retryPromise({ max: max, backoff: backoff }, async (attempt: number) => {
160
      log.silly('PuppetWebFirer', 'fireRoomJoin() retryPromise() attempt %d with timeout %d', attempt, timeout)
161

162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
      await room.refresh()
                  // .then(_ => {
      let iDone, allDone = true

      for (let i in inviteeList) {
        iDone = inviteeContactList[i] instanceof Contact
        if (!iDone) {
          let c = room.member(inviteeList[i])
          if (c) {
            inviteeContactList[i] = c
          } else {
            allDone = false
          }
        }
      }

      if (!inviterContact) {
        inviterContact = room.member(inviter)
      }

      if (allDone && inviterContact) {
        log.silly('PuppetWebFirer', 'fireRoomJoin() resolve() inviteeContactList: %s, inviterContact: %s'
                                  , inviteeContactList.map((c: Contact) => c.name()).join(',')
                                  , inviterContact.name()
                )
        return
      }

      throw new Error('not found(yet)')

    }).catch(e => {
      log.silly('PuppetWebFirer', 'fireRoomJoin() reject() inviteeContactList: %s, inviterContact: %s'
                            , inviteeContactList.map((c: Contact) => c.name()).join(',')
                            , inviterContact.name()
              )
197
    })
198

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
199
    if (!inviterContact) {
200
      log.error('PuppetWebFirer', 'firmRoomJoin() inivter not found for %s , `room-join` & `join` event will not fired', inviter)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
201 202
      return
    }
203
    if (!inviteeContactList.every(c => c instanceof Contact)) {
204 205 206
      log.error('PuppetWebFirer', 'firmRoomJoin() inviteeList not all found for %s , only part of them will in the `room-join` or `join` event'
                                 , inviteeContactList.join(',')
              )
207
      inviteeContactList = inviteeContactList.filter(c => (c instanceof Contact))
208 209 210 211
      if (inviteeContactList.length < 1) {
        log.error('PuppetWebFirer', 'firmRoomJoin() inviteeList empty.  `room-join` & `join` event will not fired')
        return
      }
212
    }
213

214 215
    await Promise.all(inviteeContactList.map(c => c.ready()))
    await inviterContact.ready()
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
216
    await room.ready()
217 218

    if (inviteeContactList.length === 1) {
219 220
      this.emit('room-join', room , inviteeContactList[0] , inviterContact)
      room.emit('join'            , inviteeContactList[0] , inviterContact)
221
    } else {
222 223
      this.emit('room-join', room , inviteeContactList    , inviterContact)
      room.emit('join'            , inviteeContactList    , inviterContact)
224
    }
225

226
  } catch (e) {
227
    log.error('PuppetWebFirer', 'exception: %s', e.stack)
228 229 230
  }

  return
231 232
}

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
233
function checkRoomLeave(content: string): string {
234 235 236 237
  const re = regexConfig.roomLeave

  const found = content.match(re)
  if (!found) {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
238
    return null
239
  }
240
  return found[1] // leaver
241 242 243 244 245
}

/**
 * You removed "Bruce LEE" from the group chat
 */
246 247 248
async function fireRoomLeave(m: Message) {
  log.verbose('PuppetWebFirer', 'fireRoomLeave(%s)', m.content())

249 250 251 252
  const leaver = checkRoomLeave(m.content())
  if (!leaver) {
    return
  }
253 254
  log.silly('PuppetWebFirer', 'fireRoomLeave() got leaver: %s', leaver)

255
  const room = m.room()
256 257
  let leaverContact = room.member(leaver)

258
  if (!leaverContact) {
259
    log.error('PuppetWebFirer', 'fireRoomLeave() leaver %s not found, event `room-leave` & `leave` will not be fired')
260 261
    return
  }
262

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
263 264 265 266 267
  await leaverContact.ready()
  await room.ready()
  this.emit('room-leave', room, leaverContact)
  room.emit('leave'           , leaverContact)
  await room.refresh()
268 269
}

270
function checkRoomTopic(content: string): [string, string] {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
271 272 273 274
  const re = regexConfig.roomTopic

  const found = content.match(re)
  if (!found) {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
275
    throw new Error('checkRoomTopic() not found')
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
276
  }
277
  const [, changer, topic] = found
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
278 279 280
  return [topic, changer]
}

281
async function fireRoomTopic(m: Message) {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
282 283 284 285
  let  topic, changer
  try {
    [topic, changer] = checkRoomTopic(m.content())
  } catch (e) { // not found
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
286 287 288 289 290 291
    return
  }

  const room = m.room()
  const oldTopic = room.topic()

292
  let changerContact: Contact
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
293 294 295 296 297
  if (/^You$/.test(changer)) {
    changerContact = Contact.load(this.userId)
  } else {
    changerContact = room.member(changer)
  }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
298 299 300 301 302 303

  if (!changerContact) {
    log.error('PuppetWebFirer', 'fireRoomTopic() changer contact not found for %s', changer)
    return
  }

304 305 306
  // co.call(this, function* () {
  try {
    await changerContact.ready()
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
307
    await room.ready()
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
308
    this.emit('room-topic', room, topic, oldTopic, changerContact)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
309
    room.emit('topic'           , topic, oldTopic, changerContact)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
310
    room.refresh()
311 312
  // }).catch(e => {
  } catch (e) {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
313
    log.error('PuppetWebFirer', 'fireRoomTopic() co exception: %s', e.stack)
314
  }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
315 316
}

317 318
// module.exports = PuppetWebFirer
export default PuppetWebFirer