app/services/editions/publishing/EditionsAppPublicationTarget.scala (74 lines of code) (raw):

package services.editions.publishing import com.amazonaws.services.s3.AmazonS3 import com.amazonaws.services.s3.model.{ObjectMetadata, PutObjectRequest} import com.amazonaws.util.StringInputStream import model.editions.EditionsIssue import play.api.libs.json.{Json, Writes} import PublishedIssueFormatters._ import com.typesafe.scalalogging.LazyLogging import model.editions.PublishAction.PublishAction import org.apache.commons.lang3.builder.{ ReflectionToStringBuilder, ToStringStyle } import java.nio.charset.StandardCharsets object EditionsAppPublicationTarget extends LazyLogging { val baseMetadata: ObjectMetadata = { val metadata = new ObjectMetadata() metadata.setContentType("application/json") metadata } def createPutObjectRequest[T: Writes]( bucketName: String, key: String, issue: T ): PutObjectRequest = { val issueJson = Json.stringify(Json.toJson(issue)) // Why do we do this? Well, because if we are sending a streaming PutObjectRequest then S3 requires the length of the stream // If it's not explicitly set in ObjectMetadata, then the AWS SDK will consume the entire string into memory just to measure the length. // This is pointless as we already _have_ it in memory here (and it creates un-necessary log noise). So we need to put the BYTE length into the header. // Note that the byte length of a UTF-8 string can easily be greater than the character length, which is why we need to use getBytes here. val metadata = baseMetadata metadata.setContentLength(issueJson.getBytes(StandardCharsets.UTF_8).length) new PutObjectRequest( bucketName, key, new StringInputStream(issueJson), metadata ) } } class EditionsAppPublicationTarget(s3Client: AmazonS3, bucketName: String) extends PublicationTarget with LazyLogging { override def putIssue( issue: EditionsIssue, version: String, action: PublishAction ): Either[String, Unit] = { val outputKey = createKey(issue, version) val publishableIssue = issue.toPublishableIssue(version, action) Right(putIssueJson(publishableIssue, outputKey)) } override def putIssueJson[T: Writes](content: T, key: String): Unit = { val request = EditionsAppPublicationTarget.createPutObjectRequest( bucketName, key, content ) logger.info( ReflectionToStringBuilder.toString( request, ToStringStyle.MULTI_LINE_STYLE ) ) s3Client.putObject(request) } def putEditionsList(rawJson: String): Unit = { val metadata = EditionsAppPublicationTarget.baseMetadata metadata.setContentLength(rawJson.getBytes(StandardCharsets.UTF_8).length) val request = new PutObjectRequest( bucketName, "editionsList", new StringInputStream(rawJson), metadata ) s3Client.putObject(request) } }