#! /usr/bin/python
import socket
import subprocess
import errno
import sys
import os
import json
import traceback
import shlex
import struct
import threading
import Queue
class ArgParser:
def __init__(self):
self.i = 0
self.args = []
def parse_type(self, make_type):
opt = self.args[self.i]
self.i += 1
if self.i >= len(self.args):
return ("Not enough params to " + opt, None)
val = None
try:
val = self.args[self.i] if make_type is None else make_type(self.args[self.i])
except Exception, e:
pass
if val is None:
return ("Bad argument to " + opt + ": " + self.args[self.i], None)
return (None, val)
def possible(self, opts, make_type):
return lambda v: make_type(v) if v in opts else None
def condition(self, make_type, condition):
return lambda v: make_type(v) if condition(make_type(v)) else None
def parse_args(self, args):
self.args = args
self.i = 0
ret = {"input":[]}
allow_opts = True
while self.i < len(self.args):
arg = self.args[self.i].strip()
if arg == "--":
allow_opts = False
self.i += 1
continue
if arg == "--port" or arg == "-p":
(msg, p) = self.parse_type(int)
if msg is not None:
return (msg, None)
ret["port"] = p
elif arg == "--type" or arg == "-t":
(msg, t) = self.parse_type(self.possible(["1", "3"], int))
if msg is not None:
return (msg, None)
ret["type"] = t
elif arg == "--scale" or arg == "-s":
(msg, s) = self.parse_type(self.condition(int, lambda s: s > 0.00001))
if msg is not None:
return (msg, None)
ret["scale"] = s
else:
ret["input"].append(arg)
self.i += 1
return (None, ret)
def usage():
print "usage 1: ./exporter.py [--port/-p wrapper_communication_port] [--type/-t (1,3)] [--scale/-s skeletal_scale] input_files..."
print " Exports the given file(s) with the given settings"
print
print "usage 2: ./exporter.py [--port/-p wrapper_communication_port] -"
print " Reads commands (everything after --port in usage 1) as lines from stdin"
print
print "usage 3: ./export.py --help|-h"
print " Shows this help message"
if "-h" in sys.argv or "--help" in sys.argv:
usage()
sys.exit(0)
(err, args) = ArgParser().parse_args(sys.argv[1:])
if err is not None:
print err
usage()
sys.exit(2)
from_stdin = False
if "-" in args["input"]:
from_stdin = True
if len(args["input"]) > 1 or "type" in args or "scale" in args:
print "If reading from stdin ('-') is specified, no other input may be given"
usage()
sys.exit(2)
if not len(args["input"]):
usage()
sys.exit(0)
port = args["port"] if "port" in args else 7890
s = socket.socket()
s.bind(("localhost", port))
exporter_args = [os.getcwd() + "/GraphicExport.exe"]
#exporter_args = [os.getcwd() + "/GraphicExport.app/GraphicExport.exe", str(port)]
g = subprocess.Popen(exporter_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
s.settimeout(0.5)
s.listen(0)
stdin_q = Queue.Queue()
def get_stdin():
while True:
line = sys.stdin.readline()
stdin_q.put(line)
if line == "":
return
def make_base_cmd(args):
return {"type": args["type"] if "type" in args else 1, \
"scale": args["scale"] if "scale" in args else 1}
num_jobs_sent = 0
def send_cmd(conn, base_cmd, in_file):
global num_jobs_sent
num_jobs_sent += 1
cmd = dict(base_cmd)
cmd["command"] = "job"
cmd["input"] = in_file
cmd["job_num"] = num_jobs_sent
send_msg(conn, cmd)
def send_msg(conn, msg):
data = json.dumps(msg)
datalen = struct.pack(">H", len(data))
conn.send(datalen)
conn.send(data)
conn = None
while conn is None and g.returncode is None:
try:
(conn, _) = s.accept()
except socket.timeout, e:
pass
except e:
print e
s.close()
g.wait()
sys.exit(1)
g.poll()
if conn:
conn.setblocking(False)
if from_stdin:
reader = threading.Thread(target=get_stdin)
reader.daemon = True
reader.start()
else:
base_cmd = make_base_cmd(args)
for i in args["input"]:
send_cmd(conn, base_cmd, i)
def handle_command(msg_str):
global quit
msg = json.loads(msg_str)
if "command" in msg:
cmd = msg["command"]
if cmd == "done":
quit = True
if cmd == "print" and "string" in msg:
sys.stdout.write(msg["string"])
sys.stdout.flush()
if cmd == "done" and "job_num" in msg:
job_num = int(cmd["job_num"])
if job_num == num_jobs_sent:
quit = True
buf = ""
quit = False
while g.returncode is None:
try:
d = conn.recv(4096)
if len(d):
buf += d
if len(buf) >= 2:
buf_len = struct.unpack_from(">H", buf, 0)[0]
if len(buf) >= 2 + buf_len:
msg = buf[2:2+buf_len]
buf = buf[2+buf_len:]
handle_command(msg)
except socket.error, e:
if e.args[0] == errno.EWOULDBLOCK or e.args[0] == errno.EAGAIN:
pass
else:
print e
quit = True
if not quit and from_stdin and stdin_q.qsize():
line = stdin_q.get()
if line == "":
quit = True
else:
parts = shlex.split(line)
(err, line_args) = ArgParser.parse_args(parts)
if err is not None:
print err
else:
base_cmd = make_base_cmd(line_args)
for i in line_args["input"]:
send_cmd(conn, base_cmd, i)
if quit:
send_msg(conn, {"command":"quit"})
conn.close()
s.close()
g.kill()
sys.exit(1)
g.poll()
if (conn):
conn.close()
s.close()