Files

430 lines
12 KiB
JavaScript

#!/usr/bin/env node
/**
* Wechaty - https://github.com/chatie/wechaty
*
* @copyright 2016-2018 Huan LI <zixia@zixia.net>
*
* 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', (leaverList, remover) => {
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 {
const helperContact = await getHelperContact()
if (!helperContact) {
log.warn('Bot', 'getHelperContact() found nobody')
await contact.say(`You don't have a friend called "${HELPER_CONTACT_NAME}",
because create a new room at least need 3 contacts, please set [HELPER_CONTACT_NAME] in the code first!`)
return
}
log.info('Bot', 'getHelperContact() ok. got: "%s"', helperContact.name())
const contactList = [contact, helperContact]
log.verbose('Bot', 'contactList: "%s"', contactList.join(','))
await contact.say(`There isn't ding room. I'm trying to create a room with "${helperContact.name()}" and you`)
const room = await bot.Room.create(contactList, 'ding')
log.info('Bot', 'createDingRoom() new ding room created: "%s"', room)
await room.topic('ding - created')
await room.say('ding - created')
return room
} catch (e) {
log.error('Bot', 'getHelperContact() exception:', e.stack)
throw e
}
}