162 lines
5.7 KiB
TypeScript
162 lines
5.7 KiB
TypeScript
// From https://github.com/Neurarian/matshell/blob/master/utils/wifi.ts
|
|
|
|
import { execAsync, Variable } from "astal";
|
|
import Network from "gi://AstalNetwork";
|
|
import { CurrentWiFi, WiFiDetails } from "./network";
|
|
|
|
// State trackers
|
|
export const availableNetworks: Variable<WiFiDetails[]> = Variable([]);
|
|
export const savedNetworks: Variable<string[]> = Variable([]);
|
|
export const activeNetwork: Variable<CurrentWiFi | null> = Variable(null);
|
|
export const isConnecting: Variable<boolean> = Variable(false);
|
|
export const showPasswordDialog: Variable<boolean> = Variable(false);
|
|
export const errorMessage: Variable<string> = Variable("");
|
|
export const isExpanded: Variable<boolean> = Variable(false);
|
|
export const passwordInput: Variable<string> = Variable("");
|
|
export const selectedNetwork: Variable<null | WiFiDetails> = Variable(null);
|
|
export const refreshIntervalId: Variable<
|
|
number | null | ReturnType<typeof setTimeout>
|
|
> = Variable(null);
|
|
|
|
// Function to scan for available networks
|
|
export const scanNetworks = () => {
|
|
const network = Network.get_default();
|
|
if (network && network.wifi) {
|
|
network.wifi.scan();
|
|
|
|
// Get available networks from access points
|
|
const networks: WiFiDetails[] = network.wifi.accessPoints
|
|
.map(ap => ({
|
|
ssid: ap.ssid,
|
|
strength: ap.strength,
|
|
secured: ap.flags !== 0,
|
|
active: network.wifi.activeAccessPoint?.ssid === ap.ssid,
|
|
accessPoint: ap,
|
|
iconName: ap.iconName,
|
|
}))
|
|
.filter(n => n.ssid);
|
|
|
|
// Sort by signal strength
|
|
networks.sort((a, b) => b.strength - a.strength);
|
|
|
|
// Remove duplicates (same SSID)
|
|
const uniqueNetworks: WiFiDetails[] = [];
|
|
const seen = new Set();
|
|
networks.forEach(network => {
|
|
if (!seen.has(network.ssid)) {
|
|
seen.add(network.ssid);
|
|
uniqueNetworks.push(network);
|
|
}
|
|
});
|
|
|
|
availableNetworks.set(uniqueNetworks);
|
|
|
|
// Update active network
|
|
if (network.wifi.activeAccessPoint) {
|
|
activeNetwork.set({
|
|
ssid: network.wifi.activeAccessPoint.ssid,
|
|
strength: network.wifi.activeAccessPoint.strength,
|
|
secured: network.wifi.activeAccessPoint.flags !== 0,
|
|
});
|
|
} else {
|
|
activeNetwork.set(null);
|
|
}
|
|
}
|
|
};
|
|
|
|
// Function to list saved networks
|
|
export const getSavedNetworks = () => {
|
|
execAsync(["bash", "-c", "nmcli -t -f NAME,TYPE connection show"])
|
|
.then(output => {
|
|
if (typeof output === "string") {
|
|
const savedWifiNetworks = output
|
|
.split("\n")
|
|
.filter(line => line.includes("802-11-wireless"))
|
|
.map(line => line.split(":")[0].trim());
|
|
savedNetworks.set(savedWifiNetworks);
|
|
}
|
|
})
|
|
.catch(error => console.error("Error fetching saved networks:", error));
|
|
};
|
|
|
|
// Function to connect to a network
|
|
|
|
export const connectToNetwork = (
|
|
ssid: string,
|
|
password: null | string = null,
|
|
) => {
|
|
isConnecting.set(true);
|
|
errorMessage.set("");
|
|
const network = Network.get_default();
|
|
const currentSsid = network.wifi.ssid;
|
|
|
|
// Function to perform the actual connection
|
|
const performConnection = () => {
|
|
let command = "";
|
|
if (password) {
|
|
// Connect with password
|
|
command = `echo '${password}' | nmcli device wifi connect "${ssid}" --ask`;
|
|
} else {
|
|
// Connect without password (saved or open network)
|
|
command = `nmcli connection up "${ssid}" || nmcli device wifi connect "${ssid}"`;
|
|
}
|
|
|
|
execAsync(["bash", "-c", command])
|
|
.then(() => {
|
|
showPasswordDialog.set(false);
|
|
isConnecting.set(false);
|
|
scanNetworks(); // Refresh network list
|
|
})
|
|
.catch(error => {
|
|
console.error("Connection error:", error);
|
|
errorMessage.set("Failed to connect. Check password.");
|
|
isConnecting.set(false);
|
|
});
|
|
};
|
|
|
|
// If already connected to a network, disconnect first
|
|
if (currentSsid && currentSsid !== ssid) {
|
|
console.log(
|
|
`Disconnecting from ${currentSsid} before connecting to ${ssid}`,
|
|
);
|
|
execAsync(["bash", "-c", `nmcli connection down "${currentSsid}"`])
|
|
.then(() => {
|
|
// Wait a moment for the disconnection to complete fully
|
|
setTimeout(() => {
|
|
performConnection();
|
|
}, 500); // 500ms delay for clean disconnection
|
|
})
|
|
.catch(error => {
|
|
console.error("Disconnect error:", error);
|
|
// Continue with connection attempt even if disconnect fails
|
|
performConnection();
|
|
});
|
|
} else {
|
|
// No active connection or connecting to same network (reconnect case)
|
|
performConnection();
|
|
}
|
|
};
|
|
|
|
// Function to disconnect from a network
|
|
export const disconnectNetwork = (ssid: string) => {
|
|
execAsync(["bash", "-c", `nmcli connection down "${ssid}"`])
|
|
.then(() => {
|
|
scanNetworks(); // Refresh network list
|
|
})
|
|
.catch(error => {
|
|
console.error("Disconnect error:", error);
|
|
});
|
|
};
|
|
|
|
// Function to forget a saved network
|
|
export const forgetNetwork = (ssid: string) => {
|
|
execAsync(["bash", "-c", `nmcli connection delete "${ssid}"`])
|
|
.then(() => {
|
|
getSavedNetworks(); // Refresh saved networks list
|
|
scanNetworks(); // Refresh network list
|
|
})
|
|
.catch(error => {
|
|
console.error("Forget network error:", error);
|
|
});
|
|
};
|