Esempio n. 1
0
 def __init__(self):
     self.parser = MessageParser()
     self.queries = []
Esempio n. 2
0
class KatCP(LineReceiver):
    """ A base class for protocol implementation of KatCP on top of twisted
    infrastructure. Specific subclasses provide client and server parts
    (which are not shared).
    """

    delimiter = '\n'
    MAX_LENGTH = 64*(2**20) # 64 MB should be fine

    def __init__(self):
        self.parser = MessageParser()
        self.queries = []

    def send_request(self, name, *args):
        if not self.transport.connected:
            raise DeviceNotConnected()
        d = Deferred()
        self.send_message(Message.request(name, *args))
        self.queries.append((name, d, []))
        return d

    def dataReceived(self, data):
        # translate '\r' into '\n'
        return LineReceiver.dataReceived(self, data.replace('\r', '\n'))

    def lineReceived(self, line):
        if not line:
            return
        msg = self.parser.parse(line)
        if msg.mtype == msg.INFORM:
            self.handle_inform(msg)
        elif msg.mtype == msg.REPLY:
            self.handle_reply(msg)
        elif msg.mtype == msg.REQUEST:
            self.handle_request(msg)
        else:
            assert False # this could never happen since parser should complain

    # some default informs
    def inform_version(self, msg):
        if msg.arguments:
            self.version = msg.arguments[0]

    def inform_build_state(self, msg):
        if msg.arguments:
            self.build_state = msg.arguments[0]

    def inform_disconnect(self, args):
        pass # unnecessary, we have a callback on loseConnection

    def handle_inform(self, msg):
        # if we have a request being processed, store all the informs
        # in a list of stuff to process
        name = msg.name
        name = name.replace('-', '_')
        meth = getattr(self, 'inform_' + name, None)
        if meth is not None:
            meth(msg)
        elif self.queries:
            name, d, queue = self.queries[0]
            if name != msg.name:
                return # instead of raising WrongQueryOrder, we discard informs
                       # that we don't know about
            queue.append(msg) # unespace?
        else:
            raise UnhandledMessage(msg)

    def handle_request(self, msg):
        name = msg.name
        name = name.replace('-', '_')
        try:
            rep_msg = getattr(self, 'request_' + name, self._request_unknown)(msg)
            if not isinstance(rep_msg, Message):
                raise ShouldReturnMessage('request_' + name + ' should return a'
                                          'message or raise AsyncReply, instead'
                                          'it returned %r' % rep_msg)
            self.send_message(rep_msg)
        except FailReply, fr:
            self.send_message(Message.reply(name, "fail", str(fr)))
        except AsyncReply:
            return