Mercurial > louis > mq > lightsd
view fix_lightscpy_readloop.patch @ 413:9067c2da9572
better commit message
author | Louis Opter <kalessin@kalessin.fr> |
---|---|
date | Fri, 01 Jan 2016 13:24:12 +0100 |
parents | 65b0dc335243 |
children | 2d7ab98d6266 |
line wrap: on
line source
# HG changeset patch # Parent c8614ad2dc1133c8d50e974afd66d84231b41c78 Fix lightsc.py's read loop It now handles arbitrarily large and partial responses properly. We do need to do non-blocking IO in case the last received buffer comes back full in this case doing another read would block the whole thing. diff --git a/examples/lightsc.py b/examples/lightsc.py --- a/examples/lightsc.py +++ b/examples/lightsc.py @@ -30,9 +30,11 @@ import argparse import contextlib +import fcntl import json import locale import os +import select import socket import subprocess import sys @@ -42,6 +44,9 @@ class LightsClient: + READ_SIZE = 4096 + ENCODING = "utf-8" + def __init__(self, url): self.url = url @@ -56,6 +61,7 @@ else: raise ValueError("Unsupported url {}".format(url)) + fcntl.fcntl(self._socket, fcntl.F_SETFL, os.O_NONBLOCK) self._pipeline = [] self._batch = False @@ -75,17 +81,27 @@ } def _execute_payload(self, payload): - print(payload) - self._socket.send(json.dumps(payload).encode("utf-8")) - # FIXME: proper read loop - response = self._socket.recv(64 * 1024).decode("utf-8") + select.select([], [self._socket], []) + payload = json.dumps(payload).encode(self.ENCODING, "surrogateescape") + self._socket.send(payload) + + response = bytearray() + select.select([self._socket], [], []) + while True: + try: + part = self._socket.recv(self.READ_SIZE) + except BlockingIOError: + break + if not part: + break + response += part + + response = response.decode(self.ENCODING, "surrogateescape") try: - response = json.loads(response) + return json.loads(response) except Exception: print("received invalid json: {}".format(response)) - return response - def _jsonrpc_call(self, method, params): payload = self._make_payload(method, params) if self._batch: