@domicile-desktop/system-network 0.0.0-alpha-44d0983a58ce → 0.0.0-alpha-56dd6c187f4e
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -4
- package/dist/follow.d.ts +2 -2
- package/dist/follow.js +4 -4
- package/dist/has-owner.d.ts +2 -2
- package/dist/has-owner.js +1 -1
- package/dist/interfaces.d.ts +14 -6
- package/dist/interfaces.js +19 -19
- package/dist/iwd-wifi.d.ts +7 -7
- package/dist/iwd-wifi.js +15 -15
- package/dist/iwd.d.ts +2 -2
- package/dist/iwd.js +6 -6
- package/dist/network-state.d.ts +4 -2
- package/dist/network.d.ts +3 -3
- package/dist/network.js +6 -6
- package/dist/networkmanager-wifi.d.ts +6 -6
- package/dist/networkmanager-wifi.js +19 -19
- package/dist/networkmanager.d.ts +2 -2
- package/dist/networkmanager.js +9 -9
- package/dist/portal.d.ts +5 -2
- package/dist/portal.js +1 -1
- package/dist/wifi-state.d.ts +6 -2
- package/dist/wifi.d.ts +7 -7
- package/dist/wifi.js +18 -18
- package/dist/wpa-supplicant.d.ts +2 -2
- package/dist/wpa-supplicant.js +9 -9
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -4,15 +4,16 @@ The network for a Domicile shell, from NetworkManager, iwd or wpa_supplicant:
|
|
|
4
4
|
connectivity and the primary connection, with the Wi-Fi network's name and
|
|
5
5
|
signal. The Wi-Fi device, from NetworkManager or iwd: its networks and
|
|
6
6
|
connection, and the requests that change them. Built on
|
|
7
|
-
|
|
7
|
+
the `dbus`, `files` and `processes` namespaces of
|
|
8
|
+
[`desktop(domicile)`](../chrome-sdk/README.md).
|
|
8
9
|
|
|
9
10
|
## Usage
|
|
10
11
|
|
|
11
12
|
```ts
|
|
12
|
-
import {
|
|
13
|
+
import { desktop } from "@domicile-desktop/sdk/desktop/desktop";
|
|
13
14
|
import { watchNetwork } from "@domicile-desktop/system-network/network";
|
|
14
15
|
|
|
15
|
-
const stop = watchNetwork(
|
|
16
|
+
const stop = watchNetwork(desktop(domicile), (network) => {
|
|
16
17
|
network.match({
|
|
17
18
|
Err: () => hide(),
|
|
18
19
|
Ok: ({ connectivity, link }) => show(connectivity, link),
|
|
@@ -111,4 +112,4 @@ bun run turbo test --filter @domicile-desktop/system-network
|
|
|
111
112
|
```
|
|
112
113
|
|
|
113
114
|
Tests replay D-Bus replies, in the compositor's JSON, through an injected
|
|
114
|
-
`
|
|
115
|
+
`dbus` namespace.
|
package/dist/follow.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Result } from "@cprussin/option-result";
|
|
2
2
|
import type { DbusMatch, DbusSignal, SystemError } from "@domicile-desktop/sdk/system";
|
|
3
|
-
import type {
|
|
3
|
+
import type { NetworkDesktop } from "./network-state";
|
|
4
4
|
/** What one read found, and which signals can change it. */
|
|
5
5
|
export type Reading<T extends NonNullable<unknown>> = {
|
|
6
6
|
value: Result<T, SystemError>;
|
|
@@ -10,4 +10,4 @@ export type Reading<T extends NonNullable<unknown>> = {
|
|
|
10
10
|
* Calls `onValue` with what `read` finds now and after each signal that
|
|
11
11
|
* matters, and returns a function that stops watching.
|
|
12
12
|
*/
|
|
13
|
-
export declare const followBus: <T extends NonNullable<unknown>>(
|
|
13
|
+
export declare const followBus: <T extends NonNullable<unknown>>(domicile: NetworkDesktop, match: DbusMatch, read: () => Promise<Reading<T>>, onValue: (value: Result<T, SystemError>) => void) => (() => void);
|
package/dist/follow.js
CHANGED
|
@@ -6,14 +6,14 @@ import { ListenedKind } from "@domicile-desktop/sdk/system";
|
|
|
6
6
|
* Calls `onValue` with what `read` finds now and after each signal that
|
|
7
7
|
* matters, and returns a function that stops watching.
|
|
8
8
|
*/
|
|
9
|
-
export const followBus = (
|
|
9
|
+
export const followBus = (domicile, match, read, onValue) => {
|
|
10
10
|
const watch = { listening: undefined, stopped: false };
|
|
11
11
|
const report = (value) => {
|
|
12
12
|
if (!watch.stopped) {
|
|
13
13
|
onValue(value);
|
|
14
14
|
}
|
|
15
15
|
};
|
|
16
|
-
follow(
|
|
16
|
+
follow(domicile, match, read, watch, report).catch((error) => {
|
|
17
17
|
// biome-ignore lint/suspicious/noConsole: surfacing a background failure
|
|
18
18
|
console.error("Failed to watch the network", error);
|
|
19
19
|
});
|
|
@@ -22,8 +22,8 @@ export const followBus = (system, match, read, onValue) => {
|
|
|
22
22
|
watch.listening?.stop();
|
|
23
23
|
};
|
|
24
24
|
};
|
|
25
|
-
const follow = async (
|
|
26
|
-
const matched = await
|
|
25
|
+
const follow = async (domicile, match, read, watch, report) => {
|
|
26
|
+
const matched = await domicile.dbus.match(match);
|
|
27
27
|
await matched.match({
|
|
28
28
|
Err: (error) => {
|
|
29
29
|
report(Err(error));
|
package/dist/has-owner.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { Result } from "@cprussin/option-result";
|
|
2
2
|
import type { SystemError } from "@domicile-desktop/sdk/system";
|
|
3
|
-
import type {
|
|
3
|
+
import type { NetworkDesktop } from "./network-state";
|
|
4
4
|
/**
|
|
5
5
|
* Whether `name` has an owner on the system bus. `NameHasOwner` does not start
|
|
6
6
|
* a service that D-Bus can activate, as a call to the service would.
|
|
7
7
|
*/
|
|
8
|
-
export declare const hasOwner: (
|
|
8
|
+
export declare const hasOwner: (domicile: NetworkDesktop, name: string) => Promise<Result<boolean, SystemError>>;
|
package/dist/has-owner.js
CHANGED
|
@@ -4,7 +4,7 @@ import { z } from "zod";
|
|
|
4
4
|
* Whether `name` has an owner on the system bus. `NameHasOwner` does not start
|
|
5
5
|
* a service that D-Bus can activate, as a call to the service would.
|
|
6
6
|
*/
|
|
7
|
-
export const hasOwner = async (
|
|
7
|
+
export const hasOwner = async (domicile, name) => (await domicile.dbus.call({
|
|
8
8
|
body: [name],
|
|
9
9
|
bus: Bus.System,
|
|
10
10
|
destination: "org.freedesktop.DBus",
|
package/dist/interfaces.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Result } from "@cprussin/option-result";
|
|
2
|
-
import type {
|
|
2
|
+
import type { Files } from "@domicile-desktop/sdk/desktop/files";
|
|
3
|
+
import type { Processes } from "@domicile-desktop/sdk/desktop/processes";
|
|
4
|
+
import type { SystemError } from "@domicile-desktop/sdk/system";
|
|
3
5
|
export declare enum InterfaceKind {
|
|
4
6
|
Wired = 0,
|
|
5
7
|
Wireless = 1
|
|
@@ -22,26 +24,32 @@ export type Addressing = {
|
|
|
22
24
|
gateway: string | undefined;
|
|
23
25
|
};
|
|
24
26
|
/** The calls {@link readInterfaces} makes. Each works while the desktop is locked. */
|
|
25
|
-
export type
|
|
27
|
+
export type InterfaceDesktop = {
|
|
28
|
+
readonly files: Pick<Files, "readDir" | "readText" | "stat">;
|
|
29
|
+
};
|
|
26
30
|
/**
|
|
27
31
|
* The interfaces with hardware behind them, by name. Virtual ones, such as
|
|
28
32
|
* the loopback, a bridge or a VPN, have no `device` link and are left out.
|
|
29
33
|
*/
|
|
30
|
-
export declare const readInterfaces: (
|
|
34
|
+
export declare const readInterfaces: (domicile: InterfaceDesktop) => Promise<Result<NetworkInterface[], SystemError>>;
|
|
31
35
|
/**
|
|
32
36
|
* Calls `onInterfaces` with {@link readInterfaces} now and whenever it
|
|
33
37
|
* changes, and returns a function that stops watching. Reads every 5 seconds.
|
|
34
38
|
*/
|
|
35
|
-
export declare const watchInterfaces: (
|
|
39
|
+
export declare const watchInterfaces: (domicile: InterfaceDesktop, onInterfaces: (interfaces: Result<NetworkInterface[], SystemError>) => void, every?: typeof everyInterval) => (() => void);
|
|
36
40
|
/**
|
|
37
41
|
* Calls `onAddresses` with {@link readAddresses} now and whenever it changes,
|
|
38
42
|
* and returns a function that stops watching. Reads every 5 seconds.
|
|
39
43
|
*/
|
|
40
|
-
export declare const watchAddresses: (
|
|
44
|
+
export declare const watchAddresses: (domicile: {
|
|
45
|
+
readonly processes: Pick<Processes, "run">;
|
|
46
|
+
}, onAddresses: (addresses: Result<Map<string, Addressing>, SystemError>) => void, every?: typeof everyInterval) => (() => void);
|
|
41
47
|
/**
|
|
42
48
|
* Each interface's global addresses in use and default gateway, by name, from
|
|
43
49
|
* `ip -j`. `ip` must be on the compositor's `PATH`.
|
|
44
50
|
*/
|
|
45
|
-
export declare const readAddresses: (
|
|
51
|
+
export declare const readAddresses: (domicile: {
|
|
52
|
+
readonly processes: Pick<Processes, "run">;
|
|
53
|
+
}) => Promise<Result<Map<string, Addressing>, SystemError>>;
|
|
46
54
|
declare const everyInterval: (ms: number, tick: () => void) => (() => void);
|
|
47
55
|
export {};
|
package/dist/interfaces.js
CHANGED
|
@@ -16,13 +16,13 @@ export var InterfaceKind;
|
|
|
16
16
|
* The interfaces with hardware behind them, by name. Virtual ones, such as
|
|
17
17
|
* the loopback, a bridge or a VPN, have no `device` link and are left out.
|
|
18
18
|
*/
|
|
19
|
-
export const readInterfaces = async (
|
|
19
|
+
export const readInterfaces = async (domicile) => (await domicile.files.readDir(NET)).match({
|
|
20
20
|
Err: (error) => Promise.resolve(Err(error)),
|
|
21
21
|
Ok: async (entries) => {
|
|
22
22
|
const read = await Promise.all(entries
|
|
23
23
|
.map(({ name }) => name)
|
|
24
24
|
.toSorted()
|
|
25
|
-
.map((name) => interfaceOf(
|
|
25
|
+
.map((name) => interfaceOf(domicile, name)));
|
|
26
26
|
return read.reduce((all, each) => all.andThen((found) => each.map((one) => one.match({ None: () => found, Some: (it) => [...found, it] }))), Ok([]));
|
|
27
27
|
},
|
|
28
28
|
});
|
|
@@ -30,19 +30,19 @@ export const readInterfaces = async (system) => (await system.readDir(NET)).matc
|
|
|
30
30
|
* Calls `onInterfaces` with {@link readInterfaces} now and whenever it
|
|
31
31
|
* changes, and returns a function that stops watching. Reads every 5 seconds.
|
|
32
32
|
*/
|
|
33
|
-
export const watchInterfaces = (
|
|
33
|
+
export const watchInterfaces = (domicile, onInterfaces, every = everyInterval) => poll(() => readInterfaces(domicile), onInterfaces, every);
|
|
34
34
|
/**
|
|
35
35
|
* Calls `onAddresses` with {@link readAddresses} now and whenever it changes,
|
|
36
36
|
* and returns a function that stops watching. Reads every 5 seconds.
|
|
37
37
|
*/
|
|
38
|
-
export const watchAddresses = (
|
|
38
|
+
export const watchAddresses = (domicile, onAddresses, every = everyInterval) => poll(() => readAddresses(domicile), onAddresses, every);
|
|
39
39
|
/**
|
|
40
40
|
* Each interface's global addresses in use and default gateway, by name, from
|
|
41
41
|
* `ip -j`. `ip` must be on the compositor's `PATH`.
|
|
42
42
|
*/
|
|
43
|
-
export const readAddresses = async (
|
|
44
|
-
const addresses = await ip(
|
|
45
|
-
const routes = await ip(
|
|
43
|
+
export const readAddresses = async (domicile) => {
|
|
44
|
+
const addresses = await ip(domicile, ["address", "show"], addressesSchema);
|
|
45
|
+
const routes = await ip(domicile, ["route", "show", "default"], routesSchema);
|
|
46
46
|
return addresses.andThen((listed) => routes.map((defaults) => new Map(listed.map(({ addr_info: info, ifname }) => [
|
|
47
47
|
ifname,
|
|
48
48
|
{
|
|
@@ -93,24 +93,24 @@ const everyInterval = (ms, tick) => {
|
|
|
93
93
|
};
|
|
94
94
|
};
|
|
95
95
|
/** The interface `name`, or `None` for a virtual one. */
|
|
96
|
-
const interfaceOf = async (
|
|
96
|
+
const interfaceOf = async (domicile, name) => {
|
|
97
97
|
const at = `${NET}/${name}`;
|
|
98
|
-
return (await exists(
|
|
98
|
+
return (await exists(domicile, `${at}/device`)).match({
|
|
99
99
|
Err: (error) => Promise.resolve(Err(error)),
|
|
100
100
|
Ok: async (physical) => physical
|
|
101
|
-
? (await hardwareOf(
|
|
101
|
+
? (await hardwareOf(domicile, name)).map(Some)
|
|
102
102
|
: Ok(None()),
|
|
103
103
|
});
|
|
104
104
|
};
|
|
105
105
|
/** The interface `name`, which has a `device`. */
|
|
106
|
-
const hardwareOf = async (
|
|
106
|
+
const hardwareOf = async (domicile, name) => {
|
|
107
107
|
const at = `${NET}/${name}`;
|
|
108
|
-
const wireless = await exists(
|
|
109
|
-
const address = await line(
|
|
110
|
-
const state = await line(
|
|
108
|
+
const wireless = await exists(domicile, `${at}/wireless`);
|
|
109
|
+
const address = await line(domicile, `${at}/address`);
|
|
110
|
+
const state = await line(domicile, `${at}/operstate`);
|
|
111
111
|
const up = state.map((operstate) => operstate === "up");
|
|
112
112
|
const speed = up.unwrapOr(false) && !wireless.unwrapOr(true)
|
|
113
|
-
? await speedOf(
|
|
113
|
+
? await speedOf(domicile, at)
|
|
114
114
|
: undefined;
|
|
115
115
|
return wireless.andThen((isWireless) => address.andThen((hardwareAddress) => up.map((linked) => ({
|
|
116
116
|
hardwareAddress,
|
|
@@ -121,17 +121,17 @@ const hardwareOf = async (system, name) => {
|
|
|
121
121
|
}))));
|
|
122
122
|
};
|
|
123
123
|
/** Whether `path` exists. */
|
|
124
|
-
const exists = async (
|
|
124
|
+
const exists = async (domicile, path) => (await domicile.files.stat(path)).match({
|
|
125
125
|
Err: (error) => error.kind === SystemErrorKind.NotFound ? Ok(false) : Err(error),
|
|
126
126
|
Ok: () => Ok(true),
|
|
127
127
|
});
|
|
128
128
|
/** A one-line file under `/sys`, without its newline. */
|
|
129
|
-
const line = async (
|
|
129
|
+
const line = async (domicile, path) => (await domicile.files.readText(path)).map((text) => text.trim());
|
|
130
130
|
/**
|
|
131
131
|
* A wired link's speed. The kernel fails the read, or answers `-1`, when the
|
|
132
132
|
* driver does not know it, which is no speed to show.
|
|
133
133
|
*/
|
|
134
|
-
const speedOf = async (
|
|
134
|
+
const speedOf = async (domicile, at) => (await line(domicile, `${at}/speed`)).match({
|
|
135
135
|
Err: () => undefined,
|
|
136
136
|
Ok: (text) => {
|
|
137
137
|
const mbits = Number.parseInt(text, 10);
|
|
@@ -139,7 +139,7 @@ const speedOf = async (system, at) => (await line(system, `${at}/speed`)).match(
|
|
|
139
139
|
},
|
|
140
140
|
});
|
|
141
141
|
/** `ip -j` with `argv`, parsed with `schema`. */
|
|
142
|
-
const ip = async (
|
|
142
|
+
const ip = async (domicile, argv, schema) => (await domicile.processes.run(["ip", "-j", ...argv])).andThen(({ code, stderr, stdout }) => code === 0
|
|
143
143
|
? Ok(schema.parse(JSON.parse(stdout)))
|
|
144
144
|
: Err({
|
|
145
145
|
kind: SystemErrorKind.Other,
|
package/dist/iwd-wifi.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Option, Result } from "@cprussin/option-result";
|
|
2
2
|
import type { SystemError } from "@domicile-desktop/sdk/system";
|
|
3
|
-
import type {
|
|
4
|
-
import type { Wifi, WifiDevice, WifiNetwork
|
|
3
|
+
import type { NetworkDesktop } from "./network-state";
|
|
4
|
+
import type { Wifi, WifiDesktop, WifiDevice, WifiNetwork } from "./wifi-state";
|
|
5
5
|
/**
|
|
6
6
|
* Calls `onWifi` with the first station device now and after each change, and
|
|
7
7
|
* returns a function that stops watching. `None` is a machine without one.
|
|
@@ -9,16 +9,16 @@ import type { Wifi, WifiDevice, WifiNetwork, WifiSystem } from "./wifi-state";
|
|
|
9
9
|
* An `Err` is a D-Bus failure, such as iwd not running. The watch keeps
|
|
10
10
|
* listening after one, so a later change reads again.
|
|
11
11
|
*/
|
|
12
|
-
export declare const watchIwdWifi: (
|
|
12
|
+
export declare const watchIwdWifi: (domicile: NetworkDesktop, onWifi: (wifi: Result<Option<Wifi>, SystemError>) => void) => (() => void);
|
|
13
13
|
/** Turn the device on or off. */
|
|
14
|
-
export declare const setIwdWifiEnabled: (
|
|
14
|
+
export declare const setIwdWifiEnabled: (domicile: NetworkDesktop, wifi: WifiDevice, enabled: boolean) => Promise<Result<"done", SystemError>>;
|
|
15
15
|
/** Ask for a scan. Networks it finds arrive as changes. */
|
|
16
|
-
export declare const scanIwdWifi: (
|
|
16
|
+
export declare const scanIwdWifi: (domicile: NetworkDesktop, wifi: WifiDevice) => Promise<Result<"done", SystemError>>;
|
|
17
17
|
/**
|
|
18
18
|
* Join `network`. A known or open network joins over D-Bus. A new secured one
|
|
19
19
|
* joins through `iwctl`, which answers iwd's request for the passphrase: iwd
|
|
20
20
|
* asks an agent for it, and a page cannot serve one.
|
|
21
21
|
*/
|
|
22
|
-
export declare const connectIwdWifi: (
|
|
22
|
+
export declare const connectIwdWifi: (domicile: WifiDesktop, wifi: WifiDevice, network: WifiNetwork, passphrase: string | undefined) => Promise<Result<"done", SystemError>>;
|
|
23
23
|
/** Leave the current network, until asked to join one. */
|
|
24
|
-
export declare const disconnectIwdWifi: (
|
|
24
|
+
export declare const disconnectIwdWifi: (domicile: NetworkDesktop, wifi: WifiDevice) => Promise<Result<"done", SystemError>>;
|
package/dist/iwd-wifi.js
CHANGED
|
@@ -21,29 +21,29 @@ const WATCHED = [DEVICE, STATION, NETWORK];
|
|
|
21
21
|
* An `Err` is a D-Bus failure, such as iwd not running. The watch keeps
|
|
22
22
|
* listening after one, so a later change reads again.
|
|
23
23
|
*/
|
|
24
|
-
export const watchIwdWifi = (
|
|
24
|
+
export const watchIwdWifi = (domicile, onWifi) => followBus(domicile, { bus: Bus.System, sender: SERVICE }, async () => ({ matters, value: await read(domicile) }), onWifi);
|
|
25
25
|
/** Turn the device on or off. */
|
|
26
|
-
export const setIwdWifiEnabled = async (
|
|
26
|
+
export const setIwdWifiEnabled = async (domicile, wifi, enabled) => done(await domicile.dbus.call({
|
|
27
27
|
...request(wifi.device, "org.freedesktop.DBus.Properties", "Set"),
|
|
28
28
|
body: [DEVICE, "Powered", { signature: "b", value: enabled }],
|
|
29
29
|
signature: "ssv",
|
|
30
30
|
}));
|
|
31
31
|
/** Ask for a scan. Networks it finds arrive as changes. */
|
|
32
|
-
export const scanIwdWifi = async (
|
|
32
|
+
export const scanIwdWifi = async (domicile, wifi) => done(await domicile.dbus.call(request(wifi.device, STATION, "Scan")));
|
|
33
33
|
/**
|
|
34
34
|
* Join `network`. A known or open network joins over D-Bus. A new secured one
|
|
35
35
|
* joins through `iwctl`, which answers iwd's request for the passphrase: iwd
|
|
36
36
|
* asks an agent for it, and a page cannot serve one.
|
|
37
37
|
*/
|
|
38
|
-
export const connectIwdWifi = async (
|
|
38
|
+
export const connectIwdWifi = async (domicile, wifi, network, passphrase) => {
|
|
39
39
|
if (network.profile !== undefined || !network.secured) {
|
|
40
|
-
return done(await
|
|
40
|
+
return done(await domicile.dbus.call(request(network.path, NETWORK, "Connect")));
|
|
41
41
|
}
|
|
42
42
|
else if (passphrase === undefined) {
|
|
43
43
|
throw new Error(`joining ${network.ssid} needs a passphrase`);
|
|
44
44
|
}
|
|
45
45
|
else {
|
|
46
|
-
const ran = await
|
|
46
|
+
const ran = await domicile.processes.run([
|
|
47
47
|
"iwctl",
|
|
48
48
|
"--passphrase",
|
|
49
49
|
passphrase,
|
|
@@ -61,7 +61,7 @@ export const connectIwdWifi = async (system, wifi, network, passphrase) => {
|
|
|
61
61
|
}
|
|
62
62
|
};
|
|
63
63
|
/** Leave the current network, until asked to join one. */
|
|
64
|
-
export const disconnectIwdWifi = async (
|
|
64
|
+
export const disconnectIwdWifi = async (domicile, wifi) => done(await domicile.dbus.call(request(wifi.device, STATION, "Disconnect")));
|
|
65
65
|
const request = (path, iface, member) => ({
|
|
66
66
|
bus: Bus.System,
|
|
67
67
|
destination: SERVICE,
|
|
@@ -86,7 +86,7 @@ const matters = (signal) => {
|
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
};
|
|
89
|
-
const read = async (
|
|
89
|
+
const read = async (domicile) => (await domicile.dbus.call({
|
|
90
90
|
bus: Bus.System,
|
|
91
91
|
destination: SERVICE,
|
|
92
92
|
interface: "org.freedesktop.DBus.ObjectManager",
|
|
@@ -100,9 +100,9 @@ const read = async (system) => (await system.dbusCall({
|
|
|
100
100
|
})[0];
|
|
101
101
|
return station === undefined
|
|
102
102
|
? Ok(None())
|
|
103
|
-
: (await wifiOf(
|
|
103
|
+
: (await wifiOf(domicile, objects, station.path, station.device, station.held)).map((wifi) => Some(wifi));
|
|
104
104
|
});
|
|
105
|
-
const wifiOf = async (
|
|
105
|
+
const wifiOf = async (domicile, objects, path, device, held) => {
|
|
106
106
|
const off = {
|
|
107
107
|
backend: WifiBackend.Iwd,
|
|
108
108
|
connection: undefined,
|
|
@@ -116,16 +116,16 @@ const wifiOf = async (system, objects, path, device, held) => {
|
|
|
116
116
|
const station = held[STATION];
|
|
117
117
|
return station === undefined
|
|
118
118
|
? Ok(off)
|
|
119
|
-
: (await stationOf(
|
|
119
|
+
: (await stationOf(domicile, objects, path, station, held[DIAGNOSTIC])).map((found) => ({ ...off, ...found }));
|
|
120
120
|
};
|
|
121
|
-
const stationOf = async (
|
|
121
|
+
const stationOf = async (domicile, objects, path, station, diagnostic) => (await domicile.dbus.call(request(path, STATION, "GetOrderedNetworks"))).andThenAsync(async ({ body }) => {
|
|
122
122
|
const networks = orderedNetworksSchema
|
|
123
123
|
.parse(body)[0]
|
|
124
124
|
.map(([network, signal]) => networkOf(objects, network, signal));
|
|
125
125
|
const connected = networks.find(({ connected: on }) => on);
|
|
126
126
|
const connection = connected === undefined
|
|
127
127
|
? Ok(None())
|
|
128
|
-
: (await diagnosticsOf(
|
|
128
|
+
: (await diagnosticsOf(domicile, path, diagnostic)).map((found) => Some({
|
|
129
129
|
...found,
|
|
130
130
|
ip: undefined,
|
|
131
131
|
ssid: connected.ssid,
|
|
@@ -157,9 +157,9 @@ const networkOf = (objects, path, signal) => {
|
|
|
157
157
|
}
|
|
158
158
|
};
|
|
159
159
|
/** The link's frequency and bitrate, when iwd offers diagnostics. */
|
|
160
|
-
const diagnosticsOf = async (
|
|
160
|
+
const diagnosticsOf = async (domicile, path, diagnostic) => diagnostic === undefined
|
|
161
161
|
? Ok({ bitrate: undefined, frequency: undefined })
|
|
162
|
-
: (await
|
|
162
|
+
: (await domicile.dbus.call(request(path, DIAGNOSTIC, "GetDiagnostics"))).map(({ body }) => {
|
|
163
163
|
const [found] = diagnosticsSchema.parse(body);
|
|
164
164
|
return { bitrate: found.RxBitrate / 10, frequency: found.Frequency };
|
|
165
165
|
});
|
package/dist/iwd.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Result } from "@cprussin/option-result";
|
|
2
2
|
import type { SystemError } from "@domicile-desktop/sdk/system";
|
|
3
|
-
import type { Network,
|
|
3
|
+
import type { Network, NetworkDesktop } from "./network-state";
|
|
4
4
|
/**
|
|
5
5
|
* Calls `onNetwork` with iwd's network now and after each change, and returns
|
|
6
6
|
* a function that stops watching.
|
|
@@ -10,4 +10,4 @@ import type { Network, NetworkSystem } from "./network-state";
|
|
|
10
10
|
* not running. The watch keeps listening after one, so a later change reads
|
|
11
11
|
* again.
|
|
12
12
|
*/
|
|
13
|
-
export declare const watchIwd: (
|
|
13
|
+
export declare const watchIwd: (domicile: NetworkDesktop, onNetwork: (network: Result<Network, SystemError>) => void) => (() => void);
|
package/dist/iwd.js
CHANGED
|
@@ -24,7 +24,7 @@ const WATCHED = ["ConnectedNetwork", "Scanning", "State"];
|
|
|
24
24
|
* not running. The watch keeps listening after one, so a later change reads
|
|
25
25
|
* again.
|
|
26
26
|
*/
|
|
27
|
-
export const watchIwd = (
|
|
27
|
+
export const watchIwd = (domicile, onNetwork) => followBus(domicile, { bus: Bus.System, sender: SERVICE }, async () => ({ matters, value: await read(domicile) }), onNetwork);
|
|
28
28
|
/**
|
|
29
29
|
* Whether `signal` can change the network: an object coming or going, or a
|
|
30
30
|
* watched station property.
|
|
@@ -44,8 +44,8 @@ const matters = (signal) => {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
};
|
|
47
|
-
const read = async (
|
|
48
|
-
const objects = await
|
|
47
|
+
const read = async (domicile) => {
|
|
48
|
+
const objects = await domicile.dbus.call({
|
|
49
49
|
bus: Bus.System,
|
|
50
50
|
destination: SERVICE,
|
|
51
51
|
interface: "org.freedesktop.DBus.ObjectManager",
|
|
@@ -54,11 +54,11 @@ const read = async (system) => {
|
|
|
54
54
|
});
|
|
55
55
|
return objects.match({
|
|
56
56
|
Err: (error) => Promise.resolve(Err(error)),
|
|
57
|
-
Ok: async ({ body }) => (await linkOf(
|
|
57
|
+
Ok: async ({ body }) => (await linkOf(domicile, managedObjectsSchema.parse(body)[0])).map((link) => ({ connectivity: Connectivity.Unknown, link })),
|
|
58
58
|
});
|
|
59
59
|
};
|
|
60
60
|
/** The first connected station's network, or `None`. */
|
|
61
|
-
const linkOf = async (
|
|
61
|
+
const linkOf = async (domicile, objects) => {
|
|
62
62
|
const station = Object.entries(objects).flatMap(([path, held]) => held[STATION] !== undefined && isOnline(held[STATION].State)
|
|
63
63
|
? [{ network: connectedNetwork(path, held[STATION]), path }]
|
|
64
64
|
: [])[0];
|
|
@@ -66,7 +66,7 @@ const linkOf = async (system, objects) => {
|
|
|
66
66
|
return Ok(Link.None());
|
|
67
67
|
}
|
|
68
68
|
else {
|
|
69
|
-
const ordered = await
|
|
69
|
+
const ordered = await domicile.dbus.call({
|
|
70
70
|
bus: Bus.System,
|
|
71
71
|
destination: SERVICE,
|
|
72
72
|
interface: STATION,
|
package/dist/network-state.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Dbus } from "@domicile-desktop/sdk/desktop/dbus";
|
|
2
2
|
/** Whether the host reaches the internet. */
|
|
3
3
|
export declare enum Connectivity {
|
|
4
4
|
Unknown = 0,
|
|
@@ -42,4 +42,6 @@ export type Network = {
|
|
|
42
42
|
link: Link;
|
|
43
43
|
};
|
|
44
44
|
/** The calls this library makes. */
|
|
45
|
-
export type
|
|
45
|
+
export type NetworkDesktop = {
|
|
46
|
+
readonly dbus: Pick<Dbus, "call" | "match">;
|
|
47
|
+
};
|
package/dist/network.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Result } from "@cprussin/option-result";
|
|
2
2
|
import type { SystemError } from "@domicile-desktop/sdk/system";
|
|
3
|
-
import type { Network,
|
|
4
|
-
export type { Network,
|
|
3
|
+
import type { Network, NetworkDesktop } from "./network-state";
|
|
4
|
+
export type { Network, NetworkDesktop } from "./network-state";
|
|
5
5
|
export { Connectivity, Link, LinkKind } from "./network-state";
|
|
6
6
|
/**
|
|
7
7
|
* Calls `onNetwork` with the network now and after each change, and returns a
|
|
@@ -12,4 +12,4 @@ export { Connectivity, Link, LinkKind } from "./network-state";
|
|
|
12
12
|
* watch. An `Err` is a D-Bus failure, such as none of them running. When the
|
|
13
13
|
* bus cannot say which runs, the watch reports that `Err` and ends.
|
|
14
14
|
*/
|
|
15
|
-
export declare const watchNetwork: (
|
|
15
|
+
export declare const watchNetwork: (domicile: NetworkDesktop, onNetwork: (network: Result<Network, SystemError>) => void) => (() => void);
|
package/dist/network.js
CHANGED
|
@@ -23,9 +23,9 @@ const BACKENDS = [
|
|
|
23
23
|
* watch. An `Err` is a D-Bus failure, such as none of them running. When the
|
|
24
24
|
* bus cannot say which runs, the watch reports that `Err` and ends.
|
|
25
25
|
*/
|
|
26
|
-
export const watchNetwork = (
|
|
26
|
+
export const watchNetwork = (domicile, onNetwork) => {
|
|
27
27
|
const watch = { stop: undefined, stopped: false };
|
|
28
|
-
detect(
|
|
28
|
+
detect(domicile, BACKENDS)
|
|
29
29
|
.then((found) => {
|
|
30
30
|
if (!watch.stopped) {
|
|
31
31
|
found.match({
|
|
@@ -33,7 +33,7 @@ export const watchNetwork = (system, onNetwork) => {
|
|
|
33
33
|
onNetwork(Err(error));
|
|
34
34
|
},
|
|
35
35
|
Ok: (backend) => {
|
|
36
|
-
watch.stop = backend(
|
|
36
|
+
watch.stop = backend(domicile, onNetwork);
|
|
37
37
|
},
|
|
38
38
|
});
|
|
39
39
|
}
|
|
@@ -48,17 +48,17 @@ export const watchNetwork = (system, onNetwork) => {
|
|
|
48
48
|
};
|
|
49
49
|
};
|
|
50
50
|
/** The first backend whose service has an owner on the bus. */
|
|
51
|
-
const detect = async (
|
|
51
|
+
const detect = async (domicile, backends) => {
|
|
52
52
|
const [first, ...rest] = backends;
|
|
53
53
|
if (first === undefined) {
|
|
54
54
|
return Ok(watchNetworkManager);
|
|
55
55
|
}
|
|
56
56
|
else {
|
|
57
57
|
const [name, backend] = first;
|
|
58
|
-
const owned = await hasOwner(
|
|
58
|
+
const owned = await hasOwner(domicile, name);
|
|
59
59
|
return owned.match({
|
|
60
60
|
Err: (error) => Promise.resolve(Err(error)),
|
|
61
|
-
Ok: (has) =>
|
|
61
|
+
Ok: (has) => has ? Promise.resolve(Ok(backend)) : detect(domicile, rest),
|
|
62
62
|
});
|
|
63
63
|
}
|
|
64
64
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Option } from "@cprussin/option-result";
|
|
2
2
|
import { Result } from "@cprussin/option-result";
|
|
3
3
|
import type { SystemError } from "@domicile-desktop/sdk/system";
|
|
4
|
-
import type {
|
|
4
|
+
import type { NetworkDesktop } from "./network-state";
|
|
5
5
|
import type { Wifi, WifiDevice, WifiNetwork } from "./wifi-state";
|
|
6
6
|
/** A read's outcome: Wi-Fi, if there is a device, or the first failure. */
|
|
7
7
|
type Found = Result<Option<Wifi>, SystemError>;
|
|
@@ -12,16 +12,16 @@ type Found = Result<Option<Wifi>, SystemError>;
|
|
|
12
12
|
* An `Err` is a D-Bus failure, such as NetworkManager not running. The watch
|
|
13
13
|
* keeps listening after one, so a later change reads again.
|
|
14
14
|
*/
|
|
15
|
-
export declare const watchNetworkManagerWifi: (
|
|
15
|
+
export declare const watchNetworkManagerWifi: (domicile: NetworkDesktop, onWifi: (wifi: Found) => void) => (() => void);
|
|
16
16
|
/** Turn the Wi-Fi radio on or off. */
|
|
17
|
-
export declare const setNetworkManagerWifiEnabled: (
|
|
17
|
+
export declare const setNetworkManagerWifiEnabled: (domicile: NetworkDesktop, _wifi: WifiDevice, enabled: boolean) => Promise<Result<"done", SystemError>>;
|
|
18
18
|
/** Ask for a scan. Networks it finds arrive as changes. */
|
|
19
|
-
export declare const scanNetworkManagerWifi: (
|
|
19
|
+
export declare const scanNetworkManagerWifi: (domicile: NetworkDesktop, wifi: WifiDevice) => Promise<Result<"done", SystemError>>;
|
|
20
20
|
/**
|
|
21
21
|
* Join `network`: through its saved profile if it has one, or with a new
|
|
22
22
|
* profile, which needs `passphrase` when the network is secured.
|
|
23
23
|
*/
|
|
24
|
-
export declare const connectNetworkManagerWifi: (
|
|
24
|
+
export declare const connectNetworkManagerWifi: (domicile: NetworkDesktop, wifi: WifiDevice, network: WifiNetwork, passphrase: string | undefined) => Promise<Result<"done", SystemError>>;
|
|
25
25
|
/** Leave the current network, until asked to join one. */
|
|
26
|
-
export declare const disconnectNetworkManagerWifi: (
|
|
26
|
+
export declare const disconnectNetworkManagerWifi: (domicile: NetworkDesktop, wifi: WifiDevice) => Promise<Result<"done", SystemError>>;
|
|
27
27
|
export {};
|
|
@@ -22,20 +22,20 @@ const WIFI_DEVICE = 2;
|
|
|
22
22
|
* An `Err` is a D-Bus failure, such as NetworkManager not running. The watch
|
|
23
23
|
* keeps listening after one, so a later change reads again.
|
|
24
24
|
*/
|
|
25
|
-
export const watchNetworkManagerWifi = (
|
|
25
|
+
export const watchNetworkManagerWifi = (domicile, onWifi) => followBus(domicile, { bus: Bus.System, sender: SERVICE }, () => read(domicile), onWifi);
|
|
26
26
|
/** Turn the Wi-Fi radio on or off. */
|
|
27
|
-
export const setNetworkManagerWifiEnabled = async (
|
|
27
|
+
export const setNetworkManagerWifiEnabled = async (domicile, _wifi, enabled) => done(await domicile.dbus.call(request(ROOT, "org.freedesktop.DBus.Properties", "Set", "ssv", [
|
|
28
28
|
SERVICE,
|
|
29
29
|
"WirelessEnabled",
|
|
30
30
|
{ signature: "b", value: enabled },
|
|
31
31
|
])));
|
|
32
32
|
/** Ask for a scan. Networks it finds arrive as changes. */
|
|
33
|
-
export const scanNetworkManagerWifi = async (
|
|
33
|
+
export const scanNetworkManagerWifi = async (domicile, wifi) => done(await domicile.dbus.call(request(wifi.device, WIRELESS, "RequestScan", "a{sv}", [{}])));
|
|
34
34
|
/**
|
|
35
35
|
* Join `network`: through its saved profile if it has one, or with a new
|
|
36
36
|
* profile, which needs `passphrase` when the network is secured.
|
|
37
37
|
*/
|
|
38
|
-
export const connectNetworkManagerWifi = async (
|
|
38
|
+
export const connectNetworkManagerWifi = async (domicile, wifi, network, passphrase) => done(await domicile.dbus.call(network.profile === undefined
|
|
39
39
|
? request(ROOT, SERVICE, "AddAndActivateConnection", "a{sa{sv}}oo", [
|
|
40
40
|
newProfile(network, passphrase),
|
|
41
41
|
wifi.device,
|
|
@@ -47,7 +47,7 @@ export const connectNetworkManagerWifi = async (system, wifi, network, passphras
|
|
|
47
47
|
network.path,
|
|
48
48
|
])));
|
|
49
49
|
/** Leave the current network, until asked to join one. */
|
|
50
|
-
export const disconnectNetworkManagerWifi = async (
|
|
50
|
+
export const disconnectNetworkManagerWifi = async (domicile, wifi) => done(await domicile.dbus.call({
|
|
51
51
|
bus: Bus.System,
|
|
52
52
|
destination: SERVICE,
|
|
53
53
|
interface: DEVICE,
|
|
@@ -85,9 +85,9 @@ const newProfile = (network, passphrase) => {
|
|
|
85
85
|
* Read Wi-Fi. A property change on an object read for it matters, as does an
|
|
86
86
|
* access point or a device coming or going.
|
|
87
87
|
*/
|
|
88
|
-
const read = async (
|
|
88
|
+
const read = async (domicile) => {
|
|
89
89
|
const paths = new Set([ROOT]);
|
|
90
|
-
const value = await readWifi(
|
|
90
|
+
const value = await readWifi(domicile, paths);
|
|
91
91
|
return { matters: (signal) => matters(paths, signal), value };
|
|
92
92
|
};
|
|
93
93
|
const matters = (paths, signal) => {
|
|
@@ -108,31 +108,31 @@ const matters = (paths, signal) => {
|
|
|
108
108
|
}
|
|
109
109
|
};
|
|
110
110
|
/** Read Wi-Fi, adding each object read to `paths`. */
|
|
111
|
-
const readWifi = async (
|
|
111
|
+
const readWifi = async (domicile, paths) => (await properties(domicile, ROOT, SERVICE, rootSchema)).andThenAsync(async ({ WirelessEnabled: enabled }) => (await call(domicile, ROOT, SERVICE, "GetDevices")).andThenAsync(async ({ body }) => {
|
|
112
112
|
const listed = devicesSchema.parse(body)[0];
|
|
113
113
|
for (const path of listed) {
|
|
114
114
|
paths.add(path);
|
|
115
115
|
}
|
|
116
|
-
const devices = Result.collect(await Promise.all(listed.map(async (path) => (await properties(
|
|
116
|
+
const devices = Result.collect(await Promise.all(listed.map(async (path) => (await properties(domicile, path, DEVICE, deviceSchema)).map((device) => ({ device, path })))));
|
|
117
117
|
return devices.andThenAsync(async (read) => {
|
|
118
118
|
const found = read.find(({ device }) => device.DeviceType === WIFI_DEVICE);
|
|
119
119
|
return found === undefined
|
|
120
120
|
? Ok(None())
|
|
121
|
-
: (await wifiOf(
|
|
121
|
+
: (await wifiOf(domicile, paths, found.path, found.device, enabled)).map((wifi) => Some(wifi));
|
|
122
122
|
});
|
|
123
123
|
}));
|
|
124
124
|
/** The Wi-Fi device at `path`. */
|
|
125
|
-
const wifiOf = async (
|
|
125
|
+
const wifiOf = async (domicile, paths, path, device, enabled) => (await properties(domicile, path, WIRELESS, wirelessSchema)).andThenAsync(async (radio) => {
|
|
126
126
|
for (const point of radio.AccessPoints) {
|
|
127
127
|
paths.add(point);
|
|
128
128
|
}
|
|
129
129
|
paths.add(device.Ip4Config);
|
|
130
130
|
const [points, profiles, ip] = await Promise.all([
|
|
131
|
-
accessPoints(
|
|
132
|
-
savedProfiles(
|
|
131
|
+
accessPoints(domicile, radio.AccessPoints),
|
|
132
|
+
savedProfiles(domicile, device.AvailableConnections),
|
|
133
133
|
radio.ActiveAccessPoint === NO_OBJECT || device.Ip4Config === NO_OBJECT
|
|
134
134
|
? Promise.resolve(Ok(None()))
|
|
135
|
-
: ipOf(
|
|
135
|
+
: ipOf(domicile, device.Ip4Config),
|
|
136
136
|
]);
|
|
137
137
|
return points.andThen((read) => profiles.andThen((saved) => ip.map((address) => ({
|
|
138
138
|
backend: WifiBackend.NetworkManager,
|
|
@@ -145,16 +145,16 @@ const wifiOf = async (system, paths, path, device, enabled) => (await properties
|
|
|
145
145
|
scanning: false,
|
|
146
146
|
}))));
|
|
147
147
|
});
|
|
148
|
-
const accessPoints = async (
|
|
148
|
+
const accessPoints = async (domicile, listed) => Result.collect(await Promise.all(listed.map(async (path) => (await properties(domicile, path, `${SERVICE}.AccessPoint`, accessPointSchema)).map((point) => ({ ...point, path })))));
|
|
149
149
|
/** Each saved Wi-Fi profile's path, by its network's name. */
|
|
150
|
-
const savedProfiles = async (
|
|
150
|
+
const savedProfiles = async (domicile, listed) => Result.collect(await Promise.all(listed.map(async (path) => (await call(domicile, path, `${SERVICE}.Settings.Connection`, "GetSettings")).map(({ body }) => ({
|
|
151
151
|
path,
|
|
152
152
|
settings: settingsSchema.parse(body)[0],
|
|
153
153
|
}))))).map((saved) => new Map(saved.flatMap(({ path, settings }) => {
|
|
154
154
|
const ssid = settings["802-11-wireless"]?.ssid;
|
|
155
155
|
return ssid === undefined ? [] : [[ssid, path]];
|
|
156
156
|
})));
|
|
157
|
-
const ipOf = async (
|
|
157
|
+
const ipOf = async (domicile, path) => (await properties(domicile, path, `${SERVICE}.IP4Config`, ip4Schema)).map((config) => Some({
|
|
158
158
|
addresses: config.AddressData.map(({ address, prefix }) => `${address}/${prefix}`),
|
|
159
159
|
dns: config.NameserverData.map(({ address }) => address),
|
|
160
160
|
gateway: config.Gateway === "" ? undefined : config.Gateway,
|
|
@@ -198,7 +198,7 @@ const connectionOf = (points, radio, ip) => {
|
|
|
198
198
|
};
|
|
199
199
|
/** `NM_802_11_AP_FLAGS_PRIVACY`, or any WPA or RSN flag. */
|
|
200
200
|
const isSecured = (point) => (point.Flags & 1) !== 0 || point.WpaFlags !== 0 || point.RsnFlags !== 0;
|
|
201
|
-
const call = (
|
|
201
|
+
const call = (domicile, path, iface, member) => domicile.dbus.call({
|
|
202
202
|
bus: Bus.System,
|
|
203
203
|
destination: SERVICE,
|
|
204
204
|
interface: iface,
|
|
@@ -206,7 +206,7 @@ const call = (system, path, iface, member) => system.dbusCall({
|
|
|
206
206
|
path,
|
|
207
207
|
});
|
|
208
208
|
/** `Properties.GetAll` on one of NetworkManager's objects, parsed. */
|
|
209
|
-
const properties = async (
|
|
209
|
+
const properties = async (domicile, path, interfaceName, schema) => (await domicile.dbus.call({
|
|
210
210
|
body: [interfaceName],
|
|
211
211
|
bus: Bus.System,
|
|
212
212
|
destination: SERVICE,
|
package/dist/networkmanager.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Result } from "@cprussin/option-result";
|
|
2
2
|
import type { SystemError } from "@domicile-desktop/sdk/system";
|
|
3
|
-
import type { Network,
|
|
3
|
+
import type { Network, NetworkDesktop } from "./network-state";
|
|
4
4
|
/**
|
|
5
5
|
* Calls `onNetwork` with NetworkManager's network now and after each change,
|
|
6
6
|
* and returns a function that stops watching.
|
|
@@ -8,4 +8,4 @@ import type { Network, NetworkSystem } from "./network-state";
|
|
|
8
8
|
* An `Err` is a D-Bus failure, such as NetworkManager not running. The watch
|
|
9
9
|
* keeps listening after one, so a later change reads again.
|
|
10
10
|
*/
|
|
11
|
-
export declare const watchNetworkManager: (
|
|
11
|
+
export declare const watchNetworkManager: (domicile: NetworkDesktop, onNetwork: (network: Result<Network, SystemError>) => void) => (() => void);
|
package/dist/networkmanager.js
CHANGED
|
@@ -17,22 +17,22 @@ const NO_OBJECT = "/";
|
|
|
17
17
|
* An `Err` is a D-Bus failure, such as NetworkManager not running. The watch
|
|
18
18
|
* keeps listening after one, so a later change reads again.
|
|
19
19
|
*/
|
|
20
|
-
export const watchNetworkManager = (
|
|
20
|
+
export const watchNetworkManager = (domicile, onNetwork) => followBus(domicile, {
|
|
21
21
|
bus: Bus.System,
|
|
22
22
|
interface: "org.freedesktop.DBus.Properties",
|
|
23
23
|
member: "PropertiesChanged",
|
|
24
24
|
sender: SERVICE,
|
|
25
|
-
}, () => read(
|
|
25
|
+
}, () => read(domicile), onNetwork);
|
|
26
26
|
/** Read the network; a change to any object read for it matters. */
|
|
27
|
-
const read = async (
|
|
28
|
-
const root = await properties(
|
|
27
|
+
const read = async (domicile) => {
|
|
28
|
+
const root = await properties(domicile, ROOT, SERVICE, rootSchema);
|
|
29
29
|
return root.match({
|
|
30
30
|
Err: (error) => Promise.resolve({
|
|
31
31
|
matters: ({ path }) => path === ROOT,
|
|
32
32
|
value: Err(error),
|
|
33
33
|
}),
|
|
34
34
|
Ok: async ({ Connectivity: connectivity, PrimaryConnection: primary }) => {
|
|
35
|
-
const link = await linkOf(
|
|
35
|
+
const link = await linkOf(domicile, primary);
|
|
36
36
|
const paths = new Set([ROOT, ...link.paths]);
|
|
37
37
|
return {
|
|
38
38
|
matters: ({ path }) => paths.has(path),
|
|
@@ -45,18 +45,18 @@ const read = async (system) => {
|
|
|
45
45
|
});
|
|
46
46
|
};
|
|
47
47
|
/** The primary connection at `path`. */
|
|
48
|
-
const linkOf = async (
|
|
48
|
+
const linkOf = async (domicile, path) => {
|
|
49
49
|
if (path === NO_OBJECT) {
|
|
50
50
|
return { paths: [], result: Ok(Link.None()) };
|
|
51
51
|
}
|
|
52
52
|
else {
|
|
53
|
-
const active = await properties(
|
|
53
|
+
const active = await properties(domicile, path, `${SERVICE}.Connection.Active`, activeSchema);
|
|
54
54
|
return active.match({
|
|
55
55
|
Err: (error) => Promise.resolve({ paths: [path], result: Err(error) }),
|
|
56
56
|
Ok: async ({ Id: name, SpecificObject: specific, Type: type, }) => {
|
|
57
57
|
switch (type) {
|
|
58
58
|
case "802-11-wireless": {
|
|
59
|
-
const point = await properties(
|
|
59
|
+
const point = await properties(domicile, specific, `${SERVICE}.AccessPoint`, accessPointSchema);
|
|
60
60
|
return {
|
|
61
61
|
paths: [path, specific],
|
|
62
62
|
result: point.map(({ Ssid: ssid, Strength: strength }) => Link.Wifi(new TextDecoder().decode(new Uint8Array(ssid)), strength / 100)),
|
|
@@ -74,7 +74,7 @@ const linkOf = async (system, path) => {
|
|
|
74
74
|
}
|
|
75
75
|
};
|
|
76
76
|
/** `Properties.GetAll` on one of NetworkManager's objects, parsed. */
|
|
77
|
-
const properties = async (
|
|
77
|
+
const properties = async (domicile, path, interfaceName, schema) => (await domicile.dbus.call({
|
|
78
78
|
body: [interfaceName],
|
|
79
79
|
bus: Bus.System,
|
|
80
80
|
destination: SERVICE,
|
package/dist/portal.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Option, Result } from "@cprussin/option-result";
|
|
2
|
-
import type {
|
|
2
|
+
import type { Processes } from "@domicile-desktop/sdk/desktop/processes";
|
|
3
|
+
import type { SystemError } from "@domicile-desktop/sdk/system";
|
|
3
4
|
/** Chrome's portal probe: `204 No Content` on the open internet. Plain http, so a portal can intercept it. */
|
|
4
5
|
export declare const PORTAL_PROBE = "http://www.gstatic.com/generate_204";
|
|
5
6
|
/**
|
|
@@ -9,4 +10,6 @@ export declare const PORTAL_PROBE = "http://www.gstatic.com/generate_204";
|
|
|
9
10
|
* Retries a probe that gets no answer, since an address or a route can arrive
|
|
10
11
|
* a moment after the network does. An `Err` is a probe that never got one.
|
|
11
12
|
*/
|
|
12
|
-
export declare const checkPortal: (
|
|
13
|
+
export declare const checkPortal: (domicile: {
|
|
14
|
+
readonly processes: Pick<Processes, "run">;
|
|
15
|
+
}) => Promise<Result<Option<string>, SystemError>>;
|
package/dist/portal.js
CHANGED
|
@@ -16,7 +16,7 @@ const RETRIES = "3";
|
|
|
16
16
|
* Retries a probe that gets no answer, since an address or a route can arrive
|
|
17
17
|
* a moment after the network does. An `Err` is a probe that never got one.
|
|
18
18
|
*/
|
|
19
|
-
export const checkPortal = async (
|
|
19
|
+
export const checkPortal = async (domicile) => (await domicile.processes.run([
|
|
20
20
|
"curl",
|
|
21
21
|
"--silent",
|
|
22
22
|
"--output",
|
package/dist/wifi-state.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Dbus } from "@domicile-desktop/sdk/desktop/dbus";
|
|
2
|
+
import type { Processes } from "@domicile-desktop/sdk/desktop/processes";
|
|
2
3
|
/** The service that manages the Wi-Fi device. */
|
|
3
4
|
export declare enum WifiBackend {
|
|
4
5
|
NetworkManager = 0,
|
|
@@ -51,4 +52,7 @@ export type Wifi = {
|
|
|
51
52
|
/** What a request needs of the device. */
|
|
52
53
|
export type WifiDevice = Pick<Wifi, "backend" | "device" | "interface">;
|
|
53
54
|
/** The calls this library makes for Wi-Fi. */
|
|
54
|
-
export type
|
|
55
|
+
export type WifiDesktop = {
|
|
56
|
+
readonly dbus: Pick<Dbus, "call" | "match">;
|
|
57
|
+
readonly processes: Pick<Processes, "run">;
|
|
58
|
+
};
|
package/dist/wifi.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Option, Result } from "@cprussin/option-result";
|
|
2
2
|
import type { SystemError } from "@domicile-desktop/sdk/system";
|
|
3
|
-
import type { Wifi, WifiDevice, WifiNetwork
|
|
4
|
-
export type { Ip, Wifi, WifiConnection, WifiDevice, WifiNetwork,
|
|
3
|
+
import type { Wifi, WifiDesktop, WifiDevice, WifiNetwork } from "./wifi-state";
|
|
4
|
+
export type { Ip, Wifi, WifiConnection, WifiDesktop, WifiDevice, WifiNetwork, } from "./wifi-state";
|
|
5
5
|
export { WifiBackend } from "./wifi-state";
|
|
6
6
|
/**
|
|
7
7
|
* Calls `onWifi` with the Wi-Fi device now and after each change, and returns
|
|
@@ -11,15 +11,15 @@ export { WifiBackend } from "./wifi-state";
|
|
|
11
11
|
* `None` is no Wi-Fi device, or neither service: wpa_supplicant alone is not
|
|
12
12
|
* controlled. An `Err` is a D-Bus failure.
|
|
13
13
|
*/
|
|
14
|
-
export declare const watchWifi: (
|
|
14
|
+
export declare const watchWifi: (domicile: WifiDesktop, onWifi: (wifi: Result<Option<Wifi>, SystemError>) => void) => (() => void);
|
|
15
15
|
/** Turn the radio on or off. */
|
|
16
|
-
export declare const setWifiEnabled: (
|
|
16
|
+
export declare const setWifiEnabled: (domicile: WifiDesktop, wifi: WifiDevice, enabled: boolean) => Promise<Result<"done", SystemError>>;
|
|
17
17
|
/** Ask for a scan. Networks it finds arrive through the watch. */
|
|
18
|
-
export declare const scanWifi: (
|
|
18
|
+
export declare const scanWifi: (domicile: WifiDesktop, wifi: WifiDevice) => Promise<Result<"done", SystemError>>;
|
|
19
19
|
/**
|
|
20
20
|
* Join `network`. A secured network with no saved profile needs `passphrase`;
|
|
21
21
|
* the call throws without one.
|
|
22
22
|
*/
|
|
23
|
-
export declare const connectWifi: (
|
|
23
|
+
export declare const connectWifi: (domicile: WifiDesktop, wifi: WifiDevice, network: WifiNetwork, passphrase: string | undefined) => Promise<Result<"done", SystemError>>;
|
|
24
24
|
/** Leave the current network. */
|
|
25
|
-
export declare const disconnectWifi: (
|
|
25
|
+
export declare const disconnectWifi: (domicile: WifiDesktop, wifi: WifiDevice) => Promise<Result<"done", SystemError>>;
|
package/dist/wifi.js
CHANGED
|
@@ -21,9 +21,9 @@ const BACKENDS = [
|
|
|
21
21
|
* `None` is no Wi-Fi device, or neither service: wpa_supplicant alone is not
|
|
22
22
|
* controlled. An `Err` is a D-Bus failure.
|
|
23
23
|
*/
|
|
24
|
-
export const watchWifi = (
|
|
24
|
+
export const watchWifi = (domicile, onWifi) => {
|
|
25
25
|
const watch = { stop: undefined, stopped: false };
|
|
26
|
-
detect(
|
|
26
|
+
detect(domicile, BACKENDS)
|
|
27
27
|
.then((found) => {
|
|
28
28
|
if (!watch.stopped) {
|
|
29
29
|
found.match({
|
|
@@ -36,7 +36,7 @@ export const watchWifi = (system, onWifi) => {
|
|
|
36
36
|
onWifi(Ok(None()));
|
|
37
37
|
},
|
|
38
38
|
Some: (chosen) => {
|
|
39
|
-
watch.stop = watchBackend(chosen)(
|
|
39
|
+
watch.stop = watchBackend(chosen)(domicile, onWifi);
|
|
40
40
|
},
|
|
41
41
|
});
|
|
42
42
|
},
|
|
@@ -53,42 +53,42 @@ export const watchWifi = (system, onWifi) => {
|
|
|
53
53
|
};
|
|
54
54
|
};
|
|
55
55
|
/** Turn the radio on or off. */
|
|
56
|
-
export const setWifiEnabled = (
|
|
56
|
+
export const setWifiEnabled = (domicile, wifi, enabled) => {
|
|
57
57
|
switch (wifi.backend) {
|
|
58
58
|
case WifiBackend.NetworkManager:
|
|
59
|
-
return setNetworkManagerWifiEnabled(
|
|
59
|
+
return setNetworkManagerWifiEnabled(domicile, wifi, enabled);
|
|
60
60
|
case WifiBackend.Iwd:
|
|
61
|
-
return setIwdWifiEnabled(
|
|
61
|
+
return setIwdWifiEnabled(domicile, wifi, enabled);
|
|
62
62
|
}
|
|
63
63
|
};
|
|
64
64
|
/** Ask for a scan. Networks it finds arrive through the watch. */
|
|
65
|
-
export const scanWifi = (
|
|
65
|
+
export const scanWifi = (domicile, wifi) => {
|
|
66
66
|
switch (wifi.backend) {
|
|
67
67
|
case WifiBackend.NetworkManager:
|
|
68
|
-
return scanNetworkManagerWifi(
|
|
68
|
+
return scanNetworkManagerWifi(domicile, wifi);
|
|
69
69
|
case WifiBackend.Iwd:
|
|
70
|
-
return scanIwdWifi(
|
|
70
|
+
return scanIwdWifi(domicile, wifi);
|
|
71
71
|
}
|
|
72
72
|
};
|
|
73
73
|
/**
|
|
74
74
|
* Join `network`. A secured network with no saved profile needs `passphrase`;
|
|
75
75
|
* the call throws without one.
|
|
76
76
|
*/
|
|
77
|
-
export const connectWifi = (
|
|
77
|
+
export const connectWifi = (domicile, wifi, network, passphrase) => {
|
|
78
78
|
switch (wifi.backend) {
|
|
79
79
|
case WifiBackend.NetworkManager:
|
|
80
|
-
return connectNetworkManagerWifi(
|
|
80
|
+
return connectNetworkManagerWifi(domicile, wifi, network, passphrase);
|
|
81
81
|
case WifiBackend.Iwd:
|
|
82
|
-
return connectIwdWifi(
|
|
82
|
+
return connectIwdWifi(domicile, wifi, network, passphrase);
|
|
83
83
|
}
|
|
84
84
|
};
|
|
85
85
|
/** Leave the current network. */
|
|
86
|
-
export const disconnectWifi = (
|
|
86
|
+
export const disconnectWifi = (domicile, wifi) => {
|
|
87
87
|
switch (wifi.backend) {
|
|
88
88
|
case WifiBackend.NetworkManager:
|
|
89
|
-
return disconnectNetworkManagerWifi(
|
|
89
|
+
return disconnectNetworkManagerWifi(domicile, wifi);
|
|
90
90
|
case WifiBackend.Iwd:
|
|
91
|
-
return disconnectIwdWifi(
|
|
91
|
+
return disconnectIwdWifi(domicile, wifi);
|
|
92
92
|
}
|
|
93
93
|
};
|
|
94
94
|
const watchBackend = (backend) => {
|
|
@@ -100,17 +100,17 @@ const watchBackend = (backend) => {
|
|
|
100
100
|
}
|
|
101
101
|
};
|
|
102
102
|
/** The first backend whose service has an owner on the bus, if any. */
|
|
103
|
-
const detect = async (
|
|
103
|
+
const detect = async (domicile, backends) => {
|
|
104
104
|
const [first, ...rest] = backends;
|
|
105
105
|
if (first === undefined) {
|
|
106
106
|
return Ok(None());
|
|
107
107
|
}
|
|
108
108
|
else {
|
|
109
109
|
const [name, backend] = first;
|
|
110
|
-
const owned = await hasOwner(
|
|
110
|
+
const owned = await hasOwner(domicile, name);
|
|
111
111
|
return owned.match({
|
|
112
112
|
Err: (error) => Promise.resolve(Err(error)),
|
|
113
|
-
Ok: (has) => has ? Promise.resolve(Ok(Some(backend))) : detect(
|
|
113
|
+
Ok: (has) => has ? Promise.resolve(Ok(Some(backend))) : detect(domicile, rest),
|
|
114
114
|
});
|
|
115
115
|
}
|
|
116
116
|
};
|
package/dist/wpa-supplicant.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Result } from "@cprussin/option-result";
|
|
2
2
|
import type { SystemError } from "@domicile-desktop/sdk/system";
|
|
3
|
-
import type { Network,
|
|
3
|
+
import type { Network, NetworkDesktop } from "./network-state";
|
|
4
4
|
/**
|
|
5
5
|
* Calls `onNetwork` with wpa_supplicant's network now and after each change,
|
|
6
6
|
* and returns a function that stops watching. wpa_supplicant is on the bus
|
|
@@ -11,4 +11,4 @@ import type { Network, NetworkSystem } from "./network-state";
|
|
|
11
11
|
* such as wpa_supplicant not on the bus. The watch keeps listening after one,
|
|
12
12
|
* so a later change reads again.
|
|
13
13
|
*/
|
|
14
|
-
export declare const watchWpaSupplicant: (
|
|
14
|
+
export declare const watchWpaSupplicant: (domicile: NetworkDesktop, onNetwork: (network: Result<Network, SystemError>) => void) => (() => void);
|
package/dist/wpa-supplicant.js
CHANGED
|
@@ -19,13 +19,13 @@ const ROOT = "/fi/w1/wpa_supplicant1";
|
|
|
19
19
|
* such as wpa_supplicant not on the bus. The watch keeps listening after one,
|
|
20
20
|
* so a later change reads again.
|
|
21
21
|
*/
|
|
22
|
-
export const watchWpaSupplicant = (
|
|
22
|
+
export const watchWpaSupplicant = (domicile, onNetwork) => followBus(domicile, { bus: Bus.System, sender: SERVICE }, () => read(domicile), onNetwork);
|
|
23
23
|
/**
|
|
24
24
|
* Read the network. An interface coming or going matters, as does a property
|
|
25
25
|
* change on an object read for it.
|
|
26
26
|
*/
|
|
27
|
-
const read = async (
|
|
28
|
-
const found = await readPaths(
|
|
27
|
+
const read = async (domicile) => {
|
|
28
|
+
const found = await readPaths(domicile);
|
|
29
29
|
return {
|
|
30
30
|
matters: (signal) => matters(found.paths, signal),
|
|
31
31
|
value: found.network.map((link) => ({
|
|
@@ -53,12 +53,12 @@ const matters = (paths, signal) => {
|
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
};
|
|
56
|
-
const readPaths = async (
|
|
57
|
-
const root = await properties(
|
|
56
|
+
const readPaths = async (domicile) => {
|
|
57
|
+
const root = await properties(domicile, ROOT, SERVICE, rootSchema);
|
|
58
58
|
return root.match({
|
|
59
59
|
Err: (error) => Promise.resolve({ network: Err(error), paths: new Set() }),
|
|
60
60
|
Ok: async ({ Interfaces: paths }) => {
|
|
61
|
-
const interfaces = Result.collect(await Promise.all(paths.map(async (path) => (await properties(
|
|
61
|
+
const interfaces = Result.collect(await Promise.all(paths.map(async (path) => (await properties(domicile, path, `${SERVICE}.Interface`, interfaceSchema)).map((held) => ({ ...held, path })))));
|
|
62
62
|
return interfaces.match({
|
|
63
63
|
Err: (error) => Promise.resolve({ network: Err(error), paths: new Set(paths) }),
|
|
64
64
|
Ok: async (held) => {
|
|
@@ -66,7 +66,7 @@ const readPaths = async (system) => {
|
|
|
66
66
|
return connected === undefined
|
|
67
67
|
? { network: Ok(Link.None()), paths: new Set(paths) }
|
|
68
68
|
: {
|
|
69
|
-
network: await linkOf(
|
|
69
|
+
network: await linkOf(domicile, connected.CurrentBSS),
|
|
70
70
|
paths: new Set([...paths, connected.CurrentBSS]),
|
|
71
71
|
};
|
|
72
72
|
},
|
|
@@ -99,9 +99,9 @@ const isOnline = (state) => {
|
|
|
99
99
|
}
|
|
100
100
|
};
|
|
101
101
|
/** The network at the BSS `path`. */
|
|
102
|
-
const linkOf = async (
|
|
102
|
+
const linkOf = async (domicile, path) => (await properties(domicile, path, `${SERVICE}.BSS`, bssSchema)).map(({ SSID: ssid, Signal: signal }) => Link.Wifi(new TextDecoder().decode(new Uint8Array(ssid)), strengthOfDbm(signal)));
|
|
103
103
|
/** `Properties.GetAll` on one of wpa_supplicant's objects, parsed. */
|
|
104
|
-
const properties = async (
|
|
104
|
+
const properties = async (domicile, path, interfaceName, schema) => (await domicile.dbus.call({
|
|
105
105
|
body: [interfaceName],
|
|
106
106
|
bus: Bus.System,
|
|
107
107
|
destination: SERVICE,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dependencies": {
|
|
3
3
|
"@cprussin/option-result": "^2.0.1",
|
|
4
|
-
"@domicile-desktop/sdk": "0.0.0-alpha-
|
|
4
|
+
"@domicile-desktop/sdk": "0.0.0-alpha-56dd6c187f4e",
|
|
5
5
|
"zod": "^4.5.4"
|
|
6
6
|
},
|
|
7
7
|
"description": "The network for a Domicile shell, from NetworkManager, iwd or wpa_supplicant: connectivity and the primary connection, with its Wi-Fi network and signal, kept current.",
|
|
@@ -64,5 +64,5 @@
|
|
|
64
64
|
"test:unit": "bun test"
|
|
65
65
|
},
|
|
66
66
|
"type": "module",
|
|
67
|
-
"version": "0.0.0-alpha-
|
|
67
|
+
"version": "0.0.0-alpha-56dd6c187f4e"
|
|
68
68
|
}
|