Revision a956ef07 ncclient/session/session.py

b/ncclient/session/session.py
16 16
from threading import Thread, Event
17 17
from Queue import Queue
18 18

  
19
import content
20 19
from capabilities import Capabilities, CAPABILITIES
21
from error import ClientError
22
from listeners import HelloListener
23
from subject import Subject
24 20

  
25
logger = logging.getLogger('ncclient.session')
21
logger = logging.getLogger('ncclient.session.session')
26 22

  
27
class SessionError(ClientError): pass
23
class SessionError(Exception):
24
    
25
    pass
26

  
27
class SessionCloseError(SessionError):
28
    
29
    def __str__(self):
30
        return 'RECEIVED: %s | UNSENT: %s' % (self._in_buf, self._out_buf)
31
    
32
    def __init__(self, in_buf, out_buf=None):
33
        SessionError.__init__(self)
34
        self._in_buf, self._out_buf = in_buf, out_buf
28 35

  
29
class Session(Thread, Subject):
36
class Session(Thread):
30 37
    
31 38
    def __init__(self):
32 39
        Thread.__init__(self, name='session')
33
        Subject.__init__(self)
34 40
        self._client_capabilities = CAPABILITIES
35 41
        self._server_capabilities = None # yet
36 42
        self._id = None # session-id
37
        self._error = None
38
        self._init_event = Event()
39 43
        self._q = Queue()
40 44
        self._connected = False # to be set/cleared by subclass implementation
45
        self._listeners = set(listeners)
46
        self._lock = Lock()
41 47
    
42 48
    def _post_connect(self):
43
        # start the subclass' main loop
44
        listener = HelloListener(self)
45
        self.add_listener(listener)
46
        self.start()
49
        from ncclient.content.builders import HelloBuilder
47 50
        # queue client's hello message for sending
48
        self.send(content.Hello.build(self._client_capabilities))
49
        # we expect server's hello message, wait for _init_event to be set
50
        self._init_event.wait()
51
        self.send(HelloBuilder.build(self._client_capabilities))
52
        
53
        error = None
54
        proceed = Event()
55
        def ok_cb(id, capabilities):
56
            self._id, self._capabilities = id, Capabilities(capabilities)
57
            proceed.set()
58
        def err_cb(err):
59
            error = err
60
            proceed.set()
61
        listener = HelloListener(ok_cb, err_cb)
62
        self.add_listener(listener)
63
        
64
        # start the subclass' main loop
65
        self.start()        
66
        # we expect server's hello message
67
        proceed.wait()
68
        # received hello message or an error happened
51 69
        self.remove_listener(listener)
52
        # there may have been an error
53 70
        if self._error:
54 71
            self._close()
55 72
            raise self._error
56 73
    
57
    def hello(self, id, capabilities):
58
        self._id, self._capabilities = id, Capabilities(capabilities)
59
        self._init_event.set()
60
    
61
    def hello_error(self, err):
62
        self._error = err
63
        self._init_event.set()
64
    
65 74
    def send(self, message):
66 75
        logger.debug('queueing message: \n%s' % message)
67 76
        self._q.put(message)
......
78 87
        elif whose == 'server':
79 88
            return self._server_capabilities
80 89
    
90
    ### Session is a subject for arbitary listeners
91
    
92
    def has_listener(self, listener):
93
        with self._lock:
94
            return (listener in self._listeners)
95
    
96
    def add_listener(self, listener):
97
        with self._lock:
98
            self._listeners.add(listener)
99
    
100
    def remove_listener(self, listener):
101
        with self._lock:
102
            self._listeners.discard(listener)
103
    
104
    def dispatch(self, event, *args, **kwds):
105
        # holding the lock while doing callbacks could lead to a deadlock
106
        # if one of the above methods is called
107
        with self._lock:
108
            listeners = list(self._listeners)
109
        for l in listeners:
110
            try:
111
                logger.debug('dispatching [%s] to [%s]' % (event, l))
112
                getattr(l, event)(*args, **kwds)
113
            except Exception as e:
114
                logger.warning(e)
115
    
81 116
    ### Properties
82 117
    
83 118
    @property
......
95 130
    @property
96 131
    def id(self):
97 132
        return self._id
133

  
134

  
135
class HelloListener:
136
    
137
    def __init__(self, init_cb, error_cb):
138
        self._init_cb, self._error_cb = reply_cb, error_cb
139
    
140
    def __str__(self):
141
        return 'HelloListener'
142
    
143
    ### Events
144
    
145
    def reply(self, raw):
146
        from ncclient.content.parsers import HelloParser
147
        try:
148
            id, capabilities = HelloParser.parse(raw)
149
        except Exception as e:
150
            self._error_cb(e)
151
        else:
152
            self._init_cb(id, capabilities)
153
    
154
    def error(self, err):
155
        self._error_cb(err)

Also available in: Unified diff