def install(app=None, timeout=0.02): """ Creates a :class:`~PySide.QtCore.QTimer` instance that will be triggered continuously to call :func:`Engine.poll() <pants.engine.Engine.poll>`, ensuring that Pants remains responsive. ========= ======== ============ Argument Default Description ========= ======== ============ app None *Optional.* The :class:`~PySide.QtCore.QCoreApplication` to attach to. If no application is provided, it will attempt to find an existing application in memory, or, failing that, create a new application instance. timeout ``0.02`` *Optional.* The maximum time to wait, in seconds, before running :func:`Engine.poll() <pants.engine.Engine.poll>`. ========= ======== ============ """ global timer global _timeout Engine.instance()._install_poller(_Qt()) if app is None: app = QCoreApplication.instance() if app is None: app = QCoreApplication([]) _timeout = timeout * 1000 timer = QTimer(app) timer.timeout.connect(do_poll) timer.start(_timeout)
def doer(*a, **kw): if Engine.instance()._running: raise RuntimeError( "synchronous calls cannot be made while Pants is already running." ) data = [] def callback(*a, **kw): if kw: if a: a = a + (kw, ) else: a = kw if isinstance(a, tuple) and len(a) == 1: a = a[0] data.append(a) Engine.instance().stop() kw['callback'] = callback func(*a, **kw) Engine.instance().start() return data[0]
def close(self): """ Close the channel. """ if self._socket is None: return Engine.instance().remove_channel(self) self._socket_close() self._safely_call(self.on_close)
def process(self): """ Block until the queued requests finish. """ if not self._requests: return self._processing = True from pants.engine import Engine Engine.instance().start()
def callback(*a,**kw): if kw: if a: a = a + (kw, ) else: a = kw if isinstance(a, tuple) and len(a) == 1: a = a[0] data.append(a) Engine.instance().stop()
def callback(*a, **kw): if kw: if a: a = a + (kw, ) else: a = kw if isinstance(a, tuple) and len(a) == 1: a = a[0] data.append(a) Engine.instance().stop()
def _handle_events(self, events): """ Handle events raised on the channel. ========= ============ Argument Description ========= ============ events The events in the form of an integer. ========= ============ """ if self._socket is None: log.warning("Received events for closed %s #%d." % (self.__class__.__name__, self.fileno)) return if events & Engine.READ: self._wait_for_read_event = False self._handle_read_event() if self._socket is None: return if events & Engine.WRITE: self._wait_for_write_event = False self._handle_write_event() if self._socket is None: return if events & Engine.ERROR: err, errstr = self._get_socket_error() if err != 0: log.error("Error on %s #%d: %s (%d)" % (self.__class__.__name__, self.fileno, errstr, err)) self.close() return if events & Engine.HANGUP: log.debug("Hang up on %s #%d." % (self.__class__.__name__, self.fileno)) self.close() return events = Engine.ERROR | Engine.HANGUP if self._wait_for_read_event: events |= Engine.READ if self._wait_for_write_event: events |= Engine.WRITE if events != self._events: self._events = events Engine.instance().modify_channel(self)
def _handle_events(self, events): """ Args: events: The events raised on the channel. """ if not self.active(): log.warning("Received events for closed channel %d." % self.fileno) return # Read event. if events & Engine.READ: if self._listening: self._handle_accept_event() elif not self._connected: self._handle_connect_event() else: self._handle_read_event() if not self.active(): return # Write event. if events & Engine.WRITE: if not self._connected: self._handle_connect_event() else: self._handle_write_event() if not self.active(): return # Error event. if events & Engine.ERROR: self.close_immediately() return # Update events. events = Engine.ERROR if self.readable(): events |= Engine.READ if self.writable(): events |= Engine.WRITE elif self._closing: # Done writing, so close. self.close_immediately() return if events != self._events: self._events = events Engine.instance().modify_channel(self)
def start_event(owner, delay, event_func, data=None, arg='', *args, **kwargs): """ Schedule a new event to trigger after ``delay`` seconds. Owners may be any Python object, but should be an instance of one of: :class:`account.Account`, :class:`char.Char`, :class:`exit.Exit`, :class:`mudsock.Mudsock`, :class:`obj.Obj`, or :class:`room.Room`. If the owner *is* one of those classes, any currently pending events are de-scheduled automatically when the owner is destroyed. Event functions should take a minimum of three arguments: the event owner, ``data``, and ``arg``. This is for compatibility with NakedMud. You may provide additional positional and keyword arguments if you wish. Returns a callable that de-schedules the event when called. =========== ============ Argument Description =========== ============ owner The object that owns the event. delay How long, in seconds, to wait before the event function should be called. event_func The function to be called. data *Optional.* Any Python object to be provided to the event function. arg *Optional.* A string to be provided to the event function. =========== ============ """ if not owner in __queued__: __queued__[owner] = [] event = Engine.instance().defer(delay, event_func, owner, data, arg, *args, **kwargs) __queued__[owner].append(event) return event
def install(app=None, timeout=0.02, engine=None): """ Creates a :class:`~PySide.QtCore.QTimer` instance that will be triggered continuously to call :func:`Engine.poll() <pants.engine.Engine.poll>`, ensuring that Pants remains responsive. ========= ======== ============ Argument Default Description ========= ======== ============ app None *Optional.* The :class:`~PySide.QtCore.QCoreApplication` to attach to. If no application is provided, it will attempt to find an existing application in memory, or, failing that, create a new application instance. timeout ``0.02`` *Optional.* The maximum time to wait, in seconds, before running :func:`Engine.poll() <pants.engine.Engine.poll>`. engine *Optional.* The :class:`pants.engine.Engine` instance to use. ========= ======== ============ """ global timer global _timeout global _engine _engine = engine or Engine.instance() _engine._install_poller(_Qt()) if app is None: app = QCoreApplication.instance() if app is None: app = QCoreApplication([]) _timeout = timeout * 1000 timer = QTimer(app) timer.timeout.connect(do_poll) timer.start(_timeout)
def setUp(self): self.engine = Engine.instance() self.client = HTTPClient(self.on_response, self.on_headers, self.on_progress, self.on_ssl_error, self.on_error, engine=self.engine)
def setUp(self): self.app = Application() self.init_app(self.app) engine = Engine.instance() self.server = HTTPServer(self.app, engine=engine) self.server.listen(('127.0.0.1', 4040)) PantsTestCase.setUp(self, engine)
def close_immediately(self): """ Close the socket immediately. Any pending data will not be sent. """ if not self.active(): return if self._write_file: self._write_file.close() self._write_file = None self._write_file_left = None Engine.instance().remove_channel(self) self._socket_close() self._update_addr() self._safely_call(self.handle_close)
def __init__(self, servers=None, engine=None): self.servers = servers or list_dns_servers() self.engine = engine or Engine.instance() # Internal State self._messages = {} self._cache = {} self._queries = {} self._tcp = {} self._udp = None self._last_id = -1
def __init__(self, socket=None): """ Initialises the channel object. Args: socket: A pre-existing socket that this channel should wrap. Optional. """ # Socket self._socket = socket or self._socket_create() self._socket.setblocking(False) self.fileno = self._socket.fileno() self.remote_addr = (None, None) self.local_addr = (None, None) # Internal state self._connected = False self._connecting = False self._listening = False self._closing = False # Input self.read_delimiter = None # String, integer or None. self._read_amount = 4096 self._read_buffer = "" # Output self._write_buffer = "" self._secondary_write_buffer = "" self._write_file = None self._write_file_left = None self._write_file_chunk = 65536 # Initialisation self._events = Engine.ERROR if self.readable(): self._events |= Engine.READ if self.writable(): self._events |= Engine.WRITE Engine.instance().add_channel(self)
def do_poll(): """ Here, we run the Pants event loop. Then, we set the timer interval, either to the provided timeout, or for how long it would take to reach the earliest deferred event. """ engine = Engine.instance() engine.poll(0) if engine._deferreds: timer.setInterval(min(1000 * (engine._deferreds[0].end - engine.time), _timeout)) else: timer.setInterval(_timeout * 1000)
def doer(*a, **kw): if Engine.instance()._running: raise RuntimeError("synchronous calls cannot be made while Pants is already running.") data = [] def callback(*a,**kw): if kw: if a: a = a + (kw, ) else: a = kw if isinstance(a, tuple) and len(a) == 1: a = a[0] data.append(a) Engine.instance().stop() kw['callback'] = callback func(*a, **kw) Engine.instance().start() return data[0]
def __init__(self, **kwargs): # Keyword arguments sock_family = kwargs.get("family", socket.AF_INET) sock_type = kwargs.get("type", socket.SOCK_STREAM) sock = kwargs.get("socket", None) if sock is None: sock = socket.socket(sock_family, sock_type) # Socket self.fileno = None self._socket = None self._socket_set(sock) # Socket state self._wait_for_read_event = True self._wait_for_write_event = True # I/O attributes self._recv_amount = 4096 # Events self._events = Engine.ALL_EVENTS Engine.instance().add_channel(self)
def install(app=None, timeout=0.02): """ Sets up the timer. This isn't necessary if you're going to be calling poll yourself. (And, if you ARE going to be calling poll yourself: why?) Args: app: The QApplication to attach to. If None, it will attempt to find the app or, failing that, it will create a new QCoreApplication instance. timeout: The length of time, in seconds, to wait between each call to the engine's poll function. """ global timer Engine.instance()._install_poller(_Qt()) if app is None: app = QCoreApplication.instance() if app is None: app = QCoreApplication([]) timer = QTimer(app) timer.timeout.connect(functools.partial(Engine.instance().poll, 0)) timer.start(timeout * 1000)
def __init__(self, **kwargs): self.engine = kwargs.get("engine", Engine.instance()) # Socket self._socket = None self._closed = False sock = kwargs.get("socket", None) if sock: self._socket_set(sock) # I/O attributes self._recv_amount = 4096 # Internal state self._events = Engine.ALL_EVENTS if self._socket: self.engine.add_channel(self)
def run(self, address=None, ssl_options=None, engine=None): """ This function exists for convenience, and when called creates a :class:`~pants.http.HTTPServer` instance with its request handler set to this application instance, calls :func:`~pants.http.HTTPServer.listen` on that HTTPServer, and finally, starts the Pants engine to process requests. ============ ============ Argument Description ============ ============ address *Optional.* The address to listen on. If this isn't specified, it will default to ``(INADDR_ANY, 80)``. ssl_options *Optional.* A dict of SSL options for the server. See :class:`pants.contrib.ssl.SSLServer` for more information. engine *Optional.* The :class:`pants.engine.Engine` instance to use. ============ ============ """ if not engine: from pants.engine import Engine engine = Engine.instance() HTTPServer(self, ssl_options=ssl_options).listen(address) engine.start()
def setUp(self, engine=None): if not engine: engine = Engine.instance() self._engine = engine self._engine_thread = threading.Thread(target=self._engine.start) self._engine_thread.start()
def test_engine_global_instance(self): engine1 = Engine.instance() engine2 = Engine.instance() self.assertTrue(engine1 is engine2)
def _add_event(self, event): if not self._events & event: self._events |= event Engine.instance().modify_channel(self)
def _process_request(self): """ Starts processing the first request on the stack. """ if not self._requests: if self._channel: self._channel.close_immediately() self._channel = None if self._processing: self._processing = False from pants.engine import Engine Engine.instance().stop() return request = self._requests[0] port = request[2].port if not port: if request[2].scheme.lower() == 'https': port = 443 else: port = 80 host = "%s:%d" % (request[2].hostname, port) if self._channel: if not self._server == host.lower() or not \ self._is_secure == (request[2].scheme.lower() == 'https'): self._channel.close() return if not self._channel: # Store the current server. self._server = host.lower() # Create a Channel, hook into it, and connect. self._channel = Channel() self._channel.handle_close = self._handle_close self._channel.handle_connect = self._handle_connect self._is_secure = request[2].scheme.lower() == 'https' if self._is_secure: self._channel.startTLS() self._channel.connect(request[2].hostname, port) return # If we got here, we're connected, and to the right server. Do stuff. self._send('%s %s HTTP/1.1%s' % (request[0], request[8], CRLF)) for k, v in request[3].iteritems(): self._send('%s: %s%s' % (k, v, CRLF)) if request[4]: self._send('%s%s' % (CRLF, request[4])) else: self._send(CRLF) # Now, wait for a response. self._channel.handle_read = self._read_headers self._channel.read_delimiter = DOUBLE_CRLF
def setUp(self): engine = Engine.instance() self.server = HTTPServer(self.request_handler, engine=engine) self.server.listen(('127.0.0.1', 4040)) PantsTestCase.setUp(self, engine)
def test_channel_constructor_no_args(self): channel = _Channel() self.assertTrue(channel.engine is Engine.instance()) self.assertTrue(channel._socket is None)
def setUp(self): engine = Engine.instance() self.server = HTTPServer(self.request_handler, engine=engine) self.server.listen(("127.0.0.1", 4040)) PantsTestCase.setUp(self, engine)
def next_pulse(function, *args, **kwargs): """ Run the provided function on the next pulse. """ Engine.instance().callback(function, *args, **kwargs)
"__version__", # Metadata "HAS_IPV6", "HAS_UNIX", # Constants "engine", # Core "Stream", "Server", # TCP Networking "struct_delimiter", # Utility Stuff ] ############################################################################### # Objects ############################################################################### #: Alias for pants.engine.Engine.instance engine = Engine.instance() ############################################################################### # Logging ############################################################################### class NullHandler(logging.Handler): """ A dummy handler to prevent logging errors if the user does not initialise logging. """ def emit(self, record): pass