この記事は GLOBIS Advent Calendar 2019 - Qiita の18日目です。
こんにちは、グロービスでエンジニアをしている @shifumin です。
皆さん、Lineを使っていますか? 僕は通知オフで使っています。理由は通知で集中力が切れるのが嫌だからです。
しかし、通知オフ設定だと送られたメッセージに長時間気づかずに怒られイベントがたまに発生しますよね? 僕はたびたび発生しています。
皆さん、Slackを使っていますか?使っていますよね。凝視していますよね。
Slackなら常に見ているから見逃さないんだけどなあ。
というわけで、多少矛盾を孕んでいますが、通知オフにしたLineで送られたメッセージをSlackに通知させるためのbotを作っていきたいと思います!
概要を3行で
- 通知させたいLineグループにLine botをjoinさせてLine Messaging APIでメッセージを取得する
- 上記で取得したメッセージをSlack botとしてSlackに通知する
- botはRailsに乗せてHerokuで動かす
はい、やっていきましょう。
Line Messaging APIを利用する準備
Lineの送られてきたメッセージを取得するのに LINE Messaging API を利用します。
LINE Developersコンソールでチャンネルの作成とbotの設定を行います。
設定方法は公式のドキュメントが詳しいので、 Messaging APIを利用するには と ボットを作成する を参考にするのが楽です。
botの作成まで終えた後に各種設定を変更します。
- グループ・複数人チャットへの参加を許可する
- オン
- あいさつメッセージ(Greeting messages)
- オフ
- 応答メッセージ(Auto-reply messages)
- オフ
- Webhook
- オン
Webhook設定はURLももちろん設定する必要があるのですが、これは後でHerokuでappを作成後に設定します。
設定後は下記の2つの値が必要になるため、メモります。
発行されていなければ、それぞれ Issue
, Reissue
から発行できると思います。
- Channel secret (Basic settingsの中)
- Channel access token (Messaging APi settingsの中)
です。
botとフレンドになる
MessagingAPi > QR code にQRコードが表示されているのでbotをフレンド登録します。
また、複数人でのグループチャットを通知させたい場合はグループに招待します。
Slackの設定
続いて、SlackのApp設定とbot追加を行います。
https://api.slack.com/apps の Create New App
からAppを作成します
まず、Appの名前と導入するWorkspaceを入力します。
その後Appの設定をいくつか行う必要があります。
Botの作成
- Botsから
Add a Bot User
をクリックしてbotを作成する
Permissionsの設定
- PermissionsをクリックしOAuth & Permissions画面へ移動する
- OAuth Tokens & Redirect URLs >
Install App to Workspace
をクリックしてAppをインストールする - Scopesで下記のScopeを追加する
- chat:write:bot
- chat:write:user
- files:write:user
また、下記の値が必要になるため、メモります。
- OAuth Access Token (OAuth & Permissions画面)
Railsアプリ作成
ここからようやくBotの実装に進めていきます。
rails new
rails newまではよしなにやってください。
とりあえず最速でrails new。
# Railsをインストールまで
bundle init
vim Gemfile # Gemfileの `# gem "rails"` 行のコメントアウトを外す
bundle install
rails new
は今回は画面描画系がいらないのでAPIモードかつ必要ないものを全てスキップしています。
参考: 小さく薄くrails newする(ViewやJSが必要ない場合) - Qiita
bundle exec rails new . --skip-yarn --skip-git --skip-action-mailer --skip-action-mailbox --skip-action-text --skip-active-record --skip-active-storage --skip-action-cable --skip-sprockets --skip-javascript --skip-turbolinks --skip-test --api --skip-bundle
SDKのインストール
Line、Slackそれぞれ公式が出しているSDKのgemを使います。
line-bot-api と slack-ruby-client です。
この2つをGemfileに追加して bundle install
します。
# Gemfile
# add
gem 'line-bot-api'
gem 'slack-ruby-client'
bundle install
コード実装
各SDKの設定
Slackは configure
で設定できたので config/initializers/
以下に設定を用意し、 Line::bot::Client
はできなかったので仕方なくApplicationControllerでクライアントを作成する際に設定するようにしました。
# config/initializers/slack_ruby_client.rb
require 'slack'
Slack.configure do |config|
config.token = ENV['SLACK_API_TOKEN']
end
Slack::Web::Client.configure do |config|
config.user_agent = 'Slack Ruby Client/1.0'
end
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
private
def line_client
@line_client ||= Line::Bot::Client.new do |config|
config.channel_secret = ENV["LINE_CHANNEL_SECRET"]
config.channel_token = ENV["LINE_CHANNEL_TOKEN"]
end
end
def slack_client
@slack_client ||= Slack::Web::Client.new
end
end
routes
Webhookはpostでリクエストが来るので、 /callback
で受けて WebhookController#callbackに渡すようにしました。
# config/routes.rb
Rails.application.routes.draw do
post '/callback' => 'webhook#callback'
end
Blocked Hostの設定
Rails6から導入されたBlocked hostの設定は良しなにやってください。
今回はHerokuでdevelopment
で動かすかつ何も考えずに全開放ということで
下記のようにしています。
Rails6でrails newするのは今回が初めてでWebhookが届かないなあと記事を書くにあたりここでめっちゃ嵌った。嵌りポイント1
# config/environments/development.rb
Rails.application.configure do
# 略
config.hosts.clear
end
controller
line-bot-api と slack-ruby-client のREADMEとサンプル実装を見ながらbotの本実装である WebhookController#callback
を書いていきます。 今回は
- メッセージが送られた場合はそのメッセージをそのままSlackに送る
- 写真が送られてきた場合はその写真を保存して(Herokuなのでそのうち消えるけど)、Slackにアップロードする
- ビデオ、スタンプの場合はそれぞれが送られてきた旨のメッセージを送る
ようにしました。
# app/controllers/webhook_controller.rb
class WebhookController < ApplicationController
CHANNEL = '#{botに通知させるチャンネル名: 例: #hoge}'
def callback
body = request.body.read
signature = request.env['HTTP_X_LINE_SIGNATURE']
unless line_client.validate_signature(body, signature)
error 400, 'Bad Request'
end
events = line_client.parse_events_from(body)
events.each do |event|
case event
when Line::Bot::Event::Message
case event.type
when Line::Bot::Event::MessageType::Text
post_message(event.message['text'])
when Line::Bot::Event::MessageType::Image
image_response = line_client.get_message_content(event.message['id'])
file = File.open("/tmp/#{Time.current.strftime('%Y%m%d%H%M%S')}.jpg", 'w+b')
file.write(image_response.body)
slack_client.files_upload(channels: CHANNEL,
file: Faraday::UploadIO.new(file.path, 'image/jpeg'),
as_user: true,
title: File.basename(file.path),
filename: File.basename(file.path),
initial_comment: '写真が送信されました')
when Line::Bot::Event::MessageType::Video
post_message('ビデオが送信されました。')
when Line::Bot::Event::MessageType::Sticker
post_message('スタンプが送信されました。')
end
end
end
head :ok
end
private
def post_message(text)
slack_client.chat_postMessage(channel: CHANNEL, text: text)
end
end
Herokuのデプロイと設定
あとはHerokuでアプリを作成してデプロイして設定したら完了です。
アプリを作成してデプロイする方法はそこら辺に転がっているので割愛します。
環境変数の設定
上の方でメモっておいた下記の環境変数を設定します。
- LINE_CHANNEL_SECRET
- Lineの
Channel secret
- Lineの
- LINE_CHANNEL_TOKEN
- Lineの
Channel access token
- Lineの
- SLACK_API_TOKEN
- Slackの
OAuth Access Token
- Slackの
Dynoの起動
Dynoも忘れずに起動させます。
Herokuを触るのが久しぶりで起動を忘れていて、動いていないHerokuに対してWebhookを大量に空振りさせていた。嵌りポイント2
Webhook URLの設定
最後にWebhook URLを設定したら完了です。
Settngs > Domains のURLを
Line DevelopersコンソールのMessaging API > Webhook settingsのURLに設定します。
エンドポイントは /callback
としているので忘れないようにします。
実際の動作
グループにbotを招待してLineからメッセージを送ると下記のようにSlackに通知されます。
(左: Line, 右: Slack)
また、Lineの通知をオフにしていても下記のような重要なメッセージを見逃すことが減ります
(なぜならSlackは見ているので)
終わりに
今回はLineのやり取りをSlackに通知するbotを作ってみました。
公式で用意されているIntegration等でSlackとLineを直接繋ぐことはできないですが、それぞれのアプリがAPIとそのSDKを用意してくれているので、少しコードを書けばこの記事のようにそれぞれのアプリを連携させることができます。
個人開発といえばアプリ作成をまず思い浮かべるかと思いますが、APIを利用したbot開発や便利スクリプト作成も手間の割に日々の生活が便利になったりするのでオススメです!!