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

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

タグ:nodejs

私自身、ふだん CMS (コンテンツ管理システム)といえばワードプレスを使うことが多かったのですが、思い立って自分でも CMS を作ってみることにしました。それもせっかくなので(?)あまり例のない Node.jsIBM Cloudant をベースとした、IBM Cloud 環境向きのインフラで実装し、かつオプションで、この中で管理するコンテンツが IBM Watson の自然言語分類機能の学習コンテンツにできるような機能も付与して BlueCMS という名称で github.com で公開しました:
https://github.com/dotnsf/bluecms

使い方やセットアップ手順は README.md に(英語で)記載していますが、いちおうここでは日本語で(図解入りで)、2017/Jul/11 時点での実装内容やセットアップ手順を紹介します。

なお、このブログエントリのタイトルで「IBM Cloud 向き」と表現していますが、この意図は「IBM Cloud (の PaaS)を使うとセットアップが楽」という意味であって、普通の PC や仮想環境、各種 IaaS サーバーなどからでもセットアップ可能です(ただし IBM Cloud の Cloudant は必要です)。


BlueCMS はコンテンツ管理システムの実装の1つです。現時点では機能的にはまだまだ足りない部分もあると思いますが、CMS としての最小限の機能に加えて、以下のような特徴を持っています:
(1) 実装は Node.js、データストアには IBM Cloudant を利用
(2) IBM Cloud のライトアカウント(無料版)でも使える
(3) コンテンツ管理だけでなく、ユーザー管理機能を内蔵している
(4) 添付ファイルを格納することもできる(IBM Cloudant 内にバイナリデータとして格納)
(5) IBM Cloud ライトアカウントの範囲ではないが、IBM ワトソンと連動する機能をビルトインで使える
(6) ソースは MIT ライセンスで公開


BlueCMS そのものは IBM Cloud 以外の環境でも動きますが、IBM Cloud のアカウントを所有していると PaaS の機能を活用して比較的すぐ&簡単に環境構築できます。なお BlueCMS 自体は無料のライトアカウントでも(他にランタイムやサービスを使っていなければ)環境構築可能ですが、後述するオプションのワトソン NLC(Natural Language Classifier) 機能を利用する場合はクレジットカードを登録してスタンダードアカウント等にしておく必要があります(その場合でも利用量によっては無料枠内で運用可能です)。


セットアップ手順

IBM Cloud アカウントを所有している場合、以下の4ステップで最低限の動作環境を構築します:

(1) インフラ(ランタイムインスタンスとサービスインスタンス)の作成

とりあえず IBM Cloud にログインします:
2018071001


まず BlueCMS を実行するための Node.js ランタイムを作成します。ログイン直後の画面(ダッシュボード)右上の「リソースの作成」ボタンをクリックします:
2018071002



「Compute」カテゴリーから「SDK for Node.js」ランタイムを選択します:
2018071102


ランタイムを作成する場合は名称と地域に注意が必要です。名称は URL の一部になるためユニークな文字列を指定します(下図では bluecms としていますが、この名称は僕が使っているので使えません)。また地域はどこでもいいのですが、以降で Cloudant や NLC を作成する場合に同じ地域を指定する必要があるので、どこを選択したかを覚えておきましょう。最後に「作成」ボタンをクリック:
2018071004


これで Node.js のランタイム(アプリケーションサーバー)を作ることができました:
2018071005


このまま次のステップに移りますが、ダッシュボードへの戻り方をガイドしておきます。IBM Cloud の画面のどこからでも画面左上の三本線メニュー(「ハンバーガーメニュー」)からダッシュボードに戻ることができます。まずはここをクリック:
2018071006


そしてポップアップメニューから「ダッシュボード」を選択します。これでダッシュボードに戻ります:
2018071007


ダッシュボードに戻ると、上記で作成したランタイムが一覧に加わっていることが確認できるはずです:
2018071008


次にデータをストアするための IBM Cloudant サービスインスタンスを作成します。やはりダッシュボードから「リソースの作成」をクリックし、今度は「Databases」カテゴリの「Cloudant」を選択します:
2018071103


サービスの地域は先程 Node.js ランタイムを作成した時と同じ地域を選択し、またプランは "Lite" を選択しておくと容量やトランザクションパフォーマンスに制約があるものの、料金はかかりません。最後に「作成」をクリック:
2018071010


