Safe Haskell | None |
---|
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]
Type Synonyms
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: ConnectionHandler
, DisconnectHandler
, and CmdHandler
.
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
the servers clientList
. At this point, the ConnectionHandler
is notified
and a message is broadcast
ed to all connected clients. After this occurs,
the server respond
s 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)
The message 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.
type ConnectionHandler = Server -> ClientConn -> IO ()Source
Each server has one ConnectionHandler that is called each time a client connects to the server.
type DisconnectHandler = Server -> ClientConn -> IO ()Source
A DisconnectHandler is called each time a client is disconnected from the server.
type CmdHandler = [String] -> Server -> ClientConn -> IO ()Source
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 Construction
To start using a simple server, one simply specifies the ConnectionHandler
, DisconnectHandler
, and port that the server will use.
server <- new simpleConnect simpleDisconnect 10010
The server does not start after construction, instead one may now register
any number of CmdHandler
s on the server using addCommand
.
addCommand server "/repeat" repeatHandler
Once all of the desired CmdHandler
s have been registered on the server
the server may be started using start
start server
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 start
.
The incomming connections will be handed off to the
specified ConnectionHandler
and incoming messages
will be handed to the appropriate CmdHandler
. If an incoming message has
no 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 stop
stop server
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.
new :: ConnectionHandler -> DisconnectHandler -> Int -> IO ServerSource
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.
addCommand :: Server -> String -> CmdHandler -> IO ()Source
Given a server, a command, and a command handler, adds the command to the server. If the command already exists, it will be overwritten.
start :: Server -> IO ()Source
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.
Client Interaction
Each time a connection is made to a server a new ClientConn
is created and
added to the servers clientList
. The server then invokes a call to its
ConnectionHandler
.
Each ClientConn
has a unique cid
and property table which can be accessed
with lookup
and modified with modify
. Each stored property is defined
by a String and stores an associated String. If a property has never been
set using modify
it will be the empty string on lookup
.
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
This 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.
data ClientConn Source
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.
cid :: ClientConn -> IntegerSource
The Unique ID for this client
lookup :: ClientConn -> String -> IO StringSource
Looks up a property for this client. By default, all properties are the empty string.
modify :: ClientConn -> String -> String -> IO ()Source
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.
respond :: ClientConn -> String -> IO ()Source
Adds a message to the clients message queue to be handled eventually.
broadcast :: Server -> String -> IO ()Source
Adds a message to all clients message queue to be handled eventually.
disconnect :: ClientConn -> IO ()Source
Disconnects the client if they are still connected to the server.
clientList :: Server -> IO [ClientConn]Source
Returns a list of all clients that are currently connected to the server