hxzrx / cl-websocket

An experimental WebSocket-Server written in Common Lisp

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

cl-websocket

A WebSocket-Server implemented in Common Lisp.

The server passes all tests of version v0.7.5/v0.10.9 of the autobahn testsuite except

  • Compression: The server does not support the compression extension
  • Fast fail-over on invalid UTF-8 data: The server reads all frames of a text message before signalling an inconsistent-data error (1007) instead of failing on the first frame that contains an invalid character.

Installation

This project is not available via quicklisp, but all its dependencies are. The easiest way to install is to clone cl-websocket into the local-projects directory of quicklisp and then to quickload it.

Clone:

cd ~/quicklisp/local-projects
git clone https://github.com/Frechmatz/cl-websocket.git

Load and install all dependencies:

(ql:quickload "cl-websocket")

Dependencies:

Example: Echo-Service

Load cl-websocket

(asdf:load-system "cl-websocket")

Define a handler class

(defclass echo-handler (clws.handler:connection-handler) ())

(defmethod clws.handler:on-open-connection ((handler echo-handler))
    (v:info :echo-handler "on-open-connection"))

(defmethod clws.handler:on-close-connection ((handler echo-handler) status-code reason)
    (v:info :echo-handler "on-close-connection"))

(defmethod clws.handler:on-text-message ((handler echo-handler) message)
    (v:info :echo-handler "on-text-message: ~a" message))
    (clws.handler:send-text-message handler message))

(defmethod clws.handler:on-binary-message ((handler echo-handler) message)
    (v:info :echo-handler "on-binary-message")
    (clws.handler:send-binary-message handler message))

Instantiate the server

(defparameter *server* (clws.server:make-websocketserver "localhost" 9001))

Register the handler class

(clws.server:register-resource-handler *server* "/echo" 'echo-handler '())

Start the server

(clws.server:start *server*)

WebSocket connections can now be established via ws://localhost:9001/echo

Stop the server

(clws.server:stop *server*)

API

Package clws.server

  • make-websocketserver (host port &key) => server

  • start (server)

  • stop (server)

  • register-resource-handler (server uri-path class options)

    • uri-path The path of the resource, for example /echo

    • class Class of the handler to be instantiated when a connection has been established

    • options An alist specifying connection options. The following options are available

      • :max-payload-length Maximum payload size of a frame
      • :max-frame-count Maximum number of frames of which a message may consist
  • [Macro] do-connection-handlers (server handler &body body)

    Iterates over the active connection handlers. Executes the body with handler bound to the connection handler.

    Example:

      (defun broadcast (message)
          (clws.server:do-connection-handlers
              *server* cur-handler
              (clws.handler:send-text-message cur-handler message)))
    
  • [Macro] do-connection-handlers-by-uri (server uri-path handler &body body)

    Iterates over the active connection handlers belonging to a given resource. Executes the body with handler bound to the connection handler.

    • uri-path The path of the resource, for example /chat

    Example:

      (defun broadcast (message)
          (clws.server:do-connection-handlers-by-uri
              *server* "/chat" cur-handler
              (clws.handler:send-text-message cur-handler message)))
    
  • [Macro] do-connection-handlers-by-handler (connection-handler handler &body body)

    Iterates over the active connection handlers belonging to the resource (uri-path) of a given handler. Executes the body with handler bound to the connection handler.

    • connection-handler A connection handler

    Example:

      (defmethod clws.handler:on-open-connection ((handler chat-handler))
          (let ((nickname (clws.server:get-uri-query-param chat-handler "name")))
              (clws.server:do-connection-handlers-by-handler
                  chat-handler cur-handler
                  (clws.handler:send-text-message
                      cur-handler
                      (format nil "~a has joined the chat" nickname)))))
    
  • get-uri-query-param (connection-handler param-name) => value

    Returns the value of a query parameter of the WebSocket request-uri that has been used to open the connection.

Package clws.handler

  • [Class] connection-handler

    A connection-handler represents an endpoint of a WebSocket connection. Connection handlers are instantiated by the server. Applications must derive their handlers from this class.

    See also clws.server:register-resource-handler

  • on-open-connection (connection-handler)

  • on-close-connection (connection-handler status-code reason)

  • on-text-message (connection-handler message)

  • on-binary-message (connection-handler payload)

    • payload An instance of '(vector (unsigned-byte 8))
  • close-connection (connection-handler status-code reason)

  • send-text-message (connection-handler message)

  • send-binary-message (connection-handler payload)

    • payload A sequence of '(unsigned-byte 8)

Logging

The server uses the Verbose framework for logging.

Set logging level (globally)

(setf (v:repl-level) :error)

Running the tests

The tests are using the lisp-unit framework. The system definition file is cl-websocket-test.asd.

Run all tests

(asdf:load-system "cl-websocket-test")
(in-package :cl-websocket-test)
(setf lisp-unit:*print-failures* t)
(use-debugger)
(run-tests)

Run a specific test

(asdf:load-system "cl-websocket-test")
(in-package :cl-websocket-test)
(setf lisp-unit:*print-failures* t)
(use-debugger)
(run-tests '(ping-test-1))

References

The Websocket Protocol: RFC 6455

About

An experimental WebSocket-Server written in Common Lisp

License:MIT License


Languages

Language:Common Lisp 96.1%Language:JavaScript 2.8%Language:HTML 0.9%Language:Shell 0.2%