socketio / socket.io-client-java

Full-featured Socket.IO Client Library for Java, which is compatible with Socket.IO v1.0 and later.
https://socketio.github.io/socket.io-client-java/installation.html
Other
5.34k stars 975 forks source link

how to change query parameter in socket? #630

Closed Azinnilchi closed 3 years ago

Azinnilchi commented 4 years ago

I have the same problem, when I want to change the account by changing token, it still connects to the previous socket! how can I deal with it?!

Originally posted by @Azinnilchi in https://github.com/socketio/socket.io-client-java/issues/394#issuecomment-719918630

Azinnilchi commented 4 years ago

I use this code but it's not working : mSocket = null var token = newToken if (token != "") { mSocket = try { val opts: IO.Options = IO.Options() opts.query = "token=$token" opts.transports = arrayOf(WebSocket.NAME) opts.forceNew = true socket(Constants.SOCKET_URL, opts) } catch (e: URISyntaxException) { throw RuntimeException(e) } }

Jay-Uppaluri commented 4 years ago

You want to change the account by changing the auth token to anothers auth token?

Azinnilchi commented 4 years ago

You want to change the account by changing the auth token to anothers auth token?

yes, that's the plan. finally, i change auth token and then disconnect the socket and reconnect it to work this through

darrachequesne commented 3 years ago

For future readers:

Unfortunately, there is an issue with the query option in this version, as it is used by both the Manager (for the low-level connection, sent in the query params) and by the Socket (for the Socket.IO connection, sent during the Socket.IO handshake).

There are two possible workarounds:

  1. update the query option used by the Manager
options.query = "y=43";
socket.disconnect().connect(); // only works when using one single Socket, as the connection will be closed when the Socket is closed
  1. update the query option used by the Socket (only works for a non-default namespace)
// set query on the Socket object by reflection (not included, because this is ugly)
// and then force reconnection
socket.disconnect().connect(); 

The issue mentioned above was fixed in 2.0.0: https://socketio.github.io/socket.io-client-java/migrating_from_1_x.html#The_Socket_query_option_is_renamed_to_auth

You can set the auth option on creation:

IO.Options options = IO.Options.builder()
        .setAuth(singletonMap("token", "abcd"))
        .build();

Socket socket = IO.socket(URI.create("https://example.com"), options);

And then update it:

options.auth.put("token", "efgh");
socket.disconnect().connect();

Documented here: https://socketio.github.io/socket.io-client-java/initialization.html#auth

n1k3c commented 2 years ago

@darrachequesne mentioned this:

options.auth.put("token", "efgh");
socket.disconnect().connect();

put() is throwing error while updating Auth: java.lang.UnsupportedOperationException at java.util.AbstractMap.put(AbstractMap.java:209)

update: Also, it seems that singletonMap doesn't change auth:

options.auth = singletonMap("token", newAccessToken)

tausifcreates commented 1 year ago

@n1k3c Did you get around this issue?

tausifcreates commented 1 year ago

@darrachequesne Hi, the way you demonstrated does not fix this issue. Even after re assigning the token it reports the same token as previous one in the server.

n1k3c commented 1 year ago

@n1k3c Did you get around this issue?

You can use reflection. For me, it's working but I don't recommend this solution.

socket.setAndReturnPrivateProperty("auth", singletonMap("token", "new_access_token").toMap())

fun <T : Any> T.setAndReturnPrivateProperty(variableName: String, data: Any): Any? {
    return javaClass.getDeclaredField(variableName).let { field ->
        field.isAccessible = true
        field.set(this, data)
        return@let field.get(this)
    }
}

If you use some kind of DI, then probably it's a bit of a problem to change token because you need IO.Options to build socket client. Later, in order to update the token you need to update IO.Options object which is impossible (at least I didn't find any good solution with Hilt). So maybe it's a good way to rethink implementation...

tausifcreates commented 1 year ago

@n1k3c Did you get around this issue?

You can use reflection. For me, it's working but I don't recommend this solution.

socket.setAndReturnPrivateProperty("auth", singletonMap("token", "new_access_token").toMap())

fun <T : Any> T.setAndReturnPrivateProperty(variableName: String, data: Any): Any? {
    return javaClass.getDeclaredField(variableName).let { field ->
        field.isAccessible = true
        field.set(this, data)
        return@let field.get(this)
    }
}

If you use some kind of DI, then probably it's a bit of a problem to change token because you need IO.Options to build socket client. Later, in order to update the token you need to update IO.Options object which is impossible (at least I didn't find any good solution with Hilt). So maybe it's a good way to rethink implementation...

I ended up using state management. Thank you for your answer!