LoginSignup
5
6

More than 5 years have passed since last update.

Node.js + Express で HTTPサーバを作りコンパクトな実行形式にする(Scratch 2 拡張を例に)

Last updated at Posted at 2017-12-09

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サーバを作成してそこで何か処理を行うようにすれば、新たな機能を拡張ブロックとして追加できます。

command_and_reporter.png

こちらの記事のように、Python版では aiohttp を使って以下のようなコードにしました。

testhelper.py
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 で作ると以下のようになります。

scratch-ex.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 以外のプラットフォームについては機会を見てテストしてみることにします。

5
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
6