#!/usr/bin/env python
from __future__ import print_function

import logging
import os
import signal
from time import sleep
from subprocess import Popen, PIPE
import socket

from core.common_functions import *
from core.run import Runner


class NginxPerf(Runner):
    """
    Runs Nginx
    """

    name = "nginx"
    exp_name = "nginx"
    bench_suite = False

    benchmarks = {"nginx": ""}
    test_benchmarks = {"nginx": ""}
    client_numbers = [1, 5, 9, 13, 17, 21, 25, 29]
    ab = "ab"
    duration = 20  # in seconds
    requests_num = 1000000  # some huge number so we always take 20 seconds

    def __init__(self, *args, **kwargs):
        super(NginxPerf, self).__init__(*args, **kwargs)

        if self.config.input_type == "test":
            self.client_numbers = (1,)

    def per_benchmark_action(self, type_, benchmark, args):
        self.log_build(type_, benchmark)
        build_path = "/".join([self.dirs["build"], type_])
        self.current_exe = build_path + '/sbin/' + benchmark

        build_benchmark(
            b=benchmark,
            t=type_,
            makefile=self.dirs['bench_src'],
            build_path=build_path
        )

        # generate an input file
        with open(build_path + "/html/index.html", "w") as f:
            f.write("<html><body><h1>It works!</h1>")
            random_text = my_check_output("lorem -p 10")
            f.write(random_text)
            f.write("</body></html>")

        # config Nginx
        replace_in_file(build_path + "/conf/nginx.conf", "listen       80;", "listen       8080;", ignoreifcontains=True)
        replace_in_file(build_path + "/conf/nginx.conf", "worker_processes  1;", "worker_processes  auto;", ignoreifcontains=True)

    def per_thread_action(self, type_, benchmark, args, thread_num):
        servercmd = "{action} {exe} -g \"daemon off;\"".format(
            action=self.action,
            exe=self.current_exe,
        )
        logging.debug("Server command: %s" % servercmd)

        # by default start client on local machine
        if env.get("CLIENT_MACHINE"):
            ssh = "ssh %s" % env["CLIENT_MACHINE"]
            logging.debug("Using remote client: %s" % env["CLIENT_MACHINE"])
        else:
            ssh = ""
            logging.debug("Using local client  (use CLIENT_MACHINE env var to specify remote client)")

        myip = [l for l in ([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1], [[(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) if l][0][0]

        with open(self.dirs["log_file"], "a") as f:
            for client_number in self.client_numbers:
                # start server
                my_check_output("pkill -9 nginx > /dev/null || true")  # for sanity
                sleep(1)
                server = Popen(servercmd, shell=True, stdout=PIPE, stderr=PIPE, preexec_fn=os.setsid)
                sleep(1)

                # start client (possibly on another machine)
                msg = self.run_message.format(input=client_number, **locals())
                self.log_run(msg)
                f.write("[run] " + msg + "\n")

                out = my_check_output("{ssh} {ab} -k -t {duration} -n {requests_num} -c {client_number} http://{myip}:8080/".format(
                    ab=self.ab,
                    duration=self.duration,
                    requests_num=self.requests_num,
                    **locals()
                ))

                f.write("===== client =====\n")
                f.write(out)

                # log and stop server
                f.write("===== return code is %s =====\n" % str(server.poll()))
                try:
                    os.killpg(server.pid, signal.SIGINT)
                except:
                    pass
                f.write("===== stdout =====\n")
                for line in server.stdout:
                    f.write(line.decode('utf-8'))
                f.write("===== stderr =====\n")
                for line in server.stderr:
                    f.write(line.decode('utf-8'))
                sleep(1)

    def set_logging(self):
        self.num_benchmarks = len(self.benchmarks) * len(self.types) * self.num_runs * len(self.client_numbers)
        logging.info("Total runs: %d" % self.num_benchmarks)


def main(benchmark_name=None):
    runner = NginxPerf()
    runner.main()

[((65, 8, 65, 55), 'logging.debug', 'logging.debug', ({(65, 22, 65, 54): "('Server command: %s' % servercmd)"}, {}), "('Server command: %s' % servercmd)", False, 'import logging\n'), ((116, 8, 116, 60), 'logging.info', 'logging.info', ({(116, 21, 116, 59): "('Total runs: %d' % self.num_benchmarks)"}, {}), "('Total runs: %d' % self.num_benchmarks)", False, 'import logging\n'), ((70, 12, 70, 76), 'logging.debug', 'logging.debug', ({(70, 26, 70, 75): "('Using remote client: %s' % env['CLIENT_MACHINE'])"}, {}), "('Using remote client: %s' % env['CLIENT_MACHINE'])", False, 'import logging\n'), ((73, 12, 73, 102), 'logging.debug', 'logging.debug', ({(73, 26, 73, 101): '"""Using local client  (use CLIENT_MACHINE env var to specify remote client)"""'}, {}), "(\n    'Using local client  (use CLIENT_MACHINE env var to specify remote client)'\n    )", False, 'import logging\n'), ((81, 16, 81, 24), 'time.sleep', 'sleep', ({(81, 22, 81, 23): '(1)'}, {}), '(1)', False, 'from time import sleep\n'), ((82, 25, 82, 101), 'subprocess.Popen', 'Popen', (), '', False, 'from subprocess import Popen, PIPE\n'), ((83, 16, 83, 24), 'time.sleep', 'sleep', ({(83, 22, 83, 23): '(1)'}, {}), '(1)', False, 'from time import sleep\n'), ((112, 16, 112, 24), 'time.sleep', 'sleep', ({(112, 22, 112, 23): '(1)'}, {}), '(1)', False, 'from time import sleep\n'), ((103, 20, 103, 56), 'os.killpg', 'os.killpg', ({(103, 30, 103, 40): 'server.pid', (103, 42, 103, 55): 'signal.SIGINT'}, {}), '(server.pid, signal.SIGINT)', False, 'import os\n'), ((75, 66, 75, 86), 'socket.gethostname', 'socket.gethostname', ({}, {}), '()', False, 'import socket\n'), ((75, 198, 75, 246), 'socket.socket', 'socket.socket', ({(75, 212, 75, 226): 'socket.AF_INET', (75, 228, 75, 245): 'socket.SOCK_DGRAM'}, {}), '(socket.AF_INET, socket.SOCK_DGRAM)', False, 'import socket\n')]