Autoconnect, reconnect, connection display

We can now autoconnect via parameter on web, e.g. `freq=430.200`, which
then autoconnects to that frequency, creating it when it is not already
created. We also now reconnect on connection failure and display the
connection state down below.
This commit is contained in:
Sebastian Lohff 2025-04-14 02:46:15 +02:00
parent 5dda7af184
commit aca5a97162
5 changed files with 136 additions and 61 deletions

View File

@ -1,7 +1,9 @@
extends Node
var first_connect_done := false
func get_external_freq_param():
match OS.get_name():
"web":
"Web":
return JavaScriptBridge.eval("new URL(window.location.href).searchParams.get('freq')")
return null

View File

@ -13,8 +13,20 @@ grow_vertical = 2
theme = ExtResource("1_2wc0w")
script = ExtResource("1_uyd8l")
[node name="ConnectView" type="Control" parent="."]
[node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="ConnectView" type="Control" parent="VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 3
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/ConnectView"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
@ -22,46 +34,42 @@ 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"]
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/ConnectView/VBoxContainer"]
layout_mode = 2
[node name="FrequencyCreator" type="TextEdit" parent="ConnectView/VBoxContainer/HBoxContainer"]
[node name="FrequencyCreator" type="TextEdit" parent="VBoxContainer/ConnectView/VBoxContainer/HBoxContainer"]
unique_name_in_owner = true
custom_minimum_size = Vector2(100, 0)
layout_mode = 2
theme_override_font_sizes/font_size = 20
text = "430.200"
[node name="Label" type="Label" parent="ConnectView/VBoxContainer/HBoxContainer"]
[node name="Label" type="Label" parent="VBoxContainer/ConnectView/VBoxContainer/HBoxContainer"]
layout_mode = 2
text = "MHz"
[node name="CreateButton" type="Button" parent="ConnectView/VBoxContainer/HBoxContainer"]
[node name="CreateButton" type="Button" parent="VBoxContainer/ConnectView/VBoxContainer/HBoxContainer"]
custom_minimum_size = Vector2(0, 100)
layout_mode = 2
size_flags_stretch_ratio = 2.41
text = "Create Frequency"
[node name="RefreshButton" type="Button" parent="ConnectView/VBoxContainer"]
[node name="RefreshButton" type="Button" parent="VBoxContainer/ConnectView/VBoxContainer"]
layout_mode = 2
text = "Refresh"
[node name="FreqList" type="ItemList" parent="ConnectView/VBoxContainer"]
[node name="FreqList" type="ItemList" parent="VBoxContainer/ConnectView/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 3
[node name="MorseView" type="Control" parent="."]
[node name="MorseView" type="Control" parent="VBoxContainer"]
unique_name_in_owner = true
visible = false
layout_mode = 2
size_flags_vertical = 3
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/MorseView"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
@ -69,43 +77,70 @@ anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="VBoxContainer" type="VBoxContainer" parent="MorseView"]
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="MorseView/VBoxContainer"]
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/MorseView/VBoxContainer"]
layout_mode = 2
[node name="Label" type="Label" parent="MorseView/VBoxContainer/HBoxContainer"]
[node name="Label" type="Label" parent="VBoxContainer/MorseView/VBoxContainer/HBoxContainer"]
layout_mode = 2
text = "Freq:"
[node name="FreqLabel" type="Label" parent="MorseView/VBoxContainer/HBoxContainer"]
[node name="FreqLabel" type="Label" parent="VBoxContainer/MorseView/VBoxContainer/HBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
[node name="PlayerContainer" type="VBoxContainer" parent="MorseView/VBoxContainer"]
[node name="PlayerContainer" type="VBoxContainer" parent="VBoxContainer/MorseView/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 3
[node name="MorseButton" type="Button" parent="MorseView/VBoxContainer"]
[node name="MorseButton" type="Button" parent="VBoxContainer/MorseView/VBoxContainer"]
layout_mode = 2
size_flags_vertical = 3
size_flags_stretch_ratio = 2.0
text = "MORSE"
[node name="LeaveButton" type="Button" parent="MorseView/VBoxContainer"]
[node name="LeaveButton" type="Button" parent="VBoxContainer/MorseView/VBoxContainer"]
layout_mode = 2
text = "Leave Frequency"
[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"]
[connection signal="button_down" from="MorseView/VBoxContainer/MorseButton" to="." method="_on_morse_button_button_down"]
[connection signal="button_up" from="MorseView/VBoxContainer/MorseButton" to="." method="_on_morse_button_button_up"]
[connection signal="pressed" from="MorseView/VBoxContainer/LeaveButton" to="." method="_on_leave_button_pressed"]
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"]
layout_mode = 2
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer/HBoxContainer"]
layout_mode = 2
text = "Status:"
[node name="StatusLabel" type="Label" parent="VBoxContainer/HBoxContainer/HBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "Disconnected"
[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer/HBoxContainer2"]
layout_mode = 2
mouse_filter = 0
text = "Last Error:"
[node name="ErrorLabel" type="Label" parent="VBoxContainer/HBoxContainer/HBoxContainer2"]
unique_name_in_owner = true
custom_minimum_size = Vector2(100, 0)
layout_mode = 2
mouse_filter = 0
text = "<None>"
autowrap_mode = 2
[connection signal="pressed" from="VBoxContainer/ConnectView/VBoxContainer/HBoxContainer/CreateButton" to="." method="_on_create_button_pressed"]
[connection signal="pressed" from="VBoxContainer/ConnectView/VBoxContainer/RefreshButton" to="." method="_on_refresh_button_pressed"]
[connection signal="item_clicked" from="VBoxContainer/ConnectView/VBoxContainer/FreqList" to="." method="_on_freq_list_join"]
[connection signal="button_down" from="VBoxContainer/MorseView/VBoxContainer/MorseButton" to="." method="_on_morse_button_button_down"]
[connection signal="button_up" from="VBoxContainer/MorseView/VBoxContainer/MorseButton" to="." method="_on_morse_button_button_up"]
[connection signal="pressed" from="VBoxContainer/MorseView/VBoxContainer/LeaveButton" to="." method="_on_leave_button_pressed"]
[connection signal="gui_input" from="VBoxContainer/HBoxContainer/HBoxContainer2/Label" to="." method="_on_error_label_gui_input"]
[connection signal="gui_input" from="VBoxContainer/HBoxContainer/HBoxContainer2/ErrorLabel" to="." method="_on_error_label_gui_input"]

View File

@ -33,7 +33,6 @@ func _ready():
print("External freq: ", Utils.get_external_freq_param())
if Utils.get_external_freq_param():
_on_multiplayer_button_pressed()
# FIXME: make this dependant on button

View File

@ -5,6 +5,8 @@ var port := "3784"
var ws_url := "wss://seba-geek.de/godot/cw-generator-ws/"
var IS_DEBUG = false
var ws := WebSocketPeer.new()
var ws_last_status = -1
var autoconnect_to_freq: String
var available_freqs = []
var mmb_self: MultiMorseBanner
@ -32,39 +34,61 @@ func _ready() -> void:
# FIXME: status / error messages
# FIXME: randomize default join frquency
# FIXME: automatic refresh
_connect_ws()
if not Utils.first_connect_done:
var cmdline_freq = Utils.get_external_freq_param()
if cmdline_freq:
autoconnect_to_freq = cmdline_freq
func _connect_ws():
if not IS_DEBUG:
print(ws_url)
print("Connecting to ", ws_url)
ws.connect_to_url(ws_url)
else:
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()
if state != WebSocketPeer.STATE_OPEN:
print("Error: websocket in state", state)
if ws_last_status != state:
match state:
WebSocketPeer.STATE_CONNECTING:
%StatusLabel.text = "Connecting...!"
WebSocketPeer.STATE_OPEN:
%StatusLabel.text = "Connected!"
WebSocketPeer.STATE_CLOSING:
%StatusLabel.text = "Disconnecting..."
WebSocketPeer.STATE_CLOSED:
%StatusLabel.text = "Disconnected :("
# Trigger reconnect
_trigger_reconnect(1)
ws_last_status = state
func _trigger_reconnect(delay: int):
await get_tree().create_timer(delay).timeout
_connect_ws()
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"):
print("Error: Could not parse data: ", data)
return
print("parsed ", parsed)
print("Recvd data: ", parsed)
match parsed["type"]:
"hello":
# fetch frequency list on first join
_on_refresh_button_pressed()
if autoconnect_to_freq:
send_data({"cmd": "create", "freq": autoconnect_to_freq, "join-if-present": true})
"join":
_join_freq(parsed["freq"], parsed["self_id"], parsed["other_players"])
@ -111,15 +135,9 @@ func _handle_packet() -> void:
return
remove_player(parsed["player"])
"leave":
%MorseView.hide()
mmb_self.set_morse_state(false)
for mmb: MultiMorseBanner in mmb_others.values():
mmb.set_morse_state(false)
mmb_self = null
mmb_others.clear()
for child in %PlayerContainer.get_children():
%PlayerContainer.remove_child(child)
%ConnectView.show()
_leave_freq()
"error":
%ErrorLabel.text = parsed["message"]
_:
print("Unhandled message: ", parsed["type"])
@ -136,6 +154,20 @@ func _join_freq(freq: String, player_id: String, other_players: Array):
%ConnectView.hide()
%MorseView.show()
func _leave_freq():
%MorseView.hide()
if mmb_self:
mmb_self.set_morse_state(false)
mmb_self = null
for mmb: MultiMorseBanner in mmb_others.values():
mmb.set_morse_state(false)
mmb_others.clear()
for child in %PlayerContainer.get_children():
%PlayerContainer.remove_child(child)
%ConnectView.show()
func _on_refresh_button_pressed() -> void:
var refresh_cmd := {"cmd": "list", "type": "cw-generator"}
var data := JSON.stringify(refresh_cmd) + "\n"
@ -191,6 +223,10 @@ func _on_morse_button_button_up() -> void:
return
set_morse_state(false)
func _on_leave_button_pressed() -> void:
send_data({"cmd": "leave"})
func _on_error_label_gui_input(event: InputEvent) -> void:
if event is InputEventMouseButton and event.pressed and event.button_index == 1:
%ErrorLabel.text = "<cleared>"

View File

@ -97,7 +97,10 @@ class Client:
return
if freq in self.freqs:
await self._send_error("Frequency already in use")
if data.get("join-if-present"):
await self._join_room({"freq": freq})
else:
await self._send_error("Frequency already in use")
return
self.curr_freq = freq