(in-package :cl-user) (defpackage clack.handler (:use :cl) (:import-from :clack.util :find-handler) (:import-from :bordeaux-threads :threadp :make-thread :thread-alive-p :destroy-thread) (:import-from :usocket) (:export :run :stop)) (in-package :clack.handler) (defstruct handler server swank-port acceptor) (defun run (app server &rest args &key (address nil address-specified-p) use-thread (swank-interface "127.0.0.1") swank-port debug silent &allow-other-keys) (declare (ignorable swank-interface)) (let ((handler-package (find-handler server)) (bt2:*default-special-bindings* `((*standard-output* . ,*standard-output*) (*error-output* . ,*error-output*) ,@bt2:*default-special-bindings*))) (when (and debug (not silent)) (format t "NOTICE: Running in debug mode. Debugger will be invoked on errors. Specify ':debug nil' to turn it off on remote environments.")) (flet ((run-server () (when swank-port #+swank (swank:create-server :interface swank-interface :port swank-port :dont-close t) #-swank (error "Swank is required to use :swank-port but is not loaded. Load SLIME or Swank first.")) (apply (intern #.(string '#:run) handler-package) app :allow-other-keys t (append (and address-specified-p (list :address (usocket:host-to-hostname (usocket:get-host-by-name address)))) args)))) (make-handler :server server :swank-port swank-port :acceptor (if use-thread (bt2:make-thread #'run-server :name (format nil "clack-handler-~(~A~)" server) :initial-bindings `((bt2:*default-special-bindings* . ',bt2:*default-special-bindings*) ,@bt2:*default-special-bindings*)) (run-server)))))) (defun stop (handler) (let ((acceptor (handler-acceptor handler)) (swank-port (handler-swank-port handler))) (if (bt2:threadp acceptor) (progn (when (bt2:thread-alive-p acceptor) (bt2:destroy-thread acceptor)) (sleep 0.5)) (let ((package (find-handler (handler-server handler)))) (funcall (intern #.(string '#:stop) package) acceptor))) (when swank-port #+swank (swank:stop-server swank-port)) t))