Source code for ngrokhelper

"""
Module to simplify the use of ngrok to get a public URL for our bot
"""
import logging
import os
import shutil
import subprocess

import backoff
import requests

log = logging.getLogger(__name__)

__all__ = ['get_public_url']


def poll_exception(e: Exception):
    # print(f'{e}')
    return False


@backoff.on_exception(backoff.constant,
                      (requests.ConnectionError, KeyError, StopIteration),
                      interval=2,
                      giveup=poll_exception,
                      max_time=10)
def poll_ngrok_for_url(host: str) -> str:
    """
    Poll Ngrok client API to get public https:// URL. Maximum time: 10 seconds

    :param host: Ngrok host to poll
    :return:
    """
    # noinspection HttpUrlsUsage
    url = f'http://{host}:4040/api/tunnels'
    with requests.Session() as session:
        with session.get(url) as response:
            response.raise_for_status()
            data = response.json()
    # we are looking for an HTTPS tunnel. KeyError and StopIteration indicate that no HTTPS tunnel exists ... yet
    tunnel = next(tunnel for tunnel in data['tunnels']
                  if tunnel['proto'] == 'https')
    return tunnel['public_url']


[docs]def get_public_url(local_port: int) -> str: """ Get public URL for local service. If environment informs us about Ngrok host then poll that host. Else start a local ngrok instance and poll that instance :param local_port: local port the webservice runs on :type local_port: int :return: """ ngrok_host = os.getenv('NGROK_HOST') or None log.debug(f'NGROK_HOST: {ngrok_host}') if ngrok_host is None: # start a local ngrok instance and then poll on localhost # where is ngrok? ngrok = shutil.which('ngrok') # commandline to start ngrok cmd = f'{ngrok} http {local_port}' # start ngrok process log.debug(f'NGROK_HOST not set, starting ngrok, command: {cmd}') subprocess.Popen(cmd.split(), stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) ngrok_host = 'localhost' # simply poll the running ngrok for public address bot_url = poll_ngrok_for_url(host=ngrok_host) return bot_url