fix(microsoft): retry 5 times when socket timeout. Closes #1691.

This commit is contained in:
huanghongxun 2022-09-03 23:33:11 +08:00
parent 5e1ae56740
commit 0c7b0f285e
3 changed files with 53 additions and 17 deletions

View File

@ -89,6 +89,7 @@ public class OAuth {
pair("grant_type", "authorization_code"), pair("client_secret", options.callback.getClientSecret()),
pair("redirect_uri", session.getRedirectURI()), pair("scope", options.scope))
.ignoreHttpCode()
.retry(5)
.getJson(AuthorizationResponse.class);
handleErrorResponse(response);
return new Result(response.accessToken, response.refreshToken);
@ -98,6 +99,7 @@ public class OAuth {
DeviceTokenResponse deviceTokenResponse = HttpRequest.POST(deviceCodeURL)
.form(pair("client_id", options.callback.getClientId()), pair("scope", options.scope))
.ignoreHttpCode()
.retry(5)
.getJson(DeviceTokenResponse.class);
handleErrorResponse(deviceTokenResponse);
@ -124,6 +126,7 @@ public class OAuth {
pair("code", deviceTokenResponse.deviceCode),
pair("client_id", options.callback.getClientId()))
.ignoreHttpCode()
.retry(5)
.getJson(TokenResponse.class);
if ("authorization_pending".equals(tokenResponse.error)) {
@ -158,6 +161,7 @@ public class OAuth {
.form(query)
.accept("application/json")
.ignoreHttpCode()
.retry(5)
.getJson(RefreshResponse.class);
handleErrorResponse(response);

View File

@ -119,6 +119,7 @@ public class MicrosoftService {
mapOf(pair("AuthMethod", "RPS"), pair("SiteName", "user.auth.xboxlive.com"),
pair("RpsTicket", "d=" + liveAccessToken))),
pair("RelyingParty", "http://auth.xboxlive.com"), pair("TokenType", "JWT")))
.retry(5)
.accept("application/json").getJson(XBoxLiveAuthenticationResponse.class);
String uhs = getUhs(xboxResponse, null);
@ -132,6 +133,7 @@ public class MicrosoftService {
pair("UserTokens", Collections.singletonList(xboxResponse.token)))),
pair("RelyingParty", "rp://api.minecraftservices.com/"), pair("TokenType", "JWT")))
.ignoreHttpErrorCode(401)
.retry(5)
.getJson(XBoxLiveAuthenticationResponse.class);
getUhs(minecraftXstsResponse, uhs);
@ -140,6 +142,7 @@ public class MicrosoftService {
MinecraftLoginWithXBoxResponse minecraftResponse = HttpRequest
.POST("https://api.minecraftservices.com/authentication/login_with_xbox")
.json(mapOf(pair("identityToken", "XBL3.0 x=" + uhs + ";" + minecraftXstsResponse.token)))
.retry(5)
.accept("application/json").getJson(MinecraftLoginWithXBoxResponse.class);
long notAfter = minecraftResponse.expiresIn * 1000L + System.currentTimeMillis();

View File

@ -21,6 +21,7 @@ import com.google.gson.JsonParseException;
import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.util.Pair;
import org.jackhuang.hmcl.util.function.ExceptionalBiConsumer;
import org.jackhuang.hmcl.util.function.ExceptionalSupplier;
import org.jackhuang.hmcl.util.gson.JsonUtils;
import java.io.IOException;
@ -28,6 +29,7 @@ import java.io.OutputStream;
import java.lang.reflect.Type;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
@ -49,6 +51,7 @@ public abstract class HttpRequest {
protected final Map<String, String> headers = new HashMap<>();
protected ExceptionalBiConsumer<URL, Integer, IOException> responseCodeTester;
protected final Set<Integer> toleratedHttpCodes = new HashSet<>();
protected int retryTimes = 1;
protected boolean ignoreHttpCode;
private HttpRequest(String url, String method) {
@ -82,6 +85,14 @@ public abstract class HttpRequest {
return this;
}
public HttpRequest retry(int retryTimes) {
if (retryTimes < 1) {
throw new IllegalArgumentException("retryTimes >= 1");
}
this.retryTimes = retryTimes;
return this;
}
public abstract String getString() throws IOException;
public CompletableFuture<String> getStringAsync() {
@ -129,9 +140,11 @@ public abstract class HttpRequest {
}
public String getString() throws IOException {
HttpURLConnection con = createConnection();
con = resolveConnection(con);
return IOUtils.readFullyAsString(con.getInputStream(), StandardCharsets.UTF_8);
return getStringWithRetry(() -> {
HttpURLConnection con = createConnection();
con = resolveConnection(con);
return IOUtils.readFullyAsString(con.getInputStream(), StandardCharsets.UTF_8);
}, retryTimes);
}
}
@ -168,25 +181,27 @@ public abstract class HttpRequest {
}
public String getString() throws IOException {
HttpURLConnection con = createConnection();
con.setDoOutput(true);
return getStringWithRetry(() -> {
HttpURLConnection con = createConnection();
con.setDoOutput(true);
try (OutputStream os = con.getOutputStream()) {
os.write(bytes);
}
try (OutputStream os = con.getOutputStream()) {
os.write(bytes);
}
if (responseCodeTester != null) {
responseCodeTester.accept(new URL(url), con.getResponseCode());
} else {
if (con.getResponseCode() / 100 != 2) {
if (!ignoreHttpCode && !toleratedHttpCodes.contains(con.getResponseCode())) {
String data = NetworkUtils.readData(con);
throw new ResponseCodeException(new URL(url), con.getResponseCode(), data);
if (responseCodeTester != null) {
responseCodeTester.accept(new URL(url), con.getResponseCode());
} else {
if (con.getResponseCode() / 100 != 2) {
if (!ignoreHttpCode && !toleratedHttpCodes.contains(con.getResponseCode())) {
String data = NetworkUtils.readData(con);
throw new ResponseCodeException(new URL(url), con.getResponseCode(), data);
}
}
}
}
return NetworkUtils.readData(con);
return NetworkUtils.readData(con);
}, retryTimes);
}
}
@ -203,6 +218,20 @@ public abstract class HttpRequest {
return new HttpPostRequest(url);
}
private static String getStringWithRetry(ExceptionalSupplier<String, IOException> supplier, int retryTimes) throws IOException {
SocketTimeoutException exception = null;
for (int i = 0; i < retryTimes; i++) {
try {
return supplier.get();
} catch (SocketTimeoutException e) {
exception = e;
}
}
if (exception != null)
throw exception;
throw new IOException("retry 0");
}
public interface Authorization {
String getTokenType();