示例#1
0
def check_version():
    from dashboard import version
    current_version = version()
    with yaspin(
            text=f"Checking for updates. Running version: {current_version}",
            color="green") as spinner:

        url = 'https://raw.githubusercontent.com/pxsocs/warden_terminal/master/version.txt'
        try:
            remote_version = tor_request(url).text
        except Exception:
            print(yellow("  [!] Could not reach GitHub to check for upgrades"))
            return

        if str(remote_version).strip() == str(current_version).strip():
            spinner.ok("✅ ")
            spinner.write(success("    You are running latest version"))
        else:
            spinner.fail("💥 ")
            spinner.write(
                warning(f"    Update available - version: {remote_version}"))
            import click
            if click.confirm(warning('    [?] Would you like to upgrade?'),
                             default=False):
                print(" ---------------------------------------")
                print(yellow("Upgrading from GitHub: ")),
                import subprocess
                subprocess.run("git fetch --all", shell=True)
                subprocess.run("git reset --hard origin/master", shell=True)
                print(yellow("Installing Python Package Requirements")),
                subprocess.run("pip3 install -r requirements.txt", shell=True)
                print(" ---------------------------------------")
                print(success("  ✅ Done Upgrading"))

        print("")
示例#2
0
def create_tor():
    from ansi_management import (warning, success, error, info, clear_screen,
                                 bold, muted, yellow, blue)
    from config import Config
    # ----------------------------------------------
    #                 Test Tor
    # ----------------------------------------------
    with yaspin(text="Testing Tor", color="cyan") as spinner:
        from connections import test_tor
        tor = test_tor()
        if tor['status']:
            logging.info(success("Tor Connected"))
            spinner.ok("✅ ")
            spinner.text = success("    Tor Connected [Success]")
            print("")
            return (tor)
        else:
            logging.error(error("Could not connect to Tor"))
            spinner.fail("💥 ")
            spinner.text = warning("    Tor NOT connected [ERROR]")
            print(error("    Could not connect to Tor."))

            print(
                info(
                    "    [i] If you have a Tor Browser installed try opening (leave it running) and try again."
                ))

            print(
                info("    [i] If you are running Linux try the command: ") +
                yellow('service tor start'))
            print(
                info(
                    "    or download Tor at: https://www.torproject.org/download/"
                ))
            print("")
示例#3
0
def data_large_price():
    from node_warden import load_config
    config = load_config(quiet=True)
    ft_config = config['MAIN']
    font = ft_config.get('large_text_font')
    btc = btc_price_data()
    try:
        btc_price = cleanfloat(btc['DISPLAY']['BTC']['USD']['PRICE'])
    except Exception:
        return (error(' >> Error getting price data. Retrying...'))
    custom_fig = pyfiglet.Figlet(font=font)
    return_fig = custom_fig.renderText('$  ' + jformat(btc_price, 0))
    return_fig = yellow(return_fig)

    chg_str = btc['DISPLAY']['BTC']['USD']['CHANGEPCTDAY']
    chg = cleanfloat(chg_str)
    msg = '\n'

    if chg >= 0:
        msg += success(f'24hr Change: +{chg_str}%\n')
    if chg > 5:
        msg += (info("[NgU] ") + muted(f"Looks like Bitcoin is pumping ") +
                emoji.emojize(":rocket:"))

    if chg < 0:
        msg += error(f'24hr Change: {chg_str}%\n')
    if chg < -5:
        msg += muted(
            f"Bitcoin dropping? Buy the dip!\nTime to stack some sats. ")

    return_fig = muted(return_fig)
    return_fig += msg

    return (return_fig)
示例#4
0
    def check_for_pump(_loop, _data):
        try:
            btc = btc_price_data()
            btc_price = btc['DISPLAY']['BTC']['USD']['PRICE']
            chg_str = btc['DISPLAY']['BTC']['USD']['CHANGEPCTDAY']
            chg = cleanfloat(chg_str)
            if chg > 5:
                logging.info(
                    info("[NgU] ") + muted(f"Looks like Bitcoin is pumping ") +
                    emoji.emojize(":rocket:") + yellow(f' {btc_price}') +
                    success(f' +{chg_str}%'))
            if chg < -5:
                logging.info(
                    info("[NgU] ") + muted(
                        f"Looks like Bitcoin is dropping. Time to stack some sats. "
                    ) + yellow(f' {btc_price}') + error(f' {chg_str}%'))
        except Exception:
            pass

        main_loop.set_alarm_in(300, check_for_pump)