これだけで IBM Cloudant のインスタンスを作ることができました:
2018071011


なお Cloudant のライトプランでの制限やライトプラン以外での料金についてはこの画面内の記述を参照してください。ライトプランの場合、容量は 1GB、パフォーマンスとしては 20 データ読み取り/秒、10 データ書き込み/秒、5 データクエリー/秒となります:
2018071105



有料アカウントを利用している場合で、かつワトソン連携機能を有効にしたい場合は IBM Watson NLC サービスインスタンスを作成します。再度ダッシュボードに戻り、「リソースの作成」から「AI」カテゴリーの「Natural Language Classifier」を選択します:
2018071101


こちらでも Node.js ランタイムを作った時と同じ地域を選択し、「作成」をクリックします:
2018071013


なお NLC の料金や無料枠についてはこの画面内の記述を参照してご注意ください。1ヶ月あたりで最初の1インスタンス、4 回の学習実行、1000件の問い合わせまでは無料ですが、それらを超えた分は課金対象となります:
2018071104


こちらもサービスを作ることができました:
2018071014


ここまでの作業でアプリケーションサーバーとデータベース(、とオプションでワトソン)の各サービスが IBM Cloud 内で有効になりました。 PaaS だとこういう所が簡単で便利です:
2018071003



(2) ランタイムとサービスのバインド

IBM Cloud を利用している場合、ランタイムとサービスをバインドすることで面倒な認証情報の設定や交換を安全かつ簡易化することができます。BlueCMS はこの仕組に対応しているので、そのための設定を行います。

まずダッシュボードを表示し、ランタイム一覧から作成した Node.js ランタイムを選択します:
2018071015


現在のランタイム動作状況が確認できる画面が表示されます:
2018071016


ここで画面左のメニューから「接続」を選択します。バインド済みサービスの一覧が表示されますが、この時点では何もバインドされていないので、何も表示されません。ここに上記で作成した IBM Cloudant(とワトソン NLC)サービスをバインドします。「接続の作成」ボタンをクリックします:
2018071017


バインド可能なサービスの一覧が表示されます。上記のインスタンス作成の過程で作成地域が全て同じであれば、この一覧の中に IBM Cloudant (とワトソン NLC)が含まれているはずです。まずは IBM Cloudant サービスを選び(マウスオーバーし)、「Connect」ボタンをクリックします:
2018071018


環境を再ステージングするか、という確認ダイアログが表示されるので「再ステージ」を選択して、再起動します。再起動が完了するまで5分弱かかります:
2018071019


再ステージが完了すると、Node.js ランタイムに IBM Cloudant がバインドされた状態になり、接続一覧からも確認できるようになります:
2018071020


ワトソン NLC サービスも作成している場合は、こちらも続けてバインドします。接続メニューの一覧から NLC を選択(マウスオーバー)し、「Connect」をクリックします:
2018071021


こちらも再ステージして、Cloudant と NLC 両方のサービスがバインドされた状態になりました:
2018071022


ここまでの作業で作成した各インスタンスがバインドされ、連携できる準備が整いました:
2018071004



これでアプリケーションインフラ部分の構築が完了しました。後は BlueCMS の中身をアップロードするだけです。


(3) ソースコードの用意とランタイムにプッシュ

あとは BlueCMS のソースコードを用意して、ランタイムにプッシュ(転送)すればいいのですが、そのためには cf というツールを使います。最初に cf ツールをダウンロード&インストールします:
https://github.com/cloudfoundry/cli/releases

上記ページから自分の環境にあった cf ツールをダウンロードしてインストールします。

改めて、いよいよソースコードを用意します。github のリポジトリからソースコードを git clone するか、(その意味がわからなければ)zip ダウンロード&展開します:
2018071001


本来であればここで認証情報の取得や設定が必要になるのですが、IBM Cloud を使っているとその部分を上記の「バインド」設定で済ませていることになります。設定を行う場合はソースコード内の settings.js 内の各種値を変更します(IBM Cloud 環境を使う場合、変更する必要があるとしたら exports.search_analyzer(検索インデックスで使う言語)と、exports.nlc_language(ワトソン NLC の学習時に指定する言語)くらいです。コンテンツが日本語の場合はともに変更の必要はありません):
2018071002


