- 投稿日:2019-04-15T23:32:29+09:00
Node.js でつくる WASM トランスパイラー - 04:比較演算子を実装する
はじめに
Node.jsで小さなプログラミング言語を作ってみるシリーズを、「ミニコンパイラー」「ミニインタープリター」とやってきました。そして三部作(?)の最後として、 ミニNode.jsからWASMを生成するトランスパイラーに取り組んでいます。
- 前回の記事 ... 03:ローカル変数を実装する
今回実現したいこと
今回は次の比較演算子のサポートが目標です。それぞれ、WASTでは次のように表記します。
- === ... eq
- !== ... ne
- < ... lt_s (符号あり)
- > ... gt_s (符号あり)
- <= ... le_s (符号あり)
- >= ... ge_s (符号あり)
比較の変換例
このミニNode.jsのソースコードを対象とします。
putn(1 !== 2);putn()は、前回用意した簡易デバッグ出力用の組み込み関数です。
これを読み込み、単純化したASTはこちらになります。
[ 'func_call', 'putn', [ '!==', [ 'lit', 1 ], [ 'lit', 2 ] ] ]この部分を次のWASTに変換することが、今回の目的です。
(call $putn (i32.ne (i32.const 1) (i32.const 2) ) )比較演算子の生成
早速ランスパイラーのgenerate()関数を拡張します。
function generate(tree, indent, lctx) { // ... 省略 ... // --- compare operator --- if (tree[0] === '===') { return generateCompareOperator(tree, indent, 'eq', lctx); } if (tree[0] === '==') { return generateCompareOperator(tree, indent, 'eq', lctx); } if (tree[0] === '!==') { return generateCompareOperator(tree, indent, 'ne', lctx); } if (tree[0] === '!=') { return generateCompareOperator(tree, indent, 'ne', lctx); } if (tree[0] === '>') { return generateCompareOperator(tree, indent, 'gt_s', lctx); } if (tree[0] === '>=') { return generateCompareOperator(tree, indent, 'ge_s', lctx); } if (tree[0] === '<') { return generateCompareOperator(tree, indent, 'lt_s', lctx); } if (tree[0] === '<=') { return generateCompareOperator(tree, indent, 'le_s', lctx); } // ... 省略 ... } // --- compare operator --- function generateCompareOperator(tree, indent, operator, lctx) { const leftBlock = generate(tree[1], indent+1, lctx); const rightBlock = generate(tree[2], indent+1, lctx); let block = TABs(indent) + '(i32.' + operator + LF(); block = block + leftBlock + LF(); block = block + rightBlock + LF(); block = block + TABs(indent) + ')'; return block; }実際にコードを生成するのは、generateCompareOperator()関数で行なっています。
比較演算子の実行
対象ソース
こちらのコードをWASM生成対象とします。
sample/neq.jsputn(1 !== 2); 0;WASMの生成
今回のステップまでのトランスパイラーのソースコードを、mininode_wasm_04.js とします。次のようにgenerated.wast を生成します。
$ node mininode_wasm_04.js sample/neq.js生成結果はこちら。
generated.wast(module (func $putn (import "imports" "imported_putn") (param i32)) (export "exported_main" (func $main)) (func $main (result i32) (call $putn (i32.ne (i32.const 1) (i32.const 2) ) ) (i32.const 0) ) )これを WASM に変換、前回用意した run_wasm_putn.js を使って実行します。
$ wasm-as generated.wast $ node run_wasm_putn.js generated.wasm Loading wasm file: generated.wasm 1 ret code=0「1 !==2」は true なので、1 が標準出力に表示されました。
色々な比較の実行
もう一つ、色々な比較を使ったサンプルを変換、実行してみます。
comp.jslet a = 1; putn(a); // expect 1 let b = (a === 2); putn(b); // expect 0 putn(a == 1); // expect 1 let c = (a !== 2); putn(c); // expect 1 putn(a != 1); // expect 0 putn(999); a = a * 10; putn(a > 10) ; // expect 0 putn(a >= 10) ; // expect 1 putn(a < 10) ; // expect 0 putn(a <= 10) ; // expect 1 22;実行結果はこちら。色々な比較演算子も想定通りの出力になりました。
Loading wasm file: generated.wasm 1 0 1 1 0 999 0 1 0 1次回は
目標の1つであるFizzBuzzに必要な、条件分岐を実装する予定です。
ここまでのソース
GitHubにソースを上げておきます。
- GitHubのレポジトリ ... https://github.com/mganeko/node_wasm
- mininode_wasm_04.js ... 今回のWASMトランスパイラー
- sample/neq.js ... シンプルな比較演算子のサンプル
- sample/comp.js ... 色々な比較演算子のサンプル
- 投稿日:2019-04-15T19:19:24+09:00
無料で作る集計Webページ!N予備校フォーラム名誉会員のシステムについて
こんにちはー!
N予備校プログラミング入門コース、講師の 折原ダビデ竜 です。N予備校には勉強に躓(つまず)いた時などに質問を投稿することができる「フォーラム」という最高すぎる機能があるのはご存知でしょうか。
ここでは日々たくさんの質問が投稿され、我々講師の方々などが返答しています。ですが!
これらの質問に答えることこそ、実はすごく良い勉強になるのです。
そして実際に回答してくださっている受講者の方もたくさんいらっしゃっいます。そこで!
- このフォーラムの質問に回答してくださっている受講者の方々を讃えたい!
- さらにより多くの受講者の方にも回答をしてみてもらいたい!
という気持ちが高ぶり
そしてこの度!
N予備校フォーラム名誉会員(めいよかいいん) という称号が回答を多くして下さっている受講者に与えられるシステムを作成いたしました✨
https://progedu.github.io/forum-ranking/
N予備校フォーラム名誉会員 について
N予備校のフォーラムに回答してくれている回数が多い方々を「フォーラム名誉会員」とし、
フォーラム名誉会員のページに アカウント名・アイコン・フォーラム貢献数・コメント数 などが掲載され、讃えられます!毎月更新される「月間フォーラム名誉会員」と全ての期間の「全期間フォーラム名誉会員」があり、日頃からフォーラムの質問に回答してくださっている方々に感謝の気持ちをお伝えしたく、作成いたしました。
こちらでも報告しています。
https://www.nnn.ed.nico/questions/10030なんと!
この集計ページは全て無料のサービスで作られています!
次に、どのようにしてこの フォーラム名誉会員のページ が作られているのかについても書いてみたいと思います。
N予備校 フォーラム名誉会員のシステムについて
このフォーラム名誉会員のページは、GitHub Pages という無料で Webサイト を公開することができる GitHub の機能を使って無料で実現できています。
(GitHub Pages の使い方は プログラミング入門コース で教えています。)そして N予備校のフォーラムからデータを取得し、回答数などを集計するシステムは Node.js のプログラムで書かれ、CircleCI にて毎朝4時に実行されることで毎日の集計を実現しています。
CircleCI は、無料でもプログラムのテストを実行してくれるサービスで、集計を行うプログラムを test.js ファイルに記述し、これを定期実行してもらうことでデータの集計を実現しています。
(CircleCI についても N予備校プログラミング入門コース で教えています。)集計結果のデータですが、本来ならばデータベースを使いたかったのですが、まだそれほど大きなデータでも無いということから JSON ファイルに集計結果を書き出すようししました。
このようにして GitHub(無料)、GitHub Pages(無料)、CircleCI(無料)のみを使用した無料の集計ページを作ることができました。
みなさまの開発の参考になればと思います。また、GitHub にソースコードも載せていますので、このシステムをより良くできるアイデアなどありましたら気軽に issue や プルリクエストを投稿してみてください。
GitHub の URL → https://github.com/progedu/forum-ranking最後に
N予備校には勉強に詰まった時に質問を投稿できる「フォーラム」というシステムがあります。
質問に答えることもすごく良い勉強になりますので、困っている人がいたら助け合い、N予備校をより良い物にしていきましょう。そして日頃からフォーラムの質問に回答してくださっている方々に感謝をお伝えしたいと思います。
以上、Quiita 初投稿でした?
- 投稿日:2019-04-15T13:41:59+09:00
MicrosoftTeamsにGoogleNewsBotを入れてみた
MicrosoftTeamsにGoogleNewsBotを入れてみた
ゴールイメージ
動機
- 会社の公認コミュニケーションツールがSlackじゃなくてTeamsになりそう
- Teamsのwebhookを使ってみたい
- お友達の作ったGoogleNewsBot for SlackをTeamsに改造してみよう
実行環境とフロー
- AWS
- CloudWatch ルールでLambda(Node.js)を定周期起動
- GoogleNewsRSSを利用して、指定したキーワドのNewsを取得して、Teamsに投げ込む
Teams側の設定
- Newsを表示したいチャンネルにIncoming Webhookコネクタを作成する必要がある。
- 詳しい解説記事が既にQiitaにあるのでこちら参照して作成してください(
チャネルの画面に戻ると 3 で付けた名前とアイコンの何者かが参加しています
まで実行すれば大丈夫)ローカルで試してみよう
npmインストール
- request-promise
- request
- rss-parser
- さくっとやりたいので
serverless
は使わない$ mkdir newsbot-teams $ cd newsbot-teams $ npm install request-promise request rss-parserソース
- 下記構成でそれぞれ作成してください
tree
. ├── index.js ├── google-news-service.js ├── main.js └── package.jsonindex.js
index.js'use strict'; const rp = require('request-promise'); const lodash = require('lodash'); const GoogleNewsService = require('./google-news-service.js'); function dateTimeFilter(articles, fromDate) { return articles.filter((article) => { const pubDate = new Date(article.pubDate); return (pubDate.getTime() - fromDate.getTime()) > 1; }); } function post2Slack(teams_webhook,message) { return rp.post(teams_webhook, { headers: { "Content-type": "application/json" }, json: { text: message } , uri : teams_webhook }); } async function main(fromDate,teams_webhook,keywords) { try { const googleNews = await (new GoogleNewsService()).exec(keywords); const news = lodash.uniqBy(dateTimeFilter(lodash.concat([], googleNews), fromDate), 'link'); const titleList = news.map((article) => { return `・[${ article.title }](${ article.link })<br>`; }).join(''); const message = 'ニュースとってきた。<br>' + titleList; await post2Slack(teams_webhook,message); } catch(error) { console.error(error); } } exports.handler = (event, context, callback) => { const fromDate = new Date(); const teams_webhook = event['teams_webhook']; const keywords = event['keywords']; fromDate.setHours(fromDate.getHours() - event['fromHour']); main(fromDate,teams_webhook,keywords); };google-news-service.js
google-news-service.jsconst Parser = require('rss-parser'); module.exports = class GoogleNewsService { constructor(){ } createGoogleNewsUrl(keyword) { return 'https://news.google.com/_/rss/search?q=' + encodeURIComponent(keyword) + '&hl=ja&gl=JP&ceid=JP:ja'; } async exec(keywords) { const splitkeywords = keywords.split(','); const parser = new Parser(); const feeds = await Promise.all(splitkeywords.map((keyword) => { return parser.parseURL(this.createGoogleNewsUrl(keyword)); })); const articles = []; feeds.forEach((feed) => { feed.items.forEach((item) => { articles.push(item); }); }); return articles; } }main.js
- ローカルでlambdaっぽく呼ぶやつ
main.jsvar event = { version: '0', id: 'XXXXXXXX-XXXXX-XXXX-XXXXX-XXXXXXXX', 'detail-type': 'Scheduled Event', source: 'aws.events', account: 'XXXXXXXXXX', time: '2019-01-30T06:27:04Z', region: 'ap-northeast-1', resources: [ 'arn:aws:events:ap-northeast-1:XXXXXXXXXX:rule/box-auditlog-exec' ], detail: {}, fromHour : '10', teams_webhook : 'https://outlook.office.com/webhook/XXXXXXXXXXXXXXXXXXXX/IncomingWebhook/XXXXXXXXXXX/XXXXXXXXXXXXXX', keywords : 'AWS,GCP,Azure,CentOS,IDaaS,okta,onelogin,ゼロトラスト,zero trust,Nginx,Microsoft,Windows Server,脆弱性,ゼロデイ' }; var context = { invokeid: 'invokeid', done: function(err,message){ return; } }; var lambda = require("./index.js"); lambda.handler(event,context);適宜変更してください
- fromHour : 過去何時間分のニュースを取得するか設定
- teams_webhook : Teams webhooksのurl.
- keywords : 取得したいNewsキーワード
ローカルで実行
$ node main.jsAWSにアップして動かしてみよう
事前準備
AWSへデプロイ
- 今回はS3を経由しているが、S3を経由する必要は特に無い
$ zip -r newsbot-teams.zip index.js node_modules $ aws s3 cp ./newsbot-teams.zip s3://[mybucket]/newsbot-teams.zip --profile [myprofile] $ aws lambda update-function-code --function-name newsbot-teams --s3-bucket [mybucket] --s3-key newsbot-teams.zip --publish --profile [myprofile]実行
- CloudWatch ルールに、lambdaを指定して引数を設定して起動する。
- 周期はお好きなように
GMTだから気をつけて
- 引数サンプル:
入力の設定
-定数(JSONテキスト)
{"fromHour": "15", "teams_webhook": "https://outlook.office.com/webhook/xxxxxxx/IncomingWebhook/xxxxxxxxxxx/xxxxxxxx", "keywords": "AWS,GCP,Azure,CentOS,IDaaS,okta,onelogin,ゼロトラスト,zero trust,Nginx,Microsoft,Windows Server,脆弱性,ゼロデイ"}部単位のチャンネルトとかに、部で共有したいNewsキーワードを設定して毎日1回とか数回ポストすると良いと思う。日常業務に忙殺されて、情報をキャッチアップできてない人多いし。
ソース置き場
こちらにソース置いておきます。(ソース汚かったらPullReqください)
- 投稿日:2019-04-15T00:07:23+09:00
Express風の簡単WebSocketフレームワーク、Hexnutのドキュメントを読んで試してみた
注意
WebSocketを趣味で勉強しているものです、間違いなどありましたらご指摘お願いします
Hexnut とは
google翻訳
?Hexnutはミドルウェアベースの、Express / Koa風のWebソケット用フレームワークInstalling HexNut
インストール
npm i hexnutCreating a server
サーバー起動
server.jsconst HexNut = require('hexnut'); const app = new HexNut({ port: 8080 }); app.start();node server.jsindex.html<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <script> { const ws = new WebSocket("ws://127.0.0.1:8080"); ws.addEventListener("open", e => console.log("socket open")); } </script> </body> </html>これでWebSocketサーバーが簡単に起動でき、接続も確認できました
Examples
https://github.com/francisrstokes/hexnut#examples
簡単な例
server.jsconst Hexnut = require('hexnut'); const app = new Hexnut({ port: 8080 }); app.onerror = async (err, ctx) => { ctx.send(`Error! ${err.message}`); }; app.use(ctx => { if (ctx.isConnection) { // 接続時に送信 ctx.state = { count: 0 }; return ctx.send('Hello, and welcome to the socket!'); } ctx.state.count++; ctx.send(`Message No. ${ctx.state.count}: ${ctx.message}`); // ctx.messageで受信したメッセージを取得できる }); app.start();<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <input type="button" value="send"> <script> { const ws = new WebSocket("ws://127.0.0.1:8080"); ws.addEventListener("message", e => console.log(e.data)); document.querySelector("[type=button]").addEventListener("click", e => { ws.send(new Date().toLocaleTimeString()); }); } </script> </body> </html>簡単にメッセージの送受信をすることができました
ctx.send(data)
だと送信してきたクライアントにしかメッセージを送らないため、
接続しているクライアント全てに送るときはctx.sendToAll(data)
とするようですJSONを自動的に解析する
server.jsconst Hexnut = require('hexnut'); const bodyParser = require('hexnut-bodyparser'); const app = new Hexnut({ port: 8080 }); app.use(bodyParser.json()); app.use(ctx => { if (ctx.isConnection) { ctx.state = { count: 0 }; return ctx.send('Hello, and welcome to the socket!'); } const { type, date, msg } = ctx.message; if (type) { ctx.state.count++; ctx.send(`Message No. ${ctx.state.count}: ${type} ${date} ${msg}`); } else { ctx.send(`Invalid message format, expecting JSON with a "type" key`); } }); app.start();npm i hexnut-bodyparser node server.js<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <input type="button" value="send"> <script> { const ws = new WebSocket("ws://127.0.0.1:8080"); ws.addEventListener("message", e => console.log(e.data)); document.querySelector("[type=button]").addEventListener("click", e => { ws.send(JSON.stringify({ type: "send", date: new Date().toLocaleTimeString(), msg: "\nabc\nあいう\n???", })); }); } </script> </body> </html>JSONを自動でオブジェクトに解析してくれたのが確認できました
hexnut-bodyparser
を使わなくても、JSON.parse(ctx.message);
とすれば同じように扱ってくれますconst Hexnut = require('hexnut'); const bodyParser = require('hexnut-bodyparser'); const app = new Hexnut({ port: 8080 }); - app.use(bodyParser.json()); app.use(ctx => { if (ctx.isConnection) { ctx.state = { count: 0 }; return ctx.send('Hello, and welcome to the socket!'); } - const { type, date, msg } = ctx.message; + const { type, date, msg } = JSON.parse(ctx.message); if (type) { ctx.state.count++; ctx.send(`Message No. ${ctx.state.count}: ${type} ${date} ${msg}`); } else { ctx.send(`Invalid message format, expecting JSON with a "type" key`); } }); app.start();メッセージの種類判別
server.jsconst Hexnut = require('hexnut'); const handle = require('hexnut-handle'); const app = new Hexnut({ port: 8080 }); // 接続時に呼ばれるイベント app.use(handle.connect(ctx => { ctx.count = 0; })); // msg === 'incCount' に一致する値が送られ的場合に実行される app.use(handle.matchMessage( msg => msg === 'incCount', ctx => ctx.count++ )); // msg === 'decCount' に一致する値が送られ的場合に実行される app.use(handle.matchMessage( msg => msg === 'decCount', ctx => ctx.count-- )); // msg === 'getCount' に一致する値が送られ的場合に実行される app.use(handle.matchMessage( msg => msg === 'getCount', ctx => ctx.send(ctx.count) )); // ↑に一致しなかった値が送られてきた場合にはここが実行される app.use(handle.message(ctx => { ctx.send(`Any other kind of message will go here.`); })); app.start();npm i hexnut-handle node server.js<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <input type="button" value="incCount"> <input type="button" value="decCount"> <input type="button" value="getCount"> <script> { const ws = new WebSocket("ws://127.0.0.1:8080"); ws.addEventListener("message", e => console.log(e.data)); Array.from(document.querySelectorAll("[type=button]")).forEach(elm => { elm.addEventListener("click", e => ws.send(e.target.value)); }); } </script> </body> </html>このように、送信するメッセージによって処理を分岐させることができました
Sequencing Interactions
メッセージを受信する順番を保証できる機能のようです
const Hexnut = require('hexnut'); const bodyParser = require('hexnut-bodyparser'); const sequence = require('hexnut-sequence'); const app = new Hexnut({ port: 8080 }); app.use(bodyParser.json()); // ユーザーが接続したときに発生 app.use(sequence.onConnect(function* (ctx) { ctx.send(`Welcome, ${ctx.ip}`); const name = yield sequence.getMessage(); // 接続時、次のメッセージが来るまで待つ、メッセージを受信したらイテレータを次に進める ctx.clientName = name; return; })); app.use(sequence.interruptible(function* (ctx) { // clientNameが存在すればイテレータを次に進める yield sequence.assert(() => 'clientName' in ctx); // type == greeting を受信すると、イテレータを次に進める const greeting = yield sequence.matchMessage(msg => msg.type === 'greeting'); // type == time を受信すると、イテレータを次に進める const time = yield sequence.matchMessage(msg => msg.type === 'time'); // ↑の条件が全てが受信されると、↓の送信の部分に処理が到達する return ctx .send(`${greeting.value} ${ctx.clientName}です、 今の時間は${time.value}です`); })); app.start();npm i hexnut-sequence node server.js<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <input type="button" value="name" data-msg="tarou"> <input type="button" value="greeting" data-msg='{"type":"greeting","value":"おはようございます"}'> <input type="button" value="time" data-msg='{"type":"time","value":"10:00"}'> <script> { const ws = new WebSocket("ws://127.0.0.1:8080"); ws.addEventListener("message", e => console.log(e.data)); Array.from(document.querySelectorAll("[type=button]")).forEach(elm => { elm.addEventListener("click", e => ws.send(e.target.dataset.msg)); });} </script> </body> </html>Middlewareを自作
server.jsconst Hexnut = require('hexnut'); const app = new Hexnut({ port: 8080 }); const myMiddleware = async (ctx, next) => { ctx.send("send myMiddleware message."); return await next(); } app.use(myMiddleware); app.use(ctx => { ctx.send("send message."); }); app.start();<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <input type="button" value="send"> <script> { const ws = new WebSocket("ws://127.0.0.1:8080"); ws.addEventListener("message", e => console.log(e.data)); document.querySelector("[type=button]").addEventListener("click", e => { ws.send(new Date().toLocaleTimeString()); }); } </script> </body> </html>ミドルウェアで、クライアントに送信前の処理がうまくいきました
HexNut Docs - API
https://github.com/francisrstokes/hexnut/blob/master/docs/api.md
引用部分は全て↑のページのgoogle翻訳です
HexNut Server
new HexNut(wsConfig)
新しいHexNutインスタンスを作成します
const Hexnut = require('hexnut'); const app = new Hexnut({ port: 8080 });app.use(middleware)
HexNutインスタンスにミドルウェア機能を追加します
app.start()
HexNut Websocketサーバーを起動します。
const Hexnut = require('hexnut'); const app = new Hexnut({ port: 8080 }); app.start(); // サーバー起動app.stop()
HexNut Websocketサーバーを停止します。
const Hexnut = require('hexnut'); const app = new Hexnut({ port: 8080 }); app.start(); app.stop(); // サーバー起動して即終了するctx
HexNut接続を表すコンテキストオブジェクト
ctx.message
受信したメッセージ
app.use(ctx => { if (ctx.isConnection) { // 接続時はnullになる console.log(ctx.message); } else { // 受信したメッセージ console.log(ctx.message); } });ctx.isConnection
app.use(ctx => { // 新しく接続されたのであればtrue、そうでなければfalse console.log(ctx.isConnection); });ctx.isMessage
app.use(ctx => { console.log(ctx.isMessage); });html<script> const ws = new WebSocket("ws://127.0.0.1:8080"); // 接続時は、ctx.isMessageはfalse ws.send("hoge"); // メッセージ送信した時は、ctx.isMessageはtrue </script>ctx.isClosing
接続終了したらtrueになる
app.use(ctx => { console.log(ctx.isClosing); });html<script> const ws = new WebSocket("ws://127.0.0.1:8080"); // 接続時は、ctx.isClosingはfalse ws.close(); // 接続終了した時は、ctx.isClosingはtrue </script>ctx.requestHeaders
この接続を開始したhttp(s)ヘッダを表すオブジェクト
app.use(ctx => { console.log(ctx.requestHeaders); });コンソール{ host: '127.0.0.1:8080', connection: 'Upgrade', pragma: 'no-cache', 'cache-control': 'no-cache', upgrade: 'websocket', origin: 'file://', 'sec-websocket-version': '13', 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36', 'accept-encoding': 'gzip, deflate, br', 'accept-language': 'ja-JP,ja;q=0.9,en-US;q=0.8,en;q=0.7', 'sec-websocket-key': '+oE1f1UWmZ3dJ0k8Et23XQ==', 'sec-websocket-extensions': 'permessage-deflate; client_max_window_bits' }ctx.ip
クライアントのIPアドレス
app.use(ctx => { console.log(ctx.ip); // ::ffff:127.0.0.1 });ctx.path
接続を開始した文字列URLパス
app.use(ctx => { console.log(ctx.path); });html<script> const ws = new WebSocket("ws://127.0.0.1:8080/path"); // ctx.pathは 「/path」となる </script>ctx.method
接続を開始するためのHTTPメソッド
app.use(ctx => { console.log(ctx.method); });html<script> const ws = new WebSocket("ws://127.0.0.1:8080"); // ctx.methodは 「GET」となる </script>ctx.send(data)
クライアントにメッセージを送る
app.use(ctx => { ctx.send("send message."); });html<script> const ws = new WebSocket("ws://127.0.0.1:8080"); ws.addEventListener("message", e => console.log(e.data)); </script>ctx.sendToAll(data)
接続されているすべてのクライアントにメッセージを送信する
app.use(ctx => { ctx.sendToAll(new Date().toLocaleTimeString()); });接続しているクライアントにメッセージを送ることができました
ctx.app
HexNutアプリへの参照
const Hexnut = require('hexnut'); const app = new Hexnut({ port: 8080 }); app.use(ctx => { console.log(app === ctx.app); // true }); app.start();
確認バージョン
- node v10.14.1
- npm 6.9.0
- hexnut 0.1.1
- hexnut-bodyparser 0.1.0
- hexnut-handle 1.0.0
- hexnut-sequence 0.1.0
最後まで読んでいただいてありがとうございましたm(_ _)m