42
43

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

HubotでRocket.Chat用Botを作る

Last updated at Posted at 2017-06-01

Rocket.Chat用のHubot作成手順です。

2018/06/14追記
https://rocket.chat/docs/bots/ にはbotkitなどの記載もありますが、現在は開発中で未リリースです。
また、hubotも https://rocket.chat/docs/bots/running-a-hubot-bot/ にはボイラープレートからの作成なども記載されていますが、これも開発中です。
bot系は開発フレームワークなども含め、強化検討されているようです。 slack の Interactive messages のような機能も検討されています。

2018/07/26追記

  • hubot-rocketchat v1.0.12 に気づいたので追記。
  • hubot-rocketchat v1.0.9 からenvelope, message, userのroomの値がIDから名称に変更されたのに気づいたので追記。
  • yo hubot すると、hubot-rocketchat v2.0.0 が入ってしまう問題に気付いたので追記。

2018/10/15追記
ボイラープレートを使用するv3系については、ボイラープレートは未だ NB: THIS IS A WORK IN PROGRESS だし、アダプタもv2系リリースタグ無し(なぜかnpmにはv2が上がっている)。またアダプタ内で使用されている @rocket.chat/sdk のバージョンが古い(v0.1.0)などにより、 still beta と判断。

  • yo hubot すると、hubot v3.1.1 が入ってしまう問題に気付いたので追記。

2018/12/14追記
一昨日くらいにSnapでRocket.Chat 0.72.1 が降ってきたタイミングで、botが一部反応しなくなった。
ROCKETCHAT_ROOM でroomを指定していると反応しない。hear, respondなどの応答系が全滅。。
LISTEN_ON_ALL_PUBLIC=true 付けると反応する。が、、全roomで反応。
1つ前のバージョンの Rocket.Chat 0.71.2 を立てて正常に動作することを確認。
rocketchat_driver.coffee 内の setupReactiveMessageList メソッド内の changedMsg.args[1] が {} になっている所まで確認。
試しにhubot 3系で動作確認したが、同様に動作しない。
このissueか?

2018/12/16追記
SnapでRocket.Chat 0.72.3 が降ってきて、正常に戻った。
changedMsg.args[1] に値が入ってくるように戻っていた。

対象

Rocket.Chat : 0.55.0 くらいで動作確認。
node : 6.10.x
開発言語 : JavaScript(≠CoffeeScript)

Hubotの開発環境作成

node, npmをインストールします。
その後、Hubot開発に必要な yo , generator-hubot をインストールします。
参考:https://hubot.github.com/docs/

# 未インストール時のみ
npm install -g yo generator-hubot

Hubot作成

雛型生成

yoで雛型生成します。

mkdir myhubot
cd myhubot
yo hubot
# 対話式で色々聞かれるが、adapterに rocketchat を指定すればとりあえずはOK
# hubot-rocketchatも一緒にインストールされる

# ******** 2018/10/15追記 ********
# yoがv3.1.1を入れてしまうので、ダウングレードする。
npm install hubot@2.19.0

# ******** 2018/07/26追記 ********
# yoがv2.0.0を入れてしまうので、ダウングレードする。
npm install hubot-rocketchat@1.0.12

2017/09/07 現在、ここでインストールされるhubotはnpmに登録されているv2.19.0です。
githubのv3.0.1を使用すると、正常に動作しないようです。

2018/10/15 現在、ここでインストールされるhubotはnpmに登録されているv3.1.1です。
v2系にダウングレードする必要があります。

hubot-rocketchat は Rocket.Chat用のHubot adapter で https://github.com/RocketChat/hubot-rocketchat で開発されています。
2018/05/01 v2.0.0 リリース ※don't use this!! yoでの生成とhubot v2が非サポートになったので使ってはいけない。
2017/10/10 v1.0.12 リリース ※githubでタグ打ちされていないバージョン。 npm に登録されていた。
2017/08/08 v1.0.11 リリース
2017/07/26 v1.0.10 リリース
2017/07/14 v1.0.9 リリース ※破壊的変更あり

