@contextmanager<EOL><INDENT>def run(self):<DEDENT>
listener_thr = _spawn(self.receiver.run)<EOL>callback_thr = _spawn(self.callbacks.run)<EOL>sender_thr = _spawn(self.sender.run)<EOL>logger_thr = _spawn(self.logger.run)<EOL>self.connect()<EOL>try:<EOL><INDENT>yield<EOL><DEDENT>finally:<EOL><INDENT>self.stop()<EOL>listener_thr.join()<EOL>self.callbacks.put('<STR_LIT>')<EOL>for obj in [self.callbacks, self.sender, self.logger]:<EOL><INDENT>obj.stop()<EOL><DEDENT>for thr in [callback_thr, sender_thr, logger_thr]:<EOL><INDENT>thr.join()<EOL><DEDENT><DEDENT>
A context manager starting up threads to send and receive data from a
gateway and handle callbacks. Yields when a connection has been made,
and cleans up connections and threads when it's done.