@push.rocks/smartproxy
Version:
A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.
211 lines • 14.5 kB
JavaScript
/**
* Base class for components that need proper resource lifecycle management
* Provides automatic cleanup of timers and event listeners to prevent memory leaks
*/
export class LifecycleComponent {
constructor() {
this.timers = new Set();
this.intervals = new Set();
this.listeners = [];
this.childComponents = new Set();
this.isShuttingDown = false;
}
/**
* Create a managed setTimeout that will be automatically cleaned up
*/
setTimeout(handler, timeout) {
if (this.isShuttingDown) {
// Return a dummy timer if shutting down
const dummyTimer = setTimeout(() => { }, 0);
if (typeof dummyTimer.unref === 'function') {
dummyTimer.unref();
}
return dummyTimer;
}
const wrappedHandler = () => {
this.timers.delete(timer);
if (!this.isShuttingDown) {
handler();
}
};
const timer = setTimeout(wrappedHandler, timeout);
this.timers.add(timer);
// Allow process to exit even with timer
if (typeof timer.unref === 'function') {
timer.unref();
}
return timer;
}
/**
* Create a managed setInterval that will be automatically cleaned up
*/
setInterval(handler, interval) {
if (this.isShuttingDown) {
// Return a dummy timer if shutting down
const dummyTimer = setInterval(() => { }, interval);
if (typeof dummyTimer.unref === 'function') {
dummyTimer.unref();
}
clearInterval(dummyTimer); // Clear immediately since we don't need it
return dummyTimer;
}
const wrappedHandler = () => {
if (!this.isShuttingDown) {
handler();
}
};
const timer = setInterval(wrappedHandler, interval);
this.intervals.add(timer);
// Allow process to exit even with timer
if (typeof timer.unref === 'function') {
timer.unref();
}
return timer;
}
/**
* Clear a managed timeout
*/
clearTimeout(timer) {
clearTimeout(timer);
this.timers.delete(timer);
}
/**
* Clear a managed interval
*/
clearInterval(timer) {
clearInterval(timer);
this.intervals.delete(timer);
}
/**
* Add a managed event listener that will be automatically removed on cleanup
*/
addEventListener(target, event, handler, options) {
if (this.isShuttingDown) {
return;
}
// For 'once' listeners, we need to wrap the handler to remove it from our tracking
let actualHandler = handler;
if (options?.once) {
actualHandler = (...args) => {
// Call the original handler
handler(...args);
// Remove from our internal tracking
const index = this.listeners.findIndex(l => l.target === target && l.event === event && l.handler === handler);
if (index !== -1) {
this.listeners.splice(index, 1);
}
};
}
// Support both EventEmitter and DOM-style event targets
if (typeof target.on === 'function') {
if (options?.once) {
target.once(event, actualHandler);
}
else {
target.on(event, actualHandler);
}
}
else if (typeof target.addEventListener === 'function') {
target.addEventListener(event, actualHandler, options);
}
else {
throw new Error('Target must support on() or addEventListener()');
}
// Store both the original handler and the actual handler registered
this.listeners.push({
target,
event,
handler,
actualHandler, // The handler that was actually registered (may be wrapped)
once: options?.once
});
}
/**
* Remove a specific event listener
*/
removeEventListener(target, event, handler) {
// Remove from target
if (typeof target.removeListener === 'function') {
target.removeListener(event, handler);
}
else if (typeof target.removeEventListener === 'function') {
target.removeEventListener(event, handler);
}
// Remove from our tracking
const index = this.listeners.findIndex(l => l.target === target && l.event === event && l.handler === handler);
if (index !== -1) {
this.listeners.splice(index, 1);
}
}
/**
* Register a child component that should be cleaned up when this component is cleaned up
*/
registerChildComponent(component) {
this.childComponents.add(component);
}
/**
* Unregister a child component
*/
unregisterChildComponent(component) {
this.childComponents.delete(component);
}
/**
* Override this method to implement component-specific cleanup logic
*/
async onCleanup() {
// Override in subclasses
}
/**
* Clean up all managed resources
*/
async cleanup() {
// Return existing cleanup promise if already cleaning up
if (this.cleanupPromise) {
return this.cleanupPromise;
}
this.cleanupPromise = this.performCleanup();
return this.cleanupPromise;
}
async performCleanup() {
this.isShuttingDown = true;
// First, clean up child components
const childCleanupPromises = [];
for (const child of this.childComponents) {
childCleanupPromises.push(child.cleanup());
}
await Promise.all(childCleanupPromises);
this.childComponents.clear();
// Clear all timers
for (const timer of this.timers) {
clearTimeout(timer);
}
this.timers.clear();
// Clear all intervals
for (const timer of this.intervals) {
clearInterval(timer);
}
this.intervals.clear();
// Remove all event listeners
for (const { target, event, handler, actualHandler } of this.listeners) {
// Use actualHandler if available (for wrapped handlers), otherwise use the original handler
const handlerToRemove = actualHandler || handler;
// All listeners need to be removed, including 'once' listeners that might not have fired
if (typeof target.removeListener === 'function') {
target.removeListener(event, handlerToRemove);
}
else if (typeof target.removeEventListener === 'function') {
target.removeEventListener(event, handlerToRemove);
}
}
this.listeners = [];
// Call subclass cleanup
await this.onCleanup();
}
/**
* Check if the component is shutting down
*/
isShuttingDownState() {
return this.isShuttingDown;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlmZWN5Y2xlLWNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL2NvcmUvdXRpbHMvbGlmZWN5Y2xlLWNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0dBR0c7QUFDSCxNQUFNLE9BQWdCLGtCQUFrQjtJQUF4QztRQUNVLFdBQU0sR0FBd0IsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUN4QyxjQUFTLEdBQXdCLElBQUksR0FBRyxFQUFFLENBQUM7UUFDM0MsY0FBUyxHQU1aLEVBQUUsQ0FBQztRQUNBLG9CQUFlLEdBQTRCLElBQUksR0FBRyxFQUFFLENBQUM7UUFDbkQsbUJBQWMsR0FBRyxLQUFLLENBQUM7SUEyT25DLENBQUM7SUF4T0M7O09BRUc7SUFDTyxVQUFVLENBQUMsT0FBaUIsRUFBRSxPQUFlO1FBQ3JELElBQUksSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ3hCLHdDQUF3QztZQUN4QyxNQUFNLFVBQVUsR0FBRyxVQUFVLENBQUMsR0FBRyxFQUFFLEdBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1lBQzNDLElBQUksT0FBTyxVQUFVLENBQUMsS0FBSyxLQUFLLFVBQVUsRUFBRSxDQUFDO2dCQUMzQyxVQUFVLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDckIsQ0FBQztZQUNELE9BQU8sVUFBVSxDQUFDO1FBQ3BCLENBQUM7UUFFRCxNQUFNLGNBQWMsR0FBRyxHQUFHLEVBQUU7WUFDMUIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDMUIsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztnQkFDekIsT0FBTyxFQUFFLENBQUM7WUFDWixDQUFDO1FBQ0gsQ0FBQyxDQUFDO1FBRUYsTUFBTSxLQUFLLEdBQUcsVUFBVSxDQUFDLGNBQWMsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUNsRCxJQUFJLENBQUMsTUFBTSxDQUFDLEdB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