s3: support pathStyle
This commit is contained in:
parent
c786e1bc55
commit
7ada849a6a
|
@ -18,7 +18,10 @@
|
||||||
"@/": "./src/",
|
"@/": "./src/",
|
||||||
"@nostrify/nostrify": "jsr:@nostrify/nostrify@^0.15.0",
|
"@nostrify/nostrify": "jsr:@nostrify/nostrify@^0.15.0",
|
||||||
"@std/cli": "jsr:@std/cli@^0.223.0",
|
"@std/cli": "jsr:@std/cli@^0.223.0",
|
||||||
|
"@std/crypto": "jsr:@std/crypto@^0.224.0",
|
||||||
|
"@std/encoding": "jsr:@std/encoding@^0.224.0",
|
||||||
"@std/json": "jsr:@std/json@^0.223.0",
|
"@std/json": "jsr:@std/json@^0.223.0",
|
||||||
|
"@std/media-types": "jsr:@std/media-types@^0.224.0",
|
||||||
"@std/streams": "jsr:@std/streams@^0.223.0",
|
"@std/streams": "jsr:@std/streams@^0.223.0",
|
||||||
"hono": "https://deno.land/x/hono@v3.10.1/mod.ts",
|
"hono": "https://deno.land/x/hono@v3.10.1/mod.ts",
|
||||||
"hono/middleware": "https://deno.land/x/hono@v3.10.1/middleware.ts",
|
"hono/middleware": "https://deno.land/x/hono@v3.10.1/middleware.ts",
|
||||||
|
|
|
@ -16,8 +16,7 @@ async function uploadFile(file: File, meta: FileMeta, signal?: AbortSignal) {
|
||||||
throw new Error('File size is too large.');
|
throw new Error('File size is too large.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { cid } = await uploader.upload(file, signal);
|
const { url } = await uploader.upload(file, { signal });
|
||||||
const url = new URL(`/ipfs/${cid}`, Conf.mediaDomain).toString();
|
|
||||||
|
|
||||||
return insertUnattachedMedia({
|
return insertUnattachedMedia({
|
||||||
pubkey,
|
pubkey,
|
||||||
|
|
|
@ -30,10 +30,12 @@ const ipfsUploader: Uploader = {
|
||||||
signal: opts?.signal,
|
signal: opts?.signal,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { Hash } = ipfsAddResponseSchema.parse(await response.json());
|
const { Hash: cid } = ipfsAddResponseSchema.parse(await response.json());
|
||||||
|
|
||||||
return {
|
return {
|
||||||
cid: Hash,
|
id: cid,
|
||||||
|
cid,
|
||||||
|
url: new URL(`/ipfs/${cid}`, Conf.mediaDomain).toString(),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async delete(cid, opts) {
|
async delete(cid, opts) {
|
||||||
|
|
|
@ -1,30 +1,39 @@
|
||||||
|
import { join } from 'node:path';
|
||||||
|
|
||||||
|
import { crypto } from '@std/crypto';
|
||||||
|
import { encodeHex } from '@std/encoding/hex';
|
||||||
|
import { extensionsByType } from '@std/media-types';
|
||||||
|
|
||||||
import { Conf } from '@/config.ts';
|
import { Conf } from '@/config.ts';
|
||||||
import { IpfsHash, S3Client } from '@/deps.ts';
|
import { S3Client } from '@/deps.ts';
|
||||||
|
|
||||||
import type { Uploader } from './types.ts';
|
import type { Uploader } from './types.ts';
|
||||||
|
|
||||||
/**
|
/** S3-compatible uploader for AWS, Wasabi, DigitalOcean Spaces, and more. */
|
||||||
* S3-compatible uploader for AWS, Wasabi, DigitalOcean Spaces, and more.
|
|
||||||
* Files are named by their IPFS CID and exposed at `/ipfs/<cid>`, letting it
|
|
||||||
* take advantage of IPFS features while not really using IPFS.
|
|
||||||
*/
|
|
||||||
const s3Uploader: Uploader = {
|
const s3Uploader: Uploader = {
|
||||||
async upload(file) {
|
async upload(file) {
|
||||||
const cid = await IpfsHash.of(file.stream()) as string;
|
const sha256 = encodeHex(await crypto.subtle.digest('SHA-256', file.stream()));
|
||||||
|
const ext = extensionsByType(file.type)?.[0] ?? 'bin';
|
||||||
|
const filename = `${sha256}.${ext}`;
|
||||||
|
|
||||||
await client().putObject(`ipfs/${cid}`, file.stream(), {
|
await client().putObject(filename, file.stream(), {
|
||||||
metadata: {
|
metadata: {
|
||||||
'Content-Type': file.type,
|
'Content-Type': file.type,
|
||||||
'x-amz-acl': 'public-read',
|
'x-amz-acl': 'public-read',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { pathStyle, bucket } = Conf.s3;
|
||||||
|
const path = (pathStyle && bucket) ? join(bucket, filename) : filename;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
cid,
|
id: filename,
|
||||||
|
sha256,
|
||||||
|
url: new URL(path, Conf.mediaDomain).toString(),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async delete(cid) {
|
async delete(id) {
|
||||||
await client().deleteObject(`ipfs/${cid}`);
|
await client().deleteObject(id);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,14 @@ interface Uploader {
|
||||||
|
|
||||||
/** Return value from the uploader after uploading a file. */
|
/** Return value from the uploader after uploading a file. */
|
||||||
interface UploadResult {
|
interface UploadResult {
|
||||||
/** IPFS CID for the file. */
|
/** File ID specific to the uploader, so it can later be referenced or deleted. */
|
||||||
cid: string;
|
id: string;
|
||||||
|
/** URL where the file can be accessed. */
|
||||||
|
url: string;
|
||||||
|
/** SHA-256 hash of the file. */
|
||||||
|
sha256?: string;
|
||||||
|
/** IPFS CID of the file. */
|
||||||
|
cid?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type { Uploader };
|
export type { Uploader };
|
||||||
|
|
Loading…
Reference in New Issue