# Copyright 2017 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from contextlib import contextmanager

import logging
import multiprocessing
import os
import shutil
import tempfile
import SocketServer
import SimpleHTTPServer

import common
from autotest_lib.client.bin import utils
from autotest_lib.client.common_lib import error
from autotest_lib.site_utils.lxc import constants


@contextmanager
def serve_locally(file_path):
    """Starts an http server on the localhost, to serve the given file.

    Copies the given file to a temporary location, then starts a local http
    server to serve that file.  Intended for use with unit tests that require
    some URL to download a file (see testInstallSsp as an example).

    @param file_path: The path of the file to serve.

    @return The URL at which the file will be served.
    """
    p = None
    try:
        # Copy the target file into a tmpdir for serving.
        tmpdir = tempfile.mkdtemp()
        shutil.copy(file_path, tmpdir)

        httpd = SocketServer.TCPServer(
                ('', 0), SimpleHTTPServer.SimpleHTTPRequestHandler)
        port = httpd.socket.getsockname()[1]

        # Start the http daemon in the tmpdir to serve the file.
        def serve():
            """Serves the tmpdir."""
            os.chdir(tmpdir)
            httpd.serve_forever()
        p = multiprocessing.Process(target=serve)
        p.daemon = True
        p.start()

        utils.poll_for_condition(
                condition=lambda: http_up(port),
                timeout=constants.NETWORK_INIT_TIMEOUT,
                sleep_interval=constants.NETWORK_INIT_CHECK_INTERVAL)
        url = 'http://127.0.0.1:{port}/{filename}'.format(
                port=port, filename=os.path.basename(file_path))
        logging.debug('Serving %s as %s', file_path, url)
        yield url
    finally:
        if p is not None:
            p.terminate()
        shutil.rmtree(tmpdir)


def http_up(port):
    """Checks for an http server on localhost:port.

    @param port: The port to check.
    """
    try:
        utils.run('curl --head http://127.0.0.1:%d' % port)
        return True
    except error.CmdError:
        return False