0
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 397 days ago Viewed 5021 times
0
Submitted by vidz657 Deno
Verified 397 days ago
1
import { S3Client } from "https://deno.land/x/s3_lite_client@0.5.0/mod.ts";
2
import { format } from "https://deno.land/std@0.89.0/datetime/mod.ts";
3
import { mime } from "https://deno.land/x/mimetypes@v1.0.0/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