Create Files unit to manage filesystem implementations defined in config
This commit is contained in:
parent
6f73df3465
commit
e772d12f20
@ -55,6 +55,7 @@ export * from './service/CanonicalStatic'
|
||||
export * from './service/FakeCanonical'
|
||||
export * from './service/Config'
|
||||
export * from './service/Controllers'
|
||||
export * from './service/Files'
|
||||
export * from './service/HTTPServer'
|
||||
export * from './service/Routing'
|
||||
export * from './service/Middlewares'
|
||||
|
@ -28,6 +28,22 @@ export function env(key: string, defaultValue?: any): any {
|
||||
return Application.getApplication().env(key, defaultValue)
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for fetching a universal path relative to the root of the application.
|
||||
* @param parts
|
||||
*/
|
||||
export function basePath(...parts: PathLike[]): UniversalPath {
|
||||
return Application.getApplication().path(...parts)
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for fetching a universal path relative to the `app/` directory.
|
||||
* @param parts
|
||||
*/
|
||||
export function appPath(...parts: PathLike[]): UniversalPath {
|
||||
return Application.getApplication().appPath(...parts)
|
||||
}
|
||||
|
||||
/**
|
||||
* The main application container.
|
||||
*/
|
||||
|
142
src/service/Files.ts
Normal file
142
src/service/Files.ts
Normal file
@ -0,0 +1,142 @@
|
||||
import {Unit} from "../lifecycle/Unit"
|
||||
import {Inject, Singleton} from "@extollo/di"
|
||||
import {Config} from "./Config"
|
||||
import {Logging} from "./Logging"
|
||||
import {Filesystem, ErrorWithContext} from "@extollo/util"
|
||||
|
||||
/**
|
||||
* Error thrown when a function is called on a filesystem that does not exists in code.
|
||||
*/
|
||||
export class FilesystemDoesNotExist extends ErrorWithContext {
|
||||
constructor(
|
||||
message: string = 'The specified filesystem does not exist.',
|
||||
context: {[key: string]: any} = {}
|
||||
) {
|
||||
super(message, context)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unit service that loads and creates Filesystem drivers from config. The filesystems
|
||||
* will automatically be opened when the app starts, and closed when it stops.
|
||||
*
|
||||
* @example
|
||||
* Filesystems can be defined in the `server.filesystems` config. For example:
|
||||
*
|
||||
* ```typescript
|
||||
* import {basePath} from "@extollo/lib"
|
||||
* import {LocalFilesystem, LocalFilesystemConfig} from "@extollo/util"
|
||||
*
|
||||
* export default {
|
||||
* // ... other configs ...
|
||||
* filesystems: {
|
||||
* default: {
|
||||
* driver: LocalFilesystem,
|
||||
* config: {
|
||||
* baseDir: basePath('..', 'uploads').toLocal,
|
||||
* } as LocalFilesystemConfig,
|
||||
* },
|
||||
* },
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The `config` key should be an instance of the config interface for the driver
|
||||
* in question.
|
||||
*
|
||||
* @example
|
||||
* Filesystems can then be accessed from the Files service:
|
||||
*
|
||||
* ```typescript
|
||||
* if ( files.hasFilesystem('default') ) {
|
||||
* const filesystem = files.getFilesystem('default')
|
||||
* // ... do something with the filesystem ...
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
@Singleton()
|
||||
export class Files extends Unit {
|
||||
protected filesystems: {[key: string]: Filesystem} = {}
|
||||
protected defaultFilesystem?: Filesystem
|
||||
|
||||
@Inject()
|
||||
protected readonly config!: Config
|
||||
|
||||
@Inject()
|
||||
protected readonly logging!: Logging
|
||||
|
||||
async up() {
|
||||
const config = this.config.get('server.filesystems', {})
|
||||
const promises = []
|
||||
for ( const key in config ) {
|
||||
if ( !config.hasOwnProperty(key) ) continue;
|
||||
if ( config[key]?.driver?.prototype instanceof Filesystem ) {
|
||||
this.logging.verbose(`Registering filesystem '${key}' with driver ${config[key].driver.name}...`)
|
||||
|
||||
const inst = <Filesystem> this.make(config[key].driver, config[key].config || {})
|
||||
promises.push(inst.open())
|
||||
|
||||
if ( this.filesystems[key] ) {
|
||||
this.logging.warn(`Overwriting filesystem with duplicate name: ${key}`)
|
||||
}
|
||||
|
||||
this.filesystems[key] = inst
|
||||
|
||||
if ( config[key]?.isDefault ) {
|
||||
this.defaultFilesystem = inst
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(promises)
|
||||
}
|
||||
|
||||
async down() {
|
||||
await Promise.all(Object.values(this.filesystems).map(fs => fs.close()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a filesystem with the given name exists.
|
||||
* @param key
|
||||
*/
|
||||
hasFilesystem(key?: string) {
|
||||
if ( !key ) {
|
||||
return !!this.defaultFilesystem
|
||||
}
|
||||
|
||||
return !!this.filesystems[key]
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the name of a filesystem registered in the system, get that filesystem.
|
||||
* @param key
|
||||
*/
|
||||
getFilesystem(key?: string): Filesystem {
|
||||
if ( !key ) {
|
||||
if ( !this.defaultFilesystem ) {
|
||||
throw new FilesystemDoesNotExist()
|
||||
}
|
||||
|
||||
return this.defaultFilesystem
|
||||
}
|
||||
|
||||
if ( !this.hasFilesystem(key) ) {
|
||||
throw new FilesystemDoesNotExist()
|
||||
}
|
||||
|
||||
return this.filesystems[key]
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the given filesystem with this service by name.
|
||||
* @param key
|
||||
* @param fs
|
||||
*/
|
||||
registerFilesystem(key: string, fs: Filesystem) {
|
||||
if ( this.hasFilesystem(key) ) {
|
||||
this.logging.warn(`Overwriting filesystem with duplicate name: ${key}`)
|
||||
}
|
||||
|
||||
this.filesystems[key] = fs
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user