old_dirserver.nim 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. ## directory server
  2. ## handles client authorization and assets
  3. import
  4. sockets, times, streams, streams_enh, tables, json, os,
  5. sg_packets, sg_assets, md5, server_utils, map_filter
  6. type
  7. THandler = proc(client: PCLient; stream: PStream)
  8. var
  9. server: TSocket
  10. handlers = initTable[char, THandler](16)
  11. thisZone = newScZoneRecord("local", "sup")
  12. zoneList = newScZoneList()
  13. thisZoneSettings: string
  14. zoneSlots: seq[tuple[name: string; key: string]] = @[]
  15. zones: seq[PClient] = @[]
  16. ## I was high.
  17. clients = initTable[TupAddress, PClient](16)
  18. alias2client = initTable[string, PClient](32)
  19. allClients: seq[PClient] = @[]
  20. proc findClient*(host: string; port: int16): PClient =
  21. let addy: TupAddress = (host, port)
  22. if clients.hasKey(addy):
  23. return clients[addy]
  24. result = newClient(addy)
  25. clients[addy] = result
  26. allClients.add(result)
  27. proc loginZone(client: PClient; login: SdZoneLogin): bool =
  28. if not client.auth:
  29. for s in zoneSlots.items:
  30. if s.name == login.name and s.key == login.key:
  31. client.auth = true
  32. client.kind = CServer
  33. client.record = login.record
  34. result = true
  35. break
  36. proc sendZoneList(client: PClient) =
  37. echo(">> zonelist ", client, ' ', HZoneList)
  38. client.send(HZonelist, zonelist)
  39. proc forwardPrivate(rcv: PClient; sender: PClient; txt: string) =
  40. var m = newScChat(CPriv, sender.alias, txt)
  41. rcv.send(HChat, m)
  42. proc sendChat(client: PClient; kind: ChatType; txt: string) =
  43. echo(">> chat ", client)
  44. var m = newScChat(kind, "", txt)
  45. client.send(HChat, m)
  46. var pubChatQueue = newIncomingBuffer()
  47. proc queuePub(sender: string, msg: CsChat) =
  48. var chat = newScChat(kind = CPub, fromPlayer = sender, text = msg.text)
  49. pubChatQueue.write(HChat)
  50. chat.pack(pubChatQueue)
  51. handlers[HHello] = (proc(client: PClient; stream: PStream) =
  52. var h = readCsHello(stream)
  53. if h.i == 14:
  54. var greet = newScHello("Well hello there")
  55. client.send(HHello, greet))
  56. handlers[HLogin] = proc(client: PClient; stream: PStream) =
  57. var loginInfo = readCsLogin(stream)
  58. echo("** login: alias = ", loginInfo.alias)
  59. if alias2client.hasKey(loginInfo.alias):
  60. client.sendError("Alias in use.")
  61. return
  62. if client.loginPlayer(loginInfo):
  63. alias2client[client.alias] = client
  64. client.sendMessage("Welcome "& client.alias)
  65. var session = newScLogin(client.id, client.alias, client.session)
  66. client.send HLogin, session
  67. client.sendZonelist()
  68. handlers[HZoneList] = proc(client: PClient; stream: PStream) =
  69. var pinfo = readCsZoneList(stream)
  70. echo("** zonelist req")
  71. sendZoneList client
  72. handlers[HChat] = proc(client: PClient; stream: PStream) =
  73. var chat = readCsChat(stream)
  74. if not client.auth:
  75. client.sendError("You are not logged in.")
  76. return
  77. if chat.target != "": ##private
  78. if alias2client.hasKey(chat.target):
  79. alias2client[chat.target].forwardPrivate(client, chat.text)
  80. else:
  81. queuePub(client.alias, chat)
  82. proc sendServMsg(client: PClient; msg: string) =
  83. var m = newDsMsg(msg)
  84. client.send HDsMsg, m
  85. handlers[HZoneLogin] = proc(client: PClient; stream: PStream) =
  86. var
  87. login = readSdZoneLogin(stream)
  88. if not client.loginZone(login):
  89. client.sendServMsg "Invalid login"
  90. else:
  91. client.sendServMsg "Welcome to the servers"
  92. echo "** Zone logged in: ", login
  93. zones.add client
  94. zonelist.zones.add client.record
  95. handlers[HFileChallenge] = proc(client: PClient; stream: PStream) =
  96. if client.auth:
  97. if client.kind == CServer:
  98. var chg = readScFileChallenge(stream)
  99. proc handlePkt(s: PClient; stream: PStream) =
  100. while not stream.atEnd:
  101. var typ = readChar(stream)
  102. if not handlers.hasKey(typ):
  103. break
  104. else:
  105. handlers[typ](s, stream)
  106. proc createServer(port: TPort) =
  107. if not server.isNil:
  108. server.close()
  109. server = socket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP, buffered = false)
  110. server.bindAddr(port)
  111. var clientIndex = 0
  112. var incoming = newIncomingBuffer()
  113. proc poll*(timeout: int = 250) =
  114. if server.isNil: return
  115. var
  116. reads = @[server]
  117. writes = @[server]
  118. if select(reads, timeout) > 0:
  119. var
  120. addy = ""
  121. port: TPort
  122. incoming.data.setLen 512
  123. let res = server.recvFromAsync(incoming.data, 512, addy, port, 0)
  124. if not res:
  125. echo("No recv")
  126. return
  127. else:
  128. var client = findClient(addy, port.int16)
  129. echo "<< ", res, " ", client, ": ", len(incoming.data), " ", repr(incoming.data)
  130. handlePkt(client, incoming)
  131. incoming.flush()
  132. if selectWrite(writes, timeout) > 0:
  133. let nclients = allClients.len
  134. if nclients == 0:
  135. return
  136. clientIndex = (clientIndex + 1) mod nclients
  137. var c = allClients[clientIndex]
  138. if c.outputBuf.getPosition > 0:
  139. let res = server.sendTo(c.addy.host, c.addy.port.TPort, c.outputBuf.data)
  140. echo("Write ", c, " result: ", res, " data: ", repr(c.outputBuf.data))
  141. c.outputBuf.flush()
  142. when true:
  143. import parseopt, strutils
  144. var cfgFile = "dirserver_settings.json"
  145. for kind, key, val in getOpt():
  146. case kind
  147. of cmdShortOption, cmdLongOption:
  148. case key
  149. of "f", "file":
  150. if fileExists(val):
  151. cfgFile = val
  152. else:
  153. echo("File does not exist: ", val)
  154. else:
  155. echo("Unknown option: ", key," ", val)
  156. else:
  157. echo("Unknown option: ", key, " ", val)
  158. var jsonSettings = parseFile(cfgFile)
  159. let port = TPort(jsonSettings["port"].num)
  160. zonelist.network = jsonSettings["network"].str
  161. for slot in jsonSettings["zones"].items:
  162. zoneSlots.add((slot["name"].str, slot["key"].str))
  163. createServer(port)
  164. echo("Listening on port ", port, "...")
  165. var pubChatTimer = cpuTime() #newClock()
  166. const PubChatDelay = 1000/1000
  167. while true:
  168. poll(15)
  169. ## TODO sort this type of thing VV into a queue api
  170. if cpuTime() - pubChatTimer > PubChatDelay: #.getElapsedTime.asMilliseconds > 100:
  171. pubChatTimer -= pubChatDelay
  172. if pubChatQueue.getPosition > 0:
  173. var cn = 0
  174. let sizePubChat = pubChatQueue.data.len
  175. var sent = 0
  176. filterIt2(allClients, it.auth == true and it.kind == CPlayer):
  177. it.outputBuf.writeData(addr pubChatQueue.data[0], sizePubChat)
  178. sent += 1
  179. #for c in allClients:
  180. # c.outputBuf.writeData(addr pubChatQueue.data[0], sizePubChat)
  181. pubChatQueue.flush()
  182. echo "pubChatQueue flushed to ", sent, "clients"