use reflect-metadata for decorators, fix npm version checker, support gzip and deflate in http

This commit is contained in:
Evert Prants 2023-04-15 09:21:50 +03:00
parent 3337222bdf
commit 320e4cef84
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
11 changed files with 80 additions and 44 deletions

15
package-lock.json generated
View File

@ -1,16 +1,17 @@
{ {
"name": "@squeebot/core", "name": "@squeebot/core",
"version": "3.3.5", "version": "3.4.1",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@squeebot/core", "name": "@squeebot/core",
"version": "3.3.5", "version": "3.4.1",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"dateformat": "^4.5.1", "dateformat": "^4.5.1",
"fs-extra": "^10.0.0", "fs-extra": "^10.0.0",
"reflect-metadata": "^0.1.13",
"semver": "^7.3.5", "semver": "^7.3.5",
"tar": "^6.1.11" "tar": "^6.1.11"
}, },
@ -1410,6 +1411,11 @@
} }
] ]
}, },
"node_modules/reflect-metadata": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
"integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg=="
},
"node_modules/regexpp": { "node_modules/regexpp": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
@ -2719,6 +2725,11 @@
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
"dev": true "dev": true
}, },
"reflect-metadata": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
"integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg=="
},
"regexpp": { "regexpp": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",

View File

@ -1,6 +1,6 @@
{ {
"name": "@squeebot/core", "name": "@squeebot/core",
"version": "3.4.1", "version": "3.5.0",
"description": "Squeebot v3 core for the execution environment", "description": "Squeebot v3 core for the execution environment",
"main": "lib/index.js", "main": "lib/index.js",
"types": "lib/index.d.ts", "types": "lib/index.d.ts",
@ -30,6 +30,7 @@
"dependencies": { "dependencies": {
"dateformat": "^4.5.1", "dateformat": "^4.5.1",
"fs-extra": "^10.0.0", "fs-extra": "^10.0.0",
"reflect-metadata": "^0.1.13",
"semver": "^7.3.5", "semver": "^7.3.5",
"tar": "^6.1.11" "tar": "^6.1.11"
} }

View File

@ -1,7 +1,9 @@
import http, { RequestOptions } from 'http'; import http, { RequestOptions } from 'http';
import https from 'https'; import https from 'https';
import fs from 'fs-extra'; import fs from 'fs-extra';
import { createGunzip, createInflate } from 'zlib';
import { URL } from 'url'; import { URL } from 'url';
import { Readable } from 'stream';
/** /**
* Create an HTTP GET request. * Create an HTTP GET request.
@ -87,11 +89,27 @@ export function httpGET(
reject(new Error('Request took too long!')); reject(new Error('Request took too long!'));
}, 5000); }, 5000);
res.on('data', (chunk) => { let output: Readable = res;
// Decompress GZip
if (res.headers['content-encoding'] === 'gzip') {
const gzip = createGunzip();
res.pipe(gzip);
output = gzip;
}
// Deflate
if (res.headers['content-encoding'] === 'deflate') {
const inflate = createInflate();
res.pipe(inflate);
output = inflate;
}
output.on('data', (chunk) => {
data += chunk; data += chunk;
}); });
res.on('end', () => { output.on('end', () => {
clearTimeout(reqTimeOut); clearTimeout(reqTimeOut);
resolve(data || saveTo); resolve(data || saveTo);

View File

@ -65,10 +65,10 @@ export class NPMExecutor {
const pkgRefSplit = pkg.split('@'); const pkgRefSplit = pkg.split('@');
const pkgFullName = (spi === 1 ? '@' : '') + pkgRefSplit[spi]; const pkgFullName = (spi === 1 ? '@' : '') + pkgRefSplit[spi];
const pkgVersion = this.removeVersionWildcard(pkgRefSplit[spi + 1]); const pkgVersion = this.removeVersionWildcard(pkgRefSplit[spi + 1]) || 'latest';
const installedVersion = this.installed[pkgFullName]; const installedVersion = this.installed[pkgFullName];
if (installedVersion && installedVersion !== 'latest' && pkgVersion !== 'latest') { if (installedVersion && installedVersion !== 'latest' && pkgVersion !== 'latest') {
const cardless = this.removeVersionWildcard(installedVersion); const cardless = this.removeVersionWildcard(installedVersion) as string;
if (semver.lte(pkgVersion, cardless)) { if (semver.lte(pkgVersion, cardless)) {
return; return;
} }
@ -101,7 +101,7 @@ export class NPMExecutor {
await this.loadPackageFile(); await this.loadPackageFile();
} }
private removeVersionWildcard(str: string): string { private removeVersionWildcard(str?: string): string | undefined {
return str.replace(/\^|>|=/, ''); return str?.replace(/\^|>|=/, '');
} }
} }

View File

@ -1,14 +1,19 @@
import 'reflect-metadata';
/** /**
* Automatically execute method on plugin initialization * Automatically execute method on plugin initialization
*/ */
export function Auto(): (...args: any[]) => void { export function Auto() {
return ( return (
target: any, target: any,
propertyKey: string, propertyKey: string,
descriptor: PropertyDescriptor, descriptor: PropertyDescriptor,
) => { ) => {
descriptor.value.prototype.__autoexec = 1; let autorunners: Array<string> = Reflect.getMetadata('sb:autorunners', target);
if (!autorunners) {
Reflect.defineMetadata('sb:autorunners', autorunners = [], target);
}
autorunners.push(propertyKey);
return descriptor; return descriptor;
}; };
} }

View File

@ -1,10 +1,11 @@
import 'reflect-metadata';
/** /**
* Declare this plugin as one that the user can configure. * Declare this plugin as one that the user can configure.
* @param defconf Default configuration * @param defconf Default configuration
*/ */
export function Configurable(defconf: any): (...arg: any[]) => any { export function Configurable(defconf: any) {
return (constructor: (...arg: any[]) => any): void => { return (constructor: any): void => {
constructor.prototype.__defconf = defconf; Reflect.defineMetadata('sb:defconf', defconf, constructor);
}; };
} }

View File

@ -1,9 +1,10 @@
import { Auto } from './auto';
/** /**
* Fire the following method automatically when a dependency is (re)loaded. * Fire the following method automatically when a dependency is (re)loaded.
* @param dep Name of the dependency * @param dependency Name of the dependency
*/ */
export function DependencyLoad(dep: string): (...args: any[]) => void { export function DependencyLoad(dependency: string) {
return ( return (
target: any, target: any,
propertyKey: string, propertyKey: string,
@ -17,23 +18,23 @@ export function DependencyLoad(dep: string): (...args: any[]) => void {
return; return;
} }
const nameof = plugin.manifest.name; const nameof = plugin.manifest.name;
if (nameof !== dep) { if (nameof !== dependency) {
return; return;
} }
originalMethod.call(self, plugin); originalMethod.call(self, plugin);
}); });
}; };
// Set the function to be autoexecuted when the plugin is initialized. // Set the function to be autoexecuted when the plugin is initialized.
descriptor.value.prototype.__autoexec = 1; Auto()(target, propertyKey, descriptor);
return descriptor; return descriptor;
}; };
} }
/** /**
* Fire the following method automatically when a dependency is unloaded. * Fire the following method automatically when a dependency is unloaded.
* @param dep Name of the dependency * @param dependency Name of the dependency
*/ */
export function DependencyUnload(dep: string): (...args: any[]) => void { export function DependencyUnload(dependency: string) {
return ( return (
target: any, target: any,
propertyKey: string, propertyKey: string,
@ -47,13 +48,14 @@ export function DependencyUnload(dep: string): (...args: any[]) => void {
if (typeof plugin !== 'string') { if (typeof plugin !== 'string') {
nameof = plugin.manifest.name; nameof = plugin.manifest.name;
} }
if (nameof !== dep) { if (nameof !== dependency) {
return; return;
} }
originalMethod.call(self, plugin); originalMethod.call(self, plugin);
}); });
}; };
descriptor.value.prototype.__autoexec = 1; // Set the function to be autoexecuted when the plugin is initialized.
Auto()(target, propertyKey, descriptor);
return descriptor; return descriptor;
}; };
} }

