From 31daa0e705af8bf4db8bfbf0984b32b293b8f97f Mon Sep 17 00:00:00 2001 From: terminaldweller Date: Tue, 17 Jan 2023 11:31:01 +0330 Subject: updates --- .newsboat/urls | 9 + .vimrc | 1 + bin/tunneltop | 231 +++++++++++++++++-------- terminaldweller.com/gemini/docker-compose.yaml | 5 +- terminaldweller.com/gemini/index.gmi | 4 +- 5 files changed, 169 insertions(+), 81 deletions(-) diff --git a/.newsboat/urls b/.newsboat/urls index 18345a3..f226194 100644 --- a/.newsboat/urls +++ b/.newsboat/urls @@ -26,6 +26,15 @@ https://rssgen.terminaldweller.com/?action=display&bridge=TwitterBridge&context= https://rssgen.terminaldweller.com/?action=display&bridge=TwitterBridge&context=By+username&u=nobitexmarket&norep=on&noretweet=on&nopinned=on&nopic=on&noimg=on&noimgscaling=on&format=Atom "~nobitex"Twitter https://rssgen.terminaldweller.com/?action=display&bridge=TwitterBridge&context=By+username&u=CVEnew&norep=on&noretweet=on&nopinned=on&nopic=on&noimg=on&noimgscaling=on&format=Atom "~CVEnew"Twitter +# Google Alerts +https://www.google.com/alerts/feeds/12093321976767190558/264763670533121619 "~Monero"Google_Alerts +https://www.google.com/alerts/feeds/12093321976767190558/3412771701207347411 "~Ethereum"Google_Alerts +https://www.google.com/alerts/feeds/12093321976767190558/13483223157227276101 "~Tor_Network"Google_Alerts +https://www.google.com/alerts/feeds/12093321976767190558/2769088908428192247 "~i2p"Google_Alerts +https://www.google.com/alerts/feeds/12093321976767190558/16765140344737729825 "~TheGreenPlace"Google_Alerts +https://www.google.com/alerts/feeds/12093321976767190558/11780712112899033397 "~Security_Breach"Google_Alerts +https://www.google.com/alerts/feeds/12093321976767190558/8312907097599403294 "~Terminaldweller"Google_Alerts + # (Youtube) # Horror https://www.youtube.com/feeds/videos.xml?channel_id=UC4QEH0BC7ZQMYIEmr1yAHfQ "~RomNex"youtube diff --git a/.vimrc b/.vimrc index 9b45043..1681bdd 100644 --- a/.vimrc +++ b/.vimrc @@ -1459,6 +1459,7 @@ augroup END let g:ale_python_black_options = "--line-length 79" let b:ale_python_flake8_options = "--ignore=E203,W503" let b:ale_python_isort_options = "--multiline 3 --profile black" +let b:ale_python_mypy_options = "--check-untyped-defs" augroup ALEPY autocmd! autocmd FileType python let b:ale_linters = {'python': ['flake8','mypy', 'pylint', 'bandit']} diff --git a/bin/tunneltop b/bin/tunneltop index ebed5d9..1c65d0d 100755 --- a/bin/tunneltop +++ b/bin/tunneltop @@ -3,7 +3,9 @@ import argparse import asyncio +import copy import enum +import signal import sys import typing @@ -128,103 +130,180 @@ def ffs( return lines -async def run_subshell(cmd: str) -> typing.Tuple[bytes, bytes]: - """Run a command in a subshell""" - proc = await asyncio.create_subprocess_shell( - cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE - ) +class TunnelTop: + """The tunnel top class""" - # return stdout and stderr - return await proc.communicate() + def __init__(self): + self.argparser = Argparser() + self.data_cols: typing.Dict[str, typing.Dict[str, str]] = {} + self.tunnel_tasks: typing.List[asyncio.Task] = [] + self.tunnel_test_tasks: typing.List[asyncio.Task] = [] + + async def run_subshell(self, cmd: str) -> typing.Tuple[bytes, bytes]: + """Run a command in a subshell""" + proc = await asyncio.create_subprocess_shell( + cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) + return await proc.communicate() -def tunnel_test_callback(task: asyncio.Task) -> None: - """Tunnel test callback function.""" - task_name = task.get_name() - # data_cols["stdout"] = task.result()[0] - # data_cols["stderr"] = task.result()[1] - if ( - task.result()[0].decode("utf-8").strip("\n") - == data_cols[task_name]["test_command_result"] - ): - data_cols[task_name]["status"] = "UP" - else: - data_cols[task_name]["status"] = "DOWN" + def tunnel_test_callback(self, task: asyncio.Task) -> None: + """Tunnel test callback function.""" + try: + task_name = task.get_name() + self.data_cols[task_name]["stdout"] = ( + task.result()[0].decode("utf-8").strip("\n") + ) + self.data_cols[task_name]["stderr"] = ( + task.result()[1].decode("utf-8").strip("\n") + ) + if ( + task.result()[0].decode("utf-8").strip("\n") + == self.data_cols[task_name]["test_command_result"] + ): + self.data_cols[task_name]["status"] = "UP" + else: + self.data_cols[task_name]["status"] = "DOWN" + except asyncio.TimeoutError: + self.data_cols[task_name]["status"] = "TMOUT" + + async def tunnel_test_procs(self) -> typing.List[asyncio.Task]: + """run all the tunnel tests in the background as separate tasks""" + tasks: typing.List[asyncio.Task] = [] + for _, value in self.data_cols.items(): + if value["test_command"] != "": + tasks.append( + asyncio.create_task( + asyncio.wait_for( + self.run_subshell(value["test_command"]), + timeout=float(value["test_timeout"]), + ), + name=value["name"], + ) + ) + tasks[-1].add_done_callback(self.tunnel_test_callback) + await asyncio.sleep(0) + return tasks -async def tunnel_test_procs() -> typing.List[asyncio.Task]: - """run all the tunnel tests in the background as separate tasks""" - tasks: typing.List[asyncio.Task] = [] - for _, value in data_cols.items(): - if value["test_command"] != "": + async def tunnel_procs( + self, + ) -> typing.List[asyncio.Task]: + """run all the tunnels in the background as separate tasks""" + tasks: typing.List[asyncio.Task] = [] + for _, value in self.data_cols.items(): tasks.append( asyncio.create_task( - run_subshell(value["test_command"]), name=value["name"] - ) + self.run_subshell(value["command"]), name=value["name"] + ), ) - tasks[-1].add_done_callback(tunnel_test_callback) await asyncio.sleep(0) - return tasks - - -async def tunnel_procs(commands: typing.List[str]) -> None: - """run all the tunnels in the background as separate tasks""" - for command in commands: - asyncio.create_task(run_subshell(command)) - await asyncio.sleep(0) - - -data_cols: typing.Dict[str, typing.Dict] = {} - - -async def main() -> None: - """entrypoint""" - argparser = Argparser() - print(Colors.screen_clear, end="") - print(Colors.hide_cursor, end="") - - with open(argparser.args.config, "rb") as conf_file: - data = tomllib.load(conf_file) - for key, value in data.items(): - data_cols[key] = { - "name": key, - "address": value["address"], - "port": value["port"], - "command": value["command"], - "status": "UNKN", - "test_command": value["test_command"], - "test_command_result": value["test_command_result"], - "test_interval": value["test_interval"], - "test_timeout": value["test_timeout"], - "stdout": "", - "stderr": "", - } - - await tunnel_procs([v["command"] for _, v in data_cols.items()]) + return tasks + + # pylint: disable=unused-argument + async def sighup_handler(self, signum, frame): + """SIGHUP handler. we want to reload the config.""" + # type: ignore # pylint: disable=E0203 + data_cols_new: typing.Dict[str, typing.Dict[str, str]] = {} + with open(self.argparser.args.config, "rb") as conf_file: + data = tomllib.load(conf_file) + for key, value in data.items(): + data_cols_new[key] = { + "name": key, + "address": value["address"], + "port": value["port"], + "command": value["command"], + "status": "UNKN", + "test_command": value["test_command"], + "test_command_result": value["test_command_result"], + "test_interval": value["test_interval"], + "test_timeout": value["test_timeout"], + "stdout": "", + "stderr": "", + } + + for k, value in data_cols_new.items(): + if k not in self.data_cols: + self.tunnel_tasks.append( + asyncio.create_task( + self.run_subshell(value["command"]), name=k + ) + ) + await asyncio.sleep(0) + else: + if ( + self.data_cols[k]["command"] != data_cols_new[k]["command"] + or self.data_cols[k]["port"] != data_cols_new[k]["port"] + or self.data_cols[k]["address"] + != data_cols_new[k]["address"] + ): + for task in self.tunnel_tasks: + if task.get_name() == k: + task.cancel() + self.data_cols[k] = copy.deepcopy(data_cols_new[k]) + self.tunnel_tasks.append( + asyncio.create_task( + self.run_subshell(value["command"]), name=k + ) + ) + await asyncio.sleep(0) + + for k, _ in self.data_cols.items(): + if k not in data_cols_new: + for task in self.tunnel_tasks: + if task.get_name() == k: + task.cancel() + del self.data_cols[k] + + async def main(self) -> None: + """entrypoint""" + signal.signal(signal.SIGHUP, self.sighup_handler) + print(Colors.screen_clear, end="") + print(Colors.hide_cursor, end="") + + with open(self.argparser.args.config, "rb") as conf_file: + data = tomllib.load(conf_file) + for key, value in data.items(): + self.data_cols[key] = { + "name": key, + "address": value["address"], + "port": value["port"], + "command": value["command"], + "status": "UNKN", + "test_command": value["test_command"], + "test_command_result": value["test_command_result"], + "test_interval": value["test_interval"], + "test_timeout": value["test_timeout"], + "stdout": "", + "stderr": "", + } + + self.tunnel_tasks = await self.tunnel_procs() while True: - await tunnel_test_procs() + self.tunnel_test_tasks = await self.tunnel_test_procs() lines = ffs( 2, ["NAME", "ADDRESS", "PORT", "STATUS", "STDOUT", "STDERR"] - if not argparser.args.noheader + if not self.argparser.args.noheader else None, False, - [v["name"] for _, v in data_cols.items()], - [v["address"] for _, v in data_cols.items()], - [repr(v["port"]) for _, v in data_cols.items()], - [v["status"] for _, v in data_cols.items()], - [v["stdout"] for _, v in data_cols.items()], - [v["stderr"] for _, v in data_cols.items()], + [v["name"] for _, v in self.data_cols.items()], + [v["address"] for _, v in self.data_cols.items()], + [repr(v["port"]) for _, v in self.data_cols.items()], + [v["status"] for _, v in self.data_cols.items()], + [v["stdout"] for _, v in self.data_cols.items()], + [v["stderr"] for _, v in self.data_cols.items()], ) for line in lines: print(line) - await asyncio.sleep(argparser.args.delay) - print(Colors.screen_clear, end="") - print(Colors.hide_cursor, end="") + await asyncio.sleep(self.argparser.args.delay) + # print(Colors.screen_clear, end="") + # print(Colors.hide_cursor, end="") if __name__ == "__main__": - asyncio.run(main()) + tunnel_top = TunnelTop() + asyncio.run(tunnel_top.main()) diff --git a/terminaldweller.com/gemini/docker-compose.yaml b/terminaldweller.com/gemini/docker-compose.yaml index 42a8a88..befa3cd 100644 --- a/terminaldweller.com/gemini/docker-compose.yaml +++ b/terminaldweller.com/gemini/docker-compose.yaml @@ -17,9 +17,8 @@ services: - SETGID - SETUID volumes: - # we have to use the same cert because of TOFU - - certs:/.certificates/ - - ./index.gmi:/srv/index.gmi:ro + - certs:/.certificates/:ro + - ./srv:/srv:ro networks: agatenet: volumes: diff --git a/terminaldweller.com/gemini/index.gmi b/terminaldweller.com/gemini/index.gmi index 1201a37..bb9a32b 100644 --- a/terminaldweller.com/gemini/index.gmi +++ b/terminaldweller.com/gemini/index.gmi @@ -49,9 +49,9 @@ Services: N/A => http://dqunl5rzlv6skqfklqr4dwi4zph2vqoaennc7qoinqs5mlug4docq2yd.onion/ tor mirror => https://keyoxide.org/hkp/9e20464f1ccf3b103249fa93a6a0f5158b3881df keyoxide => https://github.com/terminaldweller.gpg here -=> https://terminaldweller.com/keys/gpg_pubkey here +=> keys/gpg_pubkey here => https://github.com/terminaldweller.keys here -=> https://terminaldweller.com/keys/id_rsa.pub here +=> keys/id_rsa_pub here => https://libera.chat Libera => https://oftc.net OFTC => https://rizon.net/ Rizon -- cgit v1.2.3