FileUpload.java
com.mojang.realmsclient.client.FileUpload
信息
- 全限定名:com.mojang.realmsclient.client.FileUpload
- 类型:public class
- 包:com.mojang.realmsclient.client
- 源码路径:src/main/java/com/mojang/realmsclient/client/FileUpload.java
- 起始行号:L31
- 实现:AutoCloseable
- 职责:
TODO
字段/常量
-
LOGGER- 类型:
Logger - 修饰符:
private static final - 源码定位:
L32 - 说明:
TODO
- 类型:
-
MAX_RETRIES- 类型:
int - 修饰符:
private static final - 源码定位:
L33 - 说明:
TODO
- 类型:
-
UPLOAD_PATH- 类型:
String - 修饰符:
private static final - 源码定位:
L34 - 说明:
TODO
- 类型:
-
file- 类型:
File - 修饰符:
private final - 源码定位:
L35 - 说明:
TODO
- 类型:
-
realmId- 类型:
long - 修饰符:
private final - 源码定位:
L36 - 说明:
TODO
- 类型:
-
slotId- 类型:
int - 修饰符:
private final - 源码定位:
L37 - 说明:
TODO
- 类型:
-
uploadInfo- 类型:
UploadInfo - 修饰符:
private final - 源码定位:
L38 - 说明:
TODO
- 类型:
-
sessionId- 类型:
String - 修饰符:
private final - 源码定位:
L39 - 说明:
TODO
- 类型:
-
username- 类型:
String - 修饰符:
private final - 源码定位:
L40 - 说明:
TODO
- 类型:
-
clientVersion- 类型:
String - 修饰符:
private final - 源码定位:
L41 - 说明:
TODO
- 类型:
-
worldVersion- 类型:
String - 修饰符:
private final - 源码定位:
L42 - 说明:
TODO
- 类型:
-
uploadStatus- 类型:
UploadStatus - 修饰符:
private final - 源码定位:
L43 - 说明:
TODO
- 类型:
-
client- 类型:
HttpClient - 修饰符:
private final - 源码定位:
L44 - 说明:
TODO
- 类型:
内部类/嵌套类型
com.mojang.realmsclient.client.FileUpload.UploadCountingInputStream- 类型:
class - 修饰符:
private static - 源码定位:
L152 - 说明:
TODO
- 类型:
构造器
public FileUpload(File file, long realmId, int slotId, UploadInfo uploadInfo, User user, String clientVersion, String worldVersion, UploadStatus uploadStatus) @ L46
- 构造器名:FileUpload
- 源码定位:L46
- 修饰符:public
参数:
- file: File
- realmId: long
- slotId: int
- uploadInfo: UploadInfo
- user: User
- clientVersion: String
- worldVersion: String
- uploadStatus: UploadStatus
说明:
TODO
方法
下面的方法块按源码顺序生成。
public void close() @ L61
- 方法名:close
- 源码定位:L61
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
public CompletableFuture<UploadResult> startUpload() @ L66
- 方法名:startUpload
- 源码定位:L66
- 返回类型:CompletableFuture
- 修饰符:public
参数:
- 无
说明:
TODO
private CompletableFuture<UploadResult> requestUpload(int currentAttempt, long fileSize) @ L72
- 方法名:requestUpload
- 源码定位:L72
- 返回类型:CompletableFuture
- 修饰符:private
参数:
- currentAttempt: int
- fileSize: long
说明:
TODO
private static BodyPublisher inputStreamPublisherWithSize(Supplier<InputStream> inputStreamSupplier, long fileSize) @ L104
- 方法名:inputStreamPublisherWithSize
- 源码定位:L104
- 返回类型:BodyPublisher
- 修饰符:private static
参数:
- inputStreamSupplier: Supplier
- fileSize: long
说明:
TODO
private String uploadCookie() @ L108
- 方法名:uploadCookie
- 源码定位:L108
- 返回类型:String
- 修饰符:private
参数:
- 无
说明:
TODO
private UploadResult handleResponse(HttpResponse<String> response) @ L121
- 方法名:handleResponse
- 源码定位:L121
- 返回类型:UploadResult
- 修饰符:private
参数:
- response: HttpResponse
说明:
TODO
private boolean shouldRetry(long retryDelaySeconds, int currentAttempt) @ L143
- 方法名:shouldRetry
- 源码定位:L143
- 返回类型:boolean
- 修饰符:private
参数:
- retryDelaySeconds: long
- currentAttempt: int
说明:
TODO
private long getRetryDelaySeconds(HttpResponse<?> response) @ L147
- 方法名:getRetryDelaySeconds
- 源码定位:L147
- 返回类型:long
- 修饰符:private
参数:
- response: HttpResponse<?>
说明:
TODO
代码
@OnlyIn(Dist.CLIENT)
public class FileUpload implements AutoCloseable {
private static final Logger LOGGER = LogUtils.getLogger();
private static final int MAX_RETRIES = 5;
private static final String UPLOAD_PATH = "/upload";
private final File file;
private final long realmId;
private final int slotId;
private final UploadInfo uploadInfo;
private final String sessionId;
private final String username;
private final String clientVersion;
private final String worldVersion;
private final UploadStatus uploadStatus;
private final HttpClient client;
public FileUpload(
File file, long realmId, int slotId, UploadInfo uploadInfo, User user, String clientVersion, String worldVersion, UploadStatus uploadStatus
) {
this.file = file;
this.realmId = realmId;
this.slotId = slotId;
this.uploadInfo = uploadInfo;
this.sessionId = user.getSessionId();
this.username = user.getName();
this.clientVersion = clientVersion;
this.worldVersion = worldVersion;
this.uploadStatus = uploadStatus;
this.client = HttpClient.newBuilder().executor(Util.nonCriticalIoPool()).connectTimeout(Duration.ofSeconds(15L)).build();
}
@Override
public void close() {
this.client.close();
}
public CompletableFuture<UploadResult> startUpload() {
long fileSize = this.file.length();
this.uploadStatus.setTotalBytes(fileSize);
return this.requestUpload(0, fileSize);
}
private CompletableFuture<UploadResult> requestUpload(int currentAttempt, long fileSize) {
BodyPublisher publisher = inputStreamPublisherWithSize(() -> {
try {
return new FileUpload.UploadCountingInputStream(new FileInputStream(this.file), this.uploadStatus);
} catch (IOException var2) {
LOGGER.warn("Failed to open file {}", this.file, var2);
return null;
}
}, fileSize);
HttpRequest request = HttpRequest.newBuilder(this.uploadInfo.uploadEndpoint().resolve("/upload/" + this.realmId + "/" + this.slotId))
.timeout(Duration.ofMinutes(10L))
.setHeader("Cookie", this.uploadCookie())
.setHeader("Content-Type", "application/octet-stream")
.POST(publisher)
.build();
return this.client.sendAsync(request, BodyHandlers.ofString(StandardCharsets.UTF_8)).thenCompose(response -> {
long retryDelaySeconds = this.getRetryDelaySeconds((HttpResponse<?>)response);
if (this.shouldRetry(retryDelaySeconds, currentAttempt)) {
this.uploadStatus.restart();
try {
Thread.sleep(Duration.ofSeconds(retryDelaySeconds));
} catch (InterruptedException var8) {
}
return this.requestUpload(currentAttempt + 1, fileSize);
} else {
return CompletableFuture.completedFuture(this.handleResponse((HttpResponse<String>)response));
}
});
}
private static BodyPublisher inputStreamPublisherWithSize(Supplier<@Nullable InputStream> inputStreamSupplier, long fileSize) {
return BodyPublishers.fromPublisher(BodyPublishers.ofInputStream(inputStreamSupplier), fileSize);
}
private String uploadCookie() {
return "sid="
+ this.sessionId
+ ";token="
+ this.uploadInfo.token()
+ ";user="
+ this.username
+ ";version="
+ this.clientVersion
+ ";worldVersion="
+ this.worldVersion;
}
private UploadResult handleResponse(HttpResponse<String> response) {
int statusCode = response.statusCode();
if (statusCode == 401) {
LOGGER.debug("Realms server returned 401: {}", response.headers().firstValue("WWW-Authenticate"));
}
String errorMessage = null;
String body = response.body();
if (body != null && !body.isBlank()) {
try {
JsonElement errorMsgElement = LenientJsonParser.parse(body).getAsJsonObject().get("errorMsg");
if (errorMsgElement != null) {
errorMessage = errorMsgElement.getAsString();
}
} catch (Exception var6) {
LOGGER.warn("Failed to parse response {}", body, var6);
}
}
return new UploadResult(statusCode, errorMessage);
}
private boolean shouldRetry(long retryDelaySeconds, int currentAttempt) {
return retryDelaySeconds > 0L && currentAttempt + 1 < 5;
}
private long getRetryDelaySeconds(HttpResponse<?> response) {
return response.headers().firstValueAsLong("Retry-After").orElse(0L);
}
@OnlyIn(Dist.CLIENT)
private static class UploadCountingInputStream extends CountingInputStream {
private final UploadStatus uploadStatus;
private UploadCountingInputStream(InputStream proxy, UploadStatus uploadStatus) {
super(proxy);
this.uploadStatus = uploadStatus;
}
@Override
protected void afterRead(int n) throws IOException {
super.afterRead(n);
this.uploadStatus.onWrite(this.getByteCount());
}
}
}引用的其他类
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
构造调用/返回值 - 关联成员:
UploadResult()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
LenientJsonParser.parse()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Util.nonCriticalIoPool()
- 引用位置:
-
- 引用位置:
参数/字段
- 引用位置: