Skip to content

Commit d6e2195

Browse files
authored
Recreate the websocket session when XBL device token get updated (#260)
1 parent e2516df commit d6e2195

3 files changed

Lines changed: 82 additions & 45 deletions

File tree

core/src/main/java/com/rtm516/mcxboxbroadcast/core/AuthManager.java

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ public class AuthManager {
3939
private StepXblSisuAuthentication.XblSisuTokens xboxToken;
4040
private XboxTokenInfo xboxTokenInfo;
4141
private String playfabSessionTicket;
42+
private Runnable onDeviceTokenRefreshCallback;
43+
4244

4345
/**
4446
* Create an instance of AuthManager
@@ -80,15 +82,19 @@ public static XstsAuthData fromCredentials(String email, String password, ILogge
8082
private void initialise() {
8183
HttpClient httpClient = MinecraftAuth.createHttpClient();
8284

83-
// Load in cache.json if we haven't loaded one from the old auth token
84-
try {
85-
String cacheData = storageManager.cache();
86-
if (xboxToken == null && !cacheData.isBlank()) xboxToken = MinecraftAuth.BEDROCK_XBL_DEVICE_CODE_LOGIN.fromJson(JsonUtil.parseString(cacheData).getAsJsonObject());
87-
} catch (IOException e) {
88-
logger.error("Failed to load cache.json", e);
85+
// Try to load xboxToken from cache.json if is not already loaded
86+
if (xboxToken == null) {
87+
try {
88+
String cacheData = storageManager.cache();
89+
if (!cacheData.isBlank()) xboxToken = MinecraftAuth.BEDROCK_XBL_DEVICE_CODE_LOGIN.fromJson(JsonUtil.parseString(cacheData).getAsJsonObject());
90+
} catch (Exception e) {
91+
logger.error("Failed to load cache.json", e);
92+
}
8993
}
9094

9195
try {
96+
String oldDeviceTokenId = (xboxToken != null) ? xboxToken.getInitialXblSession().getXblDeviceToken().getDeviceId() : null;
97+
9298
// Get the XSTS token or refresh it if it's expired
9399
if (xboxToken == null) {
94100
xboxToken = MinecraftAuth.BEDROCK_XBL_DEVICE_CODE_LOGIN.getFromInput(logger, httpClient, new StepMsaDeviceCode.MsaDeviceCodeCallback(msaDeviceCode -> {
@@ -106,6 +112,16 @@ private void initialise() {
106112
xboxTokenInfo = new XboxTokenInfo(xboxToken);
107113

108114
playfabSessionTicket = fetchPlayfabSessionTicket(httpClient);
115+
116+
// If the device token has changed, run the callback
117+
String newDeviceTokenId = xboxToken.getInitialXblSession().getXblDeviceToken().getDeviceId();
118+
if (oldDeviceTokenId != null && newDeviceTokenId != null && !newDeviceTokenId.equals(oldDeviceTokenId)) {
119+
logger.debug("Device token has changed");
120+
if (onDeviceTokenRefreshCallback != null) {
121+
onDeviceTokenRefreshCallback.run();
122+
}
123+
}
124+
109125
} catch (Exception e) {
110126
logger.error("Failed to get/refresh auth token", e);
111127
}
@@ -138,13 +154,17 @@ private String fetchPlayfabSessionTicket(HttpClient httpClient) throws IOExcepti
138154
*/
139155
public XboxTokenInfo getXboxToken() {
140156
if (xboxToken == null || xboxTokenInfo == null || xboxToken.isExpired()) {
157+
logger.debug("xboxToken Need Refresh. (xboxToken: " + (xboxToken != null) +
158+
", xboxTokenInfo: " + (xboxTokenInfo != null) +
159+
", xboxToken.isExpired: " + (xboxToken != null && xboxToken.isExpired()) + ")");
141160
initialise();
142161
}
143162
return xboxTokenInfo;
144163
}
145164

146165
public String getPlayfabSessionTicket() {
147166
if (playfabSessionTicket == null) {
167+
logger.debug("Playfab Session Ticket Need Refresh. (playfabSessionTicket is null)");
148168
initialise();
149169
}
150170
return playfabSessionTicket;
@@ -162,4 +182,13 @@ public void updateGamertag(String gamertag) {
162182
logger.error("Failed to update gamertag", e);
163183
}
164184
}
185+
186+
/**
187+
* Set a callback to be executed when the device token has been refreshed.
188+
*
189+
* @param onDeviceTokenRefreshCallback The callback to execute on device token refresh
190+
*/
191+
public void setOnDeviceTokenRefreshCallback(Runnable onDeviceTokenRefreshCallback) {
192+
this.onDeviceTokenRefreshCallback = onDeviceTokenRefreshCallback;
193+
}
165194
}

core/src/main/java/com/rtm516/mcxboxbroadcast/core/RtaWebsocketClient.java

Lines changed: 37 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public class RtaWebsocketClient extends WebSocketClient {
1717
private String connectionId;
1818
private final Logger logger;
1919
private final String xuid;
20-
private boolean firstConnectionId = true;
20+
private boolean isFirstConnection = true;
2121
private CompletableFuture<String> connectionIdFuture = new CompletableFuture<>();
2222

2323
/**
@@ -68,46 +68,44 @@ public void onOpen(ServerHandshake serverHandshake) {
6868
*/
6969
@Override
7070
public void onMessage(String message) {
71-
if (message.contains("ConnectionId") && firstConnectionId) {
72-
Object[] parts = Constants.GSON.fromJson(message, Object[].class);
73-
connectionId = ((Map<String, String>) parts[4]).get("ConnectionId");
74-
connectionIdFuture.complete(connectionId);
75-
firstConnectionId = false;
71+
// [Type, SequenceId, ...]
72+
// Subscribe: [type, sequenceId, status, subscriptionId, data]
73+
// Unsubscribe: [type, sequenceId, status]
74+
// Event: [type, sequenceId, data]
7675

77-
// Let xbox know we want friend updates
78-
send("[1,2,\"https://social.xboxlive.com/users/xuid(" + this.xuid + ")/friends\"]");
79-
} else {
80-
// [Type, SequenceId, ...]
81-
// Subscribe: [type, sequenceId, status, subscriptionId, data]
82-
// Unsubscribe: [type, sequenceId, status]
83-
// Event: [type, sequenceId, data]
76+
// Handle the message
77+
Object[] parts = Constants.GSON.fromJson(message, Object[].class);
78+
MessageType type = MessageType.fromValue(((Double) parts[0]).intValue());
79+
switch (type) {
80+
case Subscribe:
81+
logger.debug("RTA Websocket [" + connectionId + "] subscribed: " + message);
82+
if (message.contains("ConnectionId") && isFirstConnection) {
83+
connectionId = ((Map<String, String>) parts[4]).get("ConnectionId");
84+
connectionIdFuture.complete(connectionId);
85+
isFirstConnection = false;
8486

85-
// Handle the message
86-
Object[] parts = Constants.GSON.fromJson(message, Object[].class);
87-
MessageType type = MessageType.fromValue(((Double) parts[0]).intValue());
88-
switch (type) {
89-
case Subscribe:
90-
logger.debug("RTA Websocket [" + connectionId + "] subscribed: " + message);
91-
break;
92-
case Unsubscribe:
93-
logger.debug("RTA Websocket [" + connectionId + "] unsubscribed: " + message);
94-
break;
95-
case Event:
96-
logger.debug("RTA Websocket [" + connectionId + "] event: " + message);
97-
// Get data json object
98-
Map<String, Object> data = (Map<String, Object>) parts[2];
99-
if (data.getOrDefault("NotificationType", "").equals("IncomingFriendRequestCountChanged")) {
100-
logger.debug("RTA Websocket [" + connectionId + "] friend request: " + message);
101-
sessionManager.friendManager().acceptPendingFriendRequests();
102-
}
103-
break;
104-
case Resync:
105-
logger.debug("RTA Websocket [" + connectionId + "] resync: " + message);
106-
break;
107-
default:
108-
logger.debug("RTA Websocket [" + connectionId + "] unknown: " + message);
109-
break;
110-
}
87+
// Let xbox know we want friend updates
88+
send("[1,2,\"https://social.xboxlive.com/users/xuid(" + this.xuid + ")/friends\"]");
89+
}
90+
break;
91+
case Unsubscribe:
92+
logger.debug("RTA Websocket [" + connectionId + "] unsubscribed: " + message);
93+
break;
94+
case Event:
95+
logger.debug("RTA Websocket [" + connectionId + "] event: " + message);
96+
// Get data json object
97+
Map<String, Object> data = (Map<String, Object>) parts[2];
98+
if (data.getOrDefault("NotificationType", "").equals("IncomingFriendRequestCountChanged")) {
99+
logger.debug("RTA Websocket [" + connectionId + "] friend request: " + message);
100+
sessionManager.friendManager().acceptPendingFriendRequests();
101+
}
102+
break;
103+
case Resync:
104+
logger.debug("RTA Websocket [" + connectionId + "] resync: " + message);
105+
break;
106+
default:
107+
logger.debug("RTA Websocket [" + connectionId + "] unknown: " + message);
108+
break;
111109
}
112110
}
113111

core/src/main/java/com/rtm516/mcxboxbroadcast/core/SessionManagerCore.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,16 @@ public void init() throws SessionCreationException, SessionUpdateException {
179179
// Let the user know we are done
180180
logger.info("Creation of Xbox LIVE session was successful!");
181181

182+
authManager.setOnDeviceTokenRefreshCallback(() -> {
183+
try {
184+
logger.debug("Device token refreshed, recreating session...");
185+
createSession();
186+
logger.debug("Session recreated after device token refresh");
187+
} catch (Exception e) {
188+
logger.error("Failed to recreate session after device token refresh", e);
189+
}
190+
});
191+
182192
initialized = true;
183193
}
184194

0 commit comments

Comments
 (0)