@gjsify/os 0.3.12 → 0.3.14

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/lib/esm/linux.js CHANGED
@@ -1,177 +1,183 @@
1
- import GLib from "@girs/glib-2.0";
2
1
  import { createSubnet } from "./createSubnet.js";
3
2
  import { cli } from "@gjsify/utils";
3
+ import GLib from "@girs/glib-2.0";
4
+
5
+ //#region src/linux.ts
4
6
  const byteArray = imports.byteArray;
5
7
  const EOL = /\r\n|\n/;
8
+ /**
9
+ * Read a text file directly via GLib (no subprocess).
10
+ */
6
11
  function readTextFile(path) {
7
- const [ok, contents] = GLib.file_get_contents(path);
8
- if (!ok || !contents) return "";
9
- return byteArray.toString(contents);
12
+ const [ok, contents] = GLib.file_get_contents(path);
13
+ if (!ok || !contents) return "";
14
+ return byteArray.toString(contents);
10
15
  }
11
16
  const getIPv4Subnet = createSubnet(32, 8, 10, ".");
12
17
  const getIPv6Subnet = createSubnet(128, 16, 16, ":");
13
18
  function parseInterfaces(info) {
14
- info = info.trim();
15
- if (info.length < 1) return;
16
- let iface = [], mac;
17
- for (let line, lines = info.split(EOL), i = 0; i < lines.length; i++) {
18
- line = lines[i];
19
- switch (true) {
20
- case /link\/\S+\s+((?:\S{2}:)+\S{2})/.test(line):
21
- mac = RegExp.$1;
22
- break;
23
- case /inet(\d*)\s+(\S+)/.test(line):
24
- let ip = RegExp.$2.split("/"), v = RegExp.$1 || "4";
25
- iface.push({
26
- address: ip[0],
27
- netmask: (v === "4" ? getIPv4Subnet : getIPv6Subnet)(ip[1]),
28
- family: "IPv" + v,
29
- mac,
30
- internal: ip[0] === "127.0.0.1"
31
- });
32
- break;
33
- }
34
- }
35
- if (mac) this[info.slice(0, info.indexOf(":"))] = iface;
19
+ info = info.trim();
20
+ if (info.length < 1) return;
21
+ let iface = [], mac;
22
+ for (let line, lines = info.split(EOL), i = 0; i < lines.length; i++) {
23
+ line = lines[i];
24
+ switch (true) {
25
+ case /link\/\S+\s+((?:\S{2}:)+\S{2})/.test(line):
26
+ mac = RegExp.$1;
27
+ break;
28
+ case /inet(\d*)\s+(\S+)/.test(line):
29
+ let ip = RegExp.$2.split("/"), v = RegExp.$1 || "4";
30
+ iface.push({
31
+ address: ip[0],
32
+ netmask: (v === "4" ? getIPv4Subnet : getIPv6Subnet)(ip[1]),
33
+ family: "IPv" + v,
34
+ mac,
35
+ internal: ip[0] === "127.0.0.1"
36
+ });
37
+ break;
38
+ }
39
+ }
40
+ if (mac) this[info.slice(0, info.indexOf(":"))] = iface;
36
41
  }
37
42
  ;
