git.fiddlerwoaroof.com
web-test.lisp
12d9536e
 (defpackage :fwoar.web-test
55a3cfc9
   (:import-from :fwoar.myway-acceptor :define-route-group)
   (:local-nicknames
    (:db :fwoar.web-test.db))
12d9536e
   (:use :cl )
   (:export ))
 (in-package :fwoar.web-test)
 
55a3cfc9
 (defclass my-server (fwoar.websocket-acceptor:websocket-acceptor
                      fwoar.myway-acceptor:myway-acceptor)
   ((%models :initarg :models :reader models)))
 
 (defgeneric register-model (server model)
   (:method (server model)
     (error "~s is not a class or a class name" model))
   (:method (server (model standard-class))
     (error "can only register server-aware classes, got ~s!" model))
   (:method ((server my-server) (model fwoar.server-aware-class:server-aware-class))
     (setf (fwoar.server-aware-class:server model) server))
   (:method ((server my-server) (model symbol))
     (register-model server (find-class model))))
12d9536e
 
55a3cfc9
 (defclass console-publisher ()
12d9536e
   ())
 
55a3cfc9
 (defmethod register-model ((publisher console-publisher)
                            (model fwoar.server-aware-class:server-aware-class))
   (setf (fwoar.server-aware-class:server model)
         publisher))
 
 (defmethod update-instance-for-redefined-class ((instance my-server) added-slots discarded-slots property-list &key models)
   (when (member '%models added-slots)
     (setf (slot-value instance '%models) models)))
12d9536e
 
 (defclass user (hunchensocket:websocket-client)
   ((name :initarg :user-agent :reader name :initform (error "Name this user!"))))
 
55a3cfc9
 (defclass chat-room (hunchensocket:websocket-resource)
   ((name :initarg :name :initform (error "Name this room!") :reader name))
   (:default-initargs :client-class 'user))
 
12d9536e
 (defvar *chat-rooms*
   (list (make-instance 'chat-room :name "/bongo")
         (make-instance 'chat-room :name "/fury")))
 
55a3cfc9
 (defmethod fwoar.websocket-acceptor:find-websocket-resource ((acceptor my-server) request)
12d9536e
   (find (hunchentoot:script-name request)
         *chat-rooms* :test #'string= :key #'name))
 
 (defun broadcast (room message &rest args)
   (loop for peer in (hunchensocket:clients room)
      do (hunchensocket:send-text-message peer (apply #'format nil message args))))
 
 (defmethod hunchensocket:client-connected ((room chat-room) user)
55a3cfc9
   )
12d9536e
 
 (defmethod hunchensocket:client-disconnected ((room chat-room) user)
55a3cfc9
   )
12d9536e
 
 (defmethod hunchensocket:text-message-received ((room chat-room) user message)
55a3cfc9
   )  
 
 (defun render-post (post)
   (spinneret:with-html
     (:section
      (:header
       (:h* (db:title post))
       (:div.author (db:author post)))
      (:section (db:content post)))))
 
 (defun summarize (post)
   (spinneret:with-html
     (:li
      (:a :href (format nil "/post/~a" (db:id post))
          (db:title post)))))
 
 
 
 (defmethod fwoar.server-aware-class:publish-value ((server my-server)
                                                    (object db:blog-post)
                                                    (slot (eql 'posts))
                                                    (old-value fset:map) (new-value fset:map))
   (unless (fset:equal? old-value new-value)
     (broadcast (car *chat-rooms*)
                (yason:with-output-to-string* (:indent t)
                  (yason:with-object ()
                    (yason:encode-object-elements
                     "slot" (string-downcase slot)
                     "type" (string-downcase (class-name (class-of object))))
                    (yason:with-object-element ("value")
                      (yason:with-array ()
                        (mapcar (lambda (it)
                                  (let ((val (fset:lookup new-value it)))
                                    (yason:with-object ()
                                      (yason:encode-object-elements
                                       "id" (id val)
                                       "title" (title val)))))
                                (fset:convert 'list (fset:domain (fset:map-difference-2 new-value old-value)))))))))))
 
 (defmethod fwoar.server-aware-class:publish-value ((server console-publisher)
                                                    (object db:blog-post)
                                                    slot
                                                    (old-value string)
                                                    (new-value string))
   (unless (equal old-value new-value)
     (format t "~&SLOT: ~s~%FROM: ~s~&TO: ~s~&"
             slot
             old-value
             new-value)))
 
 
 (defgeneric m-index (thing)
   )
 
 (defclass blog ()
   ((%montezuma-index :initarg :montezuma :reader m-index)))
 
 (defun posts (blog)
   (declare (ignorable blog))
   (list (db:make-blog-post "First Post" "Ed L" "This is the first post")
         (db:make-blog-post "Second Post" "Ed L" "This is the second post")
         (db:make-blog-post "Third Post" "Ed L" "This is the third post")
         (db:make-blog-post "Fourth Post" "Ed L" "This is the fourth post")))
 
 (defun connect-script ()
   (ps:ps
     (defun summarize (post)
       (spinneret:with-html
         (:li
          (:a :href (ps:chain "/post/"
                              (concat (ps:@ post id)))
              (ps:@ post title)))))
     (setf (ps:@ (ps:new (-web-socket "ws://localhost:12345/bongo")) onmessage)
           (lambda (e)
             (let ((data (ps:chain -j-s-o-n (parse (ps:@ e data)))))
               (ps:chain data value
                         (map (lambda (x)
                                (ps:chain document
                                          (query-selector "#posts")
                                          (append-child (summarize x)))))))))))
 
 (defun page ()
   (spinneret:with-html-string
     (:doctype)
     (:html
      (:body
       (:main
        (:section
         (:h* "My Blog")
         (:ul#posts
          (loop for post
             in (fset:convert 'list (fset:range (posts blog)))
             do (summarize post)))
         (:script
          (connect-script))))))))
 
 (define-route-group blog-methods (server blog)
   (:route "/" ((server my-server) (blog blog))
           (lambda (params)
             (declare (ignore params))
             ))
   (:route "/post/:id" ((server my-server) (blog blog))
           (lambda (params)
             (spinneret:with-html-string
                 (:doctype)
               (:html
                (:body
                 (:main
                  (:section
                   (:h* "My Blog")
                   (render-post
                    (fset:lookup (posts blog) (getf params :id)))))))))))