まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

タグ:nodered

Node-RED Advent Calendar 2017 に参加しました(ちなみにアドベントカレンダーに参加するのは初めて)! 12月9日のネタは「Node-RED で(普通の)ウェブアプリケーションを作る」です。

Node-RED を早くから活用している方の多くは IoT 連携であったり、組み込み機械との連携のデータフローとして使っているケースが多いと思っています。でもそんなケースばかりではなく、自分自身は Node-RED でデータベースを読み書きする REST API だけを作ったり、その REST API を呼び出すフロントエンドまでも含めて Node-RED で作ることがあります。今日はその作り方をスクリーンショットを交えて紹介します。


【普通のウェブアプリケーション】
最初に、今回作成する「(普通の)ウェブアプリケーション」を定義します。ここでの「ウェブアプリケーション」とは「アプリケーションサーバーとデータベースサーバーから構成」されていて、「アプリケーションサーバーのユーザー画面を通じて、データの保存、読み込み、検索、・・といった処理ができる」ものとします:
2017111702


これを Node-RED で作ります。具体的にはアプリケーションサーバー部分を Node-RED として、外部のデータベースサーバーに対する読み書きを行う API を Node-RED 上に定義します。そしてそれらの API を使う UI となる HTML も Node-RED で作ることで、ウェブアプリケーションとしての機能を実現します。なお今回はデータベースサーバーに IBM Cloudant を使い、全ての機能を IBM Cloud 上に作成することにします:
2017111901


【環境準備】
というわけで、まず Node-RED を用意します。Node-RED 環境が既に手元にある方は読み飛ばしていただいてもいいのですが、この後 IBM Cloudant を利用するので IBM Cloud のアカウントを取得し、IBM Cloudant のサービスインスタンスを用意するようにしてください(まあそこまでやるなら Node-RED も IBM Cloud で作っちゃうのがいいと思います)。

Node-RED はローカルで作ってしまってもいいと思いますが、このあとデータベース連携を行うので、(IBM Bluemix 改め)IBM Cloud の Node-RED 環境を使うことにします。無料のライトプランで契約している場合は Internet of Things Platform Starter ボイラープレートからランタイムを作成してください:
2017111701


ランタイムが稼働するまでしばらく待ちます。このボイラープレートから作成すると Node-RED の(Node.js の)ランタイムに加えて、Cloudant データベースのサービスインスタンスも同時に使えるようになります:
2017111701


実際に Node-RED を使おうとすると、初回のみアクセス用の ID とパスワードの設定を求められます。推測しにくいものを指定して、設定してください:
2017111702


改めて作成したアプリケーションの URL を指定し、Node-RED の画面になったら "Go to your Node-RED flow editor" をクリックしてフローエディタ画面に移動します(この際に認証が求められるので、直前に設定した ID とパスワードを指定します):
2017111703


Node-RED フローエディタ画面が表示されました。IBM Cloud 環境では画面左のパレットリスト内にデータベースや IBM Watson など初めから多くのサービスノードが有効になっているのが便利です(この後実際に使います):
2017111704


なお、Node-RED 環境をローカルで(IBM Cloud を使わずに)用意した場合は別途データベースを用意する必要があります。以下では IBM Cloudant を使う前提で紹介するので、IBM Cloud から Cloudant サービスをインスタンス化してください:
2017112101


【API を作成】
ではここから「普通のウェブアプリケーション」を作っていきます。改めて今回作成するウェブアプリケーションの構成を確認しておきます:
2017111901


今回のアプリケーションでは Node-RED 上に用意する HTML 内のフォームで入力した値を Cloudant に格納し、また格納済みの値を Cloudant から取り出して一覧表示できるようにします。 ということは、今回作成する必要があるのは以下の3つです:
 (1) ユーザー画面の HTML ページ
 (2) (1) 画面で入力した値を Cloudant に保存する API
 (3) (2) で保存した値を Cloudant から一括で取り出す API

この (2) と (3) を最初に作ることにします。

最初に (2) の格納用 API を作ることにします。機能としては((1) で用意する)ユーザー画面で指定した値を受け取ってデータベース(IBM Cloudant)に格納する API です。なので、このような仕様の REST API を作ります:
メソッドパスデータ挙動
POST/myrecordCloudant に保存するデータ(JSON)送信したデータを Cloudant データベースに保存


