Portal
Portable websockets for Common Lisp using usocket.
Install
Install with quicklisp.
(ql:quickload 'portal)
Use
Define a Resource
Resources are identified by their path in the URL.
A simple echo server.
(pws:define-resource "/echo"
:open (lambda (websocket)
(pws:send websocket "Welcome to echo server."))
:message (lambda (websocket message)
(sleep 1)
(pws:send websocket message)
(sleep 1)
(pws:send websocket message)))
You can also define :close
function and a :error
function in case something goes wrong in your other functions. You can’t send any more messages after a close has begun.
Start a Server
(defparameter server
(pws:server 4433))
Now connect to ws://localhost:4433/echo
in a websocket tester and start echoing.
You can add a :multi-thread
argument to give each client its own thread.
Close Clients
At any point, you can close a client websocket.
(pws:close websocket)
Close Server
To stop severing:
(pws:server-close server)
It is just a thread!
Handling Errors
These two methods are separate, You can both, neither, or any combination.
Custom Handler Function
When defining a resource path, you can pass a :error
argument with a function that takes the websocket and the condition that occurred. Do whatever you want here. It is called when there is an error in your :open
, :message
, or :close
function.
Debugger
There is a variable: pws:*debug-on-error*
; when it is non-nil, the debugger will be entered when there is a problem with one of your handler functions.
it is bound to t
by default.
Example
Here is another example, this time using the :error
function sends the error over the websocket instead of entering the debugger, and the :close
just prints to the Lisp console.
;; prevent entering debugger
(setq pws:*debug-on-error* nil)
(pws:define-resource "/err"
:open (lambda (socket)
(pws:send socket "Welcome to error server."))
:message (lambda (socket message)
;; error because message is a string
(pws:send socket (1+ message)))
:error (lambda (socket condition)
;; echo error to websocket
(pws:send socket condition))
:close (lambda (socket)
(declare (ignore socket))
(print "Socket leaving error server.")))
Issues
If you find any bugs of have any issues (installing, using, questions, adhering to RFC 6455) use the Github issue tracker.
Contact
If you want to contact me about collaboration, licensing, etc. You can use the email in portal.asd
.