Skip to content

Commit

Permalink
Add filter plan nodes. Fix PlanAccordion height. Merge @Tkd-Alex/2.0/…
Browse files Browse the repository at this point in the history
…search branch into 2.0. Amend search() to include list of values. #66, #36, #93, #89
  • Loading branch information
freQniK committed Apr 15, 2024
1 parent 6fca31c commit f201fab
Show file tree
Hide file tree
Showing 4 changed files with 276 additions and 75 deletions.
174 changes: 163 additions & 11 deletions src/cli/sentinel.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from datetime import datetime,timedelta
import time
from urllib.parse import urlparse
import copy

from treelib import Tree
from treelib.exceptions import DuplicatedNodeIdError
Expand All @@ -27,12 +28,13 @@
v2ray_tun2routes_connect_bash = MeileConfig.resource_path("../bin/routes.sh")

class NodeTreeData():
NodeTree = None
NodeScores = {}
NodeLocations = {}
NodeTypes = {}
NodeHealth = {}
NodeFormula = {}
BackupNodeTree = None
NodeTree = None
NodeScores = {}
NodeLocations = {}
NodeTypes = {}
NodeHealth = {}
NodeFormula = {}

def __init__(self, node_tree):
if not node_tree:
Expand Down Expand Up @@ -93,9 +95,9 @@ def get_nodes(self, latency, *kwargs):
'''Parse out old node versions < 0.7.0'''

d[NodeKeys.NodesInfoKeys[14]] = d[NodeKeys.NodesInfoKeys[14]].split('-')[0]
version = d[NodeKeys.NodesInfoKeys[14]].replace('.','')
if version not in NodeKeys.NodeVersions:
continue
#version = d[NodeKeys.NodesInfoKeys[14]].replace('.','')
#if version not in NodeKeys.NodeVersions:
# continue

# Gigabyte Prices
d[NodeKeys.NodesInfoKeys[2]] = self.return_denom(d[NodeKeys.NodesInfoKeys[2]])
Expand All @@ -111,7 +113,10 @@ def get_nodes(self, latency, *kwargs):
except Exception as e:
print(str(e)) # print the exception in this early build to identify any issues building the nodetree
pass


# Used for Search and Plans
self.BackupNodeTree = copy.deepcopy(self.NodeTree)

# For pretty output. Unicode is used in treelib > 1.6.1
self.NodeTree.show()
# User-submitted Ratings
Expand All @@ -125,7 +130,154 @@ def get_nodes(self, latency, *kwargs):

# Get MathNodes NodeFormula
self.GetNodeFormula()




# Filter nodetree.
# key; what we want to filter, for example: Moniker, Type, Health
# value; query value
# between; value must be between[0], between[1], for example:
# key = "Hourly Price", between = ("5.3426dvpn", "15.3426dvpn")
# key = "Scores", between = (8, 10)
# from_backup; if true it will be used the backupped data, else will be used the 'renderized' one (maybe already filtered)
# perfect_match; if true, value must be equal for example:
# perfect_match = True, key = "Moniker", value = "Pinco" will match only Moniker === Pinco
# perfect_match = False, key = "Moniker", value = "Pinco" will match only Moniker like Pincopallo, Pizzapinco10, Pincopallino, Pinco1

def search(self, key: str, value = None, between: tuple = (), from_backup: bool = True, perfect_match: bool = False, is_list: bool = False):
if value is None and len(between) == 0:
# at least one of value or between must be setted
return

amount_rx = r'^(\.\d|\d+\.\d+|\d+)'
key = key.title()

# Prepare the "between" values out of iteration
if value is None and len(between) == 2:
a, b = between[0], between[1]
if key in ['Hourly Price', 'Price']:
a = amount_denon_dict(a)
b = amount_denon_dict(b)
# print(f"[DEBUG] a: {a}, b: {b}")

if a is None or b is None:
# unable to continue
return

if a["denom"] != b["denom"]:
# unable to use different denom in between
return

# It the same of b["denom"], just a variable rename
def_denom = a["denom"]
if def_denom == "udvpn":
# btw, probably no one will use udvpn as search field
a["denom"] = b["denom"] = "dvpn"
a["amount"] = a["amount"] // 1000000
b["amount"] = b["amount"] // 1000000
else:
a = float(re.search(amount_rx, a).group(0))
b = float(re.search(amount_rx, b).group(0))

