friendship.ts 6.1 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
import {
41 42
  FriendshipPayload,
  FriendshipType,
43
}                         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 Friendship extends Accessory {
55

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

59
  public static load<T extends typeof Friendship>(
60 61
    this : T,
    id   : string,
62
  ): T['prototype'] {
63
    const newFriendship = new (this as any)(id)
64
    // newFriendRequest.payload = this.puppet.cacheFriendRequestPayload.get(id)
65
    return newFriendship
66 67
  }

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
  ): Promise<void> {
77
    log.verbose('Friendship', 'static send(%s, %s)',
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
78 79
                                  contact.id,
                                  hello,
80
                )
81
    await this.puppet.friendshipVerify(contact.id, hello)
82 83
  }

84 85 86
  // public static createConfirm(
  //   contactId: string,
  // ): FriendRequestPayload {
87
  //   log.verbose('Friendship', 'createConfirm(%s)',
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
  //                                         contactId,
  //               )

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

  //   return payload
  // }

  // public static createReceive(
  //   contactId : string,
  //   hello     : string,
  //   ticket    : string,
  // ): FriendRequestPayload {
104
  //   log.verbose('Friendship', 'createReceive(%s, %s, %s)',
105 106 107 108 109 110 111 112 113 114 115 116 117 118
  //                                         contactId,
  //                                         hello,
  //                                         ticket,
  //               )

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

  //   return payload
  // }
119

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

126
  protected get payload(): undefined | FriendshipPayload {
127 128 129 130
    if (!this.id) {
      return undefined
    }

131
    return this.puppet.friendshipPayloadCache(this.id)
132
  }
133

134
  constructor(
135
    public id: string,
136 137
  ) {
    super()
138
    log.verbose('Friendship', 'constructor(id=%s)', id)
139 140

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

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

    if (!this.puppet) {
148
      throw new Error('Friendship class can not be instanciated without a puppet!')
149
    }
150 151
  }

152 153
  public toString() {
    if (!this.payload) {
154
      return this.constructor.name
155
    }
156
    return [
157 158
      'Friendship#',
      FriendshipType[this.payload.type],
159 160 161 162
      '<',
      this.payload.contactId,
      '>',
    ].join('')
163 164
  }

165 166 167 168 169
  public isReady(): boolean {
    return !!this.payload && (Object.keys(this.payload).length > 0)
  }

  /**
Huan (李卓桓)'s avatar
Huan (李卓桓) 已提交
170
   * no `dirty` support because Friendship has no rawPayload(yet)
171 172 173 174 175 176
   */
  public async ready(): Promise<void> {
    if (this.payload) {
      return
    }

177
    await this.puppet.friendshipPayload(this.id)
178

179 180 181 182 183 184
    if (!this.payload) {
      throw new Error('no payload')
    }
  }

  public async accept(): Promise<void> {
185
    log.verbose('Friendship', 'accept()')
186

187 188 189 190
    if (!this.payload) {
      throw new Error('no payload')
    }

191 192
    if (this.payload.type !== Friendship.Type.Receive) {
      throw new Error('accept() need type to be FriendshipType.Receive, but it got a ' + Friendship.Type[this.payload.type!])
193
    }
194

195
    log.silly('Friendship', 'accept() to %s', this.payload.contactId)
196

197
    await this.puppet.friendshipAccept(this.id)
198

199
    const contact = this.contact()
200 201

    await Misc.retry(async (retry, attempt) => {
202
      log.silly('Friendship', 'accept() retry() ready() attempt %d', attempt)
203

204
      await contact.ready()
205

206
      if (contact.isReady()) {
207
        log.verbose('Friendship', 'accept() with contact %s ready()', contact.name())
208 209
        return
      }
210
      retry(new Error('Friendship.accept() content.ready() not ready'))
211 212

    }).catch((e: Error) => {
213
      log.warn('Friendship', 'accept() contact %s not ready because of %s', contact, e && e.message || e)
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
    })

  }

  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')
    }
229

230
    const contact = this.wechaty.Contact.load(this.payload.contactId)
231
    return contact
232
  }
233

234
  public async reject(): Promise<void> {
235
    log.warn('Friendship', 'reject() not necessary, NOP.')
236 237
    return
  }
238

239
  public type(): FriendshipType {
240 241
    return this.payload
            ? this.payload.type
242
            : FriendshipType.Unknown
243
  }
244 245

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

247
export default Friendship