Networking mixing HTTP request and RPC call

Godot Version

4.2

Question

what could be the issue i get when i send multiple request ?

i’ve builded up for study purpose a server/client network on godot 4.2 i’ve sucesfully managed to connect the server/client and i decided to further in the learning and make a gateway and a auth server wich resulted sucessfully too so the network setup look like this :
SERVER <----->CLIENT<----->GATEWAY<----->AUTH SERVER<----->PHP SCRIPT<------> MysqlDB

With this whole things set up i’ve been proud of myself to be able to succesfully access the DB from my VM to godot 4.2 (with a DNS adress )

i’ve then decided to push further and make a “simple” log in request systems wich work but not exactly correctly it seems here is the issue coming at this step :

if i try to log in the first time everything is ok i get connected to server if credential are corresponding to the DB if then i just try to log in again after closing/reopening the client Everything work fines (second login request sent i get connected to the server) but in the auth server log i can see this :

Gateway 105429151 connected.
authentification request received from acc ID:123456789
gateway requester ID :105429151
starting authentication
auth resultfalse
authentification request received from acc ID:123456789
gateway requester ID :105429151
starting authentication
auth resulttrue
auth resulttrue
Gateway 105429151 disconnected.

in this log we can see the first attempt i get wrong password or accountID the result return false and at the second attempt i get it correctly the result return true but now its printed 2 time (doubled ) and it will goes like this the full request send back so when i look up at the gateway log its the same

Gateway Server Started
succesfully connected to authentication server
client 2110031394 Connected
login request received
sending out authentication request
results recieved from the auth server and replying to player login request
returning login request result to
client ID : 2110031394
client ID after sending loginrequest : 
client 2110031394 Disconnected
client 1830433963 Connected
login request received
sending out authentication request
results recieved from the auth server and replying to player login request
returning login request result to
client ID : 2110031394
results recieved from the auth server and replying to player login request
returning login request result to
client ID : 1830433963
client ID after sending loginrequest : 
client ID after sending loginrequest : 
client 1830433963 Disconnected

so again it seems to double everything plus this time we can see the old request log printed again and even if i get connected it seems it still trying to send the old request again with the new one ?

so obviously i get error :

E 0:00:16:0856   Gateway.gd:54 @ returnLoginRequest(): Attempt to call RPC with unknown peer ID: 2110031394.
  <Erreur C++>   Method/function failed.
  <Source C++>   modules/multiplayer/scene_rpc_interface.cpp:307 @ _send_rpc()
  <Pile des appels>Gateway.gd:54 @ returnLoginRequest()
                 Authenticate.gd:35 @ AuthenticationResults()

is this whole problem related to how i handle the login request in the auth server ? since my auth server is both calling HTTP request in a queue and RPC call start that HTTP ? if you have any advice any guide , documentation (ive read many about godot networking http request signal multiplayerAPI ) that could help i thanks you in advance for the time and the help you could provide to me :slight_smile:

if needed here is some part of my auth server script and how it handle login request :

func _http_request_completed(_result,_response_code,_headers,_body):
	#print("request signal start")
	#print("Raw Response Body:\n" + _body.get_string_from_utf8())
	is_requesting = false
	var json = JSON.new()
	var response_body = _body.get_string_from_utf8()
	json.parse(response_body)
	var response = ""
	response = json.get_data()
	if _result != HTTPRequest.RESULT_SUCCESS:
		#print(response["User-Agent"])
		return
	if response['error'] != "none":
		#print(response['error'])
		#print("recieved error from http request")
		return
		
	#check if we were requesting a nonce:
	if response['command'] == 'get_nonce':
		nonce = response['response']['nonce']
		#print("got nonce: " + response['response']['nonce'])
		return
	#handle login response
	if response['command'] == 'login':
		if 'response' in response and 'login' in response['command']:
			#print(response['response']['valid'])
			var valid = response['response']['valid']
			emit_signal("authentication_completed", valid)
