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",
"version": "3.3.5",
"version": "3.4.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@squeebot/core",
"version": "3.3.5",
"version": "3.4.1",
"license": "MIT",
"dependencies": {
"dateformat": "^4.5.1",
"fs-extra": "^10.0.0",
"reflect-metadata": "^0.1.13",
"semver": "^7.3.5",
"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": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
@ -2719,6 +2725,11 @@
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
"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": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",

View File

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

View File

@ -1,7 +1,9 @@
import http, { RequestOptions } from 'http';
import https from 'https';
import fs from 'fs-extra';
import { createGunzip, createInflate } from 'zlib';
import { URL } from 'url';
import { Readable } from 'stream';
/**
* Create an HTTP GET request.
@ -87,11 +89,27 @@ export function httpGET(
reject(new Error('Request took too long!'));
}, 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;
});
res.on('end', () => {
output.on('end', () => {
clearTimeout(reqTimeOut);
resolve(data || saveTo);

View File

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

View File

@ -1,14 +1,19 @@
import 'reflect-metadata';
/**
* Automatically execute method on plugin initialization
*/
export function Auto(): (...args: any[]) => void {
export function Auto() {
return (
target: any,
propertyKey: string,
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;
};
}

View File

@ -1,10 +1,11 @@
import 'reflect-metadata';
/**
* Declare this plugin as one that the user can configure.
* @param defconf Default configuration
*/
export function Configurable(defconf: any): (...arg: any[]) => any {
return (constructor: (...arg: any[]) => any): void => {
constructor.prototype.__defconf = defconf;
export function Configurable(defconf: any) {
return (constructor: any): void => {
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.
* @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 (
target: any,
propertyKey: string,
@ -17,23 +18,23 @@ export function DependencyLoad(dep: string): (...args: any[]) => void {
return;
}
const nameof = plugin.manifest.name;
if (nameof !== dep) {
if (nameof !== dependency) {
return;
}
originalMethod.call(self, plugin);
});
};
// Set the function to be autoexecuted when the plugin is initialized.
descriptor.value.prototype.__autoexec = 1;
Auto()(target, propertyKey, descriptor);
return descriptor;
};
}
/**
* 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 (
target: any,
propertyKey: string,
@ -47,13 +48,14 @@ export function DependencyUnload(dep: string): (...args: any[]) => void {
if (typeof plugin !== 'string') {
nameof = plugin.manifest.name;
}
if (nameof !== dep) {
if (nameof !== dependency) {
return;
}
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;
};
}

View File

@ -1,9 +1,10 @@
import { Auto } from './auto';
/**
* Listen for an event targeted towards this plugin.
* @param event Event name
*/
export function EventListener(event: string): (...args: any[]) => void {
export function EventListener(event: string) {
return (
target: any,
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.
descriptor.value.prototype.__autoexec = 1;
Auto()(target, propertyKey, descriptor);
return descriptor;
};
}

View File

@ -1,10 +1,11 @@
import 'reflect-metadata';
/**
* 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 {
return (constructor: (...arg: any[]) => any): void => {
constructor.prototype.__service = servtype;
export function InjectService(injectedService: any) {
return (constructor: any): void => {
Reflect.defineMetadata('sb:service', injectedService, constructor);
};
}

View File

@ -1,3 +1,4 @@
import 'reflect-metadata';
import * as path from 'path';
import { IEnvironment, Service } from '../types';
import { IPlugin, IPluginManifest } from './plugin';
@ -232,8 +233,8 @@ export class PluginManager {
}
// Find default configuration, if it's configured, load the configuration
if (PluginModule.prototype.__defconf && config) {
config.setDefaults(PluginModule.prototype.__defconf);
if (Reflect.hasOwnMetadata('sb:defconf', PluginModule) && config) {
config.setDefaults(Reflect.getOwnMetadata('sb:defconf', PluginModule));
await config.load();
}
@ -242,8 +243,8 @@ export class PluginManager {
const loaded = new PluginModule(plugin, this.stream, config);
try {
// Give the plugin a service
if (PluginModule.prototype.__service) {
loaded.service = new Service(PluginModule.prototype.__service);
if (Reflect.hasOwnMetadata('sb:service', PluginModule)) {
loaded.service = new Service(Reflect.getOwnMetadata('sb:service', PluginModule));
}
// Call the initializer
@ -252,17 +253,12 @@ export class PluginManager {
}
// 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!
for (const name of Object.getOwnPropertyNames(PluginModule.prototype)) {
// Prevent double initialization
if (name === 'initialize') {
continue;
}
if (PluginModule.prototype[name] &&
PluginModule.prototype[name].prototype &&
PluginModule.prototype[name].prototype.__autoexec) {
loaded[name].call(loaded);
const autorunFunctions: Array<string> = Reflect.getOwnMetadata('sb:autorunners', PluginModule.prototype);
if (autorunFunctions?.length) {
for (const autoFunction of autorunFunctions) {
if (!loaded[autoFunction]) continue;
if (autoFunction === 'initialize') continue;
loaded[autoFunction].call(loaded);
}
}
} catch (e: any) {

View File

@ -11,7 +11,7 @@ export * from './checksum';
*/
export function requireNoCache(file: string): object | undefined {
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
const mod = require(fullPath);
if (require.cache && require.cache[fullPath]) {