diff --git a/src/main/java/run/halo/s3os/S3ExceptionHandler.java b/src/main/java/run/halo/s3os/S3ExceptionHandler.java new file mode 100644 index 0000000..4c0b795 --- /dev/null +++ b/src/main/java/run/halo/s3os/S3ExceptionHandler.java @@ -0,0 +1,42 @@ +package run.halo.s3os; + +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.server.ServerWebInputException; +import software.amazon.awssdk.core.exception.SdkException; +import software.amazon.awssdk.services.s3.model.S3Exception; + +@Slf4j +@UtilityClass +public class S3ExceptionHandler { + + /** + * Map user configuration caused S3 exception to ServerWebInputException + * @param throwable Exception + * @return ServerWebInputException or original exception + */ + public static Throwable map(Throwable throwable) { + if (throwable instanceof S3Exception s3e) { + log.error("S3Exception occurred", s3e); + return new ServerWebInputException(String.format( + "The object storage service returned an error status code %d. Please check the storage " + + "policy configuration and make sure your account and service are working properly.", + s3e.statusCode())); + } + if (throwable instanceof SdkException sdke && sdke.getMessage() != null + && sdke.getMessage().contains("UnknownHostException")) { + log.error("UnknownHostException occurred", sdke); + return new ServerWebInputException( + "Received an UnknownHostException, please check if the endpoint is entered correctly, " + + "especially for any spaces before or after the endpoint."); + } + if (throwable instanceof SdkException sdke && sdke.getMessage() != null + && sdke.getMessage().contains("Connect timed out")) { + log.error("ConnectTimeoutException occurred", sdke); + return new ServerWebInputException( + "Received a ConnectTimeoutException, please check if the endpoint is entered correctly, " + + "and make sure your object storage service is working properly."); + } + return throwable; + } +} \ No newline at end of file diff --git a/src/main/java/run/halo/s3os/S3LinkServiceImpl.java b/src/main/java/run/halo/s3os/S3LinkServiceImpl.java index 1fc6e33..7b7d7b8 100644 --- a/src/main/java/run/halo/s3os/S3LinkServiceImpl.java +++ b/src/main/java/run/halo/s3os/S3LinkServiceImpl.java @@ -1,5 +1,13 @@ package run.halo.s3os; +import static run.halo.s3os.S3OsAttachmentHandler.OBJECT_KEY; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -9,38 +17,18 @@ import org.springframework.security.core.context.ReactiveSecurityContextHolder; import org.springframework.security.core.context.SecurityContext; import org.springframework.stereotype.Service; import org.springframework.web.server.ResponseStatusException; -import org.springframework.web.util.UriUtils; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; import run.halo.app.core.extension.attachment.Attachment; -import run.halo.app.core.extension.attachment.Constant; import run.halo.app.core.extension.attachment.Policy; import run.halo.app.extension.ConfigMap; -import run.halo.app.extension.Metadata; import run.halo.app.extension.ReactiveExtensionClient; -import run.halo.app.infra.utils.JsonUtils; -import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; -import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3Client; -import software.amazon.awssdk.services.s3.S3Configuration; import software.amazon.awssdk.services.s3.model.HeadObjectRequest; import software.amazon.awssdk.services.s3.model.ListObjectsV2Request; import software.amazon.awssdk.services.s3.model.S3Object; -import java.net.URI; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; -import java.util.stream.Collectors; - -import static run.halo.s3os.S3OsAttachmentHandler.OBJECT_KEY; - @Service @RequiredArgsConstructor @@ -103,7 +91,8 @@ public class S3LinkServiceImpl implements S3LinkService { listObjectsV2Response.nextContinuationToken(), listObjectsV2Response.isTruncated())); }); - }); + }) + .onErrorMap(S3ExceptionHandler::map); } @Override @@ -155,7 +144,8 @@ public class S3LinkServiceImpl implements S3LinkService { .getKey() : null, tokenState.currToken, limitedObjects.size() == pageSize); }); - }); + }) + .onErrorMap(S3ExceptionHandler::map); } record TokenState(String currToken, String nextToken) { @@ -200,6 +190,7 @@ public class S3LinkServiceImpl implements S3LinkService { .flatMap(client::create) .thenReturn(new LinkResult.LinkResultItem(objectKey, true, null)); })) + .onErrorMap(S3ExceptionHandler::map) .onErrorResume(throwable -> Mono.just(new LinkResult.LinkResultItem(objectKey, false, throwable.getMessage()))); } diff --git a/src/main/java/run/halo/s3os/S3OsAttachmentHandler.java b/src/main/java/run/halo/s3os/S3OsAttachmentHandler.java index 9be34e4..5c5e321 100644 --- a/src/main/java/run/halo/s3os/S3OsAttachmentHandler.java +++ b/src/main/java/run/halo/s3os/S3OsAttachmentHandler.java @@ -82,7 +82,8 @@ public class S3OsAttachmentHandler implements AttachmentHandler { final var properties = getProperties(context.configMap()); return upload(context, properties) .subscribeOn(Schedulers.boundedElastic()) - .map(objectDetail -> this.buildAttachment(properties, objectDetail)); + .map(objectDetail -> this.buildAttachment(properties, objectDetail)) + .onErrorMap(S3ExceptionHandler::map); }); } @@ -116,6 +117,7 @@ public class S3OsAttachmentHandler implements AttachmentHandler { }) .thenReturn(context); }) + .onErrorMap(S3ExceptionHandler::map) .map(DeleteContext::attachment); } @@ -152,7 +154,8 @@ public class S3OsAttachmentHandler implements AttachmentHandler { } }, SdkPresigner::close) - .subscribeOn(Schedulers.boundedElastic()); + .subscribeOn(Schedulers.boundedElastic()) + .onErrorMap(S3ExceptionHandler::map); } @Override diff --git a/src/main/java/run/halo/s3os/S3UnlinkServiceImpl.java b/src/main/java/run/halo/s3os/S3UnlinkServiceImpl.java index 56fbe23..6024a64 100644 --- a/src/main/java/run/halo/s3os/S3UnlinkServiceImpl.java +++ b/src/main/java/run/halo/s3os/S3UnlinkServiceImpl.java @@ -1,6 +1,5 @@ package run.halo.s3os; -import java.time.Instant; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service;