initial commit

This commit is contained in:
Pierre
2026-01-11 17:26:49 +01:00
commit 888790fd11
240 changed files with 48691 additions and 0 deletions
+10
View File
@@ -0,0 +1,10 @@
export function makeid(length) {
let result = '';
let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let charactersLength = characters.length;
for ( let i = 0; i < length; i++ ) {
result += characters.charAt(Math.floor(Math.random() *
charactersLength));
}
return result;
}
+2
View File
@@ -0,0 +1,2 @@
export type Lazy<T> = () => Promise<T>;
@@ -0,0 +1,23 @@
export class ListenerCleaner {
cleaners: (() => void)[] = [];
add(cleanerCallback: () => void) {
this.cleaners.push(cleanerCallback);
}
cleaner(): () => void {
return () => {
this.cleanUp();
}
}
/**
* Call all the cleaner callbacks and reset this cleaner to be reused.
*/
cleanUp() {
for (const cleaner of this.cleaners) {
cleaner();
}
this.cleaners = [];
}
}
+66
View File
@@ -0,0 +1,66 @@
import {PromiseQueue} from "./PromiseQueue";
export class MultiQueue<T> {
private readonly queues:PromiseQueue<T>[];
/**
*
* @param concurrentTask
*/
constructor(
concurrentTask:number=1,
) {
if (concurrentTask<1){
throw new Error("concurrentTask must be >=1");
}
this.queues = [];
for(let i=0;i<concurrentTask;i++){
this.queues.push(new PromiseQueue<T>());
}
}
public getQueueSize(): number {
let ret = 0;
for(let queue of this.queues){
ret+=queue.getQueueSize();
}
return ret;
}
public async awaitQueueEmpty(){
for(let queue of this.queues){
await queue.awaitQueueEmpty();
}
}
/**
* Add a task to the queue. The queue with the smallest task size is used
* @param task
* @param id
**/
public add(task: () => Promise<T>, id: string = null): { id: string, promise: Promise<T> } {
let queue = this.queues[0];
for(let i=1;i<this.queues.length;i++){
if(this.queues[i].getQueueSize()<queue.getQueueSize()){
queue = this.queues[i];
}
}
return queue.add(task,id);
}
public cancel(id: string) {
for(let queue of this.queues){
queue.cancel(id);
}
}
/**
* The last task in progress is not canceled
*/
public async cancelAll(){
for(let queue of this.queues){
await queue.cancelAll();
}
}
}
+80
View File
@@ -0,0 +1,80 @@
import {makeid} from "./Id";
export class PromiseQueue<T> {
private nextPromise: Promise<T> = Promise.resolve(null);
private canceled = {};
private queueSize = 0;
private queueID = 0;
/**
*
* @param onlyLast if true all task are cancel and only the last one is keep alive (a task started still finishes)
*/
constructor(
private onlyLast: boolean = false
) {
this.cancelAll();
}
getQueueSize(): number {
return this.queueSize;
}
async awaitQueueEmpty(){
await this.nextPromise;//await the current promise
while (this.queueSize!=0){//await all the fowllofing promise
await this.nextPromise;
}
}
add(task: () => Promise<T>, id: string = null): { id: string, promise: Promise<T> } {
if (!id) {
id = "promise-" + makeid(8);
}
let lastPromise = this.nextPromise;
this.queueSize++;
let currentID = this.queueID;
let currentPromise=null;
currentPromise = (async () => {
this.queueSize--;
try {
await lastPromise;
}catch (e) {
/* ignore error of previous promise*/
}
if(currentID!==this.queueID){
throw new Error("canceled caused by new queue");
}
if (this.canceled[id]) {
delete this.canceled[id];
throw new Error("canceled by user");
}
if(this.onlyLast && currentPromise!=this.nextPromise){
throw new Error("canceled caused by not last");
}
//execute task and return result
return task();
})();
currentPromise.catch(e=>{
/* we catch the exception this way to avoid an uncaught exception in the console*/
});
this.nextPromise = currentPromise
return {id, promise: this.nextPromise};
}
cancel(id: string) {
this.canceled[id] = true;
}
/**
* The last task in progress is not canceled
*/
async cancelAll(){
this.queueID++;//create a new queue will cancel all previous task except the one in progress
await this.awaitQueueEmpty();
this.nextPromise = Promise.resolve(null);
this.canceled = {};
this.queueSize = 0;
}
}
+5
View File
@@ -0,0 +1,5 @@
export * from "./ListenerCleaner";
export * from "./PromiseQueue";
export * from "./MultiQueue";
export * from "./Id";
export * from "./Lazy";