Revision a14c36f9 ncclient/operations/rpc/listener.py

b/ncclient/operations/rpc/listener.py
11 11
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 12
# See the License for the specific language governing permissions and
13 13
# limitations under the License.
14

  
15
from threading import Lock
16
from weakref import WeakValueDictionary
17

  
18
from ncclient.glue import Listener
19
from ncclient.content import unqualify as __
20

  
21
import logging
22
logger = logging.getLogger('ncclient.rpc.listener')
23

  
24
class RPCReplyListener(Listener):
25
    
26
    # one instance per session
27
    def __new__(cls, session):
28
        instance = session.get_listener_instance(cls)
29
        if instance is None:
30
            instance = object.__new__(cls)
31
            instance._lock = Lock()
32
            instance._id2rpc = WeakValueDictionary()
33
            instance._pipelined = session.can_pipeline
34
            instance._errback = None
35
            session.add_listener(instance)
36
        return instance
37
    
38
    def register(self, id, rpc):
39
        with self._lock:
40
            self._id2rpc[id] = rpc
41
    
42
    def callback(self, root, raw):
43
        tag, attrs = root
44
        if __(tag) != 'rpc-reply':
45
            return
46
        rpc = None
47
        for key in attrs:
48
            if __(key) == 'message-id':
49
                id = attrs[key]
50
                try:
51
                    with self._lock:
52
                        rpc = self._id2rpc.pop(id)
53
                except KeyError:
54
                    logger.warning('no object registered for message-id: [%s]' % id)
55
                except Exception as e:
56
                    logger.debug('error - %r' % e)
57
                break
58
        else:
59
            if not self._pipelined:
60
                with self._lock:
61
                    assert(len(self._id2rpc) == 1)
62
                    rpc = self._id2rpc.values()[0]
63
                    self._id2rpc.clear()
64
            else:
65
                logger.warning('<rpc-reply> without message-id received: %s' % raw)
66
        logger.debug('delivering to %r' % rpc)
67
        rpc.deliver(raw)
68
    
69
    def set_errback(self, errback):
70
        self._errback = errback
71
    
72
    def errback(self, err):
73
        if self._errback is not None:
74
            self._errback(err)

Also available in: Unified diff