import logging import os import signal import sys import threading from pathlib import Path from subprocess import Popen import wx from wx.lib.pubsub import pub from wx.lib.newevent import NewCommandEvent import nuxhash.settings from nuxhash.devices.nvidia import enumerate_devices as nvidia_devices from nuxhash.download.downloads import make_miners from nuxhash.gui.about import AboutScreen from nuxhash.gui.benchmarks import BenchmarksScreen from nuxhash.gui.mining import MiningScreen from nuxhash.gui.settings import SettingsScreen PADDING_PX = 10 CONFIG_DIR = nuxhash.settings.DEFAULT_CONFIGDIR ICON_PATH = Path(os.path.dirname(__file__))/'icons'/'nuxhash.svg' PubSubSendEvent, EVT_PUBSUB = NewCommandEvent() class MainWindow(wx.Frame): def __init__(self, parent, *args, **kwargs): wx.Frame.__init__(self, parent, *args, **kwargs) self.SetIcon(wx.Icon(wx.IconLocation(str(ICON_PATH)))) self.SetSizeHints(minW=500, minH=500) self._Devices = self._ProbeDevices() self.Bind(wx.EVT_CLOSE, self.OnClose) self.Bind(EVT_PUBSUB, self.OnPubSend) # Create notebook and its pages. notebook = wx.Notebook(self) notebook.AddPage( MiningScreen(notebook, devices=self._Devices), text='Mining') notebook.AddPage( BenchmarksScreen(notebook, devices=self._Devices), text='Benchmarks') notebook.AddPage( SettingsScreen(notebook), text='Settings') notebook.AddPage( AboutScreen(notebook), text='About') # Check miner downloads. pub.subscribe(self._OnDownloadProgress, 'download.progress') self._DlThread = self._DlProgress = None self._DownloadMiners() # Read user data. pub.subscribe(self._OnSettings, 'data.settings') pub.subscribe(self._OnBenchmarks, 'data.benchmarks') loaded_settings = nuxhash.settings.load_settings(CONFIG_DIR) if loaded_settings == nuxhash.settings.DEFAULT_SETTINGS: self._FirstRun() pub.sendMessage('data.settings', settings=loaded_settings) benchmarks = nuxhash.settings.load_benchmarks(CONFIG_DIR, self._Devices) pub.sendMessage('data.benchmarks', benchmarks=benchmarks) def _DownloadMiners(self): to_download = [item for item in make_miners(CONFIG_DIR) if not item.verify()] if len(to_download) > 0: self._DlThread = DownloadThread(self, to_download) self._DlThread.start() self._DlProgress = wx.ProgressDialog('nuxhash', '', parent=self) self._DlProgress.ShowModal() self._DlProgress.Destroy() def _FirstRun(self): dialog = wx.MessageDialog( self, 'Welcome to nuxhash!\n\nSet your NiceHash wallet address and run ' 'some benchmarks, and then you can start mining.', style=wx.OK) dialog.ShowModal() def _OnDownloadProgress(self, progress, message): if self._DlThread: if progress > 0.99: # Avoid precision errors. self._DlProgress.Update(100.0) self._DlThread.join() self._DlThread = None else: self._DlProgress.Update(progress*100, newmsg=message) def OnClose(self, event): logging.info('Closing up!') pub.sendMessage('app.close') event.Skip() def OnPubSend(self, event): pub.sendMessage(event.topic, **event.data) def _OnSettings(self, settings): logging.info('Saving user settings.') nuxhash.settings.save_settings(CONFIG_DIR, settings) def _OnBenchmarks(self, benchmarks): logging.info('Saving user benchmarks.') nuxhash.settings.save_benchmarks(CONFIG_DIR, benchmarks) def _ProbeDevices(self): return nvidia_devices() class DownloadThread(threading.Thread): def __init__(self, frame, downloads, *args, **kwargs): threading.Thread.__init__(self, *args, **kwargs) self._frame = frame self._downloads = downloads def run(self): n_downloads = len(self._downloads) for i, item in enumerate(self._downloads): sendMessage( self._frame, 'download.progress', progress=i/n_downloads, message=f'Downloading {item.name}') item.download() sendMessage( self._frame, 'download.progress', progress=(i+1)/n_downloads, message='') def sendMessage(window, topic, **data): """Like pub.sendMessage(), except safely callable by other threads.""" wx.PostEvent(window, PubSubSendEvent(topic=topic, data=data, id=wx.ID_ANY)) def main(): sys.excepthook = excepthook app = wx.App(False) frame = MainWindow(None, title='nuxhash') frame.Show() app.MainLoop() def excepthook(type, value, traceback): sys.__excepthook__(type, value, traceback) # Restart the app and kill all miners. Popen(sys.argv, preexec_fn=os.setpgrp) os.killpg(os.getpgid(0), signal.SIGKILL) # (This also kills us.)