-
Notifications
You must be signed in to change notification settings - Fork 212
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
22 changed files
with
315 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import {IExtensionEvent, IExtensionEvents} from './IExtension'; | ||
import {ObjectManagers} from '../ObjectManagers'; | ||
import {ExtensionEvent} from './ExtensionEvent'; | ||
|
||
export const ExtensionDecorator = <I extends [], O>(fn: (ee: IExtensionEvents) => IExtensionEvent<I, O>) => { | ||
return ( | ||
target: unknown, | ||
propertyName: string, | ||
descriptor: PropertyDescriptor | ||
) => { | ||
const targetMethod = descriptor.value; | ||
descriptor.value = async function(...args: I) { | ||
const event = fn(ObjectManagers.getInstance().ExtensionManager.events) as ExtensionEvent<I, O>; | ||
const eventObj = {stopPropagation: false}; | ||
const input = await event.triggerBefore({inputs: args}, eventObj); | ||
|
||
// skip the rest of the execution if the before handler asked for stop propagation | ||
if (eventObj.stopPropagation) { | ||
return input as O; | ||
} | ||
const out = await targetMethod.apply(this, args); | ||
return await event.triggerAfter(out); | ||
}; | ||
|
||
return descriptor; | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import {IExtensionAfterEventHandler, IExtensionBeforeEventHandler, IExtensionEvent} from './IExtension'; | ||
|
||
export class ExtensionEvent<I, O> implements IExtensionEvent<I, O> { | ||
protected beforeHandlers: IExtensionBeforeEventHandler<I, O>[] = []; | ||
protected afterHandlers: IExtensionAfterEventHandler<O>[] = []; | ||
|
||
public before(handler: IExtensionBeforeEventHandler<I, O>): void { | ||
if (typeof handler !== 'function') { | ||
throw new Error('ExtensionEvent::before: Handler is not a function'); | ||
} | ||
this.beforeHandlers.push(handler); | ||
} | ||
|
||
public after(handler: IExtensionAfterEventHandler<O>): void { | ||
if (typeof handler !== 'function') { | ||
throw new Error('ExtensionEvent::after: Handler is not a function'); | ||
} | ||
this.afterHandlers.push(handler); | ||
} | ||
|
||
public offAfter(handler: IExtensionAfterEventHandler<O>): void { | ||
this.afterHandlers = this.afterHandlers.filter((h) => h !== handler); | ||
} | ||
|
||
public offBefore(handler: IExtensionBeforeEventHandler<I, O>): void { | ||
this.beforeHandlers = this.beforeHandlers.filter((h) => h !== handler); | ||
} | ||
|
||
|
||
public async triggerBefore(input: { inputs: I }, event: { stopPropagation: boolean }): Promise<{ inputs: I } | O> { | ||
let pipe: { inputs: I } | O = input; | ||
if (this.beforeHandlers && this.beforeHandlers.length > 0) { | ||
const s = this.beforeHandlers.slice(0); | ||
for (let i = 0; i < s.length; ++i) { | ||
if (event.stopPropagation) { | ||
break; | ||
} | ||
pipe = await s[i](pipe as { inputs: I }, event); | ||
} | ||
} | ||
return pipe; | ||
} | ||
|
||
public async triggerAfter(output: O): Promise<O> { | ||
if (this.afterHandlers && this.afterHandlers.length > 0) { | ||
const s = this.afterHandlers.slice(0); | ||
for (let i = 0; i < s.length; ++i) { | ||
output = await s[i](output); | ||
} | ||
} | ||
return output; | ||
} | ||
|
||
} | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import {ProjectPath} from '../../ProjectPath'; | ||
import {Config} from '../../../common/config/private/Config'; | ||
import * as fs from 'fs'; | ||
import * as path from 'path'; | ||
import {IObjectManager} from '../database/IObjectManager'; | ||
import {Logger} from '../../Logger'; | ||
import {IExtensionEvents, IExtensionObject, IServerExtension} from './IExtension'; | ||
import {ObjectManagers} from '../ObjectManagers'; | ||
import {Server} from '../../server'; | ||
import {ExtensionEvent} from './ExtensionEvent'; | ||
|
||
const LOG_TAG = '[ExtensionManager]'; | ||
|
||
export class ExtensionManager implements IObjectManager { | ||
|
||
events: IExtensionEvents = { | ||
gallery: { | ||
MetadataLoader: { | ||
loadPhotoMetadata: new ExtensionEvent() | ||
} | ||
} | ||
}; | ||
|
||
public async init() { | ||
this.loadExtensionsList(); | ||
await this.initExtensions(); | ||
} | ||
|
||
public loadExtensionsList() { | ||
if (!fs.existsSync(ProjectPath.ExtensionFolder)) { | ||
return; | ||
} | ||
Config.Extensions.list = fs | ||
.readdirSync(ProjectPath.ExtensionFolder) | ||
.filter((f): boolean => | ||
fs.statSync(path.join(ProjectPath.ExtensionFolder, f)).isDirectory() | ||
); | ||
Config.Extensions.list.sort(); | ||
} | ||
|
||
private async callServerFN(fn: (ext: IServerExtension, extName: string) => Promise<void>) { | ||
for (let i = 0; i < Config.Extensions.list.length; ++i) { | ||
const extName = Config.Extensions.list[i]; | ||
const extPath = path.join(ProjectPath.ExtensionFolder, extName); | ||
const serverExt = path.join(extPath, 'server.js'); | ||
if (!fs.existsSync(serverExt)) { | ||
continue; | ||
} | ||
// eslint-disable-next-line @typescript-eslint/no-var-requires | ||
const ext = require(serverExt); | ||
await fn(ext, extName); | ||
} | ||
} | ||
|
||
private createExtensionObject(): IExtensionObject { | ||
return { | ||
app: { | ||
objectManagers: ObjectManagers.getInstance(), | ||
config: Config, | ||
paths: ProjectPath, | ||
expressApp: Server.getInstance().app | ||
}, | ||
events: null | ||
}; | ||
} | ||
|
||
private async initExtensions() { | ||
await this.callServerFN(async (ext, extName) => { | ||
if (typeof ext?.init === 'function') { | ||
Logger.debug(LOG_TAG, 'Running Init on extension:' + extName); | ||
await ext?.init(this.createExtensionObject()); | ||
} | ||
}); | ||
} | ||
|
||
private async cleanUpExtensions() { | ||
await this.callServerFN(async (ext, extName) => { | ||
if (typeof ext?.cleanUp === 'function') { | ||
Logger.debug(LOG_TAG, 'Running Init on extension:' + extName); | ||
await ext?.cleanUp(); | ||
} | ||
}); | ||
} | ||
|
||
|
||
public async cleanUp() { | ||
await this.cleanUpExtensions(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import * as express from 'express'; | ||
import {PrivateConfigClass} from '../../../common/config/private/Config'; | ||
import {ObjectManagers} from '../ObjectManagers'; | ||
import {ProjectPathClass} from '../../ProjectPath'; | ||
import {ExtensionEvent} from './ExtensionEvent'; | ||
|
||
|
||
export type IExtensionBeforeEventHandler<I, O> = (input: { inputs: I }, event: { stopPropagation: boolean }) => Promise<{ inputs: I } | O>; | ||
export type IExtensionAfterEventHandler<O> = (output: O) => Promise<O>; | ||
|
||
|
||
export interface IExtensionEvent<I, O> { | ||
before: (handler: IExtensionBeforeEventHandler<I, O>) => void; | ||
after: (handler: IExtensionAfterEventHandler<O>) => void | ||
} | ||
|
||
export interface IExtensionEvents { | ||
gallery: { | ||
// indexing: IExtensionEvent<any, any>; | ||
// scanningDirectory: IExtensionEvent<any, any>; | ||
MetadataLoader: { | ||
loadPhotoMetadata: IExtensionEvent<any, any> | ||
} | ||
|
||
//listingDirectory: IExtensionEvent<any, any>; | ||
//searching: IExtensionEvent<any, any>; | ||
}; | ||
} | ||
|
||
export interface IExtensionApp { | ||
expressApp: express.Express; | ||
config: PrivateConfigClass; | ||
objectManagers: ObjectManagers; | ||
paths: ProjectPathClass; | ||
} | ||
|
||
export interface IExtensionObject { | ||
app: IExtensionApp; | ||
events: IExtensionEvents; | ||
} | ||
|
||
export interface IServerExtension { | ||
init(app: IExtensionObject): Promise<void>; | ||
|
||
cleanUp?: () => Promise<void>; | ||
} |
Oops, something went wrong.