Statistics
| Branch: | Tag: | Revision:

root / ncclient / session / session.py @ a956ef07

History | View | Annotate | Download (4.5 kB)

1
# Copyright 2009 Shikhar Bhushan
2
#
3
# Licensed under the Apache License, Version 2.0 (the "License");
4
# you may not use this file except in compliance with the License.
5
# You may obtain a copy of the License at
6
#
7
#    http://www.apache.org/licenses/LICENSE-2.0
8
#
9
# Unless required by applicable law or agreed to in writing, software
10
# distributed under the License is distributed on an "AS IS" BASIS,
11
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
# See the License for the specific language governing permissions and
13
# limitations under the License.
14

    
15
import logging
16
from threading import Thread, Event
17
from Queue import Queue
18

    
19
from capabilities import Capabilities, CAPABILITIES
20

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

    
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
35

    
36
class Session(Thread):
37
    
38
    def __init__(self):
39
        Thread.__init__(self, name='session')
40
        self._client_capabilities = CAPABILITIES
41
        self._server_capabilities = None # yet
42
        self._id = None # session-id
43
        self._q = Queue()
44
        self._connected = False # to be set/cleared by subclass implementation
45
        self._listeners = set(listeners)
46
        self._lock = Lock()
47
    
48
    def _post_connect(self):
49
        from ncclient.content.builders import HelloBuilder
50
        # queue client's hello message for sending
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
69
        self.remove_listener(listener)
70
        if self._error:
71
            self._close()
72
            raise self._error
73
    
74
    def send(self, message):
75
        logger.debug('queueing message: \n%s' % message)
76
        self._q.put(message)
77
    
78
    def connect(self):
79
        raise NotImplementedError
80

    
81
    def run(self):
82
        raise NotImplementedError
83
        
84
    def capabilities(self, whose='client'):
85
        if whose == 'client':
86
            return self._client_capabilities
87
        elif whose == 'server':
88
            return self._server_capabilities
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
    
116
    ### Properties
117
    
118
    @property
119
    def client_capabilities(self):
120
        return self._client_capabilities
121
    
122
    @property
123
    def server_capabilities(self):
124
        return self._server_capabilities
125
    
126
    @property
127
    def connected(self):
128
        return self._connected
129
    
130
    @property
131
    def id(self):
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)