func _send_request(request : Dictionary):
	#print("sending request start")
		#create HTTPclient
	var client = HTTPClient.new()
	var data = client.query_string_from_dict({"data" : JSON.stringify(request['data'])})
	var body = "command=" + request['command'] + "&" + data
	
	#generate 'response nonce'
	var crypto = Crypto.new()
	var random_bytes = crypto.generate_random_bytes(32)
	#  SHA256 hash as a string
	var cnonce = random_bytes.hex_encode()
	#print("SHA256 Hash:", cnonce)
	#generate our security hash:
	var client_hash = (nonce + cnonce + body + SECRET_KEY).sha256_text()
	nonce = null
	var headers = SERVER_HEADERS.duplicate()
	headers.push_back("cnonce: " + cnonce)
	headers.push_back("hash: " + client_hash)
	#make request to server
	var err = http_request.request(SERVER_URL, SERVER_HEADERS, HTTPClient.METHOD_POST,body)
	#check if there is a problem
	if err != OK:
		JSON.stringify("HTTPRequest error: " + String(err))
		return

func loginauth(accountID: String, accountPassword: String):
	var command ="login"
	var data = {
		"accountID": accountID,
		"accountPassword": accountPassword
		} 
	request_queue.push_back({"command" : command, "data" : data})
	data = {}
	command = ""


@rpc("any_peer")
func AuthenticateAccount(accID,passwrd,clientID):
	print("authentification request received from acc ID:", accID)
	var gateway_id = get_tree().get_multiplayer().get_remote_sender_id()
	print("gateway requester ID :", gateway_id)
	print("starting authentication")
	loginauth(accID,passwrd)
	var authentication_completed_handler = func (valid: bool):
			print("auth result",valid)
			rpc_id(gateway_id, "AuthenticationResults", valid, clientID)
			gateway_id = ""
			accID = ""
			passwrd = ""
			clientID = ""
	self.connect("authentication_completed", authentication_completed_handler)
	
	
	
	
@rpc("any_peer")
func AuthenticationResults(result, clientID):
	pass
1 Like

To fix your problem, put your Godot network json’s file name to 2 Bracket symbol [()] in “JSON.new()” from var json = JSON.new() :moyai::pinched_fingers:

i tried your solution i did this

var json_array := [JSON.new()]

func _http_request_completed(_result,_response_code,_headers,_body):
   is_requesting = false
   var response_body = _body.get_string_from_utf8()
   
   for json in json_array:
       json.parse(response_body)
       var response = json.get_data()

       if _result != HTTPRequest.RESULT_SUCCESS:
           return
       if response['error'] != "none":
           return
           
       

func _send_request(request : Dictionary):
   var json = JSON.new()
   json_array.append(json)

but the print and the problem persist :

Gateway 1634187524 connected.
authentification request received from client :1314651117
gateway requester ID :1634187524
starting authentication
auth resultfalse
authentification request received from client :1595224849
gateway requester ID :1634187524
starting authentication
auth resultfalse
auth resultfalse
authentification request received from client :988576104
gateway requester ID :1634187524
starting authentication
auth resulttrue
auth resulttrue
auth resulttrue

It seems like the issue persists even after adjusting the JSON handling. There might be another factor causing this duplication of results.

1 Like

I wouldn’t use RPC to send password it is not encrypted, unless you setup an encrypted peer connection.

i was having this in mind and projected to add a token veriff in the rpc later would have just set it up before but yes right now this is not very usefull , for my problem of duplicate request i guess it must be related to this part

var authentication_completed_handler = func (valid: bool): print("auth result",valid) rpc_id(gateway_id, "AuthenticationResults", valid, clientID) gateway_id = "" accID = "" passwrd = "" clientID = "" self.connect("authentication_completed", authentication_completed_handler)

i’t seems i’m not really handling correctly the signal maybe since the diplications of results are related to older clientID (get error saying it try to send the request back to an clientID that doesn’t exist anymore(older request)i think i’m on the good way i will inform if i found anything relevant