Update channel buffers with at most one complete frame of input.
(self, timeout=0)
| 197 | self.write_channel(STDIN_CHANNEL, data) |
| 198 | |
| 199 | def update(self, timeout=0): |
| 200 | """Update channel buffers with at most one complete frame of input.""" |
| 201 | if not self.is_open(): |
| 202 | return |
| 203 | if not self.sock.connected: |
| 204 | self._connected = False |
| 205 | return |
| 206 | |
| 207 | # The options here are: |
| 208 | # select.select() - this will work on most OS, however, it has a |
| 209 | # limitation of only able to read fd numbers up to 1024. |
| 210 | # i.e. does not scale well. This was the original |
| 211 | # implementation. |
| 212 | # select.poll() - this will work on most unix based OS, but not as |
| 213 | # efficient as epoll. Will work for fd numbers above 1024. |
| 214 | # select.epoll() - newest and most efficient way of polling. |
| 215 | # However, only works on linux. |
| 216 | if hasattr(select, "poll"): |
| 217 | poll = select.poll() |
| 218 | poll.register(self.sock.sock, select.POLLIN) |
| 219 | if timeout is not None: |
| 220 | timeout *= 1_000 # poll method uses milliseconds as the time unit |
| 221 | r = poll.poll(timeout) |
| 222 | poll.unregister(self.sock.sock) |
| 223 | else: |
| 224 | r, _, _ = select.select( |
| 225 | (self.sock.sock, ), (), (), timeout) |
| 226 | |
| 227 | if r: |
| 228 | op_code, frame = self.sock.recv_data_frame(True) |
| 229 | if op_code == ABNF.OPCODE_CLOSE: |
| 230 | self._connected = False |
| 231 | return |
| 232 | elif op_code == ABNF.OPCODE_BINARY or op_code == ABNF.OPCODE_TEXT: |
| 233 | data = frame.data |
| 234 | if len(data) > 0: |
| 235 | # Parse channel from raw bytes to support v5 CLOSE signal AND avoid charset issues |
| 236 | channel = data[0] |
| 237 | # In Py3, iterating bytes gives int, but indexing bytes gives int. |
| 238 | # websocket-client frame.data might be bytes. |
| 239 | |
| 240 | if channel == CLOSE_CHANNEL and self.subprotocol == V5_CHANNEL_PROTOCOL: # v5 CLOSE |
| 241 | if len(data) > 1: |
| 242 | # data[1] is already int in Py3 bytes |
| 243 | close_chan = data[1] |
| 244 | self._closed_channels.add(close_chan) |
| 245 | return |
| 246 | |
| 247 | data = data[1:] |
| 248 | # Decode data if expected text |
| 249 | if not self.binary: |
| 250 | data = data.decode("utf-8", "replace") |
| 251 | |
| 252 | if data: |
| 253 | if channel in [STDOUT_CHANNEL, STDERR_CHANNEL]: |
| 254 | # keeping all messages in the order they received |
| 255 | # for non-blocking call. |
| 256 | self._all.write(data) |