Skip to content

Commit

Permalink
feat: add cloudflare r2
Browse files Browse the repository at this point in the history
  • Loading branch information
xfl03 committed Nov 1, 2023
1 parent e9e1955 commit 6cb3730
Show file tree
Hide file tree
Showing 11 changed files with 256 additions and 91 deletions.
20 changes: 12 additions & 8 deletions .github/workflows/common.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ jobs:
modtype: [Fabric,Forge-Active,Forge-Legacy]
include:
-
website: TencentCOS
website: ObjectStorage
modtype: All
# -
# website: GitHub-Release
Expand Down Expand Up @@ -114,7 +114,7 @@ jobs:
echo "pathlist="$(find build/libs -type f|grep -v "sources"|grep -v "json")"" >> $GITHUB_OUTPUT
-
if: ${{ matrix.website == 'GitHub-PreRelease' && startsWith(github.ref, 'refs/heads') }}
name: GitHub Pre-Release Delete
name: "[GitHub Pre-Release] Delete"
uses: 8Mi-Tech/delete-release-assets-action@main
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -133,15 +133,15 @@ jobs:
EOF
-
if: ${{ matrix.website == 'GitHub-PreRelease' && startsWith(github.ref, 'refs/heads') }}
name: GitHub Pre-Release Upload Tag
name: "[GitHub Pre-Release] Upload Tag"
uses: richardsimko/update-tag@v1.0.7
with:
tag_name: CI-Build
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
if: ${{ matrix.website == 'GitHub-PreRelease' && startsWith(github.ref, 'refs/heads') }}
name: GitHub Pre-Release Publish
name: "[GitHub Pre-Release] Publish"
uses: softprops/action-gh-release@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -154,20 +154,24 @@ jobs:
-
if: ${{ matrix.website == 'GitHub-Release' && inputs.type == 'Release' }}
uses: softprops/action-gh-release@v1
name: GitHub Release Publish
name: "[GitHub Release] Publish"
with:
token: ${{ secrets.GITHUB_TOKEN }}
name: CustomSkinLoader ${{ github.ref }}
tag_name: ${{ github.ref }}
#generate_release_notes: true
files: ${{ steps.cslenv-github.outputs.pathlist }}
-
if: ${{ matrix.website == 'TencentCOS' }}
name: 【TencentCOS】 Publish
if: ${{ matrix.website == 'ObjectStorage' }}
name: "[ObjectStorage] Publish"
env:
COS_BUCKET: ${{ secrets.COS_BUCKET }}
COS_SECRET_ID: ${{ secrets.COS_SECRET_ID }}
COS_SECRET_KEY: ${{ secrets.COS_SECRET_KEY }}
R2_BASE_URL: ${{ secrets.R2_BASE_URL }}
R2_BUCKET: ${{ secrets.R2_BUCKET }}
R2_SECRET_ID: ${{ secrets.R2_SECRET_ID }}
R2_SECRET_KEY: ${{ secrets.R2_SECRET_KEY }}
IS_SNAPSHOT: ${{ inputs.is-snapshot }}
run: |
export GIT_COMMIT_DESC=$(git log --format=%B -n 1 $GITHUB_SHA)
Expand All @@ -176,7 +180,7 @@ jobs:
-
if: ${{ matrix.website == 'CurseForge_Modrinth' && inputs.type == 'Release' }}
name: CurseForge & Modrinth Publish
name: "[CurseForge & Modrinth] Publish"
uses: Kir-Antipov/mc-publish@v3.3
with:
modrinth-id: idMHQ4n2
Expand Down
2 changes: 1 addition & 1 deletion buildSrc/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ dependencies {
implementation("com.qcloud:cos_api:5.6.98")
implementation("com.tencentcloudapi:tencentcloud-sdk-java-cdn:3.1.559")
implementation("com.google.code.gson:gson:2.9.0")
implementation("commons-io:commons-io:2.11.0")
implementation("net.minecraftforge.gradle:ForgeGradle:2.3.+")
implementation("gradle.plugin.com.matthewprenger:CurseGradle:1.4.0")
implementation("gradle.plugin.com.modrinth.minotaur:Minotaur:1.2.1")
implementation("org.spongepowered:mixingradle:0.6-SNAPSHOT")
implementation("software.amazon.awssdk:s3:2.21.10")
}

