The goal of SimpleServer, as its name implies, is to make it easy to build simple message passing servers by puting a layer between the programmer and the concurrent operations between it and the network layer connecting it to multiple clients.
- type ConnectionHandler = Server -> ClientConn -> IO ()
- type DisconnectHandler = Server -> ClientConn -> IO ()
- type CmdHandler = [String] -> Server -> ClientConn -> IO ()
- data Server
- new :: ConnectionHandler -> DisconnectHandler -> Int -> IO Server
- addCommand :: Server -> String -> CmdHandler -> IO ()
- start :: Server -> IO ()
- stop :: Server -> IO ()
- data ClientConn
- cid :: ClientConn -> Integer
- lookup :: ClientConn -> String -> IO String
- modify :: ClientConn -> String -> String -> IO ()
- respond :: ClientConn -> String -> IO ()
- broadcast :: Server -> String -> IO ()
- disconnect :: ClientConn -> IO ()
- clientList :: Server -> IO [ClientConn]
To start using simple server, the programmer simply needs to define
the callbacks that occur when a client connects, disconnects, or sends a message
to the server. These three callbacks have type synonyms defined:
To create a
ConnectionHandler that notifies all clients that a new client
has connected and respond to the new client with a simple welcome message
one might define the following:
simpleConnect :: ConnectionHandler simpleConnect server client = do broadcast server "A new user has joined." respond client "Welcome!"
When a connection is received, a new
ClientConn is created and added to
clientList. At this point, the
ConnectionHandler is notified
and a message is
broadcasted to all connected clients. After this occurs,
responds to the new client.
To create a
DisconnectHandler that notifies all clients that a user has
disconnected and send a goodbye message to the disconnecting client, one
might define the following:
simpleDisconnect :: DisconnectHandler simpleDisconnect server client = do broadcast server "A user has left the room." respond client "Goodbye!"
When a user disconnects, the server will call the
DisconnectHandler so any
cleanup may be done.
To create a
CmdHandler that repeats a received message to all connected
clients, one might define the following:
repeatHandler :: CmdHandler repeatHandler (cmd:msg) server client = do name <- lookup client "name" broadcast server $ name ++ > ++ (unwords msg)
CmdHandler is passed a list of strings which is the
message received from the client.
The first element of the list is the "command" that triggered the callback.
Each server has one ConnectionHandler that is called each time a client connects to the server.
A DisconnectHandler is called each time a client is disconnected from the server.
A server may have any number of CmdHandlers. When a CmdHandler is called it is passed a list of strings representing the message the server received, the server that received it, and the client that send the message. The first part element of the list is the string that triggered the CmdHandler.
server <- new simpleConnect simpleDisconnect 10010
addCommand server "/repeat" repeatHandler
If the port specified for the server is available, a new thread is started
and the server will now accept incoming connections. The control will then be returned to the thread that called
The incomming connections will be handed off to the
ConnectionHandler and incoming messages
will be handed to the appropriate
CmdHandler. If an incoming message has
CmdHandler the message "Invalid command: cmd" will be sent to the
client. If a client does not communicate with the server for more than 60 seconds
the client is disconnected from the server.
To stop a server use
All client buffers are flushed and disconnected from the server. All threads and handles that have been created by the server are killed and closed and then the control is returned to the thread that called stop.
Creates a new server with the specified ConnectionHandler and DisconnectHandler. On a call to start, the server will attempt to connect on the specified Port. If a client does not talk to a server for more than 60 seconds it will be disconnected.
Given a server, a command, and a command handler, adds the command to the server. If the command already exists, it will be overwritten.
Starts a server if it is currently not started. Otherwise, does nothing. The server will be started on a new thread and control will be returned to the thread that called this function.
Stops a server if it is running sending a disconnect message to all clients and killing any threads that have been spawned. Otherwise, does nothing. Any shutdown operations should be run before this is called.
ClientConn has a unique
cid and property table which can be accessed
lookup and modified with
modify. Each stored property is defined
by a String and stores an associated String. If a property has never been
modify it will be the empty string on
If you wanted to write a
CmdHandler that allowed a user to specify the
value stored in their table called "name", one might define:
nameHandler :: CmdHandler nameHandler (_:msg) server client = do case msg of  -> respond client "You did not provide a name to change to." msg -> do before <- lookup client "name" let name = unwords msg message = before ++ " is now known as " ++ name modify client "name" name broadcast server message
CmdHandler first checks that the client specified a name that
was not entirely white space. Then, it generates a message stating the name
they were using and the name they are now using with
lookup. Then using
modify the clients property "name"is changed to the value specified.
Finally, the generated message is
broadcast to all connected clients.
Describes a Clients connection and provides an interface for storing data associated with the client. Each client will be given a unique cid and are Eq if their cid's are Eq.
A ClientConn comes packaged with two functions for storing additional information in Strings, lookup and modify. The lookup function takes a key and returns the current value of the key or the empty string if it has never been set. The modify function takes a key and value and updates it such that the next call to lookup with that key will return the value provided.
Looks up a property for this client. By default, all properties are the empty string.
Modifies a client property. Given a property string, and a value string, the next call to lookup for the given property will result in the value.
Adds a message to the clients message queue to be handled eventually.
Adds a message to all clients message queue to be handled eventually.
Disconnects the client if they are still connected to the server.