ではこの API を Node-RED で作ります。Node-RED のキャンバスをクリアします(初期状態で何か配置されているものは全て消します(マウスで選んで DELETE キー))。そして、以下のように3つのノードを配置&接続します:
2017112102


一番左は HTTP Request ノードです(パレット上では "http" と表示されていて、右側だけにジョイントが設定されています)。このノードをダブルクリックして、以下のような属性を指定し、POST /myrecord として動くようにします。最後に「完了」をクリックします:
2017112103


水色のノードは IBM Cloudant out ノードです("cloudant" と表示され、左側にだけジョイントが設置されているものです)。HTTP Request ノードの payload の値を受け取って、そのまま IBM Cloudant に格納する、という目的のノードです。IBM Cloud のボイラープレートから Node-RED 環境を作成した場合はこの部分は自動的にバインド先のサービス名が代入されるはずなので特に変更は不要です。格納先のデータベース名は属性として指定する必要があるので、ダブルクリックしてデータベース名を指定します(以下の例では mydb という名前のデータベースを指定しています)。また msg.payload 内の値だけを格納してほしいので、"Only store msg.payload object?" にチェックを入れておきます:
2017112104


なお、IBM Cloud のボイラープレートを使わずに、IBM Cloudant のインスタンスを別途作った場合は、ここで IBM Cloudant に接続するための username や password も指定する必要があります。


右下にあるのは HTTP Response ノードです。HTTP Request とペアで設定する必要があります。HTTP Request ノードからは IBM Cloudant ノードと HTTP Response ノードに分岐しています。この結果この POST API では HTTP Request ノードに送信されたデータがそのまま HTTP Response として返されると同時に、同じ値が IBM Cloudant の指定データベース(mydb)内に格納される、という挙動になります。ここまでの設定で下のような見た目になります。これだけで (2) のデータ保存用 REST API が出来てしまいました。簡単ですね:
2017112105



では続けて (3) の、データベースから保存されている全レコードを取り出す REST API も追加します。(2) で格納したデータを全て取り出せるように、以下のような API を定義します:
メソッドパスデータ挙動
GET/myrecords(なし)Cloudant データベースから全データを取り出して JSON 配列で返す


先程と同様に、キャンバスに以下のように3つのノードを配置して接続します:
2017112106



一番左は HTTP Request ノードです。このノードをダブルクリックして、以下のような属性を指定し、GET /myrecords として動くようにします:
2017112107


真ん中にあるのは IBM Cloudant in ノードです("cloudant" と表示され、左右両方にジョイントが設置されているものです)。HTTP Request に対して、IBM Cloudant の指定データベースから全レコードを取り出して返すようにするため、ダブルクリックして以下のように属性を指定します(以下の例では mydb という名前のデータベースから全データを取り出す指定をしています):
2017112108


右側にあるのが HTTP Response ノードです。直前の IBM Cloudant in ノードで取得した値を HTTP レスポンスの結果として返します。これで (3) の REST API も完成です:
2017112101


【HTML を作成】
では最後にここまでに作った API を呼び出して使う HTML ページ(利用者向けページ)を作ります。最終的にはそれなりに凝ったものを作りますが、とりあえずは (2) の API の挙動を確認するためのページを作ってみます。キャンバスに以下のように3つのノードを配置して接続します:
2017112102


一番左は HTTP Request ノードです。このノードをダブルクリックして、以下のような属性を指定し、GET /home として動くように(ブラウザから /home にアクセスした時に以下の HTML が表示されるように)します:
2017112103


真ん中は template ノードです。ノードをダブルクリックして以下の HTML 構文を入力します:
2017112104


(テンプレートの入力内容)
<form method="post" action="/myrecord">
Country:<input type="text" name="country" value=""/><br/>
Capital:<input type="text" name="capital" value=""/><br/>
<input type="submit" value="Submit"/>
</form>

↑ country (国名)と capital (首都)を指定して送信ボタンをクリックすると POST /myrecord を呼び出して保存する、という HTML です。


ここまでの作業で3本のフローができました。この状態で右上の「デプロイ」をクリックしてデプロイします:
2017112101


【動作確認】
まずデータを作成する前に IBM Cloud のダッシュボードから、IBM Cloudant のサービスインスタンスを選び、"LAUNCH" ボタンから Cloudant のダッシュボード画面を表示します:
2017112101