# Create a copy of Tree please ...
# Under the iteration of keys I will delete all the nodes that doesn't match our query
filtered = copy.deepcopy(self.BackupNodeTree if from_backup is True else self.NodeTree)
# Iteration via the original data, in order to prevent "RuntimeError: dictionary changed size during iteration"
for identifier, content in (self.BackupNodeTree if from_backup is True else self.NodeTree).nodes.items():
if identifier.startswith("sentnode"):
if key in content.data:
# use in... / wherlike / contains
if value is not None:
if is_list:
for v in value:
if perfect_match is True:
if v.lower().strip() != content.data[key].lower():
filtered.remove_node(identifier)
elif v.lower().strip() not in content.data[key].lower():
# use in... / wherlike / contains
filtered.remove_node(identifier)
else:
if perfect_match is True:
if value.lower().strip() != content.data[key].lower():
filtered.remove_node(identifier)
elif value.lower().strip() not in content.data[key].lower():
# use in... / wherlike / contains
filtered.remove_node(identifier)
elif len(between) == 2:

# ups, following this: https://github.com/MathNodes/meile-gui/commit/622e501d332f0a34009b77548c4672e0ae32577b#diff-3729b5451a4398b2a4fd75a4bf0062d9bd5040677dd766ade023084aa9c03379R87
# NodesInfoKeys = ["Moniker","Address","Price","Hourly Price", "Country","Speed","Latency","Peers","Handshake","Type","Version","Status"]
# NodesInfoKeys = ["Moniker","Address","Price","Hourly Price", "Country","City","Latitude","Longitude","Download","Upload","Peers","Max Peers","Handshake","Type","Version"]

# I'm so crazy and I like it
if key in ['Hourly Price', 'Price']:
# 'Hourly Price': '0.0185scrt,0.0008atom,1.8719dec,0.0189osmo,4.16dvpn',
# 'Price': '0.0526scrt,0.0092atom,1.1809dec,0.1227osmo,15.3426dvpn',
prices = content.data[key].split(",")
# Now we have an array: ['0.0185scrt', '0.0008atom', '1.8719dec', '0.0189osmo', '4.16dvpn']
# Convert array with denom as key and amount as value:
prices = {
amount_denon_dict(p)["denom"]: amount_denon_dict(p)["amount"] for p in prices
}
# print(f"[DEBUG] {identifier} | prices: {prices}")
if def_denom not in prices:
# uhm, unable to continue, probably the node doesn't support this denom (?)
# remove anyway from the tree
filtered.remove_node(identifier)
else:
# Make sure a is min and b is max
_min = min(a["amount"], b["amount"])
_max = max(a["amount"], b["amount"])
if prices[def_denom] > _max or prices[def_denom] < _min:
# print(f"[DEBUG] {identifier} | remove basecause > {_max} (max) or < {_min} (min)")
filtered.remove_node(identifier)
else:
# 'Latency': '1.762s',
# 'Peers': '0',
# --> not managed: 'Speed': '123.93MB+520.20MB',

#Extract only number
node_value = float(re.search(amount_rx, content.data[key]).group(0))
# Make sure a is min and b is max
_min = min(a, b)
_max = max(a, b)
if node_value > _max or node_value < _min:
filtered.remove_node(identifier)


# Type: wireguard / v2ray
# Type: residential / hosting .... (uhmm) - ConnectionType
elif key == "ConnectionType":
if identifier not in self.NodeTypes:
filtered.remove_node(identifier)
else:
if self.NodeTypes[identifier] != value:
filtered.remove_node(identifier)
elif key == "Health":
if identifier not in self.NodeHealth:
filtered.remove_node(identifier)
else:
as_bool = value if isinstance(value, bool) else (value.lower() == "true")
if self.NodeHealth[identifier] != as_bool:
filtered.remove_node(identifier)
elif key == "Scores":
if identifier not in self.NodeScores:
filtered.remove_node(identifier)
else:
rating = float(self.NodeScores[identifier][0])
if value is not None and float(value) != rating:
filtered.remove_node(identifier)
elif len(between) == 2:
# Make sure a is min and b is max
_min = min(a, b)
_max = max(a, b)
if rating > _max or rating < _min:
filtered.remove_node(identifier)

