Skip to content

Commit

Permalink
Merge pull request MaxMaeder#123 from vpzomtrrfrt/s3
Browse files Browse the repository at this point in the history
Add S3 Uploader
  • Loading branch information
lrmtheboss authored Apr 10, 2024
2 parents e143222 + 1639084 commit dd9ee7d
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 10 deletions.
5 changes: 5 additions & 0 deletions DriveBackup/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -231,5 +231,10 @@
<artifactId>adventure-text-serializer-legacy</artifactId>
<version>4.15.0</version>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.5.9</version>
</dependency>
</dependencies>
</project>
23 changes: 16 additions & 7 deletions DriveBackup/src/main/java/ratismal/drivebackup/TestThread.java
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
package ratismal.drivebackup;

import java.io.File;
import java.io.FileOutputStream;
import java.util.Random;

import org.bukkit.command.CommandSender;
import ratismal.drivebackup.UploadThread.UploadLogger;
import ratismal.drivebackup.config.ConfigParser;
import ratismal.drivebackup.config.ConfigParser.Config;

import org.jetbrains.annotations.NotNull;
import ratismal.drivebackup.uploaders.Uploader;
import ratismal.drivebackup.uploaders.dropbox.DropboxUploader;
import ratismal.drivebackup.uploaders.ftp.FTPUploader;
import ratismal.drivebackup.uploaders.googledrive.GoogleDriveUploader;
import ratismal.drivebackup.uploaders.onedrive.OneDriveUploader;
import ratismal.drivebackup.uploaders.s3.S3Uploader;
import ratismal.drivebackup.uploaders.webdav.NextcloudUploader;
import ratismal.drivebackup.uploaders.webdav.WebDAVUploader;
import ratismal.drivebackup.UploadThread.UploadLogger;
import ratismal.drivebackup.config.ConfigParser;
import ratismal.drivebackup.config.ConfigParser.Config;
import ratismal.drivebackup.util.MessageUtil;

import java.io.File;
import java.io.FileOutputStream;
import java.util.Random;

import static ratismal.drivebackup.config.Localization.intl;

