1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
discard """
action: compile
"""
import asyncdispatch, asyncnet
type
Client = ref object
socket: AsyncSocket
netAddr: string
id: int
connected: bool
Server = ref object
socket: AsyncSocket
clients: seq[Client]
proc newServer(): Server =
## Constructor for creating a new ``Server``.
Server(socket: newAsyncSocket(), clients: @[])
proc `$`(client: Client): string =
## Converts a ``Client``'s information into a string.
$client.id & "(" & client.netAddr & ")"
proc processMessages(server: Server, client: Client) {.async.} =
## Loops while ``client`` is connected to this server, and checks
## whether as message has been received from ``client``.
while true:
# Pause execution of this procedure until a line of data is received from
# ``client``.
let line = await client.socket.recvLine()
# The ``recvLine`` procedure returns ``""`` (i.e. a string of length 0)
# when ``client`` has disconnected.
if line.len == 0:
echo(client, " disconnected!")
client.connected = false
# When a socket disconnects it must be closed.
client.socket.close()
return
# Display the message that was sent by the client.
echo(client, " sent: ", line)
# Send the message to other clients.
for c in server.clients:
# Don't send it to the client that sent this or to a client that is
# disconnected.
if c.id != client.id and c.connected:
await c.socket.send(line & "\c\l")
proc loop(server: Server, port = 7687) {.async.} =
## Loops forever and checks for new connections.
# Bind the port number specified by ``port``.
server.socket.bindAddr(port.Port)
# Ready the server socket for new connections.
server.socket.listen()
echo("Listening on localhost:", port)
while true:
# Pause execution of this procedure until a new connection is accepted.
let (netAddr, clientSocket) = await server.socket.acceptAddr()
echo("Accepted connection from ", netAddr)
# Create a new instance of Client.
let client = Client(
socket: clientSocket,
netAddr: netAddr,
id: server.clients.len,
connected: true
)
# Add this new instance to the server's list of clients.
server.clients.add(client)
# Run the ``processMessages`` procedure asynchronously in the background,
# this procedure will continuously check for new messages from the client.
asyncCheck processMessages(server, client)
# Check whether this module has been imported as a dependency to another
# module, or whether this module is the main module.
when isMainModule:
# Initialise a new server.
var server = newServer()
echo("Server initialised!")
# Execute the ``loop`` procedure. The ``waitFor`` procedure will run the
# asyncdispatch event loop until the ``loop`` procedure finishes executing.
waitFor loop(server)
|