diff --git a/silkaj/cli.py b/silkaj/cli.py index 200298e845e03bb972a20aab3a0890c01d394a62..bcd73bec240f1c9dbbed811858996a505b379a2e 100644 --- a/silkaj/cli.py +++ b/silkaj/cli.py @@ -26,10 +26,10 @@ from silkaj.cert import send_certification from silkaj.commands import ( currency_info, difficulties, - network_info, argos_info, list_blocks, ) +from silkaj.net import network_info from silkaj.wot import received_sent_certifications, id_pubkey_correspondence from silkaj.auth import generate_auth_file from silkaj.license import license_command diff --git a/silkaj/commands.py b/silkaj/commands.py index bc8247e3233cfac50752920bf9709afe864ef262..cbf205f2d39d9ce9d25ee2167cd38ea365e1eff9 100644 --- a/silkaj/commands.py +++ b/silkaj/commands.py @@ -15,9 +15,8 @@ You should have received a copy of the GNU Affero General Public License along with Silkaj. If not, see <https://www.gnu.org/licenses/>. """ -from click import command, option, argument, IntRange, get_terminal_size -from datetime import datetime -from os import system, popen +from click import command, option, argument, IntRange +from os import system from collections import OrderedDict from tabulate import tabulate from operator import itemgetter @@ -26,19 +25,17 @@ import aiohttp from _socket import gaierror import jsonschema -from duniterpy.api.client import Client, parse_text from duniterpy.api import bma from silkaj.tools import coroutine from silkaj.wot import identity_of from silkaj.network_tools import ( - discover_peers, best_endpoint_address, EndPoint, ClientInstance, HeadBlock, ) -from silkaj.tools import convert_time, message_exit, CurrencySymbol +from silkaj.tools import convert_time, CurrencySymbol from silkaj.constants import ASYNC_SLEEP @@ -144,111 +141,6 @@ Common Proof-of-Work difficulty level: {5}, hash starting with `{6}`\n{7}".forma ) -def get_network_sort_key(endpoint): - t = list() - for akey in network_sort_keys: - if akey == "diffi" or akey == "block" or akey == "port": - t.append(int(endpoint[akey]) if akey in endpoint else 0) - else: - t.append(str(endpoint[akey]) if akey in endpoint else "") - return tuple(t) - - -@command("net", help="Display network view") -@option( - "--discover", "-d", is_flag=True, help="Discover the network (could take a while)" -) -@option( - "--sort", - "-s", - default="block,member,diffi,uid", - show_default=True, - help="Sort column names comma-separated", -) -@coroutine -async def network_info(discover, sort): - global network_sort_keys - network_sort_keys = sort.split(",") - width = get_terminal_size()[0] - if width < 146: - message_exit( - "Wide screen need to be larger than 146. Current width: " + str(width) - ) - # discover peers - # and make sure fields are always ordered the same - infos = [ - OrderedDict( - (i, p.get(i, None)) for i in ("domain", "port", "ip4", "ip6", "pubkey") - ) - for p in await discover_peers(discover) - ] - client = ClientInstance().client - diffi = await client(bma.blockchain.difficulties) - members = 0 - print("Getting informations about nodes:") - for i, info in enumerate(infos): - ep = info - api = "BASIC_MERKLED_API " if ep["port"] != "443" else "BMAS " - api += ep.get("domain") + " " if ep["domain"] else "" - api += ep.get("ip4") + " " if ep["ip4"] else "" - api += ep.get("ip6") + " " if ep["ip6"] else "" - api += ep.get("port") - print("{0:.0f}%".format(i / len(infos) * 100, 1), end=" ") - best_ep = best_endpoint_address(info, False) - print(best_ep if best_ep is None else info[best_ep], end=" ") - print(info["port"]) - await sleep(ASYNC_SLEEP) - try: - info["uid"] = await identity_of(info["pubkey"]) - info["uid"] = info["uid"]["uid"] - info["member"] = "yes" - members += 1 - except: - info["uid"] = None - info["member"] = "no" - info["pubkey"] = info["pubkey"][:5] + "…" - for d in diffi["levels"]: - if info.get("uid") is not None: - if info["uid"] == d["uid"]: - info["diffi"] = d["level"] - if len(info["uid"]) > 10: - info["uid"] = info["uid"][:9] + "…" - sub_client = Client(api) - current_blk = await sub_client(bma.blockchain.current) - if current_blk is not None: - info["gen_time"] = convert_time(current_blk["time"], "hour") - if width > 171: - info["mediantime"] = convert_time(current_blk["medianTime"], "hour") - if width > 185: - info["difftime"] = convert_time( - current_blk["time"] - current_blk["medianTime"], "hour" - ) - info["block"] = current_blk["number"] - info["hash"] = current_blk["hash"][:10] + "…" - summary = await sub_client(bma.node.summary) - info["version"] = summary["duniter"]["version"] - await sub_client.close() - if info.get("domain") is not None and len(info["domain"]) > 20: - info["domain"] = "…" + info["domain"][-20:] - if info.get("ip6") is not None: - if width < 156: - info.pop("ip6") - else: - info["ip6"] = info["ip6"][:8] + "…" - await client.close() - print( - len(infos), - "peers ups, with", - members, - "members and", - len(infos) - members, - "non-members at", - datetime.now().strftime("%H:%M:%S"), - ) - infos = sorted(infos, key=get_network_sort_key) - print(tabulate(infos, headers="keys", tablefmt="orgtbl", stralign="center")) - - @command("blocks", help="Display blocks: default: 0 for current window size") @argument("number", default=0, type=IntRange(0, 5000)) @option( diff --git a/silkaj/net.py b/silkaj/net.py new file mode 100644 index 0000000000000000000000000000000000000000..b3ba4ae5bc06f558caff59766f0467c4fb8a3ceb --- /dev/null +++ b/silkaj/net.py @@ -0,0 +1,141 @@ +""" +Copyright 2016-2020 Maël Azimi <m.a@moul.re> + +Silkaj is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Silkaj 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 Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Silkaj. If not, see <https://www.gnu.org/licenses/>. +""" + +from click import command, option, get_terminal_size +from datetime import datetime +from os import system +from collections import OrderedDict +from tabulate import tabulate +from asyncio import sleep + +from duniterpy.api.client import Client +from duniterpy.api import bma + +from silkaj.tools import coroutine +from silkaj.wot import identity_of +from silkaj.network_tools import ( + discover_peers, + best_endpoint_address, + ClientInstance, +) +from silkaj.tools import convert_time, message_exit +from silkaj.constants import ASYNC_SLEEP + + +def get_network_sort_key(endpoint): + t = list() + for akey in network_sort_keys: + if akey == "diffi" or akey == "block" or akey == "port": + t.append(int(endpoint[akey]) if akey in endpoint else 0) + else: + t.append(str(endpoint[akey]) if akey in endpoint else "") + return tuple(t) + + +@command("net", help="Display network view") +@option( + "--discover", "-d", is_flag=True, help="Discover the network (could take a while)" +) +@option( + "--sort", + "-s", + default="block,member,diffi,uid", + show_default=True, + help="Sort column names comma-separated", +) +@coroutine +async def network_info(discover, sort): + global network_sort_keys + network_sort_keys = sort.split(",") + width = get_terminal_size()[0] + if width < 146: + message_exit( + "Wide screen need to be larger than 146. Current width: " + str(width) + ) + # discover peers + # and make sure fields are always ordered the same + infos = [ + OrderedDict( + (i, p.get(i, None)) for i in ("domain", "port", "ip4", "ip6", "pubkey") + ) + for p in await discover_peers(discover) + ] + client = ClientInstance().client + diffi = await client(bma.blockchain.difficulties) + members = 0 + print("Getting informations about nodes:") + for i, info in enumerate(infos): + ep = info + api = "BASIC_MERKLED_API " if ep["port"] != "443" else "BMAS " + api += ep.get("domain") + " " if ep["domain"] else "" + api += ep.get("ip4") + " " if ep["ip4"] else "" + api += ep.get("ip6") + " " if ep["ip6"] else "" + api += ep.get("port") + print("{0:.0f}%".format(i / len(infos) * 100, 1), end=" ") + best_ep = best_endpoint_address(info, False) + print(best_ep if best_ep is None else info[best_ep], end=" ") + print(info["port"]) + await sleep(ASYNC_SLEEP) + try: + info["uid"] = await identity_of(info["pubkey"]) + info["uid"] = info["uid"]["uid"] + info["member"] = "yes" + members += 1 + except: + info["uid"] = None + info["member"] = "no" + info["pubkey"] = info["pubkey"][:5] + "…" + for d in diffi["levels"]: + if info.get("uid") is not None: + if info["uid"] == d["uid"]: + info["diffi"] = d["level"] + if len(info["uid"]) > 10: + info["uid"] = info["uid"][:9] + "…" + sub_client = Client(api) + current_blk = await sub_client(bma.blockchain.current) + if current_blk is not None: + info["gen_time"] = convert_time(current_blk["time"], "hour") + if width > 171: + info["mediantime"] = convert_time(current_blk["medianTime"], "hour") + if width > 185: + info["difftime"] = convert_time( + current_blk["time"] - current_blk["medianTime"], "hour" + ) + info["block"] = current_blk["number"] + info["hash"] = current_blk["hash"][:10] + "…" + summary = await sub_client(bma.node.summary) + info["version"] = summary["duniter"]["version"] + await sub_client.close() + if info.get("domain") is not None and len(info["domain"]) > 20: + info["domain"] = "…" + info["domain"][-20:] + if info.get("ip6") is not None: + if width < 156: + info.pop("ip6") + else: + info["ip6"] = info["ip6"][:8] + "…" + await client.close() + print( + len(infos), + "peers ups, with", + members, + "members and", + len(infos) - members, + "non-members at", + datetime.now().strftime("%H:%M:%S"), + ) + infos = sorted(infos, key=get_network_sort_key) + print(tabulate(infos, headers="keys", tablefmt="orgtbl", stralign="center"))