1
0
mirror of https://github.com/bpatrik/pigallery2.git synced 2024-12-25 02:04:15 +02:00

Adding package.json support with dependency #753

This commit is contained in:
Patrik J. Braun 2023-11-17 23:36:14 +01:00
parent 3cf45c56b5
commit 9f5257626f
5 changed files with 88 additions and 35 deletions

23
package-lock.json generated
View File

@ -22,6 +22,7 @@
"fluent-ffmpeg": "2.1.2",
"image-size": "1.0.2",
"locale": "0.1.0",
"logger": "file:extensions/logger",
"node-geocoder": "4.2.0",
"nodemailer": "6.9.4",
"reflect-metadata": "0.1.13",
@ -131,6 +132,12 @@
"mysql": "2.18.1"
}
},
"extensions/logger": {
"version": "1.0.0",
"dependencies": {
"lodash": "4.17.21"
}
},
"node_modules/@ampproject/remapping": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
@ -15585,8 +15592,7 @@
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lodash-es": {
"version": "4.17.21",
@ -15843,6 +15849,10 @@
"node": ">=8.0"
}
},
"node_modules/logger": {
"resolved": "extensions/logger",
"link": true
},
"node_modules/loupe": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz",
@ -35932,8 +35942,7 @@
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"lodash-es": {
"version": "4.17.21",
@ -36137,6 +36146,12 @@
"streamroller": "^3.0.6"
}
},
"logger": {
"version": "file:extensions/logger",
"requires": {
"lodash": "4.17.21"
}
},
"loupe": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz",

View File

@ -48,6 +48,7 @@
"fluent-ffmpeg": "2.1.2",
"image-size": "1.0.2",
"locale": "0.1.0",
"logger": "file:extensions/logger",
"node-geocoder": "4.2.0",
"nodemailer": "6.9.4",
"reflect-metadata": "0.1.13",

View File

@ -11,6 +11,9 @@ import * as express from 'express';
import {SQLConnection} from '../database/SQLConnection';
import {ExtensionObject} from './ExtensionObject';
import {ExtensionDecoratorObject} from './ExtensionDecorator';
import * as util from 'util';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const exec = util.promisify(require('child_process').exec);
const LOG_TAG = '[ExtensionManager]';
@ -76,35 +79,52 @@ export class ExtensionManager implements IObjectManager {
Logger.debug(LOG_TAG, 'Extensions found ', JSON.stringify(Config.Extensions.list));
}
private async callServerFN(fn: (ext: IServerExtension<unknown>, 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)) {
Logger.silly(LOG_TAG, `Skipping ${extName} server initiation. server.js does not exists`);
continue;
private createUniqueExtensionObject(name: string, folder: string): IExtensionObject<unknown> {
let id = name;
if (this.extObjects[id]) {
let i = 0;
while (this.extObjects[`${name}_${++i}`]) { /* empty */
}
// eslint-disable-next-line @typescript-eslint/no-var-requires
const ext = require(serverExt);
await fn(ext, extName);
id = `${name}_${++i}`;
}
if (!this.extObjects[id]) {
this.extObjects[id] = new ExtensionObject(id, name, folder, this.router, this.events);
}
private createExtensionObject(name: string): IExtensionObject<unknown> {
if (!this.extObjects[name]) {
this.extObjects[name] = new ExtensionObject(name, this.router, this.events);
}
return this.extObjects[name];
return this.extObjects[id];
}
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(extName));
for (let i = 0; i < Config.Extensions.list.length; ++i) {
const extFolder = Config.Extensions.list[i];
let extName = extFolder;
const extPath = path.join(ProjectPath.ExtensionFolder, extFolder);
const serverExtPath = path.join(extPath, 'server.js');
const packageJsonPath = path.join(extPath, 'package.json');
if (!fs.existsSync(serverExtPath)) {
Logger.silly(LOG_TAG, `Skipping ${extFolder} server initiation. server.js does not exists`);
continue;
}
if (fs.existsSync(packageJsonPath)) {
Logger.silly(LOG_TAG, `Running: "npm install --omit=dev" in ${extPath}`);
await exec('npm install --omit=dev' ,{
cwd:extPath
});
// eslint-disable-next-line @typescript-eslint/no-var-requires
const pkg = require(packageJsonPath);
if (pkg.name) {
extName = pkg.name;
}
}
// eslint-disable-next-line @typescript-eslint/no-var-requires
const ext = require(serverExtPath);
if (typeof ext?.init === 'function') {
Logger.debug(LOG_TAG, 'Running init on extension: ' + extFolder);
await ext?.init(this.createUniqueExtensionObject(extName, extPath));
}
}
if (Config.Extensions.cleanUpUnusedTables) {
// Clean up tables after all Extension was initialized.
await SQLConnection.removeUnusedTables();
@ -112,12 +132,15 @@ export class ExtensionManager implements IObjectManager {
}
private async cleanUpExtensions() {
await this.callServerFN(async (ext, extName) => {
for (const extObj of Object.values(this.extObjects)) {
const serverExt = path.join(extObj.folder, 'server.js');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const ext = require(serverExt);
if (typeof ext?.cleanUp === 'function') {
Logger.debug(LOG_TAG, 'Running Init on extension:' + extName);
await ext?.cleanUp(this.createExtensionObject(extName));
Logger.debug(LOG_TAG, 'Running Init on extension:' + extObj.extensionName);
await ext?.cleanUp(ext);
}
}
});
}

View File

@ -17,7 +17,11 @@ export class ExtensionObject<C> implements IExtensionObject<C> {
public readonly events;
public readonly RESTApi;
constructor(public readonly extensionId: string, extensionRouter: express.Router, events: IExtensionEvents) {
constructor(public readonly extensionId: string,
public readonly extensionName: string,
public readonly folder: string,
extensionRouter: express.Router,
events: IExtensionEvents) {
const logger = createLoggerWrapper(`[Extension][${extensionId}]`);
this._app = new ExtensionApp();
this.config = new ExtensionConfig<C>(extensionId);

View File

@ -117,6 +117,16 @@ export interface IExtensionConfig<C> {
}
export interface IExtensionObject<C> {
/**
* ID of the extension that is internally used. By default the name and ID matches if there is no collision.
*/
extensionId: string,
/**
* Name of the extension
*/
extensionName: string,
/**
* Inner functionality of the app. Use this with caution.
* If you want to go deeper than the standard exposed APIs, you can try doing so here.