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.
This commit is contained in:
parent
5cee4fbab7
commit
76aadbb3fb
1 changed files with 3299 additions and 3300 deletions
|
|
@ -25,7 +25,6 @@ from sat.core.i18n import _
|
|||
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 @@ __commands__ = ["Message"]
|
|||
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 @@ class Send(base.CommandBase):
|
|||
"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 @@ class Send(base.CommandBase):
|
|||
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(
|
||||
dest_jid,
|
||||
{self.args.lang: header},
|
||||
subject,
|
||||
self.args.type,
|
||||
profile_key=self.profile,
|
||||
callback=lambda: None,
|
||||
errback=lambda ignore: ignore,
|
||||
)
|
||||
# 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
|
||||
|
||||
self.to_send += len(stdin_lines)
|
||||
for line in stdin_lines:
|
||||
self.host.bridge.messageSend(
|
||||
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: 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,28 +222,7 @@ class MAM(base.CommandBase):
|
|||
"--index", dest="rsm_index", type=int,
|
||||
help=_("index of the page to retrieve"))
|
||||
|
||||
def _sessionInfosGetCb(self, session_info, data, metadata):
|
||||
self.host.own_jid = jid.JID(session_info["jid"])
|
||||
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:
|
||||
for value in ("rsm_first", "rsm_last", "rsm_index", "rsm_count",
|
||||
"mam_complete", "mam_stable"):
|
||||
if value in metadata:
|
||||
label = value.split("_")[1]
|
||||
self.disp(A.color(
|
||||
C.A_HEADER, label, ': ' , A.RESET, metadata[value]))
|
||||
|
||||
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):
|
||||
async def start(self):
|
||||
extra = {}
|
||||
if self.args.mam_start is not None:
|
||||
extra["mam_start"] = float(self.args.mam_start)
|
||||
|
|
@ -269,9 +235,35 @@ class MAM(base.CommandBase):
|
|||
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)
|
||||
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"])
|
||||
|
||||
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:
|
||||
for value in ("rsm_first", "rsm_last", "rsm_index", "rsm_count",
|
||||
"mam_complete", "mam_stable"):
|
||||
if value in metadata:
|
||||
label = value.split("_")[1]
|
||||
self.disp(A.color(
|
||||
C.A_HEADER, label, ': ' , A.RESET, metadata[value]))
|
||||
|
||||
self.host.quit()
|
||||
|
||||
|
||||
class Message(base.CommandBase):
|
||||
|
|
|
|||
Loading…
Reference in a new issue