apply from: file("patch.gradle")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package customskinloader.gradle.storage;

import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.region.Region;
import customskinloader.gradle.util.CdnUtil;

import java.nio.file.Path;

/**
* Tencent Cloud COS
*/
public class CosStorage implements Storage {
private static final String BUCKET_NAME = System.getenv("COS_BUCKET");
private COSClient cosClient = null;

private COSClient getCosClient() {
if (cosClient != null) {
return cosClient;
}

synchronized (this) {
if (cosClient != null) {
return cosClient;
}

COSCredentials cred = new BasicCOSCredentials(
System.getenv("COS_SECRET_ID"),
System.getenv("COS_SECRET_KEY")
);
ClientConfig clientConfig = new ClientConfig(new Region("ap-shanghai"));
cosClient = new COSClient(cred, clientConfig);

return cosClient;
}
}

@Override
public void put(String key, Path file) {
PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKET_NAME, key, file.toFile());
getCosClient().putObject(putObjectRequest);
}

@Override
public String getPublicBaseUrl() {
return CdnUtil.TENCENT_CDN_ROOT;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package customskinloader.gradle.storage;

import customskinloader.gradle.util.CdnUtil;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;

import javax.annotation.Nonnull;
import java.net.URI;

/**
* CloudFlare R2
*/
public class R2Storage extends S3Storage {
@Nonnull
@Override
protected S3Client initClient() {
try {
return S3Client.builder()
.endpointOverride(new URI(System.getenv("R2_BASE_URL")))
.credentialsProvider(
StaticCredentialsProvider.create(
AwsBasicCredentials.create(
System.getenv("R2_SECRET_ID"),
System.getenv("R2_SECRET_KEY"))))
.region(Region.of("auto"))
.build();
} catch (Exception e) {
throw new RuntimeException(e);
}
}

@Nonnull
@Override
protected String getBucket() {
return System.getenv("R2_BUCKET");
}

@Override
public String getPublicBaseUrl() {
return CdnUtil.CLOUDFLARE_CDN_ROOT;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package customskinloader.gradle.storage;

import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;

import javax.annotation.Nonnull;
import java.nio.file.Path;

/**
* Amazon Web Service Simple Storage Service
* There is also plenty of S3 compatible API.
*/
public abstract class S3Storage implements Storage {
private S3Client client;

/**
* The S3 client will be initialized only once.
* @return S3 client
*/
protected abstract @Nonnull S3Client initClient();

private @Nonnull S3Client getClient() {
if (client != null) {
return client;
}
synchronized (this) {
if (client != null) {
return client;
}
client = initClient();
return client;
}
}

/**
* Get bucket for object.
* @return bucket
*/
protected abstract @Nonnull String getBucket();

@Override
public void put(String key, Path file) {
getClient().putObject(
PutObjectRequest.builder()
.bucket(getBucket())
.key(key).build(),
file
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package customskinloader.gradle.storage;

import java.nio.file.Path;

public interface Storage {
/**
* Put file to object storage service.
* @param key key
* @param file file
*/
void put(String key, Path file);

String getPublicBaseUrl();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package customskinloader.gradle.storage;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

public class StorageService {
private static final List<Storage> storages = new ArrayList<>();

static {
storages.add(new CosStorage());
storages.add(new R2Storage());
}

/**
* Put file to all storage.
*
* @param key key
* @param file file
*/
public static void put(String key, Path file) {
storages.forEach(it -> it.put(key, file));
}

private static final Gson gson = new GsonBuilder().setPrettyPrinting().create();

/**
* Put object to all storage.
*
* @param key key
* @param obj obj
*/
public static void put(String key, Object obj) throws IOException {
for (Storage it : storages) {
Path file = Paths.get("build/libs/", key);
Files.write(file,
gson.toJson(obj).replace(BASE_URL, it.getPublicBaseUrl()).getBytes(StandardCharsets.UTF_8));
it.put(key, file);
}
}

public static final String BASE_URL = "{BASE_URL}";
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
package customskinloader.gradle.task;

import java.io.File;
import java.io.IOException;

import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import customskinloader.gradle.entity.CslDetail;
import customskinloader.gradle.entity.CslLatest;
import customskinloader.gradle.storage.StorageService;
import customskinloader.gradle.util.CdnUtil;
import customskinloader.gradle.util.ConfigUtil;
import customskinloader.gradle.util.CosUtil;
import customskinloader.gradle.util.StorageUtil;
import customskinloader.gradle.util.VersionUtil;
import org.gradle.api.DefaultTask;
import org.gradle.api.Project;

import java.io.File;
import java.io.IOException;

public abstract class UploadBaseTask extends DefaultTask {
public Project rootProject;

Expand All @@ -35,25 +36,25 @@ private CslLatest uploadArtifacts(String filename) throws IOException {
//Don't upload sources jar to cos
continue;
}
String key = CosUtil.getKey(file.getName());
String key = StorageUtil.getKey(file.getName());
if (key == null) {
continue;
}
CosUtil.uploadFile(key, file);
String url = CdnUtil.CDN_ROOT + key;
StorageService.put(key, file);
String mcversion = VersionUtil.getMcVersion(file.getName());
if (mcversion.equals("ForgeLegacy")) {
mcversion = "Forge";
}
System.out.printf("csl-%s-%s\t%s%n",
mcversion.replace(".", "").toLowerCase(), cslversion, url);
mcversion.replace(".", "").toLowerCase(),
cslversion, CdnUtil.CLOUDFLARE_CDN_ROOT + key);

if (key.startsWith("mods/") && key.endsWith(".jar") && !key.endsWith("-sources.jar")) {
latest.downloads.put(mcversion, url);
latest.downloads.put(mcversion, StorageService.BASE_URL + key);
}
}

CosUtil.writeAndUploadObject(filename, latest);
StorageService.put(filename, latest);
return latest;
}

Expand All @@ -71,7 +72,7 @@ private void uploadDetail(CslLatest latest, String filename) throws IOException
});

detail.sortDetails();
CosUtil.writeAndUploadObject(filename, detail);
StorageService.put(filename, detail);
}

protected void uploadBase(String latestJsonName, String detailJsonName) throws IOException, TencentCloudSDKException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
import java.util.Arrays;

public class CdnUtil {
public static final String CDN_ROOT = "https://csl.littleservice.cn/";
public static final String TENCENT_CDN_ROOT = "https://csl.littleservice.cn/";
public static final String CLOUDFLARE_CDN_ROOT = "https://csl.3-3.dev/";
private static CdnClient cdnClient;

private static CdnClient getCdnClient() {
Expand All @@ -34,7 +35,7 @@ private static CdnClient getCdnClient() {
* @throws TencentCloudSDKException when Tencent Cloud API has exception
*/
public static void updateCdn(String... paths) throws TencentCloudSDKException {
String[] urls = Arrays.stream(paths).map(it -> CDN_ROOT + it).toArray(String[]::new);
String[] urls = Arrays.stream(paths).map(it -> TENCENT_CDN_ROOT + it).toArray(String[]::new);

//Purge CDN cache
PurgeUrlsCacheRequest purgeReq = new PurgeUrlsCacheRequest();
Expand Down
Loading

0 comments on commit 6cb3730

Please sign in to comment.