Skip to content

Commit 0ff1f2a

Browse files
committed
fix: auto refresh websocket connection
(cherry picked from commit 38cea5a)
1 parent b986cf4 commit 0ff1f2a

File tree

6 files changed

+225
-17
lines changed

6 files changed

+225
-17
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright (c) 2022 AccelByte Inc. All Rights Reserved
3+
* This is licensed software from AccelByte Inc, for limitations
4+
* and restrictions contact your company contract manager.
5+
*
6+
* Code generated. DO NOT EDIT.
7+
*/
8+
9+
package net.accelbyte.sdk.api.lobby.ws_models;
10+
11+
import lombok.Builder;
12+
import lombok.Getter;
13+
import lombok.Setter;
14+
15+
import java.util.HashMap;
16+
import java.util.Map;
17+
18+
import static net.accelbyte.sdk.core.util.Helper.generateUUID;
19+
import static net.accelbyte.sdk.core.util.Helper.parseWSM;
20+
21+
@Getter
22+
@Setter
23+
public class RefreshTokenRequest {
24+
private String id;
25+
26+
private String token;
27+
28+
private RefreshTokenRequest() {}
29+
30+
@Builder
31+
// @deprecated 2022-08-29 - All args constructor may cause problems. Use builder instead.
32+
@Deprecated
33+
public RefreshTokenRequest(String id, String token) {
34+
this.id = id;
35+
this.token = token;
36+
}
37+
38+
public static String getType() {
39+
return "refreshTokenRequest";
40+
}
41+
42+
public static RefreshTokenRequest createFromWSM(String message) {
43+
RefreshTokenRequest result = new RefreshTokenRequest();
44+
Map<String, String> response = parseWSM(message);
45+
result.id = response.get("id") != null ? response.get("id") : null;
46+
result.token = response.get("token") != null ? response.get("token") : null;
47+
return result;
48+
}
49+
50+
public String toWSM() {
51+
StringBuilder stringBuilder = new StringBuilder();
52+
stringBuilder.append("type: ").append(RefreshTokenRequest.getType());
53+
if (id != null) {
54+
stringBuilder.append("\n").append("id: ").append(id);
55+
} else {
56+
stringBuilder.append("\n").append("id: ").append(generateUUID());
57+
}
58+
stringBuilder.append("\n").append("token: ").append(token);
59+
return stringBuilder.toString();
60+
}
61+
62+
public static Map<String, String> getFieldInfo() {
63+
Map<String, String> result = new HashMap<>();
64+
result.put("id", "id");
65+
result.put("token", "token");
66+
return result;
67+
}
68+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright (c) 2022 AccelByte Inc. All Rights Reserved
3+
* This is licensed software from AccelByte Inc, for limitations
4+
* and restrictions contact your company contract manager.
5+
*
6+
* Code generated. DO NOT EDIT.
7+
*/
8+
9+
package net.accelbyte.sdk.api.lobby.ws_models;
10+
11+
import lombok.Builder;
12+
import lombok.Getter;
13+
import lombok.Setter;
14+
15+
import java.util.HashMap;
16+
import java.util.Map;
17+
18+
import static net.accelbyte.sdk.core.util.Helper.generateUUID;
19+
import static net.accelbyte.sdk.core.util.Helper.parseWSM;
20+
21+
@Getter
22+
@Setter
23+
public class RefreshTokenResponse {
24+
private String id;
25+
26+
private String code;
27+
28+
private RefreshTokenResponse() {}
29+
30+
@Builder
31+
// @deprecated 2022-08-29 - All args constructor may cause problems. Use builder instead.
32+
@Deprecated
33+
public RefreshTokenResponse(String id, String code) {
34+
this.id = id;
35+
this.code = code;
36+
}
37+
38+
public static String getType() {
39+
return "refreshTokenResponse";
40+
}
41+
42+
public static RefreshTokenResponse createFromWSM(String message) {
43+
RefreshTokenResponse result = new RefreshTokenResponse();
44+
Map<String, String> response = parseWSM(message);
45+
result.id = response.get("id") != null ? response.get("id") : null;
46+
result.code = response.get("code") != null ? response.get("code") : null;
47+
return result;
48+
}
49+
50+
public String toWSM() {
51+
StringBuilder stringBuilder = new StringBuilder();
52+
stringBuilder.append("type: ").append(RefreshTokenResponse.getType());
53+
if (id != null) {
54+
stringBuilder.append("\n").append("id: ").append(id);
55+
} else {
56+
stringBuilder.append("\n").append("id: ").append(generateUUID());
57+
}
58+
stringBuilder.append("\n").append("code: ").append(code);
59+
return stringBuilder.toString();
60+
}
61+
62+
public static Map<String, String> getFieldInfo() {
63+
Map<String, String> result = new HashMap<>();
64+
result.put("id", "id");
65+
result.put("code", "code");
66+
return result;
67+
}
68+
}

src/main/java/net/accelbyte/sdk/core/client/OkhttpWebSocketClient.java

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,27 @@
66

77
package net.accelbyte.sdk.core.client;
88

9-
import java.util.concurrent.TimeUnit;
9+
import lombok.extern.java.Log;
10+
import net.accelbyte.sdk.api.lobby.ws_models.RefreshTokenRequest;
1011
import net.accelbyte.sdk.core.repository.ConfigRepository;
1112
import net.accelbyte.sdk.core.repository.TokenRepository;
12-
import okhttp3.*;
13+
import net.accelbyte.sdk.core.repository.TokenRepositoryCallback;
14+
import net.accelbyte.sdk.core.util.Helper;
15+
import okhttp3.OkHttpClient;
16+
import okhttp3.Request;
17+
import okhttp3.WebSocket;
18+
import okhttp3.WebSocketListener;
1319

14-
public class OkhttpWebSocketClient {
15-
private WebSocket websocket;
20+
import java.util.concurrent.TimeUnit;
1621

17-
private OkhttpWebSocketClient(WebSocket websocket) {
18-
this.websocket = websocket;
19-
}
22+
@Log
23+
public class OkhttpWebSocketClient extends TokenRepositoryCallback {
2024

2125
public static OkhttpWebSocketClient create(
22-
ConfigRepository configRepository,
23-
TokenRepository tokenRepository,
24-
WebSocketListener listener)
25-
throws Exception {
26+
ConfigRepository configRepository,
27+
TokenRepository tokenRepository,
28+
WebSocketListener listener)
29+
throws Exception {
2630
final OkHttpClient client = new OkHttpClient.Builder().readTimeout(0, TimeUnit.SECONDS).build();
2731
String baseURL = configRepository.getBaseURL();
2832
if (baseURL == null || baseURL.isEmpty()) {
@@ -31,14 +35,20 @@ public static OkhttpWebSocketClient create(
3135
String url = configRepository.getBaseURL() + "/lobby/";
3236
String accessToken = tokenRepository.getToken();
3337
Request request =
34-
new Request.Builder()
35-
.url(url)
36-
.addHeader("Authorization", String.format("Bearer %s", accessToken))
37-
.build();
38+
new Request.Builder()
39+
.url(url)
40+
.addHeader("Authorization", String.format("Bearer %s", accessToken))
41+
.build();
3842
WebSocket websocket = client.newWebSocket(request, listener);
39-
OkhttpWebSocketClient websocketClient = new OkhttpWebSocketClient(websocket);
43+
OkhttpWebSocketClient webSocketClient = new OkhttpWebSocketClient(websocket);
44+
tokenRepository.registerTokenRepositoryCallback(webSocketClient);
45+
return webSocketClient;
46+
}
4047

41-
return websocketClient;
48+
private final WebSocket websocket;
49+
50+
private OkhttpWebSocketClient(WebSocket websocket) {
51+
this.websocket = websocket;
4252
}
4353

4454
public void sendMessage(String message) {
@@ -52,4 +62,14 @@ public void close(int code, String reason) {
5262
this.websocket.close(code, reason);
5363
}
5464
}
65+
66+
@Override
67+
public void onAccessTokenRefreshed(String newToken) {
68+
log.info("send websocket refresh token request because token refreshed");
69+
RefreshTokenRequest request = RefreshTokenRequest.builder()
70+
.id(Helper.generateUUID())
71+
.token(newToken)
72+
.build();
73+
sendMessage(request.toWSM());
74+
}
5575
}

src/main/java/net/accelbyte/sdk/core/repository/DefaultTokenRepository.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,20 @@
66

77
package net.accelbyte.sdk.core.repository;
88

9+
import com.google.common.base.Strings;
10+
11+
import java.util.Objects;
12+
import java.util.concurrent.CopyOnWriteArrayList;
13+
import java.util.concurrent.ExecutorService;
14+
import java.util.concurrent.Executors;
15+
916
public class DefaultTokenRepository implements TokenRepository {
1017
private String accessToken = null;
1118

19+
private CopyOnWriteArrayList<TokenRepositoryCallback> callbacks = new CopyOnWriteArrayList<>();
20+
21+
private final ExecutorService executor = Executors.newCachedThreadPool();
22+
1223
public DefaultTokenRepository() {}
1324

1425
private static final class InstanceHolder {
@@ -31,6 +42,32 @@ public void removeToken() {
3142

3243
@Override
3344
public void storeToken(String accessToken) {
45+
if (Objects.isNull(accessToken) || accessToken.equals(this.accessToken)) {
46+
return;
47+
}
48+
String oldToken = this.accessToken;
3449
this.accessToken = accessToken;
50+
51+
// only notify if previous token not empty (i.e. previously already logged in)
52+
if (!Strings.isNullOrEmpty(oldToken)) {
53+
notifyOnAccessTokenRefreshed(accessToken);
54+
}
55+
}
56+
57+
protected void notifyOnAccessTokenRefreshed(String newToken) {
58+
for (TokenRepositoryCallback callback: callbacks) {
59+
executor.execute(() -> callback.onAccessTokenRefreshed(newToken));
60+
}
3561
}
62+
63+
@Override
64+
public boolean registerTokenRepositoryCallback(TokenRepositoryCallback callback) {
65+
return callbacks.add(callback);
66+
}
67+
68+
@Override
69+
public boolean unregisterTokenRepositoryCallback(TokenRepositoryCallback callback) {
70+
return callbacks.remove(callback);
71+
}
72+
3673
}

src/main/java/net/accelbyte/sdk/core/repository/TokenRepository.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,12 @@ public interface TokenRepository {
1212
String getToken() throws Exception;
1313

1414
void removeToken() throws Exception;
15+
16+
default boolean registerTokenRepositoryCallback(TokenRepositoryCallback callback) {
17+
return true;
18+
}
19+
20+
default boolean unregisterTokenRepositoryCallback(TokenRepositoryCallback callback) {
21+
return true;
22+
}
1523
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package net.accelbyte.sdk.core.repository;
2+
3+
abstract public class TokenRepositoryCallback {
4+
5+
public void onAccessTokenRefreshed(String newToken) {}
6+
7+
}

0 commit comments

Comments
 (0)