View File

@ -1,9 +1,10 @@
import { Auto } from './auto';
/** /**
* Listen for an event targeted towards this plugin. * Listen for an event targeted towards this plugin.
* @param event Event name * @param event Event name
*/ */
export function EventListener(event: string): (...args: any[]) => void { export function EventListener(event: string) {
return ( return (
target: any, target: any,
propertyKey: string, propertyKey: string,
@ -19,7 +20,7 @@ export function EventListener(event: string): (...args: any[]) => void {
); );
}; };
// Set the function to be autoexecuted when the plugin is initialized. // Set the function to be autoexecuted when the plugin is initialized.
descriptor.value.prototype.__autoexec = 1; Auto()(target, propertyKey, descriptor);
return descriptor; return descriptor;
}; };
} }

View File

@ -1,10 +1,11 @@
import 'reflect-metadata';
/** /**
* Declare this plugin as one that utilises services. * Declare this plugin as one that utilises services.
* @param servtype Service class, usually a Protocol * @param injectedService Service class, usually a Protocol
*/ */
export function InjectService(servtype: any): (...arg: any[]) => any { export function InjectService(injectedService: any) {
return (constructor: (...arg: any[]) => any): void => { return (constructor: any): void => {
constructor.prototype.__service = servtype; Reflect.defineMetadata('sb:service', injectedService, constructor);
}; };
} }