# Always override the 'renderized' one (maybe already filtered)
self.NodeTree = filtered


def GetHealthCheckData(self):
Request = HTTPRequests.MakeRequest(TIMEOUT=4)
http = Request.hadapter()
Expand Down
78 changes: 58 additions & 20 deletions src/kv/meile.kv
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,8 @@ WindowManager:
icon: "animation-outline"
theme_text_color: "Custom"
text_color: get_color_from_hex("#fcb711")

on_release: root.switch_to_plan_window()

ToolTipMDIconButton:
tooltip_text: "Settings"
icon: "cog-outline"
Expand Down Expand Up @@ -831,13 +832,13 @@ WindowManager:
MDLabel:
text: "Plan"
bold: True
size_hint_x: 2.5
size_hint_x: 2.9


MDLabel:
text: "Nodes"
bold: True
size_hint_x: 1.3
size_hint_x: 1.1

MDLabel:
text: "Countries"
Expand All @@ -850,7 +851,7 @@ WindowManager:
size_hint_x: 1.4

MDLabel:
text: "UUID"
text:
bold: True
size_hint_x: 1

Expand Down Expand Up @@ -968,14 +969,14 @@ WindowManager:
rows: 2
cols: 6
AsyncImage:
size_hint_x: .3
size_hint_x: .1
width: 100
source: root.logo_image
MDLabel:
padding: [10, 0, 0, 0]
text: root.plan_name
markup: True
size_hint_x: 2
size_hint_x: 2.5
theme_text_color: "Custom"
font_style: "H6"
font_size: sp(16)
Expand All @@ -985,28 +986,29 @@ WindowManager:
MDLabel:
text: root.num_of_nodes
markup: True
size_hint_x: 1
size_hint_x: 1.4
font_name: "../../src/fonts/arial-unicode-ms.ttf"
MDLabel:
text: root.num_of_countries
markup: True
size_hint_x: 1
size_hint_x: 1.4
font_name: "../../src/fonts/arial-unicode-ms.ttf"

MDLabel:
text: root.cost
markup: True
size_hint_x: 1
size_hint_x: 1.8
font_name: "../../src/fonts/arial-unicode-ms.ttf"

MDRaisedButton:
id: plan_sub_button
text: "SUBSCRIBE"
font_size: dp(9)
pos_hint: {"center_x": .1, "center_y": .5}
on_press: root.copy_seed_phrase()
size_hint: None, None
size: 15,10
MDFlatButton:
#md_bg_color: get_color_from_hex("#121212")
pos_hint: {'x' : .67, 'y': .275}
size_hint_x: .5
Image:
id: subscribe_button
size_hint: 1.5,1.5
source: "../../src/imgs/SubscribeButton.png"

HSeparator:
HSeparator:
HSeparator:
Expand Down Expand Up @@ -1057,35 +1059,71 @@ WindowManager:
HSeparator:

<PlanDetails>:
rows: 2
cols: 4
adaptive_height: True
rows: 3
cols: 6
#adaptive_height: True
height: 90
#orientation: 'horizontal'

MDLabel
text: "[b]UUID[/b]"
markup: True
size_hint_x: 2
MDLabel
text: "[b]ID[/b]"
markup: True


MDLabel
text: "[b]Expires[/b]"
markup: True
size_hint_x: 1.3

MDLabel
text: "[b]Deposit[/b]"
markup: True

MDLabel
text: "[b]Coin[/b]"
markup: True

TooltipMDIconButton:
icon: "table-filter"
tooltip_text: "Filter Nodes"
size_hint_x: .25
theme_text_color: "Custom"
text_color: app.theme_cls.primary_color
on_release: root.filter_nodes()

MDLabel
text: root.uuid
markup: True
font_size: sp(10)
size_hint_x: 2
MDLabel
text: root.id
markup: True
font_size: sp(10)
MDLabel
text: root.expires
markup: True
font_size: sp(11)
size_hint_x: 1.3
MDLabel
text: root.deposit
markup: True
font_size: sp(11)
MDLabel
text: root.coin
markup: True
font_size: sp(11)

MDLabel
MDLabel
MDLabel
MDLabel
MDLabel
MDLabel

<NodeDetails>:
rows: 2
Expand Down
Loading

0 comments on commit f201fab

Please sign in to comment.