Newer
Older
exporter / driver.py
import socket
import os
import subprocess
import sys
import threading
import Queue
import errno
import json
import struct

class Driver:
  def __init__(self, port, use_stdin, exporter_already_running = False, use_air = False):
    self.port = port
    self.use_stdin = use_stdin
    self.exporter_already_running = exporter_already_running
    self.use_air = use_air
    self.stdin = None
    self.conn = None

  def make_exporter_path(self, prog_name):
    return os.path.join(os.path.dirname(os.path.abspath(__file__)), prog_name)

  def start(self):
    self.sock = socket.socket()
    self.sock.bind(("localhost", self.port))

    self.sock.settimeout(0.5)
    self.sock.listen(0)
    
    if not self.exporter_already_running:
      exporter_proc_args = [self.make_exporter_path("flash/Exporter.exe")]
      if self.use_air:
        exporter_proc_args = [self.make_exporter_path("Exporter.app/Expoter.exe"), str(self.port)]

      self.proc = subprocess.Popen(exporter_proc_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

    if self.use_stdin:
      self.stdin = Queue.Queue()
      reader = threading.Thread(target=self._get_stdin)
      reader.daemon = True
      reader.start()

    while self.conn is None and (self.exporter_already_running or self.proc.returncode is None):
      try:
        (self.conn, _) = self.sock.accept()
      except socket.timeout, e:
        pass
      except e:
        print e
        self.sock.close()
        if not self.exporter_already_running:
          self.proc.wait()
        sys.exit(1)
      if not self.exporter_already_running:
        self.proc.poll()

    if self.conn:
      self.conn.setblocking(False)
    return self.conn != None

  def send_json(self, jsonObj):
    data = json.dumps(jsonObj)
    datalen = struct.pack(">I", len(data))
    self.conn.send(datalen)
    self.conn.send(data)

  def loop(self, msg_callback, stdin_callback = None):
    buf = ""
    quit = False
    closed = False
    while self.exporter_already_running or self.proc.returncode is None:
      try:
        d = self.conn.recv(4096)
        if len(d):
          buf += d
          if len(buf) >= 4:
            buf_len = struct.unpack_from(">I", buf, 0)[0]
            if len(buf) >= 4 + buf_len:
              msg = buf[4:4+buf_len]
              buf = buf[4+buf_len:]
              if not msg_callback(msg):
                quit = True
        else:
          quit = True
          closed = True
      except socket.error, e:
        if e.args[0] == errno.EWOULDBLOCK or e.args[0] == errno.EAGAIN:
          pass
        else:
          print e
          quit = True
          closed = True
      if not quit and self.use_stdin and self.stdin.qsize():
        line = self.stdin.get()
        if line == "":
          quit = True
        elif stdin_callback:
          if not stdin_callback(line):
            quit = True
      if quit:
        if not closed and not self.exporter_already_running:
          self.send_json({"command":"exit"})
        self.conn.close()
        self.sock.close()
        if not self.exporter_already_running:
          self.proc.kill()
        sys.exit(1)
      if not self.exporter_already_running:
        self.proc.poll()

    if self.conn:
      self.conn.close()
    self.sock.close()

  def _get_stdin(self):
    while True:
      line = sys.stdin.readline()
      self.stdin.put(line)
      if line == "":
        return