89 lines
2.2 KiB
TypeScript
89 lines
2.2 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
|
import { mkdir, access } from 'node:fs/promises';
|
|
import { constants } from 'node:fs';
|
|
import { dirname, join } from 'node:path';
|
|
import { AppConfigService } from '../config/config.service';
|
|
|
|
export interface StorageStatus {
|
|
root: string;
|
|
writable: boolean;
|
|
}
|
|
|
|
@Injectable()
|
|
export class LocalFilesystemStorageService {
|
|
constructor(private readonly configService: AppConfigService) {}
|
|
|
|
get root(): string {
|
|
return this.configService.storageRoot;
|
|
}
|
|
|
|
resolve(relativePath: string): string {
|
|
return join(this.root, relativePath);
|
|
}
|
|
|
|
userAudioAssetStorageKey(userId: string, sha256: string): string {
|
|
return join('users', userId, 'audio', `${sha256}.mp3`);
|
|
}
|
|
|
|
userAudioAssetPath(userId: string, sha256: string): string {
|
|
return this.resolve(this.userAudioAssetStorageKey(userId, sha256));
|
|
}
|
|
|
|
userArtworkAssetStorageKey(
|
|
userId: string,
|
|
sha256: string,
|
|
fileExtension: string,
|
|
): string {
|
|
return join('users', userId, 'artwork', `${sha256}.${fileExtension}`);
|
|
}
|
|
|
|
userArtworkAssetPath(
|
|
userId: string,
|
|
sha256: string,
|
|
fileExtension: string,
|
|
): string {
|
|
return this.resolve(
|
|
this.userArtworkAssetStorageKey(userId, sha256, fileExtension),
|
|
);
|
|
}
|
|
|
|
tempUploadStorageKey(uploadId: string): string {
|
|
return join('temp', 'uploads', `${uploadId}.part`);
|
|
}
|
|
|
|
tempUploadPath(uploadId: string): string {
|
|
return this.resolve(this.tempUploadStorageKey(uploadId));
|
|
}
|
|
|
|
async ensureDirectory(path: string): Promise<void> {
|
|
await mkdir(path, { recursive: true });
|
|
}
|
|
|
|
async ensureParentDirectory(path: string): Promise<void> {
|
|
await this.ensureDirectory(dirname(path));
|
|
}
|
|
|
|
async checkReadiness(): Promise<StorageStatus> {
|
|
const paths = [
|
|
this.root,
|
|
join(this.root, 'users'),
|
|
join(this.root, 'temp'),
|
|
join(this.root, 'temp', 'uploads'),
|
|
join(this.root, 'incoming'),
|
|
join(this.root, 'quarantine'),
|
|
join(this.root, 'library', 'audio'),
|
|
join(this.root, 'library', 'artwork'),
|
|
];
|
|
|
|
for (const path of paths) {
|
|
await mkdir(path, { recursive: true });
|
|
await access(path, constants.R_OK | constants.W_OK);
|
|
}
|
|
|
|
return {
|
|
root: this.root,
|
|
writable: true,
|
|
};
|
|
}
|
|
}
|