internal_stats_server.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. """DWC Network Server Emulator
  2. Copyright (C) 2014 polaris-
  3. Copyright (C) 2014 msoucy
  4. Copyright (C) 2015 Sepalani
  5. This program is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU Affero General Public License as
  7. published by the Free Software Foundation, either version 3 of the
  8. License, or (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU Affero General Public License for more details.
  13. You should have received a copy of the GNU Affero General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. """
  16. from twisted.web import server, resource
  17. from twisted.internet import reactor
  18. from twisted.internet.error import ReactorAlreadyRunning
  19. from multiprocessing.managers import BaseManager
  20. import time
  21. import datetime
  22. import json
  23. import logging
  24. import other.utils as utils
  25. import dwc_config
  26. logger = dwc_config.get_logger('InternalStatsServer')
  27. class GameSpyServerDatabase(BaseManager):
  28. pass
  29. GameSpyServerDatabase.register("get_server_list")
  30. class StatsPage(resource.Resource):
  31. """Servers statistics webpage.
  32. Format attributes:
  33. - header
  34. - row
  35. - footer
  36. """
  37. isLeaf = True
  38. header = """<html>
  39. <table border='1'>
  40. <tr>
  41. <td>Game ID</td><td># Players</td>
  42. </tr>"""
  43. row = """
  44. <tr>
  45. <td>%s</td>
  46. <td><center>%d</center></td>
  47. </tr>""" # % (game, len(server_list[game]))
  48. footer = """</table>
  49. <br>
  50. <i>Last updated: %s</i><br>
  51. </html>""" # % (self.stats.get_last_update_time())
  52. def __init__(self, stats):
  53. self.stats = stats
  54. def render_GET(self, request):
  55. if "/".join(request.postpath) == "json":
  56. raw = True
  57. force_update = True
  58. else:
  59. raw = False
  60. force_update = False
  61. server_list = self.stats.get_server_list(force_update)
  62. if raw:
  63. # List of keys to be removed
  64. restricted = ["publicip", "__session__", "localip0", "localip1"]
  65. # Filter out certain fields before displaying raw data
  66. if server_list is not None:
  67. for game in server_list:
  68. for server in server_list[game]:
  69. for r in restricted:
  70. if r in server:
  71. server.pop(r, None)
  72. output = json.dumps(server_list)
  73. else:
  74. output = self.header
  75. if server_list is not None:
  76. output += "".join(self.row % (game, len(server_list[game]))
  77. for game in server_list
  78. if server_list[game])
  79. output += self.footer % (self.stats.get_last_update_time())
  80. return output
  81. class InternalStatsServer(object):
  82. """Internal Statistics server.
  83. Running on port 9001 by default: http://127.0.0.1:9001/
  84. Can be displayed in json format: http://127.0.0.1:9001/json
  85. """
  86. def __init__(self):
  87. self.last_update = 0
  88. self.next_update = 0
  89. self.server_list = None
  90. # The number of seconds to wait before updating the server list
  91. self.seconds_per_update = 60
  92. def start(self):
  93. manager_address = dwc_config.get_ip_port('GameSpyManager')
  94. manager_password = ""
  95. self.server_manager = GameSpyServerDatabase(address=manager_address,
  96. authkey=manager_password.encode())
  97. self.server_manager.connect()
  98. site = server.Site(StatsPage(self))
  99. reactor.listenTCP(dwc_config.get_port('InternalStatsServer'), site)
  100. try:
  101. if not reactor.running:
  102. reactor.run(installSignalHandlers=0)
  103. except ReactorAlreadyRunning:
  104. pass
  105. def get_server_list(self, force_update=False):
  106. if force_update or self.next_update == 0 or \
  107. self.next_update - time.time() <= 0:
  108. self.last_update = time.time()
  109. self.next_update = time.time() + self.seconds_per_update
  110. self.server_list = self.server_manager.get_server_list() \
  111. ._getvalue()
  112. logger.log(logging.DEBUG, "%s", self.server_list)
  113. return self.server_list
  114. def get_last_update_time(self):
  115. return str(datetime.datetime.fromtimestamp(self.last_update))
  116. if __name__ == "__main__":
  117. stats = InternalStatsServer()
  118. stats.start()