fix(update): use curl for Xiaomi APK upload to bypass server-side body timeout

RestTemplate drops large multipart payloads on the MI API server; switching to
ProcessBuilder curl with Expect:100-continue headers and a 130-minute timeout resolves
upload failures for large APKs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
这个提交包含在:
XuqmGroup 2026-05-16 02:24:04 +08:00
父节点 afb57a5d5f
当前提交 e7dbdc2ef3

查看文件

@ -974,18 +974,30 @@ public class StoreSubmissionService {
Map.of("name", "apk", "hash", md5Hex(apkFile))
));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("apk", new FileSystemResource(apkFile));
body.add("RequestData", asJsonString(requestData));
body.add("SIG", rsaEncryptHexChunked(asJsonString(sig), publicKey));
ResponseEntity<String> response = rest.postForEntity(
"https://api.developer.xiaomi.com/devupload/dev/push",
new HttpEntity<>(body, headers),
String.class);
JsonNode root = mapper.readTree(Objects.requireNonNull(response.getBody()));
// Use curl ProcessBuilder: MI API server drops large multipart body with RestTemplate.
// curl sends Expect:100-continue which bypasses the server-side body timeout.
String requestDataJson = asJsonString(requestData);
String sigJson = rsaEncryptHexChunked(asJsonString(sig), publicKey);
ProcessBuilder pb = new ProcessBuilder(
"curl", "-s", "--connect-timeout", "30",
"--max-time", String.valueOf(130 * 60),
"-F", "apk=@" + apkFile.getAbsolutePath(),
"-F", "RequestData=" + requestDataJson,
"-F", "SIG=" + sigJson,
"https://api.developer.xiaomi.com/devupload/dev/push"
);
pb.redirectErrorStream(true);
Process process = pb.start();
String responseBody = new String(process.getInputStream().readAllBytes(), StandardCharsets.UTF_8).trim();
boolean completed = process.waitFor(130, java.util.concurrent.TimeUnit.MINUTES);
if (!completed) {
process.destroyForcibly();
throw new IllegalStateException("curl upload to MI timed out");
}
if (responseBody.isEmpty()) {
throw new IllegalStateException("curl upload to MI returned empty response (exit=" + process.exitValue() + ")");
}
JsonNode root = mapper.readTree(responseBody);
miCheckSuccess(root, "上传Apk");
}