diff options
Diffstat (limited to 'src/api/bot/interfaces/line.ts')
| -rw-r--r-- | src/api/bot/interfaces/line.ts | 238 |
1 files changed, 0 insertions, 238 deletions
diff --git a/src/api/bot/interfaces/line.ts b/src/api/bot/interfaces/line.ts deleted file mode 100644 index 8036b2fde4..0000000000 --- a/src/api/bot/interfaces/line.ts +++ /dev/null @@ -1,238 +0,0 @@ -import * as EventEmitter from 'events'; -import * as express from 'express'; -import * as request from 'request'; -import * as crypto from 'crypto'; -import User from '../../models/user'; -import config from '../../../conf'; -import BotCore from '../core'; -import _redis from '../../../db/redis'; -import prominence = require('prominence'); -import getAcct from '../../../common/user/get-acct'; -import parseAcct from '../../../common/user/parse-acct'; -import getPostSummary from '../../../common/get-post-summary'; - -const redis = prominence(_redis); - -// SEE: https://developers.line.me/media/messaging-api/messages/sticker_list.pdf -const stickers = [ - '297', - '298', - '299', - '300', - '301', - '302', - '303', - '304', - '305', - '306', - '307' -]; - -class LineBot extends BotCore { - private replyToken: string; - - private reply(messages: any[]) { - request.post({ - url: 'https://api.line.me/v2/bot/message/reply', - headers: { - 'Authorization': `Bearer ${config.line_bot.channel_access_token}` - }, - json: { - replyToken: this.replyToken, - messages: messages - } - }, (err, res, body) => { - if (err) { - console.error(err); - return; - } - }); - } - - public async react(ev: any): Promise<void> { - this.replyToken = ev.replyToken; - - switch (ev.type) { - // メッセージ - case 'message': - switch (ev.message.type) { - // テキスト - case 'text': - const res = await this.q(ev.message.text); - if (res == null) return; - // 返信 - this.reply([{ - type: 'text', - text: res - }]); - break; - - // スタンプ - case 'sticker': - // スタンプで返信 - this.reply([{ - type: 'sticker', - packageId: '4', - stickerId: stickers[Math.floor(Math.random() * stickers.length)] - }]); - break; - } - break; - - // postback - case 'postback': - const data = ev.postback.data; - const cmd = data.split('|')[0]; - const arg = data.split('|')[1]; - switch (cmd) { - case 'showtl': - this.showUserTimelinePostback(arg); - break; - } - break; - } - } - - public static import(data) { - const bot = new LineBot(); - bot._import(data); - return bot; - } - - public async showUserCommand(q: string) { - const user = await require('../../endpoints/users/show')(parseAcct(q.substr(1)), this.user); - - const acct = getAcct(user); - const actions = []; - - actions.push({ - type: 'postback', - label: 'タイムラインを見る', - data: `showtl|${user.id}` - }); - - if (user.account.twitter) { - actions.push({ - type: 'uri', - label: 'Twitterアカウントを見る', - uri: `https://twitter.com/${user.account.twitter.screen_name}` - }); - } - - actions.push({ - type: 'uri', - label: 'Webで見る', - uri: `${config.url}/@${acct}` - }); - - this.reply([{ - type: 'template', - altText: await super.showUserCommand(q), - template: { - type: 'buttons', - thumbnailImageUrl: `${user.avatar_url}?thumbnail&size=1024`, - title: `${user.name} (@${acct})`, - text: user.description || '(no description)', - actions: actions - } - }]); - - return null; - } - - public async showUserTimelinePostback(userId: string) { - const tl = await require('../../endpoints/users/posts')({ - user_id: userId, - limit: 5 - }, this.user); - - const text = `${tl[0].user.name}さんのタイムラインはこちらです:\n\n` + tl - .map(post => getPostSummary(post)) - .join('\n-----\n'); - - this.reply([{ - type: 'text', - text: text - }]); - } -} - -module.exports = async (app: express.Application) => { - if (config.line_bot == null) return; - - const handler = new EventEmitter(); - - handler.on('event', async (ev) => { - - const sourceId = ev.source.userId; - const sessionId = `line-bot-sessions:${sourceId}`; - - const session = await redis.get(sessionId); - let bot: LineBot; - - if (session == null) { - const user = await User.findOne({ - host: null, - 'account.line': { - user_id: sourceId - } - }); - - bot = new LineBot(user); - - bot.on('signin', user => { - User.update(user._id, { - $set: { - 'account.line': { - user_id: sourceId - } - } - }); - }); - - bot.on('signout', user => { - User.update(user._id, { - $set: { - 'account.line': { - user_id: null - } - } - }); - }); - - redis.set(sessionId, JSON.stringify(bot.export())); - } else { - bot = LineBot.import(JSON.parse(session)); - } - - bot.on('updated', () => { - redis.set(sessionId, JSON.stringify(bot.export())); - }); - - if (session != null) bot.refreshUser(); - - bot.react(ev); - }); - - app.post('/hooks/line', (req, res, next) => { - // req.headers['x-line-signature'] は常に string ですが、型定義の都合上 - // string | string[] になっているので string を明示しています - const sig1 = req.headers['x-line-signature'] as string; - - const hash = crypto.createHmac('SHA256', config.line_bot.channel_secret) - .update((req as any).rawBody); - - const sig2 = hash.digest('base64'); - - // シグネチャ比較 - if (sig1 === sig2) { - req.body.events.forEach(ev => { - handler.emit('event', ev); - }); - - res.sendStatus(200); - } else { - res.sendStatus(400); - } - }); -}; |