def _channel_read(self, channel, nbytes, read_func=None): if read_func is None: read_func = lambda channel, nbytes: channel.read(nbytes) source = GLib.io_create_watch(channel, GLib.IO_IN | GLib.IO_HUP) def channel_readable(read_func, channel, nbytes): return (True, read_func(channel, nbytes)) return self._delayed(source, channel_readable, read_func, channel, nbytes)
def add_writer(self, fileobj, callback, *args): fd = self._fileobj_to_fd(fileobj) self._ensure_fd_no_transport(fd) self.remove_writer(fd) channel = self._channel_from_socket(fd) source = GLib.io_create_watch(channel, GLib.IO_OUT | GLib.IO_ERR | GLib.IO_NVAL) assert fd not in self._writers self._writers[fd] = GLibHandle(loop=self, source=source, repeat=True, callback=callback, args=args)
def add_writer(self, fileobj, callback, *args): fd = self._fileobj_to_fd(fileobj) self._ensure_fd_no_transport(fd) self.remove_writer(fd) channel = self._channel_from_socket(fd) source = GLib.io_create_watch(channel, GLib.IO_OUT | GLib.IO_ERR | GLib.IO_NVAL) assert fd not in self._writers self._writers[fd] = GLibHandle( loop=self, source=source, repeat=True, callback=callback, args=args)
def sock_connect(self, sock, address): # Request connection on socket (it is expected that `sock` is already non-blocking) try: sock.connect(address) except BlockingIOError: pass # Create glib IOChannel for socket and wait for it to become writable channel = self._channel_from_socket(sock) source = GLib.io_create_watch(channel, GLib.IO_OUT) def sock_finish_connect(sock): self._socket_handle_errors(sock) return (True, sock) return self._delayed(source, sock_finish_connect, sock)
def sock_accept(self, sock): channel = self._channel_from_socket(sock) source = GLib.io_create_watch(channel, GLib.IO_IN) def sock_connection_received(sock): return (True, sock.accept()) async def accept_coro(future, conn): # Coroutine closing the accept socket if the future is cancelled try: return (await future) except CancelledError: sock.close() raise future = self._delayed(source, sock_connection_received, sock) return self.create_task(accept_coro(future, sock))
def sock_accept(self, sock): channel = self._channel_from_socket(sock) source = GLib.io_create_watch(channel, GLib.IO_IN) def sock_connection_received(sock): return (True, sock.accept()) @asyncio.coroutine def accept_coro(future, conn): # Coroutine closing the accept socket if the future is cancelled try: return (yield from future) except futures.CancelledError: sock.close() raise future = self._delayed(source, sock_connection_received, sock) return self.create_task(accept_coro(future, sock))
def _channel_write(self, channel, buf, write_func=None): if write_func is None: # note: channel.write doesn't raise BlockingIOError, instead it # returns 0 # gi.overrides.GLib.write has an isinstance(buf, bytes) check, so # we can't give it a bytearray or a memoryview. def write_func(channel, buf): return channel.write(bytes(buf)) buflen = len(buf) # Fast-path: If there is enough room in the OS buffer all data can be written synchronously try: nbytes = write_func(channel, buf) except BlockingIOError: nbytes = 0 else: if nbytes >= len(buf): # All data was written synchronously in one go result = asyncio.Future(loop=self) result.set_result(nbytes) return result # Chop off the initially transmitted data and store result # as a bytearray for easier future modification buf = bytearray(buf[nbytes:]) # Send the remaining data asynchronously as the socket becomes writable source = GLib.io_create_watch(channel, GLib.IO_OUT) def channel_writable(buflen, write_func, channel, buf): nbytes = write_func(channel, buf) if nbytes >= len(buf): return (True, buflen) else: del buf[0:nbytes] return (False, buflen) return self._delayed(source, channel_writable, buflen, write_func, channel, buf)
def _channel_write(self, channel, buf, write_func=None): if write_func is None: # note: channel.write doesn't raise BlockingIOError, instead it # returns 0 # gi.overrides.GLib.write has an isinstance(buf, bytes) check, so # we can't give it a bytearray or a memoryview. write_func = lambda channel, buf: channel.write(bytes(buf)) buflen = len(buf) # Fast-path: If there is enough room in the OS buffer all data can be written synchronously try: nbytes = write_func(channel, buf) except BlockingIOError: nbytes = 0 else: if nbytes >= len(buf): # All data was written synchronously in one go result = asyncio.Future(loop=self) result.set_result(nbytes) return result # Chop off the initially transmitted data and store result # as a bytearray for easier future modification buf = bytearray(buf[nbytes:]) # Send the remaining data asynchronously as the socket becomes writable source = GLib.io_create_watch(channel, GLib.IO_OUT) def channel_writable(buflen, write_func, channel, buf): nbytes = write_func(channel, buf) if nbytes >= len(buf): return (True, buflen) else: del buf[0:nbytes] return (False, buflen) return self._delayed(source, channel_writable, buflen, write_func, channel, buf)