from subprocess import Popen, PIPE, STDOUT
import subprocess
import select
import socket
import os
import director
from director.simpletimer import SimpleTimer
import numpy as np
[docs]def startMatlab():
return subprocess.Popen(['matlab', '-nodisplay', '-nosplash'], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
def _readAllSoFar(proc, retVal=''):
while proc.poll() is None and (select.select([proc.stdout],[],[],0)[0] != []):
retVal += proc.stdout.read(1)
return retVal
DEFALUT_MATLAB_SERVER_PORT=41576
[docs]class MatlabServer(object):
def __init__(self, port=DEFALUT_MATLAB_SERVER_PORT):
self.port = port
self.proc = None
self.sock = None
[docs] def start(self):
self.proc = startMatlab()
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.bind(('', self.port))
self.sock.listen(1)
while True:
print 'waiting for client...'
conn, addr = self.sock.accept()
print 'client connected.'
self.serve(conn)
[docs] def serve(self, sock):
sock.settimeout(0.001)
while True:
data = _readAllSoFar(self.proc, '')
if data:
sock.send(data)
try:
inData = sock.recv(1024)
if inData:
self.proc.stdin.write(inData)
else:
sock.close()
return
except socket.timeout as e:
pass
except socket.error as e:
print 'socket error:', e
sock.close()
return
[docs]class MatlabSocketClient(object):
def __init__(self, host='127.0.0.1', port=DEFALUT_MATLAB_SERVER_PORT):
self.host = host
self.port = port
self.sock = None
self.connect()
[docs] def connect(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
self.sock.connect((self.host, self.port))
except socket.error:
self.sock = None
else:
self.sock.settimeout(0.001)
[docs] def send(self, data):
self.sock.send(data)
[docs] def receive(self):
if not self.isAlive():
return ''
try:
inData = self.sock.recv(1024)
if inData:
return inData
else:
self.sock.close()
self.sock = None
return ''
except socket.timeout as e:
return ''
[docs] def isAlive(self):
return (self.sock is not None)
[docs]class MatlabPipeClient(object):
def __init__(self):
self.proc = startMatlab()
[docs] def send(self, data):
self.proc.stdin.write(data)
[docs] def receive(self):
return _readAllSoFar(self.proc, '')
[docs] def isAlive(self):
return (self.proc.poll() is None)
[docs]class MatlabCommunicator(object):
def __init__(self, matlabClient):
self.client = matlabClient
self.prompt = '>> '
self.outputConsole = None
self.echoToStdOut = True
self.echoCommandsToStdOut = False
self.writeCommandsToLogFile = False
self.logFile = None
self.logFileName = os.path.expanduser('~/.director/matlab_commands.m')
self.clearResult()
[docs] def checkForResult(self):
self.accumulatedOutput = self.accumulatedOutput + self.client.receive()
if self.accumulatedOutput.endswith(self.prompt):
self.outputLines = self.accumulatedOutput.split('\n')[:-1]
return self.outputLines
else:
return None
[docs] def getLogFile(self):
if self.logFile is None:
if not os.path.exists(os.path.dirname(self.logFileName)):
os.makedirs(os.path.dirname(self.logFileName))
self.logFile = open(self.logFileName, 'w')
return self.logFile
[docs] def isAlive(self):
return self.client.isAlive()
[docs] def waitForResult(self, timeout=None):
t = SimpleTimer()
while self.isAlive():
result = self.checkForResult()
if result is not None:
return result
if timeout is not None and t.elapsed() > timeout:
return None
def _colorReplace(self, line):
line = line.replace('[\x08', '<font color="orange">')
line = line.replace(']\x08', '</font>')
line = line.replace('}\x08', '<font color="red">')
line = line.replace('{\x08', '</font>')
return line
def _colorStrip(self, line):
line = line.replace('[\x08', '')
line = line.replace(']\x08', '')
line = line.replace('}\x08', '')
line = line.replace('{\x08', '')
return line
[docs] def printResult(self):
if not self.outputLines:
return
if self.outputConsole:
self.outputConsole.append('<pre>' +
'<br/>'.join([self._colorReplace(line) for line in self.outputLines]) + '</pre>')
if self.echoToStdOut or not self.outputConsole:
print '\n'.join([self._colorStrip(line) for line in self.outputLines])
if self.outputConsole:
scrollBar = self.outputConsole.verticalScrollBar()
scrollBar.setValue(scrollBar.maximum)
[docs] def clearResult(self):
self.accumulatedOutput = ''
self.outputLines = []
[docs] def getResult(self):
return self.outputLines
[docs] def getResultString(self):
return self.accumulatedOutput
[docs] def send(self, command):
assert self.isAlive()
self.clearResult()
self.client.send(command + '\n')
if self.echoCommandsToStdOut:
print command
if self.writeCommandsToLogFile:
self.getLogFile().write(command + '\n')
self.getLogFile().flush()
[docs] def sendCommands(self, commands, display=True):
commands = '\n'.join(commands).split('\n')
for command in commands:
self.send(command)
self.waitForResult()
if display:
self.printResult()
[docs] def waitForResultAsync(self, timeout=0.0):
while self.waitForResult(timeout) is None:
yield
[docs] def sendCommandsAsync(self, commands, timeout=0.0, display=True):
commands = '\n'.join(commands).split('\n')
for command in commands:
self.send(command)
for _ in self.waitForResultAsync(timeout):
yield
if display:
self.printResult()
[docs] def getFloatArray(self, expression):
self.send('disp(%s)' % expression)
result = self.waitForResult()
if len(result) and not result[-1]:
result.pop()
def parseRow(rowData):
values = rowData.split()
if len(values) == 1:
return float(values[0])
else:
return [float(x) for x in values]
try:
return [parseRow(x) for x in result]
except:
raise Exception('Failed to parse output as a float array. Output was:\n%s' % '\n'.join(result))
[docs] def assignFloatArray(self, array, arrayName):
def joinFloats(values, sep):
maxLength = 180.0
pieces = np.array_split(values, np.ceil(len(values)/maxLength))
pieces = [sep.join([repr(float(x)) for x in piece]) for piece in pieces]
return str(sep + '...\n').join(pieces)
if np.ndim(array) == 1:
arrayStr = '[%s]' % joinFloats(array, ';')
else:
assert np.ndim(array) == 2
arrayStr = '[%s]' % ';...\n'.join([joinFloats(row, ',') for row in array])
self.send('%s = %s;' % (arrayName, arrayStr))
self.waitForResult()
[docs] def interact(self):
self.clearResult()
previousEchoMode = self.echoToStdOut
self.echoToStdOut = True
while self.isAlive():
command = raw_input('>>>')
if not command:
continue
if command == 'break':
break
self.send(command)
self.waitForResult()
self.printResult()
self.echoToStdOut = previousEchoMode
if __name__ == '__main__':
server = MatlabServer()
server.start()