AzureBackend: Add Azure MediaBackend

Add @azure/storage-blob dependency
This is the relevant part of the official azure sdk.

Signed-off-by: Philip Molares <philip.molares@udo.edu>
This commit is contained in:
Philip Molares 2021-02-22 22:33:56 +01:00
parent b774958593
commit dde74f37ff
5 changed files with 236 additions and 7 deletions

View file

@ -0,0 +1,85 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import mediaConfiguration, { MediaConfig } from '../../config/media.config';
import { ConsoleLoggerService } from '../../logger/console-logger.service';
import { MediaBackend } from '../media-backend.interface';
import { BackendData } from '../media-upload.entity';
import {
BlobServiceClient,
BlockBlobClient,
ContainerClient,
} from '@azure/storage-blob';
import { BackendType } from './backend-type.enum';
import { MediaBackendError } from '../../errors/errors';
@Injectable()
export class AzureBackend implements MediaBackend {
private config: MediaConfig['backend']['azure'];
private client: ContainerClient;
constructor(
private readonly logger: ConsoleLoggerService,
@Inject(mediaConfiguration.KEY)
private mediaConfig: MediaConfig,
) {
this.logger.setContext(AzureBackend.name);
this.config = mediaConfig.backend.azure;
if (mediaConfig.backend.use === BackendType.AZURE) {
// only create the client if the backend is configured to azure
const blobServiceClient = BlobServiceClient.fromConnectionString(
this.config.connectionString,
);
this.client = blobServiceClient.getContainerClient(this.config.container);
}
}
async saveFile(
buffer: Buffer,
fileName: string,
): Promise<[string, BackendData]> {
const blockBlobClient: BlockBlobClient = this.client.getBlockBlobClient(
fileName,
);
try {
await blockBlobClient.upload(buffer, buffer.length);
const url = this.getUrl(fileName);
this.logger.log(`Uploaded ${url}`, 'saveFile');
return [url, null];
} catch (e) {
this.logger.error(
`error: ${(e as Error).message}`,
(e as Error).stack,
'saveFile',
);
throw new MediaBackendError(`Could not save '${fileName}' on Azure`);
}
}
async deleteFile(fileName: string, _: BackendData): Promise<void> {
const blockBlobClient: BlockBlobClient = this.client.getBlockBlobClient(
fileName,
);
try {
await blockBlobClient.delete();
const url = this.getUrl(fileName);
this.logger.log(`Deleted ${url}`, 'deleteFile');
return;
} catch (e) {
this.logger.error(
`error: ${(e as Error).message}`,
(e as Error).stack,
'deleteFile',
);
throw new MediaBackendError(`Could not delete '${fileName}' on Azure`);
}
}
private getUrl(fileName: string): string {
return `${this.client.url}/${fileName}`;
}
}

View file

@ -14,6 +14,7 @@ import { FilesystemBackend } from './backends/filesystem-backend';
import { MediaUpload } from './media-upload.entity';
import { MediaService } from './media.service';
import { ImgurBackend } from './backends/imgur-backend';
import { AzureBackend } from './backends/azure-backend';
@Module({
imports: [
@ -23,7 +24,7 @@ import { ImgurBackend } from './backends/imgur-backend';
LoggerModule,
ConfigModule,
],
providers: [MediaService, FilesystemBackend, ImgurBackend],
providers: [MediaService, FilesystemBackend, AzureBackend, ImgurBackend],
exports: [MediaService],
})
export class MediaModule {}

View file

@ -19,6 +19,7 @@ import { FilesystemBackend } from './backends/filesystem-backend';
import { MediaBackend } from './media-backend.interface';
import { MediaUpload } from './media-upload.entity';
import { MediaUploadUrlDto } from './media-upload-url.dto';
import { AzureBackend } from './backends/azure-backend';
import { ImgurBackend } from './backends/imgur-backend';
@Injectable()
@ -159,6 +160,8 @@ export class MediaService {
switch (this.mediaConfig.backend.use) {
case 'filesystem':
return BackendType.FILESYSTEM;
case 'azure':
return BackendType.AZURE;
case 'imgur':
return BackendType.IMGUR;
}
@ -168,6 +171,8 @@ export class MediaService {
switch (type) {
case BackendType.FILESYSTEM:
return this.moduleRef.get(FilesystemBackend);
case BackendType.AZURE:
return this.moduleRef.get(AzureBackend);
case BackendType.IMGUR:
return this.moduleRef.get(ImgurBackend);
}