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)) Map.of("name", "apk", "hash", md5Hex(apkFile))
)); ));
HttpHeaders headers = new HttpHeaders(); // Use curl ProcessBuilder: MI API server drops large multipart body with RestTemplate.
headers.setContentType(MediaType.MULTIPART_FORM_DATA); // curl sends Expect:100-continue which bypasses the server-side body timeout.
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>(); String requestDataJson = asJsonString(requestData);
body.add("apk", new FileSystemResource(apkFile)); String sigJson = rsaEncryptHexChunked(asJsonString(sig), publicKey);
body.add("RequestData", asJsonString(requestData)); ProcessBuilder pb = new ProcessBuilder(
body.add("SIG", rsaEncryptHexChunked(asJsonString(sig), publicKey)); "curl", "-s", "--connect-timeout", "30",
"--max-time", String.valueOf(130 * 60),
ResponseEntity<String> response = rest.postForEntity( "-F", "apk=@" + apkFile.getAbsolutePath(),
"https://api.developer.xiaomi.com/devupload/dev/push", "-F", "RequestData=" + requestDataJson,
new HttpEntity<>(body, headers), "-F", "SIG=" + sigJson,
String.class); "https://api.developer.xiaomi.com/devupload/dev/push"
JsonNode root = mapper.readTree(Objects.requireNonNull(response.getBody())); );
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"); miCheckSuccess(root, "上传Apk");
} }