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
89
90
91
92
93
94
95
96
97
98
|
import
streams, md5, sockets, unsigned,
sg_packets, zlib_helpers, idgen
type
TClientType* = enum
CServer = 0'i8, CPlayer, CUnknown
PClient* = ref TClient
TClient* = object of TObject
id*: int32
addy*: TupAddress
clientID*: uint16
auth*: bool
outputBuf*: PStringStream
case kind*: TClientType
of CPlayer:
alias*: string
session*: string
lastPing*: float
failedPings*: int
of CServer:
record*: ScZoneRecord
cfg*: TChecksumFile
of CUnknown: nil
TChecksumFile* = object
unpackedSize*: int
sum*: MD5Digest
compressed*: string
TupAddress* = tuple[host: string, port: int16]
PIDGen*[T: Ordinal] = ref TIDGen[T]
TIDGen[T: Ordinal] = object
max: T
freeIDs: seq[T]
var cliID = newIdGen[int32]()
proc sendMessage*(client: PClient; txt: string)
proc sendError*(client: PClient; txt: string)
proc `$`*(client: PClient): string
proc newIncomingBuffer*(size = 1024): PStringStream =
result = newStringStream("")
result.data.setLen size
result.data.setLen 0
result.flushImpl = proc(stream: PStream) =
stream.setPosition(0)
PStringStream(stream).data.setLen(0)
proc free*(c: PClient) =
echo "Client freed: ", c
cliID.del c.id
c.outputBuf.flush()
c.outputBuf = nil
proc newClient*(addy: TupAddress): PClient =
new(result, free)
result.addy = addy
result.outputBuf = newStringStream("")
result.outputBuf.flushImpl = proc(stream: PStream) =
stream.setPosition 0
PStringStream(stream).data.setLen 0
proc loginPlayer*(client: PClient; login: CsLogin): bool =
if client.auth:
client.sendError("You are already logged in.")
return
client.id = cliID.next()
client.auth = true
client.kind = CPlayer
client.alias = login.alias
client.session = getMD5(client.alias & $rand(10000))
result = true
proc `$`*(client: PClient): string =
if not client.auth: return $client.addy
case client.kind
of CPlayer: result = client.alias
of CServer: result = client.record.name
else: result = $client.addy
proc send*[T](client: PClient; pktType: char; pkt: var T) =
client.outputBuf.write(pktType)
pkt.pack(client.outputBuf)
proc sendMessage*(client: PClient; txt: string) =
var m = newScChat(CSystem, text = txt)
client.send HChat, m
proc sendError*(client: PClient; txt: string) =
var m = newScChat(CError, text = txt)
client.send HChat, m
proc checksumFile*(filename: string): TChecksumFile =
let fullText = readFile(filename)
result.unpackedSize = fullText.len
result.sum = toMD5(fullText)
result.compressed = compress(fullText)
proc checksumStr*(str: string): TChecksumFile =
result.unpackedSize = str.len
result.sum = toMD5(str)
result.compressed = compress(str)
|