Skip to content

Commit

Permalink
Add Public IP
Browse files Browse the repository at this point in the history
  • Loading branch information
ljuzig committed Mar 15, 2024
1 parent 5ca761b commit 6c4ddcf
Show file tree
Hide file tree
Showing 6 changed files with 312 additions and 3 deletions.
7 changes: 7 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Astra Monitor 16 - TO BE RELEASED

### Advanced Network Monitoring
As per our [Roadmap](https://github.com/AstraExt/astra-monitor?tab=readme-ov-file#roadmap), in this release we are focusing on improving the Network monitoring capabilities of Astra Monitor. Here's a list of the new features and improvements:

_THIS LIST IS TEMPORARY AND SUBJECT TO CHANGE UNTIL THE RELEASE DATE_

- **Public IP Address**: now you can see your public IPv4/IPv6 address in the Network Menu. This feature requires a remote API call to get the public IP address. We are using [ipify](https://www.ipify.org/) as the default provider, which is a free and open source service. You can choose a different provider from the settings panel or disable this feature if you don't want to use it. We support every possible provider, the ip address will be matched with a regex to extract it from the response.

### Bug fixes
- Fixed CPU Cores Usage Info user bar invisible when Cores Bar Breakdown is enabled [[#86](https://github.com/AstraExt/astra-monitor/issues/86)]

Expand Down
13 changes: 13 additions & 0 deletions prefs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -938,6 +938,19 @@ export default class AstraMonitorPrefs extends ExtensionPreferences {
{value: 'proc', text: '/proc/net/dev'},
];
this.addComboRow({title: _('Network IO'), tabs: 1}, networkIOSources, 'network-source-network-io', sourcesSection, 'string', 'auto');

this.addTextInputRow({
title: _('Public IPv4 Address'),
subtitle: _('Set to empty to disable. Address will be regex matched.'),
tabs: 1,
}, 'network-source-public-ipv4', sourcesSection, 'https://api.ipify.org');

this.addTextInputRow({
title: _('Public IPv6 Address'),
subtitle: _('Set to empty to disable. Address will be regex matched.'),
tabs: 1,
}, 'network-source-public-ipv6', sourcesSection, 'https://api6.ipify.org');

networkPage.add(group);

/* Header */
Expand Down
10 changes: 10 additions & 0 deletions schemas/org.gnome.shell.extensions.astra-monitor.gschema.xml
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,16 @@
<summary>Network IO Source</summary>
<description>Source of the network IO</description>
</key>
<key name="network-source-public-ipv4" type="s">
<default>'https://api.ipify.org'</default>
<summary>Public IPv4 Source</summary>
<description>Source of the public IPv4</description>
</key>
<key name="network-source-public-ipv6" type="s">
<default>'https://api6.ipify.org'</default>
<summary>Public IPv6 Source</summary>
<description>Source of the public IPv6</description>
</key>
<key name="network-header-show" type="b">
<default>true</default>
<summary>Network Header</summary>
Expand Down
136 changes: 136 additions & 0 deletions src/network/networkMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ export default class NetworkMenu extends MenuBase {
private totalUploadSpeedValueLabel!: St.Label;
private totalDownloadSpeedValueLabel!: St.Label;

private publicIPv4!: {
label: St.Label;
value: St.Label;
};
private publicIpv6!: {
label: St.Label;
value1: St.Label;
value2: St.Label;
};

private deviceSection!: InstanceType<typeof Grid>;
private noDevicesLabel!: St.Label;

Expand All @@ -60,6 +70,7 @@ export default class NetworkMenu extends MenuBase {

/*this.networkSectionLabel = */this.addMenuSection(_('Network'));
this.createActivitySection();
this.createPublicIps();
this.createDeviceList();

this.addUtilityButtons();
Expand All @@ -74,6 +85,10 @@ export default class NetworkMenu extends MenuBase {
const styleClass = lightTheme ? 'astra-monitor-menu-key-light' : 'astra-monitor-menu-key';
this.totalUploadSpeedValueLabel.style_class = styleClass;
this.totalDownloadSpeedValueLabel.style_class = styleClass;

this.publicIPv4.value.style_class = styleClass;
this.publicIpv6.value1.style_class = styleClass;
this.publicIpv6.value2.style_class = styleClass;
}

createActivitySection() {
Expand Down Expand Up @@ -135,6 +150,83 @@ export default class NetworkMenu extends MenuBase {
this.addToMenu(hoverButton, 2);
}

createPublicIps() {
this.addMenuSection(_('Public IP'));

const defaultStyle = '';

const hoverButton = new St.Button({
reactive: true,
track_hover: true,
style: defaultStyle
});

const grid = new Grid({ styleClass: 'astra-monitor-menu-subgrid' });
hoverButton.set_child(grid);

const publicIPv4Label = new St.Label({
text: _('Public IPv4:'),
x_expand: true,
style_class: 'astra-monitor-menu-label',
style: 'margin-top:0.25em;'
});
grid.addToGrid(publicIPv4Label);

const publicIPv4Value = new St.Label({
text: '-',
x_expand: true
});
grid.addToGrid(publicIPv4Value);

this.publicIPv4 = {
label: publicIPv4Label,
value: publicIPv4Value
};

const publicIpv6Grid = new Grid({ styleClass: 'astra-monitor-menu-subgrid', numCols: 2});

const publicIpv6Label = new St.Label({
text: _('Public IPv6:'),
x_expand: true,
style_class: 'astra-monitor-menu-label'
});
publicIpv6Grid.addGrid(publicIpv6Label, 1, 1, 1, 2);

const publicIpv6Value1 = new St.Label({
text: '-',
x_expand: true,
style: 'font-size: 1em;'
});
publicIpv6Grid.addGrid(publicIpv6Value1, 2, 1, 1, 1);

const publicIpv6Value2 = new St.Label({
text: '-',
x_expand: true,
style: 'font-size: 1em;'
});
publicIpv6Grid.addGrid(publicIpv6Value2, 2, 2, 1, 1);

grid.addToGrid(publicIpv6Grid, 2);

this.publicIpv6 = {
label: publicIpv6Label,
value1: publicIpv6Value1,
value2: publicIpv6Value2
};

hoverButton.connect('enter-event', () => {
hoverButton.style = defaultStyle + this.selectionStyle;

});

hoverButton.connect('leave-event', () => {
hoverButton.style = defaultStyle;

});

this.addToMenu(hoverButton, 2);
}

createDeviceList() {
if(this.deviceSection === undefined) {
this.addMenuSection(_('Interfaces'));
Expand Down Expand Up @@ -426,6 +518,9 @@ export default class NetworkMenu extends MenuBase {
Utils.networkMonitor.listen(this, 'detailedNetworkIO', this.update.bind(this, 'detailedNetworkIO'));
Utils.networkMonitor.requestUpdate('detailedNetworkIO');

this.update('publicIps');
Utils.networkMonitor.listen(this, 'publicIps', this.update.bind(this, 'publicIps'));

this.update('deviceList');
if(!this.updateTimer) {
this.updateTimer = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
Expand Down Expand Up @@ -516,6 +611,47 @@ export default class NetworkMenu extends MenuBase {
}
return;
}
if(code === 'publicIps') {
const publicIPv4 = Utils.networkMonitor.getCurrentValue('publicIpv4Address');
if(publicIPv4) {
this.publicIPv4.label.show();
this.publicIPv4.value.show();
this.publicIPv4.value.text = publicIPv4;
}
else {
this.publicIPv4.label.hide();
this.publicIPv4.value.hide();
}

const publicIpv6 = Utils.networkMonitor.getCurrentValue('publicIpv6Address');
if(publicIpv6) {
this.publicIpv6.label.show();

if(publicIpv6.length >= 20) {
this.publicIpv6.value1.show();
this.publicIpv6.value2.show();

const parts = publicIpv6.split(':');
const mid = Math.floor(parts.length / 2);
const part1 = parts.slice(0, mid).join(':') + ':';
const part2 = parts.slice(mid).join(':');

this.publicIpv6.value1.text = part1;
this.publicIpv6.value2.text = part2;
}
else {
this.publicIpv6.value1.show();
this.publicIpv6.value2.hide();
this.publicIpv6.value1.text = publicIpv6;
}
}
else {
this.publicIpv6.label.hide();
this.publicIpv6.value1.hide();
}

return;
}
}

clear() {
Expand Down
92 changes: 89 additions & 3 deletions src/network/networkMonitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,7 @@ type NetworkDataSources = {
networkIO?: string
};


export default class NetworkMonitor extends Monitor {

private detectedMaxSpeedsValues: MaxSpeeds;
private interfaceChecks: Record<string, boolean>;
private ignored: string[];
Expand All @@ -66,6 +64,8 @@ export default class NetworkMonitor extends Monitor {

private dataSources!: NetworkDataSources;

private publicIpsUpdaterID: number|null = null;

constructor() {
super('Network Monitor');

Expand All @@ -84,8 +84,10 @@ export default class NetworkMonitor extends Monitor {
this.dataSourcesInit();

const enabled = Config.get_boolean('network-header-show');
if(enabled)
if(enabled) {
this.updatePublicIps();
this.start();
}

Config.connect(this, 'changed::network-header-show', () => {
if(Config.get_boolean('network-header-show'))
Expand Down Expand Up @@ -159,10 +161,15 @@ export default class NetworkMonitor extends Monitor {

start() {
super.start();

this.startPublicIpsUpdater();
}

stop() {
super.stop();

this.stopPublicIpsUpdater();

this.reset();
}

Expand Down Expand Up @@ -449,6 +456,85 @@ export default class NetworkMonitor extends Monitor {
return true;
}

private startPublicIpsUpdater() {
this.publicIpsUpdaterID = GLib.timeout_add_seconds(
GLib.PRIORITY_DEFAULT,
60*5, // 5 minute
this.updatePublicIps.bind(this)
);
}

private stopPublicIpsUpdater() {
if(this.publicIpsUpdaterID !== null) {
GLib.source_remove(this.publicIpsUpdaterID);
this.publicIpsUpdaterID = null;
}
}

private updatePublicIps() {
(async () => {
try {
const ipv4 = await this.updatePublicIpv4Address();
const ipv6 = await this.updatePublicIpv6Address();

if(ipv4 || ipv6)
this.notify('publicIps');
}
catch(e) { /* EMPTY */}
})();
return true;
}

private async updatePublicIpv4Address(): Promise<boolean> {
const publicIpv4Address = Config.get_string('network-source-public-ipv4');
if(!publicIpv4Address)
return false;

const value = await Utils.getUrlAsync(publicIpv4Address, true);
if(!value)
return false;

const regex = /(\b25[0-5]|\b2[0-4][0-9]|\b[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}/;
const match = value.match(regex);

if(!match)
return false;

const ip = match[0];

const currentIp = this.getCurrentValue('publicIpv4Address');
if(currentIp === ip)
return false;

this.pushUsageHistory('publicIpv4Address', ip);
return true;
}

private async updatePublicIpv6Address(): Promise<boolean> {
const publicIpv6Address = Config.get_string('network-source-public-ipv6');
if(!publicIpv6Address)
return false;

const value = await Utils.getUrlAsync(publicIpv6Address, true);
if(!value)
return false;

const regex = /(?:[\da-f]{0,4}:){2,7}(?:(?<ipv4>(?:(?:25[0-5]|2[0-4]\d|1?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|1?\d\d?))|[\da-f]{0,4}|:)/i;
const match = value.match(regex);

if(!match)
return false;

const ip = match[0];

const currentIp = this.getCurrentValue('publicIpv6Address');
if(currentIp === ip)
return false;

this.pushUsageHistory('publicIpv6Address', ip);
return true;
}

destroy() {
Config.clear(this);
super.destroy();
Expand Down
Loading

0 comments on commit 6c4ddcf

Please sign in to comment.