naledi / client / networking.lisp
;;;; 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))
			(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)))
	(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))))