この記事はアドベントカレンダー2024 19日目の記事です。
こんにちは、@Hueterです。
こたつにでぬくぬくしながらこのブログ記事を書いているのですが、手だけはキンキンに冷えております。
つらいね。
まえおき
裏話
紆余曲折があり...(暇な人だけ読んでください)
そう、あれは先輩と飯を食べているとき...
アドベントカレンダー担当なのにブログ記事を書かないのはどうなのかと思い、今まで作ってみたいと思って放置していたBOT製作をしてみることに。
BOTを作るにしても、GoやPython、Rustなど様々な言語がありますが決められなかったので先輩にいろんな言語を出してもらってそこからランダムに選ぶことに。
結果...
本当にランダムなのか疑いたくなりましたね。まあ運命ということで。
ということでJavascriptのHubotでBOTを作ります
...これまでの流れは何だったのかって?いや、これには水たまりよりも浅く砂山よりも低い理由があったりなかったり。
C++のBOTはtraPの先輩で既に作っている人がいたのですが、その人が残したWikiに怖い一言が。
俺はどうしてもC++を使ってtraQbotを作りたいんだという奇特な方でなければ別の言語を使って作ることをおすすめします
他の言語での開発の方が絶対に楽です 主に環境構築の面で
これを見て、はじめてのBOT作成でこれに手を出すべきなのか?という考えになってしまい、その上復活のHubot?とかいう気になる記事を見つけてしまったので、Hubotを作る機運になってしまいました。(後でこの先輩から「Wikiにはこう書いたけど、多分そんなつらくないよ」と言われたのですがすでに方向転換した後でした。)C++のBOTはまたの機会にやるかもです。
本題
Hubotというものを使ってBOTを作っていきます。BOTはtraP内SNSのtraQとDiscordの二つについて作ってみました。ただ、こちらはBOTのセットアップまでの記事なので「Hubotはもう動かせて高度なことがしたいよ」って人は他の記事を参考にしてください。
また、様々なサイトでいろんなコマンドを実行してインストールしていたので、余計なものや抜けているものがあったりするかも知れません。そのことを頭の片隅にでも置いて見てください。
開発環境
- Windows11
- WSL
- Node.js v20.5.0
- npm v9.8.0
BOTを動かすサーバーはtraPの内製サービスであるNeoShowcaseを使っていきます。そのため、サーバー周りの設定はあまり参考にならないかもしれません。NeoShowcaseについてもっと知りたい方は以下の記事を見てください。
【NeoShowcase】traPには内製の作品公開プラットフォームがあります
Hubotとは
Hubot(ひゅぼっと)は、GitHub社が開発した、オープンソースのボットフレームワークです。2011年10月26日にv1.0.0がリリースされて、日本では2016-2017年ごろにブームを迎えていましたが、いつの間にか忘れられてCoffeeScriptとともに表舞台から消え去っていたらしいです。メンテナンスも2019年4月17日のv3.3.2以降完全に停止していましたが、突如2023年4月18日にv3.4.0がリリースされ、そこから怒涛の開発が行われていました。v11.0.0にて完全にCoffeeScriptが廃止され、今やv11.xまで来ています。何があったんでしょうね?
そんなこんなで、いろいろ変わった(かもしれない)Hubotをせっかくだし触ってみようということでBOT作っていきまっしょい。
BOTを作る
インスタンスの作成
公式のドキュメント Getting Started With Hubot を参考にやっていきます。
これからの操作はNode.jsとnpmが必要なので、見ながら作業したい人はこれらを入れてきてください。ここでNode.jsのバージョンをv23.xにするとExperimentalWarning
が出てしまうのでv20.xでやることをお勧めします。
まず、今回の作業ディレクトリを作って移動します。このディレクトリ内でnpm init
を実行しpackage.json
を作成します。
$ mkdir -p /path/to/hubot # hubotである必要はない 好きな場所・名前のディレクトリでOK
$ cd /path/to/hubot
$ npm init
mkdir
の-p
オプションは、複数階層のディレクトリを同時に生成することができるオプションです。
npm init
を実行すると以下のように入力を求められるので必要に応じて入力してEnter。
package name: # デフォルトで今のディレクトリ。基本エンター押すだけでいい
version: (1.0.0) # このBOTのバージョン
description: hubot test # このBOTの説明
git repository: git@github.com/.... # gitのリポジトリ なければそのままEnter
author: Hueter # 制作者の名前
license: (ISC) # そのままEnterでよい
ここまで入力できたら一旦ディレクトリの階層を一つ上がった後、npx hubot --create {directory-name}
でHubotインスタンスを作成します。この時に--adapter {adapter-name}
を最後に追加することで様々なチャットサービスに対応したBOTを作ることができます。
$ cd ..
$ npx hubot --create myhubot --adapter @hubot-friends/hubot-discord
SlackやDiscordのアダプタはHubotのREADMEにあるので必要に応じて変更してください。traQのアダプタは先輩が作成したhubot-traqを利用していきました。ありがたい。ひとまず今後はDiscordのBOTを作っていく前提で話を進めていきます。
これでBOTの大枠ができましたが、package.json
内に追加で以下のコードを追加します。
{
...,
"engines": {
"node": "20.x"
},
...
}
また、今回のBOT作成では使わないpackageが入ってしまっているので消していきます。具体的には、package.json
内のdependencies
からhubot
とアダプタ以外を消し、external-scripts.json
の[]
の中身を全削除します。その後、npm install
を実行することでpackage-lock.json
をpackage.json
と同期させます。これで良し。
今回はこれでいいですが、他のpackageを利用したい場合はnpm install {package-name}
でインストールした後external-scripts.json
内にpackage名を列挙すればいいです。npm search hubot-scripts github
を実行するとコミュニティでメンテナンスされている数多くのスクリプトを検索できるので興味があれば調べてみてください。
今までの変更を加え、以下のようになっていればOKです。順番が逆になっているとかは気にしなくて大丈夫です。
{
"name": "myhubot",
"version": "1.0.0",
"description": "A simple helpful robot for your Company",
"main": "index.js",
"scripts": {
"start": "hubot --adapter @hubot-friends/hubot-discord",
"test": "node --test"
},
"keywords": [],
"author": "Hueter",
"license": "ISC",
"dependencies": {
"@hubot-friends/hubot-discord": "^4.0.4",
"hubot": "^11.3.2"
},
"engines": {
"node": "20.x"
}
}
仮スクリプトを書く
hubot/docs/Scriptingを参考にやっていきます。
スクリプトは./scripts
というディレクトリ内に記述していきます。今までの操作をしていればすでにディレクトリが存在し.mjs
ファイルがあるのでそのファイルを編集してもいいですし新たに作成しても大丈夫です。ファイル形式は.js
と.mjs
が対応していますが今回は
.mjs
で書いていきます。.js
と.mjs
で少し記法が異なるので.js
で書こうとしている人は注意してください。
基本的なコード構造は以下のようなものです。初めにあるコメントアウトされている部分などは消しても何とかなりはしましたがひとまず残しておきます。
'use strict'
// Description:
// Test script
//
// Commands:
// hubot helo - Responds with Hello World!.
//
// Notes:
// This is a test script.
//
export default async (robot) => {
// your code here
}
新たなコードはexport default async (robot) =>{ ... }
の中に書き加えていきます。
ひとまず動作確認のために以下のように変更します。
...
...
export default async robot => {
robot.respond(/hoge$/i, async res => {
await res.reply("fuga");
});
robot.respond(/ping$/i, async res => {
await res.reply("pong");
});
}
手元でBOTを起動
ここまで出来たら、一度手元でBOTを動かしてみましょう。npx hubot
で起動できます。ただ、おそらくHubot> {"level":50,"time":...}
と出てきますがEnterを一度押してHubot>
の状態にしましょう。このエラーメッセージは出ても気にしなくても大丈夫です。この状態でhoge
かping
と打ちEenterで送信するとそれぞれfuga
、pong
と返って来ます。こんな感じにBOTの動作を確認できます。
余談
エラーメッセージについて、消さずとも動作はしますが、とりあえず私が遭遇したエラーメッセージについて消し方を載せておきます。Hubot> {"level":50,"time":...}
のmsg
の中にエラーメッセージがあるのでそこを見てください。
using deprecated documentation syntax
ES2015 で Hubot のスクリプトを書くと using deprecated documentation syntax
って怒られる件について
つまるところmain.mjs
の最初に以下を追加するだけです。Commandsの中身は空でもいいですし、下みたいにふざけてもエラーメッセージは消えます。また、Commandsである必要もなさそうでDescriptionやNotesでも大丈夫でした。詳しいことは公式ドキュメントを見てください。
// Commands:
// ぬるぽ - ガッ!
//
src/scripts does not exist
書いてある通り、src/scripts
のディレクトリがないということでディレクトリを作ればエラーメッセージは消えます。ただ、中身のないディレクトリを作るのはいまいちなので私は無視して作りました。
Hubotではsrc/scripts
とscripts
の二つのディレクトリの中にあるコードを読むようになっているのでそのディレクトリがなかったら怒るということですね。この読み込みはnode_modules/hubot/bin/Hubot.mjs
のloadScripts
内にあるawait robot.load(pathResolve('.', 'src', 'scripts'))
でscriptsを読み取るフォルダを設定していたのでここをコメントアウトすることでもエラーメッセージは消えます。が、node_modules
の中身はGithubに上げずBOT起動時に生成するようにしたので今回は無理ですね。
Gitにあげる
BOTをサーバー上で動かそうとすると大抵Gitに上げないといけないのでGitに上げていきます。(まあ、ローカル環境にしかコードがなかったら他の場所にあるサーバーがコードを参照できないのでそれはそうという話)今回はGithubを使います。まず、不要なファイルをGitに上げないために.gitignore
をNode.gitignoreからコピペして作成します。そして、Githubで空のリポジトリを作り、以下のようなコマンドを実行してGitに上げます。ここのコマンドは各自のGithubからコピペして実行する方が確実です。
$ echo "# {repository-name}" >> README.md
$ git init
$ git add README.md
$ git commit -m "first commit"
$ git branch -M main
$ git remote add origin git@github.com:Hueter57/{repository-name}.git
$ git push -u origin main
これでGitに上げられました。
Discordでアプリ作成
ここまですればターミナルとはお別れです。
Discordで新規アプリケーションを作っていきます。
Discord - Developer Documentationのサイトに行き、New Application
からアプリの名前を入力してCreate
を押すことで新規アプリが作成されます。アプリ名やアイコンは好きに決めましょう。
作成したアプリを開き、もろもろの設定をしていきます。BOTを公開するかしないかで少し操作が変わっていきます。今回は公開しない設定で行きます。
Installation
Install Link
をNone
に変更します。
OAuth2
OAuth2 URL Generator
からbot
にチェックを入れて下に出てきたURLに飛ぶことで、どのDiscordサーバーに今回作ったアプリを入れるかを決められます。この操作はサーバーの管理者権限がないとできないので、権限を付与してもらうか権限を持ってる人にお願いしましょう。
Bot
Authorization Flow
のPUBLICK BOT
をOFFにします。これはInstall Link
をNone
にしていないとできないので注意。そしてReset Token
を押してDiscordアカウントのパスワードを入力することでToken
が作られるのでコピーしておきましょう。
このトークンが洩れると他者がこのBotを操作できてしまいます。絶対に公開しないでください!
万一公開してしまった場合は再度Reset Token
を押してToken
を再生成してください!
サーバーにBOTを追加
ここまでくれば作成したBOTをサーバー上で動くようにしていきましょう。
今回はtraP内製サービスのNeoShowcaseを使っていきます。BOTのあるリポジトリやビルドの設定をした後、環境変数としてHUBOT_DISCORD_TOKEN
を追加し先ほどコピーしておいたToken
を値として設定します。
ここまでの操作が終わればBOTが起動するはずです。アプリを追加したDiscordサーバーに行きオンラインになっていれば大丈夫です。では早速動作確認をしていきましょう。
や っ た ぜ
このように返信してくれれば正常に動いています。
同様の手順でtraQ用に別に作ったのも動いて大満足です
少しだけスクリプトをいじってみる
動くことが確認できたので、少しスクリプトを変えてみましょう。まず、今のコードを見てみましょう。以下はメンションしてping
と送ったらpong
が返ってくる部分です。
robot.respond(/ping$/i, async res => {
await res.reply("pong");
});
このコードでping
とpong
の部分を変更することで反応する言葉とそれに答える言葉を変更することができます。他にも、メッセージの受け取り方法や返信方法もrespond
とreply
の部分を変更することで変えることができます。
- 発言の反応
hear
... 監視状態にあるチャンネルの発言全てに反応するようになりますrespond
... メンションやDMにのみ反応するようになります
- 返信方法
send
... そのチャンネル全員への返信reply
... 発言者への返信(メンションされる形式となる)emote
... チャンネルに対する発言 最近追加されたらしいがsend
との違いは不明
ということでいろんな組み合わせを試してみました。
今回監視対象のチャンネルを指定していないのでhear
としてもメンションしなければ使えませんが、send
,reply
,emote
は使えました。とはいってもやはりsend
とemote
は全く同じに見えますね...?なんでしょうか。私にはわかりませんでした。
終わりに
初めてのBOT制作できたが何とか完成できてよかったです。NeoShowcaseも初めて触るので一番最初にBOTが動くようになるまで1週間ぐらい格闘してましたね。ただ、先輩方やサークルの人の助けもあり何とか動かせました。感謝カンゲキ雨嵐です。
今回はNeoShowcaseを使いましたが、ここに至るまでに参考にしたサイトではGlitchとGoogle Apps Scriptを組み合わせて無料の範囲で動かしている人や、Herokuというサービスを使っている人がいました。参考資料に私が見てきたサイトを載せておくので見てみてください。
タイトルに準備編と書いたのでいつか応用編みたいなものも出せたらなと思いますが、これから先忙しくなってくるので投稿できるのは先になりそうです。新歓ブログリレーに間に合うといいなーと思って頑張っていきます。
それではみなさんも、良いHubotライフを~
明日は@Alt--erさんと@METCH722くんがブログを出してくれます。お楽しみに!