0674d389b035c5426d6059bd727e04bd810d976e — Thomas Letan 1 year, 1 month ago c50b84a
feature: Provide a new package :lb to fetch persistent resources

Currently, the only function the :lb package provides allows for
retrieving a player description in an asynchronous manner. The main
idea is to perform HTTP request, so that the backend can be
implemented in another process, potentially in another language.

Here is a straightforward use of #'lb:get-player:

   (as:start-event-loop
     (lambda ()
       (lb:get-player "lthms" :then #'print)))

A good way to provide a dummy (yet working) HTTP server is to use the
`http.server` module of python 3:

    python -m http.server 4001

The current implementation expect to find players in a `player/`
directory.

Signed-off-by: Thomas Letan <contact@thomasletan.fr>
2 files changed, 55 insertions(+), 2 deletions(-)

A backend.lisp
M lycan.asd
A backend.lisp => backend.lisp +46 -0
@@ 0,0 1,46 @@
+ ;; lycan.lisp: yet another game server for the lycan project
+ ;; Copyright (C) 2018 Thomas Letan <contact@thomasletan.fr>
+ ;;
+ ;; This program is free software: you can redistribute it and/or modify
+ ;; it under the terms of the GNU Affero General Public License as published
+ ;; by the Free Software Foundation, either version 3 of the License, or
+ ;; (at your option) any later version.
+ ;;
+ ;; This program is distributed in the hope that it will be useful,
+ ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ ;; GNU Affero General Public License for more details.
+ ;;
+ ;; You should have received a copy of the GNU Affero General Public License
+ ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ 
+ (defpackage :lycan/backend
+   (:nicknames :lb)
+   (:use :cl :alexandria)
+   (:export get-player))
+ 
+ (cl:in-package :lycan/backend)
+ 
+ (defclass player ()
+   ((name :initarg :name
+          :initform (error "must have a name")
+          :accessor name)
+    (characters :initarg :characters
+                :initform nil
+                :accessor characters)))
+ 
+ (defun get-player (name &key then event-cb)
+   (if then
+       (blackbird:catcher
+        (blackbird:multiple-promise-bind (body status)
+            (das:http-request (concatenate 'string "http://0.0.0.0:4001/player/" name))
+          (if (eq status 200)
+              (let* ((json-str (flexi-streams:octets-to-string body
+                                                               :external-format :utf-8))
+                     (json (jsown:parse json-str))
+                     (pl (make-instance 'player :name (jsown:val json "name"))))
+                (funcall then pl))))
+        (error (e)
+               (if event-cb
+                   (funcall event-cb e))))
+       (error "need to provide a callback to use the result"))))

M lycan.asd => lycan.asd +9 -2
@@ 20,8 20,15 @@ :license  "AGPLv3"
    :version "3.0.0"
    :serial t
-   :depends-on (cl-async alexandria vom)
-   :components ((:file "daemon")
+   :depends-on (cl-async
+                alexandria
+                drakma-async
+                blackbird
+                jsown
+                flexi-streams
+                vom)
+   :components ((:file "backend")
+                (:file "daemon")
                 (:file "daemon/player")
                 (:file "daemon/scene")
                 (:file "daemon/main")))