Add Websocket chat demo

This commit is contained in:
Fabio Alessandrelli
2019-07-28 14:20:57 +02:00
parent 949a9428eb
commit e9f02ff05f
11 changed files with 667 additions and 0 deletions

View File

@@ -0,0 +1,73 @@
extends Node
onready var _log_dest = get_parent().get_node("Panel/VBoxContainer/RichTextLabel")
var _client = WebSocketClient.new()
var _write_mode = WebSocketPeer.WRITE_MODE_BINARY
var _use_multiplayer = true
var last_connected_client = 0
func _init():
_client.connect("connection_established", self, "_client_connected")
_client.connect("connection_error", self, "_client_disconnected")
_client.connect("connection_closed", self, "_client_disconnected")
_client.connect("server_close_request", self, "_client_close_request")
_client.connect("data_received", self, "_client_received")
_client.connect("peer_packet", self, "_client_received")
_client.connect("peer_connected", self, "_peer_connected")
_client.connect("connection_succeeded", self, "_client_connected", ["multiplayer_protocol"])
_client.connect("connection_failed", self, "_client_disconnected")
func _client_close_request(code, reason):
Utils._log(_log_dest, "Close code: %d, reason: %s" % [code, reason])
func _peer_connected(id):
Utils._log(_log_dest, "%s: Client just connected" % id)
last_connected_client = id
func _exit_tree():
_client.disconnect_from_host(1001, "Bye bye!")
func _process(delta):
if _client.get_connection_status() == WebSocketClient.CONNECTION_DISCONNECTED:
return
_client.poll()
func _client_connected(protocol):
Utils._log(_log_dest, "Client just connected with protocol: %s" % protocol)
_client.get_peer(1).set_write_mode(_write_mode)
func _client_disconnected(clean=true):
Utils._log(_log_dest, "Client just disconnected. Was clean: %s" % clean)
func _client_received(p_id = 1):
if _use_multiplayer:
var peer_id = _client.get_packet_peer()
var packet = _client.get_packet()
Utils._log(_log_dest, "MPAPI: From %s Data: %s" % [str(peer_id), Utils.decode_data(packet, false)])
else:
var packet = _client.get_peer(1).get_packet()
var is_string = _client.get_peer(1).was_string_packet()
Utils._log(_log_dest, "Received data. BINARY: %s: %s" % [not is_string, Utils.decode_data(packet, is_string)])
func connect_to_url(host, protocols, multiplayer):
_use_multiplayer = multiplayer
if _use_multiplayer:
_write_mode = WebSocketPeer.WRITE_MODE_BINARY
return _client.connect_to_url(host, protocols, multiplayer)
func disconnect_from_host():
_client.disconnect_from_host(1000, "Bye bye!")
func send_data(data, dest):
_client.get_peer(1).set_write_mode(_write_mode)
if _use_multiplayer:
_client.set_target_peer(dest)
_client.put_packet(Utils.encode_data(data, _write_mode))
else:
_client.get_peer(1).put_packet(Utils.encode_data(data, _write_mode))
func set_write_mode(mode):
_write_mode = mode

View File

