Участник с: 11 октября 2013
|
Как продолжение темы http://archlinux.org.ru/forum/topic/13769/?page=1
Выпилил гномовский нетворгманагер - изначально не нравиось то кол-во тапов, которое требовалось для смены точки доступа. Как выпилил - не спрашивайте, не отвечу, проблемно. Вернулся к голому netctl. Для него есть неработающее расширение https://extensions.gnome.org/extension/718/netctl-systray-menu/. Стал его читать, ибо суть есть скрипт. Скрипт повсеместно требует рутовых прав, реализуя их через gksudo. Также скрипт пытается даже сервисы перезапускать systemctl stop и т.д. Даже не всякий раз скрипт отображается в строке Гнома. В предельном случае в это Гном-расширение можно было бы засунуть скрипт балансировки между сетками http://archlinux.org.ru/forum/topic/13769/?page=1, на работу которого просто не нарадуюсь.
Что и как надо сделать -
1. поскольку аплет запускается с правами пользователя, а нам надо обращаться к netctl и iwconfig, который, кстати, внезапно может требовать рутовых прав для получения сведений о качестве сигнала, следует разрешить использование netctl, iwconfig, wifi-menu, wpa_cli без рутового пароля (это не ставит безопасность под угрозу, поскольку повсеместно применяемый Гномнетворкманагер дает тот же функционал, но без рутовых прав) -
echo 'имя_юзера_в_системе ALL=(ALL) NOPASSWD: /usr/bin/netctl, /usr/bin/wifi-menu', /usr/bin/iwconfig, /usr/bin/wpa_cli'>> /etc/sudoers
1.1. поскольку управление сетью командами netctl конфликтует с авто-сервисом самого netctl, следует прибить и остановить его авто-сервис-
systemctl disable netctl-auto@wlp3s0.service
systemctl stop netctl-auto@wlp3s0.service
Изначально авторская версия расширения по п. 2 пытается командовать systemctl, но как-то неудачно. Я счел это излишним и удалил.
2. Загрузить само расширение (сам не хочу заводить свое, во всяком случае пока - ибо я же просто модицифицировал чужое расширение) https://extensions.gnome.org/extension/718/netctl-systray-menu/
3. найти в своем хомовнике /home/юзер/.local/share/gnome-shell/extensions/netctlsystraymenugnome@prmurthy/extension.js
4. открыть его редактором и заменить содержимое на нижеследующее -
/*
* Netctl Menu is a Gnome 3 extension that allows you to switch between netctl
* profiles using a menu in the notification area.
* This version has been tested with Gnome version 3.12
*
* Author: Pradeep Murthy (prmurthy ****at**** yahoo ****dot **** com)
* This was originally based on an applet by Tjaart van der Walt
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
const version = 3.0
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const St = imports.gi.St;
const GObject = imports.gi.GObject;
const Signals = imports.signals;
const Mainloop = imports.mainloop;
const MessageTray = imports.ui.messageTray;
const Util = imports.misc.util;
// Icons
const NETWORK_OFFLINE = "network-error-symbolic";
const NETWORK_ETHERNET = "network-wired-symbolic";
const NETWORK_WL_CONNECTED_0 = "network-wireless-signal-none-symbolic";
const NETWORK_WL_CONNECTED_1 = "network-wireless-signal-weak-symbolic";
const NETWORK_WL_CONNECTED_2 = "network-wireless-signal-ok-symbolic";
const NETWORK_WL_CONNECTED_3 = "network-wireless-signal-good-symbolic";
const NETWORK_WL_CONNECTED_4 = "network-wireless-signal-excellent-symbolic";
// Variables
let indicator;
let event = null;
let iface;
let wl_contype;
let enet_static_iface;
let wl_static_iface;
function Netctl() {
this._init.apply(this, arguments);
}
function execute_async(command) {
try {
let[result, argv] = GLib.shell_parse_argv(command);
let[returnval, pid] = GLib.spawn_async(null, argv, null, GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD, null);
GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, function () {
close_async(pid);
});
return pid;
} catch (e) {
global.logError(e);
}
}
function close_async(pid) {
try {
GLib.spawn_close_pid(pid);
} catch (e) {
global.logError(e);
}
}
Netctl.prototype = {
__proto__: PanelMenu.Button.prototype,
// above changed from PanelMenu.SystemStatusButton for 3.12 compatibility
// This means that this will not work with older Gnome versions
// For older versions, change this to PanelMenu.SystemStatusButton.prototype
_init: function(){
PanelMenu.Button.prototype._init.call(this, 0.0, 'netctl', false);
// Alignment (0.0) and menu parameter (false) added for compatibility with newer gnome versions
// This means that this will not work with older Gnome versions
// For older version, change this to ....call(this, 'netctl')
// We include the set_icon() and update_menu() becaust otherwise the
// icon will only appear after the timeout on refresh_details() have passed
this._update_menu();
this._set_icon();
// Will keep updating the status area icon and updating the menu every x seconds
this._refresh_details();
},
_get_interface: function () {
// gets the currently active interface. returns the active interface name if any
let check_interface_exists = GLib.spawn_command_line_sync("ip route list")[1].toString();
// if this returns a null, then there are no active interfaces
if (check_interface_exists == "") {
iface = "";
this._get_static_interface();
wl_contype = "N";
return "";
}
let iface0 = check_interface_exists.split(" ", 5)[4].toString();
return iface0;
},
_get_static_interface: function () {
// gets the names of the network devices in the system. sets the global variables wl_static_interface and enet_static_interface
// we are assuming that there is only 1 wireless and ethernet interface each, and the interface names start with w and e respectively
// If there is more than one interface each, the last interface will be the static interface selected
let ifacelist = GLib.spawn_command_line_sync("ls /sys/class/net").toString();
all_iface = ifacelist.split("\n", 3);
for (i = 0; i < all_iface.length; i++) {
if (all_iface[i].charAt(0) == "w") {
wl_static_iface = all_iface[i]
} else
if (all_iface[i].charAt(0) == "e") {
enet_static_iface = all_iface[i]
}
}
},
_get_connected_networks: function () {
// finds out the name of the network we are connected to, and how
// returns the connection type (Ethernet, Auto, Manual), Name of the connected wireless network if any, and signal quality as a 2digit decimal
if (iface == "") {
return [wl_contype, "None", 0];
}
// interface name begins with e, so it must be Ethernet
if (iface.charAt(0) == "e") {
wl_contype = "E";
return [wl_contype, "Ethernet", 0];
} else
// interface name begins with w so it must be wireless
if (iface.charAt(0) == "w") {
let t1 = GLib.spawn_command_line_sync("sudo iwconfig").toString().match(/Quality=.*/).toString();
let qmax = t1.substr(11, 2).valueOf();
let q = t1.substr(8, 2).valueOf();
let strength = (q / qmax).toFixed(2);
let profiles = GLib.spawn_command_line_sync("sudo netctl list")[1].toString();
let connected = profiles.match(/\*.*/g);
if (connected == null) {
//if above returns null, netctl could be in auto mode. So we check as below
let shellcmd = "sudo wpa_cli -i " + iface + " status";
let connected = GLib.spawn_command_line_sync(shellcmd)[1].toString().match(/(?:.*?(id_str.*)){1}/)[1].toString().slice(7);
wl_contype = "A";
return [wl_contype, connected, strength]; //we are connected automatically
} else {
wl_contype = "M";
return [wl_contype, connected.toString().slice(2), strength];
} // we are connected manually
} else {
return ["N", "None", 0];
} // Something's wrong if we are here
},
_set_icon: function () {
// Sets the systray icon and the tooltip text, after getting data from _get_connected_networks
let icon_name = "";
let networkname = this._get_connected_networks();
if (networkname[1] == "Ethernet") {
icon_name = NETWORK_ETHERNET;
tooltiptext = "Connected via Ethernet";
} else if (networkname[1] == null || networkname[1] == "None") {
icon_name = NETWORK_OFFLINE;
tooltiptext = "Not Connected";
} else {
let contype;
let quality = (networkname[2] * 100).valueOf();
if (networkname[0] == "A") {
contype = "Auto: ";
} else
if (networkname[0] == "M") {
contype = "Manual: ";
}
tooltiptext = contype + "Connected to " + networkname[1].toString() + " : " + quality.toString() + "%";
if (quality < 25) {
icon_name = NETWORK_WL_CONNECTED_1;
} else
if (quality < 50) {
icon_name = NETWORK_WL_CONNECTED_2;
} else
if (quality < 75) {
icon_name = NETWORK_WL_CONNECTED_3;
} else
if (quality <= 100) {
icon_name = NETWORK_WL_CONNECTED_4;
}
}
let statusIcon = new St.Icon({
icon_name: icon_name,
icon_size: 16
});
this.actor.get_children().forEach(function (c) {
c.destroy()
});
this.actor.add_actor(statusIcon);
},
_get_network_profiles: function () {
// gets the list of netctl profiles
// returns an array of profile names
var profileString = GLib.spawn_command_line_sync("sudo netctl list")[1].toString();
var profileArray = profileString.split("\n")
return profileArray.splice(0, profileArray.length - 1)
},
_switch_to_profile: function (newprofileName) {
// switches to selected manual profile. Not used for switching to auto profile because netctl switch-to doesnt work for switching from manual profile to auto
let _wl_contype = wl_contype;
let oldprofile = this._get_connected_networks();
let msg = "Switching to" + newprofileName + ". Please enter your password";
if (_wl_contype == "A") {
shellcmd = "sudo netctl switch-to " + newprofileName + "\'" + "\"";
let pid = execute_async(shellcmd);
// wait for child to exit and then check if it worked
GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, function () {
Netctl.prototype._switch_back_on_failure(_wl_contype, oldprofile[1].toString(), newprofileName);
});
} else if (_wl_contype == "M" || _wl_contype == "N") {
shellcmd = "sudo netctl switch-to " + newprofileName;
let pid = execute_async(shellcmd);
// wait for child to exit and then check if it worked
GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, function () {
Netctl.prototype._switch_back_on_failure(_wl_contype, oldprofile[1].toString(), newprofileName);
});
}
},
_switch_back_on_failure: function (contype, oldprofileName, newprofileName) {
// checks if the switch to a new profile worked. If it didnt, switches back to old profile. calls _get_connected_networks to update variables. updates the menu
// if iface is set to null by _get_interface, it means we arent connected any more. The switch failed, so need to switch back
iface = this._get_interface();
this._get_connected_networks();
if (iface == "") {
if (contype == "A") {
msg = "The wireless network" + newprofileName + " is not available. Re-enabling the auto profile. Please enter your password again";
shellcmd = "netctl stop-all";
execute_async(shellcmd);
} else
if (contype == "M") {
msg = "The wireless network" + newprofileName + " is not available. Switching back to" + oldprofileName + ". Please enter your password again";
shellcmd = "sudo netctl start " + oldprofileName + "\'" + "\"";
execute_async(shellcmd);
} else {
Main.notify("Netctl: Sorry, the wireless network" + newprofileName + " is not available");
}
} else {
Main.notify("Netctl: Connected to" + newprofileName);
}
this._update_menu();
},
//запуск wifi-menu
_add_wifi_menu_menu_item: function () {
// adds menu item for wifi-menu
let menuItem = new PopupMenu.PopupMenuItem(" Доступные сети, подключиться");
this.menu.addMenuItem(menuItem);
menuItem.connect('activate', Lang.bind(this, function () {
shellcmd = "/usr/bin/gnome-terminal -e 'sudo /usr/bin/wifi-menu'"
var pid = execute_async(shellcmd);
}));
},
_add_profile_menu_item: function (profile) {
// adds profiles to the menu. provides click action for inactive profiles
if (!profile.match(/\*.*/g)) {
let menuItem = new PopupMenu.PopupMenuItem(profile);
this.menu.addMenuItem(menuItem);
menuItem.connect('activate', Lang.bind(this, function () {
this._switch_to_profile(profile);
}));
} else {
this.menu.addMenuItem(new PopupMenu.PopupMenuItem(profile, {
reactive: false
}));
}
},
//отрисовка меню
_update_menu: function () {
// creates the menu
this.menu.removeAll();
iface = this._get_interface();
var profiles = this._get_network_profiles();
for (let i = 0; i < profiles.length; i++) {
this._add_profile_menu_item(profiles[i]);
}
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this._add_wifi_menu_menu_item();
},
_refresh_details: function () {
// refreshes the menu and icons/tooltip text
event = GLib.timeout_add_seconds(0, 5, Lang.bind(this, function () {
this._update_menu();
this._set_icon();
return true;
}));
}
}
function init() {
}
function enable() {
indicator = new Netctl();
Main.panel.addToStatusArea('netctl', indicator);
indicator._get_connected_networks();
}
function disable() {
indicator.destroy();
Mainloop.source_remove(event);
indicator = null;
}
5. Перезагрузить (перечитать) Гном - alt+F2 r, включить расширение.
Радоваться простенькому аплету Wi-Fi.
Чем он лучше штатного гномовского? -
1. не тратит батарейку на лишние сканирования доступных сеток. Пользователь обычно сам знает, когда и что искать 2. подключается к любой известной сетке в 2 клика 3. сканирует и подключается к любой новой сетке (запускает wifi-menu) в 2 клика (третий идет на выбор нужной сетки)
Что хочу еще прикрутить - - дополнить раскрывающимся подменю на удаление разовых сеток - включение vpn
|