2021-03-06 01:50:31 +03:00
|
|
|
//
|
|
|
|
// Copyright (c) Microsoft.
|
|
|
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
|
|
//
|
|
|
|
|
2021-07-18 00:33:35 +03:00
|
|
|
import { DefaultAzureCredential } from '@azure/identity';
|
2022-10-08 01:25:28 +03:00
|
|
|
import { BlobServiceClient, StorageSharedKeyCredential, ContainerClient } from '@azure/storage-blob';
|
2021-04-10 02:36:15 +03:00
|
|
|
|
|
|
|
import { IProviders } from '../interfaces';
|
2021-03-06 01:50:31 +03:00
|
|
|
|
2023-01-20 10:01:39 +03:00
|
|
|
import Debug from 'debug';
|
|
|
|
const debug = Debug.debug('cache');
|
2021-03-06 01:50:31 +03:00
|
|
|
|
|
|
|
export interface IBlobCacheOptions {
|
|
|
|
account: string;
|
|
|
|
key: string;
|
|
|
|
container: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface IExtendedProviders extends IProviders {
|
|
|
|
staticBlobCacheFallback: StaticBlobCacheFallback;
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function getStaticBlobCacheFallback(providers: IProviders) {
|
|
|
|
const p = providers as IExtendedProviders;
|
|
|
|
if (!p.staticBlobCacheFallback) {
|
2022-10-08 01:25:28 +03:00
|
|
|
p.staticBlobCacheFallback = new StaticBlobCacheFallback(providers.config?.client?.fallback?.blob);
|
2021-03-06 01:50:31 +03:00
|
|
|
await p.staticBlobCacheFallback.initialize();
|
|
|
|
}
|
|
|
|
return p.staticBlobCacheFallback;
|
|
|
|
}
|
|
|
|
|
|
|
|
export default class StaticBlobCacheFallback {
|
|
|
|
private _options: IBlobCacheOptions;
|
|
|
|
private _client: BlobServiceClient;
|
|
|
|
private _container: ContainerClient;
|
|
|
|
private _initialized: boolean;
|
|
|
|
|
|
|
|
constructor(options: IBlobCacheOptions) {
|
|
|
|
this._options = options;
|
|
|
|
}
|
|
|
|
|
|
|
|
async initialize() {
|
|
|
|
if (this._initialized) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const { account, key } = this._options;
|
|
|
|
if (!account) {
|
|
|
|
throw new Error('options.account required');
|
|
|
|
}
|
|
|
|
if (!this._options.container) {
|
|
|
|
throw new Error('options.container required');
|
|
|
|
}
|
2021-07-18 00:33:35 +03:00
|
|
|
if (!key) {
|
|
|
|
// TODO: remove after validation
|
|
|
|
console.log('Temporary note: using DefaultAzureCredential without a key');
|
|
|
|
}
|
2022-10-08 01:25:28 +03:00
|
|
|
const credential = key ? new StorageSharedKeyCredential(account, key) : new DefaultAzureCredential();
|
|
|
|
this._client = new BlobServiceClient(`https://${account}.blob.core.windows.net`, credential);
|
2021-03-06 01:50:31 +03:00
|
|
|
try {
|
2022-10-08 01:25:28 +03:00
|
|
|
this._container = this._client.getContainerClient(this._options.container);
|
2022-10-07 09:59:30 +03:00
|
|
|
if (!(await this._container.exists())) {
|
2021-03-06 01:50:31 +03:00
|
|
|
await this._client.createContainer(this._options.container);
|
|
|
|
}
|
|
|
|
} catch (containerError) {
|
|
|
|
console.dir(containerError);
|
|
|
|
}
|
|
|
|
this._initialized = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
async get(filename: string): Promise<[Buffer, string]> {
|
|
|
|
this.throwIfNotInitialized();
|
|
|
|
filename = filename.substr(1);
|
|
|
|
debug(`BLOB FALLBACK GET: ${filename}`);
|
|
|
|
const blobClient = this._container.getBlobClient(filename);
|
|
|
|
try {
|
|
|
|
const { contentType } = await blobClient.getProperties();
|
|
|
|
const buffer = await blobClient.downloadToBuffer();
|
|
|
|
return [buffer, contentType];
|
|
|
|
} catch (error) {
|
|
|
|
if (error && error.statusCode && error.statusCode === 404) {
|
|
|
|
return [null, null];
|
|
|
|
}
|
|
|
|
console.dir(error);
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private throwIfNotInitialized() {
|
|
|
|
if (!this._initialized) {
|
2022-10-08 01:25:28 +03:00
|
|
|
throw new Error('Static blob cache provider must be initialized before it can be used');
|
2021-03-06 01:50:31 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|