"TODO: docstring"
from cStringIO import StringIO
+from threading import Thread
from Queue import Queue
from threading import Lock
from xml.etree import cElementTree as ET
+import logging
+logger = logging.getLogger('ncclient.glue')
def parse_root(raw):
'''Parse the top-level element from a string representing an XML document.
return (element.tag, element.attrib)
-class Subject(object):
+class Subject(Thread):
'Meant for subclassing by transport.Session'
def __init__(self):
"TODO: docstring"
+ Thread.__init__(self)
self._q = Queue()
- self._listeners = set()
+ self._listeners = set() # TODO(?) weakref
self._lock = Lock()
def _dispatch_received(self, raw):
with self._lock:
listeners = list(self._listeners)
for l in listeners:
+ logger.debug('[dispatching] message to %s' % l)
l.callback(root, raw)
def _dispatch_error(self, err):
with self._lock:
listeners = list(self._listeners)
for l in listeners:
+ logger.debug('[dispatching] error to %s' % l)
l.errback(err)
def add_listener(self, listener):
"TODO: docstring"
+ logger.debug('[installing listener] %r' % listener)
with self._lock:
self._listeners.add(listener)
def remove_listener(self, listener):
"TODO: docstring"
+ logger.debug('[discarding listener] %r' % listener)
with self._lock:
self._listeners.discard(listener)
def send(self, message):
"TODO: docstring"
- logger.debug('queueing:%s' % message)
+ logger.debug('[queueing] %s' % message)
self._q.put(message)
from threading import Event, Lock
from uuid import uuid1
+from weakref import WeakValueDictionary
-from ncclient.content import TreeBuilder, BASE_NS
+from ncclient.content import TreeBuilder
+from ncclient.content import qualify as _
+from ncclient.content import unqualify as __
from ncclient.glue import Listener
from . import logger
def __init__(self, session, async=False):
self._session = session
+ self._async = async
self._id = uuid1().urn
self._listener = RPCReplyListener(session)
self._listener.register(self._id, self)
def _request(self, op):
req = self._build(op)
self._session.send(req)
- if async:
+ if self._async:
self._reply_event.wait()
self._reply.parse()
return self._reply
def build_from_spec(msgid, opspec, encoding='utf-8'):
"TODO: docstring"
spec = {
- 'tag': _('rpc', BASE_NS),
+ 'tag': _('rpc'),
'attributes': {'message-id': msgid},
'children': opspec
}
def errback(self, err):
logger.error('RPCReplyListener.errback: %r' % err)
if self._errback is not None:
- self._errback(err)
\ No newline at end of file
+ self._errback(err)
self._session.expect_close()
self._session.close()
- def request(self, reply_event=None):
- self._request(self.spec, reply_event)
+ def request(self):
+ self._request(self.spec)
class KillSession(RPC):
def callback(self, root, raw):
if __(root[0]) == 'hello':
try:
- id, capabilities = parse(raw)
+ id, capabilities = HelloHandler.parse(raw)
except Exception as e:
self._error_cb(e)
else:
# See the License for the specific language governing permissions and
# limitations under the License.
-from threading import Thread, Event
+from threading import Event
from ncclient.capabilities import Capabilities, CAPABILITIES
from ncclient.glue import Subject
from . import logger
from hello import HelloHandler
-class Session(Thread, Subject):
+class Session(Subject):
"TODO: docstring"
def __init__(self):
"TODO: docstring"
Subject.__init__(self)
- Thread.__init__(self, name='session')
- self.setDaemon(True)
+ self.setName('session')
+ self.setDaemon(True) #hmm
self._client_capabilities = CAPABILITIES
self._server_capabilities = None # yet
self._id = None # session-id
self._connected = False # to be set/cleared by subclass implementation
+ logger.debug('[session object created] client_capabilities=%r' %
+ self._client_capabilities)
def _post_connect(self):
"TODO: docstring"
- self.send(HelloHandler.build(self._client_capabilities))
- error = None
init_event = Event()
+ error = [None] # so that err_cb can bind error[0]. just how it is.
# callbacks
def ok_cb(id, capabilities):
- self._id, self._server_capabilities = id, Capabilities(capabilities)
+ self._id = id
+ self._server_capabilities = Capabilities(capabilities)
init_event.set()
def err_cb(err):
- error = err
+ error[0] = err
init_event.set()
listener = HelloHandler(ok_cb, err_cb)
self.add_listener(listener)
- # start the subclass' main loop
+ self.send(HelloHandler.build(self._client_capabilities))
+ logger.debug('[starting main loop]')
self.start()
# we expect server's hello message
init_event.wait()
# received hello message or an error happened
self.remove_listener(listener)
- if error:
- raise error
+ if error[0]:
+ raise error[0]
logger.info('initialized: session-id=%s | server_capabilities=%s' %
- (self.id, self.server_capabilities))
+ (self._id, self._server_capabilities))
def connect(self, *args, **kwds):
"TODO: docstring"
self._transport = None
self._connected = False
self._channel = None
+ self._expecting_close = False
self._buffer = StringIO() # for incoming data
# parsing-related, see _parse()
self._parsing_state = 0
self._parsing_pos = 0
+ logger.debug('[SSHSession object created]')
def _parse(self):
'''Messages ae delimited by MSG_DELIM. The buffer could have grown by a
self._parsing_state = expect
self._parsing_pos = self._buffer.tell()
+ def expect_close(self):
+ self._expecting_close = True
+
def load_system_host_keys(self, filename=None):
if filename is None:
filename = os.path.expanduser('~/.ssh/known_hosts')
raise SessionCloseError(self._buffer.getvalue(), data)
data = data[n:]
except Exception as e:
- self.close()
logger.debug('*** broke out of main loop ***')
- self._dispatch_error(e)
+ self.close()
+ if not (isinstance(e, SessionCloseError) and self._expecting_close):
+ self._dispatch_error(e)
@property
def transport(self):
# See the License for the specific language governing permissions and
# limitations under the License.
-from . import logger
+from ncclient.glue import Listener
-class DebugListener:
+import logging
+logger = logging.getLogger('DebugListener')
+
+class DebugListener(Listener):
def __str__(self):
return 'DebugListener'
def received(self, raw):
- logger.debug('DebugListener:[received]:||%s||' % raw)
+ logger.debug('[received]:||%s||' % raw)
- def error(self, err):
- logger.debug('DebugListener:[error]:%r' % err)
+ def errback(self, err):
+ logger.debug('[error]:%r' % err)