あるいはbotでいっぱいの海

 

 諸々の進捗からの現実逃避のために、今日は新京極にオタクグッズを買いに行きました。すっかり日も落ちた午後七時、修学旅行客の多い京都の商店街ですから、すっかり人の数も減っているものだと思いましたが、不思議なことに今日はたくさんの人が行き交っています。違和感に目を凝らしながら人々を眺めていると、私はその中央で記念撮影に応じる全身赤ずくめの男性の姿を認めることができました。季節外れのカープの優勝パレードでしょうか?何にせよ、京都の夜は街灯が少なくて危険です。なにぶん若い人々も多かったですから、なるべく早くに切り上げて帰宅してほしいと老婆心ながらに思いました。

 

この記事はKMC Advent Calendar 2016の25日目の記事です。前日の記事はKMC-id:hakurin さんの「はじめての同人誌」でした。僕も天龍型姉妹の子供になりたいですね。

hakurin776.hateblo.jp

 

 初めまして。KMC-id:kyp と言う者です。前期はpiet練習会に出ていて、途中からDTM勉強会にも参加するようになりながら、気づいたら部室のコタツとズブズブの関係を築いていました*1。私は(謙遜ではなく)あまりプログラミングに詳しくなく、本来このサークルに入ったのもDTMが主目的だったのですが、このサークルでは毎日色々と楽しいイベントが立っていて、気づいたら自分もコードを書いて(描いて)いることが増えてきました。今回の記事ではのんびりとSlack Botを作ってみた話をします。技術的に新しいサムシングがあるわけではないので、ゆったりと雰囲気を感じ取ってもらえると嬉しいです。

 

1.わいわいSlack

 これは特に説明がいらないかもしれません。Slackはチーム用のSNSみたいなものです。物凄く雑な説明をすると、チームの中の人たちしか見たり書き込んだりできない掲示板みたいなものです。各々勝手にスレッド(=チャンネル)を立てることができます。KMCはSlackを鬼のように使い倒していて、数百ものチャンネルが並行して立っており、文字通り今晩のおかずからハッキングまでを楽しく語り明かしています。

 で、4月くらいに入ったときから薄々感じていたのですが、KMCのSlackには膨大な数のbotが動いていました。部の内部Wikiが更新されると自動的に教えてくれる(最近はdiffまで表示されるようになった)botであるとか、仮想マシンのシェルをいじれるbotであるとか、その機能は実に様々でどれも高機能です。*2

 で、これはどういう風に動いているのか気になって、その辺にいた適当な先輩に聞いてみると、Slackはいい感じにAPIが公開されていて、これをいい感じの手続きを踏むと外部のプログラムから中のデータを読んだり書いたりすることができるらしいです。で、その手続きをいい感じにしてくれるライブラリがいい感じの言語で動くので、それをいい感じに使っていい感じのプログラムを書き、いい感じの実行環境の上で動かすことで、いい感じのbotを走らせることができるようですね。

 KMCに入部することによる大きなメリットの一つとして、部のサーバーを自由に使うことができるという点があります。インターネットと通信するbotを動かすだけなら自分のPC上で実行してもできるのですが、PCの電源を落とすとbotも落ちるし、それだと狙った機能はなかなか実行できません。ところがサーバーは24時間365日年中無休で動いています。なのでその上で動かしたBotはずっと動き続けてくれます。これを活かさない手は無いですね。

 

2.わいわいBotkit

 上に書いた「いい感じのライブラリ」は沢山あって、沢山の言語の上で動いています。「Slack bot 作り方」で検索すると色々なライブラリが出てきて迷います。迷っているうちに「今日はいいか…」という気持ちになってSteamを起動します。そして午前3時になっています。風呂に入って寝ます。目が覚めます。窓からはカーテン越しに穏やかな夕日が射し込んできます。

 で、そういう無意義な日々から脱するために、とりあえず例会講座でbase64さんが例会講座で紹介していたnode.js上で動くライブラリBotkitを使ってみることにしました。この時点ではnode.jsが何なのかよく分かってないし、自分が今何書いてるのかもよく分からない状態でしたが、まあサンプルコードをちょっと書き換えてbashから起動。

gist.github.com

  で、こうなります。

gyazo.com

 楽しい✌ ('ω' ✌ )三 ✌ ('ω') ✌ 三( ✌ 'ω') ✌

 「特定の書き込みを探す」→「それに対応した返答を返す」という機能は上の関数を改変すれば無限に作れるので、機能は無限に増えていきました。

