mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-30 20:39:10 +00:00
feat(core): 添加对 GitLab 的资源包托管支持
This commit is contained in:
@@ -26,6 +26,10 @@ public class BukkitAdvancementManager extends AbstractAdvancementManager {
|
||||
this.advancementParser = new AdvancementParser();
|
||||
}
|
||||
|
||||
public void unload() {
|
||||
advancements.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigSectionParser parser() {
|
||||
return this.advancementParser;
|
||||
|
||||
@@ -19,6 +19,7 @@ public class ResourcePackHosts {
|
||||
public static final Key ALIST = Key.of("craftengine:alist");
|
||||
public static final Key DROPBOX = Key.of("craftengine:dropbox");
|
||||
public static final Key ONEDRIVE = Key.of("craftengine:onedrive");
|
||||
public static final Key GITLAB = Key.of("craftengine:gitlab");
|
||||
|
||||
static {
|
||||
register(NONE, NoneHost.FACTORY);
|
||||
@@ -29,6 +30,7 @@ public class ResourcePackHosts {
|
||||
register(ALIST, AlistHost.FACTORY);
|
||||
register(DROPBOX, DropboxHost.FACTORY);
|
||||
register(ONEDRIVE, OneDriveHost.FACTORY);
|
||||
register(GITLAB, GitLabHost.FACTORY);
|
||||
}
|
||||
|
||||
public static void register(Key key, ResourcePackHostFactory factory) {
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
package net.momirealms.craftengine.core.pack.host.impl;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import net.momirealms.craftengine.core.pack.host.ResourcePackDownloadData;
|
||||
import net.momirealms.craftengine.core.pack.host.ResourcePackHost;
|
||||
import net.momirealms.craftengine.core.pack.host.ResourcePackHostFactory;
|
||||
import net.momirealms.craftengine.core.pack.host.ResourcePackHosts;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.util.GsonHelper;
|
||||
import net.momirealms.craftengine.core.util.HashUtils;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.MiscUtils;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.ProxySelector;
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class GitLabHost implements ResourcePackHost {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final String gitlabUrl;
|
||||
private final String accessToken;
|
||||
private final String projectId;
|
||||
private final ProxySelector proxy;
|
||||
|
||||
private String url;
|
||||
private String sha1;
|
||||
private UUID uuid;
|
||||
|
||||
public GitLabHost(String gitlabUrl, String accessToken, String projectId, ProxySelector proxy) {
|
||||
this.gitlabUrl = gitlabUrl;
|
||||
this.accessToken = accessToken;
|
||||
this.projectId = projectId;
|
||||
this.proxy = proxy;
|
||||
this.readCacheFromDisk();
|
||||
}
|
||||
|
||||
public void readCacheFromDisk() {
|
||||
Path cachePath = CraftEngine.instance().dataFolderPath().resolve("gitlab.cache");
|
||||
if (!Files.exists(cachePath)) return;
|
||||
|
||||
try (InputStream is = Files.newInputStream(cachePath)) {
|
||||
Map<String, String> cache = GsonHelper.get().fromJson(
|
||||
new InputStreamReader(is),
|
||||
new TypeToken<Map<String, String>>(){}.getType()
|
||||
);
|
||||
|
||||
this.url = cache.get("url");
|
||||
this.sha1 = cache.get("sha1");
|
||||
|
||||
String uuidString = cache.get("uuid");
|
||||
if (uuidString != null && !uuidString.isEmpty()) {
|
||||
this.uuid = UUID.fromString(uuidString);
|
||||
}
|
||||
|
||||
CraftEngine.instance().logger().info("[GitLab] Loaded cached resource pack info");
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn(
|
||||
"[GitLab] Failed to read cache file: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void saveCacheToDisk() {
|
||||
Map<String, String> cache = new HashMap<>();
|
||||
cache.put("url", this.url);
|
||||
cache.put("sha1", this.sha1);
|
||||
cache.put("uuid", this.uuid != null ? this.uuid.toString() : "");
|
||||
|
||||
Path cachePath = CraftEngine.instance().dataFolderPath().resolve("gitlab.cache");
|
||||
try {
|
||||
Files.writeString(
|
||||
cachePath,
|
||||
GsonHelper.get().toJson(cache),
|
||||
StandardOpenOption.CREATE,
|
||||
StandardOpenOption.TRUNCATE_EXISTING
|
||||
);
|
||||
} catch (IOException e) {
|
||||
CraftEngine.instance().logger().warn(
|
||||
"[GitLab] Failed to save cache: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUpload() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Key type() {
|
||||
return ResourcePackHosts.GITLAB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<List<ResourcePackDownloadData>> requestResourcePackDownloadLink(UUID player) {
|
||||
if (url == null) return CompletableFuture.completedFuture(Collections.emptyList());
|
||||
return CompletableFuture.completedFuture(List.of(ResourcePackDownloadData.of(this.url, this.uuid, this.sha1)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> upload(Path resourcePackPath) {
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
CraftEngine.instance().scheduler().executeAsync(() -> {
|
||||
this.sha1 = HashUtils.calculateLocalFileSha1(resourcePackPath);
|
||||
this.uuid = UUID.nameUUIDFromBytes(this.sha1.getBytes(StandardCharsets.UTF_8));
|
||||
try (HttpClient client = HttpClient.newBuilder().proxy(this.proxy).build()) {
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(this.gitlabUrl + "/api/v4/projects/" + this.projectId + "/uploads"))
|
||||
.header("PRIVATE-TOKEN", this.accessToken)
|
||||
.POST(HttpRequest.BodyPublishers.ofFile(resourcePackPath))
|
||||
.build();
|
||||
long uploadStart = System.currentTimeMillis();
|
||||
CraftEngine.instance().logger().info(
|
||||
"[GitLab] Initiating resource pack upload...");
|
||||
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
|
||||
.thenAccept(response -> {
|
||||
long uploadTime = System.currentTimeMillis() - uploadStart;
|
||||
CraftEngine.instance().logger().info(
|
||||
"[GitLab] Upload request completed in " + uploadTime + "ms");
|
||||
if (response.statusCode() == 200 || response.statusCode() == 201) {
|
||||
Map<String, Object> json = GsonHelper.parseJsonToMap(response.body());
|
||||
if (json.containsKey("full_path")) {
|
||||
this.url = (String) json.get("full_path");
|
||||
future.complete(null);
|
||||
saveCacheToDisk();
|
||||
return;
|
||||
}
|
||||
}
|
||||
CraftEngine.instance().logger().warn("[GitLab] Upload failed: " + response.body());
|
||||
future.completeExceptionally(new RuntimeException("Upload failed: " + response.body()));
|
||||
})
|
||||
.exceptionally(ex -> {
|
||||
CraftEngine.instance().logger().warn(
|
||||
"[GitLab] Upload error: " + ex.getMessage());
|
||||
future.completeExceptionally(ex);
|
||||
return null;
|
||||
});
|
||||
} catch (FileNotFoundException e) {
|
||||
CraftEngine.instance().logger().warn(
|
||||
"[GitLab] Failed to upload resource pack: " + e.getMessage());
|
||||
}
|
||||
});
|
||||
return future;
|
||||
}
|
||||
|
||||
public static class Factory implements ResourcePackHostFactory {
|
||||
|
||||
@Override
|
||||
public ResourcePackHost create(Map<String, Object> arguments) {
|
||||
boolean useEnv = (boolean) arguments.getOrDefault("use-environment-variables", false);
|
||||
String gitlabUrl = (String) arguments.get("gitlab-url");
|
||||
if (gitlabUrl == null || gitlabUrl.isEmpty()) {
|
||||
throw new IllegalArgumentException("'gitlab-url' cannot be empty for GitLab host");
|
||||
}
|
||||
if (gitlabUrl.endsWith("/")) {
|
||||
gitlabUrl = gitlabUrl.substring(0, gitlabUrl.length() - 1);
|
||||
}
|
||||
String accessToken = useEnv ? System.getenv("CE_GITLAB_ACCESS_TOKEN") : (String) arguments.get("access-token");
|
||||
if (accessToken == null || accessToken.isEmpty()) {
|
||||
throw new IllegalArgumentException("Missing required 'access-token' configuration");
|
||||
}
|
||||
String projectId = (String) arguments.get("project-id");
|
||||
if (projectId == null || projectId.isEmpty()) {
|
||||
throw new IllegalArgumentException("Missing required 'project-id' configuration");
|
||||
}
|
||||
projectId = URLEncoder.encode(projectId, StandardCharsets.UTF_8).replace("/", "%2F");
|
||||
ProxySelector proxy = MiscUtils.getProxySelector(arguments.get("proxy"));
|
||||
return new GitLabHost(gitlabUrl, accessToken, projectId, proxy);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user