View File

@ -1,3 +1,4 @@
import 'reflect-metadata';
import * as path from 'path'; import * as path from 'path';
import { IEnvironment, Service } from '../types'; import { IEnvironment, Service } from '../types';
import { IPlugin, IPluginManifest } from './plugin'; import { IPlugin, IPluginManifest } from './plugin';
@ -232,8 +233,8 @@ export class PluginManager {
} }
// Find default configuration, if it's configured, load the configuration // Find default configuration, if it's configured, load the configuration
if (PluginModule.prototype.__defconf && config) { if (Reflect.hasOwnMetadata('sb:defconf', PluginModule) && config) {
config.setDefaults(PluginModule.prototype.__defconf); config.setDefaults(Reflect.getOwnMetadata('sb:defconf', PluginModule));
await config.load(); await config.load();
} }
@ -242,8 +243,8 @@ export class PluginManager {
const loaded = new PluginModule(plugin, this.stream, config); const loaded = new PluginModule(plugin, this.stream, config);
try { try {
// Give the plugin a service // Give the plugin a service
if (PluginModule.prototype.__service) { if (Reflect.hasOwnMetadata('sb:service', PluginModule)) {
loaded.service = new Service(PluginModule.prototype.__service); loaded.service = new Service(Reflect.getOwnMetadata('sb:service', PluginModule));
} }
// Call the initializer // Call the initializer
@ -252,17 +253,12 @@ export class PluginManager {
} }
// Call methods that are supposed to be executed automatically on load. // Call methods that are supposed to be executed automatically on load.
// This is really nasty and probably shouldn't be done, but I don't care! const autorunFunctions: Array<string> = Reflect.getOwnMetadata('sb:autorunners', PluginModule.prototype);
for (const name of Object.getOwnPropertyNames(PluginModule.prototype)) { if (autorunFunctions?.length) {
// Prevent double initialization for (const autoFunction of autorunFunctions) {
if (name === 'initialize') { if (!loaded[autoFunction]) continue;
continue; if (autoFunction === 'initialize') continue;
} loaded[autoFunction].call(loaded);
if (PluginModule.prototype[name] &&
PluginModule.prototype[name].prototype &&
PluginModule.prototype[name].prototype.__autoexec) {
loaded[name].call(loaded);
} }
} }
} catch (e: any) { } catch (e: any) {

View File

@ -11,7 +11,7 @@ export * from './checksum';
*/ */
export function requireNoCache(file: string): object | undefined { export function requireNoCache(file: string): object | undefined {
const fullPath = path.resolve(file); const fullPath = path.resolve(file);
// TODO: maybe use new "import" function? // TODO: maybe use new "import" function? <- currently has no cache invalidation
// eslint-disable-next-line @typescript-eslint/no-var-requires // eslint-disable-next-line @typescript-eslint/no-var-requires
const mod = require(fullPath); const mod = require(fullPath);
if (require.cache && require.cache[fullPath]) { if (require.cache && require.cache[fullPath]) {