他の記事 でも、 Glitch のことを書いていて、使い回しになってしまったが、もう少し真剣に触ってみた。
自作ノードの npm からのダウンロード数を日別と累積で可視化した。
2クリックで、 Glitch 上に Node-RED を立ち上げる。
しばらく待つ。30秒くらい。
上記の [Remix on Glitch] ボタンは下記で作成。
Generate GitHub Import Button
下記画面は、1クリック目で遷移する画面。
(下記状態は、30秒程度待ってから、2クリック目ができる状態。)
画面左上のプロジェクト名 fast-dagger
(自動で一意な文字列になっている)をクリックすると、ペロってメニューが現れるので、その一番上で、プロジェクト名を変更できる。これは、アプリのサブドメイン部分になる。
- デフォルトのログインは、下記で。
- Username: admin
- Password: password
Glitch の料金
Glitch for Platforms - Delivering Developer Success
- Community
- Free
- Real-time Pair Programming
- Unlimited Project Hosting & Remixing
- Store Environment Variables & API Keys
- GitHub Import/Export
- Remix on Glitch Button
- Glitch Help
- Team
- $999
- Business
- Contact Us
Glitch の制限
Glitch – Frequently Asked Questions
- Projects created by anonymous users expire after 5 days (login via GitHub or Facebook to keep your projects around).
- 匿名ユーザーによって作成されたプロジェクトは、5日後に期限切れになります(GitHubまたはFacebook経由でログインしてプロジェクトを継続する)。
上記のやり方で、さくっと Node-RED は立ち上がるが、 Glitch にログインしていないと、アプリが5日間で期限切れになるらしい。
ログインはすぐできるので、ログインしちゃう。
- Projects sleep after 5 minutes if they are not used.
- プロジェクトが使用されていない場合、5分後にスリープ状態になります。
スリープ状態で、おそらくサーバが止まる。 inject で1分おきに動かしておくとか、自分にHTTPリクエスト投げて、受け取ってを一定間隔でやれば継続するのかな?(未検証)
(追記 2017-12-14)inject で定期処理させているだけでは、スリープしてしまう。inject ノードで定期的(試したのは1分おき)に、 http ノードで、自分(例: https://fast-dagger.glitch.com/xxx )にリクエスト投げて、受け取っていれば、スリープはしていない模様。日次バッチとかさせたい場合は、これやらないとダメなのか?? cron 的な設定があるきがしてきた。また調査する。
- Projects are limited to 4000 requests per hour, with a burst of 4000 requests (subsequent requests will return a 429 "Too Many Requests" response).
- プロジェクトは1時間に4000リクエストに制限され、4000要求がバーストされます(その後のリクエストでは429個の 'Too Many Requests'レスポンスが返されます)。
1秒間に1回のリクエストはいけるのか。
- Projects have a limit of 128MB of space on the container (though things written to '/tmp' don't count towards that, and we use compression to squeeze the most out of that space). As well as up to 512MB of assets storage.
- プロジェクトはコンテナのスペースが128MBに制限されています(ただし、 '/ tmp'に書き込まれたものはそれに含まれません)。圧縮を使用してスペースを最大限に圧縮します。最大512MBのアセットストレージ
ふむふむ。
- Projects only show up to 100 files in the file tree, the rest get hidden from view but still exist. Using
.gitignore
to temporarily remove some files from view can help work around this.
- プロジェクトでは、ファイルツリーに100個までのファイルしか表示されず、残りのファイルは非表示になりますが、まだ存在します。
.gitignore
を使って一時的にいくつかのファイルをビューから削除すると、これを回避できます。
ほうほう。
- Similarly, files above 200kb are hidden from the file tree (but still exist), and you're unable to paste data into the editor above that size too.
- 同様に、200kbを超えるファイルはファイルツリーから隠されています(ただし、まだ存在しています)。そのサイズを上回るエディタにデータを貼り付けることはできません。
そかそか。
Glitch で立ち上げたアプリケーションの構成ファイル説明
server.js
ここのコード( Node-RED : Embedding into an existing app )を元に、認証や、Glitch に合わせた設定を付け加えている。
ポートは、 3000
じゃなくてもいい。Glitch のデフォルトが 3000
らしいからそれに合わせている。
FlowFile
は重要。Node-RED のデフォルトだと flows_<hostname>.json
となるらしく、Glitch でスリープすると、おそらく hostname
が変わる。なので、フローが消える。 flows.json
に固定してあげることで解決のはず。
userDir: '/app/node-red'
とすることで、Glitch 上にも flows.json だったりが表示されるようになる。
(表示されなくたったいいのだけれど。気分的に安心する。ただしリアルタイムでは反映されないので注意。)
adminAuth
の username
と password
は、 .env
で指定している。
.env
に指定した値は、 process.env.XXX
でとれる。
[参考]
https://nodered.org/docs/configuration
var http = require('http');
var express = require("express");
var RED = require("node-red");
// Create an Express app
var app = express();
// Add a simple route for static content served from 'public'
app.use("/", express.static("public"));
// Create a server
var server = http.createServer(app);
// Create the settings object - see default settings.js file for other options
var settings = {
httpAdminRoot: "/",
httpNodeRoot: "/api/",
uiPort: 3000,
functionGlobalContext: { // enables global context
// os:require('os'),
},
adminAuth: {
type: "credentials",
users: [{
username: process.env.NODE_RED_USER,
password: process.env.NODE_RED_PW,
permissions: "*"
}]
},
debugMaxLength: 1000,
debugUseColors: true,
flowFile: 'flows.json',
userDir: '/app/node-red',
nodesDir: '/app/node-red/nodes',
ui: { path: "ui" },
logging: {
console: {
level: "trace"
}
}
};
// Initialise the runtime with a server and settings
RED.init(server, settings);
// Serve the editor UI from /
app.use(settings.httpAdminRoot, RED.httpAdmin);
// Serve the http nodes UI from /
app.use(settings.httpNodeRoot, RED.httpNode);
server.listen(3000);
// Start the runtime
RED.start();
package.json
Glitch のデフォルトに、 "node-red": "^0.17.5"
の行を付け加えた。
{
"name": "node-red-for-glitch",
"version": "0.0.1",
"description": "Node-RED for Glitch.",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"engines": {
"node": "8.x"
},
"repository": {
"type": "git",
"url": "git+https://github.com/high-u/node-red-for-glitch.git"
},
"keywords": [
"node-red",
"glitch",
"node.js"
],
"author": "high-u <zen.crazyd@gmail.com> (https://github.com/high-u)",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/high-u/node-red-for-glitch/issues"
},
"homepage": "https://github.com/high-u/node-red-for-glitch#readme",
"dependencies": {
"express": "^4.16.2",
"node-red": "^0.17.5"
}
}
.env
NODE_RED_PW
は、要注意で、 $
を \
でエスケープしてあげる必要がある。
今回は、サンプルとして、 gitリポジトリに含めたが、本来 .env
はgitリポジトリに含めるべきでないことを念のため付け加える。
# Environment Config
# store your secrets and config variables in here
# only invited collaborators will be able to see your .env values
# reference these in your code with process.env.SECRET
# Login Username
NODE_RED_USER="admin"
# Login Password
# escape doller (back-slash)
NODE_RED_PW="\$2a\$08\$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."
PORT=3000
PROJECT_DOMAIN=
PROJECT_ID=
PROJECT_INVITE_TOKEN=
# note: .env is a shell file so there can't be spaces around =
我が子を窺うダッシュボード
フロー
node-red-dashboard をインストールする。
下記フローを読み込んだら、一度、 daily
と sum
のノードをダブルクリックで開いて、 Group
の鉛筆アイコンを開かないと、反映されなかった。(なんでだろ)
[{"id":"93f7c8d1.045b58","type":"ui_chart","z":"fa0ebd82.96c16","name":"daily","group":"cf85217.db9fbe","order":0,"width":0,"height":0,"label":"Daily","chartType":"line","legend":"true","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":"1","removeOlderPoints":"","removeOlderUnit":"60","cutout":0,"useOneColor":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":450,"y":336,"wires":[["82a43b22.ba9f08"],["82a43b22.ba9f08"]]},{"id":"3d43de69.714c22","type":"inject","z":"fa0ebd82.96c16","name":"inject","topic":"https://api.npmjs.org/downloads/range/2017-09-01:2017-12-31/","payload":"[]","payloadType":"json","repeat":"","crontab":"","once":true,"x":146,"y":80,"wires":[["a5d79a9d.adbd78"]]},{"id":"82a43b22.ba9f08","type":"debug","z":"fa0ebd82.96c16","name":"","active":true,"console":"false","complete":"false","x":614,"y":368,"wires":[]},{"id":"a5d79a9d.adbd78","type":"template","z":"fa0ebd82.96c16","name":"nodes","field":"payload","fieldType":"msg","format":"handlebars","syntax":"plain","template":"[\n\"node-red-contrib-increment\",\n\"node-red-contrib-salesforce-platform-event\",\n\"node-red-contrib-aws-sdk-anything\",\n\"node-red-contrib-separate-flow-json\",\n\"node-red-contrib-manage-flow-by-git\",\n\"node-red-contrib-process-env\"\n]","output":"json","x":290,"y":80,"wires":[["2cf0fc3.1cb1d04"]]},{"id":"a6235af2.a42cb8","type":"function","z":"fa0ebd82.96c16","name":"conv","func":"// https://github.com/node-red/node-red-dashboard/blob/master/Charts.md\n\nvar s = msg.payload.downloads;\n\nvar labels = [];\nvar series = [msg.payload.package];\nvar data = [];\nvar d = [];\n\ns.forEach(function (v, i) {\n labels.push(v.day);\n d.push(v.downloads);\n});\ndata.push(d);\n\nmsg.payload = {\"series\":series, \"data\":data, \"labels\":labels};\nreturn msg;","outputs":1,"noerr":0,"x":546,"y":208,"wires":[["b14ef949.490cf8"]]},{"id":"b8716554.a26728","type":"split","z":"fa0ebd82.96c16","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":210,"y":144,"wires":[["cafce2fa.b9958"]]},{"id":"9fb7b719.eca6c8","type":"http request","z":"fa0ebd82.96c16","name":"npm API","method":"GET","ret":"obj","url":"","tls":"","x":412,"y":208,"wires":[["a6235af2.a42cb8"]]},{"id":"b14ef949.490cf8","type":"join","z":"fa0ebd82.96c16","name":"","mode":"auto","build":"string","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"","count":"","x":610,"y":272,"wires":[["5563f5.89d69c0c"]]},{"id":"af6f6234.d39f4","type":"function","z":"fa0ebd82.96c16","name":"union","func":"var p = msg.payload;\nvar chartdata = {\"series\": [],\"data\": [],\"labels\": []};\n\np.forEach(function(v,i){\n chartdata.series.push(v.series[0]);\n chartdata.data.push(v.data[0]);\n});\nchartdata.labels = p[0].labels;\n\nmsg.payload = [chartdata];\n\nreturn msg;","outputs":1,"noerr":0,"x":210,"y":336,"wires":[["93f7c8d1.045b58","fea57568.169828"]]},{"id":"2cf0fc3.1cb1d04","type":"link out","z":"fa0ebd82.96c16","name":"","links":["a2885e1b.2744d"],"x":399,"y":80,"wires":[]},{"id":"a2885e1b.2744d","type":"link in","z":"fa0ebd82.96c16","name":"","links":["2cf0fc3.1cb1d04"],"x":111,"y":144,"wires":[["b8716554.a26728"]]},{"id":"5563f5.89d69c0c","type":"link out","z":"fa0ebd82.96c16","name":"","links":["d3664632.fe1b78"],"x":703,"y":272,"wires":[]},{"id":"d3664632.fe1b78","type":"link in","z":"fa0ebd82.96c16","name":"","links":["5563f5.89d69c0c"],"x":111,"y":336,"wires":[["af6f6234.d39f4"]]},{"id":"fea57568.169828","type":"function","z":"fa0ebd82.96c16","name":"add","func":"var p = msg.payload[0].data;\n\nvar chartdata = p.map(function(pelement, pindex, parray) {\n return pelement.map(function(melement, mindex, marray) {\n return marray.filter(function(felement, findex, farray) {\n return (findex <= mindex);\n })\n .reduce(function(previousValue, currentValue, index, array) {\n return previousValue + currentValue;\n });\n });\n});\n\nmsg.payload[0].data = chartdata;\nreturn msg;","outputs":1,"noerr":0,"x":322,"y":400,"wires":[["49b7f21f.48991c"]]},{"id":"49b7f21f.48991c","type":"ui_chart","z":"fa0ebd82.96c16","name":"sum","group":"cf85217.db9fbe","order":0,"width":0,"height":0,"label":"Sum","chartType":"line","legend":"true","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":"1","removeOlderPoints":"","removeOlderUnit":"60","cutout":0,"useOneColor":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":450,"y":400,"wires":[["82a43b22.ba9f08"],["82a43b22.ba9f08"]]},{"id":"cafce2fa.b9958","type":"change","z":"fa0ebd82.96c16","name":"add url","rules":[{"t":"set","p":"url","pt":"msg","to":"msg.topic & msg.payload","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":268,"y":208,"wires":[["9fb7b719.eca6c8"]]},{"id":"cf85217.db9fbe","type":"ui_group","z":"","name":"npm downloads","tab":"ff37f545.4fbac8","disp":true,"width":"12"},{"id":"ff37f545.4fbac8","type":"ui_tab","z":"","name":"Dashboard","icon":"dashboard","order":1}]
function 内は、ゴチャゴチャやってるけど forEach 使った方が処理コストはおそらく低い。趣味で filter とかにしてる。
node-red-dashboard へ渡すJSON
下記 github のページに Stored data や Live data の使い方(データフォーマット)が書いてある。
node-red-dashboard/Charts.md at master · node-red/node-red-dashboard
で、ダッシュボードはこんな感じ。日々のダウンロード数と累積ダウンロード数をラインチャートに。
我が子紹介
node-red-contrib-aws-sdk-anything
AWS SDK は基本パターンが一緒だから何でも使えるようにしてみた。
中には使えないパターンも存在するけど、結構いけるはず。
dynamodb とか s3 とか kinesis はいけてる。
node-red-contrib-manage-flow-by-git
フローのgit管理を試して作ったやつ。たぶん名前が悪く、期待してダウンロードした人も多かったのではと、反省しつつ、名前付けの難しさと、git需要を実感できたノードw
難産ノード
node-red-contrib-salesforce-platform-event
done()
の重要さ知らなかった。処理帰って来ないっていう罠。
jsforce
の unsubscribe
の使い方に惑わされる。
期限に追われて、ギリギリの誕生。
node.on('close', function (done) {
tpc.unsubscribe();
done();
});
ここに答えが。
Node-RED : JavaScript file