IBM Cloudant のダッシュボード画面の左ペインの上から2番目のデータベースアイコンを選択し、現在の Cloudant データベースの一覧を確認します(nodered というデータベースが1つだけ存在していて、この時点では mydb データベースも、その中身のドキュメントも存在していません):
2017112102


ではデータを格納する前に、格納先である mydb データベースを作っておきます。画面右上の "Create Database" をクリックします:
2017112106


データベース作成のダイアログが表示されるので、作成するデータベースの名前(今回の場合は "mydb")を指定して "Create" ボタンをクリックします:
2017112107


すると mydb データベースが作成され、同時に画面は mydb データベースを表示するページに切り替わります(現時点では1つもドキュメントは入っていないので何も表示されません)。元のデータベース一覧に戻るにはデータベース一覧アイコンを再度クリックするか、画面左上の mydb の左にある "<" 印をクリックします:
2017112108


データベース一覧画面に戻りました。今度は nodered データベースに加えて、mydb データベースが追加されていること(そしてドキュメント数がゼロになっていること)が確認できます:
2017112109



改めて先程作成した HTML ページにウェブブラウザでアクセスします。上記では /home というパスに GET リクエストした際に表示される HTML を定義したので、ウェブブラウザで https://(Node-RED のサーバー名)/home にアクセスして、以下のような画面が表示されることを確認します:
2017112103


この Country に国名、Capital にその国の首都を入力して Submit ボタンをクリックします。たとえばこんな感じで:
2017112104


Submit ボタンをクリックすると(実際には POST /myrecord が実行されて)アドレスのパスが /myrecord に変わります。そして画面には POST /myrecord のフローで最後に定義した HTTP Response ノードから結果(送信データを同じもの)が返されます:
2017112105


同時にこのデータは Cloudant out ノードによって Cloudant の mydb データベースに格納されています。Cloudant のデータベース一覧ページをリロードすると、先程まで文書数がゼロだった mydb データベースに1件データが格納されていることが確認できます:
2017112104


具体的なデータの内容を確認するために mydb データベースを選択して中身を見てみましょう。All Documents を Table 状態で確認すると、一件のドキュメントが格納されていて、その capital は Tokyo、country は Japan となっていることが確認できます。期待通りにデータ保存 API が動いていることが確認できました:
2017112102


次にデータ一覧取得 API の挙動を確認します。その前に同様の手順を繰り返して、もう何件かデータを格納しておきます:
2017112103


とりあえず、以下のような5件のデータが入っている状態にしました。このデータを (3) の API で取り出します:
2017112105


ウェブブラウザのアドレス欄に https://(Node-RED のサーバー名)/myrecords と入力してアクセスします。すると (3) で作成した API が実行され、その結果が返ります。以下のように mydb データベース内の5件のドキュメントレコードが JSON 配列になって返されることが確認できます:
2017112106


API が正しく動くことを確認できたので、改めて HTML の見た目を改良します。(1) の(GET /home のフローの) template ノードの属性にて、HTML の内容を以下のように変更して、デプロイします:
<html>
<head>
<title>Countries & Capitals</title>
<script src='//code.jquery.com/jquery-2.2.4.min.js'></script>
<script>
$(function(){
  $('#myform').submit( function(){
    $.ajax({
      type: 'POST',
      url: '/myrecord',
      data: { country: $('#country').val(), capital: $('#capital').val() },
      success: function( data ){
        console.log( data );
        setTimeout( 'list()', 1000 );
      },
      error: function(){
        console.log( 'error' );
      }
    });
    return false;
  });
  list();
});
function list(){
  $('#list').html( '' );
  $.ajax({
    type: 'GET',
    url: '/myrecords',
    success: function( data ){
      if( data && data.length > 0 ){
        for( var i = 0; i < data.length; i ++ ){
          var doc = data[i];
          var tr = '<tr><td>' + doc.country + '</td><td>' + doc.capital + '</td></tr>';
          $('#list').append( tr );
        }
      }
    },
    error: function(){
      console.log( 'error' );
    }
  });
}
</script>
</head>
<body>
  <table border='1'>
  <thead>
  <tr><th>Country</th><th>Capital</th><tr>
  </thead>
  <tbody id='list'>
  </tbody>
</table>
<hr/>

<form method='POST' id='myform'>
  Country: <input type='text' id='country' name='country' value=''/><br/>
  Capital: <input type='text' id='capital' name="capital" value=''/><br/>
  <input type='submit' value='click'/>
