class Client(BaseComponent): channel = "client" socket_family = AF_INET socket_type = SOCK_STREAM socket_protocol = IPPROTO_IP socket_options = [] def __init__(self, bind=None, bufsize=BUFSIZE, channel=channel, **kwargs): super(Client, self).__init__(channel=channel, **kwargs) if isinstance(bind, SocketType): self._bind = bind.getsockname() self._sock = bind else: self._bind = self.parse_bind_parameter(bind) self._sock = self._create_socket() self._bufsize = bufsize self._ssock = None self._poller = None self._buffer = deque() self._closeflag = False self._connected = False self.host = None self.port = 0 self.secure = False self.server = {} self.issuer = {} def parse_bind_parameter(self, bind_parameter): return parse_ipv4_parameter(bind_parameter) @property def connected(self): return getattr(self, "_connected", None) @handler("registered", "started", channel="*") def _on_registered_or_started(self, component, manager=None): if self._poller is None: if isinstance(component, BasePoller): self._poller = component self.fire(ready(self)) else: if component is not self: return component = findcmp(self.root, BasePoller) if component is not None: self._poller = component self.fire(ready(self)) else: self._poller = Poller().register(self) self.fire(ready(self)) @handler("stopped", channel="*") def _on_stopped(self, component): self.fire(close()) @handler("read_value_changed") def _on_read_value_changed(self, value): if isinstance(value, binary_type): self.fire(write(value)) @handler("prepare_unregister", channel="*") def _on_prepare_unregister(self, event, c): if event.in_subtree(self): self._close() def _close(self): if not self._connected: return self._poller.discard(self._sock) self._buffer.clear() self._closeflag = False self._connected = False try: self._sock.shutdown(2) except SocketError: pass try: self._sock.close() except SocketError: pass self.fire(disconnected()) @handler("close") def close(self): if not self._buffer: self._close() elif not self._closeflag: self._closeflag = True def _read(self): try: try: if self.secure and self._ssock: data = self._ssock.read(self._bufsize) else: data = self._sock.recv(self._bufsize) except SSLError as exc: if exc.errno in (SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE): return raise if data: self.fire(read(data)).notify = True else: self.close() except SocketError as e: if e.args[0] == EWOULDBLOCK: return else: self.fire(error(e)) self._close() def _write(self, data): try: if self.secure and self._ssock: nbytes = self._ssock.write(data) else: nbytes = self._sock.send(data) if nbytes < len(data): self._buffer.appendleft(data[nbytes:]) except SocketError as e: if e.args[0] in (EPIPE, ENOTCONN): self._close() else: self.fire(error(e)) @handler("write") def write(self, data): if not self._poller.isWriting(self._sock): self._poller.addWriter(self, self._sock) self._buffer.append(data) @handler("_disconnect", priority=1) def __on_disconnect(self, sock): self._close() @handler("_read", priority=1) def __on_read(self, sock): self._read() @handler("_write", priority=1) def __on_write(self, sock): if self._buffer: data = self._buffer.popleft() self._write(data) if not self._buffer: if self._closeflag: self._close() elif self._poller.isWriting(self._sock): self._poller.removeWriter(self._sock) def _create_socket(self): sock = socket(self.socket_family, self.socket_type, self.socket_protocol) for option in self.socket_options: sock.setsockopt(*option) sock.setblocking(False) if self._bind is not None: sock.bind(self._bind) return sock
class Serial(Component): channel = "serial" def __init__(self, port, baudrate=115200, bufsize=BUFSIZE, timeout=TIMEOUT, channel=channel): super(Serial, self).__init__(channel=channel) if serial is None: raise RuntimeError("No serial support available") self._port = port self._baudrate = baudrate self._bufsize = bufsize self._serial = None self._poller = None self._buffer = deque() self._closeflag = False @handler("ready") def _on_ready(self, component): self.fire(_open(), self.channel) @handler("_open") def _on_open(self, port=None, baudrate=None, bufsize=None): self._port = port or self._port self._baudrate = baudrate or self._baudrate self._bufsize = bufsize or self._bufsize self._serial = serial.Serial(port=self._port, baudrate=self._baudrate, timeout=0) self._fd = self._serial.fileno() # not portable! self._poller.addReader(self, self._fd) self.fire(opened(self._port, self._baudrate)) @handler("registered", "started", channel="*") def _on_registered_or_started(self, component, manager=None): if self._poller is None: if isinstance(component, BasePoller): self._poller = component self.fire(ready(self)) else: if component is not self: return component = findcmp(self.root, BasePoller) if component is not None: self._poller = component self.fire(ready(self)) else: self._poller = Poller().register(self) self.fire(ready(self)) @handler("stopped", channel="*") def _on_stopped(self, component): self.fire(close()) @handler("prepare_unregister", channel="*") def _on_prepare_unregister(self, event, c): if event.in_subtree(self): self._close() def _close(self): if self._closeflag: return self._poller.discard(self._fd) self._buffer.clear() self._closeflag = False self._connected = False try: self._serial.close() except: pass self.fire(closed()) def close(self): if not self._buffer: self._close() elif not self._closeflag: self._closeflag = True def _read(self): try: data = self._serial.read(self._bufsize) if not isinstance(data, binary_type): data = data.encode(self._encoding) if data: self.fire(read(data)).notify = True except (OSError, IOError) as e: self.fire(error(e)) self._close() def _write(self, data): try: if not isinstance(data, binary_type): data = data.encode(self._encoding) try: nbytes = self._serial.write(data) except (serial.SerialTimeoutException) as e: nbytes = 0 if nbytes < len(data): self._buffer.appendleft(data[nbytes:]) except (OSError, IOError) as e: self.fire(error(e)) self._close() def write(self, data): if self._poller is not None and not self._poller.isWriting(self._fd): self._poller.addWriter(self, self._fd) self._buffer.append(data) @handler("_disconnect") def __on_disconnect(self, sock): self._close() @handler("_read") def __on_read(self, sock): self._read() @handler("_write") def __on_write(self, sock): if self._buffer: data = self._buffer.popleft() self._write(data) if not self._buffer: if self._closeflag: self._close() elif self._poller.isWriting(self._fd): self._poller.removeWriter(self._fd)
class Server(BaseComponent): channel = "server" socket_protocol = IPPROTO_IP def __init__(self, bind, secure=False, backlog=BACKLOG, bufsize=BUFSIZE, channel=channel, **kwargs): super(Server, self).__init__(channel=channel) self.socket_options = self.socket_options[:] + kwargs.get('socket_options', []) self._bind = self.parse_bind_parameter(bind) self._backlog = backlog self._bufsize = bufsize if isinstance(bind, socket): self._sock = bind else: self._sock = self._create_socket() self._closeq = [] self._clients = [] self._poller = None self._buffers = defaultdict(deque) self.__starttls = set() self.secure = secure self.certfile = kwargs.get("certfile") self.keyfile = kwargs.get("keyfile", None) self.cert_reqs = kwargs.get("cert_reqs", CERT_NONE) self.ssl_version = kwargs.get("ssl_version", PROTOCOL_SSLv23) self.ca_certs = kwargs.get("ca_certs", None) if self.secure and not self.certfile: raise RuntimeError("certfile must be specified for server-side operations") def parse_bind_parameter(self, bind_parameter): return parse_ipv4_parameter(bind_parameter) @property def connected(self): return True @property def host(self): if getattr(self, "_sock", None) is not None: try: sockname = self._sock.getsockname() if isinstance(sockname, tuple): return sockname[0] else: return sockname except SocketError: return None @property def port(self): if getattr(self, "_sock", None) is not None: try: sockname = self._sock.getsockname() if isinstance(sockname, tuple): return sockname[1] except SocketError: return None @handler("registered", "started", channel="*") def _on_registered_or_started(self, component, manager=None): if self._poller is None: if isinstance(component, BasePoller): self._poller = component self._poller.addReader(self, self._sock) self.fire(ready(self, (self.host, self.port))) else: if component is not self: return component = findcmp(self.root, BasePoller) if component is not None: self._poller = component self._poller.addReader(self, self._sock) self.fire(ready(self, (self.host, self.port))) else: self._poller = Poller().register(self) self._poller.addReader(self, self._sock) self.fire(ready(self, (self.host, self.port))) @handler("stopped", channel="*") def _on_stopped(self, component): self.fire(close()) @handler("read_value_changed") def _on_read_value_changed(self, value): if isinstance(value.value, binary_type): sock = value.event.args[0] self.fire(write(sock, value.value)) def _close(self, sock): if sock is None: return if sock != self._sock and sock not in self._clients: return self._poller.discard(sock) if sock in self._buffers: del self._buffers[sock] if sock in self._clients: self._clients.remove(sock) else: self._sock = None if sock in self.__starttls: self.__starttls.remove(sock) try: sock.shutdown(2) except SocketError: pass try: sock.close() except SocketError: pass self.fire(disconnect(sock)) @handler("close") def close(self, sock=None): is_closed = sock is None if sock is None: socks = [self._sock] socks.extend(self._clients[:]) else: socks = [sock] for sock in socks: if not self._buffers[sock]: self._close(sock) elif sock not in self._closeq: self._closeq.append(sock) if is_closed: self.fire(closed()) def _read(self, sock): if sock not in self._clients: return try: data = sock.recv(self._bufsize) if data: self.fire(read(sock, data)).notify = True else: self.close(sock) except SocketError as e: if e.args[0] == EWOULDBLOCK: return else: self.fire(error(sock, e)) self._close(sock) def _write(self, sock, data): if sock not in self._clients: return try: nbytes = sock.send(data) if nbytes < len(data): self._buffers[sock].appendleft(data[nbytes:]) except SocketError as e: if e.args[0] not in (EINTR, EWOULDBLOCK, ENOBUFS): self.fire(error(sock, e)) self._close(sock) else: self._buffers[sock].appendleft(data) @handler("write") def write(self, sock, data): if not self._poller.isWriting(sock): self._poller.addWriter(self, sock) self._buffers[sock].append(data) def _accept(self): try: newsock, host = self._sock.accept() except SocketError as e: if e.args[0] in (EWOULDBLOCK, EAGAIN): return elif e.args[0] == EPERM: # Netfilter on Linux may have rejected the # connection, but we get told to try to accept() # anyway. return elif e.args[0] in (EMFILE, ENOBUFS, ENFILE, ENOMEM, ECONNABORTED): # Linux gives EMFILE when a process is not allowed # to allocate any more file descriptors. *BSD and # Win32 give (WSA)ENOBUFS. Linux can also give # ENFILE if the system is out of inodes, or ENOMEM # if there is insufficient memory to allocate a new # dentry. ECONNABORTED is documented as possible on # both Linux and Windows, but it is not clear # whether there are actually any circumstances under # which it can happen (one might expect it to be # possible if a client sends a FIN or RST after the # server sends a SYN|ACK but before application code # calls accept(2), however at least on Linux this # _seems_ to be short-circuited by syncookies. return else: raise if self.secure and HAS_SSL: for _ in self._do_handshake(newsock): yield else: self._on_accept_done(newsock) def _do_handshake(self, sock, fire_connect_event=True): sslsock = ssl_socket( sock, server_side=True, keyfile=self.keyfile, ca_certs=self.ca_certs, certfile=self.certfile, cert_reqs=self.cert_reqs, ssl_version=self.ssl_version, do_handshake_on_connect=False ) for _ in do_handshake(sslsock, self._on_accept_done, self._on_handshake_error, (fire_connect_event,)): yield _ def _on_accept_done(self, sock, fire_connect_event=True): sock.setblocking(False) self._poller.addReader(self, sock) self._clients.append(sock) if fire_connect_event: try: self.fire(connect(sock, *sock.getpeername())) except SocketError as exc: # errno 107 (ENOTCONN): the client already disconnected self._on_handshake_error(sock, exc) def _on_handshake_error(self, sock, err): self.fire(error(sock, err)) self._close(sock) @handler('starttls') def starttls(self, sock): if not HAS_SSL: raise RuntimeError('Cannot start TLS. No TLS support.') if sock in self.__starttls: raise RuntimeError('Cannot reuse socket for already started STARTTLS.') self.__starttls.add(sock) self._poller.removeReader(sock) self._clients.remove(sock) for _ in self._do_handshake(sock, False): yield @handler("_disconnect", priority=1) def _on_disconnect(self, sock): self._close(sock) @handler("_read", priority=1) def _on_read(self, sock): if sock == self._sock: return self._accept() else: self._read(sock) @handler("_write", priority=1) def _on_write(self, sock): if self._buffers[sock]: data = self._buffers[sock].popleft() self._write(sock, data) if not self._buffers[sock]: if sock in self._closeq: self._closeq.remove(sock) self._close(sock) elif self._poller.isWriting(sock): self._poller.removeWriter(sock) def _create_socket(self): sock = socket(self.socket_family, self.socket_type, self.socket_protocol) for option in self.socket_options: sock.setsockopt(*option) sock.setblocking(False) if self._bind is not None: sock.bind(self._bind) return sock
class Client(BaseComponent): channel = "client" def __init__(self, bind=None, bufsize=BUFSIZE, channel=channel, **kwargs): super(Client, self).__init__(channel=channel, **kwargs) if isinstance(bind, SocketType): self._bind = bind.getsockname() self._sock = bind else: self._bind = self.parse_bind_parameter(bind) self._sock = self._create_socket() self._bufsize = bufsize self._ssock = None self._poller = None self._buffer = deque() self._closeflag = False self._connected = False self.host = None self.port = 0 self.secure = False self.server = {} self.issuer = {} def parse_bind_parameter(self, bind_parameter): return parse_ipv4_parameter(bind_parameter) @property def connected(self): return getattr(self, "_connected", None) @handler("registered", "started", channel="*") def _on_registered_or_started(self, component, manager=None): if self._poller is None: if isinstance(component, BasePoller): self._poller = component self.fire(ready(self)) else: if component is not self: return component = findcmp(self.root, BasePoller) if component is not None: self._poller = component self.fire(ready(self)) else: self._poller = Poller().register(self) self.fire(ready(self)) @handler("stopped", channel="*") def _on_stopped(self, component): self.fire(close()) @handler("read_value_changed") def _on_read_value_changed(self, value): if isinstance(value, binary_type): self.fire(write(value)) @handler("prepare_unregister", channel="*") def _on_prepare_unregister(self, event, c): if event.in_subtree(self): self._close() def _close(self): if not self._connected: return self._poller.discard(self._sock) self._buffer.clear() self._closeflag = False self._connected = False try: self._sock.shutdown(2) except SocketError: pass try: self._sock.close() except SocketError: pass self.fire(disconnected()) @handler("close") def close(self): if not self._buffer: self._close() elif not self._closeflag: self._closeflag = True def _read(self): try: if self.secure and self._ssock: data = self._ssock.read(self._bufsize) else: try: data = self._sock.recv(self._bufsize) except SSLError as exc: if exc.errno in (SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE): return raise if data: self.fire(read(data)).notify = True else: self.close() except SocketError as e: if e.args[0] == EWOULDBLOCK: return else: self.fire(error(e)) self._close() def _write(self, data): try: if self.secure and self._ssock: nbytes = self._ssock.write(data) else: nbytes = self._sock.send(data) if nbytes < len(data): self._buffer.appendleft(data[nbytes:]) except SocketError as e: if e.args[0] in (EPIPE, ENOTCONN): self._close() else: self.fire(error(e)) @handler("write") def write(self, data): if not self._poller.isWriting(self._sock): self._poller.addWriter(self, self._sock) self._buffer.append(data) @handler("_disconnect", priority=1) def __on_disconnect(self, sock): self._close() @handler("_read", priority=1) def __on_read(self, sock): self._read() @handler("_write", priority=1) def __on_write(self, sock): if self._buffer: data = self._buffer.popleft() self._write(data) if not self._buffer: if self._closeflag: self._close() elif self._poller.isWriting(self._sock): self._poller.removeWriter(self._sock)
class Server(BaseComponent): channel = "server" def __init__(self, bind, secure=False, backlog=BACKLOG, bufsize=BUFSIZE, channel=channel, **kwargs): super(Server, self).__init__(channel=channel) self._bind = self.parse_bind_parameter(bind) self._backlog = backlog self._bufsize = bufsize if isinstance(bind, socket): self._sock = bind else: self._sock = self._create_socket() self._closeq = [] self._clients = [] self._poller = None self._buffers = defaultdict(deque) self.secure = secure if self.secure: try: self.certfile = kwargs["certfile"] except KeyError: raise RuntimeError( "certfile must be specified for server-side operations") self.keyfile = kwargs.get("keyfile", None) self.cert_reqs = kwargs.get("cert_reqs", CERT_NONE) self.ssl_version = kwargs.get("ssl_version", PROTOCOL_SSLv23) self.ca_certs = kwargs.get("ca_certs", None) def parse_bind_parameter(self, bind_parameter): return parse_ipv4_parameter(bind_parameter) @property def connected(self): return True @property def host(self): if getattr(self, "_sock", None) is not None: try: sockname = self._sock.getsockname() if isinstance(sockname, tuple): return sockname[0] else: return sockname except SocketError: return None @property def port(self): if getattr(self, "_sock", None) is not None: try: sockname = self._sock.getsockname() if isinstance(sockname, tuple): return sockname[1] except SocketError: return None @handler("registered", "started", channel="*") def _on_registered_or_started(self, component, manager=None): if self._poller is None: if isinstance(component, BasePoller): self._poller = component self._poller.addReader(self, self._sock) self.fire(ready(self, (self.host, self.port))) else: if component is not self: return component = findcmp(self.root, BasePoller) if component is not None: self._poller = component self._poller.addReader(self, self._sock) self.fire(ready(self, (self.host, self.port))) else: self._poller = Poller().register(self) self._poller.addReader(self, self._sock) self.fire(ready(self, (self.host, self.port))) @handler("stopped", channel="*") def _on_stopped(self, component): self.fire(close()) @handler("read_value_changed") def _on_read_value_changed(self, value): if isinstance(value.value, binary_type): sock = value.event.args[0] self.fire(write(sock, value.value)) def _close(self, sock): if sock is None: return if sock != self._sock and sock not in self._clients: return self._poller.discard(sock) if sock in self._buffers: del self._buffers[sock] if sock in self._clients: self._clients.remove(sock) else: self._sock = None try: sock.shutdown(2) except SocketError: pass try: sock.close() except SocketError: pass self.fire(disconnect(sock)) @handler("close") def close(self, sock=None): is_closed = sock is None if sock is None: socks = [self._sock] socks.extend(self._clients[:]) else: socks = [sock] for sock in socks: if not self._buffers[sock]: self._close(sock) elif sock not in self._closeq: self._closeq.append(sock) if is_closed: self.fire(closed()) def _read(self, sock): if sock not in self._clients: return try: data = sock.recv(self._bufsize) if data: self.fire(read(sock, data)).notify = True else: self.close(sock) except SocketError as e: if e.args[0] == EWOULDBLOCK: return else: self.fire(error(sock, e)) self._close(sock) def _write(self, sock, data): if sock not in self._clients: return try: nbytes = sock.send(data) if nbytes < len(data): self._buffers[sock].appendleft(data[nbytes:]) except SocketError as e: if e.args[0] not in (EINTR, EWOULDBLOCK, ENOBUFS): self.fire(error(sock, e)) self._close(sock) else: self._buffers[sock].appendleft(data) @handler("write") def write(self, sock, data): if not self._poller.isWriting(sock): self._poller.addWriter(self, sock) self._buffers[sock].append(data) def _accept(self): # noqa # XXX: C901: This has a high McCacbe complexity score of 10. # TODO: Refactor this! def on_done(sock, host): sock.setblocking(False) self._poller.addReader(self, sock) self._clients.append(sock) self.fire(connect(sock, *host)) def on_error(sock, err): self.fire(error(sock, err)) self._close(sock) try: newsock, host = self._sock.accept() except SocketError as e: if e.args[0] in (EWOULDBLOCK, EAGAIN): return elif e.args[0] == EPERM: # Netfilter on Linux may have rejected the # connection, but we get told to try to accept() # anyway. return elif e.args[0] in (EMFILE, ENOBUFS, ENFILE, ENOMEM, ECONNABORTED): # Linux gives EMFILE when a process is not allowed # to allocate any more file descriptors. *BSD and # Win32 give (WSA)ENOBUFS. Linux can also give # ENFILE if the system is out of inodes, or ENOMEM # if there is insufficient memory to allocate a new # dentry. ECONNABORTED is documented as possible on # both Linux and Windows, but it is not clear # whether there are actually any circumstances under # which it can happen (one might expect it to be # possible if a client sends a FIN or RST after the # server sends a SYN|ACK but before application code # calls accept(2), however at least on Linux this # _seems_ to be short-circuited by syncookies. return else: raise if self.secure and HAS_SSL: sslsock = ssl_socket( newsock, server_side=True, keyfile=self.keyfile, ca_certs=self.ca_certs, certfile=self.certfile, cert_reqs=self.cert_reqs, ssl_version=self.ssl_version, do_handshake_on_connect=False ) for _ in do_handshake(sslsock, on_done, on_error, extra_args=(host,)): yield else: on_done(newsock, host) @handler("_disconnect", priority=1) def _on_disconnect(self, sock): self._close(sock) @handler("_read", priority=1) def _on_read(self, sock): if sock == self._sock: return self._accept() else: self._read(sock) @handler("_write", priority=1) def _on_write(self, sock): if self._buffers[sock]: data = self._buffers[sock].popleft() self._write(sock, data) if not self._buffers[sock]: if sock in self._closeq: self._closeq.remove(sock) self._close(sock) elif self._poller.isWriting(sock): self._poller.removeWriter(sock)
class Serial(Component): channel = "serial" def __init__(self, port, baudrate=115200, bufsize=BUFSIZE, timeout=TIMEOUT, channel=channel): super(Serial, self).__init__(channel=channel) if serial is None: raise RuntimeError("No serial support available") self._port = port self._baudrate = baudrate self._bufsize = bufsize self._serial = None self._poller = None self._buffer = deque() self._closeflag = False @handler("ready") def _on_ready(self, component): self.fire(_open(), self.channel) @handler("_open") def _on_open(self, port=None, baudrate=None, bufsize=None): self._port = port or self._port self._baudrate = baudrate or self._baudrate self._bufsize = bufsize or self._bufsize self._serial = serial.Serial( port=self._port, baudrate=self._baudrate, timeout=0) self._fd = self._serial.fileno() # not portable! self._poller.addReader(self, self._fd) self.fire(opened(self._port, self._baudrate)) @handler("registered", "started", channel="*") def _on_registered_or_started(self, component, manager=None): if self._poller is None: if isinstance(component, BasePoller): self._poller = component self.fire(ready(self)) else: if component is not self: return component = findcmp(self.root, BasePoller) if component is not None: self._poller = component self.fire(ready(self)) else: self._poller = Poller().register(self) self.fire(ready(self)) @handler("stopped", channel="*") def _on_stopped(self, component): self.fire(close()) @handler("prepare_unregister", channel="*") def _on_prepare_unregister(self, event, c): if event.in_subtree(self): self._close() def _close(self): if self._closeflag: return self._poller.discard(self._fd) self._buffer.clear() self._closeflag = False self._connected = False try: self._serial.close() except: pass self.fire(closed()) def close(self): if not self._buffer: self._close() elif not self._closeflag: self._closeflag = True def _read(self): try: data = self._serial.read(self._bufsize) if not isinstance(data, binary_type): data = data.encode(self._encoding) if data: self.fire(read(data)).notify = True except (OSError, IOError) as e: self.fire(error(e)) self._close() def _write(self, data): try: if not isinstance(data, binary_type): data = data.encode(self._encoding) try: nbytes = self._serial.write(data) except (serial.SerialTimeoutException) as e: nbytes = 0 if nbytes < len(data): self._buffer.appendleft(data[nbytes:]) except (OSError, IOError) as e: self.fire(error(e)) self._close() def write(self, data): if self._poller is not None and not self._poller.isWriting(self._fd): self._poller.addWriter(self, self._fd) self._buffer.append(data) @handler("_disconnect") def __on_disconnect(self, sock): self._close() @handler("_read") def __on_read(self, sock): self._read() @handler("_write") def __on_write(self, sock): if self._buffer: data = self._buffer.popleft() self._write(data) if not self._buffer: if self._closeflag: self._close() elif self._poller.isWriting(self._fd): self._poller.removeWriter(self._fd)
class File(Component): channel = "file" def init(self, filename, mode="r", bufsize=BUFSIZE, encoding=None, channel=channel): self._mode = mode self._bufsize = bufsize self._filename = filename self._encoding = encoding or getdefaultencoding() self._fd = None self._poller = None self._buffer = deque() self._closeflag = False @property def closed(self): return getattr(self._fd, "closed", True) \ if hasattr(self, "_fd") else True @property def filename(self): return getattr(self, "_filename", None) @property def mode(self): return getattr(self, "_mode", None) @handler("ready") def _on_ready(self, component): self.fire(_open(), self.channel) @handler("_open") def _on_open(self, filename=None, mode=None, bufsize=None): self._filename = filename or self._filename self._bufsize = bufsize or self._bufsize self._mode = mode or self._mode if isinstance(self._filename, string_types[0]): kwargs = {"encoding": self._encoding} if PY3 else {} self._fd = open(self.filename, self.mode, **kwargs) else: self._fd = self._filename self._mode = self._fd.mode self._filename = self._fd.name self._encoding = getattr(self._fd, "encoding", self._encoding) if fcntl is not None: # Set non-blocking file descriptor (non-portable) flag = fcntl.fcntl(self._fd, fcntl.F_GETFL) flag = flag | O_NONBLOCK fcntl.fcntl(self._fd, fcntl.F_SETFL, flag) if "r" in self.mode or "+" in self.mode: self._poller.addReader(self, self._fd) self.fire(opened(self.filename, self.mode)) @handler("registered", "started", channel="*") def _on_registered_or_started(self, component, manager=None): if self._poller is None: if isinstance(component, BasePoller): self._poller = component self.fire(ready(self)) else: if component is not self: return component = findcmp(self.root, BasePoller) if component is not None: self._poller = component self.fire(ready(self)) else: self._poller = Poller().register(self) self.fire(ready(self)) @handler("stopped", channel="*") def _on_stopped(self, component): self.fire(close()) @handler("prepare_unregister", channel="*") def _on_prepare_unregister(self, event, c): if event.in_subtree(self): self._close() def _close(self): if self.closed: return self._poller.discard(self._fd) self._buffer.clear() self._closeflag = False self._connected = False try: self._fd.close() except: pass self.fire(closed()) def close(self): if not self._buffer: self._close() elif not self._closeflag: self._closeflag = True def _read(self): try: data = fd_read(self._fd.fileno(), self._bufsize) if not isinstance(data, binary_type): data = data.encode(self._encoding) if data: self.fire(read(data)).notify = True else: self.fire(eof()) if not any(m in self.mode for m in ("a", "+")): self.close() else: self._poller.discard(self._fd) except (OSError, IOError) as e: if e.args[0] in (EWOULDBLOCK, EINTR): return else: self.fire(error(e)) self._close() def seek(self, offset, whence=0): self._fd.seek(offset, whence) def _write(self, data): try: if not isinstance(data, binary_type): data = data.encode(self._encoding) nbytes = fd_write(self._fd.fileno(), data) if nbytes < len(data): self._buffer.appendleft(data[nbytes:]) except (OSError, IOError) as e: if e.args[0] in (EWOULDBLOCK, EINTR): return else: self.fire(error(e)) self._close() def write(self, data): if self._poller is not None and not self._poller.isWriting(self._fd): self._poller.addWriter(self, self._fd) self._buffer.append(data) @handler("_disconnect") def __on_disconnect(self, sock): self._close() @handler("_read") def __on_read(self, sock): self._read() @handler("_write") def __on_write(self, sock): if self._buffer: data = self._buffer.popleft() self._write(data) if not self._buffer: if self._closeflag: self._close() elif self._poller.isWriting(self._fd): self._poller.removeWriter(self._fd)