+def ParseRequest(msg):
+ """Parses a LUXI request message.
+
+ """
+ try:
+ request = serializer.LoadJson(msg)
+ except ValueError, err:
+ raise ProtocolError("Invalid LUXI request (parsing error): %s" % err)
+
+ logging.debug("LUXI request: %s", request)
+
+ if not isinstance(request, dict):
+ logging.error("LUXI request not a dict: %r", msg)
+ raise ProtocolError("Invalid LUXI request (not a dict)")
+
+ method = request.get(KEY_METHOD, None) # pylint: disable=E1103
+ args = request.get(KEY_ARGS, None) # pylint: disable=E1103
+ version = request.get(KEY_VERSION, None) # pylint: disable=E1103
+
+ if method is None or args is None:
+ logging.error("LUXI request missing method or arguments: %r", msg)
+ raise ProtocolError(("Invalid LUXI request (no method or arguments"
+ " in request): %r") % msg)
+
+ return (method, args, version)
+
+
+def ParseResponse(msg):
+ """Parses a LUXI response message.
+
+ """
+ # Parse the result
+ try:
+ data = serializer.LoadJson(msg)
+ except KeyboardInterrupt:
+ raise
+ except Exception, err:
+ raise ProtocolError("Error while deserializing response: %s" % str(err))
+
+ # Validate response
+ if not (isinstance(data, dict) and
+ KEY_SUCCESS in data and
+ KEY_RESULT in data):
+ raise ProtocolError("Invalid response from server: %r" % data)
+
+ return (data[KEY_SUCCESS], data[KEY_RESULT],
+ data.get(KEY_VERSION, None)) # pylint: disable=E1103
+
+
+def FormatResponse(success, result, version=None):
+ """Formats a LUXI response message.
+
+ """
+ response = {
+ KEY_SUCCESS: success,
+ KEY_RESULT: result,
+ }
+
+ if version is not None:
+ response[KEY_VERSION] = version
+
+ logging.debug("LUXI response: %s", response)
+
+ return serializer.DumpJson(response)
+
+
+def FormatRequest(method, args, version=None):
+ """Formats a LUXI request message.
+
+ """
+ # Build request
+ request = {
+ KEY_METHOD: method,
+ KEY_ARGS: args,
+ }
+
+ if version is not None:
+ request[KEY_VERSION] = version
+
+ # Serialize the request
+ return serializer.DumpJson(request)
+
+
+def CallLuxiMethod(transport_cb, method, args, version=None):
+ """Send a LUXI request via a transport and return the response.
+
+ """
+ assert callable(transport_cb)
+
+ request_msg = FormatRequest(method, args, version=version)
+
+ # Send request and wait for response
+ response_msg = transport_cb(request_msg)
+
+ (success, result, resp_version) = ParseResponse(response_msg)
+
+ # Verify version if there was one in the response
+ if resp_version is not None and resp_version != version:
+ raise errors.LuxiError("LUXI version mismatch, client %s, response %s" %
+ (version, resp_version))
+
+ if success:
+ return result
+
+ errors.MaybeRaise(result)
+ raise RequestError(result)
+
+