|
8 | 8 | } from '@aws-sdk/client-s3'
|
9 | 9 | import mime from 'mime-types'
|
10 | 10 | import path from 'node:path'
|
| 11 | +import { createHash } from 'crypto' |
11 | 12 |
|
12 | 13 | export interface S3Object extends _Object {
|
13 | 14 | ContentType?: string
|
@@ -74,39 +75,53 @@ export class S3Service {
|
74 | 75 |
|
75 | 76 | public async putAllTextObjects(objects: Map<string, string>): Promise<void> {
|
76 | 77 | const jobs = [...objects.entries()].map(
|
77 |
| - async ([Key, Body]) => |
78 |
| - await new Promise((resolve) => { |
| 78 | + ([Key, Body]) => |
| 79 | + new Promise((resolve, reject) => { |
79 | 80 | const command = new PutObjectCommand({
|
80 | 81 | Bucket: process.env.S3_BUCKET_NAME,
|
81 | 82 | Key,
|
82 | 83 | Body,
|
83 |
| - ContentType: 'text/html' |
| 84 | + ContentType: 'text/html', |
| 85 | + IfNoneMatch: this.md5Quoted(Body) |
84 | 86 | })
|
85 | 87 |
|
86 |
| - this.client.send(command).then(resolve.bind(this)) |
| 88 | + this.client |
| 89 | + .send(command) |
| 90 | + .then(resolve.bind(this)) |
| 91 | + .catch(reject.bind(this)) |
87 | 92 | })
|
88 | 93 | )
|
89 | 94 |
|
90 |
| - await Promise.all(jobs) |
| 95 | + await Promise.allSettled(jobs) |
91 | 96 | }
|
92 | 97 |
|
93 | 98 | public async putAllBinaryObjects(objects: Map<string, string>) {
|
94 | 99 | const jobs = [...objects.entries()].map(
|
95 |
| - async ([Key, filepath]) => |
96 |
| - await new Promise((resolve) => { |
| 100 | + ([Key, filepath]) => |
| 101 | + new Promise((resolve, reject) => { |
| 102 | + const Body = fs.readFileSync(filepath) |
97 | 103 | const command = new PutObjectCommand({
|
98 | 104 | Bucket: process.env.S3_BUCKET_NAME,
|
99 | 105 | Key,
|
100 |
| - Body: fs.readFileSync(filepath), |
| 106 | + Body, |
| 107 | + IfNoneMatch: this.md5Quoted(Body), |
101 | 108 | ContentType:
|
102 | 109 | mime.contentType(path.extname(filepath)) ||
|
103 | 110 | 'application/octet-stream'
|
104 | 111 | })
|
105 | 112 |
|
106 |
| - this.client.send(command).then(resolve.bind(this)) |
| 113 | + this.client |
| 114 | + .send(command) |
| 115 | + .then(resolve.bind(this)) |
| 116 | + .catch(reject.bind(this)) |
107 | 117 | })
|
108 | 118 | )
|
109 | 119 |
|
110 |
| - await Promise.all(jobs) |
| 120 | + await Promise.allSettled(jobs) |
| 121 | + } |
| 122 | + |
| 123 | + private md5Quoted(body: string | Buffer): string { |
| 124 | + const hash = createHash('md5').update(body).digest('hex') |
| 125 | + return `"${hash}"` |
111 | 126 | }
|
112 | 127 | }
|
0 commit comments