From 56ddb29c565e8cfc7b3fb66c17e9dc429c794553 Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Sun, 27 Aug 2023 20:17:49 -0500 Subject: [PATCH] Start of added (more than just a VPN) features. --- .gitignore | 3 + edit.sh | 3 + hamncheese/{global.gd => dialog.gd} | 0 hamncheese/main.gd | 76 ++++++++++----- hamncheese/main.tscn | 31 ++++-- hamncheese/peers.gd | 140 ++++++++++++++++++++++++++++ hamncheese/project.godot | 4 +- hamncheese/util.gd | 7 ++ 8 files changed, 235 insertions(+), 29 deletions(-) create mode 100755 edit.sh rename hamncheese/{global.gd => dialog.gd} (100%) create mode 100644 hamncheese/peers.gd create mode 100644 hamncheese/util.gd diff --git a/.gitignore b/.gitignore index b25c15b..958a53e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ *~ +output.log +bin/ +hamncheese/export_presets.cfg diff --git a/edit.sh b/edit.sh new file mode 100755 index 0000000..a708c94 --- /dev/null +++ b/edit.sh @@ -0,0 +1,3 @@ +#!/bin/bash +sudo godot/bin/godot.linuxbsd.editor.x86_64 --editor --path hamncheese | tee output.log + diff --git a/hamncheese/global.gd b/hamncheese/dialog.gd similarity index 100% rename from hamncheese/global.gd rename to hamncheese/dialog.gd diff --git a/hamncheese/main.gd b/hamncheese/main.gd index 7709bea..8eb8c4c 100644 --- a/hamncheese/main.gd +++ b/hamncheese/main.gd @@ -1,6 +1,8 @@ extends Control +const SERVER_PORT = 10042 + const FILE_ID_SETTINGS = 0 const FILE_ID_EXIT = 2 @@ -10,6 +12,7 @@ const HELP_ID_MANUAL = 1 @onready var online_check_button = %OnlineCheckButton @onready var my_ip_label = %MyIPLabel +@onready var peers_tree = %PeersTree @onready var settings_window = %SettingsWindow @onready var user_name_line_edit = %UserNameLineEdit @@ -30,6 +33,45 @@ const HELP_ID_MANUAL = 1 var net; +func _go_offline(): + #***TODO*** This can take some time. Show a message. + Peers.stop_server() + net.stop_network() + Peers.clear() + peers_tree.clear() + + +func _go_online(): + net.reset_configuration() + net.set_addresses("" if ip_check_button.button_pressed else ip_line_edit.text, "" if mac_check_button.button_pressed else mac_line_edit.text) + net.set_compression(compression_check_button.button_pressed) + net.set_network(user_name_line_edit.text, network_name_line_edit.text, network_password_line_edit.text) + net.set_supernode(server_line_edit.text, server_port_spin_box.value) + var result = net.start_network() + if result < 0: + # Something is wrong. Cancel starting network. + online_check_button.set_pressed_no_signal(false) + # Tell them what happened. + var message = "An unknown error occurred. Code: " + str(result) + match result: + -1: + message = "Invalid edge confguration." + -2: + message = "Failed to create interface. Are you running as " + if OS.get_name() == "Windows": + message = message + "Administrator?" + else: + message = message + "root?" + -3: + message = "Failed to initialize edge node." + Dialog.alert("Error Starting Network", message) + else: + # Successful connection. + var userInfo = {} + userInfo["user"] = user_name_line_edit.text + Peers.start_server(net.get_ip(), SERVER_PORT, userInfo) + + func _notification(what): # Window manager requested app close. if what == NOTIFICATION_WM_CLOSE_REQUEST: @@ -52,8 +94,6 @@ func _on_file_id_pressed(id): FILE_ID_EXIT: _show_exit_dialog() - #get_tree().root.propagate_notification(NOTIFICATION_WM_CLOSE_REQUEST) - #SceneTree.quit() func _on_help_id_pressed(id): @@ -78,19 +118,9 @@ func _on_manual_window_close_requested(): func _on_online_check_button_toggled(button_pressed): # Go online or offline. if button_pressed: - net.reset_configuration() - net.set_addresses("" if ip_check_button.button_pressed else ip_line_edit.text, "" if mac_check_button.button_pressed else mac_line_edit.text) - net.set_compression(compression_check_button.button_pressed) - net.set_network(user_name_line_edit.text, network_name_line_edit.text, network_password_line_edit.text) - net.set_supernode(server_line_edit.text, server_port_spin_box.value) - var result = net.start_network() - if result < 0: - # Something is wrong. Cancel starting network. - online_check_button.set_pressed_no_signal(false) - # Tell them what happened. - + _go_online() else: - net.stop_network() + _go_offline() func _on_save_settings_button_pressed(): @@ -122,13 +152,17 @@ func _on_timer_timeout(): my_ip_label.text = net.get_ip() # Update list of known peers. var peers = net.get_peers() - #for peer in peers: - # print_debug("Type: ", peer["type"], " IP: ", peer["ip"]) + if Peers.update(peers): + # Redraw peer tree. + peers_tree.clear() + for peer in Peers.peerArray: + var child = peers_tree.create_item(peers_tree.get_root()) + child.set_text(0, peer["user"] + " (" + peer["ip"] + ")") else: # Clear network information. my_ip_label.text = "" - - + + func _ready(): # Get our network object. net = N2NVPN.new() @@ -175,9 +209,9 @@ func _show_exit_dialog(): var message = "Are you sure you wish to exit?" if online_check_button.button_pressed: message = message + "\n\nThis will disconnect you from the network!\n" - var result = await Global.confirm("Exit", message) + var result = await Dialog.confirm("Exit", message) if result: if online_check_button.button_pressed: - net.stop_network() - get_tree().quit() + _go_offline() + Engine.get_main_loop().quit() diff --git a/hamncheese/main.tscn b/hamncheese/main.tscn index 751e7b4..d04e88a 100644 --- a/hamncheese/main.tscn +++ b/hamncheese/main.tscn @@ -13,9 +13,11 @@ script = ExtResource("1_ojpam") [node name="VBoxContainer" type="VBoxContainer" parent="."] layout_mode = 1 -anchors_preset = 10 +anchors_preset = 15 anchor_right = 1.0 +anchor_bottom = 1.0 grow_horizontal = 2 +grow_vertical = 2 metadata/_edit_use_anchors_ = true [node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] @@ -24,6 +26,7 @@ size_flags_vertical = 0 [node name="MenuBar" type="MenuBar" parent="VBoxContainer/HBoxContainer"] layout_mode = 2 +size_flags_horizontal = 3 size_flags_vertical = 0 [node name="File" type="PopupMenu" parent="VBoxContainer/HBoxContainer/MenuBar"] @@ -43,18 +46,32 @@ item_0/id = 0 item_1/text = "Manual..." item_1/id = 1 -[node name="MyIPLabel" type="Label" parent="VBoxContainer/HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 3 -horizontal_alignment = 1 - [node name="OnlineCheckButton" type="CheckButton" parent="VBoxContainer/HBoxContainer"] unique_name_in_owner = true layout_mode = 2 size_flags_horizontal = 8 text = "Online" +[node name="MyIPLabel" type="Label" parent="VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +horizontal_alignment = 1 + +[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +theme_override_constants/margin_left = 20 +theme_override_constants/margin_top = 20 +theme_override_constants/margin_right = 20 +theme_override_constants/margin_bottom = 20 + +[node name="PeersTree" type="Tree" parent="VBoxContainer/MarginContainer"] +unique_name_in_owner = true +layout_mode = 2 +hide_folding = true +hide_root = true + [node name="SettingsWindow" type="Window" parent="."] unique_name_in_owner = true title = "Settings" diff --git a/hamncheese/peers.gd b/hamncheese/peers.gd new file mode 100644 index 0000000..04ba3a1 --- /dev/null +++ b/hamncheese/peers.gd @@ -0,0 +1,140 @@ +extends Node + + +var _server := UDPServer.new() +var _userInfo: Dictionary +var _pendingPackets: Array +var _metadataTimer: Timer + +# This array is of dictionary elements that contain: +# "online": Will be true except when used to update the array. +# "type": Either "pending" or "known", which is confusing. +# "ip": IP address of this peer. +# "user": User name on this IP. +# "refresh": Do we need to redraw this entry? +var peerArray: Array + + +func _metadataTimerTimeout(): + if _server.is_listening(): + var method = {} + # Request updated metadata from everyone on the network. + method["method"] = "query" + for peer in peerArray: + _sendTo(peer["ip"], method) + + +func _process(_delta): + if _server.is_listening(): + # Handle incoming data. + _server.poll() + if _server.is_connection_available(): + var client: PacketPeerUDP = _server.take_connection() + var packet = client.get_packet() + var clientIP = client.get_packet_ip() + var raw = packet.get_string_from_utf8() + var jsonIn = JSON.new() + var error = jsonIn.parse(raw) + if error == OK: + # Remote node wants our information. + if jsonIn.data["method"] == "query": + var payload = {} + payload["method"] = "queryResponse" + payload["user"] = _userInfo["user"] + client.put_packet(JSON.stringify(payload).to_utf8_buffer()) + # Remote node replied to our query. + if jsonIn.data["method"] == "queryResponse": + for i in range(0, peerArray.size() - 1): + if peerArray[i]["ip"] == clientIP: + peerArray[i]["user"] = jsonIn.data["user"] + peerArray[i]["refresh"] = true + break + client.close() + # Handle outgoing data. + for outbound in _pendingPackets: + var destination := PacketPeerUDP.new() + destination.connect_to_host(outbound["ip"], _server.get_local_port()) + destination.put_packet(JSON.stringify(outbound["message"]).to_utf8_buffer()) + destination.close() + _pendingPackets.clear() + + +func _ready(): + clear() + _metadataTimer = Timer.new() + _metadataTimer.timeout.connect(_metadataTimerTimeout) + Engine.get_main_loop().current_scene.add_child(_metadataTimer) + _metadataTimer.start(5) + + +func _sendTo(ipAddress, message): + var pending = {} + pending["ip"] = ipAddress + pending["message"] = message + _pendingPackets.append(pending) + + +func clear(): + peerArray.clear() + + +func start_server(address, port, userInfo): + _userInfo = userInfo + if !_server.is_listening(): + _server.listen(port, address) + _pendingPackets.clear() + + +func stop_server(): + if _server.is_listening(): + _server.stop() + + +func update(peers: Array): + var changed = false + var found + + # Mark everyone as offline. + for i in range(0, peerArray.size() - 1): + peerArray[i]["online"] = false + + # Now go through everyone we know is connected and mark them online and update their type. + for peerEntry in peers: + found = false + for i in range(0, peerArray.size() - 1): + if peerEntry["ip"] == peerArray[i]["ip"]: + peerArray[i]["online"] = true + if peerArray[i]["type"] != peerEntry["type"]: + peerArray[i]["type"] = peerEntry["type"] + changed = true + found = true + break + # Is this a new entry? + if !found: + var newPeer = peerEntry + # Add all dictionary elements except "ip" and "type". + newPeer["user"] = "" + newPeer["online"] = true + newPeer["refresh"] = false + peerArray.append(newPeer) + changed = true + + # Delete everyone that is offline. + found = true + while found: + found = false + for i in range(0, peerArray.size() - 1): + if peerArray[i]["online"] == false: + found = true + peerArray.remove_at(i) + changed = true + break + + # Do we need to redraw the list? + for i in range(0, peerArray.size() - 1): + if peerArray[i]["refresh"] == true: + peerArray[i]["refresh"] = false + changed = true + + # Did the array change? + return changed diff --git a/hamncheese/project.godot b/hamncheese/project.godot index b69ed34..3338e4c 100644 --- a/hamncheese/project.godot +++ b/hamncheese/project.godot @@ -20,7 +20,9 @@ config/icon="res://icon.svg" [autoload] -Global="*res://global.gd" +Dialog="*res://dialog.gd" +Util="*res://util.gd" +Peers="*res://peers.gd" [display] diff --git a/hamncheese/util.gd b/hamncheese/util.gd new file mode 100644 index 0000000..14523a4 --- /dev/null +++ b/hamncheese/util.gd @@ -0,0 +1,7 @@ +extends Node + + +func delete_children(node): + for n in node.get_children(): + node.remove_child(n) + n.queue_free()