</form>
</body>
</html>

具体的には jQuery で AJAX を使ってシングルページの中でデータの追加と一覧表示ができるようにしています。/home にアクセスしてロードすると、まず現在のデータベース内のレコード一覧が表示され、新しいデータを POST すると一覧が同一ページ内で更新されます:
2017112101


※完成形の Node-RED フロー定義をこちらに用意しました。クリップボード経由で読み込むことで再現できると思います:
https://raw.githubusercontent.com/dotnsf/samples/master/nodered_webapp.json




タイトル通りですが、「『じゃじゃじゃじゃーん』をリズムに変換する Node-RED 用ノード」を作ってみました。


ほとんどの人はこの時点でどんな処理をするノードか理解ができてないと思うので、その補足です。このノードを作るきっかけになったのはこちらのまとめサイトでした:
【超能力者】知恵袋「何の曲か分かりますか?てんてててん てんてんてて」→「戦場のメリークリスマスですね」「なんで分かるんだ!?」


要するに「じゃじゃじゃじゃーん」という日本語テキスト(音階なし、正確なリズムもわからない)だけを頼りに「交響曲第5番、『運命』」のように曲を探し出すという(超)能力を持った人がいて、こりゃすげー!と。

なるほど、面白そうだ。最終的にはこれと同じことをシステム化できないかなあ、と考えているわけですが、その開発の途中で「とりあえずは日本語テキストからリズムを取り出す」仕組みを作り、そこから少々脱線して「その仕組を Node-RED のノードにしてみた」のが今回紹介するノード: node-red-contrib-dotnsf-jajajajan です:
https://www.npmjs.com/package/node-red-contrib-dotnsf-jajajajan

2017092300


利用するにはまず Node-RED 環境を(ローカルでも IBM Bluemix でも)用意し、そこからこのノードを導入します。ローカルであれば以下のコマンドでインストールできます:
$ npm install node-red-contrib-dotnsf-jajajajan

IBM Bluemix の Node-RED の場合はメニューからパレット管理機能を使ってインストールします:
2017101401


パレットの管理画面において「ノードを追加」タブを選び、検索文字列に "jajaja" などと入力すると見つかります(私のミスで複数バージョンが登録されてしまいました。最新バージョンのものを指定して「ノードを追加」してください):
2017101402


この状態で Node-RED を起動すると機能カテゴリ内に音符アイコンの "jajajajan" というノードが追加されて、キャンバス上で使えるようになります:
2017092301


このノードの挙動を確認するために以下のようなシンプルなフローを作ってみます。入力カテゴリの inject ノードと、出力カテゴリの debug ノード、そしてこの jajajajan ノードを配置し、以下のように配線します:
2017092302


inject ノードをダブルクリックして、Payload の種類をデフォルトの timestamp から string に変更し、その値を上記で示したような日本語のリズムテキストにします。以下の例ではまさに『運命』の有名な部分である「じゃじゃじゃじゃーん、ララララーン」としています(「じゃ」でも「ラ」でも同じように処理することができることを確認するため、わざと別の表現にしています)。ここで指定したテキストが msg.payload として jajajajan ノードに渡されて処理されます。入力し終わったら「終了」ボタン:
2017092303


これでフローの準備はできました。動作を確認するため「デプロイ」します:
2017092304


デプロイできたら、画面右ペインを "debug" タブに切り替えたことを確認してから、inject ノードの左にあるボタン部分をクリックします。クリックしたタイミングで指定したテキスト(今回の例では「じゃじゃじゃじゃーん、ララララーン」)が msg.payload として jajajajan ノードに渡されます。
2017092305


クリックすると、不定のタイミングで debug タブに文字が表示されてゆくことが確認できます。このタイミングに関してはネットワーク依存があることと、Node.js 上で動く Node-RED が非同期処理を行うことから必ずしも厳密なタイミングではないのですが、なんとなく「じゃ」「じゃ」「じゃ」「じゃーん」「ラ」「ラ」「ラ」「ラーン」のリズムで1行ずつ表示されている(はず)です:
2017092306


