返回 AiToEarn
storage-provider.ts
根目录 / project / aitoearn-backend / libs / assets / src / storage-provider.ts
1 import type { Readable } from 'node:stream'
2 import { buildUrl } from '@yikart/common'
3
4 export interface StorageHeadResult {
5 contentLength?: number
6 contentType?: string
7 }
8
9 export interface StorageGetObjectResult {
10 buffer: Buffer | undefined
11 }
12
13 export interface CopyObjectOptions {
14 contentType?: string
15 contentDisposition?: string
16 metadata?: Record<string, string>
17 }
18
19 export abstract class StorageProvider {
20 protected readonly endpoint: string
21 protected readonly cdnEndpoint: string | undefined
22 protected readonly publicEndpoint: string
23
24 constructor(endpoint: string, cdnEndpoint?: string) {
25 this.endpoint = endpoint.replace(/\/+$/, '')
26 this.cdnEndpoint = cdnEndpoint?.replace(/\/+$/, '')
27 this.publicEndpoint = this.cdnEndpoint || this.endpoint
28 }
29
30 buildUrl(objectPath: string): string {
31 return buildUrl(this.publicEndpoint, objectPath)
32 }
33
34 parsePathFromUrl(url: string): string {
35 const normalizedUrl = String(url ?? '').trim()
36 if (!normalizedUrl.startsWith('http'))
37 return normalizedUrl.replace(/^\/+/, '')
38 let path = normalizedUrl
39 if (this.cdnEndpoint && normalizedUrl.startsWith(this.cdnEndpoint)) {
40 path = normalizedUrl.replace(this.cdnEndpoint, '')
41 }
42 else if (normalizedUrl.startsWith(this.endpoint)) {
43 path = normalizedUrl.replace(this.endpoint, '')
44 }
45 return decodeURIComponent(path.split(/[?#]/)[0].replace(/^\/+/, ''))
46 }
47
48 abstract putObject(objectPath: string, file: Buffer | Readable, contentType?: string): Promise<{ path: string }>
49 abstract headObject(objectPath: string): Promise<StorageHeadResult>
50 abstract putObjectFromUrl(url: string, objectPath: string): Promise<{ path: string, exists?: boolean }>
51 abstract deleteObject(objectPath: string): Promise<void>
52 abstract getUploadSignUrl(objectPath: string, contentType?: string, contentLength?: number, callbackVars?: Record<string, string>): Promise<string>
53 abstract copyObject(objectPath: string, options: CopyObjectOptions): Promise<void>
54 abstract getObject(objectPath: string): Promise<StorageGetObjectResult>
55 abstract getReadSignUrl(objectPath: string, expiresIn?: number): Promise<string>
56
57 async toPresignedUrl(urlOrPath: string, expiresIn = 3600): Promise<string> {
58 const normalizedUrlOrPath = String(urlOrPath ?? '').trim()
59 if (
60 (normalizedUrlOrPath.startsWith('http://') || normalizedUrlOrPath.startsWith('https://'))
61 && !(this.cdnEndpoint && normalizedUrlOrPath.startsWith(this.cdnEndpoint))
62 && !normalizedUrlOrPath.startsWith(this.endpoint)
63 ) {
64 return normalizedUrlOrPath
65 }
66 const objectPath = this.parsePathFromUrl(normalizedUrlOrPath)
67 return this.getReadSignUrl(objectPath, expiresIn)
68 }
69 }
70
70 lines TYPESCRIPT