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/FakeCanonical'
|
||||||
export * from './service/Config'
|
export * from './service/Config'
|
||||||
export * from './service/Controllers'
|
export * from './service/Controllers'
|
||||||
|
export * from './service/Files'
|
||||||
export * from './service/HTTPServer'
|
export * from './service/HTTPServer'
|
||||||
export * from './service/Routing'
|
export * from './service/Routing'
|
||||||
export * from './service/Middlewares'
|
export * from './service/Middlewares'
|
||||||
|
@ -28,6 +28,22 @@ export function env(key: string, defaultValue?: any): any {
|
|||||||
return Application.getApplication().env(key, defaultValue)
|
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.
|
* 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