Skip to content

Commit 0b31a47

Browse files
committed
Fix: Handle crashes and termination of RGB Lightning node
1 parent c72d716 commit 0b31a47

29 files changed

+680
-222
lines changed

.bumpversion.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 0.1.2
2+
current_version = 0.1.3
33
commit = False
44
tag = False
55
allow_dirty = True

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "iris-wallet-desktop"
3-
version = "0.1.2"
3+
version = "0.1.3"
44
description = ""
55
readme = "README.md"
66
license = ""

src/main.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from src.model.setting_model import IsBackupConfiguredModel
2626
from src.model.setting_model import IsWalletInitialized
2727
from src.utils.cache import Cache
28+
from src.utils.common_utils import disable_rln_node_termination_handling
2829
from src.utils.common_utils import load_translator
2930
from src.utils.common_utils import sigterm_handler
3031
from src.utils.excluded_page import excluded_page
@@ -49,6 +50,7 @@ def __init__(self):
4950
self.__init_ui__()
5051
self.progress_dialog = None
5152
self.ln_node_manager = LnNodeServerManager.get_instance()
53+
self.wallet_type: WalletType = SettingRepository.get_wallet_type()
5254

5355
def __init_ui__(self):
5456
"""This method initializes the main window UI of the application."""
@@ -69,8 +71,7 @@ def closeEvent(self, event): # pylint:disable=invalid-name
6971
cache = Cache.get_cache_session()
7072
if cache is not None:
7173
cache.invalidate_cache()
72-
wallet_type: WalletType = SettingRepository.get_wallet_type()
73-
if wallet_type.value == WalletType.REMOTE_TYPE_WALLET.value or page_name in excluded_page:
74+
if self.wallet_type.value == WalletType.REMOTE_TYPE_WALLET.value or page_name in excluded_page:
7475
QApplication.instance().exit()
7576
else:
7677
self.show_backup_progress()
@@ -94,6 +95,7 @@ def show_backup_progress(self):
9495
backup_configure_dialog_box.exec()
9596
else:
9697
self.progress_dialog.exec(True)
98+
disable_rln_node_termination_handling(self.wallet_type)
9799
self.progress_dialog.exec()
98100

99101

src/translations/en_IN.qm

1.04 KB
Binary file not shown.

src/translations/en_IN.ts

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,7 +1334,7 @@ If you understand the above remarks and wish to proceed, press the button below
13341334
</message>
13351335
<message>
13361336
<source>wrong_password</source>
1337-
<translation>The provided password is not correct</translation>
1337+
<translation>The provided password is incorrect</translation>
13381338
</message>
13391339
<message>
13401340
<source>invalid_invoice_error</source>
@@ -1681,24 +1681,38 @@ If you understand the above remarks and wish to proceed, press the button below
16811681
<translation>Asset</translation>
16821682
</message>
16831683
<message>
1684-
<source>data_directory_path_label</source>
1685-
<translation>Data directory path:</translation>
1684+
<source>data_directory_path_label</source>
1685+
<translation>Data directory path:</translation>
16861686
</message>
16871687
<message>
1688-
<source>remote</source>
1689-
<translation>Remote</translation>
1688+
<source>remote</source>
1689+
<translation>Remote</translation>
16901690
</message>
16911691
<message>
1692-
<source>embedded_connection_info</source>
1693-
<translation>With embedded connection, an RGB Lightning Node is automatically run in the background.</translation>
1692+
<source>embedded_connection_info</source>
1693+
<translation>With embedded connection, an RGB Lightning Node is automatically run in the background.</translation>
16941694
</message>
16951695
<message>
1696-
<source>remote_connection_info</source>
1697-
<translation>With remote connection, an RGB Lightning Node needs to be hosted separately and its URL will need to be provided.</translation>
1696+
<source>remote_connection_info</source>
1697+
<translation>With remote connection, an RGB Lightning Node needs to be hosted separately and its URL will need to be provided.</translation>
16981698
</message>
16991699
<message>
1700-
<source>rln_node_connection_description</source>
1701-
<translation>An RLN (RGB Lightning Node) instance is necessary to support the app's functionalities. Clicking an option reveals details about it.</translation>
1700+
<source>rln_node_connection_description</source>
1701+
<translation>An RLN (RGB Lightning Node) instance is necessary to support the app's functionalities. Clicking an option reveals details about it.</translation>
1702+
</message>
1703+
<message>
1704+
<source>rgb_ln_node_connection_failed</source>
1705+
<translation>The RGB Lightning Node unexpectedly crashed or was terminated, causing the connection to the provided Lightning Node to fail. The application requires the RGB Lightning Node to function properly, and it must be running for a successful connection. You can report this issue on {} for assistance.
1706+
1707+
{}You can try to restart the RGB Lightning Node or close the application.</translation>
1708+
</message>
1709+
<message>
1710+
<source>crash_dialog_close_app</source>
1711+
<translation>Close the application</translation>
1712+
</message>
1713+
<message>
1714+
<source>crash_dialog_restart_node</source>
1715+
<translation>Restart RGB Lightning Node</translation>
17021716
</message>
17031717
</context>
17041718
</TS>