出力されている内容を詳しく見てみると、"8" とか "2" とか数字が表示されています。実はこれは音符の長さを表していて、"8" は「8分音符」、"2" は「半音符(2分音符)」を意味して、その長さに合わせて debug 出力も制御されています。現在の仕様では "8" では 0.5 秒後、"2" では 2 秒後に次の音符が表示されるようにしています(なので "8" の次はすぐに表示されますが、"2" の次が表示されるまでには少し時間がかかります)。結果的になんとなく「じゃ」「じゃ」「じゃ」「じゃーん」「ラ」「ラ」「ラ」「ラーン」というリズムに合わせて1行ずつ表示されているように見える・・・のではないかと思っています(苦笑):
2017092307


試しに『メヌエット』の出だし部分である「タンタタタタタンタンタン」で試すとこんな感じです。最初の「タン」が4分音符で、そこから8分音符が4回続いて・・・というリズムで解釈されていることがわかります:
2017092308


と、またこんなくっだらないノードを作ってしまった。。どうしても使ってみたいという変わった人がいたら使ってください。ちなみにソースコードはこちらです(日本語処理の部分はかなりハードコードに依存しているので、他の言語用に移植するのが難しいかも・・):
https://github.com/dotnsf/node-red-contrib-dotnsf-jajajajan


脱線した話を元に戻すと、このノードで実現している仕組みを使ってテキストをリズムに変えて、取り出したリズムの情報をあらかじめ楽譜を元にリズムだけを取り出した楽曲のデータベースから曖昧検索して近いものを探す、という方法で冒頭で紹介したような超能力者みたいな仕組みをシステム化できないか、と考えています。こちらも諦めているわけではなく、ある程度は動くようになっている(楽譜そのものと、楽譜から主旋律を探す仕組みに苦戦している)ので、人前に出せるようになったら公開するかもしれません。まあ、そうそう簡単なものではないと分かっている上に自分が音楽や楽器が得意ではないので、まだ躓いてすらいない落とし穴が待っているかもしれませんが・・・

複数の楽器向けに書かれている楽譜から主旋律(というのかな?人間がよく知ってるパート)を探す方法を知っている人がいたら教えていただけるとうれしいです。

最近メインの業務が変わって、ずっと勉強モードだったこともあってブログの更新が滞ってました。やっと心に余裕がでてきたので、しばらくシリーズで(比較的簡単な)エントリを続けてみようと思います。

というわけで、今回紹介するのは「Node-RED で REST API を作る」というものです。Node-RED をある程度使っている人ならば「何それ簡単じゃん」と思う程度のことですが、今後引き続いて紹介しようと思ってる内容の導入部分として読んでいただければと。

まず最近話題(になってると感じる)の Node-RED はビジュアルフローエディタです:
2017090801


「ノード」と呼ばれる組み合わせ可能なブロックを順番に配置/接続して、データのフローを定義し、実行します。一通りの作業をブラウザ上の GUI で行うことができる手軽さとわかりやすさが素晴らしいと思っています。Node-RED はラズベリーパイの標準 OS である Raspbian OS にも標準搭載されていますが、IBM Bluemix 環境を使ってすぐにクラウド上の環境を用意することもできます(以下は Bluemix 環境前提で紹介します):
2017090802


Node-RED は基本的に GUI でデータのフローを定義するものであって、ここで作ったものの動きをそのまま視覚化できるわけではありません。ただノードの中にはデータを受け取って HTML ベースのダッシュボードを作るようなものがあったり、HTTP のリクエスト/レスポンスのノードも用意されているので、データを HTML で出力する(そしてそれをブラウザで表示する)といった応用もすぐにできます。今回はこの HTTP リクエスト/レスポンスノードを使って REST API を作ってみます。

Node-RED 画面左のキャンバス部分から、ノードパレットから HTTP リクエストfunctionHTTP レスポンスノードを1つずつドラッグ&ドロップでキャンバスに配置します。この時点でこのような画面になります:
2017090803


これら3つのノードの左右の端をドラッグ&ドロップして以下のように接続します。Node-RED ではデータは左から右に向かって流れていきます。つまりこの場合だと「HTTP リクエスト → function → HTTP レスポンス」という順にデータが送られていくようなフローができました:
2017090804


配置した3つのノードそれぞれの属性を(ダブルクリックして)変更してみましょう。まずは HTTP リクエストノードです。ここは「どのような HTTP リクエストに対して反応するか」を属性で指定します。今回は GET /getDate という日付時刻を返す REST API を作ってみましょう。メソッドは GET 、そして URL には /getDate を指定します。これでこのサーバー上の /getDate に対して GET リクエストが送られてきた場合にこのノードから始まる一連のフローの実行が開始するようになります。編集が終わったら右上の「完了」ボタンをクリックします:
2017090805



