~lthms/lycan.lisp

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