2018-07-15 16:51:36 +00:00
|
|
|
const WebSocket = require('ws')
|
|
|
|
const config = require('@config/index')
|
|
|
|
const DB = require('@libs/database')
|
|
|
|
const {
|
|
|
|
msgSplit
|
|
|
|
} = require('./parser')
|
2018-07-18 16:40:07 +00:00
|
|
|
const event = require('@root/event')
|
2018-07-20 16:46:01 +00:00
|
|
|
// const _ = require('lodash')
|
2018-07-15 16:51:36 +00:00
|
|
|
|
|
|
|
class WS {
|
|
|
|
constructor () {
|
|
|
|
/** @type {WebSocket} */
|
|
|
|
this.ws = null
|
2018-07-20 16:46:01 +00:00
|
|
|
// cache struct
|
|
|
|
// cache = {
|
|
|
|
// [channel]: {
|
|
|
|
// time: timestamp,
|
|
|
|
// list: []
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
this.cache = {}
|
|
|
|
this.tick = null
|
2018-07-16 08:51:31 +00:00
|
|
|
this.join = []
|
2018-07-20 16:46:01 +00:00
|
|
|
this.tick = setInterval(this.runTick.bind(this), 1000)
|
2018-07-18 16:40:07 +00:00
|
|
|
event.on('twitchJoin', (channel) => {
|
|
|
|
this.joinChannel(channel)
|
|
|
|
})
|
|
|
|
event.on('twitchSend', data => {
|
2018-07-20 16:46:01 +00:00
|
|
|
if (!('msg' in data) || typeof data.msg !== 'string') return
|
|
|
|
if (!('channel' in data) || typeof data.channel !== 'string') return
|
|
|
|
this.queueMsg(data.channel, data.msg)
|
2018-07-18 16:40:07 +00:00
|
|
|
})
|
2018-07-15 16:51:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
runBot () {
|
|
|
|
if (!config.twitch.chat_host || !config.twitch.bot_oauth) return
|
|
|
|
if (this.ws !== null) return
|
|
|
|
this.ws = new WebSocket(`wss://${config.twitch.chat_host}:443`, 'irc')
|
|
|
|
|
|
|
|
this.ws.on('open', this.handleOpen.bind(this))
|
|
|
|
|
|
|
|
this.ws.on('message', this.handleMessage.bind(this))
|
|
|
|
|
|
|
|
this.ws.on('error', this.handleError.bind(this))
|
|
|
|
|
|
|
|
this.ws.on('close', this.handleExit.bind(this))
|
|
|
|
}
|
|
|
|
|
|
|
|
handleError (err) {
|
|
|
|
console.log(err)
|
|
|
|
this.ws = null
|
|
|
|
this.runBot()
|
|
|
|
}
|
|
|
|
handleExit (code) {
|
|
|
|
this.ws = null
|
|
|
|
this.runBot()
|
|
|
|
}
|
|
|
|
handleMessage (data) {
|
|
|
|
// socket message convert to string
|
|
|
|
let d = data.toString()
|
|
|
|
// split message with \n
|
|
|
|
// filter array remove empty element
|
|
|
|
// replace \r to empty
|
|
|
|
let darr = d.split(/\n/).filter(t => t).map(t => t.replace(/\r$/, ''))
|
|
|
|
|
|
|
|
for (let i in darr) {
|
|
|
|
// parse message
|
2018-07-25 14:20:59 +00:00
|
|
|
console.log('IRC::: > ', darr[i])
|
2018-07-15 16:51:36 +00:00
|
|
|
msgSplit(this.ws, darr[i]).then(() => { /* pass */ })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
async handleOpen () {
|
|
|
|
// from pool get db connection
|
|
|
|
let db = await DB.connect()
|
|
|
|
|
|
|
|
// login to twitch irc
|
|
|
|
this.ws.send('PASS ' + config.twitch.bot_oauth)
|
|
|
|
this.ws.send('NICK mtfosbot')
|
|
|
|
this.ws.send('CAP REQ :twitch.tv/membership :twitch.tv/commands')
|
|
|
|
|
|
|
|
// 取得要加入的頻道列表
|
2018-07-20 16:46:01 +00:00
|
|
|
let text = `select "name" from "public"."twitch_channel" where "join" = true`
|
2018-07-15 16:51:36 +00:00
|
|
|
let result = await db.query({
|
|
|
|
text
|
|
|
|
})
|
|
|
|
|
|
|
|
// release pool connection
|
2018-07-16 02:47:43 +00:00
|
|
|
await db.release()
|
2018-07-15 16:51:36 +00:00
|
|
|
|
|
|
|
if (result !== null && result.rowCount > 0) {
|
|
|
|
for (let row of result.rows) {
|
|
|
|
if ('name' in row) {
|
2018-07-25 14:20:59 +00:00
|
|
|
this.joinChannel(row.name)
|
|
|
|
// this.ws.send('JOIN #' + row.name)
|
|
|
|
// this.join.push(row.name)
|
2018-07-15 16:51:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-20 16:46:01 +00:00
|
|
|
queueMsg (channel, msg) {
|
|
|
|
if (typeof channel !== 'string' || channel.trim().length === 0) return
|
|
|
|
if (typeof msg !== 'string' || msg.trim().length === 0) return
|
|
|
|
if (channel in this.cache) {
|
|
|
|
if ('list' in this.cache[channel]) {
|
|
|
|
this.cache[channel].list = [...this.cache[channel].list, msg]
|
|
|
|
} else {
|
|
|
|
this.cache[channel].list = [msg]
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
this.cache[channel] = {
|
|
|
|
time: -1,
|
|
|
|
list: [msg]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
runTick () {
|
|
|
|
if (this.cache === null || typeof this.cache !== 'object') return
|
|
|
|
let time = Date.now()
|
|
|
|
for (let i in this.cache) {
|
|
|
|
if ('time' in this.cache[i] && this.cache[i].time <= (time - 1500)) {
|
|
|
|
if ('list' in this.cache[i] && Array.isArray(this.cache[i].list) && this.cache[i].list.length > 0) {
|
|
|
|
let msg = this.cache[i].list[0]
|
|
|
|
this.cache[i].list = [...this.cache[i].list.slice(1)]
|
|
|
|
this.sendMsg(i, msg)
|
|
|
|
}
|
|
|
|
this.cache[i].time = time
|
|
|
|
} else {
|
|
|
|
if ('list' in this.cache[i] && Array.isArray(this.cache[i].list) && this.cache[i].list.length > 0) {
|
|
|
|
let msg = this.cache[i].list[0]
|
|
|
|
this.cache[i].list = [...this.cache[i].list.slice(1)]
|
|
|
|
this.sendMsg(i, msg)
|
|
|
|
}
|
|
|
|
this.cache[i].time = time
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-16 08:51:31 +00:00
|
|
|
sendMsg (channel = null, message = null) {
|
|
|
|
if (this.ws === null || !('send' in this.ws) || typeof this.ws.send !== 'function') return null
|
|
|
|
if (channel === null || typeof channel !== 'string' || channel.trim().length === 0) return null
|
|
|
|
if (message === null || typeof message !== 'string' || message.trim().length === 0) return null
|
|
|
|
if (this.join.indexOf(channel) === -1) return null
|
2018-07-25 14:20:59 +00:00
|
|
|
console.log(`IRC::: < ${`PRIVMSG #${channel} :${message}`}`)
|
2018-07-16 08:51:31 +00:00
|
|
|
this.ws.send(`PRIVMSG #${channel} :${message}`)
|
|
|
|
}
|
|
|
|
|
2018-07-15 16:51:36 +00:00
|
|
|
joinChannel (channel = null) {
|
2018-07-16 08:51:31 +00:00
|
|
|
if (this.ws === null || !('send' in this.ws) || typeof this.ws.send !== 'function') return null
|
2018-07-15 16:51:36 +00:00
|
|
|
if (channel === null || typeof channel !== 'string' || channel.trim().length === 0) return null
|
2018-07-18 16:40:07 +00:00
|
|
|
if (this.join.indexOf(channel) !== -1) return null
|
2018-07-25 14:20:59 +00:00
|
|
|
console.log(`IRC::: < ${`JOIN #${channel.trim()}`}`)
|
2018-07-15 16:51:36 +00:00
|
|
|
this.ws.send(`JOIN #${channel.trim()}`)
|
2018-07-16 08:51:31 +00:00
|
|
|
this.join.push(channel.trim())
|
2018-07-15 16:51:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = new WS()
|