def recv_bytes_wait(self, name, timeout=None, interval=0.0, **kwargs): connection = self.recv_connections[name] start_time = time.perf_counter() while not connection.poll(): time.sleep(interval) if timeout is not None and (time.perf_counter() - start_time) >= timeout: warnings.warn() return None return connection.recv_bytes(**kwargs)
async def recv_wait_async(self, name, timeout=None, interval=0.0): connection = self.recv_connections[name] start_time = time.perf_counter() while not connection.poll(): await asyncio.sleep(interval) if timeout is not None and (time.perf_counter() - start_time) >= timeout: warnings.warn() return None return connection.recv()
async def wait_for_broadcast_async(self, name, timeout=None, interval=0.0): connection = self.broadcasters[name] interrupt = self.interrupts.add(name) start_time = time.perf_counter() while not interrupt: if connection.poll(): return connection.recv() else: if timeout is not None and (time.perf_counter() - start_time) >= timeout: warnings.warn() return None await asyncio.sleep(interval) interrupt.reset() return None
def recv_bytes(self, name, poll=True, timeout=0.0, **kwargs): connection = self.recv_connections[name] if not poll or connection.poll(timeout=timeout): return connection.recv(**kwargs) else: return None
def recv(self, name, poll=True, timeout=0.0): connection = self.recv_connections[name] if not poll or connection.poll(timeout=timeout): return connection.recv() else: return None
def any_empty(self): for connection in self.recv_connections.values(): if connection.poll(): return True return False
def poll(self): output = {} for name, connection in self.recv_connections.items(): output[name] = connection.poll() return output
def run(self): """ Run the thread, accepting connections and then listening on them until they are closed. Each message is a call into the function table. """ logger.debug("server listening on '%s'", self.pipe) while self._is_closed is False: logger.debug("server thread is about to create a server") ready = False # test to see if there is a connection waiting on the pipe if sys.platform == "win32": try: mpc_win32.WaitNamedPipe(self.server.address, self.LISTEN_TIMEOUT * 1000) ready = True except WindowsError as e: logger.debug("Error during WaitNamedPipe:", exc_info=True) if e.args[0] not in ( mpc_win32.ERROR_SEM_TIMEOUT, mpc_win32.ERROR_PIPE_BUSY, ): raise ready = False else: # can use select on osx and linux (rd, _, _) = select.select([self.server._listener._socket], [], [], self.LISTEN_TIMEOUT) ready = len(rd) > 0 if not ready: logger.debug("server thread could not create server") continue connection = None try: # connection waiting to be read, accept it logger.debug("server about to accept connection") connection = SafePickleConnection(self.server.accept()) logger.debug("server accepted connection") while self._is_closed is False: # test to see if there is data waiting on the connection has_data = connection.poll(self.LISTEN_TIMEOUT) # see if we need to stop the server if self._is_closed: return # If we timed out waiting for data, go back to sleep. if not has_data: continue # data coming over the connection is a tuple of (name, args, kwargs) (respond, func_name, args, kwargs) = pickle.loads(connection.recv()) logger.debug("server calling '%s(%s, %s)'" % (func_name, args, kwargs)) try: if func_name not in self._functions: logger.error( "unknown function call: '%s', expecting one of '%s'" % (func_name, self.list_functions())) raise ValueError("unknown function call: '%s'" % func_name) # grab the function from the function table func = self._functions[func_name] # execute the function on the main thread. It may do GUI work. result = self.engine.execute_in_main_thread( func, *args, **kwargs) # If the RPC server was stopped, don't bother trying to reply, the connection # will have been broken on the client side and this will avoid an error # on the server side when calling send. if self._SERVER_WAS_STOPPED != result: # if the client expects the results, send them along logger.debug("server got result '%s'" % result) if respond: connection.send(pickle.dumps(result)) except Exception as e: # if any of the above fails send the exception back to the client logger.error("got exception '%s'" % e) logger.debug(" traceback:\n%s" % traceback.format_exc()) if respond: connection.send(pickle.dumps(e)) except (EOFError, IOError): # let these errors go # just keep serving new connections pass finally: # It's possible we failed accepting, so the variable may not be defined. if connection is not None: logger.debug("server closing") connection.close() logger.debug("server closed") logger.debug("server thread shutting down")
def run(self): """ Run the thread, accepting connections and then listening on them until they are closed. Each message is a call into the function table. """ self._logger.debug("server listening on '%s'", self.pipe) while True: # test to see if there is a connection waiting on the pipe if sys.platform == "win32": # need to use win32 api for windows mpc_win32 = multiprocessing.connection.win32 try: mpc_win32.WaitNamedPipe(self.server.address, self.LISTEN_TIMEOUT*1000) ready = True except WindowsError, e: if e.args[0] not in (mpc_win32.ERROR_SEM_TIMEOUT, mpc_win32.ERROR_PIPE_BUSY): raise ready = False else: # can use select on osx and linux (rd, _, _) = select.select([self.server._listener._socket], [], [], self.LISTEN_TIMEOUT) ready = (len(rd) > 0) if not ready: # nothing ready, see if we need to stop the server, if not keep waiting if self._stop: break continue # connection waiting to be read, accept it connection = self.server.accept() self._logger.debug("server accepted connection") try: while True: # test to see if there is data waiting on the connection if not connection.poll(self.LISTEN_TIMEOUT): # no data waiting, see if we need to stop the server, if not keep waiting if self._stop: break continue # data coming over the connection is a tuple of (name, args, kwargs) (respond, func_name, args, kwargs) = pickle.loads(connection.recv()) self._logger.debug("server calling '%s(%s, %s)'" % (func_name, args, kwargs)) try: if func_name not in self._functions: self._logger.error("unknown function call: '%s'" % func_name) raise ValueError("unknown function call: '%s'" % func_name) # grab the function from the function table func = self._functions[func_name] # execute the function on the main thread. It may do GUI work. result = self.engine.execute_in_main_thread(func, *args, **kwargs) # if the client expects the results, send them along self._logger.debug("server got result '%s'" % result) if respond: connection.send(pickle.dumps(result)) except Exception as e: # if any of the above fails send the exception back to the client self._logger.error("got exception '%s'" % e) self._logger.debug(" traceback:\n%s" % traceback.format_exc()) if respond: connection.send(pickle.dumps(e)) except (EOFError, IOError): # let these errors go # just keep serving new connections pass finally: self._logger.debug("server closing") connection.close()