Live hacking a guile web server

Live hacking a guile web server

Published by Arun Isaac on

In other languages: தமிழ்

Tags: lisp, scheme, software

How to live hack a guile web server on the REPL

Live hacking running servers on the REPL is one of the many specialities of a lisp. But doing this in scheme, or at least in guile, is quite tricky. In this post, I will explain how I do it. This may not be the best solution. If you have a better idea, I'm eager to hear about it. Shoot me an email.

First, a simple guile web server that listens on localhost:8080.

(use-modules (web server))

(define (handler request request-body)
  (values '((content-type . (text/plain)))
          "Hello World!\n"))

(run-server handler)
$ curl http://localhost:8080
Hello World!

Now, let's add a REPL server that runs on a different thread and listens on a Unix socket at /tmp/guile.

(use-modules (system repl server)
             (web server))

(define (handler request request-body)
  (values '((content-type . (text/plain)))
          "Hello World!"))

(spawn-server (make-unix-domain-server-socket
               #:path "/tmp/guile"))
(run-server handler)

You can connect to this in Emacs using M-x geiser-connect-local /​tmp/guile. Now, modifying the definition of handler using the REPL does not reflect in the output of the web server. Why? The run-server function only obtains the "value" of handler. Even though you may have modified handler, run-server still holds on to the old value of handler.

How do we mitigate this? We could use the module introspection machinery to dereference the 'handler symbol on every request. We wrap this in a lambda function and pass that to run-server. Like so:

(run-server (lambda (request body)
              ((module-ref (current-module)
                            'handler)
               request body)))

Now, changes to handler should reflect correctly in the output of the web server.

If your handler is defined in a different module, say (my-project web-server-module), you could use the following.

(run-server (lambda (request body)
              ((module-ref (resolve-module '(my-project web-server-module))
                            'handler)
               request body)))