puppeteer-friend-request.ts 4.3 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
 *       http://www.apache.org/licenses/LICENSE-2.0
11
 *
12 13 14 15 16
 *   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 22 23 24 25
 * request/accept: https://github.com/wechaty/wechaty/issues/33
 *
 * 1. send request
 * 2. receive request(in friend event)
 * 3. confirmation friendship(friend event)
L
lijiarui 已提交
26
 * @ignore
27 28
 */

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

32
import {
33
  // config,
34
  log,
Huan (李卓桓)'s avatar
merge  
Huan (李卓桓) 已提交
35
}                     from '../config'
36 37 38
import {
  FriendRequest,
}                     from '../abstract-puppet/'
39

40 41
import {
  RecommendInfo,
42 43
}                       from './schema'
import PuppeteerContact from './puppeteer-contact'
44

L
lijiarui 已提交
45 46 47
/**
 * @alias FriendRequest
 */
48
export class PuppeteerFriendRequest extends FriendRequest {
49 50 51 52 53

  public info: RecommendInfo

  private ticket: string

54
  constructor() {
55
    log.verbose('PuppeteerFriendRequest', 'constructor()')
56 57 58
    super()
  }

59
  public receive(info: RecommendInfo): void {
60
    log.verbose('PuppeteerFriendRequest', 'receive(%s)', info)
61 62 63 64

    if (!info || !info.UserName) {
      throw new Error('not valid RecommendInfo: ' + info)
    }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
65
    this.info       = info
66

67
    const contact   = PuppeteerContact.load(info.UserName)
Huan (李卓桓)'s avatar
wip...  
Huan (李卓桓) 已提交
68
    contact.puppet  = this.puppet
69

70
    this.contact    = contact
71 72
    this.hello      = info.Content
    this.ticket     = info.Ticket
73 74
    // ??? this.nick = info.NickName

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
75 76 77 78
    if (!this.ticket) {
      throw new Error('ticket not found')
    }

79
    this.type = 'receive'
80

81
    return
82 83
  }

84 85
  public confirm(contact: PuppeteerContact): void {
    log.verbose('PuppeteerFriendRequest', 'confirm(%s)', contact)
86

87 88
    if (!contact) {
      throw new Error('contact not found')
89
    }
90 91
    this.contact  = contact
    this.type     = 'confirm'
92 93
  }

L
lijiarui 已提交
94 95
  /**
   * Send a new friend request
96
   * @param {PuppeteerContact} contact
L
lijiarui 已提交
97 98 99 100 101 102 103
   * @param {string} [hello='Hi']
   * @returns {Promise<boolean>} Return a Promise, true for accept successful, false for failure.
   * @example
   * const from = message.from()
   * const request = new FriendRequest()
   * request.send(from, 'hello~')
   */
104 105
  public async send(contact: PuppeteerContact, hello = 'Hi'): Promise<void> {
    log.verbose('PuppeteerFriendRequest', 'send(%s)', contact)
106

107 108
    if (!contact) {
      throw new Error('contact not found')
109
    }
110
    this.contact  = contact
Huan (李卓桓)'s avatar
wip...  
Huan (李卓桓) 已提交
111
    this.type     = 'send'
112

Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
113 114
    if (hello) {
      this.hello = hello
115 116
    }

Huan (李卓桓)'s avatar
wip...  
Huan (李卓桓) 已提交
117
    await this.puppet.friendRequestSend(contact, hello)
118 119
  }

L
lijiarui 已提交
120 121 122
  /**
   * Accept a friend request
   *
Huan (李卓桓)'s avatar
wip...  
Huan (李卓桓) 已提交
123
   * @returns {Promise<void>} Return a Promise, true for accept successful, false for failure.
L
lijiarui 已提交
124
   */
Huan (李卓桓)'s avatar
wip...  
Huan (李卓桓) 已提交
125
  public async accept(): Promise<void> {
126
    log.verbose('FriendRequest', 'accept() %s', this.contact)
127 128

    if (this.type !== 'receive') {
129
      throw new Error('request is not a `receive` type. it is a ' + this.type + ' type')
130 131
    }

Huan (李卓桓)'s avatar
wip...  
Huan (李卓桓) 已提交
132
    await this.puppet.friendRequestAccept(this.contact, this.ticket)
133 134 135 136 137 138 139 140 141 142 143

    const max = 20
    const backoff = 300
    const timeout = max * (backoff * max) / 2
    // 20 / 300 => 63,000
    // max = (2*totalTime/backoff) ^ (1/2)
    // timeout = 11,250 for {max: 15, backoff: 100}

    // refresh to wait contact ready

    await retryPromise({ max: max, backoff: backoff }, async (attempt: number) => {
144
      log.silly('PuppeteerFriendRequest', 'accept() retryPromise() attempt %d with timeout %d', attempt, timeout)
145 146 147

      await this.contact.ready()

148 149
      if ((this.contact as PuppeteerContact).isReady()) {
        log.verbose('PuppeteerFriendRequest', 'accept() with contact %s ready()', this.contact.name())
150 151
        return
      }
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
152
      throw new Error('FriendRequest.accept() content.ready() not ready')
153 154

    }).catch( e => {
155
      log.warn('PuppeteerFriendRequest', 'accept() rejected for contact %s because %s', this.contact, e && e.message || e)
156 157
    })

158 159 160 161
  }

}

162
export default PuppeteerFriendRequest