mirror of
https://port.numenaute.org/aleajactaest/bazar_alea.git
synced 2024-11-14 03:09:08 +00:00
connect to XMPP
This commit is contained in:
parent
40d8cc0318
commit
0ab321c3e1
8 changed files with 636 additions and 12 deletions
335
client/Stream/Stream.gd
Normal file
335
client/Stream/Stream.gd
Normal file
|
@ -0,0 +1,335 @@
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
# Stream XMPP
|
||||||
|
# Author : AleaJactaEst
|
||||||
|
#
|
||||||
|
# https://xmpp.org/extensions/xep-0178.html
|
||||||
|
# https://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml
|
||||||
|
|
||||||
|
|
||||||
|
# Boucle
|
||||||
|
# - non connecte
|
||||||
|
# - connecte en claire
|
||||||
|
# - connecte en TLS
|
||||||
|
# - lance l'authentification
|
||||||
|
# - step authentification
|
||||||
|
# - identifie
|
||||||
|
|
||||||
|
signal send_msg_debug(message:String)
|
||||||
|
signal send_msg_error(message:String)
|
||||||
|
signal new_stanza(stanza)
|
||||||
|
|
||||||
|
enum StreamState {
|
||||||
|
END, # Stream is over. Starting with this.
|
||||||
|
START, # Stream hass started.
|
||||||
|
TLS, # Connection has been made and the first header is send. Let's get ssl!
|
||||||
|
AUTHENTICATE, # We have negotiated whether to use TLS, let's authenticate.
|
||||||
|
STANZA # We have authenticated, account is now allowed to send stanzas
|
||||||
|
}
|
||||||
|
var stream_status = StreamState.END
|
||||||
|
|
||||||
|
@export var server_ip:String = "localhost":
|
||||||
|
set = set_server_ip, get = get_server_ip
|
||||||
|
|
||||||
|
func set_server_ip(value:String):
|
||||||
|
server_ip = value
|
||||||
|
|
||||||
|
func get_server_ip() -> String:
|
||||||
|
return server_ip
|
||||||
|
|
||||||
|
@export var port_number:int = 5222:
|
||||||
|
set = set_port_number, get = get_port_number
|
||||||
|
|
||||||
|
func set_port_number(value:int):
|
||||||
|
port_number = value
|
||||||
|
|
||||||
|
func get_port_number() -> int:
|
||||||
|
return port_number
|
||||||
|
|
||||||
|
@export var account_name:String = "undefined@localhost":
|
||||||
|
set = set_account_name, get = get_account_name
|
||||||
|
|
||||||
|
func set_account_name(value:String):
|
||||||
|
account_name = value
|
||||||
|
|
||||||
|
func get_account_name() -> String:
|
||||||
|
return account_name
|
||||||
|
|
||||||
|
@export var password:String = "undefined":
|
||||||
|
set = set_password, get = get_password
|
||||||
|
|
||||||
|
func set_password(value:String):
|
||||||
|
password = value
|
||||||
|
|
||||||
|
func get_password() -> String:
|
||||||
|
return password
|
||||||
|
|
||||||
|
@export var locale:String = "en":
|
||||||
|
set = set_locale, get = get_locale
|
||||||
|
|
||||||
|
func set_locale(value:String):
|
||||||
|
locale = value
|
||||||
|
|
||||||
|
func get_locale() -> String:
|
||||||
|
return locale
|
||||||
|
|
||||||
|
@export var xmppclient:bool = false:
|
||||||
|
get:
|
||||||
|
return xmppclient
|
||||||
|
set(value):
|
||||||
|
xmppclient = value
|
||||||
|
|
||||||
|
var try_connect:int = 0
|
||||||
|
var count_connecting_time:float = 0
|
||||||
|
var partial_stanza:String = ""
|
||||||
|
var tcp_peer:StreamPeerTCP = StreamPeerTCP.new()
|
||||||
|
var ssl_peer:StreamPeerTLS = StreamPeerTLS.new()
|
||||||
|
var tgt_peer = null
|
||||||
|
var status:StreamState = StreamState.END
|
||||||
|
|
||||||
|
|
||||||
|
func _init():
|
||||||
|
var language = OS.get_locale()
|
||||||
|
set_locale(language)
|
||||||
|
tgt_peer = tcp_peer
|
||||||
|
|
||||||
|
func _process(delta):
|
||||||
|
#Global.msg_info("TCP:%d", [tcp_peer.get_status()])
|
||||||
|
print(server_ip, ":", port_number, " / get_status:" , tcp_peer.get_status(), " / count_connecting_time:", count_connecting_time, " / stream_status:", stream_status)
|
||||||
|
# if tcp_peer.get_status() == StreamPeerTCP.STATUS_NONE and stream_status == self.StreamState.TLS:
|
||||||
|
# #negotiate_tls()
|
||||||
|
# print("negotiate_tls")
|
||||||
|
# pass
|
||||||
|
if (tgt_peer.get_status() == StreamPeerTCP.STATUS_CONNECTED) :
|
||||||
|
print("STATUS_CONNECTED:", delta)
|
||||||
|
if (tgt_peer.has_method("poll")):
|
||||||
|
tgt_peer.poll()
|
||||||
|
if tgt_peer.get_available_bytes()>0:
|
||||||
|
var response = tgt_peer.get_string(tgt_peer.get_available_bytes())
|
||||||
|
send_msg_debug.emit("Stream: response: " + response)
|
||||||
|
if stream_status == self.StreamState.STANZA:
|
||||||
|
#collect_stanza(remove_stream_header(response))
|
||||||
|
Global.msg_info("", [])
|
||||||
|
print("collect_stanza")
|
||||||
|
else:
|
||||||
|
print("stream_process")
|
||||||
|
stream_process(remove_stream_header(response))
|
||||||
|
# print(remove_stream_header(response))
|
||||||
|
elif stream_status == self.StreamState.END:
|
||||||
|
start_stream()
|
||||||
|
stream_status = self.StreamState.START
|
||||||
|
count_connecting_time = 0
|
||||||
|
if tgt_peer.get_status() == StreamPeerTCP.STATUS_CONNECTING:
|
||||||
|
print("STATUS_CONNECTING:", delta)
|
||||||
|
count_connecting_time += delta
|
||||||
|
if (tgt_peer.has_method("poll")):
|
||||||
|
tgt_peer.poll()
|
||||||
|
if count_connecting_time > 60: # (1 -> 1s) if it took more than 1s to connect, error
|
||||||
|
print("**** Stream: Stuck connecting, will now disconnect")
|
||||||
|
Global.msg_error("Stream: Stuck connecting, will now disconnect", [])
|
||||||
|
send_msg_debug.emit("Stream: Stuck connecting, will now disconnect")
|
||||||
|
tgt_peer.disconnect_from_host() #interrupts connection to nothing
|
||||||
|
set_process(false) # stop listening for packets
|
||||||
|
try_connect = 20
|
||||||
|
stream_status = self.StreamState.END
|
||||||
|
if tgt_peer.get_status() == StreamPeerTCP.STATUS_NONE and xmppclient:
|
||||||
|
print("connect_to_server:", xmppclient)
|
||||||
|
connect_to_server()
|
||||||
|
xmppclient = false
|
||||||
|
|
||||||
|
|
||||||
|
func connect_to_server():
|
||||||
|
""" Connect to the server ip and port, and start checking whether there's stream info yet. """
|
||||||
|
if tcp_peer.get_status() == StreamPeerTCP.STATUS_CONNECTED:
|
||||||
|
pass
|
||||||
|
if try_connect == 0 and tcp_peer.get_status() == StreamPeerTCP.STATUS_NONE:
|
||||||
|
#print("-> ", server_ip, ":", port_number, "/" , tcp_peer.get_status())
|
||||||
|
var res = tcp_peer.connect_to_host(server_ip, port_number)
|
||||||
|
if res == OK:
|
||||||
|
count_connecting_time = 0
|
||||||
|
stream_status = self.StreamState.END
|
||||||
|
set_process(true)
|
||||||
|
tgt_peer = tcp_peer
|
||||||
|
else:
|
||||||
|
try_connect = 20
|
||||||
|
else:
|
||||||
|
try_connect -= 1
|
||||||
|
|
||||||
|
|
||||||
|
func send_string(stanza:String) ->void:
|
||||||
|
""" Send a string in the appropriate encoding. """
|
||||||
|
send_msg_debug.emit("Sending data: '%'".format([stanza], "%"))
|
||||||
|
tgt_peer.put_data(stanza.to_utf8_buffer())
|
||||||
|
|
||||||
|
|
||||||
|
func conv_string_to_PackedByteArray(message:String) -> PackedByteArray:
|
||||||
|
return message.to_ascii_buffer()
|
||||||
|
|
||||||
|
|
||||||
|
#func send_PackedByteArray(message:PackedByteArray) -> void:
|
||||||
|
# """ Send a PackedByteArray """
|
||||||
|
# send_msg_debug.emit("Sending data: '" + message.get_string_from_utf8() + "'")
|
||||||
|
# tgt_peer.put_data(message)
|
||||||
|
|
||||||
|
|
||||||
|
func start_stream() -> void:
|
||||||
|
""" Send the stream header.
|
||||||
|
Needs to be done several times over stream negotiation.
|
||||||
|
"""
|
||||||
|
var server_name = account_name.split("@")[-1]
|
||||||
|
var message:String = "<?xml version='1.0'?>" + \
|
||||||
|
"<stream:stream" + \
|
||||||
|
" xmlns=\"jabber:client\"" + \
|
||||||
|
" version=\"1.0\"" + \
|
||||||
|
" xmlns:stream=\"http://etherx.jabber.org/streams\"" + \
|
||||||
|
" from=\"" + account_name + "\" " + \
|
||||||
|
" to=\"" + server_name + "\" " + \
|
||||||
|
" xml:lang=\"en\"" + \
|
||||||
|
" > "
|
||||||
|
# " from=\"" + account_name + "\" " + \
|
||||||
|
# + locale + "'" +
|
||||||
|
print(message)
|
||||||
|
send_string(message)
|
||||||
|
|
||||||
|
func remove_stream_header(text :String) -> String:
|
||||||
|
var index = 0
|
||||||
|
if text.begins_with("<?") :
|
||||||
|
# Strip xml header
|
||||||
|
index = text.find("?>")
|
||||||
|
text = text.substr(index+2).strip_edges()
|
||||||
|
# strip stream header
|
||||||
|
var rg = RegEx.new()
|
||||||
|
rg.compile("<\\s?(stream|stream:stream)\\s")
|
||||||
|
var result = rg.search(text)
|
||||||
|
if result:
|
||||||
|
send_msg_debug.emit("Stream: Response header received")
|
||||||
|
index = text.find(">", result.get_end())
|
||||||
|
text = text.substr(index+1)
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
func stream_process(response :String = "") -> void:
|
||||||
|
""" Try to authenticate using SASL. We can currently only do plain.
|
||||||
|
For SCRAM based methods, we need HMAC at the very least.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if (!response.length() == 0 and stream_status != self.StreamState.STANZA):
|
||||||
|
if response.begins_with("<stream:error"):
|
||||||
|
var stream_error = XMPPStreamError.new()
|
||||||
|
stream_error.parse_from_xml(response)
|
||||||
|
var error_name = stream_error.error_name_for_enum(stream_error.error_type)
|
||||||
|
var error = tr('A stream error of type "%" occured, or in other words: % \n\nStream errors cannot be recovered from, the connection will be closed.'.format([error_name, stream_error.human_friendly_error_message()], "%"))
|
||||||
|
error.emit(error)
|
||||||
|
|
||||||
|
elif response.begins_with("<stream:features"):
|
||||||
|
var stream_features = XMPPStreamFeatures.new()
|
||||||
|
stream_features.parse_from_xml(response)
|
||||||
|
|
||||||
|
if stream_features.parsedDictionary.has("starttls"):
|
||||||
|
send_msg_debug.emit("Stream: sending request for ssl")
|
||||||
|
var request_tls = "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"
|
||||||
|
send_string(request_tls)
|
||||||
|
stream_status = self.StreamState.TLS
|
||||||
|
|
||||||
|
elif stream_features.parsedDictionary.has("mechanisms"):
|
||||||
|
print("response:", response)
|
||||||
|
var authentication_methods = stream_features.parsedDictionary["mechanisms"]
|
||||||
|
if (authentication_methods.size() > 0):
|
||||||
|
var tmp:String = ""
|
||||||
|
var sep:String = ""
|
||||||
|
for item in authentication_methods:
|
||||||
|
tmp += sep + item
|
||||||
|
sep = ", "
|
||||||
|
send_msg_debug.emit("Stream: authentication methods: " + tmp)
|
||||||
|
negotiate_sasl(authentication_methods)
|
||||||
|
stream_status = self.StreamState.AUTHENTICATE
|
||||||
|
|
||||||
|
else:
|
||||||
|
if stream_status == StreamState.TLS:
|
||||||
|
if response.begins_with("<proceed"):
|
||||||
|
send_msg_debug.emit("Stream: gotten go ahead for ssl")
|
||||||
|
negotiate_tls()
|
||||||
|
else:
|
||||||
|
send_msg_error.emit(tr("Tls negotiation failed."))
|
||||||
|
|
||||||
|
elif stream_status == StreamState.AUTHENTICATE:
|
||||||
|
if response.begins_with("<success"):
|
||||||
|
stream_status = self.StreamState.STANZA
|
||||||
|
# start_stream()
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
var parser = XMLParser.new()
|
||||||
|
# parser.open_buffer(response.to_utf8())
|
||||||
|
var failure_text = []
|
||||||
|
while parser.read() == OK:
|
||||||
|
if parser.get_node_type() == XMLParser.NODE_TEXT:
|
||||||
|
failure_text.append(parser.get_node_data())
|
||||||
|
print(failure_text)
|
||||||
|
# failure_text = tr("Authentication failed! %".format([PoolStringArray(failure_text).join(" ")], "%"))
|
||||||
|
var msg:String = ""
|
||||||
|
for item in failure_text:
|
||||||
|
msg += item
|
||||||
|
send_msg_error.emit(msg)
|
||||||
|
elif stream_status == self.StreamState.START:
|
||||||
|
connect_to_server()
|
||||||
|
start_stream()
|
||||||
|
else:
|
||||||
|
print("Mystery stream status: "+str(stream_status))
|
||||||
|
|
||||||
|
|
||||||
|
func negotiate_tls() -> void:
|
||||||
|
#var ssl_peer = StreamPeerTLS.new()
|
||||||
|
# I am unsure how to validate the ssl certificate for an unknown host?
|
||||||
|
#var ssl_succes = FAILED
|
||||||
|
var options:TLSOptions = TLSOptions.client_unsafe()
|
||||||
|
print("accept_stream")
|
||||||
|
#var ssl_succes = ssl_peer.accept_stream(tcp_peer, options)
|
||||||
|
var ssl_succes = ssl_peer.connect_to_stream(tcp_peer, "localhost", options)
|
||||||
|
print("resultat:", ssl_succes)
|
||||||
|
if ssl_succes == OK:
|
||||||
|
send_msg_debug.emit("Stream: switched to SSL!")
|
||||||
|
print("get_status:", ssl_peer.get_status())
|
||||||
|
# Wait connection done
|
||||||
|
while ssl_peer.get_status() == StreamPeerTLS.STATUS_HANDSHAKING:
|
||||||
|
ssl_peer.poll()
|
||||||
|
print("get_status:", ssl_peer.get_status())
|
||||||
|
tgt_peer = ssl_peer
|
||||||
|
start_stream()
|
||||||
|
print("get_status:", ssl_peer.get_status())
|
||||||
|
print("-----")
|
||||||
|
#stream_status == StreamState.START
|
||||||
|
else:
|
||||||
|
send_msg_error.emit("SSL failed, error %".format([ssl_succes], "%"))
|
||||||
|
|
||||||
|
|
||||||
|
func negotiate_sasl(authentication_methods : Array) -> void:
|
||||||
|
if (!authentication_methods.has("PLAIN")):
|
||||||
|
end_stream()
|
||||||
|
send_msg_debug.emit("Stream: sending request for plain")
|
||||||
|
var msg:PackedByteArray = PackedByteArray()
|
||||||
|
msg.push_back(0)
|
||||||
|
var t = account_name.split("@")[0]
|
||||||
|
msg += t.to_ascii_buffer()
|
||||||
|
#msg += conv_string_to_PackedByteArray(account_name.split("@")[0])
|
||||||
|
msg.push_back(0)
|
||||||
|
msg += password.to_ascii_buffer()
|
||||||
|
print("7:", msg)
|
||||||
|
|
||||||
|
var auth_account:String = Marshalls.raw_to_base64(msg)
|
||||||
|
var request_sasl:String = "<auth" + \
|
||||||
|
" xmlns='urn:ietf:params:xml:ns:xmpp-sasl'" + \
|
||||||
|
" mechanism='PLAIN'" + \
|
||||||
|
" >" + auth_account + "</auth>"
|
||||||
|
send_string(request_sasl)
|
||||||
|
|
||||||
|
|
||||||
|
func end_stream() -> void:
|
||||||
|
""" End the stream """
|
||||||
|
send_msg_debug.emit("Stream: Ending stream")
|
||||||
|
send_string("</stream>")
|
||||||
|
if tcp_peer.has_method("disconnect_from_stream"):
|
||||||
|
tcp_peer.disconnect_from_stream()
|
||||||
|
else:
|
||||||
|
tcp_peer.disconnect_from_host()
|
||||||
|
set_process(false)
|
||||||
|
stream_status = StreamState.END
|
147
client/Stream/xmpp_stream_errors.gd
Normal file
147
client/Stream/xmpp_stream_errors.gd
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
###
|
||||||
|
# This file is part of Godot XMPP Client
|
||||||
|
# SPDX-FileCopyrightText: 2020 Wolthera van Hovell tot Westerflier <griffinvalley@gmail.com>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
###
|
||||||
|
|
||||||
|
extends Resource
|
||||||
|
|
||||||
|
class_name XMPPStreamError
|
||||||
|
|
||||||
|
###
|
||||||
|
# This is a parser for stream errors, that keeps a list of human friendly error-explainations.
|
||||||
|
# Stream errors, unlike stanza errors, will always close the stream.
|
||||||
|
###
|
||||||
|
|
||||||
|
enum StreamErrorTypes{
|
||||||
|
bad_format,
|
||||||
|
bad_namespace_prefix,
|
||||||
|
conflict,
|
||||||
|
connection_timeout,
|
||||||
|
host_gone,
|
||||||
|
host_unknown,
|
||||||
|
improper_addressing,
|
||||||
|
internal_server_error,
|
||||||
|
invalid_from,
|
||||||
|
invalid_namespace,
|
||||||
|
invalid_xml,
|
||||||
|
not_authorized,
|
||||||
|
not_well_formed,
|
||||||
|
policy_violation,
|
||||||
|
remote_connection_failed,
|
||||||
|
reset,
|
||||||
|
resource_constraint,
|
||||||
|
restricted_xml,
|
||||||
|
see_other_host,
|
||||||
|
system_shutdown,
|
||||||
|
undefined_condition,
|
||||||
|
unsupported_encoding,
|
||||||
|
unsupported_feature,
|
||||||
|
unsupported_stanza_type,
|
||||||
|
unsupported_version
|
||||||
|
}
|
||||||
|
|
||||||
|
var humane_error_messages = {
|
||||||
|
StreamErrorTypes.bad_format:
|
||||||
|
tr("The sent message cannot be processed."),
|
||||||
|
StreamErrorTypes.bad_namespace_prefix:
|
||||||
|
tr("The namespace cannot be recognized"),
|
||||||
|
StreamErrorTypes.conflict:
|
||||||
|
tr("This connection conflicts with another connection coming from the same address, which makes it impossible to differentiate between the connections."),
|
||||||
|
StreamErrorTypes.connection_timeout:
|
||||||
|
tr("This client took too long to respond, and thus the server assumed the device had lost internet connection."),
|
||||||
|
StreamErrorTypes.host_gone:
|
||||||
|
tr("The address of the server has changed."),
|
||||||
|
StreamErrorTypes.host_unknown:
|
||||||
|
tr("The server does not know the address."),
|
||||||
|
StreamErrorTypes.improper_addressing:
|
||||||
|
tr("The address is missing from the sent message."),
|
||||||
|
StreamErrorTypes.internal_server_error:
|
||||||
|
tr("The server is experiencing issues, try again later."),
|
||||||
|
StreamErrorTypes.invalid_from:
|
||||||
|
tr("This connection is not allowed to sign it's messages with the given address."),
|
||||||
|
StreamErrorTypes.invalid_namespace:
|
||||||
|
tr("The message was formatted with an incorrect namespace."),
|
||||||
|
StreamErrorTypes.invalid_xml:
|
||||||
|
tr("The message was formatted with invalid xml."),
|
||||||
|
StreamErrorTypes.not_authorized:
|
||||||
|
tr("The client is not allowed to sent these messages because it is not authorized to do so."),
|
||||||
|
StreamErrorTypes.not_well_formed:
|
||||||
|
tr("The message was formatted with incorrectly formed xml."),
|
||||||
|
StreamErrorTypes.policy_violation:
|
||||||
|
tr("The server determined the message violated server policy in some technical manner."),
|
||||||
|
StreamErrorTypes.remote_connection_failed:
|
||||||
|
tr("The server is unable to deliver the message because it cannot connect to the other server."),
|
||||||
|
StreamErrorTypes.reset:
|
||||||
|
tr("The server closed the connection because it deemed to connection needed to be reset for either feature or security purposes."),
|
||||||
|
StreamErrorTypes.resource_constraint:
|
||||||
|
tr("The server is too busy to handle this stream."),
|
||||||
|
StreamErrorTypes.restricted_xml:
|
||||||
|
tr("The message contained restricted xml (such as comments, processing instructions, dtd subset, or an xml entity reference)"),
|
||||||
|
StreamErrorTypes.see_other_host:
|
||||||
|
tr("The server is redirecting the client to a different host."),
|
||||||
|
StreamErrorTypes.system_shutdown:
|
||||||
|
tr("The server is being shut down."),
|
||||||
|
StreamErrorTypes.undefined_condition:
|
||||||
|
tr("A special case error has occured. See included xml stream."),
|
||||||
|
StreamErrorTypes.unsupported_encoding:
|
||||||
|
tr("The message was encoded with an encoding other than UTF-8, or contained extra bytes that the server is not expecting (as possible with godot's tls functions)."),
|
||||||
|
StreamErrorTypes.unsupported_feature:
|
||||||
|
tr("The required stream features are not supported."),
|
||||||
|
StreamErrorTypes.unsupported_stanza_type:
|
||||||
|
tr("The sent message is of a stanza type that the server does not recognize."),
|
||||||
|
StreamErrorTypes.unsupported_version:
|
||||||
|
tr("This server does not support XMPP version 1.0")
|
||||||
|
}
|
||||||
|
|
||||||
|
var error_type = StreamErrorTypes.undefined_condition
|
||||||
|
var extra_data = ""
|
||||||
|
|
||||||
|
|
||||||
|
func parse_from_xml(xml:String):
|
||||||
|
var parser = XMLParser.new()
|
||||||
|
parser.open_buffer(xml.to_utf8_buffer())
|
||||||
|
parse_with_parser(parser)
|
||||||
|
|
||||||
|
|
||||||
|
func parse_with_parser(parser:XMLParser):
|
||||||
|
# Read the error element
|
||||||
|
if parser.read() == OK and parser.get_node_name() == "stream:error":
|
||||||
|
if parser.is_empty():
|
||||||
|
error_type = 0
|
||||||
|
# Read the error inside...
|
||||||
|
if parser.read() == OK:
|
||||||
|
var error_name = parser.get_node_name().replace("-", "_")
|
||||||
|
error_type = StreamErrorTypes[error_name]
|
||||||
|
if !parser.is_empty() and parser.read() == OK:
|
||||||
|
extra_data = parser.get_node_data()
|
||||||
|
return OK
|
||||||
|
|
||||||
|
|
||||||
|
func stanza() -> String:
|
||||||
|
var stanza = []
|
||||||
|
stanza.append("<stream:error>")
|
||||||
|
var error_name = error_name_for_enum(error_type)
|
||||||
|
if !error_type.empty():
|
||||||
|
stanza.append("<"+error_name)
|
||||||
|
stanza.append("xmlns='urn:ietf:params:xml:ns:xmpp-streams'")
|
||||||
|
if extra_data.empty():
|
||||||
|
stanza.append("/>")
|
||||||
|
else:
|
||||||
|
stanza.append(">"+extra_data+"</"+error_name+">")
|
||||||
|
stanza.append("</stream:error>")
|
||||||
|
return stanza.join(" ")
|
||||||
|
|
||||||
|
|
||||||
|
func error_name_for_enum(value :int) -> String:
|
||||||
|
var error_name:String = ""
|
||||||
|
for i in StreamErrorTypes.keys():
|
||||||
|
if StreamErrorTypes[i] == value:
|
||||||
|
error_name = str(i).replace("_", "-")
|
||||||
|
return error_name
|
||||||
|
|
||||||
|
|
||||||
|
func human_friendly_error_message() -> String:
|
||||||
|
""" Human friendly error messages for the error dialogue. """
|
||||||
|
return humane_error_messages[error_type]
|
88
client/Stream/xmpp_stream_features.gd
Normal file
88
client/Stream/xmpp_stream_features.gd
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
###
|
||||||
|
# This file is part of Godot XMPP Client
|
||||||
|
# SPDX-FileCopyrightText: 2020 Wolthera van Hovell tot Westerflier <griffinvalley@gmail.com>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
###
|
||||||
|
|
||||||
|
extends Resource
|
||||||
|
|
||||||
|
class_name XMPPStreamFeatures
|
||||||
|
|
||||||
|
###
|
||||||
|
# Parser for stream features.
|
||||||
|
##
|
||||||
|
|
||||||
|
@export var xml_string:String = "":
|
||||||
|
set = parse_from_xml
|
||||||
|
|
||||||
|
@export var parsedDictionary:Dictionary = {}
|
||||||
|
|
||||||
|
enum FeatureReq{
|
||||||
|
NO_FEATURE,
|
||||||
|
NO_REQ,
|
||||||
|
OPTIONAL,
|
||||||
|
REQUIRED
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func feature_done(feature:String):
|
||||||
|
""" Remove the entry as it's done. """
|
||||||
|
parsedDictionary.erase(feature)
|
||||||
|
|
||||||
|
|
||||||
|
func parse_from_xml(xml:String):
|
||||||
|
var parser = XMLParser.new()
|
||||||
|
parser.open_buffer(xml.to_utf8_buffer())
|
||||||
|
parser.read()
|
||||||
|
parse_children(parser, parser.get_node_name())
|
||||||
|
|
||||||
|
|
||||||
|
func parse_children(parser:XMLParser, _parent_name:String):
|
||||||
|
parsedDictionary = {}
|
||||||
|
while (parser.read() == OK):
|
||||||
|
if (parser.get_node_type()== XMLParser.NODE_ELEMENT):
|
||||||
|
var node_name = parser.get_node_name()
|
||||||
|
if !parser.is_empty():
|
||||||
|
match(node_name):
|
||||||
|
"mechanisms":
|
||||||
|
parsedDictionary[node_name] = parse_option_list(parser, node_name, "mechanism")
|
||||||
|
"compression":
|
||||||
|
parsedDictionary[node_name] = parse_option_list(parser, node_name, "method")
|
||||||
|
_:
|
||||||
|
parsedDictionary[node_name] = parse_requirement(parser, node_name)
|
||||||
|
else:
|
||||||
|
parsedDictionary[node_name] = FeatureReq.NO_REQ
|
||||||
|
# else:
|
||||||
|
# print("Unhandled xml node type: "+str(parser.get_node_type()))
|
||||||
|
|
||||||
|
|
||||||
|
func parse_requirement(parser:XMLParser, parent_name:String):
|
||||||
|
var required = self.FeatureReq.NO_REQ
|
||||||
|
while (parser.read() == OK):
|
||||||
|
if (parser.get_node_type()== XMLParser.NODE_ELEMENT):
|
||||||
|
var node_name = parser.get_node_name()
|
||||||
|
if parser.is_empty():
|
||||||
|
if node_name == "required":
|
||||||
|
return self.FeatureReq.REQUIRED
|
||||||
|
elif node_name == "optional":
|
||||||
|
return self.FeatureReq.OPTIONAL
|
||||||
|
elif(parser.get_node_type()== XMLParser.NODE_ELEMENT_END):
|
||||||
|
var node_name = parser.get_node_name()
|
||||||
|
if node_name == parent_name:
|
||||||
|
return required
|
||||||
|
|
||||||
|
|
||||||
|
func parse_option_list(parser:XMLParser, parent_name:String, option_name:String):
|
||||||
|
var options = []
|
||||||
|
while (parser.read() == OK):
|
||||||
|
var _result
|
||||||
|
if (parser.get_node_type()== XMLParser.NODE_ELEMENT):
|
||||||
|
if parser.get_node_name() == option_name:
|
||||||
|
_result =parser.read()
|
||||||
|
if (parser.get_node_type()== XMLParser.NODE_TEXT):
|
||||||
|
options.append(parser.get_node_data())
|
||||||
|
_result = parser.read()
|
||||||
|
elif(parser.get_node_type()== XMLParser.NODE_ELEMENT_END):
|
||||||
|
if parser.get_node_name() == parent_name:
|
||||||
|
return options
|
|
@ -315,21 +315,21 @@ var pose_warping_instance = PoseWarping.new()
|
||||||
|
|
||||||
|
|
||||||
func _process(delta):
|
func _process(delta):
|
||||||
Global.msg_info("delta: %f", [delta])
|
Global.msg_debug("delta: %f", [delta])
|
||||||
calc_animation_data()
|
calc_animation_data()
|
||||||
var orientation_warping_condition = rotation_mode != Global.ROTATION_MODE.VELOCITY_DIRECTION and \
|
var orientation_warping_condition = rotation_mode != Global.ROTATION_MODE.VELOCITY_DIRECTION and \
|
||||||
movement_state == Global.MOVEMENT_STATE.GROUNDED and \
|
movement_state == Global.MOVEMENT_STATE.GROUNDED and \
|
||||||
movement_action == Global.MOVEMENT_ACTION.NONE and \
|
movement_action == Global.MOVEMENT_ACTION.NONE and \
|
||||||
gait != Global.GAIT.SPRINTING and \
|
gait != Global.GAIT.SPRINTING and \
|
||||||
input_is_moving
|
input_is_moving
|
||||||
Global.msg_info("orientation_warping_condition:%s", [str(orientation_warping_condition)])
|
Global.msg_debug("orientation_warping_condition:%s", [str(orientation_warping_condition)])
|
||||||
pose_warping_instance.orientation_warping( orientation_warping_condition,camera_root.HObject,animation_velocity,skeleton_ref,"Hips",["Spine","Spine1","Spine2"],0.0,delta)
|
pose_warping_instance.orientation_warping( orientation_warping_condition,camera_root.HObject,animation_velocity,skeleton_ref,"Hips",["Spine","Spine1","Spine2"],0.0,delta)
|
||||||
|
|
||||||
|
|
||||||
func _physics_process(delta):
|
func _physics_process(delta):
|
||||||
#Debug()
|
#Debug()
|
||||||
#
|
#
|
||||||
Global.msg_info("delta: %f", [delta])
|
Global.msg_debug("delta: %f", [delta])
|
||||||
|
|
||||||
aim_rate_h = abs((camera_root.HObject.rotation.y - previous_aim_rate_h) / delta)
|
aim_rate_h = abs((camera_root.HObject.rotation.y - previous_aim_rate_h) / delta)
|
||||||
previous_aim_rate_h = camera_root.HObject.rotation.y
|
previous_aim_rate_h = camera_root.HObject.rotation.y
|
||||||
|
@ -382,15 +382,15 @@ func _physics_process(delta):
|
||||||
#------------------ Gravity ------------------#
|
#------------------ Gravity ------------------#
|
||||||
if is_flying == false and character_node is CharacterBody3D:
|
if is_flying == false and character_node is CharacterBody3D:
|
||||||
character_node.velocity.y = lerp(character_node.velocity.y,vertical_velocity.y - character_node.get_floor_normal().y,delta * gravity)
|
character_node.velocity.y = lerp(character_node.velocity.y,vertical_velocity.y - character_node.get_floor_normal().y,delta * gravity)
|
||||||
Global.msg_info("ID:%d velocity:%s", [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity)])
|
Global.msg_debug("ID:%d velocity:%s", [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity)])
|
||||||
var collided = character_node.move_and_slide()
|
var collided = character_node.move_and_slide()
|
||||||
Global.msg_info("ID:%d velocity:%s collided:%s" , [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity), str(collided)])
|
Global.msg_debug("ID:%d velocity:%s collided:%s" , [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity), str(collided)])
|
||||||
if character_node.velocity.x * character_node.velocity.x + character_node.velocity.z * character_node.velocity.z > 0.5:
|
if character_node.velocity.x * character_node.velocity.x + character_node.velocity.z * character_node.velocity.z > 0.5:
|
||||||
input_is_moving = true
|
input_is_moving = true
|
||||||
Global.msg_info("ID:%d distance^2:%s true", [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity.x * character_node.velocity.x + character_node.velocity.z * character_node.velocity.z )])
|
Global.msg_debug("ID:%d distance^2:%s true", [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity.x * character_node.velocity.x + character_node.velocity.z * character_node.velocity.z )])
|
||||||
else:
|
else:
|
||||||
input_is_moving = false
|
input_is_moving = false
|
||||||
Global.msg_info("ID:%d distance^2:%s false", [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity.x * character_node.velocity.x + character_node.velocity.z * character_node.velocity.z )])
|
Global.msg_debug("ID:%d distance^2:%s false", [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity.x * character_node.velocity.x + character_node.velocity.z * character_node.velocity.z )])
|
||||||
|
|
||||||
if ground_check.is_colliding() and is_flying == false:
|
if ground_check.is_colliding() and is_flying == false:
|
||||||
movement_state = Global.MOVEMENT_STATE.GROUNDED
|
movement_state = Global.MOVEMENT_STATE.GROUNDED
|
||||||
|
@ -584,13 +584,13 @@ func add_movement_input(direction: Vector3 = Vector3.ZERO, Speed: float = 0, Acc
|
||||||
if is_flying == false:
|
if is_flying == false:
|
||||||
character_node.velocity.x = lerp(character_node.velocity.x,(direction*max_speed).x,Acceleration/(max_speed if max_speed != 0 else (abs(character_node.velocity.x) if character_node.velocity.x != 0 else 1.0))*get_physics_process_delta_time())
|
character_node.velocity.x = lerp(character_node.velocity.x,(direction*max_speed).x,Acceleration/(max_speed if max_speed != 0 else (abs(character_node.velocity.x) if character_node.velocity.x != 0 else 1.0))*get_physics_process_delta_time())
|
||||||
character_node.velocity.z = lerp(character_node.velocity.z,(direction*max_speed).z,Acceleration/(max_speed if max_speed != 0 else (abs(character_node.velocity.z) if character_node.velocity.z != 0 else 1.0))*get_physics_process_delta_time())
|
character_node.velocity.z = lerp(character_node.velocity.z,(direction*max_speed).z,Acceleration/(max_speed if max_speed != 0 else (abs(character_node.velocity.z) if character_node.velocity.z != 0 else 1.0))*get_physics_process_delta_time())
|
||||||
Global.msg_info("ID:%d velocity:%s", [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity)])
|
Global.msg_debug("ID:%d velocity:%s", [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity)])
|
||||||
else:
|
else:
|
||||||
character_node.velocity = character_node.velocity.lerp((direction*max_speed),Acceleration/(max_speed if max_speed != 0 else character_node.velocity.x if character_node.velocity.x != 0 else 1.0)*get_physics_process_delta_time())
|
character_node.velocity = character_node.velocity.lerp((direction*max_speed),Acceleration/(max_speed if max_speed != 0 else character_node.velocity.x if character_node.velocity.x != 0 else 1.0)*get_physics_process_delta_time())
|
||||||
var body_collided = character_node.move_and_slide()
|
var body_collided = character_node.move_and_slide()
|
||||||
Global.msg_info("ID:%d body_collided:%s", [character_node.get_node("PlayerNetworkingComponent").id, str(body_collided)])
|
Global.msg_debug("ID:%d body_collided:%s", [character_node.get_node("PlayerNetworkingComponent").id, str(body_collided)])
|
||||||
# Get the velocity from the character node
|
# Get the velocity from the character node
|
||||||
Global.msg_info("ID:%d velocity:%s", [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity)])
|
Global.msg_debug("ID:%d velocity:%s", [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity)])
|
||||||
var character_node_velocity = character_node.velocity if character_node is CharacterBody3D else character_node.linear_velocity
|
var character_node_velocity = character_node.velocity if character_node is CharacterBody3D else character_node.linear_velocity
|
||||||
|
|
||||||
|
|
||||||
|
@ -598,7 +598,7 @@ func add_movement_input(direction: Vector3 = Vector3.ZERO, Speed: float = 0, Acc
|
||||||
movement_direction = atan2(input_velocity.x,input_velocity.z)
|
movement_direction = atan2(input_velocity.x,input_velocity.z)
|
||||||
#input_is_moving = input_velocity.length() > 0.0
|
#input_is_moving = input_velocity.length() > 0.0
|
||||||
input_acceleration = Acceleration * direction * (1 if max_speed != 0 else -1)
|
input_acceleration = Acceleration * direction * (1 if max_speed != 0 else -1)
|
||||||
Global.msg_info("ID:%d velocity:%s input_velocity:%s direction:%s input_acceleration:%s character_node_velocity:%s", [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity), str(input_velocity.length()), str(direction), str(input_acceleration), str(character_node_velocity)])
|
Global.msg_debug("ID:%d velocity:%s input_velocity:%s direction:%s input_acceleration:%s character_node_velocity:%s", [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity), str(input_velocity.length()), str(direction), str(input_acceleration), str(character_node_velocity)])
|
||||||
#
|
#
|
||||||
actual_acceleration = (character_node_velocity - PrevVelocity) / (get_physics_process_delta_time())
|
actual_acceleration = (character_node_velocity - PrevVelocity) / (get_physics_process_delta_time())
|
||||||
PrevVelocity = character_node_velocity
|
PrevVelocity = character_node_velocity
|
||||||
|
|
|
@ -18,7 +18,8 @@ config/icon="res://icon.svg"
|
||||||
[autoload]
|
[autoload]
|
||||||
|
|
||||||
Multi="*res://scenes/multi.gd"
|
Multi="*res://scenes/multi.gd"
|
||||||
Global="*res://player/Global.gd"
|
Global="*res://scripts/Global.gd"
|
||||||
|
Stream="*res://Stream/Stream.gd"
|
||||||
|
|
||||||
[display]
|
[display]
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,21 @@ func _ready():
|
||||||
Multi.update_my_position.connect(_on_update_me)
|
Multi.update_my_position.connect(_on_update_me)
|
||||||
Multi.update_player_position.connect(_on_update_player)
|
Multi.update_player_position.connect(_on_update_player)
|
||||||
Multi.remove_player.connect(_on_remove_player)
|
Multi.remove_player.connect(_on_remove_player)
|
||||||
|
Stream.set_server_ip("localhost")
|
||||||
|
Stream.set_port_number(5222)
|
||||||
|
Stream.send_msg_debug.connect(show_stream_debug)
|
||||||
|
Stream.send_msg_error.connect(show_stream_error)
|
||||||
#$Window.world_2d = _MainWindow.world_2d
|
#$Window.world_2d = _MainWindow.world_2d
|
||||||
|
|
||||||
|
|
||||||
|
func show_stream_debug(msg:String):
|
||||||
|
print("DEBUG [Stream] ", msg)
|
||||||
|
|
||||||
|
|
||||||
|
func show_stream_error(msg:String):
|
||||||
|
print("ERROR [Stream] ", msg)
|
||||||
|
|
||||||
|
|
||||||
func create_view_window():
|
func create_view_window():
|
||||||
pass
|
pass
|
||||||
# var new_window: Window = view_window.instantiate()
|
# var new_window: Window = view_window.instantiate()
|
||||||
|
@ -77,6 +90,7 @@ func _on_connexion_updated(new_state:Multi.Connexion):
|
||||||
$PlayerSpawnLocation.get_child(0).set_activate()
|
$PlayerSpawnLocation.get_child(0).set_activate()
|
||||||
$PlayerSpawnLocation.set_visible(true)
|
$PlayerSpawnLocation.set_visible(true)
|
||||||
$CameraStarting.set_current(false)
|
$CameraStarting.set_current(false)
|
||||||
|
Stream.xmppclient = true
|
||||||
else:
|
else:
|
||||||
$CameraStarting.set_current(true)
|
$CameraStarting.set_current(true)
|
||||||
$Panel/State.set_text("Unknown")
|
$Panel/State.set_text("Unknown")
|
||||||
|
|
39
start-bazar-fake-xmpp-server.sh
Executable file
39
start-bazar-fake-xmpp-server.sh
Executable file
|
@ -0,0 +1,39 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
declare WORKDIR="$(dirname $(readlink -f $0))"
|
||||||
|
declare XMPPDIR="$WORKDIR/.xmpp"
|
||||||
|
|
||||||
|
echo "WORKDIR:$WORKDIR"
|
||||||
|
echo "XMPPDIR:$XMPPDIR"
|
||||||
|
docker pull ejabberd/ecs
|
||||||
|
|
||||||
|
#if [ ! -d $XMPPDIR ]
|
||||||
|
#then
|
||||||
|
# mkdir -p $XMPPDIR
|
||||||
|
# sudo chown 9000:9000 database
|
||||||
|
#fi
|
||||||
|
|
||||||
|
list=$( docker ps -q -a -f name="ejabberd")
|
||||||
|
if [ -z "$list" ]
|
||||||
|
then
|
||||||
|
docker run --name ejabberd \
|
||||||
|
--publish 5222:5222 \
|
||||||
|
--publish 5269:5269 \
|
||||||
|
--publish 5280:5280 \
|
||||||
|
--publish 5443:5443 \
|
||||||
|
--publish 1883:1883 \
|
||||||
|
ejabberd/ecs
|
||||||
|
else
|
||||||
|
docker start ejabberd
|
||||||
|
docker logs -f ejabberd
|
||||||
|
docker stop
|
||||||
|
fi
|
||||||
|
|
||||||
|
# https://localhost:5443/admin/
|
||||||
|
# docker exec -it ejabberd bin/ejabberdctl register admin localhost passw0rd
|
||||||
|
# docker exec -it ejabberd bin/ejabberdctl register toto localhost toto
|
||||||
|
# docker exec -it ejabberd bin/ejabberdctl status
|
||||||
|
# docker exec -it ejabberd bin/ejabberdctl stats registeredusers
|
||||||
|
# docker exec -it ejabberd bin/ejabberdctl register titi localhost titi
|
||||||
|
# docker exec -it ejabberd bin/ejabberdctl register undefined localhost undefined
|
||||||
|
|
Loading…
Reference in a new issue