@@ -0,0 +1,130 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://client/client_ui.gd" type="Script" id=1]
[ext_resource path="res://client/client.gd" type="Script" id=2]
[node name="Client" type="Control"]
anchor_right = 1.0
anchor_bottom = 1.0
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Panel" type="Panel" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
__meta__ = {
}
[node name="VBoxContainer" type="VBoxContainer" parent="Panel"]
anchor_right = 1.0
anchor_bottom = 1.0
__meta__ = {
}
[node name="Connect" type="HBoxContainer" parent="Panel/VBoxContainer"]
margin_right = 1024.0
margin_bottom = 24.0
__meta__ = {
}
[node name="Host" type="LineEdit" parent="Panel/VBoxContainer/Connect"]
margin_right = 956.0
margin_bottom = 24.0
size_flags_horizontal = 3
text = "ws://localhost:8000/test/"
placeholder_text = "ws://my.server/path/"
__meta__ = {
}
[node name="Connect" type="Button" parent="Panel/VBoxContainer/Connect"]
margin_left = 960.0
margin_right = 1024.0
margin_bottom = 24.0
toggle_mode = true
text = "Connect"
__meta__ = {
}
[node name="Settings" type="HBoxContainer" parent="Panel/VBoxContainer"]
margin_top = 28.0
margin_right = 1024.0
margin_bottom = 52.0
__meta__ = {
}
[node name="Mode" type="OptionButton" parent="Panel/VBoxContainer/Settings"]
margin_right = 41.0
margin_bottom = 24.0
__meta__ = {
}
[node name="Multiplayer" type="CheckBox" parent="Panel/VBoxContainer/Settings"]
margin_left = 45.0
margin_right = 171.0
margin_bottom = 24.0
pressed = true
text = "Multiplayer API"
__meta__ = {
}
[node name="Destination" type="OptionButton" parent="Panel/VBoxContainer/Settings"]
margin_left = 175.0
margin_right = 216.0
margin_bottom = 24.0
__meta__ = {
}
[node name="Send" type="HBoxContainer" parent="Panel/VBoxContainer"]
margin_top = 56.0
margin_right = 1024.0
margin_bottom = 80.0
__meta__ = {
}
[node name="LineEdit" type="LineEdit" parent="Panel/VBoxContainer/Send"]
margin_right = 977.0
margin_bottom = 24.0
size_flags_horizontal = 3
placeholder_text = "Enter some text to send..."
__meta__ = {
}
[node name="Send" type="Button" parent="Panel/VBoxContainer/Send"]
margin_left = 981.0
margin_right = 1024.0
margin_bottom = 24.0
text = "Send"
__meta__ = {
}
[node name="RichTextLabel" type="RichTextLabel" parent="Panel/VBoxContainer"]
margin_top = 84.0
margin_right = 1024.0
margin_bottom = 600.0
size_flags_vertical = 3
__meta__ = {
}
[node name="Client" type="Node" parent="."]
script = ExtResource( 2 )
__meta__ = {
}
[connection signal="toggled" from="Panel/VBoxContainer/Connect/Connect" to="." method="_on_Connect_toggled"]
[connection signal="item_selected" from="Panel/VBoxContainer/Settings/Mode" to="." method="_on_Mode_item_selected"]
[connection signal="pressed" from="Panel/VBoxContainer/Send/Send" to="." method="_on_Send_pressed"]

View File

@@ -0,0 +1,59 @@
extends Control
onready var _client = get_node("Client")
onready var _log_dest = get_node("Panel/VBoxContainer/RichTextLabel")
onready var _line_edit = get_node("Panel/VBoxContainer/Send/LineEdit")
onready var _host = get_node("Panel/VBoxContainer/Connect/Host")
onready var _multiplayer = get_node("Panel/VBoxContainer/Settings/Multiplayer")
onready var _write_mode = get_node("Panel/VBoxContainer/Settings/Mode")
onready var _destination = get_node("Panel/VBoxContainer/Settings/Destination")
func _ready():
_write_mode.clear()
_write_mode.add_item("BINARY")
_write_mode.set_item_metadata(0, WebSocketPeer.WRITE_MODE_BINARY)
_write_mode.add_item("TEXT")
_write_mode.set_item_metadata(1, WebSocketPeer.WRITE_MODE_TEXT)
_destination.add_item("Broadcast")
_destination.set_item_metadata(0, 0)
_destination.add_item("Last connected")
_destination.set_item_metadata(1, 1)
_destination.add_item("All But last connected")
_destination.set_item_metadata(2, -1)
_destination.select(0)
func _on_Mode_item_selected( ID ):
_client.set_write_mode(_write_mode.get_selected_metadata())
func _on_Send_pressed():
if _line_edit.text == "":
return
var dest = _destination.get_selected_metadata()
if dest > 0:
dest = _client.last_connected_client
elif dest < 0:
dest = -_client.last_connected_client
Utils._log(_log_dest, "Sending data %s to %s" % [_line_edit.text, dest])
_client.send_data(_line_edit.text, dest)
_line_edit.text = ""
func _on_Connect_toggled( pressed ):
if pressed:
var multiplayer = _multiplayer.pressed
if multiplayer:
_write_mode.disabled = true
else:
_destination.disabled = true
_multiplayer.disabled = true
if _host.text != "":
Utils._log(_log_dest, "Connecting to host: %s" % [_host.text])
var supported_protocols = PoolStringArray(["my-protocol2", "my-protocol", "binary"])
_client.connect_to_url(_host.text, supported_protocols, multiplayer)
else:
_destination.disabled = false
_write_mode.disabled = false
_multiplayer.disabled = false
_client.disconnect_from_host()

