Skip to content

Move UI to System Tray #226

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 35 commits into from
Apr 1, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
40be46b
move LND into node launcher
PierreRochard Mar 25, 2019
404437e
don't prune if blocks directory already exists
PierreRochard Mar 25, 2019
e190da6
integrate bitcoind
PierreRochard Mar 25, 2019
cee0348
start implementing system tray icon
PierreRochard Mar 26, 2019
6c72e9b
refactor application and menu into classes
PierreRochard Mar 26, 2019
a310545
debug getting rid of the app icon
PierreRochard Mar 26, 2019
635c97b
Update node launcher system tray icon
PierreRochard Mar 26, 2019
9417242
Refactor object hierarchy
PierreRochard Mar 26, 2019
1131421
add percentage completion
PierreRochard Mar 26, 2019
c22cbfa
Add ETA
PierreRochard Mar 26, 2019
d7580d2
Add averaged ETA
PierreRochard Mar 26, 2019
d0a5052
Fix ETA estimate
PierreRochard Mar 27, 2019
f3664d6
Automatically create wallet
PierreRochard Mar 27, 2019
b11541c
Add more information for LND syncing
PierreRochard Mar 27, 2019
626b1a3
Fix restarting LND
PierreRochard Mar 27, 2019
e0dbec8
Remove lnd wallet layout
PierreRochard Mar 27, 2019
f55446d
Move CLI to menu
PierreRochard Mar 27, 2019
e441ad6
Add joule to system tray menu
PierreRochard Mar 27, 2019
4c8a2c7
refactor class hierarchy wip
PierreRochard Mar 27, 2019
3591e33
Finish refactoring class hierarchy
PierreRochard Mar 27, 2019
13625b9
WIP Fix up tests
PierreRochard Mar 28, 2019
fc8397c
Finish fixing up tests
PierreRochard Mar 29, 2019
859da1e
Add error message
PierreRochard Mar 29, 2019
b815179
fix windows bug
PierreRochard Apr 1, 2019
1ee0326
fix windows string splitting
PierreRochard Apr 1, 2019
c164c74
Fix new wallet creation
PierreRochard Apr 1, 2019
8fadd5c
fix logging directory
PierreRochard Apr 1, 2019
5f8500a
switch systray icon to bitcoin logo
PierreRochard Apr 1, 2019
8bfcb39
refactor handling of lnd output
PierreRochard Apr 1, 2019
cd0c354
refactor handling of bitcoind output
PierreRochard Apr 1, 2019
b3d60bf
remove duplicate output line
PierreRochard Apr 1, 2019
3e3038d
hide icon from doc on macos
PierreRochard Apr 1, 2019
70ab22f
Update screenshots
PierreRochard Apr 1, 2019
14fd1a3
change major version
PierreRochard Apr 1, 2019
8eeb57a
refactor conf writing to avoid adding new lines
PierreRochard Apr 1, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refactor handling of bitcoind output
  • Loading branch information
