-
Notifications
You must be signed in to change notification settings - Fork 356
/
Copy pathroom-bot.js
442 lines (379 loc) · 12.2 KB
/
room-bot.js
1
2
3
4
5
6
7
8
9
10
11
12
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
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
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
#!/usr/bin/env node
/**
* Wechaty - https://github.com/chatie/wechaty
*
* @copyright 2016-2018 Huan LI <[email protected]>
*
* 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
*
* 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.
*
*/
/**
*
* Known ISSUES:
* - BUG1: can't find member by this NickName:
* ' leaver: 艾静<img class="emoji emojiae" text="_web" src="/zh_CN/htmledition/v2/images/spacer.gif" />JOY
* - BUG2: leave event not right: sometimes can not found member (any more, because they left)
* create a room need at least three people
* when we create a room, the following one is the 3rd people.
*
* put name of one of your friend here, or room create function will not work.
*
* ::::::::: ___CHANGE ME___ :::::::::
* vvvvvvvvv
* vvvvvvvvv
* vvvvvvvvv
*/
const HELPER_CONTACT_NAME = '李卓桓'
/**
* ^^^^^^^^^
* ^^^^^^^^^
* ^^^^^^^^^
* ::::::::: ___CHANGE ME___ :::::::::
*
*/
/* tslint:disable:variable-name */
import qrTerm from 'qrcode-terminal'
import {
config,
Contact,
Room,
Wechaty,
log,
} from 'wechaty'
const welcome = `
=============== Powered by Wechaty ===============
-------- https://github.com/Chatie/wechaty --------
Hello,
I'm a Wechaty Botie with the following super powers:
1. Find a room
2. Add people to room
3. Del people from room
4. Change room topic
5. Monitor room events
6. etc...
If you send a message of magic word 'ding',
you will get a invitation to join my own room!
__________________________________________________
Hope you like it, and you are very welcome to
upgrade me for more super powers!
Please wait... I'm trying to login in...
`
console.log(welcome)
const bot = Wechaty.instance({ profile: config.default.DEFAULT_PROFILE })
bot
.on('scan', (qrcode, status) => {
qrTerm.generate(qrcode, { small: true })
console.log(`${qrcode}\n[${status}] Scan QR Code in above url to login: `)
})
.on('logout' , user => log.info('Bot', `"${user.name()}" logouted`))
.on('error' , e => log.info('Bot', 'error: %s', e))
/**
* Global Event: login
*
* do initialization inside this event.
* (better to set a timeout, for browser need time to download other data)
*/
.on('login', async function(user) {
let msg = `${user.name()} logined`
log.info('Bot', msg)
await this.say(msg)
msg = `setting to manageDingRoom() after 3 seconds ... `
log.info('Bot', msg)
await this.say(msg)
setTimeout(manageDingRoom.bind(this), 3000)
})
/**
* Global Event: room-join
*/
.on('room-join', async function(room, inviteeList, inviter) {
log.info( 'Bot', 'EVENT: room-join - Room "%s" got new member "%s", invited by "%s"',
await room.topic(),
inviteeList.map(c => c.name()).join(','),
inviter.name(),
)
console.log('bot room-join room id:', room.id)
const topic = await room.topic()
await room.say(`welcome to "${topic}"!`, inviteeList[0])
})
/**
* Global Event: room-leave
*/
.on('room-leave', async function(room, leaverList) {
log.info('Bot', 'EVENT: room-leave - Room "%s" lost member "%s"',
await room.topic(),
leaverList.map(c => c.name()).join(','),
)
const topic = await room.topic()
const name = leaverList[0] ? leaverList[0].name() : 'no contact!'
await room.say(`kick off "${name}" from "${topic}"!` )
})
/**
* Global Event: room-topic
*/
.on('room-topic', async function(room, topic, oldTopic, changer) {
try {
log.info('Bot', 'EVENT: room-topic - Room "%s" change topic from "%s" to "%s" by member "%s"',
room,
oldTopic,
topic,
changer,
)
await room.say(`room-topic - change topic from "${oldTopic}" to "${topic}" by member "${changer.name()}"` )
} catch (e) {
log.error('Bot', 'room-topic event exception: %s', e.stack)
}
})
/**
* Global Event: message
*/
.on('message', async function(msg) {
if (msg.age() > 3 * 60) {
log.info('Bot', 'on(message) skip age("%d") > 3 * 60 seconds: "%s"', msg.age(), msg)
return
}
const room = msg.room()
const from = msg.from()
const text = msg.text()
if (!from) {
return
}
console.log((room ? '[' + await room.topic() + ']' : '')
+ '<' + from.name() + '>'
+ ':' + msg,
)
if (msg.self()) {
return // skip self
}
/**
* `dong` will be the magic(toggle) word:
* bot will quit current room by herself.
*/
if (/^dong$/i.test(text)) {
if (room) {
await room.say('You said dong in the room, I will quit by myself!', from)
await room.quit()
} else {
await from.say('Nothing to do. If you say "dong" in a room, I will quit from the room.')
}
return
}
/**
* `ding` will be the magic(toggle) word:
* 1. say ding first time, will got a room invitation
* 2. say ding in room, will be removed out
*/
if (/^ding$/i.test(text)) {
/**
* in-room message
*/
if (room) {
if (/^ding/i.test(await room.topic())) {
/**
* move contact out of room
*/
await getOutRoom(from, room)
}
/**
* peer to peer message
*/
} else {
/**
* find room name start with "ding"
*/
try {
const dingRoom = await this.Room.find({ topic: /^ding/i })
if (dingRoom) {
/**
* room found
*/
log.info('Bot', 'onMessage: got dingRoom: "%s"', await dingRoom.topic())
if (await dingRoom.has(from)) {
/**
* speaker is already in room
*/
const topic = await dingRoom.topic()
log.info('Bot', 'onMessage: sender has already in dingRoom')
await dingRoom.say(`I found you have joined in room "${topic}"!`, from)
await from.say(`no need to ding again, because you are already in room: "${topic}"`)
// sendMessage({
// content: 'no need to ding again, because you are already in ding room'
// , to: sender
// })
} else {
/**
* put speaker into room
*/
log.info('Bot', 'onMessage: add sender("%s") to dingRoom("%s")', from.name(), dingRoom.topic())
await from.say('ok, I will put you in ding room!')
await putInRoom(from, dingRoom)
}
} else {
/**
* room not found
*/
log.info('Bot', 'onMessage: dingRoom not found, try to create one')
/**
* create the ding room
*/
const newRoom = await createDingRoom(from)
console.log('createDingRoom id:', newRoom.id)
/**
* listen events from ding room
*/
await manageDingRoom()
}
} catch (e) {
log.error(e)
}
}
}
})
.start()
.catch(e => console.error(e))
async function manageDingRoom() {
log.info('Bot', 'manageDingRoom()')
/**
* Find Room
*/
try {
const room = await bot.Room.find({ topic: /^ding/i })
if (!room) {
log.warn('Bot', 'there is no room topic ding(yet)')
return
}
log.info('Bot', 'start monitor "ding" room join/leave/topic event')
/**
* Event: Join
*/
room.on('join', function(inviteeList, inviter) {
log.verbose('Bot', 'Room EVENT: join - "%s", "%s"',
inviteeList.map(c => c.name()).join(', '),
inviter.name(),
)
console.log('room.on(join) id:', this.id)
checkRoomJoin.call(this, room, inviteeList, inviter)
})
/**
* Event: Leave
*/
room.on('leave', async function(leaverList) {
log.info('Bot', 'EVENT: room-leave - Room "%s" lost member "%s"',
await room.topic(),
const members = await room.memberAll()
if (members.length < 3) {
await room.quit()
}
})
log.info('Bot', 'Room EVENT: leave - "%s" leave(remover "%s"), byebye', leaverList.join(','), remover || 'unknown')
})
/**
* Event: Topic Change
*/
room.on('topic', (topic, oldTopic, changer) => {
log.info('Bot', 'Room EVENT: topic - changed from "%s" to "%s" by member "%s"',
oldTopic,
topic,
changer.name(),
)
})
} catch (e) {
log.warn('Bot', 'Room.find rejected: "%s"', e.stack)
}
}
async function checkRoomJoin(room, inviteeList, inviter) {
log.info('Bot', 'checkRoomJoin("%s", "%s", "%s")',
await room.topic(),
inviteeList.map(c => c.name()).join(','),
inviter.name(),
)
try {
// let to, content
const userSelf = bot.userSelf()
if (inviter.id !== userSelf.id) {
await room.say('RULE1: Invitation is limited to me, the owner only. Please do not invit people without notify me.',
inviter,
)
await room.say('Please contact me: by send "ding" to me, I will re-send you a invitation. Now I will remove you out, sorry.',
inviteeList,
)
await room.topic('ding - warn ' + inviter.name())
setTimeout(
_ => inviteeList.forEach(c => room.del(c)),
10 * 1000,
)
} else {
await room.say('Welcome to my room! :)')
let welcomeTopic
welcomeTopic = inviteeList.map(c => c.name()).join(', ')
await room.topic('ding - welcome ' + welcomeTopic)
}
} catch (e) {
log.error('Bot', 'checkRoomJoin() exception: %s', e.stack)
}
}
async function putInRoom(contact, room) {
log.info('Bot', 'putInRoom("%s", "%s")', contact.name(), await room.topic())
try {
await room.add(contact)
setTimeout(
_ => room.say('Welcome ', contact),
10 * 1000,
)
} catch (e) {
log.error('Bot', 'putInRoom() exception: ' + e.stack)
}
}
async function getOutRoom(contact, room) {
log.info('Bot', 'getOutRoom("%s", "%s")', contact, room)
try {
await room.say('You said "ding" in my room, I will remove you out.')
await room.del(contact)
} catch (e) {
log.error('Bot', 'getOutRoom() exception: ' + e.stack)
}
}
function getHelperContact() {
log.info('Bot', 'getHelperContact()')
// create a new room at least need 3 contacts
return bot.Contact.find({ name: HELPER_CONTACT_NAME })
}
async function createDingRoom(contact) {
log.info('Bot', 'createDingRoom("%s")', contact)
try {
if (!contact.room().has(contact)) {
log.warn('Bot', 'The group has less than 3 members')
await contact.say(`The group has less than 3 members, please add more members before starting the game.`)
return
}
const members = await contact.room().memberAll()
const randomMembers = []
while(randomMembers.length < 2) {
const randomIndex = Math.floor(Math.random() * members.length)
const randomMember = members[randomIndex]
if(randomMember != contact && !randomMembers.includes(randomMember)) {
randomMembers.push(randomMember)
}
}
const contactList = [contact, ...randomMembers]
log.verbose('Bot', 'contactList: "%s"', contactList.join(','))
await contact.say(`Creating a new group with you and ${randomMembers.map(member => member.name()).join(', ')}`)
const room = await bot.Room.create(contactList, 'Coffee Chat')
log.info('Bot', 'createDingRoom() new Coffee Chat room created: "%s"', room)
await room.topic('Coffee Chat - created')
await room.say(`Welcome to the coffee chat group! This group is requested by ${contact.name()}, and your random partners are ${randomMembers.map(member => member.name()).join(', ')}. I hope you guys have a good ice-breaking time!`);
return room
} catch (e) {
log.error('Bot', 'createDingRoom() exception:', e.stack)
throw e
}
}