room.js 8.4 KB
Newer Older
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
1 2 3 4 5 6 7
/**
 *
 * wechaty: Wechat for Bot. and for human who talk to bot/robot
 *
 * Licenst: ISC
 * https://github.com/zixia/wechaty
 *
8 9
 * Add/Del/Topic: https://github.com/wechaty/wechaty/issues/32
 *
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
10
 */
11 12
const EventEmitter = require('events')

13
const Wechaty   = require('./wechaty')
Huan (李卓桓)'s avatar
bug fix  
Huan (李卓桓) 已提交
14
const Contact   = require('./contact')
15 16 17
const log       = require('./brolog-env')
const UtilLib   = require('./util-lib')
const Config    = require('./config')
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
18

19
class Room extends EventEmitter{
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
20
  constructor(id) {
21
    super()
22
    log.silly('Room', `constructor(${id})`)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
23
    this.id = id
24
    this.obj = {}
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
25
    this.dirtyObj = {} // when refresh, use this to save dirty data for query
26 27
    if (!Config.puppetInstance()) {
      throw new Error('Config.puppetInstance() not found')
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
28
    }
29
  }
30

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
31
  toString()    { return this.id }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
32
  toStringEx()  { return `Room(${this.obj.topic}[${this.id}])` }
33

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
34
  // @private
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
35
  isReady() {
36
    return this.obj.memberList && this.obj.memberList.length
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
37 38 39
  }

  refresh() {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
40
    this.dirtyObj = this.obj
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
41 42 43 44
    this.obj = {}
    return this.ready()
  }

45
  ready(contactGetter) {
46
    log.silly('Room', 'ready(%s)', contactGetter ? contactGetter.constructor.name : '')
47
    if (!this.id) {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
48 49 50 51
      const e = new Error('ready() on a un-inited Room')
      log.warn('Room', e.message)
      return Promise.reject(e)
    } else if (this.isReady()) {
52
      return Promise.resolve(this)
53
    } else if (this.obj.id) {
54
      log.warn('Room', 'ready() has obj.id but memberList empty in room %s. reloading', this.obj.topic)
55
    }
56

57 58
    contactGetter = contactGetter || Config.puppetInstance()
                                            .getContact.bind(Config.puppetInstance())
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
59
    return contactGetter(this.id)
60
    .then(data => {
61
      log.silly('Room', `contactGetter(${this.id}) resolved`)
62 63
      this.rawObj = data
      this.obj    = this.parse(data)
64
      return this
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
65
    }).catch(e => {
66 67
      log.error('Room', 'contactGetter(%s) exception: %s', this.id, e.message)
      throw e
68 69 70
    })
  }

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
  owner() {
    const ownerUin = this.obj.ownerUin
    let memberList = this.obj.memberList || []

    let user = Config.puppetInstance()
                      .user

    if (user && user.get('uin') === ownerUin) {
      return user
    }

    memberList = memberList.filter(m => m.Uin === ownerUin)
    if (memberList.length > 0) {
      return memberList[0]
    }

    return null
  }

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
90
  get(prop) { return this.obj[prop] || this.dirtyObj[prop] }
91

92
  parse(rawObj) {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
93 94 95 96
    if (!rawObj) {
      return {}
    }
    return {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
97 98 99 100 101
      id:           rawObj.UserName
      , encryId:    rawObj.EncryChatRoomId // ???
      , topic:      rawObj.NickName
      , ownerUin:   rawObj.OwnerUin

102 103
      , memberList: this.parseMemberList(rawObj.MemberList)
      , nickMap:    this.parseNickMap(rawObj.MemberList)
104 105 106
    }
  }

107
  parseMemberList(memberList) {
108 109 110
    if (!memberList || !memberList.map) {
      return []
    }
111
    return memberList.map(m => Contact.load(m.UserName))
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
112 113 114 115 116
  }

  parseNickMap(memberList) {
    const nickMap = {}
    if (memberList && memberList.map) {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
117 118 119
      memberList.forEach(m => {
        nickMap[m.UserName] = m.DisplayName || m.NickName
      })
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
120 121
    }
    return nickMap
122 123
  }

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
124
  dumpRaw() {
125
    console.error('======= dump raw Room =======')
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
126
    Object.keys(this.rawObj).forEach(k => console.error(`${k}: ${this.rawObj[k]}`))
127
  }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
128
  dump()    {
129
    console.error('======= dump Room =======')
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
130
    Object.keys(this.obj).forEach(k => console.error(`${k}: ${this.obj[k]}`))
131 132
  }

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
133 134 135 136 137 138
  del(contact) {
    log.verbose('Room', 'del(%s) from %s', contact, this)

    if (!contact) {
      throw new Error('contact not found')
    }
139
    return Config.puppetInstance().roomDel(this, contact)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
140 141 142
                      .then(r => this.delLocal(contact))
  }

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
143
  // @private
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
144 145 146
  delLocal(contact) {
    log.verbose('Room', 'delLocal(%s)', contact)

147 148
    const memberList = this.obj.memberList
    if (!memberList || memberList.length === 0) {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
149 150 151 152
      return true // already in refreshing
    }

    let i
153
    for (i=0; i<memberList.length; i++) {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
154 155 156
// XXX
// console.log('########################')
// console.log(i)
157
// console.log(memberList[i].id)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
158 159
// console.log(contact.get('id'))
// console.log('!!!!!!!!!!!!!!!!!!!!!!!!!!')
160
      if (memberList[i].id === contact.get('id')) {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
161 162 163 164
        break
      }
    }
// console.log('found i=' + i)
165 166 167 168
    if (i < memberList.length) {
// console.log('splicing before: ' + memberList.length)
      memberList.splice(i, 1)
// console.log('splicing after: ' + memberList.length)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
169 170 171
      return true
    }
    return false
172
  }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
173 174 175 176

