uploaders: allow deleting files by CID
This commit is contained in:
parent
c40f10539d
commit
014b9f6d29
|
@ -20,7 +20,7 @@ const mediaController: AppController = async (c) => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { file } = result.data;
|
const { file } = result.data;
|
||||||
const { cid } = await s3Uploader(file);
|
const { cid } = await s3Uploader.upload(file);
|
||||||
|
|
||||||
return c.json({
|
return c.json({
|
||||||
id: cid,
|
id: cid,
|
||||||
|
|
|
@ -3,28 +3,48 @@ import { z } from '@/deps.ts';
|
||||||
|
|
||||||
import type { Uploader } from './types.ts';
|
import type { Uploader } from './types.ts';
|
||||||
|
|
||||||
const ipfsAddResultSchema = z.object({
|
/** Response schema for POST `/api/v0/add`. */
|
||||||
|
const ipfsAddResponseSchema = z.object({
|
||||||
Name: z.string(),
|
Name: z.string(),
|
||||||
Hash: z.string(),
|
Hash: z.string(),
|
||||||
Size: z.string(),
|
Size: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const ipfsUploader: Uploader = async (file) => {
|
/**
|
||||||
const url = new URL('/api/v0/add', Conf.ipfs.apiUrl);
|
* IPFS uploader. It expects an IPFS node up and running.
|
||||||
|
* It will try to connect to `http://localhost:5001` by default,
|
||||||
|
* and upload the file using the REST API.
|
||||||
|
*/
|
||||||
|
const ipfsUploader: Uploader = {
|
||||||
|
async upload(file) {
|
||||||
|
const url = new URL('/api/v0/add', Conf.ipfs.apiUrl);
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('file', file);
|
formData.append('file', file);
|
||||||
|
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: formData,
|
body: formData,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { Hash } = ipfsAddResultSchema.parse(await response.json());
|
const { Hash } = ipfsAddResponseSchema.parse(await response.json());
|
||||||
|
|
||||||
return {
|
return {
|
||||||
cid: Hash,
|
cid: Hash,
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
async delete(cid) {
|
||||||
|
const url = new URL('/api/v0/pin/rm', Conf.ipfs.apiUrl);
|
||||||
|
|
||||||
|
const query = new URLSearchParams();
|
||||||
|
query.set('arg', cid);
|
||||||
|
|
||||||
|
url.search = query.toString();
|
||||||
|
|
||||||
|
await fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
});
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export { ipfsUploader };
|
export { ipfsUploader };
|
||||||
|
|
|
@ -5,19 +5,29 @@ import type { Uploader } from './types.ts';
|
||||||
|
|
||||||
const s3 = new S3Client({ ...Conf.s3 });
|
const s3 = new S3Client({ ...Conf.s3 });
|
||||||
|
|
||||||
const s3Uploader: Uploader = async (file) => {
|
/**
|
||||||
const cid = await IpfsHash.of(file.stream()) as string;
|
* 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 = {
|
||||||
|
async upload(file) {
|
||||||
|
const cid = await IpfsHash.of(file.stream()) as string;
|
||||||
|
|
||||||
await s3.putObject(`ipfs/${cid}`, file.stream(), {
|
await s3.putObject(`ipfs/${cid}`, file.stream(), {
|
||||||
metadata: {
|
metadata: {
|
||||||
'Content-Type': file.type,
|
'Content-Type': file.type,
|
||||||
'x-amz-acl': 'public-read',
|
'x-amz-acl': 'public-read',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
cid,
|
cid,
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
async delete(cid) {
|
||||||
|
await s3.deleteObject(`ipfs/${cid}`);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export { s3Uploader };
|
export { s3Uploader };
|
||||||
|
|
|
@ -1,7 +1,15 @@
|
||||||
|
/** Modular uploader interface, to support uploading to different backends. */
|
||||||
|
interface Uploader {
|
||||||
|
/** Upload the file to the backend. */
|
||||||
|
upload(file: File): Promise<UploadResult>;
|
||||||
|
/** Delete the file from the backend. */
|
||||||
|
delete(cid: string): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return value from the uploader after uploading a file. */
|
||||||
interface UploadResult {
|
interface UploadResult {
|
||||||
|
/** IPFS CID for the file. */
|
||||||
cid: string;
|
cid: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Uploader = (file: File) => Promise<UploadResult>;
|
export type { Uploader };
|
||||||
|
|
||||||
export type { Uploader, UploadResult };
|
|
||||||
|
|
Loading…
Reference in New Issue