diff --git a/background.js b/background.js index 1c3db37..1413a1c 100644 --- a/background.js +++ b/background.js @@ -2,6 +2,8 @@ const cron = require('cron') const DB = require('./libs/database') const fbParser = require('./libs/facebook-pageparse') const api = require('./libs/api-action') +const event = require('./event') +const axios = require('axios') new cron.CronJob({ // eslint-disable-line cronTime: '00 */2 * * * *', @@ -204,7 +206,7 @@ new cron.CronJob({ //eslint-disable-line let db = await DB.connect() try { - let time = Date.now() + (4 * 1000 * 60 * 60) + let time = Math.floor((Date.now() + (4 * 1000 * 60 * 60)) / 1000) let text = `select "id", "name", "lastvideo", "expire" from "public"."youtube_channel" where "expire" = -1 or "expire" < $1` let values = [time] let result = await db.query({ @@ -231,3 +233,68 @@ const regYoutubeWebhook = async (yt = null) => { console.log(err) } } + +// check donate +new cron.CronJob({ //eslint-disable-line + cronTime: '*/5 * * * * *', + onTick: async () => { + let db = await DB.connect() + + try { + let text = `select "name", "id", "opayid" from "public"."twitch_channel" where "opayid" != '' and "join" = true` + let result = await db.query({ text }) + if (result.rowCount > 0) { + result.rows.forEach(t => { + checkDonate(t.name, t.opayid).then(() => {}).catch(() => {}) + }) + } + } catch (err) { + console.log(err) + } + + db.release() + }, + runOnInit: true, + start: true, + timeZone: 'Asia/Taipei' +}) + +const checkDonate = async (loginName = null, opayid = null) => { + if (typeof loginName !== 'string' || loginName.trim().length === 0) return null + if (typeof opayid !== 'string' || opayid.trim().length === 0) return null + let url = `https://payment.opay.tw/Broadcaster/CheckDonate/${opayid}` + let db = await DB.connect() + + // donate response format + // { + // "donateid": "10821396", + // "name": "XXX", + // "amount": 100, + // "msg": "這是一筆贊助測試~" + // } + + try { + let result = await axios({ + url, + method: 'post' + }) + if ('data' in result && Array.isArray(result.data) && result.data.length > 0) { + let ids = result.data.map(t => t.donateid) + let dbres = await db.query({ + text: `select * from "public"."donate_list" where "donate_id" in ($1)`, + values: [ids] + }) + let list = result.data.filter(t => { + for (let i of dbres.rows) { + if (i.donate_id === t.donateid) return false + } + return true + }) + + } + } catch (err) { + console.log(err) + } + + db.release() +} diff --git a/bin/dbVersion.json b/bin/dbVersion.json index 0b320b2..3a2ad2d 100644 --- a/bin/dbVersion.json +++ b/bin/dbVersion.json @@ -9,7 +9,8 @@ {"file": "20180711-1.sql", "version": 7}, {"file": "20180712-1.sql", "version": 8}, {"file": "20180716-1.sql", "version": 9}, - {"file": "20180718-1.sql", "version": 10} + {"file": "20180718-1.sql", "version": 10}, + {"file": "20180719-1.sql", "version": 11} ], "test": [] } \ No newline at end of file diff --git a/config/index.js b/config/index.js index d67cff6..4a51cc2 100644 --- a/config/index.js +++ b/config/index.js @@ -21,5 +21,9 @@ module.exports = { user: process.env.DB_USER || 'postgres', pass: process.env.DB_PASS || '', dbname: process.env.DB_NAME || 'mtfosbot' + }, + redis: { + host: process.env.REDIS_HOST || 'localhost', + port: process.env.REDIS_PORT || 6379 } } diff --git a/event.js b/event.js new file mode 100644 index 0000000..36cd5bb --- /dev/null +++ b/event.js @@ -0,0 +1,6 @@ +const EventEmitter = require('events') + +class EventCls extends EventEmitter { +} + +module.exports = new EventCls() diff --git a/index.js b/index.js index 7210190..7e02b8d 100644 --- a/index.js +++ b/index.js @@ -7,3 +7,6 @@ try { } catch (err) {} require('./app') require('./background') +require('./event') +const twitchChat = require('./libs/twitch-bot') +twitchChat.runBot() diff --git a/jsconfig.json b/jsconfig.json index c2ae2a2..1743bc8 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -5,7 +5,8 @@ "paths": { "@libs/*": ["libs/*"], "@config/*": ["config/*"], - "@route/*": ["route/*"] + "@route/*": ["route/*"], + "@root/*": ["./*"] } } } \ No newline at end of file diff --git a/libs/redis.js b/libs/redis.js new file mode 100644 index 0000000..dfad1b4 --- /dev/null +++ b/libs/redis.js @@ -0,0 +1,91 @@ +const Redis = require('ioredis') +const config = require('@config/index') + +class RedisStore { + constructor () { + this._redis = new Redis(config.redis.port, config.redis.host) + this._expires = 86400 // day (sec) + } + + /** + * set data to redis + * @param {string} key + * @param {string|object} data string or json + * @param {number} expires default 1 day + */ + set (key, data = null, expires = null) { + if (!key || typeof key !== 'string') return + if (key.trim().length === 0) return + if (typeof data === 'object') { + try { + data = JSON.stringify(data) + } catch (err) {} + } + + if (expires === null || !isFinite(expires)) expires = this._expires + + let args = [`${key}`, data] + if (expires > 0) args.push('EX', expires) + + this._redis.set(...args) + } + + /** + * get data from redis + * @param {string} key + * @param {boolean=} toJSON parse data to json (default true) + */ + async get (key, toJSON = true) { + if (!key || typeof key !== 'string') return null + if (key.trim().length === 0) return null + let self = this + let data = null + try { + data = await self._redis.get(`${key}`) + } catch (err) { + return null + } + if (toJSON === true) { + try { + data = JSON.parse(data) + } catch (err) { + return null + } + } + return data + } + + /** + * delete data + * @param {string} key + */ + del (key) { + if (!key || typeof key !== 'string') return null + if (key.trim().length === 0) return null + this._redis.del(`${key}`) + } + + /** + * show all this project namespace data + */ + async show () { + // return this._store + let self = this + let json = {} + let keys = await this._redis.keys(`*`) + for (let i in keys) { + try { + let data = await this._redis.get(keys[i]) + let j = JSON.parse(data) + let k = keys[i].replace(self._namespace, '') + json[k] = j + } catch (err) { + continue + } + } + + return json + } +} + +module.exports = new RedisStore() diff --git a/libs/twitch-bot/index.js b/libs/twitch-bot/index.js index 7b4ea69..f94fa33 100644 --- a/libs/twitch-bot/index.js +++ b/libs/twitch-bot/index.js @@ -4,12 +4,19 @@ const DB = require('@libs/database') const { msgSplit } = require('./parser') +const event = require('@root/event') class WS { constructor () { /** @type {WebSocket} */ this.ws = null this.join = [] + event.on('twitchJoin', (channel) => { + this.joinChannel(channel) + }) + event.on('twitchSend', data => { + this.sendMsg(data.channel, data.message) + }) } runBot () { @@ -89,6 +96,7 @@ class WS { joinChannel (channel = 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 (this.join.indexOf(channel) !== -1) return null this.ws.send(`JOIN #${channel.trim()}`) this.join.push(channel.trim()) } diff --git a/package.json b/package.json index 7b4450a..a8d7ca0 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "cron": "^1.3.0", "dotenv": "^6.0.0", "gm": "^1.23.1", + "ioredis": "^3.2.2", "koa": "^2.5.1", "koa-body": "^4.0.3", "koa-logger": "^3.2.0", @@ -35,6 +36,7 @@ "_moduleAliases": { "@libs": "libs", "@config": "config", - "@route": "route" + "@route": "route", + "@root": "." } } diff --git a/schema/20180718-1.sql b/schema/20180718-1.sql new file mode 100644 index 0000000..b83770b --- /dev/null +++ b/schema/20180718-1.sql @@ -0,0 +1 @@ +ALTER TABLE public.youtube_channel ALTER COLUMN expire TYPE bigint USING expire::bigint; \ No newline at end of file diff --git a/schema/20180719-1.sql b/schema/20180719-1.sql new file mode 100644 index 0000000..74cb0c6 --- /dev/null +++ b/schema/20180719-1.sql @@ -0,0 +1,16 @@ +create extension "uuid-ossp" with schema public; + +-- auto-generated definition +create table public.donate_list +( + id uuid default public.uuid_generate_v4() not null + constraint donate_list_pkey + primary key, + opayid varchar(200) not null, + donate_id varchar(200) not null, + price integer default 0 not null, + text varchar(1000) default '' :: character varying not null, + ctime timestamp with time zone default CURRENT_TIMESTAMP not null, + name varchar(100) default '' :: character varying not null +); +