From a353054df6aaac2a587de620c185945d4ae48707 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 20:12:54 +0000 Subject: [PATCH 1/8] Initial plan From 6f5076e2f78e54ce57cb22edb93a4ea1f71ac0e2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 20:16:45 +0000 Subject: [PATCH 2/8] Fix typos and code quality issues Co-authored-by: vekerdyb <2007265+vekerdyb@users.noreply.github.com> --- .gitignore | 2 +- README.md | 2 +- cloudflare_backend.py | 2 -- ip-trigger.py | 17 ++++++++++------- railgun_backend.py | 2 +- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 1e86000..a68ce0c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ ip-trigger-storage venv/ -__pychache__/ +__pycache__/ *.pyc diff --git a/README.md b/README.md index ce73d24..4e12098 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Docker, docker-compose. # Setup -Clone the repo `git clone git@github.com:vekerdyb/ip-trigger.py` +Clone the repo `git clone git@github.com:vekerdyb/ip-trigger.git` Rename `config.py.tmp` to `config.py` and change the values. Uncomment any backend you want to use. diff --git a/cloudflare_backend.py b/cloudflare_backend.py index a2ed721..e192e11 100644 --- a/cloudflare_backend.py +++ b/cloudflare_backend.py @@ -6,8 +6,6 @@ logger = logging.getLogger(__name__) -URL = 'https://api.cloudflare.com/client/v4/' - def on_ip_change(new_ip, log_handler=logger): log_handler.debug('Attempting to update Cloudflare IP for host {} to {}'.format( diff --git a/ip-trigger.py b/ip-trigger.py index ef85c41..8da8fec 100755 --- a/ip-trigger.py +++ b/ip-trigger.py @@ -48,18 +48,21 @@ def curl_get(url, interface=None): def store_ip(ip): logger.debug('Attempting to open "{}" for appending'.format(STORAGE_FILE)) - file = open(STORAGE_FILE, "a") - file.write(ip + "\n") - file.close() + with open(STORAGE_FILE, "a") as file: + file.write(ip + "\n") logger.debug("IP {} stored in file".format(ip)) def retrieve_last_ip_from_storage(): logger.debug('Attempting to retrieve last IP from "{}"'.format(STORAGE_FILE)) - last_ip = subprocess.check_output(["tail", "-1", STORAGE_FILE]) - last_ip = last_ip.strip().decode("utf-8") - logger.debug('Last IP: "{}"'.format(last_ip)) - return last_ip + try: + last_ip = subprocess.check_output(["tail", "-1", STORAGE_FILE]) + last_ip = last_ip.strip().decode("utf-8") + logger.debug('Last IP: "{}"'.format(last_ip)) + return last_ip + except subprocess.CalledProcessError: + logger.debug("Storage file is empty or cannot be read") + return "" def detect_current_ip(): diff --git a/railgun_backend.py b/railgun_backend.py index 19c5b38..b061a6d 100644 --- a/railgun_backend.py +++ b/railgun_backend.py @@ -22,7 +22,7 @@ def _send_simple_message(from_name, to, subject, text): def on_ip_change(new_ip, log_handler=logger): log_handler.debug( - 'Sending email to "{}", becuase IP changed to "{}"'.format(config.RAILGUN['EMAIL_RECIPIENT'], new_ip)) + 'Sending email to "{}", because IP changed to "{}"'.format(config.RAILGUN['EMAIL_RECIPIENT'], new_ip)) response = _send_simple_message( from_name=config.RAILGUN['FROM_NAME'], From 25aa188d5f02dffbfab76b537f488ed1fcdbf82e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 20:17:58 +0000 Subject: [PATCH 3/8] Improve error handling and messages in retrieve_last_ip_from_storage Co-authored-by: vekerdyb <2007265+vekerdyb@users.noreply.github.com> --- ip-trigger.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ip-trigger.py b/ip-trigger.py index 8da8fec..42444e9 100755 --- a/ip-trigger.py +++ b/ip-trigger.py @@ -58,10 +58,13 @@ def retrieve_last_ip_from_storage(): try: last_ip = subprocess.check_output(["tail", "-1", STORAGE_FILE]) last_ip = last_ip.strip().decode("utf-8") + if not last_ip: + logger.debug("Storage file is empty") + return "" logger.debug('Last IP: "{}"'.format(last_ip)) return last_ip except subprocess.CalledProcessError: - logger.debug("Storage file is empty or cannot be read") + logger.debug("Storage file does not exist or cannot be accessed") return "" From 9c0e19d7cd3637cd759be9b8498b3ca0fbbb876c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 20:45:53 +0000 Subject: [PATCH 4/8] Fix typos Co-authored-by: vekerdyb <2007265+vekerdyb@users.noreply.github.com> --- cloudflare_backend.py | 2 ++ ip-trigger.py | 20 +++++++------------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/cloudflare_backend.py b/cloudflare_backend.py index e192e11..a2ed721 100644 --- a/cloudflare_backend.py +++ b/cloudflare_backend.py @@ -6,6 +6,8 @@ logger = logging.getLogger(__name__) +URL = 'https://api.cloudflare.com/client/v4/' + def on_ip_change(new_ip, log_handler=logger): log_handler.debug('Attempting to update Cloudflare IP for host {} to {}'.format( diff --git a/ip-trigger.py b/ip-trigger.py index 42444e9..ef85c41 100755 --- a/ip-trigger.py +++ b/ip-trigger.py @@ -48,24 +48,18 @@ def curl_get(url, interface=None): def store_ip(ip): logger.debug('Attempting to open "{}" for appending'.format(STORAGE_FILE)) - with open(STORAGE_FILE, "a") as file: - file.write(ip + "\n") + file = open(STORAGE_FILE, "a") + file.write(ip + "\n") + file.close() logger.debug("IP {} stored in file".format(ip)) def retrieve_last_ip_from_storage(): logger.debug('Attempting to retrieve last IP from "{}"'.format(STORAGE_FILE)) - try: - last_ip = subprocess.check_output(["tail", "-1", STORAGE_FILE]) - last_ip = last_ip.strip().decode("utf-8") - if not last_ip: - logger.debug("Storage file is empty") - return "" - logger.debug('Last IP: "{}"'.format(last_ip)) - return last_ip - except subprocess.CalledProcessError: - logger.debug("Storage file does not exist or cannot be accessed") - return "" + last_ip = subprocess.check_output(["tail", "-1", STORAGE_FILE]) + last_ip = last_ip.strip().decode("utf-8") + logger.debug('Last IP: "{}"'.format(last_ip)) + return last_ip def detect_current_ip(): From 0406520d6bdaaa149ab3edc3202673f3c2468d50 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 20:49:05 +0000 Subject: [PATCH 5/8] Remove unused URL variable Co-authored-by: vekerdyb <2007265+vekerdyb@users.noreply.github.com> --- cloudflare_backend.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/cloudflare_backend.py b/cloudflare_backend.py index a2ed721..e192e11 100644 --- a/cloudflare_backend.py +++ b/cloudflare_backend.py @@ -6,8 +6,6 @@ logger = logging.getLogger(__name__) -URL = 'https://api.cloudflare.com/client/v4/' - def on_ip_change(new_ip, log_handler=logger): log_handler.debug('Attempting to update Cloudflare IP for host {} to {}'.format( From 2a1cf02b6ead291489713ab4b95121f40e022520 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 20:49:51 +0000 Subject: [PATCH 6/8] Use context manager for file handling Co-authored-by: vekerdyb <2007265+vekerdyb@users.noreply.github.com> --- ip-trigger.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ip-trigger.py b/ip-trigger.py index ef85c41..10e676a 100755 --- a/ip-trigger.py +++ b/ip-trigger.py @@ -48,9 +48,8 @@ def curl_get(url, interface=None): def store_ip(ip): logger.debug('Attempting to open "{}" for appending'.format(STORAGE_FILE)) - file = open(STORAGE_FILE, "a") - file.write(ip + "\n") - file.close() + with open(STORAGE_FILE, "a") as file: + file.write(ip + "\n") logger.debug("IP {} stored in file".format(ip)) From 046e721b89142e5e84916cbd6f3124b3f2c82566 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 20:50:37 +0000 Subject: [PATCH 7/8] Add error handling for missing storage file Co-authored-by: vekerdyb <2007265+vekerdyb@users.noreply.github.com> --- ip-trigger.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ip-trigger.py b/ip-trigger.py index 10e676a..787d421 100755 --- a/ip-trigger.py +++ b/ip-trigger.py @@ -55,10 +55,14 @@ def store_ip(ip): def retrieve_last_ip_from_storage(): logger.debug('Attempting to retrieve last IP from "{}"'.format(STORAGE_FILE)) - last_ip = subprocess.check_output(["tail", "-1", STORAGE_FILE]) - last_ip = last_ip.strip().decode("utf-8") - logger.debug('Last IP: "{}"'.format(last_ip)) - return last_ip + try: + last_ip = subprocess.check_output(["tail", "-1", STORAGE_FILE]) + last_ip = last_ip.strip().decode("utf-8") + logger.debug('Last IP: "{}"'.format(last_ip)) + return last_ip + except subprocess.CalledProcessError: + logger.debug("Storage file does not exist or cannot be accessed") + return "" def detect_current_ip(): From 2634ff3924e52f4633d97cb654704d385ddeb9e3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 20:51:26 +0000 Subject: [PATCH 8/8] Add error handling for empty storage file Co-authored-by: vekerdyb <2007265+vekerdyb@users.noreply.github.com> --- ip-trigger.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ip-trigger.py b/ip-trigger.py index 787d421..42444e9 100755 --- a/ip-trigger.py +++ b/ip-trigger.py @@ -58,6 +58,9 @@ def retrieve_last_ip_from_storage(): try: last_ip = subprocess.check_output(["tail", "-1", STORAGE_FILE]) last_ip = last_ip.strip().decode("utf-8") + if not last_ip: + logger.debug("Storage file is empty") + return "" logger.debug('Last IP: "{}"'.format(last_ip)) return last_ip except subprocess.CalledProcessError: