深町さんがサムライトでEngine.IOサーバーを書いていたので試しに動かしてみた。 github.com
ただ、そのままじゃClack(Lack)やwebsocket-driverの変更に追従していなかったので、forkして修正してみた。
果たして今さらプルリクエストを作成しても見てもらえるのだろうか。。。
インストール
ros install somewrite-adtech/engine-io-parser # ros install somewrite-adtech/engine-io-server ros install peccu/engine-io-server # クライアントテスト用 npm i engine.io-client
echoサーバーのサンプル
- server.ros
#!/bin/sh #|-*- mode:lisp -*-|# #| <Put a one-line description here> exec ros -Q -- $0 "$@" |# (progn ;;init forms (ros:ensure-asdf) #+quicklisp (ql:quickload '(:engine-io-server) :silent t) ) (defpackage :ros.script.server.3706692586 (:use :cl :engine-io-server) ) (in-package :ros.script.server.3706692586) (defparameter *server* nil) (defparameter *port* 3456) ;; https://github.com/somewrite-adtech/engine-io-server/blob/master/t/util.lisp#L47 (defmacro with-server ((&rest initargs) &body body) (let ((handler (gensym "HANDLER"))) `(tagbody beginning (let* ((*server* (make-instance 'server ,@initargs)) (,handler (start-server *server* :port *port*))) (unwind-protect (handler-bind ((usocket:connection-refused-error (lambda (e) (declare (ignore e)) (sleep 1) (go beginning)))) ,@body) (stop-server ,handler) (sleep 0.5)))))) (defun main (&rest argv) (declare (ignorable argv)) (with-server (:allow-upgrades nil) (on :connection *server* (lambda (socket) ;; 多分ここにイベントハンドラを増やしていけばよい ;; echo server (on :message socket (lambda (msg) (format t "~a~%" msg) (send socket msg))) )) (loop (sleep 0.1)))) ;;; vim: set ft=lisp lisp:
- client.js
var socket = require('engine.io-client')('ws://127.0.0.1:3456'); socket.on('open', function(){ console.log('open'); socket.on('message', function(data){ console.log('message', data); }); socket.on('close', function(){ console.log('close'); }); socket.send('abc'); }); socket.on('error', function(e){ console.log('error', e); });
- サーバーは
./server.ros
で起動する。うまく動いていればこんな感じ
% ./server.ros Wookie server is started. Listening on localhost:3456.
- クライアントは
node client.js
で起動する。
% node client.js open message abc
感想
engine-io-serverの修正と動作確認のために実装を読んで、色々勉強になった。
- Common LispからNode.jsを呼び出す方法、
- アプリを起動してもすぐ終了しない方法(loop使ってタイムアウト処理を書けばいいんや)
- asdファイルにパスが通っていればql:quickloadできて、ql:quickloadしていないとuseとかimport-fromができないこと
先日のLispユーザー会で佐野さんにドキュメントがない時のコードの読み方を聞いておいてよかった。 コードリーディングのエントリーポイントとか指針があると読めるような気になってくる。
ros install、ros-tap便利
次
Clack, Caveman, Engine.IOそれぞれで似たようなことをしようとしたらどうするのか比較してみる。
比較してみたいことは以下のとおり
- POSTを受け付けてwebsocket用のURLを発行する
- websocketのメッセージに対する処理を記述する