示例#5
0
 def onion_string():
     from utils import pickle_it
     if app.settings['SERVER'].getboolean('onion_server'):
         try:
             pickle_it('save', 'onion_address.pkl',
                       app.tor_service_id + '.onion')
             return (f"""
     {emoji.emojize(':onion:')} Tor Onion server running at:
     {yellow(app.tor_service_id + '.onion')}
                 """)
         except Exception:
             return (yellow("[!] Tor Onion Server Not Running"))
     else:
         return ('')
示例#6
0
def data_random_satoshi():
    from node_warden import load_config
    config = load_config(quiet=True)
    url = config['QUOTES'].get('url')
    try:
        quotes = tor_request(url).json()
    except Exception:
        return (error(' >> Error contacting server. Retrying... '))
    quote = quotes[randrange(len(quotes))]
    return_str = info(f"Satoshi Quotes | Subject: {quote['category']}\n")
    return_str += muted(f"{quote['date']} on {quote['medium']}\n")
    return_str += yellow(f"{quote['text']} \n\n")
    return_str += muted("Source: Nakamoto Institute")
    return (return_str)
示例#7
0
 def close_running_threads(app):
     print("")
     print("")
     print(yellow("[i] Please Wait... Shutting down."))
     # Delete Debug File
     try:
         from config import Config
         os.remove(Config.debug_file)
     except FileNotFoundError:
         pass
     # Clean all messages
     app.message_handler.clean_all()
     # Breaks background jobs
     app.scheduler.shutdown(wait=False)
     goodbye()
     os._exit(1)
示例#8
0
def data_logger():
    from node_warden import debug_file
    try:
        lines = 8
        log_txt = tail(debug_file, lines)
        return_str = []
        for element in log_txt:
            if 'INFO' in element:
                return_str.append(info(element))
            elif 'ERROR' in log_txt:
                return_str.append(error(element))
            elif 'WARN' in log_txt:
                return_str.append(warning(element))
            else:
                return_str.append((element))
        return_str = ''.join(return_str)
    except Exception:
        return yellow('>> Error Loading Log Messages. Retying...')
    return return_str
