Put a list of objects in a bucket
One script reply has been approved by the moderators Verified

Uploads a list of files encoded in base64 to S3.

Detects file type/extension using base64 header (e.g. "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAA..."). The output of File Input component can be used as parameter for this function.

Created by vidz657 1085 days ago Picked 22 times
Submitted by vidz657 Deno
Verified 310 days ago
1
import { S3Client } from "https://deno.land/x/[email protected]/mod.ts";
2
import { format } from "https://deno.land/[email protected]/datetime/mod.ts";
3
import { mime } from "https://deno.land/x/[email protected]/mod.ts";
4

5
const MESSAGES_I9 = {
6
  en: {
7
    error_mimetype: "File type could not be identified",
8
    error_file_upload: "Error uploading file (S3)",
9
  },
10
  pt_br: {
11
    error_mimetype: "Tipo do arquivo não pôde ser identificado",
12
    error_file_upload: "Erro ao enviar arquivo (S3)",
13
  },
14
};
15
const MESSAGES = MESSAGES_I9.en;
16

17
/****
18
 * Returns the mimetype and extension of a base64 encoded file
19
 * @param encoded Base64 encoded file
20
 * @returns Object with mimetype and extension
21
 */
22
function base64MimeType(encoded: string) {
23
  let result = null;
24

25
  if (typeof encoded !== "string") {
26
    return result;
27
  }
28

29
  const match = encoded.match(/data:([a-zA-Z0-9]+\/[a-zA-Z0-9-.+]+).*,.*/);
30
  if (match && match.length) {
31
    result = {
32
      mimetype: match[1],
33
      extension: mime.getExtension(match[1]),
34
    };
35
  }
36

37
  return result;
38
}
39

40
/****
41
 * Uploads a list of files to S3
42
 * @param s3 S3 resource
43
 * @param files Array of base64 encoded files
44
 * @returns Object with error_count and array of results (files URLs or error messages)
45
 *
46
 * Detects file type/extension using base64 header (e.g. "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAA...").
47
 * The output of File Input component can be used as parameter for this function.
48
 */
49
type S3 = {
50
  endPoint: string;
51
  port: number;
52
  useSSL: boolean;
53
  pathStyle: boolean;
54
  bucket: string;
55
  accessKey: string;
56
  secretKey: string;
57
  region: string;
58
};
59
export async function main(s3: S3, files: string[]) {
60
  if (files.length <= 0) {
61
    return;
62
  }
63

64
  const s3client = new S3Client(s3);
65

66
  const out: any[] = [];
67
  let error_count = 0;
68

69
  await Promise.all(
70
    files.map(async (file: string) => {
71
      try {
72
        const mime_data = base64MimeType(file)!;
73
        if (mime_data) {
74
          const file_name =
75
            format(new Date(), "yyyy-MM-dd-HH-mm-ss") +
76
            "-" +
77
            Math.random().toString(36).substring(2, 8) +
78
            "." +
79
            mime_data.extension;
80
          const base64Data = file.replace(/^data:\w+\/\w+;base64,/, "");
81
          const bytes = Uint8Array.from(atob(base64Data), (c) =>
82
            c.charCodeAt(0),
83
          );
84

85
          await s3client.putObject(file_name, bytes, {
86
            metadata: {
87
              "Content-Type": mime_data.mimetype,
88
            },
89
          });
90

91
          const url = `https://${s3["endPoint"]}/${s3["bucket"]}/${file_name}`;
92
          out.push({
93
            success: true,
94
            url,
95
          });
96
        } else {
97
          out.push({
98
            success: false,
99
            message: MESSAGES.error_mimetype,
100
          });
101
          error_count++;
102
        }
103
      } catch (error) {
104
        out.push({
105
          success: false,
106
          message: `${MESSAGES.error_file_upload} (S3): ${error.message}`,
107
        });
108
        error_count++;
109
      }
110
    }),
111
  );
112

113
  return { error_count, files: out };
114
}
115