issork / gift

Godot IRC For Twitch addon
MIT License
144 stars 22 forks source link

TwitchAPIConnection does not allow you to get_users() without specifying names or ids #43

Open KyleReese opened 1 month ago

KyleReese commented 1 month ago

According to the Twitch API docs you can get information about the user of your current bearer token if you do a get-users request without specifying specific names or ids to get information about.

For example this allows you to get the username of a user from just the auth bearer token.

However, the get_users function of TwitchAPIConnection immediately returns an empty dictionary if you do not provide either names or ids. Ideally this method should still perform the no param request with just the token to get this information.

I think getting info about the user of the current token is useful and the immediate return if the names and ids arrays are empty should be removed from this function to allow this.

bearlikelion commented 3 weeks ago

I wrote a small change to make this work, but couldn't find a clean way to wait until the connection is established to make the call

Edit GIFT/api_connection.gd

func get_users(names : Array[String], ids : Array[String]) -> Dictionary:
    var headers : PackedStringArray = [
        "Authorization: Bearer %s" % id_conn.last_token.token,
        "Client-Id: %s" % id_conn.last_token.last_client_id
    ]
    if (names.is_empty() && ids.is_empty()):
        var response = await(request(HTTPClient.METHOD_GET, "/helix/users", headers))
        return response
        # return {}

in GIFT.gd autoload

    # Store the token in the ID connection, create all other connections.
    id = TwitchIDConnection.new(token)
    irc = TwitchIRCConnection.new(id)
    api = TwitchAPIConnection.new(id)
    iconloader = TwitchIconDownloader.new(api)
    # For everything to work, the id connection has to be polled regularly.
    get_tree().process_frame.connect(id.poll)

    await get_tree().create_timer(1.0).timeout # HACK: Wait 1.0 second for twitch server connection
    var twitch_username = await api.get_users([],[])
    print("Connected As: %s" % twitch_username.data[0]["login"])

    # Connect to the Twitch chat.
    connected = await irc.connect_to_irc(twitch_username.data[0]["login"])

Log:

Waiting for user to login.
Success.
Connected As: bearlikelion
KyleReese commented 3 weeks ago

This is how I ended up changing get_users for use in my project:

func get_users(names : Array[String], ids : Array[String]) -> Dictionary:
    var headers : PackedStringArray = [
        "Authorization: Bearer %s" % id_conn.last_token.token,
        "Client-Id: %s" % id_conn.last_token.last_client_id
    ]
    var params = "?"
    if (names.is_empty() && ids.is_empty()):
        params = ""

    if (names.size() > 0):
        params += "login=%s" % names.pop_back()
        while(names.size() > 0):
            params += "&login=%s" % names.pop_back()
    if (params.length() > 1):
        params += "&"
    if (ids.size() > 0):
        params += "id=%s" % ids.pop_back()
        while(ids.size() > 0):
            params += "&id=%s" % ids.pop_back()
    var response = await(request(HTTPClient.METHOD_GET,"/helix/users/%s" % params, headers))
    match (client.get_response_code()):
        400:
            id_conn.token_invalid.emit()
            return {}
    return response

That's a good point about the connection status, it would be nice to refactor that to check the error returned by client.connect_to_host(...) in _init() and poll until the connection is ready as shown in this tutorial from the docs.

But I think that would apply to the entire class (And looks like it is potentially an issue in TwitchIconDownloader's use of HTTPClient as well) so should probably be a separate issue.

I am setting up my EventSubConnection after initializing my API connection and prior to calling get_users which likely takes long enough for the API connection to be established which explains why I haven't yet run into the connection issue you're seeing.