Mercurial > libervia-backend
diff sat_frontends/jp/cmd_message.py @ 3040:fee60f17ebac
jp: jp asyncio port:
/!\ this commit is huge. Jp is temporarily not working with `dbus` bridge /!\
This patch implements the port of jp to asyncio, so it is now correctly using the bridge
asynchronously, and it can be used with bridges like `pb`. This also simplify the code,
notably for things which were previously implemented with many callbacks (like pagination
with RSM).
During the process, some behaviours have been modified/fixed, in jp and backends, check
diff for details.
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 25 Sep 2019 08:56:41 +0200 |
parents | ab2696e34d29 |
children | 9d0df638c8b4 |
line wrap: on
line diff
--- a/sat_frontends/jp/cmd_message.py Wed Sep 25 08:53:38 2019 +0200 +++ b/sat_frontends/jp/cmd_message.py Wed Sep 25 08:56:41 2019 +0200 @@ -25,7 +25,6 @@ from sat.tools.utils import clean_ustr from sat.tools.common import data_format from sat.tools.common.ansi import ANSI as A -from functools import partial __commands__ = ["Message"] @@ -33,7 +32,6 @@ class Send(base.CommandBase): def __init__(self, host): super(Send, self).__init__(host, "send", help=_("send a message to a contact")) - self.need_loop=True def add_parser_options(self): self.parser.add_argument( @@ -84,25 +82,15 @@ "jid", help=_("the destination jid") ) - def multi_send_cb(self): - self.sent += 1 - if self.sent == self.to_send: - self.host.quit(self.errcode) - - def multi_send_eb(self, failure_, msg): - self.disp(_("Can't send message [{msg}]: {reason}").format( - msg=msg, reason=failure_)) - self.errcode = C.EXIT_BRIDGE_ERRBACK - self.multi_send_cb() - - def sendStdin(self, dest_jid): + async def sendStdin(self, dest_jid): """Send incomming data on stdin to jabber contact @param dest_jid: destination jid """ header = "\n" if self.args.new_line else "" + # FIXME: stdin is not read asynchronously at the moment stdin_lines = [ - stream.decode("utf-8", "ignore") for stream in sys.stdin.readlines() + stream for stream in sys.stdin.readlines() ] extra = {} if self.args.subject is None: @@ -113,99 +101,98 @@ if self.args.xhtml or self.args.rich: key = "xhtml" if self.args.xhtml else "rich" if self.args.lang: - key = "{}_{}".format(key, self.args.lang) + key = f"{key}_{self.args.lang}" extra[key] = clean_ustr("".join(stdin_lines)) stdin_lines = [] - if self.args.separate: # we send stdin in several messages - self.to_send = 0 - self.sent = 0 - self.errcode = 0 + to_send = [] + + error = False + if self.args.separate: + # we send stdin in several messages if header: - self.to_send += 1 - self.host.bridge.messageSend( + # first we sent the header + try: + await self.host.bridge.messageSend( + dest_jid, + {self.args.lang: header}, + subject, + self.args.type, + profile_key=self.profile, + ) + except Exception as e: + self.disp(f"can't send header: {e}", error=True) + error = True + + to_send.extend({self.args.lang: clean_ustr(l.replace("\n", ""))} + for l in stdin_lines) + else: + # we sent all in a single message + if not (self.args.xhtml or self.args.rich): + msg = {self.args.lang: header + clean_ustr("".join(stdin_lines))} + else: + msg = {} + to_send.append(msg) + + for msg in to_send: + try: + await self.host.bridge.messageSend( dest_jid, - {self.args.lang: header}, - subject, - self.args.type, - profile_key=self.profile, - callback=lambda: None, - errback=lambda ignore: ignore, - ) - - self.to_send += len(stdin_lines) - for line in stdin_lines: - self.host.bridge.messageSend( - dest_jid, - {self.args.lang: line.replace("\n", "")}, + msg, subject, self.args.type, extra, - profile_key=self.host.profile, - callback=self.multi_send_cb, - errback=partial(self.multi_send_eb, msg=line), - ) + profile_key=self.host.profile) + except Exception as e: + self.disp(f"can't send message {msg!r}: {e}", error=True) + error = True - else: - msg = ( - {self.args.lang: header + clean_ustr("".join(stdin_lines))} - if not (self.args.xhtml or self.args.rich) - else {} - ) - self.host.bridge.messageSend( - dest_jid, - msg, - subject, - self.args.type, - extra, - profile_key=self.host.profile, - callback=self.host.quit, - errback=partial(self.errback, - msg=_("Can't send message: {}"))) + if error: + # at least one message sending failed + self.host.quit(C.EXIT_BRIDGE_ERRBACK) - def encryptionNamespaceGetCb(self, namespace, jid_): - self.host.bridge.messageEncryptionStart( - jid_, namespace, not self.args.encrypt_noreplace, - self.profile, - callback=lambda: self.sendStdin(jid_), - errback=partial(self.errback, - msg=_("Can't start encryption session: {}"), - exit_code=C.EXIT_BRIDGE_ERRBACK, - )) + self.host.quit() - - def start(self): + async def start(self): if self.args.xhtml and self.args.separate: self.disp( "argument -s/--separate is not compatible yet with argument -x/--xhtml", error=True, ) - self.host.quit(2) + self.host.quit(C.EXIT_BAD_ARG) - jids = self.host.check_jids([self.args.jid]) + jids = await self.host.check_jids([self.args.jid]) jid_ = jids[0] if self.args.encrypt_noreplace and self.args.encrypt is None: self.parser.error("You need to use --encrypt if you use --encrypt-noreplace") if self.args.encrypt is not None: - self.host.bridge.encryptionNamespaceGet(self.args.encrypt, - callback=partial(self.encryptionNamespaceGetCb, jid_=jid_), - errback=partial(self.errback, - msg=_("Can't get encryption namespace: {}"), - exit_code=C.EXIT_BRIDGE_ERRBACK, - )) - else: - self.sendStdin(jid_) + try: + namespace = await self.host.bridge.encryptionNamespaceGet( + self.args.encrypt) + except Exception as e: + self.disp(f"can't get encryption namespace: {e}", error=True) + self.host.quit(C.EXIT_BRIDGE_ERRBACK) + + try: + await self.host.bridge.messageEncryptionStart( + jid_, namespace, not self.args.encrypt_noreplace, self.profile + ) + except Exception as e: + self.disp(f"can't start encryption session: {e}", error=True) + self.host.quit(C.EXIT_BRIDGE_ERRBACK) + + await self.sendStdin(jid_) class MAM(base.CommandBase): def __init__(self, host): super(MAM, self).__init__( - host, "mam", use_output=C.OUTPUT_MESS, use_verbose=True, help=_("query archives using MAM")) - self.need_loop=True + host, "mam", use_output=C.OUTPUT_MESS, use_verbose=True, + help=_("query archives using MAM")) def add_parser_options(self): self.parser.add_argument( @@ -235,9 +222,37 @@ "--index", dest="rsm_index", type=int, help=_("index of the page to retrieve")) - def _sessionInfosGetCb(self, session_info, data, metadata): + async def start(self): + extra = {} + if self.args.mam_start is not None: + extra["mam_start"] = float(self.args.mam_start) + if self.args.mam_end is not None: + extra["mam_end"] = float(self.args.mam_end) + if self.args.mam_with is not None: + extra["mam_with"] = self.args.mam_with + for suff in ('max', 'after', 'before', 'index'): + key = 'rsm_' + suff + value = getattr(self.args,key) + if value is not None: + extra[key] = str(value) + try: + data, metadata, profile = await self.host.bridge.MAMGet( + self.args.service, data_format.serialise(extra), self.profile) + except Exception as e: + self.disp(f"can't retrieve MAM archives: {e}", error=True) + self.host.quit(C.EXIT_BRIDGE_ERRBACK) + + try: + session_info = await self.host.bridge.sessionInfosGet(self.profile) + except Exception as e: + self.disp(f"can't get session infos: {e}", error=True) + self.host.quit(C.EXIT_BRIDGE_ERRBACK) + + # we need to fill own_jid for message output self.host.own_jid = jid.JID(session_info["jid"]) - self.output(data) + + await self.output(data) + # FIXME: metadata are not displayed correctly and don't play nice with output # they should be added to output data somehow if self.verbosity: @@ -250,29 +265,6 @@ self.host.quit() - def _MAMGetCb(self, result): - data, metadata, profile = result - self.host.bridge.sessionInfosGet(self.profile, - callback=partial(self._sessionInfosGetCb, data=data, metadata=metadata), - errback=self.errback) - - def start(self): - extra = {} - if self.args.mam_start is not None: - extra["mam_start"] = float(self.args.mam_start) - if self.args.mam_end is not None: - extra["mam_end"] = float(self.args.mam_end) - if self.args.mam_with is not None: - extra["mam_with"] = self.args.mam_with - for suff in ('max', 'after', 'before', 'index'): - key = 'rsm_' + suff - value = getattr(self.args,key) - if value is not None: - extra[key] = str(value) - self.host.bridge.MAMGet( - self.args.service, data_format.serialise(extra), self.profile, - callback=self._MAMGetCb, errback=self.errback) - class Message(base.CommandBase): subcommands = (Send, MAM)