settings.js の準備が完了したら、いよいよ cf を使ってコードをランタイムにプッシュします。コマンドプロンプトやターミナルを開き、まずは cf コマンドで IBM Cloudant にログインします(ログインパスワードを聞かれるので入力します):
$ cf login -a https://api.ng.bluemix.net/ -u (IBM Cloud のログイン名)

ログインできたらランタイムにプッシュするだけです:
$ cf push (ランタイムの名前(上記例だと bluecms となっている所に指定したもの))

プッシュが成功すると BlueCMS が Node.js ランタイム上で動き出します。BlueCMS は起動と同時に Cloudant 上にデータベースをインデックスごと作成するので、あらかじめ Cloudant 側で準備しておく必要はありません:
2018071005


まだ必要な管理用/編集用のユーザーを作っていないため投稿はできないのですが、この時点でトップページを表示することはできます。

ウェブブラウザで https://(ランタイム作成時に指定したアプリケーション名).mybluemix.net/ にアクセスします:
2018071000
 (まだ中身がないので今はこれだけ)

↑こんな感じのトップ画面が表示されればほぼ完成、あともう少しです!


(4) 最初の管理ユーザー ID の作成

(注 この部分の手順は将来変更の可能性がありますが)専用の API を使って BlueCMS の最初の管理ユーザーを作成します。

BlueCMS には2種類のユーザーがいます。1つが管理者ユーザー、もう1つが編集者ユーザーです。BlueCMS のコンテンツを作成/編集することができるのは管理者ユーザーと編集者ユーザーで、ユーザーの作成/変更/削除といったことができるのが編集者ユーザーです。

BlueCMS の場合、ログインしなくてもコンテンツの一覧や1つ1つを参照することはできます。ただコンテンツの中身を編集したり、編集者ユーザーを登録したりするにはユーザー登録が必要になります。これらの編集/登録作業は BlueCMS にログインした後のコンソールから行うことが可能ですが、一番最初の管理者ユーザーだけは(まだ誰もコンソールにアクセスできないため)別の方法で作成する必要があります。その方法を以下に紹介します。

最初の管理者ユーザーは curl コマンドを使って、以下の REST API を使って作成します:
$ curl -XPOST -H 'Content-Type: application/json' 'https://(ランタイム作成時に指定したアプリの名前).mybluemix.net/adminuser' -d '{"id":"abc@xyz.com","password":"yourpassword","name":"yourname","email":"abc@xyz.com"}'

-d オプションに続いてパラメータが指定されています。それぞれ以下のような意味があります:
 id: ログインID(ログイン時に指定するユーザーID)
 password: ログインパスワード(ログイン時に指定するパスワード)
 name: 画面に表示される時の名前、省略時は id が使われる
 email: メールアドレス、省略時は admin@admin となる


管理者権限で編集することはあまり想定しておらず、あくまで管理者権限で編集者を作成し、編集者権限でログインしてコンテンツを編集、することを想定しています。そのためこの最初の管理者ユーザーはどちらかというと「編集者ユーザーの管理者」的な位置づけになりますが、その管理者ユーザーを上記コマンドで作成しました:
2018071006


このコマンドが成功(結果に status:true が含まれている)すれば、このユーザーで BlueCMS にログインすることができるようになります。これで BlueCMS を使うために必要な最低限の準備は完了です。


ログイン

では作成した管理者ユーザーでログインしてみます。ウェブブラウザで https://(ランタイムに作成したアプリ名).mybluemix.net/ にアクセスし、画面右上の login ボタンをクリックします:
2018071000


ログインフォームが表示されたら、先程の REST API で作成した管理者ユーザーの id とパスワードを指定して login をクリックします:
2018071001


正しい情報が指定されていればログインし、管理用コンソールに移動します:
2018071002


この管理用コンソールでユーザーの作成/編集/削除を行ったり、コンテンツの作成/編集/追加、添付ファイルの作成と削除を行うことができます。その使い方についてはまた別の機会に、とりあえず BlueCMS とその初期セットアップ方法の紹介でした。


(2018/Jul/12 追記)
続きの使い方の説明はこちら:
ワトソン対応の IBM Cloud 向き CMS "BlueCMS" を公開しました(使い方)


Node.js を使っていて 404 エラーや 500 エラーなどが発生した場合に表示されるエラーページをカスタマイズできないか、と思って挑戦してみました。

今回挑戦した環境では Node.js にフレームワークの Express と、テンプレートエンジンに EJS を使いました。エラーページを EJS で作ることを想定しています。

