-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathextension.js
172 lines (143 loc) · 5.63 KB
/
extension.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
'use strict';
// Import necessary GObject and GNOME Shell modules
import GObject from 'gi://GObject';
import St from 'gi://St';
import GLib from 'gi://GLib';
import Clutter from 'gi://Clutter';
import Gio from 'gi://Gio';
import { Extension } from 'resource:///org/gnome/shell/extensions/extension.js';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
// Constants for the update interval and network interfaces to ignore
const UPDATE_INTERVAL_SECONDS = 3;
const NETWORK_INTERFACES_TO_IGNORE = ['lo', 'vir', 'vbox', 'docker', 'br-'];
const PROC_NET_DEV_PATH = '/proc/net/dev';
// Define the NetworkSpeedIndicator class, extending St.Label
const NetworkSpeedIndicator = GObject.registerClass(
class NetworkSpeedIndicator extends St.Label {
// Constructor to initialize the label and set initial values
_init() {
super._init({
style_class: 'panel-button', // default panel-button CSS class for styling
y_align: Clutter.ActorAlign.CENTER, // Vertically center the label
text: '↓ 0 B/s ↑ 0 B/s' // Initial text
});
this._previousRxBytes = 0; // Previous received bytes
this._previousTxBytes = 0; // Previous transmitted bytes
this._updateTimer = null; // Timer for periodic updates
// Create a Gio.File instance for asynchronous file operations
this._netDevFile = Gio.File.new_for_path(PROC_NET_DEV_PATH);
}
// Method to destroy the indicator and stop updates
destroy() {
this.stopUpdate(); // Stop the periodic updates
super.destroy(); // Call the parent class destroy method
}
// Method to format the speed value for display
_formatSpeedValue(bytes) {
const units = ['B/s', 'KB/s', 'MB/s', 'GB/s']; // Units of measurement
let unitIndex = 0; // Index for the units array
let speed = bytes; // Speed value in bytes
// Convert bytes to higher units if applicable
while (speed >= 1024 && unitIndex < units.length - 1) {
speed /= 1024;
unitIndex++;
}
// Return the formatted speed value
return `${speed.toFixed(1)} ${units[unitIndex]}`;
}
// Method to check if the network interface should be ignored
_isIgnoredInterface(interfaceName) {
return NETWORK_INTERFACES_TO_IGNORE.some(prefix =>
interfaceName.startsWith(prefix)
);
}
// Method to read network statistics asynchronously
async _readNetworkStats() {
return new Promise((resolve, reject) => {
this._netDevFile.load_contents_async(null, (file, result) => {
try {
const [success, contents] = file.load_contents_finish(result);
if (!success) throw new Error('Failed to read network stats');
const lines = new TextDecoder().decode(contents).split('\n');
let totalRxBytes = 0;
let totalTxBytes = 0;
for (const line of lines.slice(2)) {
const trimmed = line.trim();
if (!trimmed) continue;
const [iface, data] = trimmed.split(':');
if (!data || this._isIgnoredInterface(iface)) continue;
const [rxBytes, , , , , , , , txBytes] = data.trim()
.split(/\s+/)
.map(n => parseInt(n, 10));
totalRxBytes += rxBytes;
totalTxBytes += txBytes;
}
resolve({ totalRxBytes, totalTxBytes });
} catch (error) {
console.error('NetworkSpeed: Error reading stats:', error);
reject(null);
}
});
});
}
// Method to update the network speed display
async _updateSpeed() {
const stats = await this._readNetworkStats();
if (!stats) return GLib.SOURCE_CONTINUE;
const { totalRxBytes, totalTxBytes } = stats;
// Initialize previous values if first run
this._previousRxBytes ||= totalRxBytes;
this._previousTxBytes ||= totalTxBytes;
// Calculate current speeds
const downloadSpeed = this._formatSpeedValue(
(totalRxBytes - this._previousRxBytes) / UPDATE_INTERVAL_SECONDS
);
const uploadSpeed = this._formatSpeedValue(
(totalTxBytes - this._previousTxBytes) / UPDATE_INTERVAL_SECONDS
);
// Update the display
this.text = `↓ ${downloadSpeed} ↑ ${uploadSpeed}`;
// Store current values for next update
this._previousRxBytes = totalRxBytes;
this._previousTxBytes = totalTxBytes;
return GLib.SOURCE_CONTINUE;
}
// Method to start periodic updates of network speed
startUpdate() {
// Initial update
this._updateSpeed();
// Schedule periodic updates
this._updateTimer = GLib.timeout_add_seconds(
GLib.PRIORITY_DEFAULT,
UPDATE_INTERVAL_SECONDS,
() => {
this._updateSpeed();
return GLib.SOURCE_CONTINUE;
}
);
}
// Method to stop periodic updates of network speed
stopUpdate() {
if (this._updateTimer) {
GLib.source_remove(this._updateTimer);
this._updateTimer = null;
}
}
}
);
// Define the NetworkSpeedExtension class, extending Extension
export default class NetworkSpeedExtension extends Extension {
// Method to enable the extension
enable() {
this._indicator = new NetworkSpeedIndicator(); // Create a new indicator
Main.panel._rightBox.insert_child_at_index(this._indicator, 0); // Add the indicator to the panel
this._indicator.startUpdate(); // Start updating the indicator
}
// Method to disable the extension
disable() {
if (this._indicator) {
this._indicator.destroy(); // Destroy the indicator
this._indicator = null; // Clear the reference
}
}
}