@freemework/common
Version:
Common library of the Freemework Project.
66 lines (56 loc) • 1.98 kB
text/typescript
import { FLimit } from "../f_limit.js";
import { FLimitException } from "../f_limit_exception.js";
import { FInternalLimitSyncBase } from "./f_internal_limit_sync_base.js";
import { FInternalLimitTokenDeferred } from "./f_internal_limit_token_deferred.js";
type FLimitTokenDeferred = FInternalLimitTokenDeferred & { finalize: () => void };
export class FLimitInternalParallelLimit extends FInternalLimitSyncBase {
private readonly _maxWeight: number;
private _activeTokenDefers: Array<FInternalLimitTokenDeferred>;
public constructor(totalWeight: FLimit.Weight) {
super();
this._maxWeight = totalWeight;
this._activeTokenDefers = [];
}
public get availableWeight(): number {
if (super.disposed) { throw new Error("Wrong operation on disposed object"); }
return this._maxWeight - this._activeTokenDefers.reduce((p, c) => p + c.weight, 0);
}
public get maxWeight(): number {
if (super.disposed) { throw new Error("Wrong operation on disposed object"); }
return this._maxWeight;
}
public accrueToken(weight: FLimit.Weight): FLimit.Token {
super.verifyNotDisposed();
if (this.availableWeight < weight) { throw new FLimitException("No any available tokens"); }
let defer: FLimitTokenDeferred | null = null;
{ // local scope
const realDefer: FLimitTokenDeferred = {
...FInternalLimitTokenDeferred.create<void>(weight),
finalize: () => {
realDefer.resolve();
const index = this._activeTokenDefers.indexOf(realDefer);
this._activeTokenDefers.splice(index, 1);
this.raiseReleaseToken();
}
};
this._activeTokenDefers.push(realDefer);
defer = realDefer;
}
const token: FLimit.Token = {
commit: () => {
if (defer !== null) {
defer.finalize();
}
},
rollback: () => {
if (defer !== null) {
defer.finalize();
}
}
};
return token as FLimit.Token;
}
protected async onDispose(): Promise<void> {
await Promise.all(this._activeTokenDefers.map(d => d.promise));
}
}