とりあえず動作確認

環境変数を設定し、Hubotを起動します。

# 環境変数設定
export ROCKETCHAT_URL=http://192.168.0.123:3000
export ROCKETCHAT_ROOM=general
export ROCKETCHAT_USER=chabot # botのユーザー
export ROCKETCHAT_PASSWORD=chabotpassword # botのパスワード
export ROCKETCHAT_AUTH=password

# adapterにrocketchatを指定して起動
bin/hubot -a rocketchat

以下を確認。

  • Rocket.Chat の general にボットユーザーが参加されていることを確認。
  • chabot ping と打ち、PONG と帰ってくることを確認。

Ctrl+Cで終了。
ここまでで、基本的な枠の作成は完了です。

不要なパッケージ削除

yoで生成した雛型には不要なパッケージが色々入っているので削除します。
私はデータ保持にはredisは使わず、代わりにnedbをよく使用している為、以下ではhubot-redis-brainも消してます。

# 全無まとめて削除Ver.
npm uninstall hubot-diagnostics hubot-google-images hubot-google-translate hubot-help hubot-heroku-keepalive hubot-maps hubot-pugme hubot-redis-brain hubot-rules hubot-scripts hubot-shipit --save

# ping等
npm uninstall hubot-diagnostics --save

# リスの画像
npm uninstall hubot-shipit --save

# heroku用
npm uninstall heroku-keepalive --save

# map
npm uninstall hubot-maps --save

# help
npm uninstall hubot-help --save

# google-translate
npm uninstall hubot-google-translate --save

# google-images
npm uninstall hubot-google-images --save

# パグの画像
npm uninstall hubot-pugme --save

# ロボット3原則
npm uninstall hubot-rules --save

# DEPRECATED
npm uninstall hubot-scripts --save

# redisを使ってデータを保持したい場合使用。
# 私はnedb使ったりするので削除。
npm uninstall hubot-redis-brain --save

不要なファイル削除

以下のファイルを削除します。

  • external-script.json
    外部botコードを使用しないので削除します。

  • hubot-script.json
    hubot-scriptを使わないので削除します。

  • bin/hubot.cmd
    本番でwindowsで動作させたい場合などは残します。
    windowsで開発する場合もGit for Windowsが入っていると思うのでbash.exeで問題なければ基本使わないハズ。

  • scripts/example.coffee
    サンプルコードなので削除します。

nodeのバージョン変更

package.jsonに記載されているenginesのバージョンが古いので動作させるnodeのバージョンに書き換えます。

"engines": {
  "node": "6.10.x"
}

起動スクリプト編集

私は bin/hubot に環境変数などを以下のように書いて起動しています。
また、本番環境では Systemdに登録して起動しています。

#!/bin/sh

set -e

export ROCKETCHAT_URL=http://192.168.0.123:3000
export ROCKETCHAT_ROOM=wg-sandbox
export ROCKETCHAT_USER=chabot
export ROCKETCHAT_PASSWORD=chabotpassword
export ROCKETCHAT_AUTH=password

npm install
export PATH="node_modules/.bin:node_modules/hubot/node_modules/.bin:$PATH"

exec node_modules/.bin/hubot --name "chabot" -a rocketchat

メイン処理ファイル作成

scripts ディレクトリ以下にjsファイルを作成します。ファイル名は任意です。
私は main.js を作成しています。

// Description:
//   先頭に"// Description:"コメントを書いておかないと起動時に警告(INFOだが)が出る。
module.exports = (robot) => {

    // ここに処理を記述する。
    robot.respond(/hoge/i, (res) => {
        res.send("hoge!!!");
    });

};

※開発言語について

