package com.fanruan.fs.s3.repository.core; import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.client.builder.AwsClientBuilder; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; import com.amazonaws.services.s3.model.CopyObjectRequest; import com.amazonaws.services.s3.model.DeleteObjectRequest; import com.amazonaws.services.s3.model.GetObjectRequest; import com.amazonaws.services.s3.model.ListObjectsRequest; import com.amazonaws.services.s3.model.ObjectListing; import com.amazonaws.services.s3.model.ObjectMetadata; import com.amazonaws.services.s3.model.PutObjectRequest; import com.amazonaws.services.s3.model.S3Object; import com.amazonaws.services.s3.model.S3ObjectSummary; import com.fanruan.api.log.LogKit; import com.fanruan.api.util.StringKit; import com.fr.io.repository.FineFileEntry; import com.fr.io.repository.base.BaseResourceRepository; import com.fr.stable.Filter; import com.fr.workspace.resource.ResourceIOException; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.List; /** * @author richie * @version 10.0 * Created by richie on 2020/6/15 */ public class S3ResourceRepository extends BaseResourceRepository { private static final String DELIMITER = "/"; private final AmazonS3 s3; private final String bucket; public S3ResourceRepository(String repoName, String workRoot, S3Config config) { super(repoName, workRoot); BasicAWSCredentials credentials = new BasicAWSCredentials(config.getAccessKeyId(), config.getAccessKeySecret()); this.s3 = AmazonS3ClientBuilder.standard() .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(config.getEndPoint(), config.getRegion())) .withCredentials(new AWSStaticCredentialsProvider(credentials)).build(); this.bucket = config.getBucket(); } @Override public String getSeparator() { return "/"; } @Override public FineFileEntry getEntry(String path) { GetObjectRequest request = new GetObjectRequest(bucket, path); S3Object s3Object = s3.getObject(request); return s3Object2FileEntry(s3Object, path); } @Override public FineFileEntry[] listEntry(String dir) { List result = new ArrayList<>(); if (!dir.endsWith(DELIMITER)) { dir += DELIMITER; } ListObjectsRequest listObjectsRequest = new ListObjectsRequest().withBucketName(bucket) .withPrefix(dir).withDelimiter(DELIMITER); ObjectListing objectListing = s3.listObjects(listObjectsRequest); for (S3ObjectSummary summary : objectListing.getObjectSummaries()) { String key = summary.getKey(); if (!key.endsWith(DELIMITER)) { result.add(s3Object2FileEntry(summary, key)); } } for (String prefix : objectListing.getCommonPrefixes()) { FineFileEntry entry = new FineFileEntry(prefix); entry.setDirectory(true); result.add(entry); } return result.toArray(new FineFileEntry[0]); } private FineFileEntry s3Object2FileEntry(S3ObjectSummary s3Object, String path) { FineFileEntry entry = new FineFileEntry(path); entry.setDirectory(s3Object.getKey().endsWith("/")); entry.setSize(s3Object.getSize()); entry.setTimestamp(s3Object.getLastModified().getTime()); return entry; } private FineFileEntry s3Object2FileEntry(S3Object s3Object, String path) { FineFileEntry entry = new FineFileEntry(path); entry.setDirectory(s3Object.getKey().endsWith("/")); entry.setSize(s3Object.getObjectMetadata().getContentLength()); entry.setTimestamp(s3Object.getObjectMetadata().getLastModified().getTime()); return entry; } @Override public URL getResource(String path) { throw new RuntimeException("Not support method."); } @Override public InputStream read(String filePath) throws ResourceIOException { GetObjectRequest request = new GetObjectRequest(bucket, filePath); try { return s3.getObject(request).getObjectContent(); } catch (Exception e) { return new ByteArrayInputStream(new byte[0]); } } @Override public void write(String path, byte[] data) { ObjectMetadata metadata; try { metadata = s3.getObjectMetadata(bucket, path); } catch (Exception e) { metadata = new ObjectMetadata(); String mimeType = URLConnection.guessContentTypeFromName(path); if (mimeType != null) { metadata.setContentType(mimeType); } metadata.setContentLength(data.length); } s3.putObject(bucket, path, new ByteArrayInputStream(data), metadata); } @Override public boolean createFile(String path) { PutObjectRequest request = new PutObjectRequest(bucket, path, new ByteArrayInputStream(new byte[0]), new ObjectMetadata()); try { s3.putObject(request); } catch (Exception e) { return false; } return true; } @Override public boolean createDirectory(String path) { PutObjectRequest request = new PutObjectRequest(bucket, path + "/", new ByteArrayInputStream(new byte[0]), new ObjectMetadata()); try { s3.putObject(request); } catch (Exception e) { return false; } return true; } @Override public boolean delete(String path) { try { s3.deleteObject(bucket, path); } catch (Exception e) { LogKit.error(e.getMessage(), e); return false; } return true; } @Override public boolean exist(String path) { try { return !s3.listObjects(bucket, path).getObjectSummaries().isEmpty(); } catch (Exception e) { return false; } } @Override public String[] list(String dir, final Filter filter) { List result = new ArrayList<>(); if (!dir.endsWith(DELIMITER)) { dir += DELIMITER; } ListObjectsRequest listObjectsRequest = new ListObjectsRequest().withBucketName(bucket) .withPrefix(dir).withDelimiter(DELIMITER); ObjectListing objectListing = s3.listObjects(listObjectsRequest); for (S3ObjectSummary objectSummary : objectListing.getObjectSummaries()) { String[] arr = objectSummary.getKey().split(DELIMITER); String name = arr[arr.length - 1]; if (filter == null) { result.add(name); } else { if (filter.accept(name)) { result.add(name); } } } for (String prefix : objectListing.getCommonPrefixes()) { String[] arr = prefix.split(DELIMITER); String name = arr[arr.length - 1] + DELIMITER; if (filter == null) { result.add(name); } else { if (filter.accept(name)) { result.add(name); } } } return result.toArray(new String[0]); } @Override public boolean isDirectory(String path) { if (path.endsWith(DELIMITER)) { return true; } ObjectListing listing = s3.listObjects(bucket, path); if (listing.getObjectSummaries().isEmpty()) { return false; } if (listing.getObjectSummaries().size() > 1) { return true; } else { S3ObjectSummary summary = listing.getObjectSummaries().get(0); return !StringKit.equals(listing.getPrefix(), summary.getKey()); } } @Override public long lastModified(String path) { S3Object s3Object = s3.getObject(bucket, path); if (s3Object == null) { return -1L; } return s3Object.getObjectMetadata().getLastModified().getTime(); } @Override public long length(String path) { S3Object s3Object = s3.getObject(bucket, path); if (s3Object == null) { return -1L; } return s3Object.getObjectMetadata().getContentLength(); } @Override public boolean rename(String path, String newPath) throws ResourceIOException { try { CopyObjectRequest copyObjRequest = new CopyObjectRequest(bucket, path, bucket, newPath); s3.copyObject(copyObjRequest); s3.deleteObject(new DeleteObjectRequest(bucket, path)); } catch (Exception e) { LogKit.error(e.getMessage(), e); return false; } return true; } @Override public void shutDown() { s3.shutdown(); } @Override public String getIdentity() { return S3RepositoryFactory.IDENTITY; } }