diff sat_frontends/jp/cmd_avatar.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_avatar.py	Wed Sep 25 08:53:38 2019 +0200
+++ b/sat_frontends/jp/cmd_avatar.py	Wed Sep 25 08:56:41 2019 +0200
@@ -18,59 +18,24 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
-from . import base
 import os
 import os.path
+import asyncio
+from . import base
 from sat.core.i18n import _
 from sat_frontends.jp.constants import Const as C
 from sat.tools import config
-import subprocess
 
 
 __commands__ = ["Avatar"]
 DISPLAY_CMD = ["xv", "display", "gwenview", "showtell"]
 
 
-class Set(base.CommandBase):
-    def __init__(self, host):
-        super(Set, self).__init__(
-            host, "set", use_verbose=True, help=_("set avatar of the profile")
-        )
-        self.need_loop = True
-
-    def add_parser_options(self):
-        self.parser.add_argument(
-            "image_path", type=str, help=_("path to the image to upload")
-        )
-
-    def start(self):
-        """Send files to jabber contact"""
-        path = self.args.image_path
-        if not os.path.exists(path):
-            self.disp(_("file [{}] doesn't exist !").format(path), error=True)
-            self.host.quit(1)
-        path = os.path.abspath(path)
-        self.host.bridge.avatarSet(
-            path, self.profile, callback=self._avatarCb, errback=self._avatarEb
-        )
-
-    def _avatarCb(self):
-        self.disp(_("avatar has been set"), 1)
-        self.host.quit()
-
-    def _avatarEb(self, failure_):
-        self.disp(
-            _("error while uploading avatar: {msg}").format(msg=failure_), error=True
-        )
-        self.host.quit(C.EXIT_ERROR)
-
-
 class Get(base.CommandBase):
     def __init__(self, host):
         super(Get, self).__init__(
             host, "get", use_verbose=True, help=_("retrieve avatar of an entity")
         )
-        self.need_loop = True
 
     def add_parser_options(self):
         self.parser.add_argument("jid", help=_("entity"))
@@ -78,54 +43,81 @@
             "-s", "--show", action="store_true", help=_("show avatar")
         )
 
-    def showImage(self, path):
+    async def showImage(self, path):
         sat_conf = config.parseMainConf()
         cmd = config.getConfig(sat_conf, "jp", "image_cmd")
         cmds = [cmd] + DISPLAY_CMD if cmd else DISPLAY_CMD
         for cmd in cmds:
             try:
-                ret = subprocess.call([cmd] + [path])
+                process = await asyncio.create_subprocess_exec(cmd, path)
+                ret = await process.wait()
             except OSError:
-                pass
-            else:
-                if ret in (0, 2):
-                    # we can get exit code 2 with display when stopping it with C-c
-                    break
+                continue
+
+            if ret in (0, 2):
+                # we can get exit code 2 with display when stopping it with C-c
+                break
         else:
             # didn't worked with commands, we try our luck with webbrowser
-            # in some cases, webbrowser can actually open the associated display program
+            # in some cases, webbrowser can actually open the associated display program.
+            # Note that this may be possibly blocking, depending on the platform and
+            # available browser
             import webbrowser
 
             webbrowser.open(path)
 
-    def _avatarGetCb(self, avatar_path):
+    async def start(self):
+        try:
+            avatar_path = await self.host.bridge.avatarGet(
+                self.args.jid,
+                False,
+                False,
+                self.profile,
+            )
+        except Exception as e:
+            self.disp(f"can't retrieve avatar: {e}", error=True)
+            self.host.quit(C.EXIT_BRIDGE_ERRBACK)
+
         if not avatar_path:
             self.disp(_("No avatar found."), 1)
             self.host.quit(C.EXIT_NOT_FOUND)
 
         self.disp(avatar_path)
         if self.args.show:
-            self.showImage(avatar_path)
+            await self.showImage(avatar_path)
 
         self.host.quit()
 
-    def _avatarGetEb(self, failure_):
-        self.disp(_("error while getting avatar: {msg}").format(msg=failure_), error=True)
-        self.host.quit(C.EXIT_ERROR)
+
+class Set(base.CommandBase):
+    def __init__(self, host):
+        super(Set, self).__init__(
+            host, "set", use_verbose=True, help=_("set avatar of the profile")
+        )
+
+    def add_parser_options(self):
+        self.parser.add_argument(
+            "image_path", type=str, help=_("path to the image to upload")
+        )
 
-    def start(self):
-        self.host.bridge.avatarGet(
-            self.args.jid,
-            False,
-            False,
-            self.profile,
-            callback=self._avatarGetCb,
-            errback=self._avatarGetEb,
-        )
+    async def start(self):
+        path = self.args.image_path
+        if not os.path.exists(path):
+            self.disp(_(f"file {path!r} doesn't exist!"), error=True)
+            self.host.quit(C.EXIT_BAD_ARG)
+        path = os.path.abspath(path)
+        try:
+            await self.host.bridge.avatarSet(path, self.profile)
+        except Exception as e:
+            self.disp(f"can't set avatar: {e}", error=True)
+            self.host.quit(C.EXIT_BRIDGE_ERRBACK)
+        else:
+            self.disp(_("avatar has been set"), 1)
+            self.host.quit()
 
 
 class Avatar(base.CommandBase):
-    subcommands = (Set, Get)
+    subcommands = (Get, Set)
 
     def __init__(self, host):
         super(Avatar, self).__init__(