contact.ts 5.6 KB
Newer Older
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
1 2 3 4 5 6 7 8
/**
 *
 * wechaty: Wechat for Bot. and for human who talk to bot/robot
 *
 * Licenst: ISC
 * https://github.com/zixia/wechaty
 *
 */
9 10 11 12
import Config   from './config'
import UtilLib  from './util-lib'

import log      from './brolog-env'
13

14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
type ContactObj = {
  id:       string
  uin:      string
  name:     string
  remark:   string
  weixin:   string
  sex:      string
  province: string
  city:     string
  signature:  string
  address:    string
  stranger: boolean
  star:     boolean
}

type ContactRawObj = {
  UserName:     string
  Uin:          string
  Alias:        string
  RemarkName:   string
  Sex:          string
  Province:     string
  City:         string
  NickName:     string
  StarFriend:   string
  stranger:     string
  Signature:    string
}

43 44 45 46
type ContactQueryFilter = {
  name: string | RegExp
}

47
class Contact {
48 49 50 51 52 53
  private static pool = new Map<string, Contact>()

  private obj: ContactObj
  private rawObj: ContactRawObj

  constructor(public readonly id: string) {
54
    log.silly('Contact', `constructor(${id})`)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
55

56 57 58
    if (typeof id !== 'string') {
      throw new Error('id must be string. found: ' + typeof id)
    }
59 60
  }

61 62
  public toString()  { return this.id }
  public toStringEx() { return `Contact(${this.obj && this.obj.name}[${this.id}])` }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
63

64 65
  private parse(rawObj: ContactRawObj): ContactObj {
    return !rawObj ? null : {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
66
      id:           rawObj.UserName
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
67
      , uin:        rawObj.Uin    // stable id: 4763975 || getCookie("wxuin")
68
      , weixin:     rawObj.Alias  // Wechat ID
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
69 70 71
      , name:       rawObj.NickName
      , remark:     rawObj.RemarkName
      , sex:        rawObj.Sex
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
72 73 74
      , province:   rawObj.Province
      , city:       rawObj.City
      , signature:  rawObj.Signature
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
75

76 77
      , address:    rawObj.Alias // XXX: need a stable address for user

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
78 79
      , star:       !!rawObj.StarFriend
      , stranger:   !!rawObj.stranger // assign by injectio.js
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
80 81
    }
  }
82

83 84 85 86
  public name()      { return UtilLib.plainText(this.obj && this.obj.name) }
  public remark()    { return this.obj && this.obj.remark }
  public stranger()  { return this.obj && this.obj.stranger }
  public star()      { return this.obj && this.obj.star }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
87

88
  public get(prop)   { return this.obj && this.obj[prop] }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
89

90
  public ready(contactGetter?: (id: string) => Promise<ContactRawObj>): Promise<Contact> {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
91
    log.silly('Contact', 'ready(' + (contactGetter ? typeof contactGetter : '') + ')')
92 93 94
    if (!this.id) {
      log.warn('Contact', 'ready() call on an un-inited contact')
      return Promise.resolve(this)
95
    }
96

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
97
    if (this.obj && this.obj.id) { // already ready
98 99
      return Promise.resolve(this)
    }
100 101

    if (!contactGetter) {
102 103 104 105 106
      if (!Config.puppetInstance()) { throw new Error('Config.puppetInstance() is not found by Contact') }

      log.silly('Contact', 'get contact via ' + Config.puppetInstance().constructor.name)
      contactGetter = Config.puppetInstance()
                              .getContact.bind(Config.puppetInstance())
107 108
    }
    return contactGetter(this.id)
109 110 111 112 113 114 115 116 117
            .then(data => {
              log.silly('Contact', `contactGetter(${this.id}) resolved`)
              this.rawObj = data
              this.obj    = this.parse(data)
              return this
            }).catch(e => {
              log.error('Contact', `contactGetter(${this.id}) exception: %s`, e.message)
              throw e
            })
118 119
  }

120
  public dumpRaw() {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
121
    console.error('======= dump raw contact =======')
122
    Object.keys(this.rawObj).forEach(k => console.error(`${k}: ${this.rawObj[k]}`))
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
123
  }
124
  public dump()    {
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
125
    console.error('======= dump contact =======')
126
    Object.keys(this.obj).forEach(k => console.error(`${k}: ${this.obj[k]}`))
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
127
  }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
128

129 130 131 132
  public static findAll(query: ContactQueryFilter): Promise<Contact[]> {
    log.silly('Cotnact', 'findAll({ name: %s })', query.name)

    const name = query.name
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
133 134 135 136 137

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

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
138 139 140 141 142 143
    /**
     * must be string because we need inject variable value
     * into code as variable name
     */
    let filterFunction: string

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
144 145 146 147 148 149 150 151 152 153 154
    if (name instanceof RegExp) {
      filterFunction = `c => ${name.toString()}.test(c)`
    } else if (typeof name === 'string') {
      filterFunction = `c => c === '${name}'`
    } else {
      throw new Error('unsupport name type')
    }

    return Config.puppetInstance()
                  .contactFind(filterFunction)
                  .catch(e => {
155 156
                    log.error('Contact', 'findAll() rejected: %s', e.message)
                    return [] // fail safe
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
157
                  })
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
158
  }
159

160 161
  public static find(query: ContactQueryFilter): Promise<Contact> {
    log.verbose('Contact', 'find(%s)', query.name)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
162

163 164 165 166 167 168 169 170 171 172 173
    return Contact.findAll(query)
                  .then(contactList => {
                    if (contactList && contactList.length > 0) {
                      return contactList[0]
                    }
                    return null
                  })
                  .catch(e => {
                    log.error('Contact', 'find() rejected: %s', e.message)
                    return null // fail safe
                  })
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
174 175
  }

176
  public static load(id: string): Contact {
177 178 179
    if (!id || typeof id !== 'string') {
      return null
    }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
180

181 182 183 184
    if (!(id in Contact.pool)) {
      Contact.pool[id] = new Contact(id)
    }
    return Contact.pool[id]
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
185
  }
186

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
187
}
188

189 190 191 192 193 194 195 196 197 198
// Contact.search = function(options) {
//   if (options.name) {
//     const regex = new RegExp(options.name)
//     return Object.keys(Contact.pool)
//     .filter(k => regex.test(Contact.pool[k].name()))
//     .map(k => Contact.pool[k])
//   }

//   return []
// }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
199

200 201 202
// module.exports = Contact.default = Contact.Contact = Contact

export default Contact