Permalink
Browse files

Converted the bare responses (status, etc) into json strings.

  • Loading branch information...
1 parent 0f6b490 commit d01a17503faa98fe51297e3278ab62680784433a @foucault committed Aug 26, 2011
Showing with 49 additions and 30 deletions.
  1. +15 −9 README.md
  2. +34 −21 pkgupdate_server.py
View
@@ -32,35 +32,41 @@ It can be safely backgrounded if you want. After the daemon is started
you may check it out with `pkgupdate_conky.py`. This should return a conky
formatted string (use with `${execp}` or `${execpi}`) with the number
of updates in `repos+AUR` format or `OK` otherwise. The conky client output
-can be customized more if you want; `pkgupdate_conky.py -?` for more
+can be customized more if you want; `pkgupdate_conky.py --help` for more
details.
Communicating
-------------
Interacting with the server is pretty easy, but the protocol is long way
from being finalized. Communication is done via a UNIX socket named
`\0PkgUpdateSocket`. Maybe in the near future the socket name will be
-configurable. The available "commands" are listed below.
+configurable.
Please note that all commands should be sent encoded in utf-8 and
__must be terminated with `\r\n`__. If you do not terminate your command and
the input buffer gets over the threshold the connection will be terminated
-and `OVFLO` will be sent to the client.
-All responses are encoded in utf-8 as well.
+and `{'error':'OVFLO'}` will be sent to the client.
+All responses are json objects encoded in utf-8 as well and fall into three
+main categories
-`nudge`: This just pings the server. Returns `OK` if the server is up.
+* Successful queries return `{'ack':'OK',<rest of data here>}`.
+* Failed queries return `{'error':'<error message here>'}`.
+* Status queries return `{'status':'<status here>'}`.
+
+The available commands are:
+`nudge`: This just pings the server. Returns `{'ack':'OK'}` if the server is up.
`force_upd <SERVICE_ID>`: This forces the server to poll the specified action
for updates. Without arguments it polls alpm for non-foreign package updates.
`force_upd_all`: Force all registered actions for updates.
-`status`: Returns `WORKING` when a background thread is working. Returns
-`IDLE` otherwise.
+`status`: Returns `{'status':'WORKING'}` when a background thread is working.
+Returns `{'status':'IDLE'}` otherwise.
`normal`: This returns all available updates as a JSON utf-8 byte-encoded
string formatted as:
- {'repos':[{'name':PKG_NAME1,'version':PKG_VRS1},...],
+ {'ack':'OK','repos':[{'name':PKG_NAME1,'version':PKG_VRS1},...],
'aur':[{'name':PKG_NAME1,'version':PKG_VRS1},...]}
The `'aur'` line appears only if the server has been started with the `-a`
option. The `pkgupdate.rc` does that by default.
@@ -80,7 +86,7 @@ library (in this case `./libs`).
Bugs
----
-If you have discovered a bug, which is quite likely at the moment, please
+If you have discovered a bug, which is quite likely, please
open an issue ticket. If you have a solution for that bug (even better) send
in a pull request.
View
@@ -322,11 +322,15 @@ class ServerHandler(asynchat.async_chat):
requested data back to the client
"""
- MAX_MSG_LENGTH = 16384
+ MAX_MSG_LENGTH = 512
+ RESP_ACK = 'ack'
+ RESP_ERR = 'error'
+ RESP_STA = 'status'
def __init__(self, sock, services):
asynchat.async_chat.__init__(self,sock)
self.ibuffer = []
+ self.isize = 0
#self.services = services
self.services = dict()
for service in services:
@@ -354,13 +358,15 @@ def ibufsize(self):
def collect_incoming_data(self, data):
self.ibuffer.append(data)
+ self.isize += len(data)
LOG.debug("Collecting client data")
# Do not buffer unlimited data
- if(self.ibufsize() > self.MAX_MSG_LENGTH):
+ if(self.isize > self.MAX_MSG_LENGTH):
del self.ibuffer[:]
- LOG.warning("Input exceeded %d bytes; sending OVFLO to client"\
+ LOG.warning("Input length exceeded %d; sending OVFLO to client"\
%self.MAX_MSG_LENGTH)
- self.push(b'OVFLO')
+ msg = {self.RESP_ERR:'OVFLO'}
+ self.push(json.dumps(msg).encode('UTF-8'))
self.close_when_done()
def close_me(f):
@@ -375,40 +381,41 @@ def inner(f):
return f
return inner
- @close_me
@syntax('nudge')
+ @close_me
def nudge(self):
- self.push(b'OK')
+ self.push(json.dumps({self.RESP_ACK:'OK'}).encode("UTF-8"))
- @close_me
@syntax('force_upd <SERVICE_ID>=repos')
+ @close_me
def force_upd(self, aid='repos'):
LOG.info("Forcing update")
service = self.service_by_id(aid)
if service is not None:
service.force_update()
else:
- self.push(b"No such service")
+ self.push(json.dumps({self.RESP_ERR:\
+ 'No such service'%aid}).encode('UTF-8'))
- @close_me
@syntax('force_upd_all')
+ @close_me
def force_upd_all(self):
LOG.info("Forcing update (all)")
for service in self.servicess:
services.force_update()
- @close_me
@syntax('status')
+ @close_me
def status(self):
LOG.debug("Status check")
- working = any( service.working for service in self.services )
+ working = any(self.services[key].working for key in self.services.keys())
if working:
- self.push(b"WORKING")
+ self.push(json.dumps({self.RESP_STA:'WORKING'}).encode('UTF-8'))
else:
- self.push(b"IDLE")
+ self.push(json.dumps({self.RESP_STA:'IDLE'}).encode('UTF-8'))
- @close_me
@syntax('normal')
+ @close_me
def default(self, service="*"):
data = dict()
service = service.strip()
@@ -423,6 +430,7 @@ def default(self, service="*"):
if value is not None: # Not all services return data
LOG.info("Client requested data from service '%s'"%service)
data[service] = value
+ data[self.RESP_ACK] = 'OK'
resp = (json.dumps(data)).encode('UTF-8')
self.push(resp)
@@ -433,18 +441,19 @@ def found_terminator(self):
args = parts[1:]
LOG.debug("Command: %s - Args: %s"%(command, args))
del self.ibuffer[:] # clear the buffer
+ self.isize = 0
try:
if command in self.mapper.keys():
self.mapper[command](*args)
else:
- msg = "Unknown command %s"%command
- self.push(msg.encode())
+ msg = {self.RESP_ERR:"Unknown command %s"%command}
+ self.push(json.dumps(msg).encode('UTF-8'))
self.close_when_done()
except TypeError as exc:
- msg = "Incorrect syntax for command %s\n try: %s"%\
- (command, command.syntax)
- LOG.debug(msg)
- self.push(msg.encode())
+ msg = {self.RESP_ERR:"Incorrect syntax for command %s\n try: %s"%\
+ (command, self.mapper[command].syntax)}
+ LOG.debug(exc)
+ self.push(json.dumps(msg).encode('UTF-8'))
self.close_when_done()
LOG.debug("Connection terminated")
@@ -542,7 +551,11 @@ def get_options_parser():
sock.send("status\r\n".encode('utf-8'))
status = sock.recv(150).decode()
sock.close()
- print(status)
+ ret = json.loads(status)
+ if('error' in ret.keys()):
+ LOG.critical(ret['error'])
+ sys.exit(1)
+ print(ret['status'])
sys.exit(0)
except Exception as exc:
LOG.critical(exc)

0 comments on commit d01a175

Please sign in to comment.