Easily make TCP servers in Common Lisp.
Iri al dosiero
Jaidyn Lev a7f5301e87 Refactoring, etc. 2018-12-02 19:27:18 -06:00
src Refactoring, etc. 2018-12-02 19:27:18 -06:00
COPYING.txt Init 2018-12-02 02:09:38 -06:00
README.txt Added TODO list, and exported :journal for consitent logging. 2018-12-02 02:18:47 -06:00
facilservil.asd Refactoring, etc. 2018-12-02 19:27:18 -06:00

===============================================================================
FACILSERVIL : `Easy Server`                           Dead-simple, dead-useful.
===============================================================================

Sometimes, it's just annoying and time-draining to deal with all of the
intricacies of :usockets-- if, to that, you say something like...

        "I just want to write a simple TCP server, dammit!
         There's got to be an easier way!"

... then Facilservil is for you!

Facilservil ("easy server") abstracts away the entire server bits, allowing you
to focus on flexibility.


----------------------------------------
FEATURES
----------------------------------------

 * Multi-user
 * Shutdown protection
 * Input-handling
 * Simple logging system
 * Flexibility
 * UTF-8


----------------------------------------
DEMONSTRATION
----------------------------------------

Load up Facilservil, then run this in your repl:
    
       (facilservil:ex-server 8888)

Now, connect your computer on port 8888!
If you're on LiGNUx or BSD, you can use "telnet localhost 8888"

It'll show you a pretty example server. :)

In reality, 'ex-server is just a small function for demonstration-- the
example server really looks like this:

        (facilservil:server "0.0.0.0" port
	                    'facilservil:connect-ex 'facilservil:disconnect-ex
			    'facilservil:input-handle-ex)

It runs #'connect-ex when you connect, #'disconnect-ex when you disconnect,
and #'input-handle-ex after you finish a command, to handle your input.

If you wanna see this example's code (is there a better way to learn?), look
in "/src/ex.lisp".

For a different kind of example (less interesting, since it takes no user
input), look at QOTDD (https://git.eunichx.us/qotdd).

For a more comprehensive guide to Facilservil, look to USAGE, coming right up.


----------------------------------------
USAGE
----------------------------------------

To use Facilservil, just use the `facilservil:server` function somewhere:

        (facilservil:server host port
                            connecting disconnecting input-handler
                            &key (command-byte 10) (halting 'halt-ex))

"host" and "port" are, obviously, the host-IP and port, respectively.
"connecting"	is the function that will be executed when a user connects.
"disconnecting"	is the function that will run when someone disconnects.
"input-handler"	interprets the input of a user, when they complete a command.
"command-byte"	is the byte which determines if they've completed a command.
            	it's 10 by default, which is newline.
"halting"    	is the function executed when the server shuts down.


Basically, you write the "connecting", "disconnecting", and "input-handler"
functions (maybe "halting"), and you've got a handy-dandy server.

These functions you write must accept the following arguments:
        connecting	(socket client-id)
        disconnecting	(socket client-id)
        input-handler	(socket client-id input-string)
	halting    	()

Let's say that you want to write a connecting function which sends a friendly
"welcome" message. You'd do that like this, just about:

        (defun my-connecting-function (socket client-id)
	  (client-write socket
	    (format nil "Hey, welcome to this server, ~A! <3" client-id)
	    'T))

This will write to the connecting user's socket (which is passed to your
function), "Hey, welcome to this server," followed by their client-id.

Every user, upon connection, is given a client ID number which is correlated
with their connection socket. This ID number is random, and can be up to
999999 in value.

To send a message to a user, get their socket, and run
          (facilservil:client-write socket string &optional newline)

"newline", which defaults to nil, determines whether or not your message is
followed with a newline.

I'll give you one more quick example-- then you'll probably get usage.

Let's write a quick input handler.
           (defun my-input-handler (socket client-id input-string)
	     (if (equal input-string "Hello")
		(facilservil:client-write socket "And hi to you!" 't)
		(facilservil:client-write socket "You won't even say hi?" 'T)))

It should be pretty self-explanatory.
You just scale up from them-- write a nice command parser or something, and
you're on your way! :)

Now, one more thing: to run the server with your new functions, just do this:

            (facilservil:server host port
	    'my-connecting-function 'facilservil:disconnect-ex
	    'my-input-handler)


TIP: When it comes to user data, you might want to use a hash-table or two which
     correlate client-ids and user data. ^_^


----------------------------------------
NON-FEATURES (TODO)
----------------------------------------

 * Ctrl-C etc will crash servers
 * Some UTF characters don't go over well
 * Internationalization should be supported--
   right now, logs etc are always in English.
   Not cool.
 * You should be able to log to a file.


----------------------------------------
BORING STUFF
----------------------------------------
License is in COPYING (GNU GPLv3)
Author is Jaidyn Ann <jadedctrl@teknik.io>
Sauce is at https://git.eunichx.us/facilservil