Beispiel #1
0
class WebUI(BaseWebUI):
    def __init__(self, app, hub, debug=False):
        BaseWebUI.__init__(self, "index.html", app, hub, debug)
        self.html = index.html

        self.agent = '%s v%s' % (USER_AGENT, '.'.join(str(v) for v in VERSION))
        log("Starting [%s]..." % self.agent, LEVEL_INFO)

        # Setup the system tray icon
        if sys.platform == 'darwin':
            tray_icon = 'ombre_16x16.png'
        elif sys.platform == "win32":
            tray_icon = 'ombre_16x16.png'
        else:
            tray_icon = 'ombre_32x32.png'

        self.trayIcon = QSystemTrayIcon(self._getQIcon(tray_icon))
        self.trayIcon.setToolTip(tray_icon_tooltip)

        # Setup the tray icon context menu
        self.trayMenu = QMenu()

        self.showAppAction = QAction('&Show %s' % APP_NAME, self)
        f = self.showAppAction.font()
        f.setBold(True)
        self.showAppAction.setFont(f)
        self.trayMenu.addAction(self.showAppAction)

        self.aboutAction = QAction('&About...', self)
        self.trayMenu.addAction(self.aboutAction)

        self.trayMenu.addSeparator()
        self.exitAction = QAction('&Exit', self)
        self.trayMenu.addAction(self.exitAction)
        # Add menu to tray icon
        self.trayIcon.setContextMenu(self.trayMenu)

        # connect signals
        self.trayIcon.activated.connect(self._handleTrayIconActivate)
        self.exitAction.triggered.connect(self.handleExitAction)
        self.aboutAction.triggered.connect(self.handleAboutAction)
        self.showAppAction.triggered.connect(self._handleShowAppAction)
        self.app.aboutToQuit.connect(self._handleAboutToQuit)

        # Setup notification support
        self.system_tray_running_notified = False
        self.notifier = Notify(APP_NAME)
        self.trayIcon.show()

    def run(self):
        # load user's pool list
        # load_pools(self.app.property("AppPath"))

        self.view.loadFinished.connect(self._load_finished)
        #         self.view.load(qt_core.QUrl(self.url))
        self.view.setHtml(index.html, qt_core.QUrl(self.url))

        self.resetWindowSize()
        self.center()

        self.timer = QTimer(self)
        self.timer.timeout.connect(self._updateHashRate)
        self.timer.start(2000)

        self.wait(1)

        self.timer2 = QTimer(self)
        self.timer2.timeout.connect(self._reportError)
        self.timer2.start(2000)

        self.trayIcon.show()
        self.show()

    def closeEvent(self, event):
        """ Override QT close event
        """
        event.ignore()
        self.hide()
        if not self.system_tray_running_notified:
            self.notify("%s is still running at system tray." % APP_NAME,
                        "Running Status")
            self.system_tray_running_notified = True

    def resetWindowSize(self):
        ws = qt_core.QSize(
            WINDOW_WIDTH, HEAD_ROW_HEIGHT + POOL_ROW_HEIGHT *
            (len([p
                  for p in self.hub.pools.all_pools if not p['is_hidden']])) +
            BOTTOM_MARGIN)
        self.setFixedSize(ws)

    def _getQIcon(self, icon_file):
        _icon_path = os.path.join(self.app.property("ResPath"), 'icons',
                                  icon_file)
        return QIcon(_icon_path)

    def _handleTrayIconActivate(self, reason):
        if reason == QSystemTrayIcon.DoubleClick:
            self.showNormal()
            self.activateWindow()

    def handleExitAction(self, show_confirmation=False):
        reply = QMessageBox.No
        if show_confirmation:
            reply = QMessageBox.question(self, 'Exit %s?' % APP_NAME,
                                         "Are you sure to exit %s?" % APP_NAME,
                                         QMessageBox.Yes, QMessageBox.No)
        if not show_confirmation or reply == QMessageBox.Yes:
            self.trayIcon.hide()
            QTimer.singleShot(250, self.app.quit)

    def _handleShowAppAction(self):
        self.showNormal()
        self.activateWindow()

    def handleAboutAction(self):
        self.showNormal()
        self.about()

    def _reportError(self):
        for pool_info in self.hub.pools.all_pools:
            if 'error' in pool_info:
                if pool_info['error'] is not None:
                    self.hub.report_error(pool_info['id'], pool_info['error'])
                else:
                    self.hub.report_error(pool_info['id'], 'ERROR_END')
                    pool_info.pop("error", None)

    def _updateHashRate(self):
        _sum_hashrates = 0.
        for pool_info in self.hub.pools.all_pools:
            _json = {'pool_id': pool_info['id']}
            hash_rates = pool_info[
                'hash_report'] if 'hash_report' in pool_info else {}
            if len(hash_rates) > 0:
                _hash_rates = dict(hash_rates)
                _total_hash_rate = reduce(
                    lambda x, y: x + y, [_hash_rates[k] for k in _hash_rates])
                _json['hash_rate'] = _total_hash_rate
                _sum_hashrates += _total_hash_rate
                pool_info['total_hashrate'] = _total_hash_rate
            else:
                _json['hash_rate'] = 0.0
            # reset hashrate
            if 'hash_report' in pool_info and 'thr_list' in pool_info:
                if pool_info['thr_list'] is not None:
                    for thr in pool_info['thr_list']:
                        pool_info['hash_report'].update(
                            {'%d' % thr._thr_id: 0.0})

            work_report = pool_info[
                'work_report'] if 'work_report' in pool_info else {}
            if 'work_submited' in work_report and work_report[
                    'work_submited'] > 0:
                _json['shares_good'] = work_report[
                    'work_accepted'] if 'work_accepted' in work_report else 0
                _json['shares_total'] = work_report['work_submited']
                _json['shares_pct'] = "%.2f%%" % (
                    _json['shares_good'] * 100.0 / _json['shares_total'], )
            else:
                _json['shares_good'] = 0
                _json['shares_total'] = 0
                _json['shares_pct'] = "0.00%"

            if 'difficulty' in work_report:
                _json['difficulty'] = "%.f" % work_report['difficulty']
            else:
                _json['difficulty'] = "0"

            self.hub.update_hashrate(json.dumps(_json))

        self.trayIcon.setToolTip(
            "%s\nHashrate: %s" %
            (tray_icon_tooltip, human_readable_hashrate(_sum_hashrates)))

    def _load_finished(self):
        #This is the actual context/frame a webpage is running in.
        # Other frames could include iframes or such.
        main_page = self.view.page()
        main_frame = main_page.mainFrame()
        # ATTENTION here's the magic that sets a bridge between Python to HTML
        main_frame.addToJavaScriptWindowObject("app_hub", self.hub)

        if self.is_first_load:  ## Avoid re-settings on page reload (if happened)
            change_setting = main_page.settings().setAttribute
            settings = web_core.QWebSettings
            change_setting(settings.DeveloperExtrasEnabled, self.debug)
            change_setting(settings.LocalStorageEnabled, True)
            change_setting(settings.OfflineStorageDatabaseEnabled, True)
            change_setting(settings.OfflineWebApplicationCacheEnabled, True)
            change_setting(settings.JavascriptCanOpenWindows, True)
            change_setting(settings.PluginsEnabled, False)

            # Show web inspector if debug on
            if self.debug:
                self.inspector = web_core.QWebInspector()
                self.inspector.setPage(self.view.page())
                self.inspector.show()
        #Tell the HTML side, we are open for business
        main_frame.evaluateJavaScript("app_ready()")
        # send pool list to HTML for rendering
        self.hub.create_pool_list()
        # Resize main window to fit web content (avoid scroll bars showed)
        main_page.setViewportSize(main_frame.contentsSize())
        #self.setFixedSize(860, 360)

        # resume mining jobs
        for p in self.hub.pools.all_pools:
            if 'is_mining' in p and p['is_mining']:
                self.hub.start_stop_mining(p['id'])

        self.is_first_load = False

    def _handleAboutToQuit(self):
        log("%s is about to quit..." % APP_NAME, LEVEL_INFO)
        for pool_info in self.hub.pools.all_pools:
            if not 'thr_list' in pool_info or pool_info['thr_list'] is None:
                pool_info['is_mining'] = False
            else:
                # shut down threads
                for thr in pool_info['thr_list']:
                    thr.shutdown()
                    thr.join()
                # shut down RPC client
                pool_info['rpc'].shutdown()
                pool_info['rpc'].join()
                pool_info[
                    'is_mining'] = True  # save mining status to resume on next start

        if manager: manager.shutdown()
        # save pool list
        self.hub.pools.save_all()

    def notify(self, message, title="", icon=None, msg_type=None):
        if self.notifier.notifier is not None:
            self.notifier.notify(title, message, icon)
        else:
            self.showMessage(message, title, msg_type)

    def showMessage(self, message, title="", msg_type=None, timeout=2000):
        """Displays 'message' through the tray icon's showMessage function,
        with title 'title'. 'type' is one of the enumerations of
        'common.MessageTypes'.
        """
        if msg_type is None or msg_type == MSG_TYPE_INFO:
            icon = QSystemTrayIcon.Information

        elif msg_type == MSG_TYPE_WARNING:
            icon = QSystemTrayIcon.Warning

        elif msg_type == MSG_TYPE_CRITICAL:
            icon = QSystemTrayIcon.Critical

        title = "%s - %s" % (APP_NAME, title) if title else APP_NAME
        self.trayIcon.showMessage(title, message, icon, timeout)

    def about(self):
        QMessageBox.about(self, "About", \
            u"%s <br><br>Copyright© 2017 - Sumokoin Projects<br><br>\
            <b>www.sumokoin.org</b>"                                     % self.agent)

    def wait(self, timeout=1):
        for _ in range(timeout * 10):
            sleep(0.1)
            self.app.processEvents()