src/utils/common_utils.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,3 +614,24 @@ def get_bitcoin_info_by_network():
614614
'medium_checkBox': MEDIUM_TRANSACTION_FEE_BLOCKS,
615615
'fast_checkBox': FAST_TRANSACTION_FEE_BLOCKS,
616616
}
617+
618+
619+
def disable_rln_node_termination_handling(wallet_type: WalletType):
620+
"""
621+
Disconnects the RLN node process termination handler when the user closes the application.
622+
623+
This ensures that the rln node termination handling logic does not trigger when the user explicitly exits.
624+
625+
Args:
626+
wallet_type (WalletType): The type of the wallet being used.
627+
"""
628+
if wallet_type.value == WalletType.EMBEDDED_TYPE_WALLET.value:
629+
ln_node_manager = LnNodeServerManager.get_instance()
630+
631+
try:
632+
ln_node_manager.process.finished.disconnect()
633+
except CommonException as exc:
634+
logger.error(
635+
'Exception occurred: %s, Message: %s',
636+
type(exc).__name__, str(exc),
637+
)

src/utils/constant.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@
121121

122122
# Email and github issue url for error report
123123
CONTACT_EMAIL = 'iriswalletdesktop@gmail.com'
124-
GITHUB_ISSUE_LINK = 'https://github.com/RGB-Tools/iris-wallet-desktop/issues/new?template=Blank+issue'
124+
GITHUB_ISSUE_LINK = 'https://github.com/RGB-Tools/iris-wallet-desktop/issues/new/choose'
125125

126126
# Translation context key
127127
IRIS_WALLET_TRANSLATIONS_CONTEXT = 'iris_wallet_desktop'

src/utils/ln_node_manage.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
from src.utils.constant import MAX_ATTEMPTS_TO_WAIT_FOR_NODE
3333
from src.utils.constant import NODE_CLOSE_INTERVAL
3434
from src.utils.endpoints import NODE_INFO_ENDPOINT
35+
from src.utils.logging import rln_qprocess_logger
3536
from src.utils.request import Request
3637

3738

@@ -53,6 +54,7 @@ class LnNodeServerManager(QObject):
5354
process_already_running = Signal()
5455
process_finished_on_request_app_close = Signal()
5556
process_finished_on_request_app_close_error = Signal()
57+
main_window_loader = Signal(bool)
5658
_instance = None
5759

5860
def __init__(self):
@@ -65,6 +67,8 @@ def __init__(self):
6567
self.process.started.connect(self.on_process_started)
6668
self.process.finished.connect(self.on_process_terminated)
6769
self.process.errorOccurred.connect(self.on_process_error)
70+
self.process.readyReadStandardOutput.connect(self.handle_stdout)
71+
self.process.readyReadStandardError.connect(self.handle_stderr)
6872
self.timer = QTimer()
6973
self.timer.timeout.connect(self.check_node_status)
7074
self.attempts = 0
@@ -129,13 +133,15 @@ def check_node_status(self):
129133
if self.attempts >= MAX_ATTEMPTS_TO_WAIT_FOR_NODE:
130134
self.process_error.emit(500, 'Unable to start server')
131135
self.timer.stop()
136+
self.main_window_loader.emit(False)
132137
return
133138

134139
try:
135140
response = Request.get(NODE_INFO_ENDPOINT)
136141
response.raise_for_status()
137142
self.process_started.emit()
138143
self.timer.stop()
144+
self.main_window_loader.emit(False)
139145
except HTTPError:
140146
self.process_started.emit()
141147
self.timer.stop()
@@ -188,6 +194,18 @@ def _get_ln_path(self):
188194
return os.path.join(base_path, 'ln_node_binary', ln_binary_name)
189195
return os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../', 'ln_node_binary', ln_binary_name))
190196

