From ea9f8f2e612465eff5fb5ca311b1a49e6cdffc83 Mon Sep 17 00:00:00 2001 From: Yekta Yazar Date: Wed, 29 Oct 2025 09:55:09 -0700 Subject: [PATCH 1/7] adds env variable to hold proxy url. Be able to set proxy url --- .env.template | 4 ++++ trace/services/elog_client.py | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/.env.template b/.env.template index 4a28fe3a..9ef756b4 100644 --- a/.env.template +++ b/.env.template @@ -1,2 +1,6 @@ SWAPPS_TRACE_ELOG_API_URL=https://accel-webapp-dev.slac.stanford.edu/api/elog-apptoken SWAPPS_TRACE_ELOG_API_KEY= + +# Optional: Proxy URL for environments that require proxy access to ELOG API +# Leave empty or unset if no proxy is needed +SWAPPS_TRACE_ELOG_PROXY_URL= diff --git a/trace/services/elog_client.py b/trace/services/elog_client.py index 689740fa..4040ad28 100644 --- a/trace/services/elog_client.py +++ b/trace/services/elog_client.py @@ -17,6 +17,13 @@ ELOG_API_URL = os.getenv("SWAPPS_TRACE_ELOG_API_URL") ELOG_API_KEY = os.getenv("SWAPPS_TRACE_ELOG_API_KEY") +# Configure proxy if specified in environment +ELOG_PROXY_URL = os.getenv("SWAPPS_TRACE_ELOG_PROXY_URL") +if ELOG_PROXY_URL: + os.environ['HTTP_PROXY'] = ELOG_PROXY_URL + os.environ['HTTPS_PROXY'] = ELOG_PROXY_URL + logger.info(f"ELOG client using proxy: {ELOG_PROXY_URL}") + def get_user() -> tuple[int, dict | Exception]: """ From 553c7ab2615fc1372d3440e6d12baab565009a11 Mon Sep 17 00:00:00 2001 From: Yekta Yazar Date: Wed, 29 Oct 2025 11:45:41 -0700 Subject: [PATCH 2/7] added note to Environment Setup in the installation docs --- docs/installation.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/installation.md b/docs/installation.md index 5b3a1510..d84cb7f7 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -52,6 +52,7 @@ Below is a table describing the environment variables that need to be set. | PYDM_ARCHIVER_URL | The base URL for the Archiver Appliance Data Plugin | | SWAPPS_TRACE_ELOG_API_URL | The base URL for the E-Log API | | SWAPPS_TRACE_ELOG_API_KEY | Your API key for authenticating with the E-Log system | +| SWAPPS_TRACE_ELOG_PROXY_URL | Proxy URL for environments that require proxy access to ELOG API | From c1d75a032a17486627093d7b9e3f2c7bf1b2edbc Mon Sep 17 00:00:00 2001 From: Yekta Yazar Date: Wed, 29 Oct 2025 11:47:13 -0700 Subject: [PATCH 3/7] formatting fix --- trace/services/elog_client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trace/services/elog_client.py b/trace/services/elog_client.py index 4040ad28..f226efa7 100644 --- a/trace/services/elog_client.py +++ b/trace/services/elog_client.py @@ -20,8 +20,8 @@ # Configure proxy if specified in environment ELOG_PROXY_URL = os.getenv("SWAPPS_TRACE_ELOG_PROXY_URL") if ELOG_PROXY_URL: - os.environ['HTTP_PROXY'] = ELOG_PROXY_URL - os.environ['HTTPS_PROXY'] = ELOG_PROXY_URL + os.environ["HTTP_PROXY"] = ELOG_PROXY_URL + os.environ["HTTPS_PROXY"] = ELOG_PROXY_URL logger.info(f"ELOG client using proxy: {ELOG_PROXY_URL}") From 9855203cbf652b51ea159750de0ae5eb822279fc Mon Sep 17 00:00:00 2001 From: Yekta Yazar Date: Wed, 29 Oct 2025 16:18:47 -0700 Subject: [PATCH 4/7] add a test for the proxy --- trace/services/elog_client.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/trace/services/elog_client.py b/trace/services/elog_client.py index f226efa7..f513e2c5 100644 --- a/trace/services/elog_client.py +++ b/trace/services/elog_client.py @@ -22,7 +22,22 @@ if ELOG_PROXY_URL: os.environ["HTTP_PROXY"] = ELOG_PROXY_URL os.environ["HTTPS_PROXY"] = ELOG_PROXY_URL - logger.info(f"ELOG client using proxy: {ELOG_PROXY_URL}") + + # Test proxy connectivity immediately + if ELOG_API_URL: + try: + test_response = requests.head(ELOG_API_URL, timeout=5) + logger.info(f"ELOG client using proxy: {ELOG_PROXY_URL} - Connection test successful") + except requests.exceptions.ProxyError as e: + logger.error(f"Proxy connection failed: {ELOG_PROXY_URL} is not accessible - {e}") + except requests.exceptions.ConnectionError as e: + logger.error(f"Connection failed through proxy {ELOG_PROXY_URL}. Check network connectivity and proxy configuration - {e}") + except requests.exceptions.Timeout as e: + logger.error(f"Connection timeout through proxy {ELOG_PROXY_URL}. The proxy or server may be slow or unresponsive - {e}") + except requests.exceptions.RequestException as e: + logger.error(f"Proxy connection test failed for {ELOG_PROXY_URL}: {e}") + else: + logger.warning("Proxy configured but ELOG_API_URL is not set. Skipping proxy test.") def get_user() -> tuple[int, dict | Exception]: From b5a1a45c3a6f5e402b1229a973fda6bfcc7ca076 Mon Sep 17 00:00:00 2001 From: Yekta Yazar Date: Wed, 29 Oct 2025 16:19:12 -0700 Subject: [PATCH 5/7] formatting fix --- trace/services/elog_client.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/trace/services/elog_client.py b/trace/services/elog_client.py index f513e2c5..b4b83957 100644 --- a/trace/services/elog_client.py +++ b/trace/services/elog_client.py @@ -31,9 +31,13 @@ except requests.exceptions.ProxyError as e: logger.error(f"Proxy connection failed: {ELOG_PROXY_URL} is not accessible - {e}") except requests.exceptions.ConnectionError as e: - logger.error(f"Connection failed through proxy {ELOG_PROXY_URL}. Check network connectivity and proxy configuration - {e}") + logger.error( + f"Connection failed through proxy {ELOG_PROXY_URL}. Check network connectivity and proxy configuration - {e}" + ) except requests.exceptions.Timeout as e: - logger.error(f"Connection timeout through proxy {ELOG_PROXY_URL}. The proxy or server may be slow or unresponsive - {e}") + logger.error( + f"Connection timeout through proxy {ELOG_PROXY_URL}. The proxy or server may be slow or unresponsive - {e}" + ) except requests.exceptions.RequestException as e: logger.error(f"Proxy connection test failed for {ELOG_PROXY_URL}: {e}") else: From ff6341e3a05e851f031ce57eaf3c875bc6fb4013 Mon Sep 17 00:00:00 2001 From: Yekta Yazar Date: Wed, 29 Oct 2025 16:24:30 -0700 Subject: [PATCH 6/7] another formatting fix --- trace/services/elog_client.py | 36 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/trace/services/elog_client.py b/trace/services/elog_client.py index b4b83957..9492b46e 100644 --- a/trace/services/elog_client.py +++ b/trace/services/elog_client.py @@ -23,25 +23,23 @@ os.environ["HTTP_PROXY"] = ELOG_PROXY_URL os.environ["HTTPS_PROXY"] = ELOG_PROXY_URL - # Test proxy connectivity immediately - if ELOG_API_URL: - try: - test_response = requests.head(ELOG_API_URL, timeout=5) - logger.info(f"ELOG client using proxy: {ELOG_PROXY_URL} - Connection test successful") - except requests.exceptions.ProxyError as e: - logger.error(f"Proxy connection failed: {ELOG_PROXY_URL} is not accessible - {e}") - except requests.exceptions.ConnectionError as e: - logger.error( - f"Connection failed through proxy {ELOG_PROXY_URL}. Check network connectivity and proxy configuration - {e}" - ) - except requests.exceptions.Timeout as e: - logger.error( - f"Connection timeout through proxy {ELOG_PROXY_URL}. The proxy or server may be slow or unresponsive - {e}" - ) - except requests.exceptions.RequestException as e: - logger.error(f"Proxy connection test failed for {ELOG_PROXY_URL}: {e}") - else: - logger.warning("Proxy configured but ELOG_API_URL is not set. Skipping proxy test.") + # Test proxy connectivity + try: + test_response = requests.head(ELOG_API_URL, timeout=5) + logger.info(f"ELOG client using proxy: {ELOG_PROXY_URL} - Connection test successful") + except requests.exceptions.ProxyError as e: + logger.error(f"Proxy connection failed: {ELOG_PROXY_URL} is not accessible - {e}") + except requests.exceptions.ConnectionError as e: + logger.error( + f"""Connection failed through proxy {ELOG_PROXY_URL}. + Check network connectivity and proxy configuration - {e}""" + ) + except requests.exceptions.Timeout as e: + logger.error( + f"Connection timeout through proxy {ELOG_PROXY_URL}.The proxy or server may be slow or unresponsive - {e}" + ) + except requests.exceptions.RequestException as e: + logger.error(f"Proxy connection test failed for {ELOG_PROXY_URL}: {e}") def get_user() -> tuple[int, dict | Exception]: From 051d6ab57a8da18c4bc8e37d226657f18e46f167 Mon Sep 17 00:00:00 2001 From: Yekta Yazar Date: Thu, 30 Oct 2025 09:47:13 -0700 Subject: [PATCH 7/7] moved the proxy check to when the print to elog button is first clicked --- trace/main.py | 20 ++++++++++++++- trace/services/__init__.py | 2 +- trace/services/elog_client.py | 46 ++++++++++++++++++++++++++--------- 3 files changed, 55 insertions(+), 13 deletions(-) diff --git a/trace/main.py b/trace/main.py index f5a414b0..de002511 100644 --- a/trace/main.py +++ b/trace/main.py @@ -35,7 +35,14 @@ from config import logger, datetime_pv from file_io import PathAction, TraceFileHandler from widgets import ControlPanel, ElogPostModal, DataInsightTool, PlotSettingsModal -from services import Theme, IconColors, ThemeManager, get_user, post_entry +from services import ( + Theme, + IconColors, + ThemeManager, + get_user, + post_entry, + test_proxy_connection, +) DISABLE_AUTO_SCROLL = -2 # Using -2 as invalid since QButtonGroups use -1 as invalid @@ -552,6 +559,17 @@ def elog_button_clicked(self) -> bool: bool True if the post was successful, False otherwise. """ + # Test proxy connection first if proxy is configured + proxy_success, proxy_error = test_proxy_connection() + if not proxy_success: + error_dialog = QMessageBox() + error_dialog.setIcon(QMessageBox.Warning) + error_dialog.setWindowTitle("Proxy Connection Failed") + error_dialog.setText(proxy_error) + error_dialog.setStandardButtons(QMessageBox.Ok) + error_dialog.exec_() + return False + # Test if API is reachable status_code, _ = get_user() if status_code != 200: diff --git a/trace/services/__init__.py b/trace/services/__init__.py index 3f985237..bc057203 100644 --- a/trace/services/__init__.py +++ b/trace/services/__init__.py @@ -1,2 +1,2 @@ -from .elog_client import get_user, post_entry, get_logbooks +from .elog_client import get_user, post_entry, get_logbooks, test_proxy_connection from .theme_manager import ThemeManager, Theme, IconColors diff --git a/trace/services/elog_client.py b/trace/services/elog_client.py index 9492b46e..97693aa5 100644 --- a/trace/services/elog_client.py +++ b/trace/services/elog_client.py @@ -6,6 +6,7 @@ import os import json +from typing import Optional from pathlib import Path import requests @@ -22,24 +23,47 @@ if ELOG_PROXY_URL: os.environ["HTTP_PROXY"] = ELOG_PROXY_URL os.environ["HTTPS_PROXY"] = ELOG_PROXY_URL + logger.info(f"ELOG client configured to use proxy: {ELOG_PROXY_URL}") + + +def test_proxy_connection() -> tuple[bool, Optional[str]]: + """ + Tests proxy connectivity if a proxy is configured. + + :return: A tuple of (success, error_message). If successful, error_message is None. + If failed, error_message contains a detailed description of the failure. + """ + if not ELOG_PROXY_URL: + # No proxy configured, consider this a success + return True, None + + if not ELOG_API_URL: + return False, "ELOG API URL is not configured. Cannot test proxy connection." + + error_msg = ( + f"Failed to connect through proxy {ELOG_PROXY_URL}. " + f"Please check your network connection and proxy configuration." + ) - # Test proxy connectivity try: - test_response = requests.head(ELOG_API_URL, timeout=5) - logger.info(f"ELOG client using proxy: {ELOG_PROXY_URL} - Connection test successful") + requests.head(ELOG_API_URL, timeout=2) + logger.info(f"Proxy connection test successful: {ELOG_PROXY_URL}") + return True, None except requests.exceptions.ProxyError as e: - logger.error(f"Proxy connection failed: {ELOG_PROXY_URL} is not accessible - {e}") + logger.error(f"Proxy connection test failed: {e}") + return False, error_msg except requests.exceptions.ConnectionError as e: - logger.error( - f"""Connection failed through proxy {ELOG_PROXY_URL}. - Check network connectivity and proxy configuration - {e}""" - ) + logger.error(f"Proxy connection test failed: {e}") + return False, error_msg except requests.exceptions.Timeout as e: - logger.error( - f"Connection timeout through proxy {ELOG_PROXY_URL}.The proxy or server may be slow or unresponsive - {e}" + error_msg = ( + f"Connection timeout through proxy {ELOG_PROXY_URL}. " f"The proxy or server may be slow or unresponsive." ) + logger.error(f"Proxy connection test failed: {e}") + return False, error_msg except requests.exceptions.RequestException as e: - logger.error(f"Proxy connection test failed for {ELOG_PROXY_URL}: {e}") + logger.error(f"Proxy connection test failed: {e}") + return False, error_msg def get_user() -> tuple[int, dict | Exception]: