URI: 
       tcrash_reporter.py - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
       tcrash_reporter.py (6768B)
       ---
            1 import sys
            2 import json
            3 
            4 from aiohttp.client_exceptions import ClientError
            5 from kivy import base, utils
            6 from kivy.clock import Clock
            7 from kivy.core.window import Window
            8 from kivy.factory import Factory
            9 from kivy.lang import Builder
           10 from kivy.uix.label import Label
           11 from kivy.utils import platform
           12 
           13 from electrum.gui.kivy.i18n import _
           14 
           15 from electrum.base_crash_reporter import BaseCrashReporter
           16 from electrum.logging import Logger
           17 
           18 
           19 Builder.load_string('''
           20 <CrashReporter@Popup>
           21     BoxLayout:
           22         orientation: 'vertical'
           23         Label:
           24             id: crash_message
           25             text_size: root.width, None
           26             size: self.texture_size
           27             size_hint: None, None
           28         Label:
           29             id: request_help_message
           30             text_size: root.width*.95, None
           31             size: self.texture_size
           32             size_hint: None, None
           33         BoxLayout:
           34             size_hint: 1, 0.1
           35         Button:
           36             text: 'Show report contents'
           37             height: '48dp'
           38             size_hint: 1, None
           39             on_release: root.show_contents()
           40         BoxLayout:
           41             size_hint: 1, 0.1
           42         Label:
           43             id: describe_error_message
           44             text_size: root.width, None
           45             size: self.texture_size
           46             size_hint: None, None
           47         TextInput:
           48             id: user_message
           49             size_hint: 1, 0.3
           50         BoxLayout:
           51             size_hint: 1, 0.7
           52         BoxLayout:
           53             size_hint: 1, None
           54             height: '48dp'
           55             orientation: 'horizontal'
           56             Button:
           57                 height: '48dp'
           58                 text: 'Send'
           59                 on_release: root.send_report()
           60             Button:
           61                 text: 'Never'
           62                 on_release: root.show_never()
           63             Button:
           64                 text: 'Not now'
           65                 on_release: root.dismiss()
           66 
           67 <CrashReportDetails@Popup>
           68     BoxLayout:
           69         orientation: 'vertical'
           70         ScrollView:
           71             do_scroll_x: False
           72             Label:
           73                 id: contents
           74                 text_size: root.width*.9, None
           75                 size: self.texture_size
           76                 size_hint: None, None
           77         Button:
           78             text: 'Close'
           79             height: '48dp'
           80             size_hint: 1, None
           81             on_release: root.dismiss()
           82 ''')
           83 
           84 
           85 class CrashReporter(BaseCrashReporter, Factory.Popup):
           86     issue_template = """[b]Traceback[/b]
           87 
           88 [i]{traceback}[/i]
           89 
           90 
           91 [b]Additional information[/b]
           92  * Electrum version: {app_version}
           93  * Operating system: {os}
           94  * Wallet type: {wallet_type}
           95  * Locale: {locale}
           96         """
           97 
           98     def __init__(self, main_window, exctype, value, tb):
           99         BaseCrashReporter.__init__(self, exctype, value, tb)
          100         Factory.Popup.__init__(self)
          101         self.main_window = main_window
          102         self.title = BaseCrashReporter.CRASH_TITLE
          103         self.title_size = "24sp"
          104         self.ids.crash_message.text = BaseCrashReporter.CRASH_MESSAGE
          105         self.ids.request_help_message.text = BaseCrashReporter.REQUEST_HELP_MESSAGE
          106         self.ids.describe_error_message.text = BaseCrashReporter.DESCRIBE_ERROR_MESSAGE
          107 
          108     def show_contents(self):
          109         details = CrashReportDetails(self.get_report_string())
          110         details.open()
          111 
          112     def show_popup(self, title, content):
          113         popup = Factory.Popup(title=title,
          114                               content=Label(text=content, text_size=(Window.size[0] * 3/4, None)),
          115                               size_hint=(3/4, 3/4))
          116         popup.open()
          117 
          118     def send_report(self):
          119         try:
          120             loop = self.main_window.network.asyncio_loop
          121             proxy = self.main_window.network.proxy
          122             # FIXME network request in GUI thread...
          123             response = json.loads(BaseCrashReporter.send_report(self, loop, proxy,
          124                                                                 "/crash.json", timeout=10))
          125         except (ValueError, ClientError) as e:
          126             self.logger.warning(f"Error sending crash report. exc={e!r}")
          127             self.show_popup(_('Unable to send report'), _("Please check your network connection."))
          128         else:
          129             self.show_popup(_('Report sent'), response["text"])
          130             location = response["location"]
          131             if location:
          132                 self.logger.info(f"Crash report sent. location={location!r}")
          133                 self.open_url(location)
          134         self.dismiss()
          135 
          136     def on_dismiss(self):
          137         self.main_window.on_wizard_aborted()
          138 
          139     def open_url(self, url):
          140         if platform != 'android':
          141             return
          142         from jnius import autoclass, cast
          143         String = autoclass("java.lang.String")
          144         url = String(url)
          145         PythonActivity = autoclass('org.kivy.android.PythonActivity')
          146         activity = PythonActivity.mActivity
          147         Intent = autoclass('android.content.Intent')
          148         Uri = autoclass('android.net.Uri')
          149         browserIntent = Intent()
          150         # This line crashes the app:
          151         # browserIntent.setAction(Intent.ACTION_VIEW)
          152         # Luckily we don't need it because the OS is smart enough to recognize the URL
          153         browserIntent.setData(Uri.parse(url))
          154         currentActivity = cast('android.app.Activity', activity)
          155         currentActivity.startActivity(browserIntent)
          156 
          157     def show_never(self):
          158         self.main_window.electrum_config.set_key(BaseCrashReporter.config_key, False)
          159         self.dismiss()
          160 
          161     def get_user_description(self):
          162         return self.ids.user_message.text
          163 
          164     def get_wallet_type(self):
          165         return self.main_window.wallet.wallet_type
          166 
          167 
          168 class CrashReportDetails(Factory.Popup):
          169     def __init__(self, text):
          170         Factory.Popup.__init__(self)
          171         self.title = "Report Details"
          172         self.ids.contents.text = text
          173         print(text)
          174 
          175 
          176 class ExceptionHook(base.ExceptionHandler, Logger):
          177     def __init__(self, main_window):
          178         base.ExceptionHandler.__init__(self)
          179         Logger.__init__(self)
          180         self.main_window = main_window
          181         if not main_window.electrum_config.get(BaseCrashReporter.config_key, default=True):
          182             return
          183         # For exceptions in Kivy:
          184         base.ExceptionManager.add_handler(self)
          185         # For everything else:
          186         sys.excepthook = lambda exctype, value, tb: self.handle_exception(value)
          187 
          188     def handle_exception(self, _inst):
          189         exc_info = sys.exc_info()
          190         self.logger.error('exception caught by crash reporter', exc_info=exc_info)
          191         # Check if this is an exception from within the exception handler:
          192         import traceback
          193         for item in traceback.extract_tb(exc_info[2]):
          194             if item.filename.endswith("crash_reporter.py"):
          195                 return
          196         e = CrashReporter(self.main_window, *exc_info)
          197         # Open in main thread:
          198         Clock.schedule_once(lambda _: e.open(), 0)
          199         return base.ExceptionManager.PASS