git.fiddlerwoaroof.com
myway-acceptor.lisp
55a3cfc9
 (defpackage :fwoar.myway-acceptor
   (:use :cl)
   (:export
    #:*current-route*
    #:define-route-group
    #:resolve-request
    #:myway-acceptor
    #:route-group))
 (in-package :fwoar.myway-acceptor)
 
 (defclass myway-acceptor (hunchentoot:acceptor)
   ((%mapper :initform (myway:make-mapper) :reader mapper)))
 
 (defvar *current-route*)
 (define-method-combination route-group
     ()
   ((routes (:route . *)))
   (:arguments server)
   `(progn
      ,@(mapcar (lambda (method)
                  (destructuring-bind (_ path . rest) (method-qualifiers method)
                    (declare (ignore _))
                    (let ((http-verb (when rest
                                       (etypecase (car rest)
                                         (keyword (list :method (car rest)))))))
                      `(let ((*current-route* ,path))
                         (myway:connect (mapper ,server) ,path
                                        (call-method ,method)
                                        ,@http-verb)))))
                (stable-sort routes #'<
                             :key (alexandria:compose #'length
                                                      #'cadr
                                                      #'method-qualifiers)))))
 
 (defmacro define-route-group (name (server &rest args) &body body)
   (let* ((docstring (when (and body (stringp (car body)))
                       (car body)))
          (body (if docstring
                    (cdr body)
                    body)))
     `(defgeneric ,name (,server ,@args)
        (:method-combination route-group)
        (:documentation ,docstring)
        ,@(mapcar (serapeum:op `(:method
                                    ,@(subseq _1 0 2)
                                  (,@(elt _1 2))
                                  ,@(subseq _1 3)))
                  body))))
 
 (defgeneric resolve-request (acceptor request)
   (:method-combination or :most-specific-first)
   (:method or ((acceptor myway-acceptor) request)
            (setf (hunchentoot:return-code*) 404)
            (format nil "~s not found" (hunchentoot:script-name*))))
 
 (defmethod hunchentoot:acceptor-dispatch-request ((acceptor myway-acceptor) request)
   (let ((router (mapper acceptor)))
     (multiple-value-bind (result matched) (myway:dispatch router (hunchentoot:script-name*)
                                                           :method (hunchentoot:request-method*))
       (if matched
           result
           (or (resolve-request acceptor request)
               (call-next-method))))))