示例#9
0
def main(debug=False, reloader=False):
    from utils import (create_config, runningInDocker)
    from ansi_management import (warning, success, error, info, clear_screen,
                                 bold, muted, yellow, blue)

    # Make sure current libraries are found in path
    current_path = os.path.abspath(os.path.dirname(__file__))

    # CLS + Welcome
    print("")
    print("")
    print(yellow("Welcome to the WARden <> Launching Application ..."))
    print("")
    print(f"[i] Running from directory: {current_path}")
    print("")

    if runningInDocker():
        print(
            success(
                f"✅ Running inside docker container {emoji.emojize(':whale:')} Getting some James Bartley vibes..."
            ))
        print("")

    app = create_app()
    app.app_context().push()
    app = init_app(app)
    app.app_context().push()

    def close_running_threads(app):
        print("")
        print("")
        print(yellow("[i] Please Wait... Shutting down."))
        # Delete Debug File
        try:
            from config import Config
            os.remove(Config.debug_file)
        except FileNotFoundError:
            pass
        # Clean all messages
        app.message_handler.clean_all()
        # Breaks background jobs
        app.scheduler.shutdown(wait=False)
        goodbye()
        os._exit(1)

    # Register the def above to run at close
    atexit.register(close_running_threads, app)

    print("")
    print(success("✅ WARden Server is Ready... Launch cool ASCII logo!"))
    print("")
    logging.info("Launched WARden Server [Success]")

    def onion_string():
        from utils import pickle_it
        if app.settings['SERVER'].getboolean('onion_server'):
            try:
                pickle_it('save', 'onion_address.pkl',
                          app.tor_service_id + '.onion')
                return (f"""
        {emoji.emojize(':onion:')} Tor Onion server running at:
        {yellow(app.tor_service_id + '.onion')}
                    """)
            except Exception:
                return (yellow("[!] Tor Onion Server Not Running"))
        else:
            return ('')

    def local_network_string():
        host = app.settings['SERVER'].get('host')
        port = str(app.settings['SERVER'].getint('port'))
        if app.runningInDocker:
            return ('')
        else:
            if host == '0.0.0.0':
                return (f"""
      Or through your network at address:
      {yellow('http://')}{yellow(get_local_ip())}{yellow(f':{port}/')}
                """)

    port = app.settings['SERVER'].getint('port')

    # Check if this port is available
    from utils import is_port_in_use
    ports = [5001, 5002, 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010]
    if is_port_in_use(port) is True:
        # Ooops. Port in use... Let's try other ports...
        for p in ports:
            if is_port_in_use(p) is False:
                print(
                    warning(
                        f"[i] Please note that port {str(port)} is in use."))
                print(
                    warning(
                        f"[i] Port was automatically changed to {str(p)} which is free."
                    ))
                # Reassign port
                port = p
                app.settings['SERVER']['port'] = str(port)
                break

    print(
        fg.brightgreen("""
        _   _           __        ___    ____     _
       | |_| |__   ___  \ \      / / \  |  _ \ __| | ___ _ __
       | __| '_ \ / _ \  \ \ /\ / / _ \ | |_) / _` |/ _ \ '_  |
       | |_| | | |  __/   \ V  V / ___ \|  _ < (_| |  __/ | | |
        \__|_| |_|\___|    \_/\_/_/   \_\_| \_\__,_|\___|_| |_|"""))

    print(f"""
                                    {yellow("Powered by NgU technology")} {emoji.emojize(':rocket:')}


           Privacy Focused Portfolio & Bitcoin Address Tracker
    -----------------------------------------------------------------
                          Application Loaded

      Open your browser and navigate to one of these addresses:
      {yellow('http://localhost:' + str(port) + '/')}
      {yellow('http://127.0.0.1:' + str(port) + '/')}
      {local_network_string()}
      {onion_string()}
    ----------------------------------------------------------------
                         CTRL + C to quit server
    ----------------------------------------------------------------

    """)

    app.run(debug=debug,
            threaded=True,
            host=app.settings['SERVER'].get('host'),
            port=port,
            use_reloader=reloader)

    if app.settings['SERVER'].getboolean('onion_server'):
        from tor import stop_hidden_services
        stop_hidden_services(app)
