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() )