Node.js 版 Scratch 2 HTTP拡張ヘルパーを作ろう
Node.js + express で作成したものを、zeit/pkg を使って各OSの実行形式ファイルにするテストも行います。
ブラウザ(Chromium)は含める必要がないため、Electron より軽量(小さいファイルサイズ)になるはずです。
Scratch 2 とHTTP拡張ヘルパー
HTTPサーバ (ヘルパーアプリ) を用意すると、ブロックプログラミングの Scratch 2(オフライン版)に独自機能(拡張ブロック)を加えることができます。
こちらの記事ではPython + aiohttpでヘルパーを作成しましたが、これを Node.js + Expressで作成してみます。さらに、それを Node.js がインストールされていない環境で使用するために、 Windows の実行形式にしてみます(Mac や Linux も出来ますが実行できるかは手元に環境がないため未テスト)。
ここで作成するヘルパーは簡易HTTPサーバ
Scratch 2 (offline版) の拡張ブロックには、Scratch側からコマンドを送る「コマンドブロック」(四角い形のブロック)と、Scratch側で値を受け取る「レポーターブロック」(角の丸い形のブロック)など、いくつかの種類があります。いずれも Scratch側から GET を送っており、値を受け取るときもポーリング方式をとっています。したがって、Scratch からの GET を待ち受けるような簡易ローカルHTTPサーバを作成してそこで何か処理を行うようにすれば、新たな機能を拡張ブロックとして追加できます。
こちらの記事のように、Python版では aiohttp を使って以下のようなコードにしました。
from aiohttp import web
volume = 0
async def handle_poll(request):
text = "volume " + str(volume) + "\n"
return web.Response(text=text)
async def handle_beep(request):
print("play beep!")
print("\007")
return web.Response(text="OK")
async def handle_setvolume(request):
global volume # 忘れずに
tmp_volume = int(request.match_info['vol']) # いったん別の変数へ
if tmp_volume >= 0 and tmp_volume <= 10:
volume = tmp_volume
print("set volume= " + str(volume))
else:
print("out of range: " + str(tmp_volume))
return web.Response(text="OK")
app = web.Application()
app.router.add_get('/poll', handle_poll)
app.router.add_get('/playBeep', handle_beep)
app.router.add_get('/setVolume/{vol}', handle_setvolume)
web.run_app(app, host='127.0.0.1', port=12345)
なお volume
という変数名ではありますが、この実装では音量が変わるわけではないです・・(単に値のやりとりのテストです。)
Express + Node.js 版
上記のコードを Express + Node.js で作ると以下のようになります。
"use strict";
var express = require('express');
var app = express();
var server = app.listen(12345, function(){
console.log("Server start... listening port " + server.address().port);
});
var volume = 0;
app.get('/poll', (req, res) => {
res.send("volume " + volume);
});
app.get('/playBeep', (req, res) => {
console.log("play beep!");
process.stderr.write("\x07"); // to prevent new line (instead of console.log)
res.send("OK");
});
app.get('/setVolume/:volume', (req, res) => {
var tmp_volume = req.params.volume;
if(tmp_volume >= 0 && tmp_volume <= 10){
volume = tmp_volume;
console.log("set volume= " + volume);
}else{
console.log("out of range: " + tmp_volume);
}
res.send("OK");
});
実行するにはまず Node.js および Express をインストールしておきますが、たとえばこの記事が参考になります。
> mkdir new_project
> cd new_project
> npm init
順に答えていき、"main"
はファイル名(上の例ではscratch2-ex.js
)にします。また、このディレクトリ内にファイル scratch2-ex.js
を置いておきます。
> npm install express --save
> node scratch2-ex.js
これで Express サーバが実行されます。
zeit/pkg で実行形式にする
実行形式にするには Electron を使うこともできますが、インストール後のサイズがかなり大きくなります(Hello world でも 100MB を越える)。Electrino など、Electron を軽量化するプロジェクトもあるようですが、今回はコンソールアプリでブラウザ機能は不要なので、(EncloneJSの後継の)zeit による pkg というツールを使ってみます。他にも node-packer (nodec) というのもありましたが、pkg の方がすんなり動いたので今回はこちらにします。
インストールは非常に簡単です。
> npm install -g pkg
使い方も簡単で、以下のコマンドで Windows (x64) の実行形式にできます。
> pkg -t win-x64 scratch2-ex.js
これで scratch2-ex.exe
ができるので、実行して試してみます。
Scratch 2 オフライン版を立ち上げ、シフトを押しながら「ファイル」メニューをクリックし、「実験的なHTTP拡張を読み込み」からこのような感じのJSON形式のファイルを読み込んで試してみます。詳しくは以前の記事を参照してください。
Scratch 2 からのポーリングに反応していれば、赤丸が緑色になります。
-t
はターゲット指定で、nodeのバージョン、OS (freebsd, linux, macos, win)、アーキテクチャ (x64, x86, armv6, armv7) などを指定できます。
> pkg scratch2-ex.js
のように省略すると、linux, macos, win がデフォルト値で一度に作成されます。詳しくは https://github.com/zeit/pkg を確認してみてください。Windows 以外のプラットフォームについては機会を見てテストしてみることにします。