示例#10
0
def check_cryptocompare():
    from utils import pickle_it

    with yaspin(text="Testing price grab from Cryptocompare",
                color="green") as spinner:
        data = {'Response': 'Error', 'Message': None}
        try:
            api_key = pickle_it('load', 'cryptocompare_api.pkl')
            if api_key != 'file not found':
                baseURL = (
                    "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=BTC"
                    + "&tsyms=USD&api_key=" + api_key)
                req = requests.get(baseURL)
                data = req.json()
                btc_price = (data['DISPLAY']['BTC']['USD']['PRICE'])
                spinner.text = (success(f"BTC price is: {btc_price}"))
                spinner.ok("✅ ")
                pickle_it('save', 'cryptocompare_api.pkl', api_key)
                return
            else:
                data = {'Response': 'Error', 'Message': 'No API Key is set'}
        except Exception as e:
            data = {'Response': 'Error', 'Message': str(e)}
            logging.error(data)

        try:
            if data['Response'] == 'Error':
                spinner.color = 'yellow'
                spinner.text = "CryptoCompare Returned an error " + data[
                    'Message']
                # ++++++++++++++++++++++++++
                #  Load Legacy
                # ++++++++++++++++++++++++++
                try:
                    # Let's try to use one of the
                    # legacy api keys stored under cryptocompare_api.keys file
                    # You can add as many as you'd like there
                    filename = 'warden/static/cryptocompare_api.keys'
                    file = open(filename, 'r')
                    for line in file:
                        legacy_key = str(line)

                        spinner.text = (
                            warning(f"Trying different API Keys..."))

                        baseURL = (
                            "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=BTC"
                            + "&tsyms=USD&api_key=" + legacy_key)

                        try:
                            data = None
                            logging.debug(f"Trying API Key {legacy_key}")
                            request = requests.get(baseURL)
                            data = request.json()
                            btc_price = (
                                data['DISPLAY']['BTC']['USD']['PRICE'])
                            spinner.text = (
                                success(f"BTC price is: {btc_price}"))
                            spinner.ok("✅ ")
                            logging.debug(f"API Key {legacy_key} Success")
                            pickle_it('save', 'cryptocompare_api.pkl',
                                      legacy_key)
                            return
                        except Exception as e:
                            logging.debug(f"API Key {legacy_key} ERROR: {e}")
                            logging.debug(
                                f"API Key {legacy_key} Returned: {data}")
                            spinner.text = "Didn't work... Trying another."
                except Exception:
                    pass
                spinner.text = (error("Failed to get API Key - read below."))
                spinner.fail("[!]")
                print(
                    '    -----------------------------------------------------------------'
                )
                print(yellow("    Looks like you need to get an API Key. "))
                print(yellow("    The WARden comes with a shared key that"))
                print(yellow("    eventually gets to the call limit."))
                print(
                    '    -----------------------------------------------------------------'
                )
                print(
                    yellow(
                        '    Go to: https://www.cryptocompare.com/cryptopian/api-keys'
                    ))
                print(
                    yellow(
                        '    To get an API Key. Keys from cryptocompare are free.'
                    ))
                print(
                    yellow(
                        '    [Tip] Get a disposable email to signup and protect privacy.'
                    ))
                print(
                    yellow(
                        '    Services like https://temp-mail.org/en/ work well.'
                    ))

                print(muted("    Current API:"))
                print(f"    {api_key}")
                new_key = input('    Enter new API key (Q to quit): ')
                if new_key == 'Q' or new_key == 'q':
                    exit()
                pickle_it('save', 'cryptocompare_api.pkl', new_key)
                check_cryptocompare()
        except KeyError:
            try:
                btc_price = (data['DISPLAY']['BTC']['USD']['PRICE'])
                spinner.ok("✅ ")
                spinner.write(success(f"BTC price is: {btc_price}"))
                pickle_it('save', 'cryptocompare_api.pkl', api_key)
                return
            except Exception:
                spinner.text = (
                    warning("CryptoCompare Returned an UNKNOWN error"))
                spinner.fail("💥 ")
        return (data)
