/// import { GetObjectCommand, ListObjectsV2Command, S3Client, } from "@aws-sdk/client-s3"; import { AwsContext, s3MoveObject } from "./context.ts"; import { getLogger } from "../logger.ts"; import { getConfig } from "../config.ts"; import { Mail } from "../mail.ts"; export class AwsMailRetriever { readonly liveMailPrefix = "mail/live/"; readonly archiveMailPrefix = "mail/archive/"; readonly mailBucket = getConfig().getValue("awsMailBucket"); private readonly s3Client; constructor( aws: AwsContext, private readonly callback: (mail: Mail) => Promise, ) { const { region, credentials } = aws; this.s3Client = new S3Client({ region, credentials }); } async listLiveMails(): Promise { const listCommand = new ListObjectsV2Command({ Bucket: this.mailBucket, Prefix: this.liveMailPrefix, }); const res = await this.s3Client.send(listCommand); if (res.Contents == null) { getLogger().warn("Listing live mails in S3 returns null Content."); return []; } const result: string[] = []; for (const object of res.Contents) { if (object.Key != null) { // TODO: check prefix consistence here. result.push(object.Key.slice(this.liveMailPrefix.length)); } else { getLogger().warn( "Listing live mails in S3 returns an object with no Key.", ); } } return result; } async deliverS3MailObject(messageId: string) { const mailPath = `${this.liveMailPrefix}${messageId}`; const command = new GetObjectCommand({ Bucket: this.mailBucket, Key: mailPath, }); const res = await this.s3Client.send(command); if (res.Body == null) { // TODO: Better error. throw new Error(); } const rawMail = await res.Body.transformToString(); const mail = new Mail(rawMail); mail.awsMessageId = messageId; await this.callback(mail); // TODO: Continue here. await s3MoveObject( this.s3Client, this.mailBucket, mailPath, `${this.archiveMailPrefix}${ mail.simpleGetDateString("invalid-date") }/${messageId}`, ); } async recycleLiveMails() { const mails = await this.listLiveMails(); for (const messageId of mails) { await this.deliverS3MailObject(messageId); } } }