Refactor Polling Mechanism: Implement Class-Based Poller with Start/Stop Control (#528)

* custom module updates to class based.

* Finish poller logic.

* Use composition for pollers

* Rename poller

* Handle recorder polling.

* Fix quotes in bash command

* Remove logs
This commit is contained in:
Jas Singh
2024-11-23 03:55:00 -08:00
committed by GitHub
parent c10c9d0e93
commit a4f5fb5917
26 changed files with 460 additions and 169 deletions

90
lib/poller/BashPoller.ts Normal file
View File

@@ -0,0 +1,90 @@
import { Variable as VariableType } from 'types/variable';
import { Bind } from 'lib/types/variable';
import { GenericFunction } from 'lib/types/customModules/generic';
import { BarModule } from 'lib/types/options';
import { Poller } from './Poller';
/**
* A class that manages polling of a variable by executing a bash command at specified intervals.
*/
export class BashPoller<Value, Parameters extends unknown[]> {
private poller: Poller;
private params: Parameters;
/**
* Creates an instance of BashPoller.
*
* @param targetVariable - The target variable to poll.
* @param trackers - An array of trackers to monitor.
* @param pollingInterval - The interval at which polling occurs.
* @param updateCommand - The command to update the target variable.
* @param pollingFunction - The function to execute during each poll.
* @param params - Additional parameters for the polling function.
*
* @example
*
* ```ts
* //##################### EXAMPLE ##########################
* const updatesPoller = new BashPoller<string, []>(
* pendingUpdates,
* [padZero.bind('value'), postInputUpdater.bind('value')],
* pollingInterval.bind('value'),
* updateCommand.value,
* processUpdateCount,
* );
* //#######################################################
*
* ```
*/
constructor(
private targetVariable: VariableType<Value>,
private trackers: Bind[],
private pollingInterval: Bind,
private updateCommand: string,
private pollingFunction: GenericFunction<Value, [string, ...Parameters]>,
...params: Parameters
) {
this.params = params;
this.poller = new Poller(this.pollingInterval, this.trackers, this.execute);
}
/**
* Executes the bash command specified in the updateCommand property.
*
* The result of the command is processed by the pollingFunction and
* assigned to the targetVariable.
*/
public execute = async (): Promise<void> => {
try {
const res = await Utils.execAsync(`bash -c "${this.updateCommand}"`);
this.targetVariable.value = await this.pollingFunction(res, ...this.params);
} catch (error) {
console.error(`Error executing bash command "${this.updateCommand}":`, error);
}
};
/**
* Starts the polling process.
*/
public start(): void {
this.poller.start();
}
/**
* Stops the polling process.
*/
public stop(): void {
this.poller.stop();
}
/**
* Initializes the poller with the specified module.
*
* @param moduleName - The name of the module to initialize.
*/
public initialize(moduleName?: BarModule): void {
this.poller.initialize(moduleName);
}
}

View File

@@ -0,0 +1,86 @@
import { Variable as VariableType } from 'types/variable';
import { Bind } from 'lib/types/variable';
import { GenericFunction } from 'lib/types/customModules/generic';
import { BarModule } from 'lib/types/options';
import { Poller } from './Poller';
/**
* A class that manages polling of a variable by executing a generic function at specified intervals.
*/
export class FunctionPoller<Value, Parameters extends unknown[] = []> {
private poller: Poller;
private params: Parameters;
/**
* Creates an instance of FunctionPoller.
*
* @param targetVariable - The target variable to poll.
* @param trackers - An array of trackers to monitor.
* @param pollingInterval - The interval at which polling occurs.
* @param pollingFunction - The function to execute during each poll.
* @param params - Additional parameters for the polling function.
*
* @example
*
* ```ts
* //##################### EXAMPLE ##########################
* const cpuPoller = new FunctionPoller<number, []>(
* cpuUsage,
* [round.bind('value')],
* pollingInterval.bind('value'),
* computeCPU,
* );
* //#######################################################
*
* ```
*/
constructor(
private targetVariable: VariableType<Value>,
private trackers: Bind[],
private pollingInterval: Bind,
private pollingFunction: GenericFunction<Value, Parameters>,
...params: Parameters
) {
this.params = params;
this.poller = new Poller(this.pollingInterval, this.trackers, this.execute);
}
/**
* Executes the polling function with the provided parameters.
*
* The result of the function is assigned to the target variable.
*/
private execute = async (): Promise<void> => {
try {
const result = await this.pollingFunction(...this.params);
this.targetVariable.value = result;
} catch (error) {
console.error('Error executing polling function:', error);
}
};
/**
* Starts the polling process.
*/
public start(): void {
this.poller.start();
}
/**
* Stops the polling process.
*/
public stop(): void {
this.poller.stop();
}
/**
* Initializes the poller with the specified module.
*
* @param moduleName - The name of the module to initialize.
*/
public initialize(moduleName?: BarModule): void {
this.poller.initialize(moduleName);
}
}

107
lib/poller/Poller.ts Normal file
View File

@@ -0,0 +1,107 @@
import GLib from 'gi://GLib?version=2.0';
import { Bind } from 'lib/types/variable';
import { BarModule } from 'lib/types/options';
import { getLayoutItems } from 'lib/utils';
const { layouts } = options.bar;
/**
* A class that manages the polling lifecycle, including interval management and execution state.
*/
export class Poller {
private intervalInstance: number | null = null;
private isExecuting: boolean = false;
private pollingFunction: () => Promise<void>;
/**
* Creates an instance of Poller.
* @param pollingInterval - The interval at which polling occurs.
* @param trackers - An array of trackers to monitor.
* @param pollingFunction - The function to execute during each poll.
*/
constructor(
private pollingInterval: Bind,
private trackers: Bind[],
pollingFunction: () => Promise<void>,
) {
this.pollingFunction = pollingFunction;
}
/**
* Starts the polling process by setting up the interval.
*/
public start(): void {
Utils.merge([this.pollingInterval, ...this.trackers], (intervalMs: number) => {
this.executePolling(intervalMs);
});
}
/**
* Stops the polling process and cleans up resources.
*/
public stop(): void {
if (this.intervalInstance !== null) {
GLib.source_remove(this.intervalInstance);
this.intervalInstance = null;
}
}
/**
* Initializes the polling based on module usage.
*
* If not module is provided then we can safely assume that we want
* to always run the pollig interval.
*
* @param moduleName - The name of the module to initialize.
*/
public initialize(moduleName?: BarModule): void {
if (moduleName === undefined) {
return this.start();
}
const initialModules = getLayoutItems();
if (initialModules.includes(moduleName)) {
this.start();
} else {
this.stop();
}
layouts.connect('changed', () => {
const usedModules = getLayoutItems();
if (usedModules.includes(moduleName)) {
this.start();
} else {
this.stop();
}
});
}
/**
* Executes the polling function at the specified interval.
*
* @param intervalMs - The polling interval in milliseconds.
*/
private executePolling(intervalMs: number): void {
if (this.intervalInstance !== null) {
GLib.source_remove(this.intervalInstance);
}
this.intervalInstance = Utils.interval(intervalMs, async () => {
if (this.isExecuting) {
return;
}
this.isExecuting = true;
try {
await this.pollingFunction();
} catch (error) {
console.error('Error during polling execution:', error);
} finally {
this.isExecuting = false;
}
});
}
}