示例#11
0
                         CTRL + C to quit server
    ----------------------------------------------------------------

    """)

    app.run(debug=debug,
            threaded=True,
            host=app.settings['SERVER'].get('host'),
            port=port,
            use_reloader=reloader)

    if app.settings['SERVER'].getboolean('onion_server'):
        from tor import stop_hidden_services
        stop_hidden_services(app)


if __name__ == '__main__':
    # Run Diagnostic Function
    from ansi_management import yellow
    debug = False
    reloader = False
    if "debug" in sys.argv:
        print("")
        print(yellow("  [i] DEBUG MODE: ON"))
        debug = True
    if "reloader" in sys.argv:
        print("")
        print(yellow("  [i] RELOAD MODE: ON"))
        reloader = True
    main(debug=debug, reloader=reloader)
示例#12
0
def data_mempool():
    from node_warden import load_config
    from node_warden import launch_logger
    launch_logger()

    config = load_config(quiet=True)
    mp_config = config['MEMPOOL']
    url = mp_config.get('url')
    tabs = []

    # Get recommended fees

    mp_fee = tor_request(url + '/api/v1/fees/recommended').json()
    tabs = list(mp_fee.values())
    tabs = [[str(x) + ' sats/Vb' for x in tabs]]
    tabs = tabulate(tabs,
                    headers=["Fastest Fee", "30 min fee", "1 hour fee"],
                    colalign=["center", "center", "center"])
    try:
        block_height = tor_request(url + '/api/blocks/tip/height').json()
    except Exception:
        return (error(f' >> Error getting data from {url}. Retrying...'))
    # Save the latest block height
    saved_block = pickle_it(action='load', filename='block.pkl')
    if (saved_block != block_height) and (
            config['MEMPOOL'].getboolean('block_found_sound')):
        # Block found play sound
        try:
            engine = pyttsx3.init()
            engine.setProperty('rate', 270)
            engine.say(config['MEMPOOL'].get('block_found_txt'))
            engine.runAndWait()
        except Exception:
            pass
        logging.info(
            info('[MEMPOOL] ') +
            success("A new Bitcoin Block was just found. ") +
            yellow("'Tick. Tock. Next block.'"))

    pickle_it(action='save', filename='block.pkl', data=block_height)

    block_txt = success(f' Block Height: {jformat(block_height, 0)}\n\n')
    tabs = block_txt + info(' Mempool Fee Estimates: \n') + tabs

    try:
        mp_blocks = tor_request(url + '/api/blocks').json()
    except Exception:
        return (error(" >> Error getting Mempool data. Retrying..."))

    mp_tabs = []
    gradient_color = 0
    for block in mp_blocks:
        mp_tabs.append([
            time_ago(block['timestamp']),
            jformat(block['height'], 0),
            jformat(block['tx_count'], 0),
            jformat(block['size'], 2, 1000000) + ' MB'
        ])
        gradient_color += 1

    mp_tabs = tabulate(mp_tabs,
                       headers=[" Time", "Height", "Tx Count", "Size"],
                       colalign=["right", "center", "center", "right"])
    tabs += info('\n\n Latest Blocks: \n') + mp_tabs
    tabs += muted(f"\n\n Source: {url}  {success('[Tor Request]')}\n")
    return tabs
示例#13
0
def check_cryptocompare():
    with yaspin(text=f"Testing price grab from Cryptocompare",
                color="green") as spinner:
        config = load_config(True)
        api_key = config['API'].get('cryptocompare')
        # tickers should be in comma sep string format like "BTC,ETH,LTC" and "USD,EUR"
        baseURL = (
            "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=BTC" +
            "&tsyms=USD&api_key=" + api_key)
        try:
            request = tor_request(baseURL)
        except requests.exceptions.ConnectionError:
            spinner.fail("💥 ")
            spinner.write(
                warning("    Connection Error - check internet connection"))
            exit()

        data = request.json()

        try:
            if data['Response'] == 'Error':
                config_file = os.path.join(basedir, 'config.ini')
                spinner.fail("💥 ")
                spinner.write(warning("    CryptoCompare Returned an error"))
                print("    " + data['Message'])
                if data['Message'] == 'You are over your rate limit please upgrade your account!':
                    # First try to get a random API KEY
                    if config['API'].getboolean('random') is not True:
                        print(
                            "    Looks like you are over the API Limit. Will try to generate a random API."
                        )
                        size = 16
                        import binascii
                        random_key = binascii.b2a_hex(os.urandom(size))
                        config['API']['random'] = 'True'
                        config['API']['cryptocompare'] = str(
                            random_key.decode("utf-8"))
                        with open(config_file, 'w') as configfile:
                            config.write(configfile)
                        check_cryptocompare()
                        return

                    print(
                        '    -----------------------------------------------------------------'
                    )
                    print(
                        yellow("    Looks like you need to get an API Key. "))
                    print(
                        yellow("    The WARden comes with a shared key that"))
                    print(yellow("    eventually gets to the call limit."))
                    print(
                        '    -----------------------------------------------------------------'
                    )
                    print(
                        blue(
                            '    Go to: https://www.cryptocompare.com/cryptopian/api-keys'
                        ))
                    print(muted("    Current API:"))
                    print(f"    {api_key}")
                    new_key = input('    Enter new API key (Q to quit): ')
                    if new_key == 'Q' or new_key == 'q':
                        exit()
                    config['API']['cryptocompare'] = new_key
                    with open(config_file, 'w') as configfile:
                        config.write(configfile)
                    check_cryptocompare()
        except KeyError:
            try:
                btc_price = (data['DISPLAY']['BTC']['USD']['PRICE'])
                spinner.ok("✅ ")
                spinner.write(success(f"    BTC price is: {btc_price}"))
                return
            except Exception:
                spinner.fail("💥 ")
                spinner.write(
                    warning("    CryptoCompare Returned an UNKNOWN error"))
                print(data)

        return (data)
示例#14
0
def main(debug=False, reloader=False):
    from utils import (create_config, runningInDocker)
    from ansi_management import (warning, success, error, info, clear_screen, bold,
                                 muted, yellow, blue)

    # Make sure current libraries are found in path
    current_path = os.path.abspath(os.path.dirname(__file__))

    # CLS + Welcome
    print("")
    print("")
    print(yellow("  Welcome to the WARden <> Launching Application ..."))
    print("")
    print(f"  [i] Running from directory: {current_path}")
    print("")

    if runningInDocker():
        print(success(f"✅ Running inside docker container {emoji.emojize(':whale:')} Getting some James Bartley vibes..."))
        print("")

    app = create_app()
    app.app_context().push()
    app = init_app(app)
    app.app_context().push()

    def close_running_threads(app):
        print("")
        print("")
        print(yellow("  [i] Please Wait... Shutting down."))
        # Delete Debug File
        try:
            from config import Config
            os.remove(Config.debug_file)
        except FileNotFoundError:
            pass
        # Clean all messages
        app.message_handler.clean_all()
        # Breaks background jobs
        app.scheduler.shutdown(wait=False)
        print("""
                           Goodbye &
                         Keep Stacking
            """)
        print("")

    # Register the def above to run at close
    atexit.register(close_running_threads, app)

    print("")
    print(success("✅ WARden Server is Ready... Launch cool ASCII logo!"))
    print("")

    def onion_string():
        if app.settings['SERVER'].getboolean('onion_server'):
            return (f"""
      {emoji.emojize(':onion:')} Tor Onion server running at:
      {yellow(app.tor_service_id + '.onion')}
                """)
        else:
            return ('')

    def local_network_string():
        host = app.settings['SERVER'].get('host')
        if app.runningInDocker:
            return ('')
        else:
            if host == '0.0.0.0':
                return (f"""
      Or through your network at address:
      {yellow('http://')}{yellow(get_local_ip())}{yellow(':5000/')}
                """)

    print(
        fg.brightgreen("""
        _   _           __        ___    ____     _
       | |_| |__   ___  \ \      / / \  |  _ \ __| | ___ _ __
       | __| '_ \ / _ \  \ \ /\ / / _ \ | |_) / _` |/ _ \ '_  |
       | |_| | | |  __/   \ V  V / ___ \|  _ < (_| |  __/ | | |
        \__|_| |_|\___|    \_/\_/_/   \_\_| \_\__,_|\___|_| |_|"""))

    print(f"""
                                    {yellow("Powered by NgU technology")} {emoji.emojize(':rocket:')}


           Privacy Focused Portfolio & Bitcoin Address Tracker
    -----------------------------------------------------------------
                          Application Loaded

      Open your browser and navigate to one of these addresses:
      {yellow('http://localhost:5000/')}
      {yellow('http://127.0.0.1:5000/')}
      {local_network_string()}
      {onion_string()}
    ----------------------------------------------------------------
                         CTRL + C to quit server
    ----------------------------------------------------------------

    """)

    app.run(debug=debug,
            threaded=True,
            host=app.settings['SERVER'].get('host'),
            port=app.settings['SERVER'].getint('port'),
            use_reloader=reloader)

    if app.settings['SERVER'].getboolean('onion_server'):
        from tor import stop_hidden_services
        stop_hidden_services(app)
示例#15
0
def main_dashboard(config, tor, spinner):

    try:
        refresh_interval = int(config['MAIN'].get('refresh'))
    except Exception:
        refresh_interval = 5

    running_jobs = {
        'btc': {
            'workers': 0
        },
        'tor': {
            'workers': 0
        },
        'login': {
            'workers': 0
        },
        'mp': {
            'workers': 0
        },
        'logger': {
            'workers': 0
        }
    }

    palette = [('titlebar', 'dark green', ''),
               ('refresh button', 'dark green,bold', ''),
               ('quit button', 'dark green', ''),
               ('getting quote', 'dark blue', ''),
               ('headers', 'white,bold', ''), ('change ', 'dark green', ''),
               ('change negative', 'dark red', '')]

    def exit_on_q(key):
        if key in ('q', 'Q'):
            raise urwid.ExitMainLoop()

    def update_header(layout, message=None, message_type=None):
        # Create Header
        refresh_time = datetime.now().strftime('%H:%M:%S')
        txt = u' WARden Node Edition (Version: ' + version(
        ) + ') | Last Refresh on: ' + refresh_time
        if message:
            txt += ' | ' + message
        header_text = urwid.Text(txt)
        header = urwid.AttrMap(header_text, 'titlebar')
        layout.header = header

    # Draw empty dashboard
    spinner.stop()
    menu = urwid.Text([u'Press (', ('quit button', u'Q'), u') to quit.'])

    # Class to Create URWID box window to receive data
    class Box:
        def __init__(self,
                     loader_text=None,
                     valign='top',
                     top=1,
                     bottom=1,
                     left=1,
                     right=1,
                     height=None):
            self.loader_text = loader_text
            self.valign = valign
            self.top = top
            self.bottom = bottom
            self.left = left
            self.right = right
            self.height = height

            self.text = urwid.Text(self.loader_text)
            self.filler = urwid.Filler(self.text,
                                       valign=self.valign,
                                       top=self.top,
                                       bottom=self.bottom)
            self.v_padding = urwid.Padding(self.filler,
                                           left=self.left,
                                           right=self.right)
            self.line_box = urwid.LineBox(self.v_padding)
            self.box_size = self.height

    # Create the BTC price box
    quote_box_size = len(ast.literal_eval(
        config['CURRENCIES'].get('fx_list'))) + 10
    quote_box = Box(loader_text='Loading Prices...',
                    height=quote_box_size).line_box

    # Create the TOR Box
    tor_box_size = 9
    tor_box = Box(loader_text='Checking Tor Status...',
                  height=tor_box_size).line_box

    # Create user login Box
    login_box_size = 12
    login_box = Box(loader_text='Loading User Logins...',
                    height=login_box_size).line_box

    # Create MemPool Box
    mp_box_size = 24
    mp_box = Box(loader_text='Loading Mempool...', height=mp_box_size).line_box

    # Create Logger Box
    logger_box_size = 10
    logger_box = Box(loader_text='Loading Message Log...',
                     height=logger_box_size).line_box

    # Create the Satoshi Quotes Box
    satoshi_box_size = 20
    satoshi_box = Box(loader_text='Loading Satoshi Wisdom...',
                      height=satoshi_box_size).line_box

    # Assemble the widgets
    header = 'Loading...'
    log_tor = urwid.Columns([mp_box, urwid.Pile([login_box, tor_box])])
    log_tor_size = max(mp_box_size, login_box_size, tor_box_size)
    bottom_box_size = max(satoshi_box_size, logger_box_size)
    bottom_box = urwid.Columns([logger_box, satoshi_box])
    body_widget = urwid.Pile([(quote_box_size, quote_box),
                              (log_tor_size, log_tor),
                              (bottom_box_size, bottom_box)])

    layout = urwid.Frame(header=header, body=body_widget, footer=menu)
    update_header(layout)

    # Handle key presses
    def handle_input(key):
        if key == 'R' or key == 'r':
            refresh(main_loop, '')

        if key == 'Q' or key == 'q':
            raise urwid.ExitMainLoop()

    def check_for_pump(_loop, _data):
        try:
            btc = btc_price_data()
            btc_price = btc['DISPLAY']['BTC']['USD']['PRICE']
            chg_str = btc['DISPLAY']['BTC']['USD']['CHANGEPCTDAY']
            chg = cleanfloat(chg_str)
            if chg > 5:
                logging.info(
                    info("[NGU] ") + muted(f"Looks like Bitcoin is pumping ") +
                    emoji.emojize(":rocket:") + yellow(f' {btc_price}') +
                    success(f' +{chg_str}%'))
            if chg < -5:
                logging.info(
                    info("[NGU] ") + muted(
                        f"Looks like Bitcoin is dropping. Time to stack some sats. "
                    ) + yellow(f' {btc_price}') + error(f' {chg_str}%'))
        except Exception:
            pass

        main_loop.set_alarm_in(300, check_for_pump)

    def get_quote(_loop, _data):
        quote = translate_text_for_urwid(data_random_satoshi())
        satoshi_box.base_widget.set_text(quote)
        main_loop.set_alarm_in(60, get_quote)

    def refresh(_loop, _data):
        # Add Background Tasks
        update_header(layout)
        main_loop.draw_screen()

        # Add Background Updates
        max_workers = 1  # Max number of threads **KEEP AT 1***

        # Beware of increasing the max_workers - need to make sure
        # processes are killed for all workers - CODE IS NOT DOING THAT
        # right now and will lead to CPU usage blowing up

        # UPDATER FUNCTIONS - ONE NEEDED PER UPDATE
        # These run on background as watch pipes
        def update_btc(read_data):
            read_data = translate_text_for_urwid(read_data)
            quote_box.base_widget.set_text(read_data)
            main_loop.remove_watch_pipe = True
            running_jobs['btc']['workers'] = 0
            for pipe in running_jobs['btc']['pipe']:
                if pipe != []:
                    pipe.kill()
                    gc.collect()

        def update_tor(read_data):
            read_data = translate_text_for_urwid(read_data)
            tor_box.base_widget.set_text(read_data)
            running_jobs['tor']['workers'] = 0
            for pipe in running_jobs['tor']['pipe']:
                if pipe != []:
                    pipe.kill()
                    gc.collect()

        def update_login(read_data):
            read_data = translate_text_for_urwid(read_data)
            login_box.base_widget.set_text(read_data)
            running_jobs['login']['workers'] = 0
            for pipe in running_jobs['login']['pipe']:
                if pipe != []:
                    pipe.kill()
                    gc.collect()

        def update_mp(read_data):
            read_data = translate_text_for_urwid(read_data)
            mp_box.base_widget.set_text(read_data)
            main_loop.remove_watch_pipe = True
            running_jobs['mp']['workers'] = 0
            for pipe in running_jobs['mp']['pipe']:
                if pipe != []:
                    pipe.kill()
                    gc.collect()

        def update_logger(read_data):
            read_data = translate_text_for_urwid(read_data)
            logger_box.base_widget.set_text(read_data)
            main_loop.remove_watch_pipe = True
            running_jobs['logger']['workers'] = 0
            for pipe in running_jobs['logger']['pipe']:
                if pipe != []:
                    pipe.kill()
                    gc.collect()

        # Job List Dictionaty
        job_list = {
            'btc': {
                'max_workers': 1,
                'subprocess': 'python3 data.py data_btc_price',
                'updater': update_btc
            },
            'tor': {
                'max_workers': 1,
                'subprocess': 'python3 data.py data_tor',
                'updater': update_tor
            },
            'login': {
                'max_workers': 1,
                'subprocess': 'python3 data.py data_login',
                'updater': update_login
            },
            'mp': {
                'max_workers': 1,
                'subprocess': 'python3 data.py data_mempool',
                'updater': update_mp
            },
            'logger': {
                'max_workers': 1,
                'subprocess': 'python3 data.py data_logger',
                'updater': update_logger
            }
        }

        for job in job_list.keys():
            if running_jobs[job]['workers'] < job_list[job]['max_workers']:
                running_jobs[job]['workers'] += 1
                stdout = main_loop.watch_pipe(job_list[job]['updater'])
                stderr = main_loop.watch_pipe(job_list[job]['updater'])
                launch_process = subprocess.Popen(job_list[job]['subprocess'],
                                                  shell=True,
                                                  stdout=stdout,
                                                  stderr=stderr)
                # Store or create a list to store
                running_jobs[job].setdefault('pipe', []).append(launch_process)

        main_loop.set_alarm_in(refresh_interval, refresh)

    try:
        main_loop = urwid.MainLoop(layout, palette, unhandled_input=handle_input)
        main_loop.set_alarm_in(30, check_for_pump)
        main_loop.set_alarm_in(10, get_quote)
        main_loop.set_alarm_in(0, refresh)
        main_loop.run()
    except Exception as e:  # Catch some timeouts - only once
        logging.error(info('[MAIN] ') + muted('Error: ') + yellow(str(e)))
        update_header(layout, message=f'Error: {e}')
        main_dashboard(config, tor, spinner)