まず、JavaScript のコードはこんな感じです:

app.js
// app.js
var express = require( 'express' );
var app = express();

//. EJS テンプレートエンジン
app.set( 'views', __dirname + '/templates' );
app.set( 'view engine', 'ejs' );

//. / へのアクセスは正常にできる
app.get( '/', function( req, res ){
  res.render( 'index', {} );
});

//. /err へのアクセスは 500 エラーとする
app.get( '/err', function( req, res ){
  res.render( 'index', { value: novalue } ); //. novalue 変数が未定義なので 500 エラーが発生する
});

//. 有効なルーティングを上記に記述
//. /, /err 以外のパスは 404 エラー

//. 404 エラーが発生した場合、
app.use( function( req, res, next ){
  res.status( 404 ); //. 404 エラー
  res.render( 'err404', { path: req.path } ); //. 404 エラーが発生したパスをパラメータとして渡す
});

//. 500 エラーが発生した場合、
app.use( function( err, req, res, next ){
  res.status( 500 ); //. 500 エラー
  res.render( 'err500', { error: err } ); //. 500 エラーの内容をパラメータとして渡す
});

var port = 3000;
app.listen( port );
console.log( 'server started on ' + port );

上記を補足すると、Express でルーティングを2つ定義しています。1つめがドキュメントルート(/)へのアクセスで、この場合は正常な処理として(後述の)index.ejs を表示します。

2つめは /err へのアクセスで、こちらの場合はわざと 500 エラーを発生させています(index.ejs でページを表示させるような記述にしていますが、実際にはこの中で使われている novalue という変数が未定義なので、そこで 500 エラーが発生するようにしています)。

ルーティングとしてはこの2つ(/ と /err)だけを定義しているので、これら以外のパス(例えば /home)にアクセスがあった場合は 404 エラーが発生します。404 エラーが発生した場合の処理としては err404.ejs というテンプレートを使って、アクセスしたパス(/home)が存在していない、という旨のエラーページを表示します。

最後に 500 エラーが発生した場合の処理を定義しています。ここでは err500.ejs というテンプレートを使って、エラーの内容をあわせて表示します。上記で /err ページにアクセスすると 500 エラーが発生するので、この err500.ejs のページが表示されることになります。


次に上記で使うことにした3種類のテンプレート(index.ejs, err404.ejs, err500.ejs)を用意します。それぞれ以下のような内容にしました:

index.ejs
<html>
<head>
<title>index</title>
</head>
<body>
<h1>index</h1>
</body>
</html>
↑単に index と表示されるだけのシンプルなページ


err404.ejs
<html>
<head>
<title>err404</title>
</head>
<body>
<h1>err404</h1>
<%= path %> is not defined nor found.
</body>
</html>
↑ "(エラーがあったパス)is not defined nor found." というエラーメッセージが表示されるページ


err500.ejs
<html>
<head>
<title>err500</title>
</head>
<body>
<h1>err500</h1>
Error: <%= error %>
</body>
</html>
↑ "Error: (エラー内容)" というエラーメッセージが表示されるページ


app.js ではこれらのテンプレートファイルが templates/ フォルダに存在していることを前提に参照するようにしています。したがって templates/ フォルダを作って、その中にこれら3つの .ejs ファイルを格納しておきます。これで準備OK。


実際に動かして試してみました。まずは正常系、/ へのアクセスは普通に問題なくできます:
2018070401


次に /home にアクセスして、わざと 404 エラーを発生させてみた時の画面です。err404.ejs で定義されたテンプレートを使って期待通りにエラーページが表示されています:
2018070402


最後に /err にアクセスして、わざと 500 エラーを発生させてみた時の画面です。こちらも err500.ejs で定義されたテンプレートを使って期待通りにエラー内容が表示されています:
2018070403


上記コードのサンプルをこちらに用意しました:
https://github.com/dotnsf/nodejserror


これで Node.js でもカスタムエラーページを作れることがわかりました。

IBM Cloud から提供されている IoT サービスである IBM Watson IoT Platform (の QuickStart)にメッセージをパブリッシュする Node.js のサンプルアプリケーション(とソースコード)を作って公開しました:
https://github.com/dotnsf/mqtt_pub_ibmiot

2018051501


主要なソースコードは app.js だけですが、内部的に MQTT.js ライブラリを使っています:
2018051500