gyazo.com

 正規表現に初めて触れる様子

gist.github.com

gyazo.com

 変数を使ってみる様子

gist.github.com

 

gyazo.com

 わいわい。上に挙げたような高機能なBotからは程遠いですが、とりあえず発言すれば狙い通りの返事が帰ってきて楽しいです。これは人間とのコミュニケーションでは中々無いことです。

 

3.わいわいtwitter

 ところで私はtwitterが好きです。思春期のほとんどをtwitterに費やし、青春のエネルギーを黒歴史に変換し、そして数度に渡ってその全てを消し去っていきました。今動かしているアカウントがはたして何代めのものか、今名乗っている名前が何個めのものかも分かりませんが、ともかく私は百聞は一ツイートにしかずという世界観で生きてきたのです。ということで、Slackの次はtwitterbotを作ってみようと思いました。

 インターネットで初心者用の説明記事を参照すると、PythonとかRubyとかが多くてアレだったのですが、せっかく環境を築いたのでnode.jsのtwitterというライブラリを使ってみることにしました。

gist.github.com

 

 よさそうでした。でも、特に具体的なBotのアイデアがあるわけでもなかったので、とりあえず思考停止でSlackの特定チャンネルへの書き込みをtwitterに流すプログラムを作成。#kyp_memoチャンネルで「tweet (.*)」と書くとその内容で私のアカウントが呟きます。ここで重要なのは、Slackでは書き込み者の限定をしていない(つまり、誰でも私のアカウントを介して呟ける)ということです。*3

gist.github.com

 平和ですね。

 ところがこの牧歌的な光景は、思いもがけない方法で終わりを告げることとなります。

gyazo.com

 つい失念していたのですが、D <twitterSN> …… でダイレクトメッセージを送ることができるのですね。他にもリプライを送ったり、ツイートのURLで引用RTしたりとか、 次々と良くなさそうな行動が取れることが発覚していき*4、ところで他人の通知欄を汚すのは極刑に値する重大犯罪なので、一旦この機能は停止させられました。その後微妙にリプライを弾いたり先頭にSlackからの発言であることを示すヘッダーをつけたり*5して再起動しましたが、思いの外この機能が好評を博しており、毎秒に近いペースで呟きが投稿され、つまるところ荒らし以外の何物でもなくなっていたのでやっぱり機能停止ということになりました。

 

 さて、私はKMCのアドベントカレンダーに対し、特に考えることなく参加表明をしてしまっており、さりとて何か成果を挙げられるような活動をしていたわけでもなかったので、そう考えるとbot作りの事実はネタとして最適なのかなあという感じが起きました。なので、ネタとしてこの機能は復活させておこう、ただし人々には分からないようにして、という企みを起こしました。ところで私は口が軽いです。

gyazo.com

 そして部室でおだてられて更なるヒントを与えてしまい、

gyazo.com

 なぜか文字化けしていました。で、その後頑張って修正したんですが、

gyazo.com

 ……。

  その頃のお気持ちが偲ばれるツイートです(このツイートを打っている最中にも私は超人的な速さで無差別に下ネタを投下するアカウントになっています)。

 で、皆さんの理性を取り戻すために、ten君の「5%で発言者のidが表示される」というアイデアを元に、いい感じに実装!……できなかった。

 

4.ちょっとだけnode.jsっぽい話

 例えば私のID @kyp のように、表に出てくるSlackのIDは自分で付けられる分かりやすい名前になるのですが、twitterとかと一緒で、内部的にはどうもそうじゃないらしいです。で、発言についてくる情報はその内部的なごちゃごちゃした何かなので、それを皆がよく知っているほうのIDに変換する必要があります。で、そういうAPIがありました。

 こことかを参考にしながら、何の疑問も持たずにコピペ。

gist.github.com

 node.jsを知っている人であれば、というかそうでなくても、私の誤ちがどこにあるか容易に指摘できると思います。私はそうではありませんでした……。乱数を一旦排除してあるので、全ての書き込みに[by ***]とついて欲しいのですが、残念ながらそうはいかなかったのです。console.log()で色々吐き出させているうち、ようやく私は「処理が下から上に行われている!!」と気づいたのですね*6

 javascriptの文法に明るくなく、サンプルコードに頻出する「});」みたいなコードもぼけっと眺めていた私にとって、これが関数の引数として与えられている関数で、しかも実行されるのはその(自分が引数となっている)関数が終了したとき(そして変数のスコープはクロージャーで云々……)というのは確かな知識として備わっていませんでした。

 まあつまり図にすると、私がこう

