How to wait for an HTTPRequest to complete?

Godot Version

4.6.2

Question

I'm making multiplayer game and as you all know multiplayer games need matchmaking with lobbynames not IPs, but I constantly have the problem where my script sends an HTTPRequest to my matchmaking server but the rest of my script does not care and keeps running with an empty host IP or if I HTTPRequest api.ipify.org and variable myip is left blank. So how do I await for the HTTPRequest to finish?

You wait for the request to complete:

$HTTPRequest.request_completed.connect(processRequestComplete)

And then determine what to do with it:

func processRequestComplete(result: int, nResponseCode: int, aHeaders: PackedStringArray, aBody: PackedByteArray):
match nResponseCode:
200:
success.emit(aBody)
404:
failure.emit(“Something went wrong.\nThe Web program seems to be missing.”)
_:
failure.emit("Something went wrong, and the server replied\nwith error code " + str(nResponseCode))
queue_free()


2 Likes

Wait, but in my code even the

$HTTPRequest.request_completed.connect(processRequestComplete)

is in another function. Because you have a lot of other stuff to do other than determining what happens after the request is complete.
For instance:

func findip() -> void:
	# Create HTTPRequest node
	var http_request = HTTPRequest.new()
	add_child(http_request)

	# Connect the completion signal
	http_request.request_completed.connect(_on_ip_request_completed)

	# Make request to ipify (returns just your IP as plain text)
	var error = http_request.request("https://api.ipify.org")
	if error != OK:
#		print("HTTP request failed: ", error)
		myip = "HTTP request failed: " + str(error)

and then in my big function when I call findip() the program makes a seperate thread processing the HTTP, which leaves the myip blank.

You need to keep track of the order of execution then. It looks like you make a lot of requests in a lot of different places without verifying the data from any of it.

1 Like

What do you mean I have a lot of requests in a lot of places? I thought I just have that single request to api.ipify.org. Also, what do you mean without verifying? You mean api.ipify.org might give me malicious output?

You don’t need a separate thread, that may be the largest problem with your code.

Without seeing _on_ip_request_completed it seems like the snippet you posted would work, certainly so on the main thread.

2 Likes

I agree that we don’t need a separate thread. But I’m not making the separate thread – the program is, which I’m trying to stop.

func _on_ip_request_completed(result, response_code, headers, body):
	if result == HTTPRequest.RESULT_SUCCESS and response_code == 200:
		var my_public_ip = body.get_string_from_utf8()
		myip = my_public_ip
		print(myip)
	else:
		myip = "Request failed with code: " + str(response_code)

Godot doesn’t make a separate thread for signals.

Do you mean to run the rest of your script only after this myip variable has been set?

Can you explain in big-picture detail what you want to happen, and then what is actually happening?

1 Like

Like this:

var myip: String = "i'm empty"

func _ready() -> void:
	# Connect all the callbacks related to networking.
	multiplayer.peer_connected.connect(_player_connected)
	multiplayer.peer_disconnected.connect(_player_disconnected)
	multiplayer.connected_to_server.connect(_connected_ok)
	multiplayer.connection_failed.connect(_connected_fail)
	multiplayer.server_disconnected.connect(_server_disconnected)
	_on_find_public_ip_pressed()
	print(myip)

and when I ran my game the output says “i’m empty”

The print statement will not wait for asynchronous code to finish, assuming _on_find_public_ip_pressed is the same as findip that you posted the HTTP request does not alter myip unless there is an error so your print statement will show the default value.

If you only want to print myip then you should only do so as part of the _on_ip_request_completed, which you do.

1 Like

Wait a second. I didn’t understand your “which you do” until I looked back and saw the print(myip). But always had I ran the game without seeing anything in the outputs before I added that print(myip) in _ready()!
Anyways, I thought having a global myipthen changing it or visiting in throughout the program isn’t standard coding practices, so is there any way I can improve that?

Globals are fine, I don’t know what you are trying to do with the myip variable so I cannot recommend any action to scope it better.

If you didn’t see anything print it may be because the my_public_ip is empty, or the HTTP request is taking longer than expected