def connect(self): _logger.debug('[%s]: Opening new connection to "%s"' % (CLIENT, str(self._host))) stream = yield self._job_client.connect(self._host, self._port, ssl_options=self._ssl_options) self._connection = TCPConnection(stream, self._host, SERVER, on_close_callback=self.shutdown) _logger.info('[%s]: Connected to "%s"' % (CLIENT, str(self._host)))
class JobHandler(object): def __init__(self, host, port, verbose, auth_key, ssl_options): self._host = host self._port = port self._verbose = verbose self._auth_key = auth_key self._ssl_options = ssl_options self._connection = None self._job_client = JobTCPClient() @gen.coroutine def connect(self): _logger.debug('[%s]: Opening new connection to "%s"' % (CLIENT, str(self._host))) stream = yield self._job_client.connect(self._host, self._port, ssl_options=self._ssl_options) self._connection = TCPConnection(stream, self._host, SERVER, on_close_callback=self.shutdown) _logger.info('[%s]: Connected to "%s"' % (CLIENT, str(self._host))) @gen.coroutine def receive_greeting(self): data = json.loads((yield self._connection.read_message()).rstrip()) if not Reply.is_valid(data): raise Exception("Invalid reply!") reply = Reply(data[Reply.KEY_RESULT], data[Reply.KEY_MSG]) if not reply.result: _logger.error("[%s]: %s" % (SERVER, reply.msg)) raise Exception("Greeting failed!") _logger.info('[%s]: "%s"' % (SERVER, reply.msg)) @gen.coroutine def authenticate(self): _logger.debug('[%s]: Start authentication' % CLIENT) request = Request(Request.Command.AUTH, {Request.ARGS_AUTH_KEY: self._auth_key}) yield self._connection.send_message( request, logging_enabled=False) # do not log key! data = json.loads((yield self._connection.read_message()).rstrip()) if not Reply.is_valid(data): raise Exception("Invalid reply!") reply = Reply(data[Reply.KEY_RESULT], data[Reply.KEY_MSG]) if not reply.result: _logger.error("[%s]: %s" % (SERVER, reply.msg)) raise Exception("Authentication failed!") _logger.info('[%s]: "%s"' % (SERVER, reply.msg)) @gen.coroutine def send_job_started_notification(self, job_ID, title, image_URL): _logger.debug('[%s]: Sending job started notification' % CLIENT) args = { Request.ARGS_JOB_ID: job_ID, Request.ARGS_IMAGE_URL: image_URL, Request.ARGS_TITLE: json_encode(title)[1:-1], Request.ARGS_MSG: "Job started" } request = Request(Request.Command.JOB_STARTED_NOTIFICATION, args) yield self._connection.send_message(request) # Job started (reply) data = json.loads((yield self._connection.read_message()).rstrip()) if not Reply.is_valid(data): raise Exception("Invalid reply!") reply = Reply(data[Reply.KEY_RESULT], data[Reply.KEY_MSG]) if not reply.result: _logger.error("[%s]: %s" % (SERVER, reply.msg)) raise Exception("Job started notification failed!") _logger.info('[%s]: "%s"' % (SERVER, reply.msg)) @gen.coroutine def send_job_progress_notification(self, job_ID, progress): # Job progress (request) if not isinstance(progress, int): _logger.warn("[{}]: Cannot send progress notification! Given progress is "\ "no valid int: '{}'".format(CLIENT, progress)) return _logger.debug('[%s]: (%d%%) Sending job progress notification' % (CLIENT, progress)) args = {Request.ARGS_JOB_ID: job_ID, Request.ARGS_PROGRESS: progress} yield self._connection.send_message( Request(Request.Command.JOB_PROGRESS_NOTIFICATION, args)) # # Job progress (reply) # data = json.loads((yield self._connection.read_message()).rstrip()) # if not Reply.is_valid(data): # raise Exception("Invalid reply!") # reply = Reply(data[Reply.KEY_RESULT], data[Reply.KEY_MSG]) # if not reply.result: # _logger.error("[%s]: %s" % (SERVER, reply.msg)) # raise Exception("Job progress notification failed!") # _logger.info('[%s]: "%s"' % (SERVER, reply.msg)) @gen.coroutine def send_job_output_notification(self, job_ID, messages): # Job output (request) assert isinstance(messages, list) messages = map(lambda message: message.replace('"', ''), messages) _logger.debug('[%s]: Sending job output notification: %s' % (CLIENT, "\n".join(messages))) args = {Request.ARGS_JOB_ID: job_ID, Request.ARGS_LINES: messages} yield self._connection.send_message( Request(Request.Command.JOB_OUTPUT_NOTIFICATION, args)) # # Job output (reply) # data = json.loads((yield self._connection.read_message()).rstrip()) # if not Reply.is_valid(data): # raise Exception("Invalid reply!") # reply = Reply(data[Reply.KEY_RESULT], data[Reply.KEY_MSG]) # if not reply.result: # _logger.error("[%s]: %s" % (SERVER, reply.msg)) # raise Exception("Job output notification failed!") # _logger.info('[%s]: "%s"' % (SERVER, reply.msg)) @gen.coroutine def send_job_conversion_finished_notification(self, job_ID, exit_code): # Job finished (request) _logger.debug('[%s]: Sending job finished notification' % CLIENT) args = { Request.ARGS_JOB_ID: job_ID, Request.ARGS_RESULT: exit_code, Request.ARGS_MSG: "Job finished" } yield self._connection.send_message( Request(Request.Command.JOB_CONVERSION_FINISHED_NOTIFICATION, args)) # Job finished (reply) data = json.loads((yield self._connection.read_message()).rstrip()) if not Reply.is_valid(data): raise Exception("Invalid reply!") reply = Reply(data[Reply.KEY_RESULT], data[Reply.KEY_MSG]) if not reply.result: _logger.error("[%s]: %s" % (SERVER, reply.msg)) raise Exception("Job finished notification failed!") _logger.info('[%s]: "%s"' % (SERVER, reply.msg)) @gen.coroutine def pre_processing(self, args): pass # optional => you may implement this in your subclass @gen.coroutine def run_job(self, args): raise Exception( "FAILED!!! You MUST implement this method in the subclass.") @gen.coroutine def post_processing(self, args): pass # optional => you may implement this in your subclass def shutdown(self): pass # optional => you may implement this in your subclass @gen.coroutine def handle_exception(self, msg): _logger.exception("{}!".format(msg)) self._connection.print_error_and_close_stream() @gen.coroutine def run(self, args): # (I) Connect to server try: yield self.connect() except: self.handle_exception("Cannot connect to server") return # (II) Receive greeting try: yield self.receive_greeting() except: self.handle_exception("Unable to receive greeting") return # (III) Authentication try: yield self.authenticate() except: self.handle_exception("Authentication failed") return # (IV) Pre processing try: yield self.pre_processing(args) except: self.handle_exception("Pre processing failed...") return # (V) Run job try: yield self.run_job(args) except: self.handle_exception("Unable to run job") return # (VI) Post processing (e.g. file transfer, send email, ...) try: yield self.post_processing(args) except: self.handle_exception("Post processing failed...") return # (VII) Shutdown Job Handler self.shutdown()
class JobHandler(object): def __init__(self, host, port, verbose, auth_key, ssl_options): self._host = host self._port = port self._verbose = verbose self._auth_key = auth_key self._ssl_options = ssl_options self._connection = None self._job_client = JobTCPClient() @gen.coroutine def connect(self): _logger.debug('[%s]: Opening new connection to "%s"' % (CLIENT, str(self._host))) stream = yield self._job_client.connect(self._host, self._port, ssl_options=self._ssl_options) self._connection = TCPConnection(stream, self._host, SERVER, on_close_callback=self.shutdown) _logger.info('[%s]: Connected to "%s"' % (CLIENT, str(self._host))) @gen.coroutine def receive_greeting(self): data = json.loads((yield self._connection.read_message()).rstrip()) if not Reply.is_valid(data): raise Exception("Invalid reply!") reply = Reply(data[Reply.KEY_RESULT], data[Reply.KEY_MSG]) if not reply.result: _logger.error("[%s]: %s" % (SERVER, reply.msg)) raise Exception("Greeting failed!") _logger.info('[%s]: "%s"' % (SERVER, reply.msg)) @gen.coroutine def authenticate(self): _logger.debug('[%s]: Start authentication' % CLIENT) request = Request(Request.Command.AUTH, { Request.ARGS_AUTH_KEY: self._auth_key}) yield self._connection.send_message(request, logging_enabled=False) # do not log key! data = json.loads((yield self._connection.read_message()).rstrip()) if not Reply.is_valid(data): raise Exception("Invalid reply!") reply = Reply(data[Reply.KEY_RESULT], data[Reply.KEY_MSG]) if not reply.result: _logger.error("[%s]: %s" % (SERVER, reply.msg)) raise Exception("Authentication failed!") _logger.info('[%s]: "%s"' % (SERVER, reply.msg)) @gen.coroutine def send_job_started_notification(self, job_ID, title, image_URL): _logger.debug('[%s]: Sending job started notification' % CLIENT) args = { Request.ARGS_JOB_ID: job_ID, Request.ARGS_IMAGE_URL: image_URL, Request.ARGS_TITLE: title, Request.ARGS_MSG: "Job started" } request = Request(Request.Command.JOB_STARTED_NOTIFICATION, args) yield self._connection.send_message(request) # Job started (reply) data = json.loads((yield self._connection.read_message()).rstrip()) if not Reply.is_valid(data): raise Exception("Invalid reply!") reply = Reply(data[Reply.KEY_RESULT], data[Reply.KEY_MSG]) if not reply.result: _logger.error("[%s]: %s" % (SERVER, reply.msg)) raise Exception("Job started notification failed!") _logger.info('[%s]: "%s"' % (SERVER, reply.msg)) @gen.coroutine def send_job_progress_notification(self, job_ID, progress): # Job progress (request) if not isinstance(progress, int): _logger.warn("[{}]: Cannot send progress notification! Given progress is "\ "no valid int: '{}'".format(CLIENT, progress)) return _logger.debug('[%s]: (%d%%) Sending job progress notification' % (CLIENT, progress)) args = { Request.ARGS_JOB_ID: job_ID, Request.ARGS_PROGRESS: progress } yield self._connection.send_message(Request(Request.Command.JOB_PROGRESS_NOTIFICATION, args)) # # Job progress (reply) # data = json.loads((yield self._connection.read_message()).rstrip()) # if not Reply.is_valid(data): # raise Exception("Invalid reply!") # reply = Reply(data[Reply.KEY_RESULT], data[Reply.KEY_MSG]) # if not reply.result: # _logger.error("[%s]: %s" % (SERVER, reply.msg)) # raise Exception("Job progress notification failed!") # _logger.info('[%s]: "%s"' % (SERVER, reply.msg)) @gen.coroutine def send_job_output_notification(self, job_ID, messages): # Job output (request) assert isinstance(messages, list) messages = map(lambda message: message.replace('"', ''), messages) _logger.debug('[%s]: Sending job output notification: %s' % (CLIENT, "\n".join(messages))) args = { Request.ARGS_JOB_ID: job_ID, Request.ARGS_LINES: messages } yield self._connection.send_message(Request(Request.Command.JOB_OUTPUT_NOTIFICATION, args)) # # Job output (reply) # data = json.loads((yield self._connection.read_message()).rstrip()) # if not Reply.is_valid(data): # raise Exception("Invalid reply!") # reply = Reply(data[Reply.KEY_RESULT], data[Reply.KEY_MSG]) # if not reply.result: # _logger.error("[%s]: %s" % (SERVER, reply.msg)) # raise Exception("Job output notification failed!") # _logger.info('[%s]: "%s"' % (SERVER, reply.msg)) @gen.coroutine def send_job_conversion_finished_notification(self, job_ID, exit_code): # Job finished (request) _logger.debug('[%s]: Sending job finished notification' % CLIENT) args = { Request.ARGS_JOB_ID: job_ID, Request.ARGS_RESULT: exit_code, Request.ARGS_MSG: "Job finished" } yield self._connection.send_message(Request(Request.Command.JOB_CONVERSION_FINISHED_NOTIFICATION, args)) # Job finished (reply) data = json.loads((yield self._connection.read_message()).rstrip()) if not Reply.is_valid(data): raise Exception("Invalid reply!") reply = Reply(data[Reply.KEY_RESULT], data[Reply.KEY_MSG]) if not reply.result: _logger.error("[%s]: %s" % (SERVER, reply.msg)) raise Exception("Job finished notification failed!") _logger.info('[%s]: "%s"' % (SERVER, reply.msg)) @gen.coroutine def pre_processing(self, args): pass # optional => you may implement this in your subclass @gen.coroutine def run_job(self, args): raise Exception("FAILED!!! You MUST implement this method in the subclass.") @gen.coroutine def post_processing(self, args): pass # optional => you may implement this in your subclass def shutdown(self): pass # optional => you may implement this in your subclass @gen.coroutine def handle_exception(self, msg): _logger.exception("{}!".format(msg)) self._connection.print_error_and_close_stream() @gen.coroutine def run(self, args): # (I) Connect to server try: yield self.connect() except: self.handle_exception("Cannot connect to server") return # (II) Receive greeting try: yield self.receive_greeting() except: self.handle_exception("Unable to receive greeting") return # (III) Authentication try: yield self.authenticate() except: self.handle_exception("Authentication failed") return # (IV) Pre processing try: yield self.pre_processing(args) except: self.handle_exception("Pre processing failed...") return # (V) Run job try: yield self.run_job(args) except: self.handle_exception("Unable to run job") return # (VI) Post processing (e.g. file transfer, send email, ...) try: yield self.post_processing(args) except: self.handle_exception("Post processing failed...") return # (VII) Shutdown Job Handler self.shutdown()
def handle_stream(self, stream, address): self.streams[stream] = time.time() conn = TCPConnection(stream, address, CLIENT) handler = TCPConnectionHandler(self, conn) yield handler.run()