Skip to content

Commit

Permalink
I added data type(json) for client communicate easily with qtile server.
Browse files Browse the repository at this point in the history
Closes #868
  • Loading branch information
sux2mfgj authored and flacjacket committed Feb 29, 2016
1 parent 7a6e035 commit a3cbb1f
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 13 deletions.
4 changes: 2 additions & 2 deletions libqtile/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
44 changes: 34 additions & 10 deletions libqtile/ipc.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import socket
import struct
import fcntl
import json

from . import asyncio

Expand All @@ -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!"
Expand All @@ -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))
Expand All @@ -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:
Expand All @@ -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:
Expand All @@ -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))
Expand Down Expand Up @@ -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:
Expand All @@ -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')
Expand Down
9 changes: 8 additions & 1 deletion libqtile/scripts/qsh.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down

0 comments on commit a3cbb1f

Please sign in to comment.