;;;; src/main.lisp ;;;; ;;;; Main App Definition And Entry Point ;;;; (in-package :cl-user) (defpackage #:cl-deck-builder2 (:use #:cl #:cl-deck-builder2.db #:cl-deck-builder2.draw #:cl-deck-builder2.toolkit #:cl-deck-builder2.models ;;#:cl-deck-builder2-test ) (:local-nicknames (#:v #:org.shirakumo.verbose)) (:import-from :cl-deck-builder2.config :config :*app-log-file*) (:import-from :clack :clackup) (:export :start :stop :my/start :main) (:documentation "The main package for the deck builder project. This package exports the START and STOP functions, as well as the convenience function MY/START.")) (in-package :cl-deck-builder2) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defvar *appfile-path* (asdf:system-relative-pathname :cl-deck-builder2 #P"app.lisp") "The application path we pass to CLACK:CLACKUP.") (defvar *clack-handler* nil "The CLACK handler currently running. NIL if there is no server running.") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun start (&rest args &key server port debug &allow-other-keys) "Start the app. If the app is already running, raise an ERROR." (declare (ignore server port debug)) (when *clack-handler* (restart-case (error "Server is already running.") (restart-server () :report "Restart the server" (stop)))) (v:info :main "CLACKUP") (setf *clack-handler* (apply #'clackup *appfile-path* args))) (defun stop () "Stop the app, if it is running." (v:info :main "CLACK:STOP") (prog1 (clack:stop *clack-handler*) (setf *clack-handler* nil))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun my/start (&rest args) "Convenience function for invoking RESTART-SERVER in the case that the server is already running." (handler-bind ((simple-error (lambda (c) (format t "~A~&Invoking RESTART-SERVER." c) (invoke-restart 'restart-server)))) ;; TODO Multiple Addresses? ;; TODO Put it behind NGINX? ;; TODO sslh? (apply #'start args))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Loader Customize ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defmacro start-helper (service-name &body body) `(progn (v:info :app "~&Starting ~a ...~&" ,service-name) (if ,@body (v:info :app "~&... started.~&") (v:info :app "~&... failed?~&")))) ;; Initialize Logging ;; ;; (v:output-here *standard-output*) ;; (defun main () (v:output-here (open *app-log-file* :direction :output :if-does-not-exist :create :if-exists :append)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (v:start v:*global-controller*) (start-helper "slynk server" (apply #'slynk:create-server (config :slynk))) (v:info :app "~&Constructing database...~&") ;; (apply #'create-table *class-list*) (ensure-tables-exist) (v:info :app "~&...complete~%") (start-helper "web app" (apply #'my/start (config :server))) (start-helper "WebSocket Server Side Client" (handler-case (apply #'cl-deck-builder2.web::make-chat-client (config :websocket)) (usocket:connection-refused-error () nil) (usocket:connection-reset-error () nil))))