なお GET リクエストの場合、URL パラメータで指定された値は msg.req.query 内に格納されます。例えば /getDate?a=x&b=y というリクエストを処理した場合には msg.req.query.a = x, msg.req.query.b = y という値が格納された状態で次のノードが実行されます(といったような情報が画面右の「情報」タブに表示されます。キャンバスで選択中のノードに関する説明はここから参照できます):
2017090801


その次のノードである function ノードは JavaScript を記述することができます。ある意味でビジュアルフローっぽくないというか、一般的なプログラミングに近い処理を行うノードです。今回はこのノードを使って API として返す値(今回の例であれば日付時刻)を生成します。以下のような内容に書き換えます(緑文字部分は処理に関係のないコメントなので不要です):
var dt = new Date();  //. 現在時刻
if( msg.req.query.timestamp ){
  //. timestamp パラメータが指定されていた場合は、そのタイムスタンプの時刻に設定する
  dt.setTime( msg.req.query.timestamp );
}
msg.payload = dt;   //. ペイロードに時刻文字列を設定
return msg;

2017090806




今回作成する API は時刻の文字列を返すようにしました。特にパラメータ指定なしで実行した場合は現在時刻を、timestamp というパラメータが指定された場合はその値をタイムスタンプ値(1970年1月1日午前0時からの経過ミリ秒)と見なして、その日時の時刻を返すようにしています。


そして最後に HTTP レスポンスノードの属性を設定します。普通に動かすだけであれば何も設定しなくても(このままでも)動きます。が、今回は後でこの API を外部の JavaScript からも呼び出せるような設定を加えます(外部からの呼び出しを許可するため、HTTP レスポンスヘッダにクロスオリジンを許可する項目を加えます。詳しくはこちらを参照)。HTTP レスポンスノードのヘッダに Access-Control-Allow-Origin という項目を追加し、その値を * に指定します:
2017090807


これでこの HTTP リクエストは、外部のサーバーから AJAX などで呼び出しても利用できるようになりました。


こうして Node-RED 上に作成したフローを画面右上のボタンから「デプロイ」します:
2017090808


デプロイが成功することを確認します:
2017090802


デプロイが成功したら、ウェブブラウザで http(s)://(Node-RED の動いているサーバー)/getDate にアクセスしてみます。画面に現在時刻が表示されれば成功です(実際には Node-RED が稼働している環境の言語設定などに依存するので日本時間で表示されたり、外国の時間で表示されたりしますが、同じユニバーサル時刻が表示されるはずです。下図では GMT 時間で表示されています):
2017090803


今度は timestamp パラメータを指定して、 http(s)://(Node-RED の動いているサーバー)/getDate?timestamp=1 にアクセスしてみます。これは 1970/01/01 00:00:00 から1ミリ秒経過したタイミングを指定しているので、このような表示になるはずです:
2017090804


と、まずは単純な GET アクセスだけの API を1つだけ作ってみました。Node-RED を使うと最小で3つのノードを組み合わせるだけで簡単に作れることが分かりました。同様にして POST メソッドに対応させたりすることもできますので、興味ある方はチャレンジしてみてください。


なお、Node-RED に関しては最近たて続けに日本語書籍が発表されています。Node-RED そのものに関する情報はこれらの書籍も参考にしてください(↓アマゾンへのリンクです):




 

最近、ボット関連の API や SDK をよく見るわりに、自分では使う機会が少なかったので、今更ながら1つ作ってみました。

今回作ってみたのは「シェルボット」です。名前の通り、ボットでシェルっぽいインターフェースを実現しました。何言ってるかよくわからない人はこちらの画面を参照ください:
2017060901



ボットっぽい対話型インターフェースを使って、対話しているかのようにシェルコマンドを実行します。今回はインターフェースに独自の HTML ページを用意しましたが、ぶっちゃけ LINE などでも(Messaging API を使うなどすれば)応用できると思っています。

#「チャットボット」とは違うけど「ボット」ですっ!


ソースコードを github で公開しておきました。セキュリティ的な面はまだまだ改良の余地があると思っています(rm コマンド他は実行不可にしていますが、本当は他にも実行を制御するコマンドを考慮したほうがいいと思う):
https://github.com/dotnsf/shellbot