gyazo.com

 思っていたのが、実際にはこう

gyazo.com

 だったんですね。で、SlackのAPIにユーザーの名前を尋ねに行くよりも、twitterにポストしてしまう動作のほうが早いので、下の関数が先に呼び出され、outputはフッターなしに出力されてしまう……と。

 で、この問題点は雑な実装により解決されました。

gist.github.com

 雑ですね~~~~~~~。

 コールバックが4重くらいになってますね。雑。雑すぎる。

 なんかPromiseとかthenとかの存在は知っているので、絶対にそのうち書き換えます。でもこないだnode -v とか打ったら0.10.29とか出てきて不穏でした。バージョンアップの方法も調べてやってみましたけど、どうもroot権限が必要っぽい?グローバルインストールとかなんとか、知らない概念がたくさん出てきたのでまた勉強するしかなさそうですね。

 

5.現況

 本来は秀逸なツイートを逐一貼り付けていって笑いを誘おうかとでも思ったのですが、このままだとアドベントカレンダーの中で一番長い記事になりそうです。しんどいですね。というわけで雑にこれを貼ります。

 頑張って時折発言者名が覗くようにしたのに、過激なツイートは一切止むことはありません。というかこれはかなり無力でした。

gyazo.com

 いい発想ですよね。また、この機能は新たな火種を生みました。上のコードを見て分かる通り、投稿者の偽装は数回の試行の後直ちにブロッキングされたのですが、

gyazo.com

 とても分かりづらいですが、「y」がキリル文字の「у」(ウー)に置き換えられています。他にも0x202d(Left-To-Right Override。文章が左から右に流れることを示す制御記号らしいが、表示上は何も現れない)を間に挟むとか、あるいは単に半角全角の混合とか、そういう欺瞞に満ちたダークウェブの前に我々はあまりに無力です。

 ところでこれはその失敗例です。

 

6.終わりに

 ここまで見てもらって薄々感じ取っていただいたように、KMCの人々はBotを公開するととことん使い倒してくれます。その方向性は主に脆弱性を突く方向に行くのですが、しかしそれもまた一種のコミュニケーションという感じがあって楽しいです。クラッカーとインフラエンジニアの仁義なき戦いを10000倍くらい水で薄めるとこういう感じになるんじゃないかと思います。

 ちなみに、これまで#kyp_memoの元にされたツイートの数は208個です。たった3日間の出来事です。最高の承認ですね。

 

 というわけで、KMCでは新規部員を募集しています!KMCには入部制限はなく、年齢や学歴、人種、宗教、信条、性別、社会的身分、門地、国籍、経験などは不問です!ちなみに私は文学部です!Botを作って承認欲求を満たしたいみんな、集まれ~~~!!!!

www.kmc.gr.jp

 

 で、さらに言えば、

  もあります。脚注にもありますが、KMCで動いてるBotについて興味関心のある方にはきっと満足して頂ける内容になっていると思います!僕もいくつかの企画に顔を出しています!部誌もCDも一瞬で買いましょう!

 ちなみに、KMCではグラフィッカーを中心にもう一つのアドベントカレンダーも行われています!

www.adventar.org

 僕も神絵師になりたい!来年はプロジェクト参加します!

 

最後に

www.youtube.com

 最初にちらっと書きましたが、私はDTMが大好きです。そういうことです。絶対にチャンネル登録して拡散してください。よろしくお願いします。*7

*1:この記事も部室のコタツの上で書かれています

*2:Slackで動いているbotについてもっと知りたい方は、C91で配布されるKMCの部誌にもそれっぽい記事があるので、よければ読んでみてください!

*3:本当のことを言えば、実装の仕方を知らなくて放置してただけなんですが……。

*4:そのうちのいくつかはKMCの先輩を対象に私のアカウントを通して実行されました。

*5:皆さん"\b"と呟いて消そうと頑張っていました。

*6:この数日前にwassさんからそういう話を聞いていたのに……無念です。でも話を聞かなかったら気づきすらしなかったかもなので感謝です。

*7:本当は今日までにオリジナルの曲を作って投稿するつもりでしたが、間に合いませんでした……。無念です。