public class TestThread implements Runnable {
Expand Down Expand Up @@ -145,6 +146,14 @@ private void testUploadMethod(String testFileName, int testFileSize, @NotNull St
return;
}
break;
case "s3":
if (config.backupMethods.s3.enabled) {
uploadMethod = new S3Uploader(logger, config.backupMethods.s3);
} else {
sendMethodDisabled(logger, S3Uploader.UPLOADER_NAME);
return;
}
break;
case "ftp":
if (config.backupMethods.ftp.enabled) {
uploadMethod = new FTPUploader(logger, config.backupMethods.ftp);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import ratismal.drivebackup.uploaders.googledrive.GoogleDriveUploader;
import ratismal.drivebackup.uploaders.mysql.MySQLUploader;
import ratismal.drivebackup.uploaders.onedrive.OneDriveUploader;
import ratismal.drivebackup.uploaders.s3.S3Uploader;
import ratismal.drivebackup.uploaders.webdav.NextcloudUploader;
import ratismal.drivebackup.uploaders.webdav.WebDAVUploader;
import ratismal.drivebackup.util.BlacklistEntry;
Expand Down Expand Up @@ -247,6 +248,9 @@ public void run() {
if (config.backupMethods.nextcloud.enabled) {
uploaders.add(new NextcloudUploader(logger, config.backupMethods.nextcloud));
}
if (config.backupMethods.s3.enabled) {
uploaders.add(new S3Uploader(logger, config.backupMethods.s3));
}
if (config.backupMethods.ftp.enabled) {
uploaders.add(new FTPUploader(logger, config.backupMethods.ftp));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,21 @@ public NextcloudBackupMethod(boolean enabled, String hostname, String username,
}
}

public static class S3BackupMethod extends BackupMethod {
public final String endpoint;
public final String accessKey;
public final String secretKey;
public final String bucket;

public S3BackupMethod(boolean enabled, String endpoint, String accessKey, String secretKey, String bucket) {
super(enabled);
this.endpoint = endpoint;
this.accessKey = accessKey;
this.secretKey = secretKey;
this.bucket = bucket;
}
}

public static class FTPBackupMethod extends BackupMethod {
public final String hostname;
public final int port;
Expand Down Expand Up @@ -117,14 +132,16 @@ public FTPBackupMethod(
public final DropboxBackupMethod dropbox;
public final WebDAVBackupMethod webdav;
public final NextcloudBackupMethod nextcloud;
public final S3BackupMethod s3;
public final FTPBackupMethod ftp;

public BackupMethods(GoogleDriveBackupMethod googleDrive, OneDriveBackupMethod oneDrive, DropboxBackupMethod dropbox, WebDAVBackupMethod webdav, NextcloudBackupMethod nextcloud, FTPBackupMethod ftp) {
public BackupMethods(GoogleDriveBackupMethod googleDrive, OneDriveBackupMethod oneDrive, DropboxBackupMethod dropbox, WebDAVBackupMethod webdav, NextcloudBackupMethod nextcloud, S3BackupMethod s3, FTPBackupMethod ftp) {
this.googleDrive = googleDrive;
this.oneDrive = oneDrive;
this.dropbox = dropbox;
this.webdav = webdav;
this.nextcloud = nextcloud;
this.s3 = s3;
this.ftp = ftp;
}

Expand Down Expand Up @@ -156,6 +173,15 @@ public static BackupMethods parse(@NotNull FileConfiguration config, Logger logg
config.getString("nextcloud.remote-save-directory", config.getString("remote-save-directory")),
config.getInt("nextcloud.chunk-size", 10_000_000)
);

S3BackupMethod s3Method = new S3BackupMethod(
config.getBoolean("s3.enabled"),
config.getString("s3.endpoint"),
config.getString("s3.access-key"),
config.getString("s3.secret-key"),
config.getString("s3.bucket")
);

boolean ftpEnabled = config.getBoolean("ftp.enabled");
String publicKey = "";
if (!Strings.isNullOrEmpty(config.getString("ftp.sftp-public-key")) && ftpEnabled) {
Expand Down Expand Up @@ -186,6 +212,6 @@ public static BackupMethods parse(@NotNull FileConfiguration config, Logger logg
baseDir
);

return new BackupMethods(googleDriveMethod, oneDriveMethod, dropboxMethod, webdavMethod, nextcloudMethod, ftpMethod);
return new BackupMethods(googleDriveMethod, oneDriveMethod, dropboxMethod, webdavMethod, nextcloudMethod, s3Method, ftpMethod);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ public List<String> onTabComplete(CommandSender player, @NotNull Command cmd, St
if (methods.nextcloud.enabled) {
commandList.add("nextcloud");
}
if (methods.s3.enabled) {
commandList.add("s3");
}
if (methods.ftp.enabled) {
commandList.add("ftp");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package ratismal.drivebackup.uploaders.s3;

import io.minio.ListObjectsArgs;
import io.minio.MinioClient;
import io.minio.RemoveObjectArgs;
import io.minio.Result;
import io.minio.UploadObjectArgs;
import io.minio.messages.Item;
import org.jetbrains.annotations.NotNull;
import ratismal.drivebackup.UploadThread.UploadLogger;
import ratismal.drivebackup.config.ConfigParser;
import ratismal.drivebackup.config.configSections.BackupMethods.S3BackupMethod;
import ratismal.drivebackup.uploaders.Authenticator;
import ratismal.drivebackup.uploaders.Uploader;
import ratismal.drivebackup.util.MessageUtil;
import ratismal.drivebackup.util.NetUtil;

import java.io.File;
import java.net.URL;
import java.time.ZonedDateTime;
import java.util.Map;
import java.util.TreeMap;

import static ratismal.drivebackup.config.Localization.intl;

public class S3Uploader extends Uploader {
private UploadLogger logger;

public static final String UPLOADER_NAME = "S3";
public static final String UPLOADER_ID = "s3";

private MinioClient minioClient;

private boolean _errorOccurred;
private String _bucket;
private String _hostname;

public S3Uploader(UploadLogger logger, S3BackupMethod config) {
super(UPLOADER_NAME, UPLOADER_ID);
this.logger = logger;
try {
_hostname = new URL(config.endpoint).getHost();
_bucket = config.bucket;
minioClient = MinioClient.builder().endpoint(config.endpoint).credentials(config.accessKey, config.secretKey).build();
} catch(Exception e) {
MessageUtil.sendConsoleException(e);
setErrorOccurred(true);
}
}

@Override
public String getName() {
return UPLOADER_NAME;
}

@Override
public String getId() {
return UPLOADER_ID;
}

@Override
public Authenticator.AuthenticationProvider getAuthProvider() {
return null;
}

@Override
public boolean isAuthenticated() {
return true;
}

@Override
public boolean isErrorWhileUploading() {
return _errorOccurred;
}

@Override
public void test(File testFile) {
try {
minioClient.uploadObject(UploadObjectArgs.builder().bucket(_bucket).object(testFile.getName()).filename(testFile.getAbsolutePath()).build());
Thread.sleep(5L);
minioClient.removeObject(RemoveObjectArgs.builder().bucket(_bucket).object(testFile.getName()).build());
} catch (Exception exception) {
NetUtil.catchException(exception, _hostname, logger);
MessageUtil.sendConsoleException(exception);
setErrorOccurred(true);
}
}

@Override
public void uploadFile(File file, String type) {
type = normalizeType(type);
try {
String key = type + "/" + file.getName();
minioClient.uploadObject(UploadObjectArgs.builder().bucket(_bucket).object(key).filename(file.getAbsolutePath()).build());
try {
pruneBackups(type);
} catch (Exception e) {
logger.log(intl("backup-method-prune-failed"));
throw e;
}
} catch(Exception exception) {
NetUtil.catchException(exception, _hostname, logger);
MessageUtil.sendConsoleException(exception);
setErrorOccurred(true);
}
}

@Override
public void close() {
}

public void setErrorOccurred(boolean errorOccurred) {
_errorOccurred = errorOccurred;
}

public void pruneBackups(String type) throws Exception {
int fileLimit = ConfigParser.getConfig().backupStorage.keepCount;
if (fileLimit == -1) {
return;
}
TreeMap<ZonedDateTime, Item> files = getZipFiles(type);
if (files.size() > fileLimit) {
logger.info(
intl("backup-method-limit-reached"),
"file-count", String.valueOf(files.size()),
"upload-method", getName(),
"file-limit", String.valueOf(fileLimit));
while (files.size() > fileLimit) {
Map.Entry<ZonedDateTime, Item> firstEntry = files.firstEntry();
minioClient.removeObject(RemoveObjectArgs.builder().bucket(_bucket).object(firstEntry.getValue().objectName()).build());
files.remove(firstEntry.getKey());
}
}
}

@NotNull
private TreeMap<ZonedDateTime, Item> getZipFiles(String type) throws Exception {
type = normalizeType(type);
String prefix = type + "/";
TreeMap<ZonedDateTime, Item> files = new TreeMap<>();
for (Result<Item> result : minioClient.listObjects(ListObjectsArgs.builder().bucket(_bucket).prefix(prefix).build())) {
Item item = result.get();
files.put(item.lastModified(), item);
}
return files;
}

@NotNull
private String normalizeType(@NotNull String type) {
if(type.startsWith("./")) {
return type.substring(2);
}
return type;
}

}
8 changes: 7 additions & 1 deletion DriveBackup/src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ nextcloud:
username: "Username"
password: "Password"
chunk-size: 20_000_000
s3:
enabled: false
endpoint: "https://s3.us-west-2.amazonaws.com"
access-key: "AKIAxxxxxxxxxxxxxxxx"
secret-key: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
bucket: "bucket"
ftp:
enabled: false
hostname: "ftp.example.com"
Expand All @@ -73,4 +79,4 @@ advanced:
debug: false
date-language: "en"
date-timezone: "-00:00"
ftp-file-separator: "/"
ftp-file-separator: "/"

0 comments on commit dd9ee7d

Please sign in to comment.