↑このソースコードはビジュアルフローエディタである Node-RED で使う前提のものです。(IBM Bluemix などを使って)Node-RED 環境を用意し、func-exec ノードを追加した上でキャンバスに shellbot_nodes.txt の内容をインポートして、ブラウザで /shell にアクセスするだけです(詳しくは README.md 参照)。

#あー、あと今のところ Linux/Unix 系 OS に導入する前提です。


実際に Node-RED 環境上にインポートした様子のスクリーンショットがこちらです。2本のシンプルな HTTP リクエスト処理が定義されているだけのもの(うち1つは HTML 画面定義)ですが、本当にこれだけでこのシェルボットが動きます:
2017060902


実は今まで「ボット」=「チャットボット」=「コンシェルジュ」的なイメージを持っていてハードルが高かったのですが、今回のアプリを作った結果、難しく考えずに「既存アプリケーションのインターフェースを対話型にする」という実装もアリかな、と思うようになりました。


久しぶりに IBM BluemixNode-RED を使ったら、ちょっと挙動というか、使い始めるまでのステップが変わっていたことに気付きました。クラウド環境なので今後も UI 含め色々な変更があるかもしれませんが、このブログエントリを書いている2017年4月18日時点での「Bluemix 環境下での Node-RED の使い方」をまとめてみることにしました。

既に Bluemix や Node-RED を使っている方にとっては復習の部分も多く含まれていると思いますが、ユーザー名やパスワードの設定など比較的最近になって変わった部分もあるので参考にしてください。


まず PC のウェブブラウザ(FireFox, Chrome 推奨)で Bluemix 環境にログインします。アカウントをお持ちでない方は無料体験版のアカウントを申し込むなどしてアカウントをご用意の上でログインしてください。


では早速 Node-RED 環境を用意します。ログイン後のダッシュボード画面で「アプリの作成」をクリックします:
2017041801


Bluemix の Node-RED は「ボイラープレート」の「Node-RED Starter」として簡単に環境が用意できるテンプレートが用意されています。こちらを選択します:
2017041802


これから作成する Node-RED 環境の名称(URL の一部)を入力します。例えばここで test という名称を付けると、デフォルト状態では(カスタムドメインを使わなければ)Node-RED 環境のホスト名は test.mybluemix.net となります。URL の一部になる名称のため、簡単すぎる名前だと既に使われている可能性があり、その場合は利用できません(先に進めません)。例えば (自分の名前)-(日付) など、他と被らないような名称を指定してください(以下の例では dotnsf-nodered-20170418 という名称を指定しています。この場合のホスト名は dotnsf-nodered-20170418.mybluemix.net となります)。指定し終わったら最後に「作成」ボタンをクリックしてこの環境を作成します:
2017041803


(おまけ)
なお、上記画面をよく見ると分かるのですが、この Node-RED Starter ボイラープレートを使って Node-RED 環境を構築すると、Node.js ランタイム(アプリケーションサーバー)と Cloudant NoSQL データベースが1インスタンスずつ作成されます:
2017041804


Node.js ランタイムは Node-RED の実行前提環境として必要なサーバーなのですが、Cloudant の使いみちについて補足しておきます。通常の(Bluemix 環境ではない、オープンソース版の)Node-RED も Node.js サーバー上で動くウェブアプリケーションですが、そのままでは1つのサーバーインスタンス上で稼働する前提の挙動がいくつかあります。具体的にはフロー図の情報などはファイルシステムとして保存しています:
2017041801


そのため、例えばクラウド環境で使う場合のインスタンス数を2つや3つなどに増やした場合、最新の保存情報は複数あるインスタンスのどれかのファイルシステムに保存されている、ということが発生してしまい、インスタンスによって定義されているフローが異なる、という事態が発生してしまいます。そのため負荷が高くなったからといって単純にスケールアウトさせるわけにはいかなくなります:
2017041802



一方、Bluemix 環境ではこの辺りが拡張されており、フロー情報などは全て Cloudant のデータベース内に格納されます(これらのファイルを書き換えるイベントをフックして、ファイルではなくDBを書き換えるような拡張が加えられています)。全てのインスタンスは同データベースにバインドされており、インスタンスの増減があっても常に(論理的に)1つのデータベースに対してこれらの情報を読み書きするため、スケールメリットの大きなクラウド環境においても Node-RED が安心して利用できる環境となっています。ここも Bluemix で Node-RED を利用する上でのメリットだと思っています:
2017041803


