URI: 
       tqt.py - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
       tqt.py (4293B)
       ---
            1 from functools import partial
            2 import zlib
            3 import json
            4 from io import BytesIO
            5 import sys
            6 import platform
            7 from typing import TYPE_CHECKING
            8 
            9 from PyQt5.QtWidgets import (QComboBox, QGridLayout, QLabel, QPushButton)
           10 
           11 from electrum.plugin import BasePlugin, hook
           12 from electrum.gui.qt.util import WaitingDialog, EnterButton, WindowModalDialog, read_QIcon
           13 from electrum.i18n import _
           14 from electrum.logging import get_logger
           15 
           16 if TYPE_CHECKING:
           17     from electrum.gui.qt.transaction_dialog import TxDialog
           18 
           19 
           20 _logger = get_logger(__name__)
           21 
           22 
           23 try:
           24     import amodem.audio
           25     import amodem.main
           26     import amodem.config
           27     _logger.info('Audio MODEM is available.')
           28     amodem.log.addHandler(amodem.logging.StreamHandler(sys.stderr))
           29     amodem.log.setLevel(amodem.logging.INFO)
           30 except ImportError:
           31     amodem = None
           32     _logger.info('Audio MODEM is not found.')
           33 
           34 
           35 class Plugin(BasePlugin):
           36 
           37     def __init__(self, parent, config, name):
           38         BasePlugin.__init__(self, parent, config, name)
           39         if self.is_available():
           40             self.modem_config = amodem.config.slowest()
           41             self.library_name = {
           42                 'Linux': 'libportaudio.so'
           43             }[platform.system()]
           44 
           45     def is_available(self):
           46         return amodem is not None
           47 
           48     def requires_settings(self):
           49         return True
           50 
           51     def settings_widget(self, window):
           52         return EnterButton(_('Settings'), partial(self.settings_dialog, window))
           53 
           54     def settings_dialog(self, window):
           55         d = WindowModalDialog(window, _("Audio Modem Settings"))
           56 
           57         layout = QGridLayout(d)
           58         layout.addWidget(QLabel(_('Bit rate [kbps]: ')), 0, 0)
           59 
           60         bitrates = list(sorted(amodem.config.bitrates.keys()))
           61 
           62         def _index_changed(index):
           63             bitrate = bitrates[index]
           64             self.modem_config = amodem.config.bitrates[bitrate]
           65 
           66         combo = QComboBox()
           67         combo.addItems([str(x) for x in bitrates])
           68         combo.currentIndexChanged.connect(_index_changed)
           69         layout.addWidget(combo, 0, 1)
           70 
           71         ok_button = QPushButton(_("OK"))
           72         ok_button.clicked.connect(d.accept)
           73         layout.addWidget(ok_button, 1, 1)
           74 
           75         return bool(d.exec_())
           76 
           77     @hook
           78     def transaction_dialog(self, dialog: 'TxDialog'):
           79         b = QPushButton()
           80         b.setIcon(read_QIcon("speaker.png"))
           81 
           82         def handler():
           83             blob = dialog.tx.serialize()
           84             self._send(parent=dialog, blob=blob)
           85         b.clicked.connect(handler)
           86         dialog.sharing_buttons.insert(-1, b)
           87 
           88     @hook
           89     def scan_text_edit(self, parent):
           90         parent.addButton('microphone.png', partial(self._recv, parent),
           91                          _("Read from microphone"))
           92 
           93     @hook
           94     def show_text_edit(self, parent):
           95         def handler():
           96             blob = str(parent.toPlainText())
           97             self._send(parent=parent, blob=blob)
           98         parent.addButton('speaker.png', handler, _("Send to speaker"))
           99 
          100     def _audio_interface(self):
          101         interface = amodem.audio.Interface(config=self.modem_config)
          102         return interface.load(self.library_name)
          103 
          104     def _send(self, parent, blob):
          105         def sender_thread():
          106             with self._audio_interface() as interface:
          107                 src = BytesIO(blob)
          108                 dst = interface.player()
          109                 amodem.main.send(config=self.modem_config, src=src, dst=dst)
          110 
          111         _logger.info(f'Sending: {repr(blob)}')
          112         blob = zlib.compress(blob.encode('ascii'))
          113 
          114         kbps = self.modem_config.modem_bps / 1e3
          115         msg = 'Sending to Audio MODEM ({0:.1f} kbps)...'.format(kbps)
          116         WaitingDialog(parent, msg, sender_thread)
          117 
          118     def _recv(self, parent):
          119         def receiver_thread():
          120             with self._audio_interface() as interface:
          121                 src = interface.recorder()
          122                 dst = BytesIO()
          123                 amodem.main.recv(config=self.modem_config, src=src, dst=dst)
          124                 return dst.getvalue()
          125 
          126         def on_finished(blob):
          127             if blob:
          128                 blob = zlib.decompress(blob).decode('ascii')
          129                 _logger.info(f'Received: {repr(blob)}')
          130                 parent.setText(blob)
          131 
          132         kbps = self.modem_config.modem_bps / 1e3
          133         msg = 'Receiving from Audio MODEM ({0:.1f} kbps)...'.format(kbps)
          134         WaitingDialog(parent, msg, receiver_thread, on_finished)