added simple network explorer (#60)

This commit is contained in:
DYefremov
2022-05-07 23:13:17 +03:00
parent a8739be31d
commit d09c14518e
3 changed files with 100 additions and 13 deletions

View File

@@ -733,9 +733,9 @@ class HttpAPI:
self._executor.shutdown()
@staticmethod
def get_response(req_type, url, data=None, s_type=SettingsType.ENIGMA_2):
def get_response(req_type, url, data=None, s_type=SettingsType.ENIGMA_2, timeout=10):
try:
with urlopen(Request(url, data=data), timeout=10) as f:
with urlopen(Request(url, data=data), timeout=timeout) as f:
if s_type is SettingsType.ENIGMA_2:
return HttpAPI.get_e2_response_data(req_type, f)
elif s_type is SettingsType.NEUTRINO_MP:

View File

@@ -3,7 +3,7 @@
The MIT License (MIT)
Copyright (c) 2018-2021 Dmitriy Yefremov
Copyright (c) 2018-2022 Dmitriy Yefremov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -32,7 +32,7 @@ Author: Dmitriy Yefremov
<!-- interface-license-type mit -->
<!-- interface-name DemonEditor -->
<!-- interface-description Enigma2 channel and satellites list editor. -->
<!-- interface-copyright 2018-2021 Dmitriy Yefremov -->
<!-- interface-copyright 2018-2022 Dmitriy Yefremov -->
<!-- interface-authors Dmitriy Yefremov -->
<object class="GtkAdjustment" id="begins_hour_adjustment">
<property name="upper">23</property>
@@ -1141,6 +1141,8 @@ Author: Dmitriy Yefremov
<column type="gchararray"/>
<!-- column-name data -->
<column type="PyObject"/>
<!-- column-name tooltip -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkListStore" id="rec_paths_model">
@@ -2457,7 +2459,8 @@ Author: Dmitriy Yefremov
<object class="GtkToggleButton" id="control_network_button">
<property name="label">gtk-network</property>
<property name="width_request">100</property>
<property name="can_focus">True</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
<property name="use_stock">True</property>
@@ -2619,7 +2622,7 @@ Author: Dmitriy Yefremov
<property name="spacing">10</property>
<child>
<object class="GtkFrame" id="control_network_frame">
<property name="width_request">240</property>
<property name="width_request">280</property>
<property name="can_focus">False</property>
<property name="label_xalign">0.5</property>
<property name="shadow_type">in</property>
@@ -2645,11 +2648,14 @@ Author: Dmitriy Yefremov
<property name="model">network_model</property>
<property name="enable_search">False</property>
<property name="tooltip_column">3</property>
<signal name="query-tooltip" handler="on_network_view_query_tooltip" swapped="no"/>
<child internal-child="selection">
<object class="GtkTreeSelection" id="network_view_selection"/>
</child>
<child>
<object class="GtkTreeViewColumn" id="network_name_column">
<property name="resizable">True</property>
<property name="min_width">25</property>
<property name="title" translatable="yes">Name</property>
<property name="expand">True</property>
<property name="alignment">0.5</property>
@@ -2663,11 +2669,16 @@ Author: Dmitriy Yefremov
</child>
<child>
<object class="GtkTreeViewColumn" id="network_ip_column">
<property name="resizable">True</property>
<property name="min_width">25</property>
<property name="title" translatable="yes">IP</property>
<property name="expand">True</property>
<property name="alignment">0.5</property>
<child>
<object class="GtkCellRendererText" id="network_ip_renderer"/>
<object class="GtkCellRendererText" id="network_ip_renderer">
<property name="xpad">2</property>
<property name="xalign">0.49</property>
</object>
<attributes>
<attribute name="text">1</attribute>
</attributes>
@@ -2676,11 +2687,16 @@ Author: Dmitriy Yefremov
</child>
<child>
<object class="GtkTreeViewColumn" id="network_status_column">
<property name="title" translatable="yes">Status</property>
<property name="resizable">True</property>
<property name="min_width">25</property>
<property name="title" translatable="yes">Power</property>
<property name="expand">True</property>
<property name="alignment">0.5</property>
<child>
<object class="GtkCellRendererText" id="network_status_renderer"/>
<object class="GtkCellRendererText" id="network_status_renderer">
<property name="xalign">0.49</property>
<property name="ellipsize">end</property>
</object>
<attributes>
<attribute name="text">2</attribute>
</attributes>

View File

@@ -28,6 +28,7 @@
""" Receiver control module via HTTP API. """
import os
import re
from datetime import datetime
from enum import Enum
from ftplib import all_errors
@@ -842,7 +843,8 @@ class ControlTool(Gtk.Box):
handlers = {"on_volume_changed": self.on_volume_changed,
"on_screenshot_draw": self.on_screenshot_draw,
"on_network_toggled": self.on_network_toggled}
"on_network_toggled": self.on_network_toggled,
"on_network_view_query_tooltip": self.on_network_view_query_tooltip}
builder = get_builder(UI_RESOURCES_PATH + "control.glade", handlers,
objects=("control_box", "volume_adjustment", "network_model"))
@@ -860,8 +862,11 @@ class ControlTool(Gtk.Box):
self._ber_level_bar = builder.get_object("ber_level_bar")
self._agc_level_bar = builder.get_object("agc_level_bar")
self._volume_button = builder.get_object("volume_button")
self._network_button = builder.get_object("control_network_button")
self._header_box = builder.get_object("control_header_box")
# Network.
self._network_button = builder.get_object("control_network_button")
self._network_model = builder.get_object("network_model")
self.init_actions(app)
if settings.alternate_layout:
@@ -1038,6 +1043,72 @@ class ControlTool(Gtk.Box):
# ***************** Network explorer ********************** #
@run_task
def on_network_toggled(self, button):
pass
self._network_model.clear()
if button.get_active():
self.update_network()
@run_task
def update_network(self):
pattern = re.compile(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')
ips = [match for match in re.findall(pattern, os.popen("arp -a").read())]
for ip in ips:
if not self._network_button.get_active():
break
url = f"http://{ip}/web/{HttpAPI.Request.INFO.value}"
try:
resp = HttpAPI.get_response(HttpAPI.Request.INFO, url, timeout=5)
except OSError as e:
log(f"{ip} {e}")
else:
if resp.get("e2distroversion", None):
log(f"Receiver found. Model: {resp.get('e2model', 'N/A')} [{ip} ]")
self.append_box_data(resp)
@run_idle
def append_box_data(self, data):
ip = data.get('e2lanip', 'N/A')
itr = self._network_model.append((data.get("e2model", "N/A"), ip, None, data, None))
GLib.timeout_add_seconds(3, self.check_power_state, itr, priority=GLib.PRIORITY_LOW)
def on_network_view_query_tooltip(self, view, x, y, keyboard_mode, tooltip):
result = view.get_dest_row_at_pos(x, y)
if not result:
return False
path, pos = result
model = view.get_model()
data = model[path][3]
dist = data.get("e2distroversion", "N/A")
img = data.get("e2imageversion", "N/A")
txt = f"Distro version: {dist}\nImage version: {img}"
tooltip.set_text(txt)
view.set_tooltip_row(tooltip, path)
return True
def check_power_state(self, itr):
active = self._network_button.get_active()
if not active:
return False
data = self._network_model.get_value(itr, 3)
url = f"http://{data.get('e2lanip', 'N/A')}/web/powerstate"
self.update_power_state(itr, url)
return active
@run_task
def update_power_state(self, itr, url):
try:
resp = HttpAPI.get_response(HttpAPI.Request.POWER, url, timeout=2)
except OSError as e:
log(e)
else:
state = get_message("On" if resp.get("e2instandby", "N/A").strip() == "false" else "Standby")
GLib.idle_add(self._network_model.set_value, itr, 2, state)
if __name__ == "__main__":
pass