主な挙動としては settings.js で指定された内容に併せて、1秒(デフォルト)ごとに0から1つずつ増えるカウンタ値、タイムスタンプ値、実行したマシンの CPU 稼働率、12回周期のサイン値およびコサイン値、そしてランダムな値が JSON で IBM Watson IoT Platform の QuickStart に送られます。その際のデバイス ID 値は settings.js 内で指定されていればその値が、されていなければ動的に生成されるようにしました。


IBM Cloud 環境で Node-RED ランタイムを作ると動作を確認しやすく、またそのためカスタマイズの勘所が分かりやすいと思っています。以下、この環境での動作確認方法を紹介します。

まずはこのサンプルを動かす前提として Node.js がインストールされたマシンが必要です。Windows/MacOS/Linux/Raspberry Pi などなど、Node.js をインストール可能なマシンで導入を済ませていると仮定して以下を続けます。

次に上記リポジトリから git clone またはダウンロード&展開して、アプリケーションのソースコードを手元に用意します:
$ git clone https://github.com/dotnsf/mqtt_pub_ibmiot
$ cd mqtt_pub_ibmiot

必要に応じてテキストエディタで settings.js の中身を編集します。とはいえ、変える必要がありそうなのは exports.interval の値(メッセージデータを送信する時間間隔(ミリ秒)。デフォルト値は 1000 なので1秒ごとにメッセージを送信する)と、exports.deviceId の値(後で指定するデバイス ID。デフォルトは空文字列なので、後で自動生成された値になります)くらいです。なお、settings.js の値は変えなくても動きます。


※もし exports.deviceId の値を編集する場合は、("test" のような簡単な単語ではなく)他の人が使わないようなユニークな値になるよう指定してください。exports.deviceId の値をデフォルトのから文字列のままにする場合は、実行時ごとにデバイス ID を生成するので、この値は実行ごとに変わることに留意してください。


ではアプリケーションの動作に必要なライブラリをインストールします:
$ npm install

そして実行します:
$ node app

実行が成功して IBM Watson IoT Platform に接続すると、"client#connect: " という文字列に続いてデバイス ID が画面に表示されます(以下の例では 5d7436e992d0)。この値は settings.js で指定した場合はその値が、指定しなかった場合は自動生成された値が表示されます。この後で使うのでメモしておきます:
2018051502


※なお、メッセージを送信しているアプリケーションの終了方法は特に用意していないので、終了する場合は Ctrl+C で強制終了してください。


これでサンプルアプリケーションが IBM Watson IoT Platform に接続し、exports.interval で指定した値の間隔でメッセージデータを送信し続けている状態になりました。

最後にこの送信データを Node-RED で確認してみます。IBM Cloud で Node-RED ランタイムを作成し、IBM IoT のインプットノード(右側にジョイントのあるノード)と、debug アウトプットノードをキャンバスに配置して接続します:
2018051503


↑IBM Watson IoT Platform サーバーにメッセージが送られてきたらその payload の内容をデバッグタブに表示する、というシンプルなフローです。


IBM IoT インプットノードをダブルクリックし、Authentication が Quickstart になっていることを確認した上で、Device Id 欄に先程確認した実行中アプリケーションのデバイス ID を指定します。そして「完了」してから、このアプリケーションを「デプロイ」します:
2018051504


すると、Node-RED 画面右のデバッグタブに(デフォルトであれば)1秒おきにメッセージが追加されていく様子が確認できるはずです:
2018051505


メッセージの1つを選んで展開してみると、元のアプリケーションから送信されたカウント値(count)、タイムスタンプ値(timestamp)、CPU稼働率(cpu)、サイン値(sin)、コサイン値(cos)、そして乱数値(random)が確認できます。つまり Node.js を使って動かしたアプリケーションから MQTT 経由で実際にデータが送信されていて、その内容を Node-RED と IBM IoT インプットノードを使って取り出して確認できたことになります:
2018051506


送信データをカスタマイズしたり、別の値を送信したい場合は app.js をカスタマイズして、publish 時に送信する data 変数の中身を変える(必要な値を取得して、この中に JSON で入れる)ということになります。こちらはシンプルなのでなんとなく理解できるんじゃないかな・・・と期待しています。


また Node-RED の場合であれば node-red-dashboard と組み合わせることで、ここで取得した値を簡単にチャート化することもできます。例えば Gauge ノードと Chart ノードを使って CPU 負荷とサインカーブをこんな感じで・・・
2018051600


