demo-counter.lisp (5061B)
1 ;;; Copyright (C) 2013, 2014, 2015 Tomas Hlavaty <tom@logand.com> 2 ;;; 3 ;;; Permission is hereby granted, free of charge, to any person 4 ;;; obtaining a copy of this software and associated documentation 5 ;;; files (the "Software"), to deal in the Software without 6 ;;; restriction, including without limitation the rights to use, copy, 7 ;;; modify, merge, publish, distribute, sublicense, and/or sell copies 8 ;;; of the Software, and to permit persons to whom the Software is 9 ;;; furnished to do so, subject to the following conditions: 10 ;;; 11 ;;; The above copyright notice and this permission notice shall be 12 ;;; included in all copies or substantial portions of the Software. 13 ;;; 14 ;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 ;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 ;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 ;;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 18 ;;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 19 ;;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 ;;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 ;;; DEALINGS IN THE SOFTWARE. 22 23 (defpackage :rw.demo.counter 24 (:use :cl)) 25 26 (in-package :rw.demo.counter) 27 28 (defun counter-widget (i rvar) 29 (let ((n 0)) ;;rw.ui:slet ((n 0 rvar)) 30 (lambda () 31 `(:p ,i ": " 32 " " ,(rw.ui:link "up" (lambda () (incf n))) 33 " " ,(rw.ui:link "down" (lambda () (decf n))) 34 " " (:b ,n))))) 35 36 (defun toplevel-widget () 37 (let ((w (mapcar 'counter-widget '(1 2 3 4) '(i j x y))) 38 (w2 (rw.ui:calendar-widget 2012 7))) 39 (lambda () 40 `(:html 41 (:head 42 ((:meta :http-equiv "content-type" 43 :content "text/html;charset=utf-8")) 44 ((:meta :http-equiv "cache-control" :content "no-cache,no-store")) 45 ((:meta :http-equiv "pragma" :content "no-cache")) 46 ((:meta :http-equiv "expires" :content -1)) 47 (:title "counter")) 48 (:body ,@(mapcar #'funcall w) ,(funcall w2)))))) 49 50 (defun construct (sid aid renv) 51 (let ((prefix "/")) 52 (with-output-to-string (s) 53 (format s "~a?s=~a&a=~a" prefix sid aid) 54 (loop 55 for (k v) on renv by #'cddr 56 when v 57 do (format s "&~(~a~)=~a" k v))))) 58 59 (defvar *query-parameters*) 60 61 (defun query-parameter (key) 62 (cdr (assoc key *query-parameters* :test #'equal))) 63 64 (defun deconstruct () 65 (values (query-parameter "s") 66 (query-parameter "a"))) 67 68 (defun draw-counter () 69 (rw.ui:draw (lambda () 70 (let ((w (toplevel-widget))) 71 (lambda () 72 `(:http-1.0 73 :code 200 74 :headers (("Content-Type" . "text/html;charset=utf-8") 75 ("cache-control" . "no-cache,no-store") 76 ("pragma" . "no-cache") 77 ("expires" . "-1")) 78 :body ,(funcall w))))) 79 'construct 80 'deconstruct)) 81 82 (defun counter-handler (msg stream method query protocol headers &optional body) 83 (declare (ignore protocol headers)) 84 (ecase msg 85 (:read (rw:till (rw:peek-reader stream))) 86 (:write 87 (let ((rw.ui:*http-server* 88 (let ((pp (rw.http::post-parameters method body))) 89 (lambda (msg &rest args) 90 (declare (ignore args)) 91 (ecase msg 92 (:method method) 93 (:post-parameters pp))))) 94 (*query-parameters* (nth-value 1 (rw.uri:parse-query-string query)))) 95 (draw-counter))))) 96 97 (defun start () 98 (rw.http:server (rw.socket:make-ipv4-address "0.0.0.0") 99 2349 100 'counter-handler 101 :quit (lambda () nil) 102 :allowed-methods '(:get :post) 103 :ignore-errors-p t)) 104 105 ;;(start) 106 107 (defun save-image () 108 #-(or ccl sbcl) 109 (error "TODO RW.DEMO.COUNTER::SAVE-IMAGE") 110 #+ccl ;; TODO no debug on ^C 111 (ccl:save-application "cl-rw-demo-counter" 112 :prepend-kernel t 113 :error-handler :quit-quietly 114 :toplevel-function (lambda () 115 (handler-case 116 (progn 117 (start) 118 (loop (sleep 1))) 119 (condition () 120 (ccl:quit 1))))) 121 #+sbcl 122 (sb-ext:save-lisp-and-die "cl-rw-demo-counter" 123 :executable t 124 :toplevel (lambda () 125 (handler-case 126 (progn 127 (start) 128 (loop (sleep 1))) 129 (condition () 130 (sb-ext:exit :code 1 :abort t))))))