webserver.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. #!/usr/bin/env python
  2. # WS server example that synchronizes state across clients
  3. import asyncio
  4. import functools
  5. import json
  6. import logging
  7. import os
  8. import random
  9. import websockets
  10. from enum import Enum
  11. from command import (Command, Option)
  12. from game import Game
  13. from player import (Color, Player)
  14. logging.basicConfig()
  15. games = dict() # code -> game
  16. sockets = dict() # code -> [(player, websocket), ...]
  17. class DogEncoder(json.JSONEncoder):
  18. def default(self, obj):
  19. if hasattr(obj, '__dict__'):
  20. return obj.__dict__
  21. return json.JSONEncoder.default(self, obj)
  22. from http import HTTPStatus
  23. MIME_TYPES = {
  24. "html": "text/html",
  25. "js": "text/javascript",
  26. "css": "text/css"
  27. }
  28. async def process_request(sever_root, path, request_headers):
  29. """Serves a file when doing a GET request with a valid path."""
  30. if "Upgrade" in request_headers:
  31. return # Probably a WebSocket connection
  32. path = '/dog.html'
  33. response_headers = [
  34. ('Server', 'asyncio websocket server'),
  35. ('Connection', 'close'),
  36. ]
  37. # Derive full system path
  38. full_path = os.path.realpath(os.path.join(sever_root, path[1:]))
  39. # Validate the path
  40. if os.path.commonpath((sever_root, full_path)) != sever_root or \
  41. not os.path.exists(full_path) or not os.path.isfile(full_path):
  42. print("HTTP GET {} 404 NOT FOUND".format(path))
  43. return HTTPStatus.NOT_FOUND, [], b'404 NOT FOUND'
  44. # Guess file content type
  45. extension = full_path.split(".")[-1]
  46. mime_type = MIME_TYPES.get(extension, "application/octet-stream")
  47. response_headers.append(('Content-Type', mime_type))
  48. # Read the whole file into memory and send it out
  49. body = open(full_path, 'rb').read()
  50. response_headers.append(('Content-Length', str(len(body))))
  51. print("HTTP GET {} 200 OK".format(path))
  52. return HTTPStatus.OK, response_headers, body
  53. async def notify(playerSockets):
  54. if playerSockets:
  55. await asyncio.wait([websocket.send(json.dumps(player, cls=DogEncoder)) for (player, websocket) in playerSockets])
  56. async def handler(websocket, path):
  57. try:
  58. player = Player()
  59. player.options = [
  60. Option(Command.NEWGAME, None, "Nieuw spel"),
  61. Option(Command.JOINGAME, ["#"], "Doe mee met een spel")]
  62. async for message in websocket:
  63. option = Option(**json.loads(message))
  64. if not player.checkOption(option):
  65. await notify([(player, websocket)])
  66. continue
  67. if option.command == Command.NEWGAME:
  68. code = 3936 #random.randint(1000, 9999);
  69. sockets[code] = [(player, websocket)]
  70. player.message = f"De andere spelers kunnen meedoen door code {code} in te voeren"
  71. player.options = []
  72. await notify(sockets[code])
  73. elif option.command == Command.JOINGAME:
  74. code = int(option.args[0])
  75. socketlist = sockets.get(code)
  76. if socketlist == None:
  77. player.message = f"onbekande code {code}"
  78. await notify([(player, websocket)])
  79. continue
  80. sockets[code].append((player, websocket))
  81. if len(sockets[code]) < 4:
  82. player.message = "wacht op de andere spelers"
  83. player.options = []
  84. await notify([(player, websocket)])
  85. else:
  86. for (player, _) in sockets[code]:
  87. player.message = "Kies een kleur om mee te spelen"
  88. player.options = [
  89. Option(Command.PICKCOLOR, [Color.RED], "Rood"),
  90. Option(Command.PICKCOLOR, [Color.BLUE], "Blauw"),
  91. Option(Command.PICKCOLOR, [Color.YELLOW], "Geel"),
  92. Option(Command.PICKCOLOR, [Color.GREEN], "Groen")
  93. ]
  94. await notify(sockets[code])
  95. elif option.command == Command.PICKCOLOR:
  96. color = option.args[0]
  97. if any(other.color == color for (other, _) in sockets[code]):
  98. player.message = f"Kleur {option.text} is al gekozen door een andere speler. " + player.message
  99. await notify([(player, websocket)])
  100. continue
  101. player.color = color
  102. player.name = option.text
  103. player.message = "Wacht op de andere spelers"
  104. player.options = []
  105. for (other, _) in sockets[code]:
  106. other.options = [option for option in other.options if option.args[0] != color]
  107. if all( not any(p.options) for (p, _) in sockets[code]):
  108. game = Game(p for (p, _) in sockets[code])
  109. games[code] = game
  110. await notify(sockets[code])
  111. else:
  112. game = games[code]
  113. game.playOption(player, option)
  114. await notify(sockets[code])
  115. finally:
  116. sockets[code].remove((player, websocket))
  117. pass
  118. if __name__ == "__main__":
  119. staticHandler = functools.partial(process_request, os.getcwd() + '\\ui')
  120. start_server = websockets.serve(handler, "localhost", 6789, process_request=staticHandler)
  121. print("Running server at http://127.0.0.1:6789/")
  122. asyncio.get_event_loop().run_until_complete(start_server)
  123. asyncio.get_event_loop().run_forever()