(おまけおわり)


話を戻します。Node-RED ボイラープレートから「作成」ボタンを押すと一瞬画面が暗転して・・・
2017041804


しばらくするとこの環境(Node.js + Cloudant NoSQL の2つのサーバー)を作成中のステータスに変わります。しばらくお待ち下さい:
2017041805


しばらくするとステータスが「実行中」に変わります。この段階では Node-RED が利用できるようになっているので、横のホスト名部分をクリックして、Node-RED にアクセスします(ここまでは今までの Node-RED と同じです):
2017041806


最新の Bluemix の Node-RED はここからが少し変わりました。以前はここから早速フローエディタが使えるようになっていましたが、現在はもう1段階の簡易設定を行う画面に移行します。まずは Next をクリック:
2017041807


Node-RED のフローエディタにアクセスできる人を制限する設定画面が表示されます。上の "Secure your editor as only authenticated users can access it" にチェックを入れると、その下に指定するユーザー名/パスワードを入力できた人だけが編集できるようになります。なお、更にその下の "Allow anyone to view the editor, but not make any changes" にチェックすると、「誰でもフローエディタを見ることはできるが、変更はできない」というモードになります(下図ではチェックしていません):
20170418075


一方、下のように "Not recommended: Allow anyone to access the editor and make changes" にチェックを入れると(これまで同様に)URL を知っている誰もがフローエディタにアクセスし、変更できるようになります。このいずれかをチェックした上で "Next" をクリックします:
2017041808


後で詳しく説明しますが、標準の Node-RED には含まれていない拡張機能を後から追加することもできるようになっています。そのような拡張機能の代表的なものが紹介されています:
2017041809


例えば node-red-dashboard という箇所をクリックすると、ダッシュボード機能を追加する拡張モジュールの説明が表示され、内容を確認できます。このモジュールの追加方法については後述します:
20170418095


最後に設定内容の確認を行います。なお、ここで行った設定については実行環境の環境変数でも挙動を指定/変更することが可能です。最後に "Finish" をクリックします:
2017041810


すると一瞬このような画面になってから・・・
2017041811


改めて Bluemix 環境での Node-RED のスタート画面が表示されます。ここでは "Go to your Node-RED flow editor" ボタンをクリックしてフローエディタ画面に移動します:
2017041812


先程の画面でパスワードによる認証が設定されていると、ここでユーザー名とパスワードを入力する画面になります:
2017041813


設定時に自分で指定したユーザー名/パスワードを入力して「ログイン」します:
2017041814


正しい情報が入力されていると、Node-RED フローエディタ画面に移動します。これで Bluemix 環境下の Node-RED が利用できるようになりました:
2017041815



さて、比較的最近のアップデートで Node-RED 環境に GUI 操作でカスタムノードモジュールを追加できるようになりました(今まではソースコードの package.json を編集する必要があったので、それを意識せずに環境を構築できる Bluemix ではこの作業のためにソースコードを用意する必要があったりして不便に感じていました)。最後にその方法を紹介しながら、先程参照したダッシュボード機能のモジュールを追加してみます。Node-RED 画面右上のハンバーガーメニューから「処理ノードの追加削除」を選択します:
2017041801


すると画面左に「処理ノードの追加削除」というペインが現れ、ここで現在利用中のノードモジュールの一覧を参照したり、追加/削除といったカスタマイズが可能になります:
2017041802


ここで「処理ノードを追加」タブを選び、検索フィールドに dashboard と入力すると、検索結果一覧の中に "node-red-dashboard" が出て来るはずです(似た名前もあるので注意)。これを選んで「処理ノードを追加」ボタンをクリックします:
2017041807


ノードを追加インストールする確認メッセージが表示されます。ここでは "Install" を選択:
2017041803


しばらくするとノードが追加され、成功を示すメッセージが(一瞬)表示されます:
2017041804


この状態でノード一覧を下の方にスクロールすると、"dashboard" カテゴリの中にいくつもの node-red-dashboard ノードが追加されたことが確認できるはずです。またこの dashboard ノードが利用するための "dashboard" タブが右ペインにも追加されているはずです:
2017041806


動的なノード追加も簡単にできるようになっていることが確認できました!








 

このページのトップヘ