Add Code files

This commit is contained in:
Michael Fabian 'Xaymar' Dirks
2023-03-18 23:40:40 +01:00
parent e02cd32e52
commit 173aa63be5
10 changed files with 2009 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
*.json
*.css
/generated
+99
View File
@@ -0,0 +1,99 @@
{
"root": true,
"env": {
"browser": true,
"worker": true,
"es2020": true
},
"globals": {
"config": "readonly"
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module",
"impliedStrict": true
},
"plugins": [
"@typescript-eslint"
],
"rules": {
"brace-style": [
"warn",
"1tbs"
],
"dot-location": [
"warn",
"property"
],
"eol-last": [
"warn",
"always"
],
"indent": [
"error",
"tab"
],
"linebreak-style": "off",
"max-len": [
"off",
{
"code": 120,
"tabWidth": 4
}
],
"new-parens": [
"error",
"always"
],
"no-cond-assign": [
"error",
"except-parens"
],
"no-debugger": "warn",
"no-dupe-else-if": "error",
"no-empty": "warn",
"no-multiple-empty-lines": [
"warn",
{
"max": 1,
"maxEOF": 1,
"maxBOF": 0
}
],
"no-prototype-builtins": "warn",
"no-undef": "warn",
"no-unreachable": "warn",
"no-useless-catch": "warn",
"quotes": [
"error",
"double"
],
"semi": [
"error",
"always"
],
"semi-spacing": [
"warn",
{
"before": false,
"after": true
}
],
"semi-style": [
"warn",
"last"
],
"valid-typeof": "warn",
"vars-on-top": "warn",
"@typescript-eslint/no-inferrable-types": "off",
"@typescript-eslint/no-namespace": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-empty-function": "warn",
"@typescript-eslint/ban-ts-comment": "off"
}
}
+16
View File
@@ -0,0 +1,16 @@
# Git
/.git
/.gitignore
# Node, NPM, ESLint, TypeScript
/node_modules
/.eslintignore
/.eslintrc.json
/tsconfig.json
/*.tgz
.tsbuildinfo
# Development files
/.editorconfig
/.vscode
/workspace.code-workspace
+18
View File
@@ -0,0 +1,18 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}",
//"preLaunchTask": "tsc: build"
}
]
}
+42
View File
@@ -0,0 +1,42 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "install",
"group": "build",
"problemMatcher": [],
"label": "npm: install",
"detail": "Install dependencies via NPM"
},
{
"type": "npm",
"script": "clean-install",
"group": "build",
"problemMatcher": [],
"label": "npm: clean-install",
"detail": "Install dependencies via NPM cleanly"
},
{
"type": "npm",
"script": "fix",
"group": "build",
"problemMatcher": [],
"label": "eslint: fix",
"detail": "Let ESLint fix things."
},
{
"type": "npm",
"script": "build",
"problemMatcher": [
"$eslint-stylish",
"$tsc"
],
"group": {
"kind": "build",
"isDefault": true
},
"label": "tsc: build"
}
]
}
+1679
View File
File diff suppressed because it is too large Load Diff
+24
View File
@@ -0,0 +1,24 @@
{
"name": "@xaymar/ratelimiter",
"version": "0.1.0",
"description": "A simple but effective way to rate limit Tasks in JavaScript.",
"main": "generated/ratelimiter.js",
"scripts": {
"lint": "npx eslint ./source --ext .ts,.mts",
"fix": "npx eslint ./source --ext .ts,.mts --fix",
"compile": "npx tsc",
"build": "npm run fix && npm run compile",
"prepublish": "npm run build",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Michael Fabian 'Xaymar' Dirks <info@xaymar.com>",
"license": "GPLv3",
"devDependencies": {
"@types/express": "^4.17.17",
"@types/node": "^18.15.3",
"@typescript-eslint/eslint-plugin": "^5.43.0",
"@typescript-eslint/parser": "^5.43.0",
"eslint": "^8.27.0",
"typescript": "^4.9.3"
}
}
+95
View File
@@ -0,0 +1,95 @@
// Copyright (C) 2023, Michael Fabian Dirks <info@xaymar.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// --------------------------------------------------------------------------------
// Also available under a commercial license, contact info@xaymar.com for more information.
// --------------------------------------------------------------------------------
import os from "node:os";
interface RateLimiterInstance {
task?: Promise<any>,
solver?: Promise<any>,
}
export type RateLimiterAsyncExecutor = (...args: any[]) => Promise<any>;
export type RateLimiterSyncExecutor = (...args: any[]) => any;
export type RateLimiterExecutor = RateLimiterSyncExecutor | RateLimiterAsyncExecutor;
export class RateLimiter {
private _maximum: number = 0;
private _available: number = 0;
private _instances: any[];
constructor(limit?: number) {
if (!limit) {
this._maximum = Math.ceil(Math.max(1, os.cpus().length / 3 * 2));
} else {
this._maximum = limit;
}
this._available = this._maximum;
this._instances = [];
}
async queue(executor: RateLimiterExecutor, ...args: any[]) {
// Use async/await to find a free slot.
while (this._available == 0) {
await Promise.race(this._instances);
}
// Decrement the number of available slots.
--this._available;
// Once we have a slot, properly enqueue the work.
const data: RateLimiterInstance = {};
data.task = new Promise((resolve, reject) => {
try {
if (executor.constructor.name == "AsyncFunction") {
executor().then((res: any) => {
resolve(res);
}, (err: any) => {
reject(err);
});
} else {
resolve(executor(...args));
}
} catch (ex) {
reject(ex);
}
});
data.solver = data.task.finally(() => {
// Remove this promise from the locks list.
const taskIndex = this._instances.indexOf(data.task);
if (taskIndex >= 0) {
this._instances.splice(taskIndex, 1);
}
const solverIndex = this._instances.indexOf(data.solver);
if (solverIndex >= 0) {
this._instances.splice(solverIndex, 1);
}
// Increment the number of available slots again.
++this._available;
});
// Push this instance to the known instance list.
this._instances.push(data.solver);
// And return the result gained from running the runner.
return await data.solver;
}
}
+25
View File
@@ -0,0 +1,25 @@
{
"include": [
"./source/**/*"
],
"compilerOptions": {
"declaration": true,
"declarationDir": "generated",
"declarationMap": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"incremental": true,
"module": "NodeNext",
"moduleResolution": "NodeNext",
"outDir": "generated",
"removeComments": true,
"rootDir": "source",
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"strictNullChecks": true,
"target": "ES2020",
"tsBuildInfoFile": "./generated/.tsbuildinfo",
"useDefineForClassFields": true,
}
}
+8
View File
@@ -0,0 +1,8 @@
{
"folders": [
{
"path": "."
}
],
"settings": {}
}