friend-request.ts 6.7 KB
Newer Older
1
/**
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
2
 *   Wechaty - https://github.com/chatie/wechaty
3
 *
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
4
 *   @copyright 2016-2018 Huan LI <zixia@zixia.net>
5
 *
6 7 8
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
9
 *
10 11 12 13 14 15 16
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
L
lijiarui 已提交
17
 *   @ignore
18 19 20
 *
 */

21
 /* tslint:disable:no-var-requires */
22
// const retryPromise  = require('retry-promise').default
23 24 25
import {
  instanceToClass,
}                   from 'clone-class'
26

27 28 29 30 31 32
import {
  Accessory,
}                   from './accessory'
import {
  Contact,
}                   from './contact'
33 34
import {
  log,
35 36 37 38
}                   from './config'
import {
  Misc,
}                   from './misc'
39

40 41 42 43
import {
  FriendRequestPayload,
  FriendRequestType,
}                         from './puppet/'
44

L
lijiarui 已提交
45 46 47 48 49 50 51
/**
 * Send, receive friend request, and friend confirmation events.
 *
 * 1. send request
 * 2. receive request(in friend event)
 * 3. confirmation friendship(friend event)
 *
52
 * [Examples/Friend-Bot]{@link https://github.com/Chatie/wechaty/blob/master/examples/friend-bot.ts}
L
lijiarui 已提交
53
 */
54
export class FriendRequest extends Accessory {
55

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
56 57 58
  // tslint:disable-next-line:variable-name
  public static Type = FriendRequestType

59
  public static load<T extends typeof FriendRequest>(
60 61
    this : T,
    id   : string,
62 63
  ): T['prototype'] {
    const newFriendRequest = new (this as any)(id)
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
64
    newFriendRequest.payload = this.puppet.cacheFriendRequestPayload.get(id)
65 66 67
    return newFriendRequest
  }

68 69 70 71 72
  /**
   * Send a Friend Request to a `contact` with message `hello`.
   * @param contact
   * @param hello
   */
73
  public static async send(
74 75
    contact : Contact,
    hello   : string,
76 77 78
  ): Promise<void> {
    log.verbose('PuppeteerFriendRequest', 'static send(%s, %s)',
                                          contact.id,
79 80
                                          hello,
                )
81
    await this.puppet.friendRequestSend(contact.id, hello)
82 83
  }

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
  // public static createConfirm(
  //   contactId: string,
  // ): FriendRequestPayload {
  //   log.verbose('PuppeteerFriendRequest', 'createConfirm(%s)',
  //                                         contactId,
  //               )

  //   const payload: FriendRequestPayloadConfirm = {
  //     type : FriendRequestType.Confirm,
  //     contactId,
  //   }

  //   return payload
  // }

  // public static createReceive(
  //   contactId : string,
  //   hello     : string,
  //   ticket    : string,
  // ): FriendRequestPayload {
  //   log.verbose('PuppeteerFriendRequest', 'createReceive(%s, %s, %s)',
  //                                         contactId,
  //                                         hello,
  //                                         ticket,
  //               )

  //   const payload: FriendRequestPayloadReceive = {
  //     type : FriendRequestType.Receive,
  //     contactId,
  //     hello,
  //     ticket,
  //   }

  //   return payload
  // }
119

120 121 122 123 124
  /**
   *
   * Instance Properties
   *
   */
125 126 127

  protected payload?: FriendRequestPayload

128
  constructor(
129
    public id: string,
130 131
  ) {
    super()
132
    log.verbose('PuppeteerFriendRequest', 'constructor(id=%s)', id)
133 134 135 136 137 138 139 140 141 142 143

    // tslint:disable-next-line:variable-name
    const MyClass = instanceToClass(this, FriendRequest)

    if (MyClass === FriendRequest) {
      throw new Error('FriendRequest class can not be instanciated directly! See: https://github.com/Chatie/wechaty/issues/1217')
    }

    if (!this.puppet) {
      throw new Error('FriendRequest class can not be instanciated without a puppet!')
    }
144 145
  }

146 147
  public toString() {
    if (!this.payload) {
148
      return this.constructor.name
149
    }
150 151 152 153 154 155 156
    return [
      'FriendRequest#',
      FriendRequestType[this.payload.type],
      '<',
      this.payload.contactId,
      '>',
    ].join('')
157 158
  }

159 160 161 162 163 164 165 166 167 168 169 170 171 172
  public isReady(): boolean {
    return !!this.payload && (Object.keys(this.payload).length > 0)
  }

  /**
   * no `noCache` support because FriendRequest has no rawPayload(yet)
   */
  public async ready(): Promise<void> {
    if (this.payload) {
      return
    }

    this.payload = await this.puppet.friendRequestPayload(this.id)

173 174 175 176 177
    if (!this.payload) {
      throw new Error('no payload')
    }
  }

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
  // public async send(): Promise<void> {
  //   if (!this.payload) {
  //     throw new Error('no payload')
  //   } else if (!this.payload.contactId) {
  //     throw new Error('no contact')
  //   } else if (this.payload.type !== FriendRequest.Type.Send) {
  //     throw new Error('not a send request')
  //   }
  //   log.verbose('PuppeteerFriendRequest', 'send() to %s', this.payload.contactId)

  //   await this.puppet.friendRequestSend(
  //     this.payload.contactId,
  //     this.payload.hello,
  //   )
  // }

194
  public async accept(): Promise<void> {
195 196
    log.verbose('FriendRequest', 'accept()')

197 198 199 200
    if (!this.payload) {
      throw new Error('no payload')
    }

201 202 203
    if (this.payload.type !== FriendRequest.Type.Receive) {
      throw new Error('accept() need type to be FriendRequestType.Receive, but it got a ' + FriendRequest.Type[this.payload.type!])
    }
204

205
    log.silly('FriendRequest', 'accept() to %s', this.payload.contactId)
206

207
    await this.puppet.friendRequestAccept(this.payload.contactId, this.payload.ticket)
208

209
    const contact = this.contact()
210 211

    await Misc.retry(async (retry, attempt) => {
212
      log.silly('PuppeteerFriendRequest', 'accept() retry() ready() attempt %d', attempt)
213

214
      await contact.ready()
215

216 217
      if (contact.isReady()) {
        log.verbose('PuppeteerFriendRequest', 'accept() with contact %s ready()', contact.name())
218 219
        return
      }
220
      retry(new Error('FriendRequest.accept() content.ready() not ready'))
221 222

    }).catch((e: Error) => {
223
      log.warn('PuppeteerFriendRequest', 'accept() contact %s not ready because of %s', contact, e && e.message || e)
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
    })

  }

  public hello(): string {
    if (!this.payload) {
      throw new Error('no payload')
    }
    return this.payload.hello || ''
  }

  public contact(): Contact {
    if (!this.payload) {
      throw new Error('no payload')
    }
239

240
    const contact = this.wechaty.Contact.load(this.payload.contactId)
241
    return contact
242
  }
243

244 245 246 247
  public async reject(): Promise<void> {
    log.warn('PuppeteerFriendRequest', 'reject() not necessary, NOP.')
    return
  }
248

249
  public type(): FriendRequestType {
250 251 252
    return this.payload
            ? this.payload.type
            : FriendRequestType.Unknown
253
  }
254 255

}
Huan (李卓桓)'s avatar
merge  
Huan (李卓桓) 已提交
256 257

export default FriendRequest