From a3cbb1fc2124f1749b2f13f52c96d7207f995b17 Mon Sep 17 00:00:00 2001 From: himaaaatti Date: Thu, 11 Feb 2016 10:34:33 +0900 Subject: [PATCH] I added data type(json) for client communicate easily with qtile server. Closes #868 --- libqtile/command.py | 4 ++-- libqtile/ipc.py | 44 +++++++++++++++++++++++++++++++---------- libqtile/scripts/qsh.py | 9 ++++++++- 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/libqtile/command.py b/libqtile/command.py index 8b937badf7..5d43f88b69 100644 --- a/libqtile/command.py +++ b/libqtile/command.py @@ -242,10 +242,10 @@ class Client(_CommandRoot): Exposes a command tree used to communicate with a running instance of Qtile. """ - def __init__(self, fname=None): + def __init__(self, fname=None, is_json=False): if not fname: fname = find_sockfile() - self.client = ipc.Client(fname) + self.client = ipc.Client(fname, is_json) _CommandRoot.__init__(self) def call(self, selectors, name, *args, **kwargs): diff --git a/libqtile/ipc.py b/libqtile/ipc.py index 6e8b901c60..d3ea7b8ec8 100644 --- a/libqtile/ipc.py +++ b/libqtile/ipc.py @@ -29,6 +29,7 @@ import socket import struct import fcntl +import json from . import asyncio @@ -43,11 +44,19 @@ class IPCError(Exception): class _IPC(object): def _unpack(self, data): + + if data is None: + raise IPCError("received data is None") + try: + return json.loads(data.decode('utf-8')), True + except ValueError: + pass + try: assert len(data) >= HDRLEN size = struct.unpack("!L", data[:HDRLEN])[0] assert size >= len(data[HDRLEN:]) - return self._unpack_body(data[HDRLEN:HDRLEN + size]) + return self._unpack_body(data[HDRLEN:HDRLEN + size]), False except AssertionError: raise IPCError( "error reading reply!" @@ -57,6 +66,10 @@ def _unpack(self, data): def _unpack_body(self, body): return marshal.loads(body) + def _pack_json(self, msg): + json_obj = json.dumps(msg) + return json_obj.encode('utf-8') + def _pack(self, msg): msg = marshal.dumps(msg) size = struct.pack("!L", len(msg)) @@ -83,8 +96,14 @@ def connection_made(self, transport): self.recv = b'' self.reply = asyncio.Future() - def send(self, msg): - self.transport.write(self._pack(msg)) + def send(self, msg, is_json=False): + if is_json: + send_data = self._pack_json(msg) + else: + send_data = self._pack(msg) + + self.transport.write(send_data) + try: self.transport.write_eof() except AttributeError: @@ -96,7 +115,7 @@ def data_received(self, data): def eof_received(self): # The server sends EOF when there is data ready to be processed try: - data = self._unpack(self.recv) + data, _ = self._unpack(self.recv) except IPCError as e: self.reply.set_exception(e) else: @@ -111,20 +130,20 @@ def connection_lost(self, exc): class Client(object): - def __init__(self, fname): + def __init__(self, fname, is_json=False): self.fname = fname self.loop = asyncio.get_event_loop() + self.is_json = is_json def send(self, msg): client_coroutine = self.loop.create_unix_connection(_ClientProtocol, path=self.fname) try: - _, client_proto = self.loop.run_until_complete(client_coroutine) except OSError: raise IPCError("Could not open %s" % self.fname) - client_proto.send(msg) + client_proto.send(msg, is_json=self.is_json) try: self.loop.run_until_complete(asyncio.wait_for(client_proto.reply, timeout=10)) @@ -168,9 +187,9 @@ def data_received(self, recv): def eof_received(self): logger.info('EOF received by server') try: - req = self._unpack(self.data) + req, is_json = self._unpack(self.data) except IPCError: - logger.info('Invalid data received, closing connection') + logger.warn('Invalid data received, closing connection') self.transport.close() return finally: @@ -181,7 +200,12 @@ def eof_received(self): self.transport.write_eof() rep = self.handler(req) - result = self._pack(rep) + + if is_json: + result = self._pack_json(rep) + else: + result = self._pack(rep) + logger.info('Sending result on receive EOF') self.transport.write(result) logger.info('Closing connection on receive EOF') diff --git a/libqtile/scripts/qsh.py b/libqtile/scripts/qsh.py index fe4468830e..9380c472d2 100644 --- a/libqtile/scripts/qsh.py +++ b/libqtile/scripts/qsh.py @@ -49,10 +49,17 @@ def main(): default=None, help='Run the specified qsh command and exit.' ) + parser.add_argument( + "-j", "--json", + action="store_true", + default=False, + dest="is_json", + help='Use json in order to communicate with qtile server.' + ) args = parser.parse_args() - client = command.Client(args.socket) + client = command.Client(args.socket, is_json=args.is_json) if args.pyfile is None: qsh = sh.QSh(client) if args.command is not None: