slavery-js
Version:
A simple clustering app that allows you to scale an application on multiple thread, containers or machines
255 lines (219 loc) • 7.29 kB
text/typescript
import Queue from './Queue.js'
class Pool<T> {
/* *
* this class handle the socket connectd
* queue of sockets and manages connection with the workers
* */
private enabled: Queue<string>;
private disabled: string[];
private items: { [key: string]: T };
constructor() {
this.enabled = new Queue();
this.disabled = [];
this.items = {}
}
has( id: string ): boolean {
return this.items[id] ? true : false;
}
add( id: string, item: T ): boolean {
// if the item is already in the pool
if (this.has(id)) this.remove(id);
// add to the queue
this.enabled.enqueue(id);
// add the item to the pool
this.items[id] = item;
// return true
return false;
}
disable(id: string): boolean {
if( !this.has(id) ) return false;
// if it is in the disable list, job done
if( this.disabled.indexOf(id) !== -1 ) return true;
// if it is in the enabled list, remove it
if( this.enabled.indexOf(id) !== -1 ){
this.enabled.remove(id);
// add the slave to the disable list
this.disabled.push(id);
return true;
}
return false;
}
disableUntil(id: string, timeOrCondition: number | Function): undefined {
// if it is not in the pool, return false
if( !this.has(id) ) return;
// check if timeOrCondition is a number or a function
let time = null;
let condition : any = null;
if(typeof timeOrCondition === 'number')
time = timeOrCondition;
else if(typeof timeOrCondition === 'function')
condition = timeOrCondition;
else throw new Error('timeOrCondition must be a number or a function');
// if it is already disabled, we want to keep it disabled until the timeOrCondition is met
// if it is in the enabled list, disable it
if( this.enabled.indexOf(id) !== -1 ) this.disable(id);
// check that the id is in the disabled list
if( this.disabled.indexOf(id) === -1 ) throw new Error('id is not in the disabled list');
// if time is defined, set a timeout
if(time) setTimeout(() => this.enable(id), time);
// if condition is defined, set a interval
if(condition){
let interval = setInterval(() => {
if(condition()){
clearInterval(interval);
this.enable(id);
}
}, 100);
}
}
enable(id: string) : boolean {
// if it is not in the pool, return false
if( !this.has(id) ) return false;
// if it is already enabled, job done
if( this.enabled.indexOf(id) !== -1 ) return true;
// if it is in the disabled list, remove it
if( this.disabled.indexOf(id) !== -1 ){
// remove the slave from the disable list
this.disabled = this.disabled.filter( e => e !== id );
// add the slave to the queue
this.enabled.enqueue(id);
return true
}
return false;
}
nextAndEnable() : string | boolean {
// if the diabled list is empty, return false
if( this.disabled.length === 0 ) return false;
// get the first element of the disabled list
let id = this.disabled[0];
// and enable it
this.enable(id);
// return the id
return id;
}
rotate() : T | null {
// dequeue and enqueue
if(this.size() === 0) return null
const id = this.enabled.dequeue()
if(!id) return null
this.enabled.enqueue(id)
return this.items[id]
}
hasEnabled() : boolean {
return this.enabled.size() > 0;
}
nextAndDisable() : T | null { // dequeue and disable
if(this.size() === 0) return null
const id = this.enabled.dequeue();
if(!id) return null;
this.disabled.push(id);
return this.items[id];
}
// remove value while maintaining order
remove( id: string ) : T | null {
// look in the queue for the id
let result = this._lookUp(id);
if(result){
let index = result.index;
let list = result.list;
// remove the lists
if(list === 'enabled')
this.enabled.removeAt(index);
else
this.disabled.splice(index, 1);
// remove the items
let item = this.items[id];
delete this.items[id];
// return true
return item;
}
return null;
}
removeOne() : T | null {
// get the first element of the enabled list
if(this.enabled.size() > 0){
let id = this.enabled.dequeue();
if(id === undefined || id === false) return null;
// remove the item from the pool
let item = this.items[id];
delete this.items[id];
return item;
}
return null;
}
get( id: string ) : T | null {
/* get the item from the pool */
if(!this.has(id)) return null;
return this.items[id];
}
// get the size of the pool
size() : number {
return Object.keys(this.items).length;
}
// lenght of the pool
length() : number {
return this.size();
}
// count the enabled elements
getEnabledCount() : number {
return this.enabled.size();
}
// count the disabled elements
getDisabledCount() : number {
return this.disabled.length;
}
// check if queue is empty
isEmpty() : boolean {
return this.size() === 0;
}
_lookUp( id : string ) : { index: number, list: string } | false {
// look in the queue for the id
let index = this.enabled.indexOf(id);
if(!(index === -1))
return { index, list: 'enabled' };
// look in the disable list for the id
index = this.disabled.indexOf(id);
if(!(index === -1))
return { index, list: 'disabled' };
return false;
}
toArray() : T[] {
return Object.values(this.items);
}
print() : void {
console.log(this.toArray());
}
getEnabled() : string[] {
return this.enabled.toArray();
}
getEnabledObjects() : T[] {
return this.enabled.toArray().map( id => this.items[id] );
}
getDisabled() : string[] {
return this.disabled;
}
getDisabledObjects() : T[] {
return this.disabled.map( id => this.items[id] );
}
getConnections() : string[] {
return Object.keys(this.items);
}
healthCheck() : boolean {
let total = this.size();
let enabled = this.getEnabled().length;
let disabled = this.getDisabled().length;
if(total === (enabled + disabled))
return true;
else return false;
}
// synonims
next = this.rotate
pop = this.nextAndDisable;
shift = this.nextAndEnable;
unshift = this.add;
push = this.add;
count = this.size;
removeAt = this.remove;
removeItem = this.remove;
}
export default Pool;