0674d389b035c5426d6059bd727e04bd810d976e — Thomas Letan 1 year, 4 months 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")))