38
43
  const cpus = () => {
39
- const PROCESSOR = /^processor\s*:\s*(\d+)/i;
40
- const NAME = /^model[\s_]+name\s*:([^\r\n]+)/i;
41
- const FREQ = /^cpu[\s_]+MHz\s*:\s*(\d+)/i;
42
- const result = [];
43
- let cpu;
44
- readTextFile("/proc/cpuinfo").split(EOL).forEach((line) => {
45
- switch (true) {
46
- case PROCESSOR.test(line):
47
- result[RegExp.$1.trim()] = cpu = {
48
- model: "",
49
- speed: 0,
50
- times: { user: 0, nice: 0, sys: 0, idle: 0, irq: 0 }
51
- };
52
- break;
53
- case NAME.test(line):
54
- cpu.model = RegExp.$1.trim();
55
- break;
56
- case FREQ.test(line):
57
- cpu.speed = parseFloat(RegExp.$1.trim());
58
- break;
59
- }
60
- });
61
- try {
62
- const statLines = readTextFile("/proc/stat").split(EOL);
63
- for (const line of statLines) {
64
- const m = /^cpu(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+\d+\s+(\d+)/.exec(line);
65
- if (m && result[parseInt(m[1], 10)]) {
66
- result[parseInt(m[1], 10)].times = {
67
- user: parseInt(m[2], 10) * 10,
68
- nice: parseInt(m[3], 10) * 10,
69
- sys: parseInt(m[4], 10) * 10,
70
- idle: parseInt(m[5], 10) * 10,
71
- irq: parseInt(m[6], 10) * 10
72
- };
73
- }
74
- }
75
- } catch {
76
- }
77
- return result;
44
+ const PROCESSOR = /^processor\s*:\s*(\d+)/i;
45
+ const NAME = /^model[\s_]+name\s*:([^\r\n]+)/i;
46
+ const FREQ = /^cpu[\s_]+MHz\s*:\s*(\d+)/i;
47
+ const result = [];
48
+ let cpu;
49
+ readTextFile("/proc/cpuinfo").split(EOL).forEach((line) => {
50
+ switch (true) {
51
+ case PROCESSOR.test(line):
52
+ result[RegExp.$1.trim()] = cpu = {
53
+ model: "",
54
+ speed: 0,
55
+ times: {
56
+ user: 0,
57
+ nice: 0,
58
+ sys: 0,
59
+ idle: 0,
60
+ irq: 0
61
+ }
62
+ };
63
+ break;
64
+ case NAME.test(line):
65
+ cpu.model = RegExp.$1.trim();
66
+ break;
67
+ case FREQ.test(line):
68
+ cpu.speed = parseFloat(RegExp.$1.trim());
69
+ break;
70
+ }
71
+ });
72
+ try {
73
+ const statLines = readTextFile("/proc/stat").split(EOL);
74
+ for (const line of statLines) {
75
+ const m = /^cpu(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+\d+\s+(\d+)/.exec(line);
76
+ if (m && result[parseInt(m[1], 10)]) {
77
+ result[parseInt(m[1], 10)].times = {
78
+ user: parseInt(m[2], 10) * 10,
79
+ nice: parseInt(m[3], 10) * 10,
80
+ sys: parseInt(m[4], 10) * 10,
81
+ idle: parseInt(m[5], 10) * 10,
82
+ irq: parseInt(m[6], 10) * 10
83
+ };
84
+ }
85
+ }
86
+ } catch {}
87
+ return result;
78
88
  };
79
89
  const endianness = () => "LE";
80
90
  const freemem = () => {
81
- const content = readTextFile("/proc/meminfo");
82
- let memFree = 0;
83
- for (const line of content.split("\n")) {
84
- const available = /^MemAvailable:\s+(\d+)\s+kB/.exec(line);
85
- if (available) return parseInt(available[1], 10) * 1024;
86
- const free = /^MemFree:\s+(\d+)\s+kB/.exec(line);
87
- if (free) memFree = parseInt(free[1], 10) * 1024;
88
- }
89
- return memFree;
91
+ const content = readTextFile("/proc/meminfo");
92
+ let memFree = 0;
93
+ for (const line of content.split("\n")) {
94
+ const available = /^MemAvailable:\s+(\d+)\s+kB/.exec(line);
95
+ if (available) return parseInt(available[1], 10) * 1024;
96
+ const free = /^MemFree:\s+(\d+)\s+kB/.exec(line);
97
+ if (free) memFree = parseInt(free[1], 10) * 1024;
98
+ }
99
+ return memFree;
90
100
  };
91
- const loadavg = () => /(\d+(?:\.\d+))\s+(\d+(?:\.\d+))\s+(\d+(?:\.\d+))/.test(
92
- readTextFile("/proc/loadavg")
93
- ) && [
94
- parseFloat(RegExp.$1),
95
- parseFloat(RegExp.$2),
96
- parseFloat(RegExp.$3)
101
+ const loadavg = () => /(\d+(?:\.\d+))\s+(\d+(?:\.\d+))\s+(\d+(?:\.\d+))/.test(readTextFile("/proc/loadavg")) && [
102
+ parseFloat(RegExp.$1),
103
+ parseFloat(RegExp.$2),
104
+ parseFloat(RegExp.$3)
97
105
  ];
98
106
  const networkInterfaces = () => {
99
- try {
100
- const ifaces = {};
101
- cli("ip addr").split(/^\d+:\s+/m).forEach(parseInterfaces, ifaces);
102
- return ifaces;
103
- } catch {
104
- return readNetworkInterfacesFromProc();
105
- }
107
+ try {
108
+ const ifaces = {};
109
+ cli("ip addr").split(/^\d+:\s+/m).forEach(parseInterfaces, ifaces);
110
+ return ifaces;
111
+ } catch {
112
+ return readNetworkInterfacesFromProc();
113
+ }
106
114
  };
115
+ /**
116
+ * Fallback: read network interface data from procfs/sysfs when `ip` is unavailable.
117
+ * Provides interface names + MACs from sysfs, IPv6 from /proc/net/if_inet6,
118
+ * and loopback IPv4 (127.0.0.1). Other IPv4 addresses require `ip` or `ifconfig`.
119
+ */
107
120
  function readNetworkInterfacesFromProc() {
108
- const ifaces = {};
109
- const macs = {};
110
- try {
111
- const netDev = readTextFile("/proc/net/dev");
112
- for (const line of netDev.split("\n").slice(2)) {
113
- const name = line.split(":")[0]?.trim();
114
- if (!name) continue;
115
- ifaces[name] = [];
116
- try {
117
- macs[name] = readTextFile(`/sys/class/net/${name}/address`).trim();
118
- } catch {
119
- macs[name] = "00:00:00:00:00:00";
120
- }
121
- }
122
- } catch {
123
- return ifaces;
124
- }
125
- try {
126
- const inet6 = readTextFile("/proc/net/if_inet6");
127
- for (const line of inet6.split("\n")) {
128
- const parts = line.trim().split(/\s+/);
129
- if (parts.length < 6) continue;
130
- const [addrHex, , prefixLen, , , devName] = parts;
131
- const groups = addrHex.match(/.{4}/g);
132
- if (!groups || !ifaces[devName]) continue;
133
- ifaces[devName].push({
134
- address: groups.join(":"),
135
- netmask: getIPv6Subnet(prefixLen),
136
- family: "IPv6",
137
- mac: macs[devName] || "00:00:00:00:00:00",
138
- internal: devName === "lo"
139
- });
140
- }
141
- } catch {
142
- }
143
- if (ifaces["lo"]) {
144
- ifaces["lo"].unshift({
145
- address: "127.0.0.1",
146
- netmask: "255.0.0.0",
147
- family: "IPv4",
148
- mac: macs["lo"] || "00:00:00:00:00:00",
149
- internal: true
150
- });
151
- }
152
- for (const name of Object.keys(ifaces)) {
153
- if (ifaces[name].length === 0) delete ifaces[name];
154
- }
155
- return ifaces;
121
+ const ifaces = {};
122
+ const macs = {};
123
+ try {
124
+ const netDev = readTextFile("/proc/net/dev");
125
+ for (const line of netDev.split("\n").slice(2)) {
126
+ const name = line.split(":")[0]?.trim();
127
+ if (!name) continue;
128
+ ifaces[name] = [];
129
+ try {
130
+ macs[name] = readTextFile(`/sys/class/net/${name}/address`).trim();
131
+ } catch {
132
+ macs[name] = "00:00:00:00:00:00";
133
+ }
134
+ }
135
+ } catch {
136
+ return ifaces;
137
+ }
138
+ try {
139
+ const inet6 = readTextFile("/proc/net/if_inet6");
140
+ for (const line of inet6.split("\n")) {
141
+ const parts = line.trim().split(/\s+/);
142
+ if (parts.length < 6) continue;
143
+ const [addrHex, , prefixLen, , , devName] = parts;
144
+ const groups = addrHex.match(/.{4}/g);
145
+ if (!groups || !ifaces[devName]) continue;
146
+ ifaces[devName].push({
147
+ address: groups.join(":"),
148
+ netmask: getIPv6Subnet(prefixLen),
149
+ family: "IPv6",
150
+ mac: macs[devName] || "00:00:00:00:00:00",
151
+ internal: devName === "lo"
152
+ });
153
+ }
154
+ } catch {}
155
+ if (ifaces["lo"]) {
156
+ ifaces["lo"].unshift({
157
+ address: "127.0.0.1",
158
+ netmask: "255.0.0.0",
159
+ family: "IPv4",
160
+ mac: macs["lo"] || "00:00:00:00:00:00",
161
+ internal: true
162
+ });
163
+ }
164
+ for (const name of Object.keys(ifaces)) {
165
+ if (ifaces[name].length === 0) delete ifaces[name];
166
+ }
167
+ return ifaces;
156
168
  }
157
169
  const totalmem = () => {
158
- const content = readTextFile("/proc/meminfo");
159
- for (const line of content.split("\n")) {
160
- const match = /^MemTotal:\s+(\d+)\s+kB/.exec(line);
161
- if (match) return parseInt(match[1], 10) * 1024;
162
- }
163
- return 0;
170
+ const content = readTextFile("/proc/meminfo");
171
+ for (const line of content.split("\n")) {
172
+ const match = /^MemTotal:\s+(\d+)\s+kB/.exec(line);
173
+ if (match) return parseInt(match[1], 10) * 1024;
174
+ }
175
+ return 0;
164
176
  };
165
177
  const uptime = () => {
166
- const content = readTextFile("/proc/uptime").trim();
167
- return parseFloat(content.split(" ")[0]) || 0;
168
- };
169
- export {
170
- cpus,
171
- endianness,
172
- freemem,
173
- loadavg,
174
- networkInterfaces,
175
- totalmem,
176
- uptime
178
+ const content = readTextFile("/proc/uptime").trim();
179
+ return parseFloat(content.split(" ")[0]) || 0;
177
180
  };
181
+
182
+ //#endregion
183
+ export { cpus, endianness, freemem, loadavg, networkInterfaces, totalmem, uptime };
package/lib/esm/win32.js CHANGED
@@ -1 +1,4 @@
1
+ //#region src/win32.ts
1
2
  console.warn("os core module is not fully supported here");
3
+
4
+ //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/os",
3
- "version": "0.3.12",
3
+ "version": "0.3.14",
4
4
  "description": "Node.js os module for Gjs",
5
5
  "module": "lib/esm/index.js",
6
6
  "types": "lib/types/index.d.ts",
@@ -30,13 +30,13 @@
30
30
  "os"
31
31
  ],
32
32
  "dependencies": {
33
- "@girs/gio-2.0": "^2.88.0-4.0.0-rc.9",
34
- "@girs/glib-2.0": "^2.88.0-4.0.0-rc.9",
35
- "@gjsify/utils": "^0.3.12"
33
+ "@girs/gio-2.0": "2.88.0-4.0.0-rc.9",
34
+ "@girs/glib-2.0": "2.88.0-4.0.0-rc.9",
35
+ "@gjsify/utils": "^0.3.14"
36
36
  },
37
37
  "devDependencies": {
38
- "@gjsify/cli": "^0.3.12",
39
- "@gjsify/unit": "^0.3.12",
38
+ "@gjsify/cli": "^0.3.14",
39
+ "@gjsify/unit": "^0.3.14",
40
40
  "@types/node": "^25.6.0",
41
41
  "typescript": "^6.0.3"
42
42
  }