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
import asyncdispatch, asyncnet, sequtils, json, tables, math, options
import ws, nmqtt
import types, vars, modbus
proc addVal* (resp: var string, name: string, key: string, val: string, lastUpdated: int64) =
resp = resp & name & "{"
resp = resp & "device=\"" & key & "\""
resp = resp & "} "
resp = resp & val
if lastUpdated != 0:
resp = resp & " "
resp = resp & $(lastUpdated * 1000)
resp = resp & "\n"
proc fmtBool* (b: bool): string =
if b:
return "1"
else:
return "0"
proc cleanupConnections*() =
# echo "subscribedConnections: " & $subscribedConnections.len
subscribedConnections.keepIf(proc(x: Websocket): bool = x.readyState != Closed)
wsConnections.keepIf(proc(x: Websocket): bool = x.readyState != Closed)
# echo "subscribedConnections(after clenup): " & $subscribedConnections.len
proc broadcast* (msg: string) =
cleanupConnections()
try:
for socket in subscribedConnections:
if socket.readyState == Open:
asyncCheck socket.send(msg)
except WebSocketError:
echo "socket closed:", getCurrentExceptionMsg()
proc broadcastServerState* () =
broadcast($(%*server.state))
proc sendPing* () =
try:
for socket in wsConnections:
if socket.readyState == Open:
asyncCheck socket.send("")
except WebSocketError:
echo "socket closed:", getCurrentExceptionMsg()
proc isaRound* [T: float32|float64](value: T, places: int = 0): float =
if places == 0:
result = round(value)
else:
result = value * pow(10.0, T(places))
result = floor(result)
result = result / pow(10.0, T(places))
proc checkAccessToken* (token: Option[string]): bool =
if not token.isNone:
if server.config.serverConfig.accessToken != token.get:
return false
else:
if server.config.serverConfig.accessToken != "":
return false
return true
proc closeOpenConnections* () =
#close mqtt connection
waitFor mqttContext.disconnect()
#close modbus connection
deinitModbus()
#close lacrosse socket
lacrosseSocket.close()
#close all websocket connections
for wsConnection in wsConnections:
wsConnection.close()
proc initUtil*() =
lastClientId = 1
subscribedConnections = @[]
#send empty paket every 2 seconds to every subscribed client
addTimer(2000, false, proc (fd: AsyncFD): bool {.gcsafe.} =
sendPing()
)
#clean up broken websocket connections every 60 seconds
addTimer(60000, false, proc (fd: AsyncFD): bool {.gcsafe.} =
cleanupConnections()
)