IBM Watson IoT Platform の Quickstart にデータを送信するサンプルとして使ってくださいませ。

たまに子供や初心者を相手にプログラミングを教えてみせたりする際に Scratch を使っています:
Screenshot from 2018-05-04 15-28-23


MIT メディアラボが開発した GUI によるプログラミング開発言語および実行環境です。プログラムをエディタでガリガリと記述するような、いわゆる「コーディング」に相当する作業があまり必要なく、GUI を中心とした見た目に対する処理や変更をイベント単位に足していきながら少しずつ動くものを作っていくものです。そのためユーザーが完成形をイメージしながら作っていくことができ、コーディングそのものに不慣れな人がプログラミングを理解するのに向いていると思っています。

この Scratch は良くも悪くも GUI 中心の作業になるため、他の環境との連携が難しい(というか、そもそもどういう外部インターフェースが用意されているのかわかっていなかった)という印象を持っていました。Scratch の閉じた世界の中では初心者にも簡単でわかりやすい、という面があるのと同時に、Scratch 以外の環境とは繋がりにくいと思っていました。

で、なんかインターフェースが公開されてないかなあ・・・ と思って探していたら、この Scratch の国内第一人者でもある石原さんが書かれた一連のブログを見つけました:
Scratch(スクラッチ)を外部のプログラムなどとつなぐ「遠隔センサー接続」を解説する(その1)


↑このブログで書かれている内容は Scratch 1.4 の「遠隔センサーを有効に設定」して 42001 番ポートを開放した上で、TCP/IP のメッセージングによる連携を Ruby で行う、というものです。基本的にはほぼ同じ内容を Node.js で実装してみようと思い、調べた結果をまとめました。


なお、石原さんは「まちくえすと」の開発などで活躍されていてご存知の方もいらっしゃると思いますが、拙作マンホールマップiOS アプリ版の開発に尽力いただいたご縁もあり、そのお付き合いの中で Scratch のことも教えていただきました。僕にとっては「Scratch の先生」でもあります。石原さん、このブログとても助かりました。ありがとうございます!



まず、以下の作業を行う前提として、Scratch はローカルインストール可能なバージョン 1.4 を使う必要があります。公式サイトからオンライン版であるバージョン 2.0 以降を利用することも可能ですが、以下で紹介する Node.js 連携は Scratch 1.4 をローカルインストールして使う想定で記載しています。各種 OS 向けの Scratch 1.4 はこちらからダウンロードして導入してください(以下、Ubuntu 16.04 環境に Scratch 1.4 を導入した前提で記述します):
https://scratch.mit.edu/scratch_1.4/



まず最初に、Scrach を外部連携するためのポート開放を行います。Scratch 1.4 を起動し、「調べる」カテゴリ内「●●センサーの値」と書かれたブロックを右クリックして、「遠隔センサー接続を有効にする」を選択します:
Screenshot from 2018-05-04 15-29-09


すると「遠隔センサー接続が有効になりました」という確認ダイアログが表示されます:
Screenshot from 2018-05-04 15-29-39



この作業後、Scratch は 42001 番ポートで接続できるようになっています。つまり僕の以前のブログで紹介したような TCP/IP プログラミングによって Scratch との TCP/IP 接続が可能になっているのでした。試しに以下のような Node.js プログラム(scratch01.js)を書いて実行してみます(以前のブログで書いたものよりも更に簡略化し、最小限必要な内容だけにしています):
var net = require( 'net' );

//. 接続先 IP アドレスとポート番号
var host = '127.0.0.1';
var port = 42001;

//. 接続
var client = new net.Socket();
client.connect( port, host, function(){
  console.log( '接続: ' + host + ':' + port );
});

//. サーバーからメッセージを受信したら、その内容を表示する
client.on( 'data', function( data ){
  console.log( '' + data );
});

↑このプログラムを実行すると、127.0.0.1(自分自身)の 42001 番ポートに TCP/IP 接続し、接続先から何かメッセージが送られてくるとそのメッセージ内容を文字列化してそのまま表示する、というものです。これをまず node コマンドを使って実行しておきます:
$ node scratch01.js

これで 42001 番ポートに接続し、メッセージの受信待ち状態になりました。


