#!/usr/bin/python

import sys, os, getopt, logging
import socket
import ashd.scgi, ashd.perf, ashd.serve
try:
    import pdm.srv
except:
    pdm = None

def usage(out):
    out.write("usage: scgi-wsgi [-hAL] [-m PDM-SPEC] [-p MODPATH] [-T [HOST:]PORT] HANDLER-MODULE [ARGS...]\n")

sk = None
modwsgi_compat = False
setlog = True
opts, args = getopt.getopt(sys.argv[1:], "+hALp:T:m:")
for o, a in opts:
    if o == "-h":
        usage(sys.stdout)
        sys.exit(0)
    elif o == "-p":
        sys.path.insert(0, a)
    elif o == "-L":
        setlog = False
    elif o == "-T":
        sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        p = a.rfind(":")
        if p < 0:
            bindhost = "localhost"
            bindport = int(a)
        else:
            bindhost = a[:p]
            bindport = int(a[p + 1:])
        sk.bind((bindhost, bindport))
        sk.listen(32)
    elif o == "-A":
        modwsgi_compat = True
    elif o == "-m":
        if pdm is not None:
            pdm.srv.listen(a)
if len(args) < 1:
    usage(sys.stderr)
    sys.exit(1)
if setlog:
    logging.basicConfig(format="scgi-wsgi(%(name)s): %(levelname)s: %(message)s")

if sk is None:
    # This is suboptimal, since the socket on stdin is not necessarily
    # AF_UNIX, but Python does not seem to offer any way around it,
    # that I can find.
    sk = socket.fromfd(0, socket.AF_UNIX, socket.SOCK_STREAM)

try:
    handlermod = __import__(args[0], fromlist = ["dummy"])
except ImportError, exc:
    sys.stderr.write("scgi-wsgi: handler %s not found: %s\n" % (args[0], exc.message))
    sys.exit(1)
if not modwsgi_compat:
    if not hasattr(handlermod, "wmain"):
        sys.stderr.write("scgi-wsgi: handler %s has no `wmain' function\n" % args[0])
        sys.exit(1)
    handler = handlermod.wmain(*args[1:])
else:
    if not hasattr(handlermod, "application"):
        sys.stderr.write("scgi-wsgi: handler %s has no `application' object\n" % args[0])
        sys.exit(1)
    handler = handlermod.application

def mkenv(head, sk):
    env = dict(head)
    env["wsgi.version"] = 1, 0
    if "HTTP_X_ASH_PROTOCOL" in env:
        env["wsgi.url_scheme"] = env["HTTP_X_ASH_PROTOCOL"]
    elif "HTTPS" in env:
        env["wsgi.url_scheme"] = "https"
    else:
        env["wsgi.url_scheme"] = "http"
    env["wsgi.input"] = sk
    env["wsgi.errors"] = sys.stderr
    env["wsgi.multithread"] = True
    env["wsgi.multiprocess"] = False
    env["wsgi.run_once"] = False
    return env

class reqthread(ashd.serve.wsgithread):
    def __init__(self, sk):
        super(reqthread, self).__init__()
        self.bsk = sk.dup()
        self.sk = self.bsk.makefile("r+")

    def handlewsgi(self):
        return handler(self.env, self.startreq)

    def writehead(self, status, headers):
        try:
            self.sk.write("Status: %s\n" % status)
            for nm, val in headers:
                self.sk.write("%s: %s\n" % (nm, val))
            self.sk.write("\n")
        except IOError:
            raise ashd.serve.closed()

    def writedata(self, data):
        try:
            self.sk.write(data)
            self.sk.flush()
        except IOError:
            raise ashd.serve.closed()

    def handle(self):
        head = ashd.scgi.readhead(self.sk)
        self.env = mkenv(head, self.sk)
        reqevent = ashd.perf.request(self.env)
        exc = (None, None, None)
        try:
            super(reqthread, self).handle()
            if self.status:
                reqevent.response([self.status, self.headers])
        except:
            exc = sys.exc_info()
            raise
        finally:
            reqevent.__exit__(*exc)

    def run(self):
        try:
            super(reqthread, self).run()
        finally:
            self.sk.close()
            self.bsk.close()

while True:
    nsk, addr = sk.accept()
    try:
        reqthread(nsk).start()
    finally:
        nsk.close()
