Minor: Refactor the code-base for better organization and compartmentalization. (#934)
* Clean up unused code * Fix media player formatting issue for labels with new line characteres. * Refactor the media player handlers into a class. * More code cleanup and organize shared weather utils into distinct classes. * Flatten some nesting. * Move weather manager in dedicated class and build HTTP Utility class for Rest API calling. * Remove logs * Rebase master merge * Reorg code (WIP) * More reorg * Delete utility scripts * Reorg options * Finish moving all options over * Fix typescript issues * Update options imports to default * missed update * Screw barrel files honestly, work of the devil. * Only initialize power profiles if power-profiles-daemon is running. * Fix window positioning and weather service naming * style dir * More organization * Restructure types to be closer to their source * Remove lib types and constants * Update basic weather object to be saner with extensibility. * Service updates * Fix initialization strategy for services. * Fix Config Manager to only emit changed objects and added missing temp converters. * Update storage service to handle unit changes. * Added cpu temp sensor auto-discovery * Added missing JSDocs to services * remove unused * Migrate to network service. * Fix network password issue. * Move out password input into helper * Rename password mask constant to be less double-negativey. * Dropdown menu rename * Added a component to edit JSON in the settings dialog (rough/WIP) * Align settings * Add and style JSON Editor. * Adjust padding * perf(shortcuts): ⚡ avoid unnecessary polling when shortcuts are disabled Stops the recording poller when shortcuts are disabled, preventing redundant polling and reducing resource usage. * Fix types and return value if shortcut not enabled. * Move the swww daemon checking process outside of the wallpaper service into a dedicated deamon lifecyle processor. * Add more string formatters and use title case for weather status (as it was). * Fix startup errors. * Rgba fix * Remove zod from dependencies --------- Co-authored-by: KernelDiego <gonzalezdiego.contact@gmail.com>
This commit is contained in:
102
src/services/network/ethernet.ts
Normal file
102
src/services/network/ethernet.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import { bind, Variable } from 'astal';
|
||||
import AstalNetwork from 'gi://AstalNetwork?version=0.1';
|
||||
|
||||
/**
|
||||
* EthernetManager handles ethernet-related functionality for dropdowns
|
||||
*/
|
||||
export class EthernetManager {
|
||||
private _astalNetwork: AstalNetwork.Network;
|
||||
|
||||
public wiredState: Variable<AstalNetwork.DeviceState> = Variable(AstalNetwork.DeviceState.UNKNOWN);
|
||||
public wiredInternet: Variable<AstalNetwork.Internet> = Variable(AstalNetwork.Internet.DISCONNECTED);
|
||||
public wiredIcon: Variable<string> = Variable('');
|
||||
public wiredSpeed: Variable<number> = Variable(0);
|
||||
|
||||
private _wiredStateBinding: Variable<void> | undefined;
|
||||
private _wiredInternetBinding: Variable<void> | undefined;
|
||||
private _wiredIconBinding: Variable<void> | undefined;
|
||||
private _wiredSpeedBinding: Variable<void> | undefined;
|
||||
|
||||
constructor(networkService: AstalNetwork.Network) {
|
||||
this._astalNetwork = networkService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the wired service changes to update bindings
|
||||
*/
|
||||
public onWiredServiceChanged(): void {
|
||||
this._getWiredState();
|
||||
this._getWiredInternet();
|
||||
this._getWiredIcon();
|
||||
this._getWiredSpeed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current state of the wired network.
|
||||
*/
|
||||
private _getWiredState(): void {
|
||||
this._wiredStateBinding?.drop();
|
||||
this._wiredStateBinding = undefined;
|
||||
|
||||
if (this._astalNetwork.wired === null) {
|
||||
this.wiredState.set(AstalNetwork.DeviceState.UNAVAILABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
this._wiredStateBinding = Variable.derive([bind(this._astalNetwork.wired, 'state')], (state) => {
|
||||
this.wiredState.set(state);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current internet status of the wired network.
|
||||
*/
|
||||
private _getWiredInternet(): void {
|
||||
this._wiredInternetBinding?.drop();
|
||||
this._wiredInternetBinding = undefined;
|
||||
|
||||
if (this._astalNetwork.wired === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._wiredInternetBinding = Variable.derive(
|
||||
[bind(this._astalNetwork.wired, 'internet')],
|
||||
(internet) => {
|
||||
this.wiredInternet.set(internet);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current icon for the wired network.
|
||||
*/
|
||||
private _getWiredIcon(): void {
|
||||
this._wiredIconBinding?.drop();
|
||||
this._wiredIconBinding = undefined;
|
||||
|
||||
if (this._astalNetwork.wired === null) {
|
||||
this.wiredIcon.set('network-wired-symbolic');
|
||||
return;
|
||||
}
|
||||
|
||||
this._wiredIconBinding = Variable.derive([bind(this._astalNetwork.wired, 'iconName')], (icon) => {
|
||||
this.wiredIcon.set(icon);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current speed of the wired network.
|
||||
*/
|
||||
private _getWiredSpeed(): void {
|
||||
this._wiredSpeedBinding?.drop();
|
||||
this._wiredSpeedBinding = undefined;
|
||||
|
||||
if (this._astalNetwork.wired === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._wiredSpeedBinding = Variable.derive([bind(this._astalNetwork.wired, 'speed')], (speed) => {
|
||||
this.wiredSpeed.set(speed);
|
||||
});
|
||||
}
|
||||
}
|
||||
70
src/services/network/index.ts
Normal file
70
src/services/network/index.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { bind, Variable } from 'astal';
|
||||
import AstalNetwork from 'gi://AstalNetwork?version=0.1';
|
||||
import { WifiManager } from './wifi';
|
||||
import { EthernetManager } from './ethernet';
|
||||
import { WifiIcon, wifiIconMap } from './types';
|
||||
|
||||
/**
|
||||
* NetworkService consolidates all network-related functionality from various components
|
||||
* into a single service for better organization and maintainability.
|
||||
*/
|
||||
export class NetworkService {
|
||||
private static _instance: NetworkService;
|
||||
private _astalNetwork: AstalNetwork.Network;
|
||||
|
||||
public wifi: WifiManager;
|
||||
public ethernet: EthernetManager;
|
||||
|
||||
private constructor() {
|
||||
this._astalNetwork = AstalNetwork.get_default();
|
||||
this.wifi = new WifiManager(this._astalNetwork);
|
||||
this.ethernet = new EthernetManager(this._astalNetwork);
|
||||
|
||||
this._setupBindings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the singleton instance of NetworkService
|
||||
*
|
||||
* @returns The NetworkService instance
|
||||
*/
|
||||
public static getInstance(): NetworkService {
|
||||
if (!this._instance) {
|
||||
this._instance = new NetworkService();
|
||||
}
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up bindings to monitor network service changes
|
||||
*/
|
||||
private _setupBindings(): void {
|
||||
Variable.derive([bind(this._astalNetwork, 'wifi')], () => {
|
||||
this.wifi.onWifiServiceChanged();
|
||||
});
|
||||
|
||||
Variable.derive([bind(this._astalNetwork, 'wired')], () => {
|
||||
this.ethernet.onWiredServiceChanged();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the appropriate WiFi icon based on the provided icon name.
|
||||
*
|
||||
* @param iconName - The name of the icon to look up. If not provided, a default icon is returned.
|
||||
* @returns The corresponding WiFi icon as a string.
|
||||
*/
|
||||
public getWifiIcon(iconName?: string): WifiIcon {
|
||||
if (iconName === undefined) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const wifiIcon = wifiIconMap.get(iconName.toLowerCase());
|
||||
|
||||
if (wifiIcon) {
|
||||
return wifiIcon;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
43
src/services/network/types.ts
Normal file
43
src/services/network/types.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import AstalNetwork from 'gi://AstalNetwork?version=0.1';
|
||||
|
||||
export type WifiIcon = '' | '' | '' | '' | '' | '' | '' | '' | '' | '' | '' | '';
|
||||
|
||||
type DeviceSate = AstalNetwork.DeviceState;
|
||||
type DevceStates = {
|
||||
[key in DeviceSate]: string;
|
||||
};
|
||||
|
||||
export const DEVICE_STATES: DevceStates = {
|
||||
[AstalNetwork.DeviceState.UNKNOWN]: 'Unknown',
|
||||
[AstalNetwork.DeviceState.UNMANAGED]: 'Unmanaged',
|
||||
[AstalNetwork.DeviceState.UNAVAILABLE]: 'Unavailable',
|
||||
[AstalNetwork.DeviceState.DISCONNECTED]: 'Disconnected',
|
||||
[AstalNetwork.DeviceState.PREPARE]: 'Prepare',
|
||||
[AstalNetwork.DeviceState.CONFIG]: 'Config',
|
||||
[AstalNetwork.DeviceState.NEED_AUTH]: 'Need Authentication',
|
||||
[AstalNetwork.DeviceState.IP_CONFIG]: 'IP Configuration',
|
||||
[AstalNetwork.DeviceState.IP_CHECK]: 'IP Check',
|
||||
[AstalNetwork.DeviceState.SECONDARIES]: 'Secondaries',
|
||||
[AstalNetwork.DeviceState.ACTIVATED]: 'Activated',
|
||||
[AstalNetwork.DeviceState.DEACTIVATING]: 'Deactivating',
|
||||
[AstalNetwork.DeviceState.FAILED]: 'Failed',
|
||||
} as const;
|
||||
|
||||
export const wifiIconMap = new Map<string, WifiIcon>([
|
||||
['network-wireless-acquiring', ''],
|
||||
['network-wireless-connected', ''],
|
||||
['network-wireless-encrypted', ''],
|
||||
['network-wireless-hotspot', ''],
|
||||
['network-wireless-no-route', ''],
|
||||
['network-wireless-offline', ''],
|
||||
['network-wireless-signal-excellent', ''],
|
||||
['network-wireless-signal-good', ''],
|
||||
['network-wireless-signal-ok', ''],
|
||||
['network-wireless-signal-weak', ''],
|
||||
['network-wireless-signal-none', ''],
|
||||
]);
|
||||
|
||||
export const AP_FLAGS = {
|
||||
NONE: 0,
|
||||
PRIVACY: 1,
|
||||
} as const;
|
||||
351
src/services/network/wifi.ts
Normal file
351
src/services/network/wifi.ts
Normal file
@@ -0,0 +1,351 @@
|
||||
import { bind, execAsync, Variable } from 'astal';
|
||||
import { Astal } from 'astal/gtk3';
|
||||
import AstalNetwork from 'gi://AstalNetwork?version=0.1';
|
||||
import { SystemUtilities } from 'src/core/system/SystemUtilities';
|
||||
import { isPrimaryClick } from 'src/lib/events/mouse';
|
||||
import { AP_FLAGS, DEVICE_STATES } from './types';
|
||||
|
||||
/**
|
||||
* WifiManager handles all WiFi-related functionality for staging and connecting to
|
||||
* wireless networks
|
||||
*/
|
||||
export class WifiManager {
|
||||
private _astalNetwork: AstalNetwork.Network;
|
||||
|
||||
public isWifiEnabled: Variable<boolean> = Variable(false);
|
||||
public isScanning: Variable<boolean> = Variable(false);
|
||||
public wifiAccessPoints: Variable<AstalNetwork.AccessPoint[]> = Variable([]);
|
||||
public staging = Variable<AstalNetwork.AccessPoint | undefined>(undefined);
|
||||
public connecting = Variable<string>('');
|
||||
|
||||
private _wifiEnabledBinding: Variable<void> | undefined;
|
||||
private _scanningBinding: Variable<void> | undefined;
|
||||
private _accessPointBinding: Variable<void> | undefined;
|
||||
|
||||
constructor(networkService: AstalNetwork.Network) {
|
||||
this._astalNetwork = networkService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the WiFi service changes to update bindings
|
||||
*/
|
||||
public onWifiServiceChanged(): void {
|
||||
this._wifiEnabled();
|
||||
this._scanningStatus();
|
||||
this._accessPoints();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if WiFi is enabled and updates the `isWifiEnabled` variable.
|
||||
*/
|
||||
private _wifiEnabled(): void {
|
||||
this._wifiEnabledBinding?.drop();
|
||||
this._wifiEnabledBinding = undefined;
|
||||
|
||||
if (this._astalNetwork.wifi === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._wifiEnabledBinding = Variable.derive(
|
||||
[bind(this._astalNetwork.wifi, 'enabled')],
|
||||
(isEnabled) => {
|
||||
this.isWifiEnabled.set(isEnabled);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the WiFi scanning status.
|
||||
*/
|
||||
private _scanningStatus(): void {
|
||||
this._scanningBinding?.drop();
|
||||
this._scanningBinding = undefined;
|
||||
|
||||
if (this._astalNetwork.wifi === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._scanningBinding = Variable.derive([bind(this._astalNetwork.wifi, 'scanning')], (scanning) => {
|
||||
this.isScanning.set(scanning);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the list of WiFi access points.
|
||||
*/
|
||||
private _accessPoints(): void {
|
||||
this._accessPointBinding?.drop();
|
||||
this._accessPointBinding = undefined;
|
||||
|
||||
if (this._astalNetwork.wifi === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Variable.derive([bind(this._astalNetwork.wifi, 'accessPoints')], (axsPoints) => {
|
||||
this.wifiAccessPoints.set(axsPoints);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes duplicate access points based on their SSID.
|
||||
*
|
||||
* @returns An array of deduplicated access points.
|
||||
*/
|
||||
private _dedupeWAPs(): AstalNetwork.AccessPoint[] {
|
||||
if (this._astalNetwork.wifi === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const WAPs = this._astalNetwork.wifi.get_access_points();
|
||||
const dedupMap: Record<string, AstalNetwork.AccessPoint> = {};
|
||||
|
||||
WAPs.forEach((item: AstalNetwork.AccessPoint) => {
|
||||
if (item.ssid !== null && !Object.prototype.hasOwnProperty.call(dedupMap, item.ssid)) {
|
||||
dedupMap[item.ssid] = item;
|
||||
}
|
||||
});
|
||||
|
||||
return Object.keys(dedupMap).map((itm) => dedupMap[itm]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a given access point is currently in the staging area.
|
||||
*
|
||||
* @param wap - The access point to check.
|
||||
* @returns True if the access point is in staging; otherwise, false.
|
||||
*/
|
||||
private _isInStaging(wap: AstalNetwork.AccessPoint): boolean {
|
||||
const wapInStaging = this.staging.get();
|
||||
if (wapInStaging === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return wap.bssid === wapInStaging.bssid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of filtered wireless access points by removing duplicates and excluding specific entries.
|
||||
*
|
||||
* @returns A filtered array of wireless access points.
|
||||
*/
|
||||
public getFilteredWirelessAPs(): AstalNetwork.AccessPoint[] {
|
||||
const dedupedWAPs = this._dedupeWAPs();
|
||||
|
||||
const filteredWAPs = dedupedWAPs
|
||||
.filter((ap: AstalNetwork.AccessPoint) => {
|
||||
return ap.ssid !== 'Unknown' && !this._isInStaging(ap);
|
||||
})
|
||||
.sort((a: AstalNetwork.AccessPoint, b: AstalNetwork.AccessPoint) => {
|
||||
if (this.isApActive(a)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (this.isApActive(b)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return b.strength - a.strength;
|
||||
});
|
||||
|
||||
return filteredWAPs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the device is in an active state.
|
||||
*
|
||||
* @param state - The current state of the device.
|
||||
* @returns True if the device is in an active state; otherwise, false.
|
||||
*/
|
||||
public isApEnabled(state: AstalNetwork.DeviceState | undefined): boolean {
|
||||
if (state === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !(
|
||||
state === AstalNetwork.DeviceState.DISCONNECTED ||
|
||||
state === AstalNetwork.DeviceState.UNAVAILABLE ||
|
||||
state === AstalNetwork.DeviceState.FAILED
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given access point is the currently active one.
|
||||
*
|
||||
* @param accessPoint - The access point to check.
|
||||
* @returns True if the access point is active; otherwise, false.
|
||||
*/
|
||||
public isApActive(accessPoint: AstalNetwork.AccessPoint): boolean {
|
||||
return accessPoint.ssid === this._astalNetwork.wifi?.activeAccessPoint?.ssid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified access point is in the process of disconnecting.
|
||||
*
|
||||
* @param accessPoint - The access point to check.
|
||||
* @returns True if the access point is disconnecting; otherwise, false.
|
||||
*/
|
||||
public isDisconnecting(accessPoint: AstalNetwork.AccessPoint): boolean {
|
||||
if (this.isApActive(accessPoint)) {
|
||||
return this._astalNetwork.wifi?.state === AstalNetwork.DeviceState.DEACTIVATING;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current Wi-Fi status based on the network service state.
|
||||
*
|
||||
* @returns A string representing the current Wi-Fi status.
|
||||
*/
|
||||
public getWifiStatus(): string {
|
||||
const wifiState = this._astalNetwork.wifi?.state;
|
||||
|
||||
if (wifiState !== null) {
|
||||
return DEVICE_STATES[wifiState];
|
||||
}
|
||||
return DEVICE_STATES[AstalNetwork.DeviceState.UNKNOWN];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates a connection to the specified access point.
|
||||
*
|
||||
* @param accessPoint - The access point to connect to.
|
||||
* @param event - The click event triggering the connection.
|
||||
*/
|
||||
public connectToAP(accessPoint: AstalNetwork.AccessPoint, event: Astal.ClickEvent): void {
|
||||
if (
|
||||
accessPoint.bssid === this.connecting.get() ||
|
||||
this.isApActive(accessPoint) ||
|
||||
!isPrimaryClick(event)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!accessPoint.flags || accessPoint.flags === AP_FLAGS.NONE) {
|
||||
this.connecting.set(accessPoint.bssid ?? '');
|
||||
|
||||
execAsync(`nmcli device wifi connect ${accessPoint.bssid}`)
|
||||
.then(() => {
|
||||
this.connecting.set('');
|
||||
this.staging.set({} as AstalNetwork.AccessPoint);
|
||||
})
|
||||
.catch((err: Error) => {
|
||||
this.connecting.set('');
|
||||
SystemUtilities.notify({
|
||||
summary: 'Network',
|
||||
body: err.message,
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.staging.set(accessPoint);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to a secured access point with a password.
|
||||
*
|
||||
* @param accessPoint - The access point to connect to.
|
||||
* @param password - The password for the network.
|
||||
*/
|
||||
public async connectToAPWithPassword(
|
||||
accessPoint: AstalNetwork.AccessPoint,
|
||||
password: string,
|
||||
): Promise<void> {
|
||||
if (!accessPoint.ssid || !password) {
|
||||
return Promise.reject(new Error('SSID and password are required'));
|
||||
}
|
||||
|
||||
this.connecting.set(accessPoint.bssid || '');
|
||||
|
||||
const connectCommand = `nmcli device wifi connect "${accessPoint.ssid}" password "${password}"`;
|
||||
|
||||
return execAsync(connectCommand)
|
||||
.then(() => {
|
||||
this.connecting.set('');
|
||||
this.staging.set(undefined);
|
||||
})
|
||||
.catch((err: Error) => {
|
||||
this.connecting.set('');
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects from the specified access point.
|
||||
*
|
||||
* @param accessPoint - The access point to disconnect from.
|
||||
* @param event - The click event triggering the disconnection.
|
||||
*/
|
||||
public disconnectFromAP(accessPoint: AstalNetwork.AccessPoint, event: Astal.ClickEvent): void {
|
||||
if (!isPrimaryClick(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.connecting.set(accessPoint.bssid || '');
|
||||
execAsync('nmcli connection show --active').then((res: string) => {
|
||||
const connectionId = this._getIdFromSsid(accessPoint.ssid || '', res);
|
||||
|
||||
if (connectionId === undefined) {
|
||||
console.error(`Error while disconnecting "${accessPoint.ssid}": Connection ID not found`);
|
||||
return;
|
||||
}
|
||||
|
||||
execAsync(`nmcli connection down ${connectionId} "${accessPoint.ssid}"`)
|
||||
.then(() => {
|
||||
this.connecting.set('');
|
||||
})
|
||||
.catch((err: unknown) => {
|
||||
this.connecting.set('');
|
||||
console.error(`Error while disconnecting "${accessPoint.ssid}": ${err}`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Forgets the specified access point by deleting its connection.
|
||||
*
|
||||
* @param accessPoint - The access point to forget.
|
||||
* @param event - The click event triggering the forget action.
|
||||
*/
|
||||
public forgetAP(accessPoint: AstalNetwork.AccessPoint, event: Astal.ClickEvent): void {
|
||||
if (!isPrimaryClick(event)) {
|
||||
return;
|
||||
}
|
||||
this.connecting.set(accessPoint.bssid || '');
|
||||
execAsync('nmcli connection show --active').then((res: string) => {
|
||||
const connectionId = this._getIdFromSsid(accessPoint.ssid || '', res);
|
||||
|
||||
if (connectionId === undefined) {
|
||||
console.error(`Error while forgetting "${accessPoint.ssid}": Connection ID not found`);
|
||||
return;
|
||||
}
|
||||
|
||||
execAsync(`nmcli connection delete ${connectionId} "${accessPoint.ssid}"`)
|
||||
.then(() => {
|
||||
this.connecting.set('');
|
||||
})
|
||||
.catch((err: unknown) => {
|
||||
this.connecting.set('');
|
||||
console.error(`Error while forgetting "${accessPoint.ssid}": ${err}`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the connection ID associated with a given SSID from the `nmcli` command output.
|
||||
*
|
||||
* @param ssid - The SSID of the network.
|
||||
* @param nmcliOutput - The output string from the `nmcli` command.
|
||||
* @returns The connection ID if found; otherwise, undefined.
|
||||
*/
|
||||
private _getIdFromSsid(ssid: string, nmcliOutput: string): string | undefined {
|
||||
const lines = nmcliOutput.trim().split('\n');
|
||||
|
||||
for (const line of lines) {
|
||||
const columns = line.trim().split(/\s{2,}/);
|
||||
|
||||
if (columns[0].includes(ssid)) {
|
||||
return columns[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user