101 lines
2.7 KiB
Nim
101 lines
2.7 KiB
Nim
|
import asyncdispatch, asyncnet, os, strformat, strutils, tables
|
||
|
from net import IpAddress, Port, `$`
|
||
|
import ../../message
|
||
|
|
||
|
# TODO: we need to find out our own external IP and return it to clients who
|
||
|
# connect from our LAN
|
||
|
|
||
|
type
|
||
|
Register = object
|
||
|
peerId: string
|
||
|
ip: IpAddress
|
||
|
ports: array[3, Port]
|
||
|
|
||
|
GetInfo = object
|
||
|
peerId: string
|
||
|
|
||
|
NotifyPeer = object
|
||
|
sender: string
|
||
|
recipient: string
|
||
|
data: string
|
||
|
|
||
|
Client = object
|
||
|
sock: AsyncSocket
|
||
|
ip: IpAddress
|
||
|
ports: array[3, Port]
|
||
|
|
||
|
proc removeClient(clients: TableRef[string, Client], peerId: string) =
|
||
|
if peerId.len > 0: clients.del(peerId)
|
||
|
|
||
|
proc processClient(client: AsyncSocket, clients: TableRef[string, Client]) {.async.} =
|
||
|
let (address, port) = client.getPeerAddr
|
||
|
await client.send(&"notify-endpoint|{address}|{port.int}\n")
|
||
|
var id = ""
|
||
|
var peerId = ""
|
||
|
while true:
|
||
|
let line = await client.recvLine(maxLength = 400)
|
||
|
if line.len == 0:
|
||
|
removeClient(clients, peerId)
|
||
|
break
|
||
|
try:
|
||
|
let args = line.parseArgs(3)
|
||
|
id = args[1]
|
||
|
case args[0]:
|
||
|
of "register":
|
||
|
let req = parseMessage[Register](args[2])
|
||
|
peerId = req.peerId
|
||
|
clients[peerId] = Client(sock: client, ip: req.ip, ports: req.ports)
|
||
|
asyncCheck client.send(&"ok|{id}\n")
|
||
|
of "get-info":
|
||
|
let req = parseMessage[GetInfo](args[2])
|
||
|
let peer = clients[req.peerId]
|
||
|
let peerPorts = peer.ports.join(",")
|
||
|
asyncCheck client.send(&"ok|{id}|{peer.ip}|{peerPorts}\n")
|
||
|
of "notify-peer":
|
||
|
let req = parseMessage[NotifyPeer](args[2])
|
||
|
let recipient = clients[req.recipient]
|
||
|
asyncCheck recipient.sock.send(&"notify-peer|{req.sender}|{req.recipient}|{req.data}\n")
|
||
|
asyncCheck client.send(&"ok|{id}\n")
|
||
|
else:
|
||
|
client.close()
|
||
|
removeClient(clients, peerId)
|
||
|
break
|
||
|
|
||
|
except KeyError:
|
||
|
asyncCheck client.send(&"error|{id}|peer not registered\n")
|
||
|
|
||
|
except ValueError:
|
||
|
client.close
|
||
|
removeClient(clients, peerId)
|
||
|
break
|
||
|
|
||
|
proc serve(port: Port) {.async.} =
|
||
|
var clients = newTable[string, Client]()
|
||
|
var server = newAsyncSocket()
|
||
|
server.setSockOpt(OptReuseAddr, true)
|
||
|
server.bindAddr(port)
|
||
|
server.listen()
|
||
|
|
||
|
while true:
|
||
|
let client = await server.accept()
|
||
|
asyncCheck processClient(client, clients)
|
||
|
|
||
|
proc main() =
|
||
|
if paramCount() != 1:
|
||
|
echo(fmt"usage: {paramStr(0)} PORT")
|
||
|
quit(1)
|
||
|
|
||
|
try:
|
||
|
let portNumber = paramStr(1).parseUInt
|
||
|
if portNumber > uint16.high:
|
||
|
raise newException(ValueError, "port out of range")
|
||
|
let port = Port(portNumber)
|
||
|
asyncCheck serve(port)
|
||
|
runForever()
|
||
|
|
||
|
except ValueError as e:
|
||
|
echo e.msg
|
||
|
|
||
|
when isMainModule:
|
||
|
main()
|