そして Scratch 側からはこの(42001 番ポートの)接続先に対してメッセージを送信してみます。この処理を行うには「制御」カテゴリ内「●●を送る」ブロックを使います:
Screenshot from 2018-05-04 15-40-55


同ブロックを右クリックして「新規」を選択し、メッセージの名前を任意に指定します。以下の例ではメッセージの名前に Hello と指定してます:
Screenshot from 2018-05-04 15-42-14


するとブロックの表示内容が「Hello を送る」と切り替わります。この状態で同ブロックを何度かマウスでクリックします(クリックするたびにこのブロックが処理を実行します):
Screenshot from 2018-05-04 15-42-41


すると先に実行していた Node.js プログラムのコンソール画面に(最初の制御文字に続いて) 
broadcast "Hello"
という文字行がクリックするたびに表示されます:
Screenshot from 2018-05-04 15-46-59


この結果から Scratch の「●●を送る」ブロックを1回実行すると
broadcast "(指定したメッセージ)"

という文字列が送信される、ということが分かりました。これで Scratch から Node.js のプログラムにメッセージを送信し、Node.js プログラム側でその内容を受信することができました。


この応用で逆に Node.js から Scratch にメッセージを送ることもできます。例えば scratch02.js を以下の内容で作成します(接続後に 'broadcast "a"' というメッセージを Scratch に送信する、という内容です):
//. scratch02.js
var net = require( 'net' );
var host = '127.0.0.1';
var port = 42001;

var client = new net.Socket();
client.connect( port, host, function(){
  console.log( '接続: ' + host + ':' + port );

  var msg = 'broadcast "a"';
  var len = msg.length;
  var buf = pack( len );
  client.write( buf + msg );  //. msg の内容を Scratch へ送信
});

//. 4バイトのバイト列(Buffer)に変換
function pack( n ){
  var m1 = n % 256;
  n = Math.floor( n / 256 );
  var m2 = n % 256;
  n = Math.floor( n / 256 );
  var m3 = n % 256;
  var m4 = Math.floor( n / 256 );

  return new Buffer( [ m4, m3, m2, m1 ] );
}



そして Scratch 側では 'broadcast "a"' というメッセージを受け取ったら何らかの処理がスタートする、というプログラムを書いておきます(下の例ではスプライト1の猫のキャラクターが画面内を歩き始める処理がスタートする、という内容にしています):
Screenshot from 2018-05-05 15-54-06


この状態で scratch02.js を実行すると、TCP/IP 通信によって Scratch に接続し、broadcast "a" というメッセージが送られ、Scratch のスプライト1のキャラクターが壁に跳ね返りながら動き回る処理がスタートします(特に止める方法を用意していないので、止めるには画面右上の赤丸部分をクリックしてください):
Screenshot from 2018-05-05 16-02-12


これで Scratch から Nodejs にメッセージを送ったり、逆に Node.js から Scratch にメッセージを送る、ということが実現できました。

 

Node.js はサーバーサイドで動く JavaScript ということもあって、Express などを使ってサーバーサイドのアプリケーションランタイムとして利用することが多いと思っています。

が、必ずしもサーバーサイド開発言語にのみに使えるということはなく、クライアント側のアプリケーションを記述・実行することも可能です。そんな一例として(HTTP よりも汎用的な)TCP/IP を使ったクライアントアプリケーションを作るサンプルを紹介します。

以下は 127.0.0.1 の 42001 番ポートで待ち受けるサーバーに対して、クライアントとして接続したり、メッセージを送信したり、受信したり、切断したときの挙動を実装しています:

var net = require( 'net' );

//. 接続先 IP アドレスとポート番号
var host = '127.0.0.1';
var port = 42001;

//. 接続 var client = new net.Socket(); client.connect( port, host, function(){ console.log( '接続: ' + host + ':' + port ); //. サーバーへメッセージを送信 client.write( 'ハロー' ); }); //. サーバーからメッセージを受信したら、その内容を表示する client.on( 'data', function( data ){ console.log( data ); }); //. 接続が切断されたら、その旨をメッセージで表示する client.on( 'close', function(){ console.log( '切断' ); })

実際の挙動としてはサーバーへメッセージを送る必要があるのかないのか、サーバーからメッセージを受信することがあるのかないのか、・・・といったサーバー側の挙動も考慮してクライアント側を作ることになりますが、特定のポートに対する TCP/IP 接続はこんな感じで実現できるようです。

このページのトップヘ