View File

@@ -0,0 +1,62 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://server/server.tscn" type="PackedScene" id=1]
[ext_resource path="res://client/client.tscn" type="PackedScene" id=2]
[node name="Combo" type="Control"]
anchor_right = 1.0
anchor_bottom = 1.0
mouse_filter = 1
__meta__ = {
}
[node name="Box" type="HBoxContainer" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
custom_constants/separation = 20
__meta__ = {
}
[node name="ServerControl" parent="Box" instance=ExtResource( 1 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_right = 502.0
margin_bottom = 600.0
size_flags_horizontal = 3
[node name="VBoxContainer" type="VBoxContainer" parent="Box"]
margin_left = 522.0
margin_right = 1024.0
margin_bottom = 600.0
size_flags_horizontal = 3
__meta__ = {
}
[node name="Client" parent="Box/VBoxContainer" instance=ExtResource( 2 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_right = 502.0
margin_bottom = 197.0
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="Client2" parent="Box/VBoxContainer" instance=ExtResource( 2 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_top = 201.0
margin_right = 502.0
margin_bottom = 398.0
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="Client3" parent="Box/VBoxContainer" instance=ExtResource( 2 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_top = 402.0
margin_right = 502.0
margin_bottom = 600.0
size_flags_horizontal = 3
size_flags_vertical = 3

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://icon.png"
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View File

@@ -0,0 +1,28 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=4
_global_script_classes=[ ]
_global_script_class_icons={
}
[application]
config/name="Websocket Chat Demo"
run/main_scene="res://combo/combo.tscn"
config/icon="res://icon.png"
[autoload]
Utils="*res://utils.gd"
[gdnative]
singletons=[ ]

View File

@@ -0,0 +1,74 @@
extends Node
onready var _log_dest = get_parent().get_node("Panel/VBoxContainer/RichTextLabel")
var _server = WebSocketServer.new()
var _clients = {}
var _write_mode = WebSocketPeer.WRITE_MODE_BINARY
var _use_multiplayer = true
var last_connected_client = 0
func _init():
_server.connect("client_connected", self, "_client_connected")
_server.connect("client_disconnected", self, "_client_disconnected")
_server.connect("client_close_request", self, "_client_close_request")
_server.connect("data_received", self, "_client_receive")
_server.connect("peer_packet", self, "_client_receive")
_server.connect("peer_connected", self, "_client_connected", ["multiplayer_protocol"])
_server.connect("peer_disconnected", self, "_client_disconnected")
func _exit_tree():
_clients.clear()
_server.stop()
func _process(delta):
if _server.is_listening():
_server.poll()
func _client_close_request(id, code, reason):
print(reason == "Bye bye!")
Utils._log(_log_dest, "Client %s close code: %d, reason: %s" % [id, code, reason])
func _client_connected(id, protocol):
_clients[id] = _server.get_peer(id)
_clients[id].set_write_mode(_write_mode)
last_connected_client = id
Utils._log(_log_dest, "%s: Client connected with protocol %s" % [id, protocol])
func _client_disconnected(id, clean = true):
Utils._log(_log_dest, "Client %s disconnected. Was clean: %s" % [id, clean])
if _clients.has(id):
_clients.erase(id)
func _client_receive(id):
if _use_multiplayer:
var peer_id = _server.get_packet_peer()
var packet = _server.get_packet()
Utils._log(_log_dest, "MPAPI: From %s data: %s" % [peer_id, Utils.decode_data(packet, false)])
else:
var packet = _server.get_peer(id).get_packet()
var is_string = _server.get_peer(id).was_string_packet()
Utils._log(_log_dest, "Data from %s BINARY: %s: %s" % [id, not is_string, Utils.decode_data(packet, is_string)])
func send_data(data, dest):
if _use_multiplayer:
_server.set_target_peer(dest)
_server.put_packet(Utils.encode_data(data, _write_mode))
else:
for id in _clients:
_server.get_peer(id).put_packet(Utils.encode_data(data, _write_mode))
func listen(port, supported_protocols, multiplayer):
_use_multiplayer = multiplayer
if _use_multiplayer:
set_write_mode(WebSocketPeer.WRITE_MODE_BINARY)
return _server.listen(port, supported_protocols, multiplayer)
func stop():
_server.stop()
func set_write_mode(mode):
_write_mode = mode
for c in _clients:
_clients[c].set_write_mode(_write_mode)

View File

@@ -0,0 +1,129 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://server/server_ui.gd" type="Script" id=1]
[ext_resource path="res://server/server.gd" type="Script" id=2]
[node name="ServerControl" type="Control"]
anchor_right = 1.0
anchor_bottom = 1.0
script = ExtResource( 1 )
__meta__ = {
}
[node name="Server" type="Node" parent="."]
script = ExtResource( 2 )
__meta__ = {
}
[node name="Panel" type="Panel" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
__meta__ = {
}
[node name="VBoxContainer" type="VBoxContainer" parent="Panel"]
anchor_right = 1.0
anchor_bottom = 1.0
__meta__ = {
}
[node name="HBoxContainer" type="HBoxContainer" parent="Panel/VBoxContainer"]
margin_right = 1024.0
margin_bottom = 24.0
__meta__ = {
}
[node name="Port" type="SpinBox" parent="Panel/VBoxContainer/HBoxContainer"]
margin_right = 74.0
margin_bottom = 24.0
min_value = 1.0
max_value = 65535.0
value = 8000.0
__meta__ = {
}
[node name="Listen" type="Button" parent="Panel/VBoxContainer/HBoxContainer"]
margin_left = 78.0
margin_right = 129.0
margin_bottom = 24.0
toggle_mode = true
text = "Listen"
__meta__ = {
}
[node name="HBoxContainer2" type="HBoxContainer" parent="Panel/VBoxContainer"]
margin_top = 28.0
margin_right = 1024.0
margin_bottom = 52.0
__meta__ = {
}
[node name="WriteMode" type="OptionButton" parent="Panel/VBoxContainer/HBoxContainer2"]
margin_right = 41.0
margin_bottom = 24.0
__meta__ = {
}
[node name="MPAPI" type="CheckBox" parent="Panel/VBoxContainer/HBoxContainer2"]
margin_left = 45.0
margin_right = 171.0
margin_bottom = 24.0
pressed = true
text = "Multiplayer API"
__meta__ = {
}
[node name="Destination" type="OptionButton" parent="Panel/VBoxContainer/HBoxContainer2"]
margin_left = 175.0
margin_right = 216.0
margin_bottom = 24.0
__meta__ = {
}
[node name="HBoxContainer3" type="HBoxContainer" parent="Panel/VBoxContainer"]
margin_top = 56.0
margin_right = 1024.0
margin_bottom = 80.0
__meta__ = {
}
[node name="LineEdit" type="LineEdit" parent="Panel/VBoxContainer/HBoxContainer3"]
margin_right = 977.0
margin_bottom = 24.0
size_flags_horizontal = 3
__meta__ = {
}
[node name="Send" type="Button" parent="Panel/VBoxContainer/HBoxContainer3"]
margin_left = 981.0
margin_right = 1024.0
margin_bottom = 24.0
text = "Send"
__meta__ = {
}
[node name="RichTextLabel" type="RichTextLabel" parent="Panel/VBoxContainer"]
margin_top = 84.0
margin_right = 1024.0
margin_bottom = 600.0
size_flags_vertical = 3
__meta__ = {
}
[connection signal="toggled" from="Panel/VBoxContainer/HBoxContainer/Listen" to="." method="_on_Listen_toggled"]
[connection signal="item_selected" from="Panel/VBoxContainer/HBoxContainer2/WriteMode" to="." method="_on_WriteMode_item_selected"]
[connection signal="pressed" from="Panel/VBoxContainer/HBoxContainer3/Send" to="." method="_on_Send_pressed"]

View File

@@ -0,0 +1,67 @@
extends Control
onready var _server = get_node("Server")
onready var _port = get_node("Panel/VBoxContainer/HBoxContainer/Port")
onready var _line_edit = get_node("Panel/VBoxContainer/HBoxContainer3/LineEdit")
onready var _write_mode = get_node("Panel/VBoxContainer/HBoxContainer2/WriteMode")
onready var _log_dest = get_node("Panel/VBoxContainer/RichTextLabel")
onready var _multiplayer = get_node("Panel/VBoxContainer/HBoxContainer2/MPAPI")
onready var _destination = get_node("Panel/VBoxContainer/HBoxContainer2/Destination")
func _ready():
_write_mode.clear()
_write_mode.add_item("BINARY")
_write_mode.set_item_metadata(0, WebSocketPeer.WRITE_MODE_BINARY)
_write_mode.add_item("TEXT")
_write_mode.set_item_metadata(1, WebSocketPeer.WRITE_MODE_TEXT)
_write_mode.select(0)
_destination.add_item("Broadcast")
_destination.set_item_metadata(0, 0)
_destination.add_item("Last connected")
_destination.set_item_metadata(1, 1)
_destination.add_item("All But last connected")
_destination.set_item_metadata(2, -1)
_destination.select(0)
func _on_Listen_toggled( pressed ):
if pressed:
var use_multiplayer = _multiplayer.pressed
_multiplayer.disabled = true
var supported_protocols = PoolStringArray(["my-protocol", "binary"])
var port = int(_port.value)
if use_multiplayer:
_write_mode.disabled = true
_write_mode.select(0)
else:
_destination.disabled = true
_destination.select(0)
if _server.listen(port, supported_protocols, use_multiplayer) == OK:
Utils._log(_log_dest, "Listing on port %s" % port)
if not use_multiplayer:
Utils._log(_log_dest, "Supported protocols: %s" % supported_protocols)
else:
Utils._log(_log_dest, "Error listening on port %s" % port)
else:
_server.stop()
_multiplayer.disabled = false
_write_mode.disabled = false
_destination.disabled = false
Utils._log(_log_dest, "Server stopped")
func _on_Send_pressed():
if _line_edit.text == "":
return
var dest = _destination.get_selected_metadata()
if dest > 0:
dest = _server.last_connected_client
elif dest < 0:
dest = -_server.last_connected_client
Utils._log(_log_dest, "Sending data %s to %s" % [_line_edit.text, dest])
_server.send_data(_line_edit.text, dest)
_line_edit.text = ""
func _on_WriteMode_item_selected( ID ):
_server.set_write_mode(_write_mode.get_selected_metadata())

View File

@@ -0,0 +1,11 @@
extends Node
func encode_data(data, mode):
return data.to_utf8() if mode == WebSocketPeer.WRITE_MODE_TEXT else var2bytes(data)
func decode_data(data, is_string):
return data.get_string_from_utf8() if is_string else bytes2var(data)
func _log(node, msg):
print(msg)
node.add_text(str(msg) + "\n")