Revision 1d540e60

b/ncclient/glue.py
15 15
"TODO: docstring"
16 16

  
17 17
from cStringIO import StringIO
18
from threading import Thread
18 19
from Queue import Queue
19 20
from threading import Lock
20 21
from xml.etree import cElementTree as ET
21 22

  
23
import logging
24
logger = logging.getLogger('ncclient.glue')
22 25

  
23 26
def parse_root(raw):
24 27
    '''Parse the top-level element from a string representing an XML document.
......
32 35
        return (element.tag, element.attrib)
33 36

  
34 37

  
35
class Subject(object):
38
class Subject(Thread):
36 39
    
37 40
    'Meant for subclassing by transport.Session'
38 41

  
39 42
    def __init__(self):
40 43
        "TODO: docstring"
44
        Thread.__init__(self)
41 45
        self._q = Queue()
42
        self._listeners = set()
46
        self._listeners = set() # TODO(?) weakref
43 47
        self._lock = Lock()
44 48
    
45 49
    def _dispatch_received(self, raw):
......
48 52
        with self._lock:
49 53
            listeners = list(self._listeners)
50 54
        for l in listeners:
55
            logger.debug('[dispatching] message to %s' % l)
51 56
            l.callback(root, raw)
52 57
    
53 58
    def _dispatch_error(self, err):
......
55 60
        with self._lock:
56 61
            listeners = list(self._listeners)
57 62
        for l in listeners:
63
            logger.debug('[dispatching] error to %s' % l)
58 64
            l.errback(err)
59 65
    
60 66
    def add_listener(self, listener):
61 67
        "TODO: docstring"
68
        logger.debug('[installing listener] %r' % listener)
62 69
        with self._lock:
63 70
            self._listeners.add(listener)
64 71
    
65 72
    def remove_listener(self, listener):
66 73
        "TODO: docstring"
74
        logger.debug('[discarding listener] %r' % listener)
67 75
        with self._lock:
68 76
            self._listeners.discard(listener)
69 77
    
......
78 86
    
79 87
    def send(self, message):
80 88
        "TODO: docstring"
81
        logger.debug('queueing:%s' % message)
89
        logger.debug('[queueing] %s' % message)
82 90
        self._q.put(message)
83 91

  
84 92

  
b/ncclient/operations/rpc.py
14 14

  
15 15
from threading import Event, Lock
16 16
from uuid import uuid1
17
from weakref import WeakValueDictionary
17 18

  
18
from ncclient.content import TreeBuilder, BASE_NS
19
from ncclient.content import TreeBuilder
20
from ncclient.content import qualify as _
21
from ncclient.content import unqualify as __
19 22
from ncclient.glue import Listener
20 23

  
21 24
from . import logger
......
26 29
    
27 30
    def __init__(self, session, async=False):
28 31
        self._session = session
32
        self._async = async
29 33
        self._id = uuid1().urn
30 34
        self._listener = RPCReplyListener(session)
31 35
        self._listener.register(self._id, self)
......
41 45
    def _request(self, op):
42 46
        req = self._build(op)
43 47
        self._session.send(req)
44
        if async:
48
        if self._async:
45 49
            self._reply_event.wait()
46 50
            self._reply.parse()
47 51
            return self._reply
......
74 78
    def build_from_spec(msgid, opspec, encoding='utf-8'):
75 79
        "TODO: docstring"
76 80
        spec = {
77
            'tag': _('rpc', BASE_NS),
81
            'tag': _('rpc'),
78 82
            'attributes': {'message-id': msgid},
79 83
            'children': opspec
80 84
            }
......
132 136
    def errback(self, err):
133 137
        logger.error('RPCReplyListener.errback: %r' % err)
134 138
        if self._errback is not None:
135
            self._errback(err)
139
            self._errback(err)
b/ncclient/operations/session.py
30 30
            self._session.expect_close()
31 31
        self._session.close()
32 32
    
33
    def request(self, reply_event=None):
34
        self._request(self.spec, reply_event)
33
    def request(self):
34
        self._request(self.spec)
35 35

  
36 36

  
37 37
class KillSession(RPC):
b/ncclient/transport/hello.py
32 32
    def callback(self, root, raw):
33 33
        if __(root[0]) == 'hello':
34 34
            try:
35
                id, capabilities = parse(raw)
35
                id, capabilities = HelloHandler.parse(raw)
36 36
            except Exception as e:
37 37
                self._error_cb(e)
38 38
            else:
b/ncclient/transport/session.py
12 12
# See the License for the specific language governing permissions and
13 13
# limitations under the License.
14 14

  
15
from threading import Thread, Event
15
from threading import Event
16 16

  
17 17
from ncclient.capabilities import Capabilities, CAPABILITIES
18 18
from ncclient.glue import Subject
......
20 20
from . import logger
21 21
from hello import HelloHandler
22 22

  
23
class Session(Thread, Subject):
23
class Session(Subject):
24 24
    
25 25
    "TODO: docstring"
26 26
    
27 27
    def __init__(self):
28 28
        "TODO: docstring"
29 29
        Subject.__init__(self)
30
        Thread.__init__(self, name='session')
31
        self.setDaemon(True)
30
        self.setName('session')
31
        self.setDaemon(True) #hmm
32 32
        self._client_capabilities = CAPABILITIES
33 33
        self._server_capabilities = None # yet
34 34
        self._id = None # session-id
35 35
        self._connected = False # to be set/cleared by subclass implementation
36
        logger.debug('[session object created] client_capabilities=%r' %
37
                     self._client_capabilities)
36 38
    
37 39
    def _post_connect(self):
38 40
        "TODO: docstring"
39
        self.send(HelloHandler.build(self._client_capabilities))
40
        error = None
41 41
        init_event = Event()
42
        error = [None] # so that err_cb can bind error[0]. just how it is.
42 43
        # callbacks
43 44
        def ok_cb(id, capabilities):
44
            self._id, self._server_capabilities = id, Capabilities(capabilities)
45
            self._id = id
46
            self._server_capabilities = Capabilities(capabilities)
45 47
            init_event.set()
46 48
        def err_cb(err):
47
            error = err
49
            error[0] = err
48 50
            init_event.set()
49 51
        listener = HelloHandler(ok_cb, err_cb)
50 52
        self.add_listener(listener)
51
        # start the subclass' main loop
53
        self.send(HelloHandler.build(self._client_capabilities))
54
        logger.debug('[starting main loop]')
52 55
        self.start()
53 56
        # we expect server's hello message
54 57
        init_event.wait()
55 58
        # received hello message or an error happened
56 59
        self.remove_listener(listener)
57
        if error:
58
            raise error
60
        if error[0]:
61
            raise error[0]
59 62
        logger.info('initialized: session-id=%s | server_capabilities=%s' %
60
                     (self.id, self.server_capabilities))
63
                     (self._id, self._server_capabilities))
61 64
    
62 65
    def connect(self, *args, **kwds):
63 66
        "TODO: docstring"
b/ncclient/transport/ssh.py
37 37
        self._transport = None
38 38
        self._connected = False
39 39
        self._channel = None
40
        self._expecting_close = False
40 41
        self._buffer = StringIO() # for incoming data
41 42
        # parsing-related, see _parse()
42 43
        self._parsing_state = 0 
43 44
        self._parsing_pos = 0
45
        logger.debug('[SSHSession object created]')
44 46
    
45 47
    def _parse(self):
46 48
        '''Messages ae delimited by MSG_DELIM. The buffer could have grown by a
