M conf/nginx.conf => conf/nginx.conf +5 -1
@@ 9,7 9,11 @@ http {
location / {
default_type text/html;
content_by_lua_file server/server.lua;
- lua_code_cache off;
+ lua_code_cache off;
+ }
+ location /wss {
+ content_by_lua_file server/wss.lua;
+ lua_code_cache off;
}
}
}=
\ No newline at end of file
M makefile => makefile +2 -1
@@ 5,7 5,7 @@ all: server
clean: clean-server
.PHONY: server
-server: server/server.lua server/html.lua
+server: server/server.lua server/html.lua server/wss.lua
.PHONY: clean-server
clean-server:
@@ 13,3 13,4 @@ clean-server:
server/server.lua: server/server.fnl ; modules/fennel/fennel --compile $^ > $@
server/html.lua: server/html.fnl ; modules/fennel/fennel --compile $^ > $@
+server/wss.lua: server/wss.fnl ; modules/fennel/fennel --compile $^ > $@
M server/server.fnl => server/server.fnl +15 -3
@@ 1,8 1,20 @@
(global ngx ngx)
-(local html (require :html))
+(local html (require :server.html))
+
+(local script "var ws = null; function connect() { if (ws !== null) return log('already connected'); ws = new WebSocket('ws://127.0.0.1:8090/wss/'); ws.onopen = function () { log('connected'); }; ws.onerror = function (error) { log(error); }; ws.onmessage = function (e) { log('recv: ' + e.data); }; ws.onclose = function () { log('disconnected'); ws = null; }; return false;}function disconnect() { if (ws === null) return log('already disconnected'); ws.close(); return false;}function send() { if (ws === null) return log('please connect first'); var text = document.getElementById('text').value; document.getElementById('text').value = ''; log('send: ' + text); ws.send(text); return false;}function log(text) { var li = document.createElement('li'); li.appendChild(document.createTextNode(text)); document.getElementById('log').appendChild(li); return false;}")
(local homepage
- [:div {}
- [:h1 {} "Hello, world!"]])
+ [:html {}
+ [:head {}
+ [:script {} script]]
+ [:body {}
+ [:div {}
+ [:h1 {} "Hello, world!"]
+ [:form {:onSubmit "return send();"}
+ [:button {:type :button :onClick "return connect();"} :Connect]
+ [:button {:type :button :onClick "return disconnect();"} :Disconnect]
+ [:input {:id :text :type :text}]
+ [:button {:type :submit} :Send]]]
+ [:ol {:id :log}]]])
(ngx.say (html homepage))
A server/wss.fnl => server/wss.fnl +40 -0
@@ 0,0 1,40 @@
+(global ngx ngx)
+(local server (require :resty.websocket.server))
+(local (wb, err) (: server :new {:timeout 60000 :max_payload_len 65535}))
+
+(if (not wb)
+ (do (ngx.log ngx.ERR "failed to connect to new websocket: ", err)
+ (ngx.exit 444))
+
+ (while true
+ (local (data typ err) (: wb :recv_frame))
+ (if wb.fatal
+ (do (ngx.log ngx.ERR "failed to receive frame: ", err)
+ (ngx.exit 444))
+
+ (not data)
+ (let [(bytes err) (: wb :send_ping)]
+ (when (not bytes)
+ (ngx.log ngx.ERR "failed to send ping: " err)
+ (ngx.exit 444)))
+
+ (= typ :close)
+ (: wb :send_close)
+
+ (= typ :ping)
+ (let [(bytes err) (: wb :send_pong)]
+ (when (not bytes)
+ (ngx.log ngx.ERR "failed to send pong: " err)
+ (ngx.exit 444)))
+
+ (= typ :pong)
+ (do (ngx.log ngx.INFO "client ponged")
+ (: wb :send_close))
+
+ (= typ :text)
+ (let [(bytes err) (: wb :send_text data)]
+ (if (not bytes)
+ (do (ngx.log ngx.ERR "failed to send text: " err)
+ (ngx.exit 444))))
+
+ (: wb :send_close))))