  quit() {
    throw new Error('wx web not implement yet')
    // WechatyBro.glue.chatroomFactory.quit("@@1c066dfcab4ef467cd0a8da8bec90880035aa46526c44f504a83172a9086a5f7"
177
  }
178

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
179 180 181 182 183 184
  add(contact) {
    log.verbose('Room', 'add(%s) to %s', contact, this)

    if (!contact) {
      throw new Error('contact not found')
    }
185

186
    return Config.puppetInstance().roomAdd(this, contact)
187
  }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
188

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
189 190
  topic(newTopic) {
    log.verbose('Room', 'topic(%s)', newTopic)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
191

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
192
    if (newTopic) {
193
      Config.puppetInstance().roomTopic(this, newTopic)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
194 195
      return newTopic
    }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
196 197
    // return this.get('topic')
    return UtilLib.plainText(this.obj.topic)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
198 199
  }

200
  nick(contact) {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
201 202 203
    if (!this.obj.nickMap) {
      return ''
    }
204 205 206 207 208 209 210 211 212 213 214 215 216
    return this.obj.nickMap[contact.id]
  }

  has(contact) {
    if (!this.obj.memberList) {
      return false
    }
    return this.obj.memberList
                    .filter(c => c.id === contact.id)
                    .length > 0
  }

  member(name) {
217 218
    log.verbose('Room', 'member(%s)', name)

219
    if (!this.obj.memberList) {
220
      log.warn('Room', 'member() not ready')
221 222 223 224 225
      return null
    }
    const nickMap = this.obj.nickMap
    const idList = Object.keys(nickMap)
                          .filter(k => nickMap[k] === name)
226 227 228

    log.silly('Room', 'member() check nickMap: %s', JSON.stringify(nickMap))

229 230 231 232 233
    if (idList.length) {
      return Contact.load(idList[0])
    } else {
      return null
    }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
234 235
  }

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
236 237 238 239 240 241
  static create(contactList) {
    log.verbose('Room', 'create(%s)', contactList.join(','))

    if (!contactList || ! typeof contactList === 'array') {
      throw new Error('contactList not found')
    }
242
    return Config.puppetInstance().roomCreate(contactList)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
  }

  // private
  static _find({
    name
  }) {
    log.silly('Room', '_find(%s)', name)

    if (!name) {
      throw new Error('name not found')
    }

    let filterFunction
    if (name instanceof RegExp) {
      filterFunction = `c => ${name.toString()}.test(c)`
    } else if (typeof name === 'string') {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
259
      filterFunction = `c => c === '${name}'`
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
260 261 262 263
    } else {
      throw new Error('unsupport name type')
    }

264
    return Config.puppetInstance().roomFind(filterFunction)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
              .then(idList => {
                return idList
              })
              .catch(e => {
                log.error('Room', '_find() rejected: %s', e.message)
                throw e
              })
  }

  static find({
    name
  }) {
    log.verbose('Room', 'find(%s)', name)

    return Room._find({name})
              .then(idList => {
                if (!idList || !Array.isArray(idList)){
                  throw new Error('_find return error')
                }
                if (idList.length < 1) {
                  return null
                }
                const id = idList[0]
                return Room.load(id)
              })
              .catch(e => {
                log.error('Room', 'find() rejected: %s', e.message)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
292
                return null // fail safe
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
              })
  }

  static findAll({
    name
  }) {
    log.verbose('Room', 'findAll(%s)', name)

    return Room._find({name})
              .then(idList => {
                // console.log(idList)
                if (!idList || !Array.isArray(idList)){
                  throw new Error('_find return error')
                }
                if (idList.length < 1) {
                  return []
                }
                return idList.map(i => Room.load(i))
              })
              .catch(e => {
                log.error('Room', 'findAll() rejected: %s', e.message)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
314
                return [] // fail safe
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
315 316 317 318 319 320 321 322 323 324 325 326 327 328
              })
  }

  static init() { Room.pool = {} }

  static load(id) {
    if (!id) { return null }

    if (id in Room.pool) {
      return Room.pool[id]
    }
    return Room.pool[id] = new Room(id)
  }

329 330 331 332
  // static attach(puppet) {
  //   // if (!puppet) {
  //   //   throw new Error('Room.attach got no puppet to attach!')
  //   // }
333
  //   Config.puppetInstance() = puppet
334
  // }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
335

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
336
}
337

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
338 339
Room.init()

340
module.exports = Room