Hubotのデフォルト開発言語はCoffeeScriptですが(v3系(#1347)からJavaScriptに移行してました)、scriptsフォルダにJavaScriptファイルを置いても実行されます。Rocket.ChatもCoffeeScriptからJavaScriptに移行していますし、私はJavaScriptで書いています。
参考:https://github.com/RocketChat/Rocket.Chat/issues/796

メッセージ投稿処理について

基本応答

ユーザーの投稿に反応して応答を返す場合、robot.hearrobot.respond の応答関数の引数のメソッド res.send を使用します。
デフォルトでは新規投稿にしか反応しません。編集投稿に反応するようにするためには環境変数 RESPOND_TO_EDITED=true を設定する必要があります。
2017/09/07 現在 hear 内でメッセージ( res.message )が新規か編集かを判別する手段は無いようです。どうしても必要な場合、Rocket.Chat用のHubot adapterの recketchat.coffee にコードを1行追加して hear 内で判別可能なようにできます。

// Description:
//   先頭に"// Description:"コメントを書いておかないと起動時に警告が出る。(INFOだが)
module.exports = (robot) => {

	robot.hear(/hoge/i,(res) => {
		res.send("hoge! 全ての投稿でhearが含まれる投稿に反応して発言する。");
	});

	robot.respond(/piyo/i,(res) => {
		res.send("piyo! botの名前+piyoが含まれる投稿に反応して発言する。");
		// 注意:
		// ここでのbotの名前はbin/hubotの中に書かれている --name 【名前】でも反応する。
		// これはyo hubot時に質問されるbotname。
		// ボット名はアットマークなしで反応する。
	});

};

能動的に投稿

cronnode-schedule などを使用して、定時に投稿する場合などは、 robot.send を使用します。
2017/09/07 今更ながら robot.messageRoom を発見。こちらの方がシンプル。

// チャンネル名を指定する必要があります。
robot.send({ room: "wg-hoge" }, "hogeeeee!");
// こっちのほうがシンプル。
robot.messageRoom("wg-hoge", "hogeeeee!");

テキスト以外の情報を含むメッセージ投稿

テキスト以外の情報を含める場合、メッセージオブジェクトを作成して send に渡します。

robot.hear(/hoge/ig, (res) => {

	// 文字列のみ
	res.send("hoge?!");

	// 絵文字もOK
	res.send("emoji! :ok:");

	// メッセージオブジェクトを作って送信
	const message = {
		msg: "message here!",
		attachments: [{
			"text": "text here! :tada:",
			"color": "#ff0000",
			"alias": "別名を表示させたいときに設定",
			"avatar": "投稿者アイコンにアバターを表示させたいときに設定。URLを指定する。",
			"emoji": "投稿者アイコンに絵文字を表示させたいときに設定。ex. :ok:",
			"fields": [{
				"short": true,
				"title": "ok (no title emoji :ok: )",
				"value": "[Link](https://google.com/) *bold* _italic_ "
			},{
				"short": true,
				"title": "ng",
				"value": "no emoji :tada: , \r\n %0a no newline, no `inline` "
			}]
		}]
	};
	res.send(message);
});
// 自発的に投稿、またはチャンネルを指定して送る場合、robot.sendを使う。
robot.send({ room: "wg-hoge" }, "hogeeeee!");

// メッセージオブジェクトを作って送信
const message = {
	msg:"send to wg-hoge!",
	attachments: [{
		"text": ":ok: emoji OK!",
		"color": "#FF0000"
	}]
};
robot.send({ room: "wg-hoge" }, message);
// こっちのほうがシンプル。
robot.messageRoom("wg-hoge", message);

Hubotのsend時のメッセージオブジェクトのドキュメントは今のところ発見できず、rest-apirealtime-api 見ながら探してます。
今のところ msg , attachment でほぼ事足りています。
avatar自分のQiitaのアイコンURLでも表示されました。

res(RocketChatResponseオブジェクト)の中身

robot.hearrobot.respondなどのコールバック関数の引数のresについて。
Rocket.Chat Hubot adapter定義クラスHubot定義クラスを継承)。

メソッド

メソッド 実装箇所
sendDirect RocketChatBotAdapterのsendDirect
sendPrivate RocketChatBotAdapterのsendDirect
send RocketChatBotAdapterのsend
emote RocketChatBotAdapterのemote
reply RocketChatBotAdapterのreply

その他topicやplayなどもあるがRocketChatBotAdapterで未実装のため使用不可。

プロパティ

いろんなところにroomやmessage, userが入ってて紛らわしいですが、全て同じ情報が入っています。

2018/07/26追記
※1: roomについて、1.0.9からルームIDではなくルーム名が入るようになったようです。(破壊的変更)
また、1.0.10からダイレクトメッセージ、ライブチャットの場合はIDがセットされています。

プロパティ 内容
robot 上位のrobotと同じ。
message TextMessageオブジェクト
match マッチ配列。String.match()の戻り値と同様(g付き時にinput, indexが無いとかナントカ)
envelope エンベロープ。room, user, messageが入っています。

res.envelope

プロパティ 内容
room ルーム名 ※1
user Userオブジェクト
message TextMessageオブジェクト

TextMessageオブジェクト

Hubot定義クラス
メッセージ内容が入っています。出現箇所は以下。

  • res.message
  • res.envelope.message
プロパティ 内容
user Userオブジェクト
text 投稿メッセージ内容
id メッセージID(内部ID)
done 処理済みフラグ。これを true にすると後続のhearrespondが処理しない。listenは通った。
room ルーム名 ※1

Userオブジェクト

Hubot定義クラスid, name 以外は自由っぽい。
投稿したユーザーの情報が入っています。出現箇所は以下。

  • res.message.user
  • res.envelope.user
  • res.envelope.message.user
プロパティ 内容
id ユーザーID(内部ID)
name ユーザー名(名前ではない)
alias エイリアス(無い場合undefined)
room ルーム名 ※1
roomID ルームID(内部ID)※1.0.9で追加された。
roomType ルームタイプ ※1.0.12で追加された。※2

※2: ルームタイプ(他にもあるかも)

内容
c パブリックチャンネル
p プライベートチャンネル
d ダイレクトメッセージ

Hubotの運用環境

基本node, npmが入っていれば問題ないです。

環境変数について

https://rocket.chat/docs/administrator-guides/hubot#configuration-options https://rocket.chat/docs/bots/configure-bot-environment/ に説明は書いてありますが、ハマったり、よくわからなかった設定値について動作確認した記録です。
2018/06/14追記
URLが変わってました。

ROCKETCHAT_URL

ROCKETCHAT_URL=http://192.168.0.123:3000/ のように最後に / を付けると正しく動作しません。
0.46.0以前くらいでは起動していた時期がありました。

LISTEN_ON_ALL_PUBLIC

基本的にボットが参加しているチャンネルすべてでlistenしますが、
LISTEN_ON_ALL_PUBLIC=true を指定して起動した場合、ボットが参加していないチャンネルもlistenします。
応答した場合は、ボットは未参加のままメッセージが投稿されます。
この値が設定された場合、 ROCKETCHAT_ROOM='' とするべき、と書いてあります、理由は不明。
hubot-rocketchat内部で LISTEN_ON_ALL_PUBLIC=true の場合、 ROCKETCHAT_ROOM='' が設定されるようになっていました。

ROCKETCHAT_ROOM

ROCKETCHAT_ROOM=random
ボット起動時、ボットが指定チャンネルに参加していない場合、参加します。
ここに記載していないチャンネルでもユーザーがボットを参加させると listen するようです。

RESPOND_TO_EDITED

ボットはデフォルトでは新規投稿時にしか反応しません。(default: false)
RESPOND_TO_EDITED=true とすることにより、編集時にも反応するようになります。

PORT

Hubotのパラメーター。
HubotにはExpressが内蔵されていて、ポートを指定しない場合、デフォルトの8080が使用されます。
そのため、同一端末で2つのHubotを起動すると、後から起動したHubotの8080が使えず、起動時にエラーログが出力されます。
Expressの機能を使わない場合、hubot起動オプションで--disable-httpdまたは-dを指定します。

42
43
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
42
43

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?