LambdaでChatWorkのメッセージをslackに流してみました

AmazonLambda

ベルリンの半瀬です。
こんにちは。

はじめに

ベルリンチームは主にSlackでやり取りをしていますが、国内ではChatWorkが主なので、そちらの動きも追う必要があります。
行ったり来たりするのは不便なので、一部の部屋の投稿だけSlackに流す方法を探していました。
下記のZapierを使った方法などはすぐに設定ができて楽そうでした。

ChatWork→Slack連携: ChatWorkの新着通知をSlackに投稿する | atskimura-memo

ZapierのFreeプランではZap回数に制限があったりするので、流量の多い部屋だとすぐに上限に到達してしまうことや、 もう少しリアルタイム性が欲しいなーということで、試しにlambdaとcloudwatch eventで自動転記をしてみました。
(スクリプトは↑の参考URLを見本とさせていただきました(__m謝

pythonスクリプト

2.7で書きます。こんな感じ

#-*- coding: utf-8 -*-
from __future__ import print_function

import requests
from datetime import datetime

cwtoken = '787dxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
sltoken = 'xoxp-4xxxxxxxxxxx-50xxxxxxxxxxxx-2xxxxxxxxxxxxxx-d65dxxxxxxxxxxxxxxxxxxxxxxxx'

cwapiurl = 'https://api.chatwork.com/v2'
slapiurl = 'https://slack.com/api'

def lambda_handler(event, context):
  fromto = event['fromto']

  for list in fromto:
    roomid  = list['cwroomid']
    channel = list['slchannel']
    
    url1     = cwapiurl + '/rooms/' + roomid + '/messages'
    headers1 = {'X-ChatWorkToken': cwtoken }
    
    try : 
       req1 = requests.get(url1, headers=headers1)
       if req1.status_code == 204 :
          print('204' )
       else : 
          res_json=req1.json()
          i = 0
          l = len(res_json) - 1
          while i <= l : 
             body = res_json[i]['body']
             name = res_json[i]['account']['name']
             msid = res_json[i]['message_id']
             time = res_json[i]['send_time']

             try :
                text = '*' + str(datetime.fromtimestamp(time)) + ' message from: ' + name + '*\n```' + body + '```'
                url2    = slapiurl + '/chat.postMessage'
                params2 = {
                   'token' : sltoken,
                   'channel' : channel,
                   'text' : text,
                   'as_user': 'false',
                   'username': 'ChatWork(auto)'
                }
                req2 = requests.put(url2, params=params2)

             except Exception as e :
                print('[error][put]' + str(e))

             i += 1

    except Exception as e :
       print('[error][get]' + str(e))

if __name__ == "__main__":
    lambda_handler({}, {})

このスクリプトはchatwork api のトークンとslack apiのトークンが前提になっています。 chatworkはここを参考に、slackはここからそれぞれ取得しておきましょう。slack のpermission scopeは「chat:write:bot」が必要です。

注意: できないこと - slackからChatworkへの転記はできません。

スクリプトの使い方

トークンと部屋情報の記載

cwtokenにChatworkのトークンを、sltokenにSLackのトークンを入れます。

次に、転機元のChatwork部屋と転記先のslackチャンネルの情報が必要となりますが、fromto = event['fromto']の様な形としておき、これはcloudwatchからJSONリスト形式で渡す様にします(後述)。

Lambda

AWS Lambdaに載せます。requestsモジュールを使っていますので、パッケージ化をしてからアップロードしましょう。

CloudWatch Eventsの設定(転送元と先の指定)

Cloudwatch 「ルール」からアップロードしたlambda関数を指定して、1分間隔での実行を指定します。
その際、「入力の設定」から「定数(JSONテキスト)」を選択し、以下を参考にJSONテキストを渡す様に指定します。

AWS CloudWach Events実行時に便利なConfigure input | Developers.IO

{
	"fromto": [{
		"cwroomid": "<ChatWorkルームのID>",
		"slchannel": "<SlackチャンネルのID>"
	}, {
		"cwroomid": "< 〃 >",
		"slchannel": "< 〃 >"
	}, {
		"cwroomid": "< 〃 >",
		"slchannel": "< 〃 >"
	}]
}

cwroomidに、ルームID( 例:「https://kcw.kddi.ne.jp/#!rid{{ここの数字}}」)
slchannelにチャンネル名(例: #test1だと、「test1」)
複数ある場合は、リスト形式で追記します。「,」を忘れずに。
以下の様な形で設定します。
20170703-00

テスト

Chatworkに投稿
20170703-01

1分以内にSlackで表示。もちろん絵文字は反映されません。
20170703-02

終わりに

以上です。

APIの制限周りを考慮しきれていません。Chatwork APIは「5分に100回まで」という制限があるので、APIを実行するユーザーで他にAPI実行していないかどうか、気をつけてください。分間実行でもChatwork側で20部屋くらいを指定すると上限に当たる気がします。
多分そこまで使わないはず。。はず。。

参考にしたもの

Methid chat.postMessage | Slack API
Rate Limits | Slack API
エンドポイント: /rooms | ChatWork API ドキュメント
エンドポイント: APIの利用回数制限について | ChatWork API ドキュメント

それではー