......
85 87
        self._parsing_state = expect
86 88
        self._parsing_pos = self._buffer.tell()
87 89
    
90
    def expect_close(self):
91
        self._expecting_close = True
92
    
88 93
    def load_system_host_keys(self, filename=None):
89 94
        if filename is None:
90 95
            filename = os.path.expanduser('~/.ssh/known_hosts')
......
266 271
                            raise SessionCloseError(self._buffer.getvalue(), data)
267 272
                        data = data[n:]
268 273
        except Exception as e:
269
            self.close()
270 274
            logger.debug('*** broke out of main loop ***')
271
            self._dispatch_error(e)
275
            self.close()
276
            if not (isinstance(e, SessionCloseError) and self._expecting_close):
277
                self._dispatch_error(e)
272 278
    
273 279
    @property
274 280
    def transport(self):
b/ncclient/transport/util.py
12 12
# See the License for the specific language governing permissions and
13 13
# limitations under the License.
14 14

  
15
from . import logger
15
from ncclient.glue import Listener
16 16

  
17
class DebugListener:
17
import logging
18
logger = logging.getLogger('DebugListener')
19

  
20
class DebugListener(Listener):
18 21
    
19 22
    def __str__(self):
20 23
        return 'DebugListener'
21 24
    
22 25
    def received(self, raw):
23
        logger.debug('DebugListener:[received]:||%s||' % raw)
26
        logger.debug('[received]:||%s||' % raw)
24 27
    
25
    def error(self, err):
26
        logger.debug('DebugListener:[error]:%r' % err)
28
    def errback(self, err):
29
        logger.debug('[error]:%r' % err)

Also available in: Unified diff