PierreRochard committed Apr 1, 2019
commit cd0c35402e27fc8dadad3053b6ba1d71e0e7733b
6 changes: 0 additions & 6 deletions node_launcher/gui/menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,6 @@ def __init__(self, node_set: NodeSet, system_tray):
node_set=self.node_set,
system_tray=self.system_tray
)
self.node_set.bitcoin.process.readyReadStandardError.connect(
self.bitcoind_output_widget.handle_error
)
self.node_set.bitcoin.process.readyReadStandardOutput.connect(
self.bitcoind_output_widget.handle_output
)
self.bitcoind_output_action = self.addAction('See Bitcoin Output')
self.bitcoind_output_action.triggered.connect(
self.bitcoind_output_widget.show
Expand Down
119 changes: 52 additions & 67 deletions node_launcher/gui/system_tray_widgets/bitcoind_output_widget.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import os
from datetime import datetime, timedelta

import humanize
from PySide2.QtCore import QByteArray, QProcess, QThreadPool, Qt
from PySide2.QtWidgets import QDialog, QTextEdit
from PySide2.QtCore import QProcess, QThreadPool, Qt

from node_launcher.gui.components.grid_layout import QGridLayout
from node_launcher.gui.system_tray_widgets.output_widget import OutputWidget
from node_launcher.node_set import NodeSet


class BitcoindOutputWidget(QDialog):
class BitcoindOutputWidget(OutputWidget):
node_set: NodeSet
process: QProcess

Expand All @@ -18,79 +16,66 @@ def __init__(self, node_set: NodeSet, system_tray):
self.node_set = node_set
self.system_tray = system_tray
self.process = node_set.bitcoin.process
self.setWindowTitle('Bitcoind Output')
self.layout = QGridLayout()

self.threadpool = QThreadPool()
self.process.readyReadStandardError.connect(self.handle_error)
self.process.readyReadStandardOutput.connect(self.handle_output)

self.output = QTextEdit()
self.output.acceptRichText = True
self.setWindowTitle('Bitcoind Output')

self.layout.addWidget(self.output)
self.setLayout(self.layout)
self.threadpool = QThreadPool()

self.old_progress = None
self.old_timestamp = None

self.timestamp_changes = []

def handle_error(self):
output: QByteArray = self.process.readAllStandardError()
message = output.data().decode('utf-8').strip()
self.output.append(message)

def handle_output(self):
output: QByteArray = self.process.readAllStandardOutput()
message = output.data().decode('utf-8').strip()
lines = message.split('\n')
for line in lines:
if 'Bitcoin Core version' in line:
self.system_tray.menu.bitcoind_status_action.setText(
'Bitcoin starting'
)
elif 'Leaving InitialBlockDownload' in line:
self.system_tray.menu.bitcoind_status_action.setText(
'Bitcoin synced'
)
elif 'Shutdown: done' in line:
self.system_tray.menu.bitcoind_status_action.setText(
'Error, please check Bitcoin Output'
)
elif 'UpdateTip' in line:
line_segments = line.split(' ')
timestamp = line_segments[0]
for line_segment in line_segments:
if 'progress' in line_segment:
new_progress = round(float(line_segment.split('=')[-1]), 4)
new_timestamp = datetime.strptime(
timestamp,
'%Y-%m-%dT%H:%M:%SZ'
)
if new_progress != self.old_progress:
if self.old_progress is not None:
change = new_progress - self.old_progress
timestamp_change = new_timestamp - self.old_timestamp
total_left = 1 - new_progress
time_left = ((total_left / change)*timestamp_change).seconds
self.timestamp_changes.append(time_left)
if len(self.timestamp_changes) > 100:
self.timestamp_changes.pop(0)
average_time_left = sum(self.timestamp_changes)/len(self.timestamp_changes)
humanized = humanize.naturaltime(-timedelta(seconds=average_time_left))
self.system_tray.menu.bitcoind_status_action.setText(
f'ETA: {humanized}, {new_progress*100:.2f}% done'
)
else:
if round(new_progress*100) == 100:
continue
self.system_tray.menu.bitcoind_status_action.setText(
f'{new_progress*100:.2f}%'
)
def process_output_line(self, line: str):
if 'Bitcoin Core version' in line:
self.system_tray.menu.bitcoind_status_action.setText(
'Bitcoin starting'
)
elif 'Leaving InitialBlockDownload' in line:
self.system_tray.menu.bitcoind_status_action.setText(
'Bitcoin synced'
)
elif 'Shutdown: done' in line:
self.system_tray.menu.bitcoind_status_action.setText(
'Error, please check Bitcoin Output'
)
elif 'UpdateTip' in line:
line_segments = line.split(' ')
timestamp = line_segments[0]
for line_segment in line_segments:
if 'progress' in line_segment:
new_progress = round(float(line_segment.split('=')[-1]), 4)
new_timestamp = datetime.strptime(
timestamp,
'%Y-%m-%dT%H:%M:%SZ'
)
if new_progress != self.old_progress:
if self.old_progress is not None:
change = new_progress - self.old_progress
timestamp_change = new_timestamp - self.old_timestamp
total_left = 1 - new_progress
time_left = ((total_left / change)*timestamp_change).seconds
self.timestamp_changes.append(time_left)
if len(self.timestamp_changes) > 100:
self.timestamp_changes.pop(0)
average_time_left = sum(self.timestamp_changes)/len(self.timestamp_changes)
humanized = humanize.naturaltime(-timedelta(seconds=average_time_left))
self.system_tray.menu.bitcoind_status_action.setText(
f'ETA: {humanized}, {new_progress*100:.2f}% done'
)
else:
if round(new_progress*100) == 100:
continue
self.system_tray.menu.bitcoind_status_action.setText(
f'{new_progress*100:.2f}%'
)

self.old_progress = new_progress
self.old_timestamp = new_timestamp
self.old_progress = new_progress
self.old_timestamp = new_timestamp

self.output.append(line)

def show(self):
self.showMaximized()
Expand Down
115 changes: 49 additions & 66 deletions node_launcher/gui/system_tray_widgets/lnd_output_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@
# noinspection PyPackageRequirements
from grpc._channel import _Rendezvous
import humanize
from PySide2.QtCore import QByteArray, QThreadPool, QProcess, Qt, QTimer
from PySide2.QtWidgets import QDialog, QTextEdit
from PySide2.QtCore import QThreadPool, Qt, QTimer

from node_launcher.constants import keyring
from node_launcher.gui.components.grid_layout import QGridLayout
from node_launcher.gui.components.thread_worker import Worker
from node_launcher.gui.system_tray_widgets.output_widget import OutputWidget
from node_launcher.logging import log
Expand All @@ -22,30 +20,61 @@ def __init__(self, node_set: NodeSet, system_tray):
self.node_set = node_set
self.system_tray = system_tray
self.process = node_set.lnd.process
self.process.readyReadStandardError.connect(
self.handle_error
)
self.process.readyReadStandardOutput.connect(
self.handle_output
)
self.process.readyReadStandardError.connect(self.handle_error)
self.process.readyReadStandardOutput.connect(self.handle_output)
self.setWindowTitle('LND Output')
self.layout = QGridLayout()

self.threadpool = QThreadPool()

self.output = QTextEdit()
self.output.acceptRichText = True

self.layout.addWidget(self.output)
self.setLayout(self.layout)

self.old_height = None
self.old_timestamp = None

def handle_error(self):
output: QByteArray = self.process.readAllStandardError()
message = output.data().decode('utf-8').strip()
self.output.append(message)
def process_output_line(self, line: str):
self.output.append(line)
if 'Active chain: Bitcoin' in line:
self.system_tray.menu.lnd_status_action.setText(
'LND starting'
)
elif 'Waiting for wallet encryption password' in line:
self.system_tray.menu.lnd_status_action.setText(
'LND unlocking wallet'
)
QTimer.singleShot(100, self.auto_unlock_wallet)
elif 'Shutdown complete' in line:
QTimer.singleShot(3000, self.process.start)
elif 'Unable to synchronize wallet to chain' in line:
self.process.terminate()
QTimer.singleShot(3000, self.process.start)
elif 'LightningWallet opened' in line:
self.system_tray.set_blue()
self.system_tray.menu.lnd_status_action.setText(
'LND syncing with network'
)
elif 'Starting HTLC Switch' in line:
self.system_tray.set_green()
self.system_tray.menu.lnd_status_action.setText(
'LND synced'
)
elif 'Caught up to height' in line:
new_height = int(line.split(' ')[-1])
timestamp = line.split('[INF]')[0].strip()
new_timestamp = datetime.strptime(
timestamp,
'%Y-%m-%d %H:%M:%S.%f'
)
if self.old_height is not None:
change = new_height - self.old_height
timestamp_change = new_timestamp - self.old_timestamp
total_left = 600000 - new_height
time_left = (total_left / change)*timestamp_change
humanized = humanize.naturaltime(-time_left)
self.system_tray.menu.lnd_status_action.setText(
f'ETA: {humanized}, caught up to height {new_height}'
)

self.old_height = new_height
self.old_timestamp = new_timestamp


@staticmethod
def unlock_wallet(lnd, progress_callback, password: str):
Expand Down Expand Up @@ -165,52 +194,6 @@ def auto_unlock_wallet(self):
worker.signals.result.connect(self.handle_unlock_wallet)
self.threadpool.start(worker)

def process_output_line(self, line: str):
self.output.append(line)
if 'Active chain: Bitcoin' in line:
self.system_tray.menu.lnd_status_action.setText(
'LND starting'
)
elif 'Waiting for wallet encryption password' in line:
self.system_tray.menu.lnd_status_action.setText(
'LND unlocking wallet'
)
QTimer.singleShot(100, self.auto_unlock_wallet)
elif 'Shutdown complete' in line:
QTimer.singleShot(3000, self.process.start)
elif 'Unable to synchronize wallet to chain' in line:
self.process.terminate()
QTimer.singleShot(3000, self.process.start)
elif 'LightningWallet opened' in line:
self.system_tray.set_blue()
self.system_tray.menu.lnd_status_action.setText(
'LND syncing with network'
)
elif 'Starting HTLC Switch' in line:
self.system_tray.set_green()
self.system_tray.menu.lnd_status_action.setText(
'LND synced'
)
elif 'Caught up to height' in line:
new_height = int(line.split(' ')[-1])
timestamp = line.split('[INF]')[0].strip()
new_timestamp = datetime.strptime(
timestamp,
'%Y-%m-%d %H:%M:%S.%f'
)
if self.old_height is not None:
change = new_height - self.old_height
timestamp_change = new_timestamp - self.old_timestamp
total_left = 600000 - new_height
time_left = (total_left / change)*timestamp_change
humanized = humanize.naturaltime(-time_left)
self.system_tray.menu.lnd_status_action.setText(
f'ETA: {humanized}, caught up to height {new_height}'
)

self.old_height = new_height
self.old_timestamp = new_timestamp

def show(self):
self.showMaximized()
self.raise_()
Expand Down
15 changes: 14 additions & 1 deletion node_launcher/gui/system_tray_widgets/output_widget.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from PySide2.QtCore import QByteArray, QProcess
from PySide2.QtWidgets import QDialog
from PySide2.QtWidgets import QDialog, QGridLayout, QTextEdit

from node_launcher.node_set import NodeSet

Expand All @@ -10,9 +10,22 @@ class OutputWidget(QDialog):

def __init__(self):
super().__init__()
self.layout = QGridLayout()
self.output = QTextEdit()
self.output.setReadOnly(True)
self.output.acceptRichText = True
self.output.document().setMaximumBlockCount(1000)
self.layout.addWidget(self.output)
self.setLayout(self.layout)

def handle_output(self):
while self.process.canReadLine():
line_bytes: QByteArray = self.process.readLine()
line_str = line_bytes.data().decode('utf-8').strip()
self.output.append(line_str)
self.process_output_line(line_str)

def handle_error(self):
output: QByteArray = self.process.readAllStandardError()
message = output.data().decode('utf-8').strip()
self.output.append(message)