mirror of
https://github.com/urbit/shrub.git
synced 2024-12-30 07:35:19 +03:00
interface: supports both S3 and GCP Storage
The S3 client has another layer of indirection we missed. To support it expediently, we just make the promise() method on GcpUpload do all the work in GcpClient.
This commit is contained in:
parent
6ec574d32b
commit
6b3397bd9f
@ -1,9 +1,15 @@
|
||||
// Very simple GCP Storage client.
|
||||
//
|
||||
// It's designed to match a subset of the S3 client upload API. The upload
|
||||
// function on S3 returns a ManagedUpload, which has a promise() method on
|
||||
// it. We don't care about any of the other methods on ManagedUpload, so we
|
||||
// just do the work in its promise() method.
|
||||
//
|
||||
import querystring from 'querystring';
|
||||
import {
|
||||
StorageAcl,
|
||||
StorageClient,
|
||||
StorageUpload,
|
||||
UploadParams,
|
||||
UploadResult
|
||||
} from './StorageClient';
|
||||
@ -11,14 +17,17 @@ import {
|
||||
|
||||
const ENDPOINT = 'storage.googleapis.com';
|
||||
|
||||
export default class GcpClient implements StorageClient {
|
||||
class GcpUpload implements StorageUpload {
|
||||
#params: UploadParams;
|
||||
#accessKey: string;
|
||||
|
||||
constructor(accessKey: string) {
|
||||
constructor(params: UploadParams, accessKey: string) {
|
||||
this.#params = params;
|
||||
this.#accessKey = accessKey;
|
||||
}
|
||||
|
||||
async upload({Bucket, Key, ContentType, Body}: UploadParams): UploadResult {
|
||||
async promise(): UploadResult {
|
||||
const {Bucket, Key, ContentType, Body} = this.#params;
|
||||
const urlParams = {
|
||||
uploadType: 'media',
|
||||
name: Key,
|
||||
@ -42,3 +51,15 @@ export default class GcpClient implements StorageClient {
|
||||
return {Location: `https://${ENDPOINT}/${Bucket}/${Key}`};
|
||||
}
|
||||
}
|
||||
|
||||
export default class GcpClient implements StorageClient {
|
||||
#accessKey: string;
|
||||
|
||||
constructor(accessKey: string) {
|
||||
this.#accessKey = accessKey;
|
||||
}
|
||||
|
||||
upload(params: UploadParams): StorageUpload {
|
||||
return new GcpUpload(params, this.#accessKey);
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,11 @@ export interface UploadResult {
|
||||
Location: string;
|
||||
};
|
||||
|
||||
export interface StorageClient {
|
||||
upload(params: UploadParams): Promise<UploadResult>;
|
||||
// Extra layer of indirection used by S3 client.
|
||||
export interface StorageUpload {
|
||||
promise(): Promise<UploadResult>;
|
||||
};
|
||||
|
||||
export interface StorageClient {
|
||||
upload(params: UploadParams): StorageUpload;
|
||||
};
|
||||
|
@ -19,37 +19,32 @@ const useStorage = (s3: S3State, gcp: GcpState,
|
||||
{ accept = '*' } = { accept: '*' }): IuseStorage => {
|
||||
const [uploading, setUploading] = useState(false);
|
||||
|
||||
const gcpClient = useRef<GcpClient | null>(null);
|
||||
const s3Client = useRef<S3Client | null>(null);
|
||||
const client = useRef<StorageClient | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
// prefer GCP if available, else use S3.
|
||||
if (gcp.accessKey) {
|
||||
gcpClient.current = new GcpClient(gcp.accessKey);
|
||||
s3Client.current = null;
|
||||
client.current = new GcpClient(gcp.accessKey);
|
||||
} else {
|
||||
if (!s3.credentials) {
|
||||
return;
|
||||
}
|
||||
s3Client.current = new S3({
|
||||
client.current = new S3({
|
||||
credentials: s3.credentials,
|
||||
endpoint: s3.credentials.endpoint
|
||||
});
|
||||
gcpClient.current = null;
|
||||
}
|
||||
}, [gcp.accessKey, s3.credentials]);
|
||||
|
||||
const canUpload = useMemo(
|
||||
() =>
|
||||
((gcpClient || s3Client) && s3.configuration.currentBucket !== "") || false,
|
||||
[gcpClient, s3Client, s3.configuration.currentBucket]
|
||||
(client && s3.configuration.currentBucket !== "") || false,
|
||||
[client, s3.configuration.currentBucket]
|
||||
);
|
||||
|
||||
const upload = useCallback(
|
||||
async (file: File, bucket: string) => {
|
||||
const client: StorageClient | null =
|
||||
gcpClient.current || s3Client.current;
|
||||
if (!client) {
|
||||
if (client.current === null) {
|
||||
throw new Error("Storage not ready");
|
||||
}
|
||||
|
||||
@ -68,21 +63,21 @@ const useStorage = (s3: S3State, gcp: GcpState,
|
||||
|
||||
setUploading(true);
|
||||
|
||||
const { Location } = await client.upload(params);
|
||||
const { Location } = await client.current.upload(params).promise();
|
||||
|
||||
setUploading(false);
|
||||
|
||||
return Location;
|
||||
},
|
||||
[gcpClient, s3Client, setUploading]
|
||||
[client, setUploading]
|
||||
);
|
||||
|
||||
const uploadDefault = useCallback(async (file: File) => {
|
||||
if (s3.configuration.currentBucket == '') {
|
||||
throw new Error('current bucket not set');
|
||||
if (s3.configuration.currentBucket === '') {
|
||||
throw new Error("current bucket not set");
|
||||
}
|
||||
return upload(file, s3.configuration.currentBucket);
|
||||
}, [s3.configuration, upload]);
|
||||
}, [s3, upload]);
|
||||
|
||||
const promptUpload = useCallback(
|
||||
() => {
|
||||
|
Loading…
Reference in New Issue
Block a user