197+
def handle_stdout(self):
198+
"""Read and print the standard output."""
199+
output = self.process.readAllStandardOutput().data().decode()
200+
if output:
201+
rln_qprocess_logger.info(output)
202+
203+
def handle_stderr(self):
204+
"""Read and print the standard error output."""
205+
error_output = self.process.readAllStandardError().data().decode()
206+
if error_output:
207+
rln_qprocess_logger.error(error_output)
208+
191209
@staticmethod
192210
def get_instance():
193211
"""

src/utils/logging.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from src.utils.local_store import local_store
1414

1515

16-
def setup_logging(application_status: str) -> logging.Logger:
16+
def setup_logger(logger_name: str, log_file_name: str, application_status: str | None = None) -> logging.Logger:
1717
"""
1818
Sets up the logging configuration for the application.
1919
@@ -22,16 +22,18 @@ def setup_logging(application_status: str) -> logging.Logger:
2222
size limit and backup count. For development, it logs both to a file and the console.
2323
2424
Args:
25-
application_status (str): The current status of the application, either 'production' or 'development'.
26-
25+
logger_name (str): Name of the logger.
26+
log_file_name (str): Log file name.
27+
application_status (str | None, optional): The current status of the application, either 'production',
28+
'development', or None. If None, it defaults to 'development'.
2729
Returns:
28-
logging.Logger: Configured logger instance for the application.
30+
logging.Logger: Configured logger instance.
2931
"""
3032
log_directory = LOG_FOLDER_NAME
3133
path = local_store.create_folder(log_directory)
3234

3335
# Create a logger
34-
logger_instance = logging.getLogger('iris-wallet')
36+
logger_instance = logging.getLogger(logger_name)
3537
# Set to debug to capture all levels of messages
3638
logger_instance.setLevel(logging.DEBUG)
3739
# Prevent logging from propagating to the root logger
@@ -42,7 +44,7 @@ def setup_logging(application_status: str) -> logging.Logger:
4244
'%(asctime)s - %(levelname)s - %(message)s',
4345
datefmt='%Y-%m-%d %H:%M:%S',
4446
)
45-
file_name = os.path.join(path, 'iris_wallet_desktop.log')
47+
file_name = os.path.join(path, log_file_name)
4648

4749
# Define and add handlers based on network
4850
file_handler = RotatingFileHandler(
@@ -72,5 +74,11 @@ def setup_logging(application_status: str) -> logging.Logger:
7274
sys, 'frozen', False,
7375
) else 'development'
7476

75-
# Set up logging based on the current network
76-
logger = setup_logging(APPLICATION_STATUS)
77+
# Set up loggers using the refactored function and capturing all logs without applying `APPLICATION_STATUS`
78+
logger = setup_logger(
79+
'iris-wallet', 'iris_wallet_desktop.log',
80+
)
81+
82+
rln_qprocess_logger = setup_logger(
83+
'qprocess', 'rln_qprocess.log',
84+
)

src/utils/request.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ def get(
6060
params = params if params is not None else {}
6161
url = f'{Request.load_base_url()}{endpoint}'
6262

63+
# Log request initiation
64+
logger.info('Starting GET request to %s', url)
65+
6366
response = requests.get(
6467
url,
6568
headers=headers,
@@ -90,6 +93,9 @@ def post(
9093
params = params if params is not None else {}
9194
url = f'{Request.load_base_url()}{endpoint}'
9295

96+
# Log request initiation
97+
logger.info('Starting POST request to %s', url)
98+
9399
if files is not None:
94100
response = requests.post(url, files=files, timeout=REQUEST_TIMEOUT)
95101
else:
@@ -122,6 +128,9 @@ def put(
122128
params = params if params is not None else {}
123129
url = f'{Request.load_base_url()}{endpoint}'
124130

131+
# Log request initiation
132+
logger.info('Starting PUT request to %s', url)
133+
125134
response = requests.put(
126135
url,
127136
json=body,
@@ -150,6 +159,9 @@ def delete(
150159
params = params if params is not None else {}
151160
url = f'{Request.load_base_url()}{endpoint}'
152161

162+
# Log request initiation
163+
logger.info('Starting DELETE request to %s', url)
164+
153165
response = requests.delete(
154166
url,
155167
headers=headers,

0 commit comments

Comments
 (0)