CL-CONT を使った継続ベースの Web アプリケーション

CL-CONT で継続を使って単にページ遷移するだけの Web アプリケーション。
基本はこんな感じで、あとはマクロでくるめばそれらしいものになるかしら。

(eval-when (:compile-toplevel :load-toplevel :execute)
  (require :hunchentoot)
  (require :cl-who)
  (require :cl-cont)
  (use-package :hunchentoot)
  (use-package :cl-who)
  (use-package :cl-cont))

;; エンコーディング設定
(setf *hunchentoot-default-external-format* '(:utf-8 :eol-style :lf)
      *default-content-type* "text/html; charset=utf-8")

(setf *dispatch-table*
      (list (create-regex-dispatcher "^/$" 'p0)))

(defmacro with-html (&body body)
  `(with-html-output-to-string (*standard-output* nil :indent t)
     ,@body))

(defun p1 ()
  (with-html
    (:html
     (:body "page 1"
            (:div (:a :href "/" "next"))))))
(defun p2 ()
  (with-html
    (:html
     (:body "page 2"
            (:div (:a :href "/" "next"))))))
(defun p3 ()
  (with-html
    (:html
     (:body "page 3"
            (:div (:a :href "/" "next"))))))

(defun p0 ()
  "リクエストハンドラ"
  (let ((cc (session-value 'cc)))
    (with-call/cc
      (let/cc k
        (if cc
            (funcall cc k)
            (page-flow k))))))

(defun page-flow (ret)
  "ページフロー。ここで page1 〜 page3 がリクエスト毎に呼び出されていく。"
  (with-call/cc
    (let/cc k
      (setf (session-value 'cc) k)
      (funcall ret (p1)))
    (let/cc k
      (setf (session-value 'cc) k)
      (funcall ret (p2)))
    (setf (session-value 'cc) nil)
    (funcall ret (p3))))

(defun start ()
  (start-server :port 7777))

;;(start)