import threading
import os
import socket
try:
from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
from SimpleHTTPServer import SimpleHTTPRequestHandler
except ImportError:
# Python 3.x
from xmlrpc.server import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
from http.server import SimpleHTTPRequestHandler
from multiprocessing.managers import BaseManager, BaseProxy
[docs]class MultiprocessingInterface(BaseManager):
""" A multiprocessing interface to the solver controller
This object exports a controller instance proxy over the multiprocessing
interface. Control actions can be performed by connecting to the interface
and calling methods on the controller proxy instance """
def __init__(self, address=None, authkey=None, try_next_port=False):
BaseManager.__init__(self, address, authkey)
self.authkey = authkey
self.try_next_port = try_next_port
def get_controller(self):
return self.controller
def start(self, controller):
self.controller = controller
self.register('get_controller', self.get_controller)
if not self.try_next_port:
self.get_server().serve_forever()
host, port = self.address
while self.try_next_port:
try:
BaseManager.__init__(self, (host,port), self.authkey)
self.get_server().serve_forever()
self.try_next_port = False
except socket.error as e:
try_next_port = False
import errno
if e.errno == errno.EADDRINUSE:
port += 1
else:
raise
[docs]class MultiprocessingClient(BaseManager):
""" A client for the multiprocessing interface
Override the run() method to do appropriate actions on the proxy
instance of the controller object or add an interface using the add_interface
methods similar to the Controller.add_interface method """
def __init__(self, address=None, authkey=None, serializer='pickle', start=True):
BaseManager.__init__(self, address, authkey, serializer)
if start:
self.start()
def start(self, connect=True):
self.interfaces = []
# to work around a python caching bug
# http://stackoverflow.com/questions/3649458/broken-pipe-when-using-python-multiprocessing-managers-basemanager-syncmanager
if self.address in BaseProxy._address_to_local:
del BaseProxy._address_to_local[self.address][0].connection
self.register('get_controller')
if connect:
self.connect()
self.controller = self.get_controller()
self.run(self.controller)
@staticmethod
def is_available(address):
try:
socket.create_connection(address, 1).close()
return True
except socket.error:
return False
def run(self, controller):
pass
[docs] def add_interface(self, callable):
""" This makes it act as substitute for the actual command_manager """
thr = threading.Thread(target=callable, args=(self.controller,))
thr.daemon = True
thr.start()
return thr
[docs]class CrossDomainXMLRPCRequestHandler(SimpleXMLRPCRequestHandler,
SimpleHTTPRequestHandler):
""" SimpleXMLRPCRequestHandler subclass which attempts to do CORS
CORS is Cross-Origin-Resource-Sharing (http://www.w3.org/TR/cors/)
which enables xml-rpc calls from a different domain than the xml-rpc server
(such requests are otherwise denied)
"""
[docs] def do_OPTIONS(self):
""" Implement the CORS pre-flighted access for resources """
self.send_response(200)
self.send_header("Access-Control-Allow-Origin", "*")
self.send_header("Access-Control-Allow-METHODS", "POST,GET,OPTIONS")
#self.send_header("Access-Control-Max-Age", "60")
self.send_header("Content-length", "0")
self.end_headers()
[docs] def do_GET(self):
""" Handle http requests to serve html/image files only """
print(self.path, self.translate_path(self.path))
permitted_extensions = ['.html','.png','.svg','.jpg', '.js']
if not os.path.splitext(self.path)[1] in permitted_extensions:
self.send_error(404, 'File Not Found/Allowed')
else:
SimpleHTTPRequestHandler.do_GET(self)
[docs] def end_headers(self):
""" End response header with adding Access-Control-Allow-Origin
This is done to enable CORS request from all clients """
self.send_header("Access-Control-Allow-Origin", "*")
SimpleXMLRPCRequestHandler.end_headers(self)
[docs]class XMLRPCInterface(SimpleXMLRPCServer):
""" An XML-RPC interface to the solver controller
Currently cannot work with objects which cannot be marshalled
(which is basically most custom classes, most importantly
ParticleArray and numpy arrays) """
def __init__(self, addr, requestHandler=CrossDomainXMLRPCRequestHandler,
logRequests=True, allow_none=True,
encoding=None, bind_and_activate=True):
SimpleXMLRPCServer.__init__(self, addr, requestHandler, logRequests,
allow_none, encoding, bind_and_activate)
def start(self, controller):
self.register_instance(controller, allow_dotted_names=False)
self.register_introspection_functions()
self.serve_forever()
[docs]class CommandlineInterface(object):
""" command-line interface to the solver controller """
def start(self, controller):
while True:
try:
try:
inp = raw_input('pysph[%d]>>> '%controller.get('count'))
except NameError:
inp = input('pysph[%d]>>> '%controller.get('count'))
cmd = inp.strip().split()
try:
cmd, args = cmd[0], cmd[1:]
except Exception as e:
print('Invalid command')
self.help()
continue
args2 = []
for arg in args:
try:
arg = eval(arg)
except:
pass
finally:
args2.append(arg)
if cmd=='p' or cmd=='pause':
controller.pause_on_next()
elif cmd=='c' or cmd=='cont':
controller.cont()
elif cmd=='g' or cmd=='get':
print(controller.get(args[0]))
elif cmd=='s' or cmd=='set':
print(controller.set(args[0], args2[1]))
elif cmd=='q' or cmd=='quit':
break
else:
print(getattr(controller, cmd)(*args2))
except Exception as e:
self.help()
print(e)
def help(self):
print('''Valid commands are:
p | pause
c | cont
g | get <name>
s | set <name> <value>
q | quit -- quit commandline interface (solver keeps running)''')