gnome-shell-pi-hole/pi-hole@fnxweb.com/extension.js

402 lines
12 KiB
JavaScript
Raw Normal View History

// Import
2022-05-17 09:45:21 +00:00
const { Atk, Gio, GLib, GObject, Gtk, Soup, St } = imports.gi;
const { main, panelMenu, popupMenu } = imports.ui;
const ExtensionUtils = imports.misc.extensionUtils
const Mainloop = imports.mainloop;
const IndicatorName = 'pi-hole';
2021-02-23 17:34:48 +00:00
// Common
const PiHoleExtMetadata = ExtensionUtils.getCurrentExtension();
const Common = PiHoleExtMetadata.imports.common;
const Gettext = imports.gettext.domain( PiHoleExtMetadata.metadata['gettext-domain'] );
2021-02-28 14:20:11 +00:00
const _ = Gettext.gettext;
let PiHoleExtButton = null;
2021-02-23 17:34:48 +00:00
// Implement PiHole class
2022-05-17 09:45:21 +00:00
const PiHole = GObject.registerClass(
class PiHole extends panelMenu.Button
{
2022-05-17 09:45:21 +00:00
// ctor
_init ()
{
// Core setup
super._init( null, IndicatorName );
ExtensionUtils.initTranslations();
this.Name = IndicatorName;
2022-05-17 09:45:21 +00:00
// Debug
this.Debug= false;
2022-05-17 09:45:21 +00:00
// Status URL
this.Url= '';
2022-05-17 09:45:21 +00:00
// API key
this.ApiKey = '';
2022-05-17 09:45:21 +00:00
// Timer period (seconds)
this.UpdateTime = 0;
2022-05-17 09:45:21 +00:00
// Disable duration (seconds)
this.DisableTime = 0;
2022-05-17 09:45:21 +00:00
// Updates
this.StatusEvent= null;
2022-05-17 09:45:21 +00:00
// Current status
this.StatusField= null;
this.IconStatus= "";
this.Status= "unknown";
2022-05-17 09:45:21 +00:00
// Buttons
this.Icon= null;
this.PauseButton= null;
this.EnableDisableButton= null;
this.SettingsButton= null;
2021-02-23 17:34:48 +00:00
2022-05-17 09:45:21 +00:00
// Watch settings
this.SettingChangedHandlerIds= null;
2021-02-23 17:34:48 +00:00
// Settings
this.Settings = ExtensionUtils.getSettings();
this.Url = this.Settings.get_string( Common.URL_SETTING );
this.ApiKey = this.Settings.get_string( Common.API_KEY_SETTING );
this.UpdateTime = this.Settings.get_uint( Common.UPDATE_RATE_SETTING );
2021-02-23 17:34:48 +00:00
if (this.UpdateTime < 5)
this.UpdateTime = 5;
this.DisableTime = this.Settings.get_uint( Common.DISABLE_TIME_SETTING );
2021-02-23 17:34:48 +00:00
if (this.DisableTime < 1)
this.DisableTime = 1;
// Diag
if (this.Debug)
{
2021-02-23 17:34:48 +00:00
this.dprint("Url: " + this.Url);
this.dprint("ApiKey: " + this.ApiKey);
this.dprint("UpdateTime: " + this.UpdateTime.toString());
this.dprint("DisableTime: " + this.DisableTime.toString());
}
// Create a Soup session with which to do requests
this.SoupSession = new Soup.SessionAsync();
if (Soup.Session.prototype.add_feature != null)
Soup.Session.prototype.add_feature.call(this.SoupSession, new Soup.ProxyResolverDefault());
// Create button/icon
this.Icon = new St.Icon({ style_class: 'system-status-icon' });
this.add_child( this.Icon );
this.setIcon();
// Prep. menu
2022-05-17 09:45:21 +00:00
if (main.panel._menus == undefined)
main.panel.menuManager.addMenu(this.menu);
else
2022-05-17 09:45:21 +00:00
main.panel._menus.addMenu(this.menu);
// Add status popup
2021-02-23 17:34:48 +00:00
// .. status
this.StatusField = new St.Label({style_class:'stage popup-menu pihole-label', text:""});
this.setStatusText();
this.addMenuItem( this.StatusField );
2021-02-23 17:34:48 +00:00
// .. sep
2022-05-17 09:45:21 +00:00
this.menu.addMenuItem(new popupMenu.PopupSeparatorMenuItem());
2021-02-23 17:34:48 +00:00
// .. control buttons
2022-05-17 09:45:21 +00:00
this.PauseButton = new popupMenu.PopupMenuItem(_("Pause temporarily"), {style_class:"pihole-indent"});
this.PauseButton.connect('activate', () => {
this.onPauseButton();
return 0;
});
this.menu.addMenuItem(this.PauseButton);
//
2022-05-17 09:45:21 +00:00
this.EnableDisableButton = new popupMenu.PopupMenuItem(_("Disable"), {style_class:"pihole-indent"});
this.EnableDisableButton.connect('activate', () => {
this.onEnableDisableButton();
return 0;
});
this.menu.addMenuItem(this.EnableDisableButton);
2021-02-23 17:34:48 +00:00
// .. sep
2022-05-17 09:45:21 +00:00
this.menu.addMenuItem(new popupMenu.PopupSeparatorMenuItem());
2021-02-23 17:34:48 +00:00
// .. settings
2022-05-17 09:45:21 +00:00
this.SettingsButton = new popupMenu.PopupMenuItem(_("Settings"), {style_class:"pihole-indent"});
this.SettingsButton.connect('activate', () => {
this.onSettingsButton();
return 0;
});
this.menu.addMenuItem(this.SettingsButton);
2021-02-23 17:34:48 +00:00
// Get initial status (starts timer for next)
this.getPiHoleStatus();
2021-02-23 17:34:48 +00:00
// Watch for settings changes
this.SettingChangedHandlerIds = [
this.Settings.connect("changed::" + Common.URL_SETTING, () => {
PiHoleExtButton.Url = this.Settings.get_string( Common.URL_SETTING );
}),
this.Settings.connect("changed::" + Common.API_KEY_SETTING, () => {
PiHoleExtButton.ApiKey = this.Settings.get_string( Common.API_KEY_SETTING);
}),
this.Settings.connect("changed::" + Common.UPDATE_RATE_SETTING, () => {
PiHoleExtButton.UpdateTime = this.Settings.get_uint( Common.UPDATE_RATE_SETTING );
}),
this.Settings.connect("changed::" + Common.DISABLE_TIME_SETTING, () => {
PiHoleExtButton.DisableTime = this.Settings.get_uint( Common.DISABLE_TIME_SETTING );
})
2021-02-23 17:34:48 +00:00
];
2022-05-17 09:45:21 +00:00
}
// Debug
2022-05-17 09:45:21 +00:00
dprint(msg)
{
if (this.Debug)
print("PiHole: " + msg);
2022-05-17 09:45:21 +00:00
}
// Error
2022-05-17 09:45:21 +00:00
eprint(msg)
{
global.log("PiHole: " + msg);
2022-05-17 09:45:21 +00:00
}
// Add an item to the “menu”
2022-05-17 09:45:21 +00:00
addMenuItem(item)
{
2022-05-17 09:45:21 +00:00
let menuitem = new popupMenu.PopupBaseMenuItem({ reactive:false });
menuitem.actor.add_actor( item );
this.menu.addMenuItem( menuitem );
2022-05-17 09:45:21 +00:00
}
// Set correct icon
2022-05-17 09:45:21 +00:00
setIcon()
{
if (this.Status == this.IconStatus)
return;
this.IconStatus = this.Status;
if (this.IconStatus == "enabled")
this.Icon.set_gicon( this.getCustomIcon('pi-hole-symbolic') );
else if (this.IconStatus == "disabled")
this.Icon.set_gicon( this.getCustomIcon('pi-hole-disabled-symbolic') );
else
this.Icon.set_gicon( this.getCustomIcon('pi-hole-unknown-symbolic') );
2022-05-17 09:45:21 +00:00
}
// Get custom icon from theme or file
2022-05-17 09:45:21 +00:00
getCustomIcon(icon_name)
{
let icon_path = PiHoleExtMetadata.dir.get_child('icons').get_child( icon_name + ".svg" ).get_path();
let theme = Gtk.IconTheme.get_default();
if (theme)
{
let theme_icon = theme.lookup_icon( icon_name, -1, 2 );
if (theme_icon)
icon_path = theme_icon.get_filename();
}
this.dprint("setting new icon from " + icon_path);
return Gio.FileIcon.new( Gio.File.new_for_path( icon_path ) );
2022-05-17 09:45:21 +00:00
}
// Request pi-hole status
2022-05-17 09:45:21 +00:00
getPiHoleStatus()
{
this.dprint("getting pi-hole status");
try
{
// Trigger request
let me = this;
2021-02-23 17:34:48 +00:00
let url = this.Url + "/api.php?status&auth=" + this.ApiKey;
let request = Soup.Message.new('GET', url);
this.SoupSession.queue_message(request, function(soup, message) {
if (message.status_code == 200)
2021-02-23 17:34:48 +00:00
{
me.processPiHoleStatus(request.response_body.data);
2021-02-23 17:34:48 +00:00
}
else
2021-02-23 17:34:48 +00:00
{
me.eprint("error retrieving status: " + message.status_code);
me.newPiHoleStatus("unknown");
}
});
// Now do it again in a bit
this.StatusEvent = GLib.timeout_add_seconds(0, this.UpdateTime, () => {
this.getPiHoleStatus();
return 0;
});
}
catch (err)
{
this.eprint("exception requesting status: " + err);
}
2022-05-17 09:45:21 +00:00
}
// Pause pi-hole
2022-05-17 09:45:21 +00:00
onPauseButton()
{
// Do op
this.dprint("pausing pi-hole");
this.enableDisable( "disable=" + this.DisableTime.toString() );
// Now ask for status again a second after it should be re-enabled
Mainloop.source_remove(PiHoleExtButton.StatusEvent);
this.StatusEvent = GLib.timeout_add_seconds(0, this.DisableTime + 1, () => {
this.getPiHoleStatus();
return 0;
});
2022-05-17 09:45:21 +00:00
}
// Enable or disable pi-hole
2022-05-17 09:45:21 +00:00
onEnableDisableButton()
{
// Do correct op
let op;
if (this.Status == "enabled")
{
this.dprint("disabling pi-hole (currently " + this.Status + ")");
op = "disable";
}
else
{
this.dprint("enabling pi-hole (currently " + this.Status + ")");
op = "enable";
}
this.enableDisable( op );
// Restart status request cycle since we just got an up-to-date status
Mainloop.source_remove(PiHoleExtButton.StatusEvent);
this.StatusEvent = GLib.timeout_add_seconds(0, this.UpdateTime, () => {
this.getPiHoleStatus();
return 0;
});
2022-05-17 09:45:21 +00:00
}
// Enable or disable pi-hole given op
2022-05-17 09:45:21 +00:00
enableDisable( op )
{
this.dprint("requesting " + op);
try
{
// Trigger request
let me = this;
2021-02-23 17:34:48 +00:00
let url = this.Url + "/api.php?" + op + "&auth=" + this.ApiKey;
let request = Soup.Message.new('GET', url);
this.SoupSession.queue_message(request, function(soup, message) {
if (message.status_code == 200)
2021-02-23 17:34:48 +00:00
{
me.processPiHoleStatus(request.response_body.data);
2021-02-23 17:34:48 +00:00
}
else
2021-02-23 17:34:48 +00:00
{
me.eprint("error requesting disable: " + message.status_code);
me.newPiHoleStatus("unknown");
}
});
}
catch (err)
{
this.eprint("exception requesting enable/disable: " + err);
2021-02-23 17:34:48 +00:00
this.newPiHoleStatus("unknown");
}
2022-05-17 09:45:21 +00:00
}
2021-02-23 17:34:48 +00:00
// Handle status
2022-05-17 09:45:21 +00:00
processPiHoleStatus(data)
{
this.dprint("processing status");
// Process JSON response status
this.Status = "unknown";
try
{
// Process results string
var obj = JSON.parse( data.toString() );
2021-02-23 17:34:48 +00:00
this.newPiHoleStatus( obj.status );
}
catch (err)
{
this.eprint("exception processing status [" + data.toString() + "]: " + err);
2021-02-23 17:34:48 +00:00
this.newPiHoleStatus("unknown");
}
2022-05-17 09:45:21 +00:00
}
2021-02-23 17:34:48 +00:00
// New status
2022-05-17 09:45:21 +00:00
newPiHoleStatus(newstatus)
2021-02-23 17:34:48 +00:00
{
if (newstatus === undefined)
newstatus = "undefined";
this.Status = newstatus;
// Update statuses
this.dprint("got status " + this.Status);
this.setStatusText();
this.setIcon();
if (this.Status == "enabled")
this.EnableDisableButton.label.set_text(_("Disable"));
else
this.EnableDisableButton.label.set_text(_("Enable"));
}
// Status text
setStatusText()
{
let clutter_text = this.StatusField.get_clutter_text();
clutter_text.set_markup( _("Pi-Hole Status") + ": <b>" + this.Status + "</b>" );
2022-05-17 09:45:21 +00:00
}
2021-02-23 17:34:48 +00:00
// Open settings
2022-05-17 09:45:21 +00:00
onSettingsButton()
2021-02-23 17:34:48 +00:00
{
ExtensionUtils.openPrefs();
2021-02-23 17:34:48 +00:00
}
2022-05-17 09:45:21 +00:00
});
// Setup
function init()
{
}
// Turn on
function enable()
{
PiHoleExtButton = new PiHole();
main.panel.addToStatusArea( IndicatorName, PiHoleExtButton );
}
// Turn off
function disable()
{
2021-02-23 17:34:48 +00:00
// Disconnects the setting listeners
for (let id in this.SettingChangedHandlerIds)
this._settings.disconnect(this.SettingChangedHandlerIds[id]);
this.SettingChangedHandlerIds = null;
// Finish off
Mainloop.source_remove(PiHoleExtButton.StatusEvent);
PiHoleExtButton.destroy();
PiHoleExtButton = null;
}