(load "~/quicklisp/setup.lisp") (ql:quickload '(clack websocket-driver alexandria)) (defvar *connections* (make-hash-table)) (defun broadcast-to-room (connection message) (let ((message (format nil "{\"uid\":\"~a\", \"msg\":~a}" (gethash connection *connections*) message))) (loop :for con :being :the :hash-key :of *connections* :do (websocket-driver:send con message)))) (defun handle-new-connection (con) (let ((user (format nil "~a" (random 100000)))) (setf (gethash con *connections*) user) (websocket-driver:send con (format nil "{\"uid\":\"~a\",\"msg\":{\"cmd\":\"login\"}}" user)))) (defun handle-close-connection (connection) (let ((message (format nil "{ \"uid\":\"~a\",\"msg\":{\"cmd\":\"login\"}}" (gethash connection *connections*)))) (remhash connection *connections*) (loop :for con :being :the :hash-key :of *connections* :do (websocket-driver:send con message)))) (defun chat-server (env) (let ((ws (websocket-driver:make-server env))) (websocket-driver:on :open ws (lambda () (handle-new-connection ws))) (websocket-driver:on :message ws (lambda (msg) (broadcast-to-room ws msg))) (websocket-driver:on :error ws (lambda (msg) (format t "~a" msg))) (websocket-driver:on :close ws (lambda (&key code reason) (declare (ignore code reason)) (handle-close-connection ws))) (lambda (responder) (declare (ignore responder)) (websocket-driver:start-connection ws)))) (defvar *chat-handler* (clack:clackup #'chat-server :port 5000))