Compare commits
1 Commits
main
...
multiplaye
Author | SHA1 | Date |
---|---|---|
|
e59a36a922 |
|
@ -129,7 +129,7 @@ permissions/install_location_provider=false
|
||||||
permissions/install_packages=false
|
permissions/install_packages=false
|
||||||
permissions/install_shortcut=false
|
permissions/install_shortcut=false
|
||||||
permissions/internal_system_window=false
|
permissions/internal_system_window=false
|
||||||
permissions/internet=false
|
permissions/internet=true
|
||||||
permissions/kill_background_processes=false
|
permissions/kill_background_processes=false
|
||||||
permissions/location_hardware=false
|
permissions/location_hardware=false
|
||||||
permissions/manage_accounts=false
|
permissions/manage_accounts=false
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
importer="texture"
|
importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://dvaugiwdmfmge"
|
uid="uid://bkoamufjn5wa1"
|
||||||
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
|
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"vram_texture": false
|
"vram_texture": false
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
[gd_scene load_steps=2 format=3 uid="uid://ug3u6jf36dst"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://j1oei8suq5sj" path="res://scenes/morse_banner.gd" id="1_a1ve8"]
|
||||||
|
|
||||||
|
[node name="MorseBanner" type="Control"]
|
||||||
|
custom_minimum_size = Vector2(200, 100)
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_a1ve8")
|
|
@ -0,0 +1,89 @@
|
||||||
|
[gd_scene load_steps=2 format=3 uid="uid://dnxcrx04kl3xy"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://di8r70441xdms" path="res://scenes/multiplayer_connect.gd" id="1_uyd8l"]
|
||||||
|
|
||||||
|
[node name="MultiplayerConnect" type="Control"]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_uyd8l")
|
||||||
|
|
||||||
|
[node name="ConnectView" type="Control" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="ConnectView"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="HBoxContainer" type="HBoxContainer" parent="ConnectView/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="FrequencyCreator" type="TextEdit" parent="ConnectView/VBoxContainer/HBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(100, 0)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "430.200"
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="ConnectView/VBoxContainer/HBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "MHz"
|
||||||
|
|
||||||
|
[node name="CreateButton" type="Button" parent="ConnectView/VBoxContainer/HBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_stretch_ratio = 2.41
|
||||||
|
text = "Create Frequency"
|
||||||
|
|
||||||
|
[node name="RefreshButton" type="Button" parent="ConnectView/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Refresh"
|
||||||
|
|
||||||
|
[node name="FreqList" type="ItemList" parent="ConnectView/VBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="MorseView" type="Control" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
visible = false
|
||||||
|
anchors_preset = 0
|
||||||
|
offset_right = 40.0
|
||||||
|
offset_bottom = 40.0
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="MorseView"]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_right = 40.0
|
||||||
|
offset_bottom = 40.0
|
||||||
|
|
||||||
|
[node name="HBoxContainer" type="HBoxContainer" parent="MorseView/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="MorseView/VBoxContainer/HBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Freq:"
|
||||||
|
|
||||||
|
[node name="FreqLabel" type="Label" parent="MorseView/VBoxContainer/HBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="MorseButton" type="Button" parent="MorseView/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
size_flags_stretch_ratio = 2.0
|
||||||
|
text = "MORSE"
|
||||||
|
|
||||||
|
[connection signal="pressed" from="ConnectView/VBoxContainer/HBoxContainer/CreateButton" to="." method="_on_create_button_pressed"]
|
||||||
|
[connection signal="pressed" from="ConnectView/VBoxContainer/RefreshButton" to="." method="_on_refresh_button_pressed"]
|
||||||
|
[connection signal="item_clicked" from="ConnectView/VBoxContainer/FreqList" to="." method="_on_freq_list_join"]
|
|
@ -6,6 +6,7 @@ var phase = 0.0
|
||||||
var morse_state := false
|
var morse_state := false
|
||||||
var playback: AudioStreamPlayback = null
|
var playback: AudioStreamPlayback = null
|
||||||
var vol_on := -30
|
var vol_on := -30
|
||||||
|
var multiplayer_enabled: bool = true # FIXME: maybe make this a tag?
|
||||||
|
|
||||||
func _process(_delta):
|
func _process(_delta):
|
||||||
fill_buffer()
|
fill_buffer()
|
||||||
|
@ -24,6 +25,9 @@ func _ready():
|
||||||
$Player.play()
|
$Player.play()
|
||||||
playback = $Player.get_stream_playback()
|
playback = $Player.get_stream_playback()
|
||||||
fill_buffer()
|
fill_buffer()
|
||||||
|
|
||||||
|
if multiplayer_enabled:
|
||||||
|
$VBoxContainer/MultiplayerButton.visible = true
|
||||||
|
|
||||||
OS.open_midi_inputs()
|
OS.open_midi_inputs()
|
||||||
print(OS.get_connected_midi_inputs())
|
print(OS.get_connected_midi_inputs())
|
||||||
|
@ -144,3 +148,7 @@ func _on_wav_button_pressed() -> void:
|
||||||
|
|
||||||
func _on_reset_button_pressed() -> void:
|
func _on_reset_button_pressed() -> void:
|
||||||
MorseState.reset()
|
MorseState.reset()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_multiplayer_button_pressed() -> void:
|
||||||
|
get_tree().change_scene_to_file("res://scenes/MultiplayerConnect.tscn")
|
||||||
|
|
|
@ -63,6 +63,11 @@ size_flags_vertical = 3
|
||||||
size_flags_stretch_ratio = 0.5
|
size_flags_stretch_ratio = 0.5
|
||||||
text = "Reset"
|
text = "Reset"
|
||||||
|
|
||||||
|
[node name="MultiplayerButton" type="Button" parent="VBoxContainer"]
|
||||||
|
visible = false
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Connect to Frequency"
|
||||||
|
|
||||||
[node name="Player" type="AudioStreamPlayer" parent="."]
|
[node name="Player" type="AudioStreamPlayer" parent="."]
|
||||||
stream = SubResource("AudioStreamGenerator_kvn5v")
|
stream = SubResource("AudioStreamGenerator_kvn5v")
|
||||||
volume_db = -80.0
|
volume_db = -80.0
|
||||||
|
@ -74,3 +79,4 @@ script = ExtResource("3_sugp2")
|
||||||
[connection signal="button_up" from="VBoxContainer/MorseButton" to="." method="_on_morse_button_up"]
|
[connection signal="button_up" from="VBoxContainer/MorseButton" to="." method="_on_morse_button_up"]
|
||||||
[connection signal="pressed" from="VBoxContainer/WavButton" to="." method="_on_wav_button_pressed"]
|
[connection signal="pressed" from="VBoxContainer/WavButton" to="." method="_on_wav_button_pressed"]
|
||||||
[connection signal="pressed" from="VBoxContainer/ResetButton" to="." method="_on_reset_button_pressed"]
|
[connection signal="pressed" from="VBoxContainer/ResetButton" to="." method="_on_reset_button_pressed"]
|
||||||
|
[connection signal="pressed" from="VBoxContainer/MultiplayerButton" to="." method="_on_multiplayer_button_pressed"]
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
@tool
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
var color_on := Color(0, 128, 0)
|
||||||
|
var color_off := Color(0, 0, 0)
|
||||||
|
var last_delta := 0.0
|
||||||
|
@export_range(0.1, 120.0) var display_sec := 5.0
|
||||||
|
@export var stretch_display := false
|
||||||
|
|
||||||
|
var morse_step_perc := 0.45
|
||||||
|
|
||||||
|
|
||||||
|
func _draw_morse_rect(x: float, width: float, state: bool):
|
||||||
|
var rect := Rect2(max(x, 0.0), morse_step_perc * size.y, width, (0.5 - morse_step_perc) * size.y)
|
||||||
|
draw_rect(rect, color_on if state else color_off, true, -1.0, true)
|
||||||
|
|
||||||
|
func _draw():
|
||||||
|
# black background
|
||||||
|
draw_rect(Rect2(0.0, 0.0, size.x, size.y), Color.BLACK)
|
||||||
|
|
||||||
|
# in editor we only want a black rectangle
|
||||||
|
if Engine.is_editor_hint():
|
||||||
|
return
|
||||||
|
|
||||||
|
var morse_on := MorseState.curr_state
|
||||||
|
var first_time := Time.get_ticks_msec() - MorseState.last_change
|
||||||
|
var curr_x := float(size.x)
|
||||||
|
|
||||||
|
var px_per_s := 0.0
|
||||||
|
if not stretch_display:
|
||||||
|
px_per_s = size.x / display_sec
|
||||||
|
else:
|
||||||
|
px_per_s = size.x / (Time.get_ticks_msec() - MorseState.start_time) * 1000.0
|
||||||
|
|
||||||
|
for n in [-1] + range(MorseState.states.size() - 1, -1, -1):
|
||||||
|
var duration := first_time if n == -1 else MorseState.states[n]
|
||||||
|
var rect_width: float = min(duration / 1000.0 * px_per_s, curr_x)
|
||||||
|
curr_x -= rect_width
|
||||||
|
if morse_on:
|
||||||
|
# at the moment we only draw the morse rects
|
||||||
|
_draw_morse_rect(curr_x, rect_width, morse_on)
|
||||||
|
morse_on = not morse_on
|
||||||
|
if curr_x <= 0.0:
|
||||||
|
break
|
||||||
|
|
||||||
|
func _process(_delta):
|
||||||
|
last_delta += _delta
|
||||||
|
queue_redraw()
|
|
@ -0,0 +1 @@
|
||||||
|
uid://b1k6j1jti114u
|
|
@ -0,0 +1,69 @@
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
var server := "localhost"
|
||||||
|
var port := "3784"
|
||||||
|
var ws := WebSocketPeer.new()
|
||||||
|
|
||||||
|
var mb_scene := preload("res://scenes/MultiMorseBanner.tscn")
|
||||||
|
var available_freqs = []
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
print("ws://%s:%s" % [server, port])
|
||||||
|
ws.connect_to_url("ws://%s:%s" % [server, port])
|
||||||
|
|
||||||
|
func refresh_list() -> void:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
|
ws.poll()
|
||||||
|
var state := ws.get_ready_state()
|
||||||
|
# print("moin ", state)
|
||||||
|
while state == WebSocketPeer.STATE_OPEN and ws.get_available_packet_count():
|
||||||
|
_handle_packet()
|
||||||
|
|
||||||
|
func _handle_packet() -> void:
|
||||||
|
var data := ws.get_packet().get_string_from_utf8()
|
||||||
|
print(data)
|
||||||
|
var parsed: Dictionary = JSON.parse_string(data)
|
||||||
|
if typeof(parsed) != TYPE_DICTIONARY or not parsed.has("type"):
|
||||||
|
return
|
||||||
|
print("parsed ", parsed)
|
||||||
|
|
||||||
|
match parsed["type"]:
|
||||||
|
"join":
|
||||||
|
_join_freq(parsed["freq"])
|
||||||
|
|
||||||
|
"freq-list":
|
||||||
|
%FreqList.clear()
|
||||||
|
for freq in parsed["freqs"]:
|
||||||
|
var text = "%s MHz (%d present)" % [freq["freq"], freq["players"]]
|
||||||
|
print("Adding ", text)
|
||||||
|
var idx: int = %FreqList.add_item(text)
|
||||||
|
%FreqList.set_item_metadata(idx, freq)
|
||||||
|
|
||||||
|
func _join_freq(freq: String):
|
||||||
|
%FreqLabel.text = "%s MHz" % freq
|
||||||
|
%ConnectView.hide()
|
||||||
|
%MorseView.show()
|
||||||
|
|
||||||
|
func _on_refresh_button_pressed() -> void:
|
||||||
|
var refresh_cmd := {"cmd": "list", "type": "cw-generator"}
|
||||||
|
var data := JSON.stringify(refresh_cmd) + "\n"
|
||||||
|
ws.send_text(data)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_create_button_pressed() -> void:
|
||||||
|
var freq: String = "%.3f" % float(%FrequencyCreator.text)
|
||||||
|
var refresh_cmd := {"cmd": "create", "type": "cw-generator", "freq": freq}
|
||||||
|
var data := JSON.stringify(refresh_cmd) + "\n"
|
||||||
|
ws.send_text(data)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_freq_list_join(index: int, at_position: Vector2, mouse_button_index: int) -> void:
|
||||||
|
var meta = %FreqList.get_item_metadata(index)
|
||||||
|
var freq: String = meta["freq"]
|
||||||
|
print("Yop ", index, " metadata ", freq)
|
||||||
|
var join_cmd := {"cmd": "join", "freq": freq, "type": "cw-generator"}
|
||||||
|
ws.send_text(JSON.stringify(join_cmd) + "\n")
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
uid://di8r70441xdms
|
|
@ -0,0 +1,146 @@
|
||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
|
||||||
|
from websockets.asyncio.server import serve
|
||||||
|
|
||||||
|
__VERSION__ = "0.0.1"
|
||||||
|
|
||||||
|
|
||||||
|
class Client:
|
||||||
|
freqs = {}
|
||||||
|
freq_re = re.compile(r"^\d+\.\d{3}$")
|
||||||
|
|
||||||
|
def __init__(self, websocket):
|
||||||
|
self.websocket = websocket
|
||||||
|
self.curr_freq = None
|
||||||
|
|
||||||
|
async def handle(self):
|
||||||
|
print(f" >>> New client {self.client} connected")
|
||||||
|
exc = None
|
||||||
|
try:
|
||||||
|
await self._handle_client()
|
||||||
|
except Exception as e:
|
||||||
|
exc = e
|
||||||
|
finally:
|
||||||
|
# FIXME: basically handle disconnect / leave from room
|
||||||
|
print(f" <<< Client {self.client} disconnected: {exc}")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def client(self):
|
||||||
|
ip, port, *_ = self.websocket.remote_address
|
||||||
|
if ':' in ip:
|
||||||
|
ip = f"[{ip}]"
|
||||||
|
return f"{ip}:{port}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def id(self):
|
||||||
|
return str(self.websocket.id)
|
||||||
|
|
||||||
|
async def _handle_client(self):
|
||||||
|
await self._send(type="hello", name="LobbySrv 3000", version=__VERSION__)
|
||||||
|
async for data in self.websocket:
|
||||||
|
print(f" <-- client {self.client} sent {repr(data)}")
|
||||||
|
try:
|
||||||
|
data = json.loads(data)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
self._send_error("Could not decode message, invalid json")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not isinstance(data, dict) or "cmd" not in data:
|
||||||
|
self._send_error("Invalid format in json")
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(f"{self.client} wrote:", data)
|
||||||
|
|
||||||
|
match data["cmd"]:
|
||||||
|
case "quit":
|
||||||
|
break
|
||||||
|
case "create":
|
||||||
|
await self._create_room(data)
|
||||||
|
case "join":
|
||||||
|
await self._join_room(data)
|
||||||
|
case "list":
|
||||||
|
freqs = [{"freq": freq, "players": len(players)}
|
||||||
|
for freq, players in self.freqs.items()]
|
||||||
|
await self._send(type="freq-list", freqs=freqs)
|
||||||
|
case "disconnect":
|
||||||
|
pass
|
||||||
|
case "morse-state":
|
||||||
|
# FIXME: send to all other clients
|
||||||
|
pass
|
||||||
|
case _:
|
||||||
|
await self._send_error("Unknown command")
|
||||||
|
|
||||||
|
async def _create_room(self, data):
|
||||||
|
if self.curr_freq:
|
||||||
|
await self._send_error(f"Already on frequency {self.curr_freq}")
|
||||||
|
return
|
||||||
|
|
||||||
|
if "freq" not in data:
|
||||||
|
await self._send_error("No frequency in create message")
|
||||||
|
return
|
||||||
|
freq = data["freq"]
|
||||||
|
|
||||||
|
if not self.freq_re.match(freq):
|
||||||
|
await self._send_error("Invalid frequency")
|
||||||
|
return
|
||||||
|
|
||||||
|
if freq in self.freqs:
|
||||||
|
await self._send_error("Frequency already in use")
|
||||||
|
return
|
||||||
|
|
||||||
|
self.curr_freq = freq
|
||||||
|
self.freqs[freq] = [self]
|
||||||
|
await self._send(type="join", freq=self.curr_freq, others=[])
|
||||||
|
|
||||||
|
async def _join_room(self, data):
|
||||||
|
if self.curr_freq:
|
||||||
|
await self._send_error(f"Already on frequency {self.curr_freq}")
|
||||||
|
return
|
||||||
|
|
||||||
|
if "freq" not in data:
|
||||||
|
await self._send_error("No frequency in join message")
|
||||||
|
return
|
||||||
|
freq = data["freq"]
|
||||||
|
|
||||||
|
if freq not in self.freqs:
|
||||||
|
await self._send_error(f"Frequency {freq} not available")
|
||||||
|
return
|
||||||
|
|
||||||
|
self.freqs[freq].append(self)
|
||||||
|
# FIXME: do we need locking here?
|
||||||
|
await self._send(type="join", freq=self.curr_freq, players=[c.id for c in self._others(freq)])
|
||||||
|
for other in self._others(freq):
|
||||||
|
await self._send(type="player-joined", player=self.id)
|
||||||
|
|
||||||
|
def _others(self, freq):
|
||||||
|
return [c for c in self.freqs[freq] if c != self.websocket]
|
||||||
|
|
||||||
|
async def _send(self, **kwargs):
|
||||||
|
data = json.dumps(kwargs).encode()
|
||||||
|
print(f" --> sending out to {self.client}: {data}")
|
||||||
|
await self.websocket.send(json.dumps(kwargs).encode() + b"\n")
|
||||||
|
|
||||||
|
async def _send_error(self, msg: str):
|
||||||
|
await self._send(type="error", message=msg)
|
||||||
|
|
||||||
|
|
||||||
|
async def new_client(websocket):
|
||||||
|
try:
|
||||||
|
client = Client(websocket)
|
||||||
|
await client.handle()
|
||||||
|
finally:
|
||||||
|
pass
|
||||||
|
# async for message in websocket:
|
||||||
|
# await websocket.send(message)
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
HOST, PORT = "localhost", 3784
|
||||||
|
async with serve(new_client, HOST, PORT) as server:
|
||||||
|
await server.serve_forever()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
|
@ -0,0 +1,81 @@
|
||||||
|
import json
|
||||||
|
import socketserver
|
||||||
|
|
||||||
|
__VERSION__ = "0.0.1"
|
||||||
|
|
||||||
|
# https://websockets.readthedocs.io/en/stable/reference/asyncio/server.html
|
||||||
|
|
||||||
|
|
||||||
|
class LobbyMgr:
|
||||||
|
__instance = None
|
||||||
|
|
||||||
|
def __new__(cls):
|
||||||
|
if cls.__instance is None:
|
||||||
|
cls.__instance = LobbyMgr()
|
||||||
|
|
||||||
|
return cls.__instance
|
||||||
|
|
||||||
|
|
||||||
|
class LobbyHandler(socketserver.StreamRequestHandler):
|
||||||
|
def handle(self):
|
||||||
|
print(f" >>> New client {self.client} connected")
|
||||||
|
exc = None
|
||||||
|
try:
|
||||||
|
self._handle_client()
|
||||||
|
except Exception as e:
|
||||||
|
exc = e
|
||||||
|
finally:
|
||||||
|
print(f" <<< Client {self.client} disconnected: {exc}")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def client(self):
|
||||||
|
return f"{':'.join(map(str, self.client_address))}"
|
||||||
|
|
||||||
|
def _handle_client(self):
|
||||||
|
self._send(type="hello", name="LobbySrv 3000", version=__VERSION__)
|
||||||
|
while True:
|
||||||
|
data = self.rfile.readline(10000).rstrip()
|
||||||
|
print(f" <-- client {self.client} sent {repr(data)}")
|
||||||
|
|
||||||
|
if not data.strip():
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
data = json.loads(data)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
self._send_error("Could not decode message, invalid json")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not isinstance(data, dict) or "cmd" not in data:
|
||||||
|
self._send_error("Invalid format in json")
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(f"{self.client_address[0]} wrote:", data)
|
||||||
|
|
||||||
|
match data["cmd"]:
|
||||||
|
case "quit":
|
||||||
|
break
|
||||||
|
case _:
|
||||||
|
self._send_error("Unknown command")
|
||||||
|
|
||||||
|
def _send(self, **kwargs):
|
||||||
|
data = json.dumps(kwargs).encode()
|
||||||
|
print(f" --> sending out to {self.client}: {data}")
|
||||||
|
self.wfile.write(json.dumps(kwargs).encode() + b"\n")
|
||||||
|
|
||||||
|
def _send_error(self, msg: str):
|
||||||
|
self._send(type="error", message=msg)
|
||||||
|
|
||||||
|
|
||||||
|
class LobbyServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
|
||||||
|
allow_reuse_address = True
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
HOST, PORT = "localhost", 3784
|
||||||
|
|
||||||
|
with LobbyServer((HOST, PORT), LobbyHandler) as server:
|
||||||
|
server.serve_forever()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Reference in New Issue