blob: 66de59ea2d74e595ab3834a243d4aa4b433e0ef5 [file] [log] [blame]
# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Classes and objects for the Servo Client API.
"""
import re
import xmlrpclib
DEFAULT_HOST = 'localhost'
DEFAULT_PORT = 9999
class ServoClientError(Exception):
"""Error class for ServoRequest"""
def __init__(self, text, xmlexc):
"""Constructor for ServoClientError Class
This class wraps xmlrpclib.Fault exceptions.
Args:
text: a string, error message generated by caller of exception handler
xmlexc: xmlrpclib.Fault object supplied by the caught exception. In some
cases is replaced with None and ignored.
xmlrpclib.Fault.faultString has the following format:
<type 'exception type'>:'actual error message'
we filter out the actual error message to make it available for the
downstream exception handler
"""
if xmlexc:
xml_error = re.sub('^.*>:', '', xmlexc.faultString)
err_match = re.match('No control named (\w+)', xml_error)
if err_match:
name = err_match.group(1)
error_msg = 'No control named "%s"\n' % name
# We know that the second line of the fault text is the comma
# separated list of all available controls. Let's try finding
# something similar to what user requested.
all_controls = xml_error.splitlines()[1]
candidates = [x for x in all_controls.split(',') if name in x]
if candidates:
error_msg += "Consider %s" % ' '.join(candidates)
else:
error_msg = xml_error
self.message = '%s :: %s' % (text, error_msg)
else:
self.message = text
class ServoClient(object):
"""Class to link client to servod via xmlrpc.
Beyond method initialize, the remaining methods (doc_all, doc, get, get_all,
set) have a corresponding method implmented in servod's server.
"""
def __init__(self, host=DEFAULT_HOST, port=DEFAULT_PORT, verbose=False):
"""Constructor for ServoClient Class
Args:
host: name or IP address of servo server host
port: TCP port on which servod is listening on
verbose: enable verbose messaging across xmlrpclib.ServerProxy
"""
self._verbose = verbose
remote = 'http://%s:%s' % (host, port)
self._server = xmlrpclib.ServerProxy(remote, verbose=self._verbose,
allow_none=True)
def doc_all(self):
"""Get the doc string for all controls from servo.
Returns:
string of all doc strings of controls from servo.
"""
return self._server.doc_all()
def doc(self, name):
"""Get the doc string from servo for control name.
Args:
name: string, name of control to retrieve doc string for.
Returns:
doc string for control name
Raises:
ServoClientError: If error occurs retrieving doc string.
"""
try:
return self._server.doc(name)
except xmlrpclib.Fault as e:
raise ServoClientError("Problem docstring '%s'" % name, e)
def get(self, name):
"""Get the value from servo for control name.
Args:
name: string, name of control to get value for.
Returns:
value currently set on control name
Raises:
ServoClientError: If error occurs getting value.
"""
try:
return self._server.get(name)
except xmlrpclib.Fault as e:
raise ServoClientError("Problem getting '%s'" % name, e)
def get_all(self):
"""Get all controls current values.
Returns:
String of all controls and their current values
"""
return self._server.get_all(self._verbose)
def set_get_all(self, controls):
"""Set &| get one or more control values.
Args:
controls: string, controls to set &| get.
Raises:
ServoClientError: If error occurs setting value.
"""
try:
rv = self._server.set_get_all(controls)
except xmlrpclib.Fault as e:
# TODO(tbroch) : more detail of failure. Note xmlrpclib only
# passes one exception above
raise ServoClientError("Problem with %s" % (controls), e)
return rv
def set(self, name, value):
"""Set the value from servo for control name.
Args:
name: string, name of control to set.
value: string, value to set control to.
Raises:
ServoClientError: If error occurs setting value.
"""
try:
self._server.set(name, value)
except xmlrpclib.Fault as e:
# TODO(tbroch) : more detail of failure. Note xmlrpclib only
# passes one exception above
raise ServoClientError("Problem setting '%s' to '%s'" %
(name, value), e)
def ftdii2c(self, args):
"""Calling a method of Fi2c."""
self._server.ftdii2c(args)
def hwinit(self):
"""Initialize the controls."""
self._server.hwinit()