;;;; ;;;; Naledi ya Africa ("Star of Africa") is an ncurses-based survival game ;;;; set in Africa. ;;;; ;;;; This file is responsible for connecting to the server. ;;;; ;;;; (c) 2018 Daniel Vedder, MIT license ;;;; (in-package :naledi-ya-africa) (let ((naledi-server NIL)) (defun connect-server (&optional (ip *host*) (port *port*)) "Connect to the specified server" ;;FIXME I need to catch some exceptions here... (setf naledi-server (usocket:socket-connect ip port)) (if naledi-server (notify "Connected to server ~A:~A" ip port) (notify "Connection to server ~A:~A failed." ip port))) (defun current-server () naledi-server) ;XXX remove after development? (defun connectedp () (not (null naledi-server))) (defun query-server (&rest request) "Send a request string to the server and return the answer" ;; If one argument is :ignore-errors, error strings are passed up ;; to the caller. Otherwise, they cause a crash. (unless naledi-server ;XXX do this with exceptions? (disconnect "No connection to server.") (return-from query-server)) (let* ((servstr (usocket:socket-stream naledi-server)) (ig-errors (find ':ignore-errors request)) (req (string-from-list (remove-if #'(lambda (s) (eq s ':ignore-errors)) request)))) (logf 4 "CLIENT: sending request ~S" request) (format servstr "~A~%" req) (finish-output servstr) ;;FIXME hangs if the server crashes (unless (usocket:wait-for-input naledi-server :timeout 5) ;XXX magic number ;;terminate gracefully if the server crashed or is unresponsive (disconnect "Server not responding, disconnected.")) (let ((reply (read servstr nil))) (logf 4 "CLIENT: received reply.") (when (search "ERROR" reply) (if ig-errors (logf 1 reply) (error reply))) reply))) (defun disconnect (&optional (msg "Disconnected from server.")) "Disconnect from the server" (when naledi-server (usocket:socket-close naledi-server) (setf naledi-server NIL) (notify msg)) ;;terminate if we're running a local game (when (runningp) (terminate))))