mirror of https://github.com/usbharu/Hideout.git
feat: S3にアップロードできるように
This commit is contained in:
parent
97cf5eac65
commit
e4ac377404
|
@ -3,13 +3,17 @@ package dev.usbharu.hideout.config
|
||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials
|
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.S3Client
|
||||||
|
import java.net.URI
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
class AwsConfig {
|
class AwsConfig {
|
||||||
@Bean
|
@Bean
|
||||||
fun s3(awsConfig: StorageConfig): S3Client {
|
fun s3(awsConfig: StorageConfig): S3Client {
|
||||||
return S3Client.builder()
|
return S3Client.builder()
|
||||||
|
.endpointOverride(URI.create(awsConfig.endpoint))
|
||||||
|
.region(Region.of(awsConfig.region))
|
||||||
.credentialsProvider { AwsBasicCredentials.create(awsConfig.accessKey, awsConfig.secretKey) }
|
.credentialsProvider { AwsBasicCredentials.create(awsConfig.accessKey, awsConfig.secretKey) }
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import dev.usbharu.hideout.controller.mastodon.generated.MediaApi
|
||||||
import dev.usbharu.hideout.domain.mastodon.model.generated.MediaAttachment
|
import dev.usbharu.hideout.domain.mastodon.model.generated.MediaAttachment
|
||||||
import dev.usbharu.hideout.domain.model.hideout.form.Media
|
import dev.usbharu.hideout.domain.model.hideout.form.Media
|
||||||
import dev.usbharu.hideout.service.api.mastodon.MediaApiService
|
import dev.usbharu.hideout.service.api.mastodon.MediaApiService
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.springframework.http.ResponseEntity
|
import org.springframework.http.ResponseEntity
|
||||||
import org.springframework.stereotype.Controller
|
import org.springframework.stereotype.Controller
|
||||||
import org.springframework.web.multipart.MultipartFile
|
import org.springframework.web.multipart.MultipartFile
|
||||||
|
@ -15,8 +16,8 @@ class MastodonMediaApiController(private val mediaApiService: MediaApiService) :
|
||||||
thumbnail: MultipartFile?,
|
thumbnail: MultipartFile?,
|
||||||
description: String?,
|
description: String?,
|
||||||
focus: String?
|
focus: String?
|
||||||
): ResponseEntity<MediaAttachment> {
|
): ResponseEntity<MediaAttachment> = runBlocking {
|
||||||
return ResponseEntity.ok(
|
ResponseEntity.ok(
|
||||||
mediaApiService.postMedia(
|
mediaApiService.postMedia(
|
||||||
Media(
|
Media(
|
||||||
file,
|
file,
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
package dev.usbharu.hideout.domain.model.hideout.dto
|
||||||
|
|
||||||
|
data class ProcessedFile(
|
||||||
|
val byteArray: ByteArray,
|
||||||
|
val extension: String
|
||||||
|
)
|
|
@ -0,0 +1,6 @@
|
||||||
|
package dev.usbharu.hideout.domain.model.hideout.dto
|
||||||
|
|
||||||
|
data class ProcessedMedia(
|
||||||
|
val file: ProcessedFile,
|
||||||
|
val thumbnail: ProcessedFile?
|
||||||
|
)
|
|
@ -2,13 +2,21 @@ package dev.usbharu.hideout.service.api.mastodon
|
||||||
|
|
||||||
import dev.usbharu.hideout.domain.mastodon.model.generated.MediaAttachment
|
import dev.usbharu.hideout.domain.mastodon.model.generated.MediaAttachment
|
||||||
import dev.usbharu.hideout.domain.model.hideout.form.Media
|
import dev.usbharu.hideout.domain.model.hideout.form.Media
|
||||||
|
import dev.usbharu.hideout.service.core.Transaction
|
||||||
import dev.usbharu.hideout.service.media.MediaService
|
import dev.usbharu.hideout.service.media.MediaService
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class MediaApiServiceImpl(private val mediaService: MediaService, private val transaction: Transaction) :
|
||||||
|
MediaApiService {
|
||||||
|
|
||||||
class MediaApiServiceImpl(private val mediaService: MediaService) : MediaApiService {
|
|
||||||
override suspend fun postMedia(media: Media): MediaAttachment {
|
override suspend fun postMedia(media: Media): MediaAttachment {
|
||||||
val uploadLocalMedia = mediaService.uploadLocalMedia(media)
|
return transaction.transaction {
|
||||||
return MediaAttachment(
|
|
||||||
|
|
||||||
)
|
val uploadLocalMedia = mediaService.uploadLocalMedia(media)
|
||||||
|
return@transaction MediaAttachment(
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,8 @@ class MediaServiceImpl(
|
||||||
private val mediaProcessService: MediaProcessService
|
private val mediaProcessService: MediaProcessService
|
||||||
) : MediaService {
|
) : MediaService {
|
||||||
override suspend fun uploadLocalMedia(media: Media): EntityMedia {
|
override suspend fun uploadLocalMedia(media: Media): EntityMedia {
|
||||||
|
logger.info("Media upload. filename:${media.file.name} size:${media.file.size} contentType:${media.file.contentType}")
|
||||||
|
|
||||||
if (media.file.size == 0L) {
|
if (media.file.size == 0L) {
|
||||||
throw MediaFileSizeIsZeroException("Media file size is zero.")
|
throw MediaFileSizeIsZeroException("Media file size is zero.")
|
||||||
}
|
}
|
||||||
|
@ -37,13 +39,19 @@ class MediaServiceImpl(
|
||||||
throw UnsupportedMediaException("FileType: $fileType is not supported.")
|
throw UnsupportedMediaException("FileType: $fileType is not supported.")
|
||||||
}
|
}
|
||||||
|
|
||||||
val process = mediaProcessService.process(fileType, media.file.bytes, media.thumbnail?.bytes)
|
val process = mediaProcessService.process(
|
||||||
|
fileType,
|
||||||
|
media.file.contentType.orEmpty(),
|
||||||
|
media.file.name,
|
||||||
|
media.file.bytes,
|
||||||
|
media.thumbnail?.bytes
|
||||||
|
)
|
||||||
|
|
||||||
val dataMediaSave = MediaSave(
|
val dataMediaSave = MediaSave(
|
||||||
UUID.randomUUID().toString(),
|
"${UUID.randomUUID()}.${process.file.extension}",
|
||||||
"",
|
"",
|
||||||
process.first,
|
process.file.byteArray,
|
||||||
process.second
|
process.thumbnail?.byteArray
|
||||||
)
|
)
|
||||||
val save = try {
|
val save = try {
|
||||||
mediaDataStore.save(dataMediaSave)
|
mediaDataStore.save(dataMediaSave)
|
||||||
|
|
|
@ -33,7 +33,10 @@ class S3MediaDataStore(private val s3Client: S3Client, private val storageConfig
|
||||||
awaitAll(
|
awaitAll(
|
||||||
async {
|
async {
|
||||||
if (dataMediaSave.thumbnailInputStream != null) {
|
if (dataMediaSave.thumbnailInputStream != null) {
|
||||||
s3Client.putObject(fileUploadRequest, RequestBody.fromBytes(dataMediaSave.thumbnailInputStream))
|
s3Client.putObject(
|
||||||
|
thumbnailUploadRequest,
|
||||||
|
RequestBody.fromBytes(dataMediaSave.thumbnailInputStream)
|
||||||
|
)
|
||||||
"thumbnail" to s3Client.utilities()
|
"thumbnail" to s3Client.utilities()
|
||||||
.getUrl(GetUrlRequest.builder().bucket(storageConfig.bucket).key(thumbnailKey).build())
|
.getUrl(GetUrlRequest.builder().bucket(storageConfig.bucket).key(thumbnailKey).build())
|
||||||
} else {
|
} else {
|
||||||
|
@ -41,7 +44,7 @@ class S3MediaDataStore(private val s3Client: S3Client, private val storageConfig
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async {
|
async {
|
||||||
s3Client.putObject(thumbnailUploadRequest, RequestBody.fromBytes(dataMediaSave.fileInputStream))
|
s3Client.putObject(fileUploadRequest, RequestBody.fromBytes(dataMediaSave.fileInputStream))
|
||||||
"file" to s3Client.utilities()
|
"file" to s3Client.utilities()
|
||||||
.getUrl(GetUrlRequest.builder().bucket(storageConfig.bucket).key(dataMediaSave.name).build())
|
.getUrl(GetUrlRequest.builder().bucket(storageConfig.bucket).key(dataMediaSave.name).build())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package dev.usbharu.hideout.service.media
|
package dev.usbharu.hideout.service.media
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.dto.ProcessedFile
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
interface ThumbnailGenerateService {
|
interface ThumbnailGenerateService {
|
||||||
fun generate(bufferedImage: InputStream, width: Int, height: Int): ByteArray
|
fun generate(bufferedImage: InputStream, width: Int, height: Int): ProcessedFile?
|
||||||
fun generate(outputStream: ByteArray, width: Int, height: Int): ByteArray
|
fun generate(outputStream: ByteArray, width: Int, height: Int): ProcessedFile?
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,27 @@
|
||||||
package dev.usbharu.hideout.service.media
|
package dev.usbharu.hideout.service.media
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.dto.ProcessedFile
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.awt.image.BufferedImage
|
import java.awt.image.BufferedImage
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
|
||||||
import javax.imageio.ImageIO
|
import javax.imageio.ImageIO
|
||||||
import javax.imageio.stream.MemoryCacheImageOutputStream
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class ThumbnailGenerateServiceImpl : ThumbnailGenerateService {
|
class ThumbnailGenerateServiceImpl : ThumbnailGenerateService {
|
||||||
override fun generate(bufferedImage: InputStream, width: Int, height: Int): ByteArrayOutputStream {
|
override fun generate(bufferedImage: InputStream, width: Int, height: Int): ProcessedFile? {
|
||||||
val image = ImageIO.read(bufferedImage)
|
val image = ImageIO.read(bufferedImage)
|
||||||
return internalGenerate(image)
|
return internalGenerate(image)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun generate(outputStream: OutputStream, width: Int, height: Int): ByteArrayOutputStream {
|
override fun generate(outputStream: ByteArray, width: Int, height: Int): ProcessedFile? {
|
||||||
val image = ImageIO.read(MemoryCacheImageOutputStream(outputStream))
|
val image = ImageIO.read(outputStream.inputStream())
|
||||||
return internalGenerate(image)
|
return internalGenerate(image)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun internalGenerate(image: BufferedImage): ByteArrayOutputStream {
|
private fun internalGenerate(image: BufferedImage): ProcessedFile {
|
||||||
val byteArrayOutputStream = ByteArrayOutputStream()
|
val byteArrayOutputStream = ByteArrayOutputStream()
|
||||||
ImageIO.write(image, "webp", byteArrayOutputStream)
|
ImageIO.write(image, "jpeg", byteArrayOutputStream)
|
||||||
return byteArrayOutputStream
|
return ProcessedFile(byteArrayOutputStream.toByteArray(), "jpg")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package dev.usbharu.hideout.service.media.converter
|
package dev.usbharu.hideout.service.media.converter
|
||||||
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.FileType
|
import dev.usbharu.hideout.domain.model.hideout.dto.FileType
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.dto.ProcessedFile
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
interface MediaConverter {
|
interface MediaConverter {
|
||||||
fun isSupport(fileType: FileType): Boolean
|
fun isSupport(fileType: FileType): Boolean
|
||||||
fun convert(inputStream: InputStream): ByteArray
|
fun convert(inputStream: InputStream): ProcessedFile
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
package dev.usbharu.hideout.service.media.converter
|
package dev.usbharu.hideout.service.media.converter
|
||||||
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.FileType
|
import dev.usbharu.hideout.domain.model.hideout.dto.FileType
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.dto.ProcessedFile
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
interface MediaConverterRoot {
|
interface MediaConverterRoot {
|
||||||
suspend fun convert(fileType: FileType, inputStream: InputStream): ByteArray
|
suspend fun convert(
|
||||||
|
fileType: FileType,
|
||||||
|
contentType: String,
|
||||||
|
filename: String,
|
||||||
|
inputStream: InputStream
|
||||||
|
): ProcessedFile
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package dev.usbharu.hideout.service.media.converter
|
package dev.usbharu.hideout.service.media.converter
|
||||||
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.FileType
|
import dev.usbharu.hideout.domain.model.hideout.dto.FileType
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.dto.ProcessedFile
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
@ -8,11 +9,24 @@ import java.io.InputStream
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class MediaConverterRootImpl(private val converters: List<MediaConverter>) : MediaConverterRoot {
|
class MediaConverterRootImpl(private val converters: List<MediaConverter>) : MediaConverterRoot {
|
||||||
override suspend fun convert(fileType: FileType, inputStream: InputStream): ByteArray {
|
override suspend fun convert(
|
||||||
return converters.find {
|
fileType: FileType,
|
||||||
|
contentType: String,
|
||||||
|
filename: String,
|
||||||
|
inputStream: InputStream
|
||||||
|
): ProcessedFile {
|
||||||
|
val convert = converters.find {
|
||||||
it.isSupport(fileType)
|
it.isSupport(fileType)
|
||||||
}?.convert(inputStream) ?: withContext(Dispatchers.IO) {
|
}?.convert(inputStream)
|
||||||
inputStream.readAllBytes()
|
if (convert != null) {
|
||||||
|
return convert
|
||||||
|
}
|
||||||
|
return withContext(Dispatchers.IO) {
|
||||||
|
if (filename.contains('.')) {
|
||||||
|
ProcessedFile(inputStream.readAllBytes(), filename.substringAfterLast("."))
|
||||||
|
} else {
|
||||||
|
ProcessedFile(inputStream.readAllBytes(), contentType.substringAfterLast("/"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
package dev.usbharu.hideout.service.media.converter
|
package dev.usbharu.hideout.service.media.converter
|
||||||
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.FileType
|
import dev.usbharu.hideout.domain.model.hideout.dto.FileType
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.dto.ProcessedMedia
|
||||||
|
|
||||||
interface MediaProcessService {
|
interface MediaProcessService {
|
||||||
suspend fun process(
|
suspend fun process(
|
||||||
fileType: FileType,
|
fileType: FileType,
|
||||||
|
contentType: String,
|
||||||
|
fileName: String,
|
||||||
file: ByteArray,
|
file: ByteArray,
|
||||||
thumbnail: ByteArray?
|
thumbnail: ByteArray?
|
||||||
): Pair<ByteArray, ByteArray>
|
): ProcessedMedia
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package dev.usbharu.hideout.service.media.converter
|
package dev.usbharu.hideout.service.media.converter
|
||||||
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.FileType
|
import dev.usbharu.hideout.domain.model.hideout.dto.FileType
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.dto.ProcessedMedia
|
||||||
import dev.usbharu.hideout.exception.media.MediaConvertException
|
import dev.usbharu.hideout.exception.media.MediaConvertException
|
||||||
import dev.usbharu.hideout.service.media.ThumbnailGenerateService
|
import dev.usbharu.hideout.service.media.ThumbnailGenerateService
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
@ -13,26 +14,30 @@ class MediaProcessServiceImpl(
|
||||||
) : MediaProcessService {
|
) : MediaProcessService {
|
||||||
override suspend fun process(
|
override suspend fun process(
|
||||||
fileType: FileType,
|
fileType: FileType,
|
||||||
|
contentType: String,
|
||||||
|
filename: String,
|
||||||
file: ByteArray,
|
file: ByteArray,
|
||||||
thumbnail: ByteArray?
|
thumbnail: ByteArray?
|
||||||
): Pair<ByteArray, ByteArray> {
|
): ProcessedMedia {
|
||||||
|
|
||||||
val fileInputStream = try {
|
val fileInputStream = try {
|
||||||
mediaConverterRoot.convert(fileType, file.inputStream().buffered())
|
mediaConverterRoot.convert(fileType, contentType, filename, file.inputStream().buffered())
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger.warn("Failed convert media.", e)
|
logger.warn("Failed convert media.", e)
|
||||||
throw MediaConvertException("Failed convert media.", e)
|
throw MediaConvertException("Failed convert media.", e)
|
||||||
}
|
}
|
||||||
val thumbnailInputStream = try {
|
val thumbnailInputStream = try {
|
||||||
thumbnail?.let { mediaConverterRoot.convert(fileType, it.inputStream().buffered()) }
|
thumbnail?.let { mediaConverterRoot.convert(fileType, contentType, filename, it.inputStream().buffered()) }
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger.warn("Failed convert thumbnail media.", e)
|
logger.warn("Failed convert thumbnail media.", e)
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
return fileInputStream to thumbnailGenerateService.generate(
|
return ProcessedMedia(
|
||||||
thumbnailInputStream ?: fileInputStream,
|
fileInputStream, thumbnailGenerateService.generate(
|
||||||
2048,
|
thumbnailInputStream?.byteArray ?: file,
|
||||||
2048
|
2048,
|
||||||
|
2048
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,14 +7,7 @@ hideout:
|
||||||
key-id: a
|
key-id: a
|
||||||
private-key: "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC7VJTUt9Us8cKjMzEfYyjiWA4R4/M2bS1GB4t7NXp98C3SC6dVMvDuictGeurT8jNbvJZHtCSuYEvuNMoSfm76oqFvAp8Gy0iz5sxjZmSnXyCdPEovGhLa0VzMaQ8s+CLOyS56YyCFGeJZqgtzJ6GR3eqoYSW9b9UMvkBpZODSctWSNGj3P7jRFDO5VoTwCQAWbFnOjDfH5Ulgp2PKSQnSJP3AJLQNFNe7br1XbrhV//eO+t51mIpGSDCUv3E0DDFcWDTH9cXDTTlRZVEiR2BwpZOOkE/Z0/BVnhZYL71oZV34bKfWjQIt6V/isSMahdsAASACp4ZTGtwiVuNd9tybAgMBAAECggEBAKTmjaS6tkK8BlPXClTQ2vpz/N6uxDeS35mXpqasqskVlaAidgg/sWqpjXDbXr93otIMLlWsM+X0CqMDgSXKejLS2jx4GDjI1ZTXg++0AMJ8sJ74pWzVDOfmCEQ/7wXs3+cbnXhKriO8Z036q92Qc1+N87SI38nkGa0ABH9CN83HmQqt4fB7UdHzuIRe/me2PGhIq5ZBzj6h3BpoPGzEP+x3l9YmK8t/1cN0pqI+dQwYdgfGjackLu/2qH80MCF7IyQaseZUOJyKrCLtSD/Iixv/hzDEUPfOCjFDgTpzf3cwta8+oE4wHCo1iI1/4TlPkwmXx4qSXtmw4aQPz7IDQvECgYEA8KNThCO2gsC2I9PQDM/8Cw0O983WCDY+oi+7JPiNAJwv5DYBqEZB1QYdj06YD16XlC/HAZMsMku1na2TN0driwenQQWzoev3g2S7gRDoS/FCJSI3jJ+kjgtaA7Qmzlgk1TxODN+G1H91HW7t0l7VnL27IWyYo2qRRK3jzxqUiPUCgYEAx0oQs2reBQGMVZnApD1jeq7n4MvNLcPvt8b/eU9iUv6Y4Mj0Suo/AU8lYZXm8ubbqAlwz2VSVunD2tOplHyMUrtCtObAfVDUAhCndKaA9gApgfb3xw1IKbuQ1u4IF1FJl3VtumfQn//LiH1B3rXhcdyo3/vIttEk48RakUKClU8CgYEAzV7W3COOlDDcQd935DdtKBFRAPRPAlspQUnzMi5eSHMD/ISLDY5IiQHbIH83D4bvXq0X7qQoSBSNP7Dvv3HYuqMhf0DaegrlBuJllFVVq9qPVRnKxt1Il2HgxOBvbhOT+9in1BzA+YJ99UzC85O0Qz06A+CmtHEy4aZ2kj5hHjECgYEAmNS4+A8Fkss8Js1RieK2LniBxMgmYml3pfVLKGnzmng7H2+cwPLhPIzIuwytXywh2bzbsYEfYx3EoEVgMEpPhoarQnYPukrJO4gwE2o5Te6T5mJSZGlQJQj9q4ZB2Dfzet6INsK0oG8XVGXSpQvQh3RUYekCZQkBBFcpqWpbIEsCgYAnM3DQf3FJoSnXaMhrVBIovic5l0xFkEHskAjFTevO86Fsz1C2aSeRKSqGFoOQ0tmJzBEs1R6KqnHInicDTQrKhArgLXX4v3CddjfTRJkFWDbE/CkvKZNOrcf1nhaGCPspRJj2KUkj1Fhl9Cncdn/RsYEONbwQSjIfMPkvxF+8HQ=="
|
private-key: "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC7VJTUt9Us8cKjMzEfYyjiWA4R4/M2bS1GB4t7NXp98C3SC6dVMvDuictGeurT8jNbvJZHtCSuYEvuNMoSfm76oqFvAp8Gy0iz5sxjZmSnXyCdPEovGhLa0VzMaQ8s+CLOyS56YyCFGeJZqgtzJ6GR3eqoYSW9b9UMvkBpZODSctWSNGj3P7jRFDO5VoTwCQAWbFnOjDfH5Ulgp2PKSQnSJP3AJLQNFNe7br1XbrhV//eO+t51mIpGSDCUv3E0DDFcWDTH9cXDTTlRZVEiR2BwpZOOkE/Z0/BVnhZYL71oZV34bKfWjQIt6V/isSMahdsAASACp4ZTGtwiVuNd9tybAgMBAAECggEBAKTmjaS6tkK8BlPXClTQ2vpz/N6uxDeS35mXpqasqskVlaAidgg/sWqpjXDbXr93otIMLlWsM+X0CqMDgSXKejLS2jx4GDjI1ZTXg++0AMJ8sJ74pWzVDOfmCEQ/7wXs3+cbnXhKriO8Z036q92Qc1+N87SI38nkGa0ABH9CN83HmQqt4fB7UdHzuIRe/me2PGhIq5ZBzj6h3BpoPGzEP+x3l9YmK8t/1cN0pqI+dQwYdgfGjackLu/2qH80MCF7IyQaseZUOJyKrCLtSD/Iixv/hzDEUPfOCjFDgTpzf3cwta8+oE4wHCo1iI1/4TlPkwmXx4qSXtmw4aQPz7IDQvECgYEA8KNThCO2gsC2I9PQDM/8Cw0O983WCDY+oi+7JPiNAJwv5DYBqEZB1QYdj06YD16XlC/HAZMsMku1na2TN0driwenQQWzoev3g2S7gRDoS/FCJSI3jJ+kjgtaA7Qmzlgk1TxODN+G1H91HW7t0l7VnL27IWyYo2qRRK3jzxqUiPUCgYEAx0oQs2reBQGMVZnApD1jeq7n4MvNLcPvt8b/eU9iUv6Y4Mj0Suo/AU8lYZXm8ubbqAlwz2VSVunD2tOplHyMUrtCtObAfVDUAhCndKaA9gApgfb3xw1IKbuQ1u4IF1FJl3VtumfQn//LiH1B3rXhcdyo3/vIttEk48RakUKClU8CgYEAzV7W3COOlDDcQd935DdtKBFRAPRPAlspQUnzMi5eSHMD/ISLDY5IiQHbIH83D4bvXq0X7qQoSBSNP7Dvv3HYuqMhf0DaegrlBuJllFVVq9qPVRnKxt1Il2HgxOBvbhOT+9in1BzA+YJ99UzC85O0Qz06A+CmtHEy4aZ2kj5hHjECgYEAmNS4+A8Fkss8Js1RieK2LniBxMgmYml3pfVLKGnzmng7H2+cwPLhPIzIuwytXywh2bzbsYEfYx3EoEVgMEpPhoarQnYPukrJO4gwE2o5Te6T5mJSZGlQJQj9q4ZB2Dfzet6INsK0oG8XVGXSpQvQh3RUYekCZQkBBFcpqWpbIEsCgYAnM3DQf3FJoSnXaMhrVBIovic5l0xFkEHskAjFTevO86Fsz1C2aSeRKSqGFoOQ0tmJzBEs1R6KqnHInicDTQrKhArgLXX4v3CddjfTRJkFWDbE/CkvKZNOrcf1nhaGCPspRJj2KUkj1Fhl9Cncdn/RsYEONbwQSjIfMPkvxF+8HQ=="
|
||||||
public-key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u+qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyehkd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdgcKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbcmwIDAQAB"
|
public-key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u+qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyehkd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdgcKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbcmwIDAQAB"
|
||||||
storage:
|
|
||||||
use-s3: true
|
|
||||||
endpoint: ""
|
|
||||||
public-url: ""
|
|
||||||
bucket: ""
|
|
||||||
region: ""
|
|
||||||
access-key: ""
|
|
||||||
secret-key: ""
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue