That is HUNCHENtoot ISSR. Make sure to see the main readme for the ISSR project and setup issr.js. ISSR allows you to make interactive web pages without writing client scripting; just include issr.js and generate some HTML in your server language (in the case of Hunchenissr: Common Lisp).
Install with quicklisp. You may want to include some other web tools too. I suggest markup for generating HTML.
(ql:quickload '(hunchenissr markup))Then include hunchentoot and hunchenissr in your package:
(defpackage your-package
(:use #:cl #:markup)
(:import-from #:hunchentoot
;; any other hunchentoot functions you might need
easy-acceptor)
(:import-from #:hunchenissr
define-easy-handler
*id*
*socket*
*ws-port*
start
stop
redirect
-on-connect-hook-
-on-disconnect-hook-))
(in-package #:your-package)Start your server:
(defparameter server
(start (make-instance 'easy-acceptor
:port 8080
:document-root "resources/")
:ws-port 4433)):ws-port becomes a global variable.
Now you can use define-easy-handler just like you would in hunchentoot. Inside define-easy-handler, some new variables will be available:
*id*: The unique id to make the connection use is in the setup of issr.js.*ws-port*: The port websockets connect on. Also used in setup of issr.js.*first-time*:tif it is the first HTTP connection of this client.*socket*:The current connection. It isnilon the first HTTP connection.-clients-: A hash-table of all connections. Key: sockets, Value:(list hunchentoot-request previous-virtual-dom)
Mostly everything works just like regular Hunchentoot with the following caveats:
- Cookies not sent over and initial HTTP request must be
:http-only nilor they will not be saved. - Since session uses cookie, if you want to use session, then you must call
(start-session)on the initial HTTP request because you don’t want the session cookie being not HTTP only. - You have the
hunchenissr:rrfunction which can Re-Render a different client with some parameters (optional). This allows the advantages of websockets without the complexity of actually programming any. This doesn’t cover all the websocket use cases, but it covers some basic ones.
In addition to the back-end hunchenissr:rr function, there are two hooks: -on-connect-hook- and -on-disconnect-hook-. These hooks work like hooks in Emacs: they are each a list of functions; the functions should take a socket as their only parameter. Use pushnew to add functions to the hooks (best not to use anonymous functions). All functions in -on-connect-hook- are called right after a socket connects, so it’s request and previous page will be present in -clients- . All functions in -on-disconnect-hook- are run right before the socket disconnects so its request is also available in -clients-.
Enable Markup’s HTML syntax. You could use something like CL-WHO instead.
(markup:enable-reader)Define Easy Handler with ISSR.
This example is just an unordered list of consecutive numbers. The “add” button makes the list longer, and the “delete” button makes the list shorter (minimum length is 0).
(define-easy-handler (example :uri "/example")
((x :init-form "0"))
(setq x (parse-integer x))
(write-html
<html>
<head>
<script src="/issr.js"></script>
<script noupdate="t">
,(format nil "connect(~a, 'ws', ~a)" *id* *ws-port*)
</script>
<title>Easy Handler Example</title>
</head>
<body>
<ul>
<!-- Comma and ,@ are to run Lisp code and dump the result into HTML -->
<!-- ,@ is to dump a list rather than a value -->
,@(loop for n from 1 to x
collect <li>,(progn n)</li>)
</ul>
<button onclick="rr(this)" action="x" value=(+ x 1)>
add
</button>
<button onclick="rr(this)" action="x" value=(max 0 (- x 1))>
delete
</button>
</body>
</html>))Hunchenissr uses Hunchentoot and Portal for communications with the client.
To enter the debugger for errors on the initial connection:
(setq hunchentoot:*catch-errors-p* nil)To show errors to the client on the initial connection:
(setq hunchentoot:*show-lisp-errors-p* t)To *not* enter the debugger on subsequent errors:
(setq pws:*debug-on-error* nil)To show errors in the JavaScript console.error on subsequent errors:
(setq hunchenissr:*show-errors-to-client* t)If you find any bugs of have any issues (installing, using, questions) use the Github issue tracker.
If you want to contact me about collaboration, licensing, implementing a new back-end, etc. You can use the email in hunchenissr.asd.