Mercurial > libervia-backend
annotate sat_frontends/jp/loops.py @ 4069:3d91d0aa68db
tests (unit): Skip XEP-0373 test if gpg can't be imported
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 01 Jun 2023 21:37:34 +0200 |
parents | 524856bd7b19 |
children | 4b842c1fb686 |
rev | line source |
---|---|
3043 | 1 #!/usr/bin/env python3 |
2 | |
3 # jp: a SAT command line tool | |
3479 | 4 # Copyright (C) 2009-2021 Jérôme Poisson (goffi@goffi.org) |
3043 | 5 |
6 # This program is free software: you can redistribute it and/or modify | |
7 # it under the terms of the GNU Affero General Public License as published by | |
8 # the Free Software Foundation, either version 3 of the License, or | |
9 # (at your option) any later version. | |
10 | |
11 # This program is distributed in the hope that it will be useful, | |
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 # GNU Affero General Public License for more details. | |
15 | |
16 # You should have received a copy of the GNU Affero General Public License | |
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | |
19 import sys | |
20 import asyncio | |
21 import logging as log | |
22 from sat.core.i18n import _ | |
23 from sat_frontends.jp.constants import Const as C | |
24 | |
25 log.basicConfig(level=log.WARNING, | |
26 format='[%(name)s] %(message)s') | |
27 | |
28 USER_INTER_MSG = _("User interruption: good bye") | |
29 | |
30 | |
31 class QuitException(BaseException): | |
32 """Quitting is requested | |
33 | |
34 This is used to stop execution when host.quit() is called | |
35 """ | |
36 | |
37 | |
4037
524856bd7b19
massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents:
3479
diff
changeset
|
38 def get_jp_loop(bridge_name): |
3043 | 39 if 'dbus' in bridge_name: |
40 import signal | |
41 import threading | |
42 from gi.repository import GLib | |
43 | |
44 class JPLoop: | |
45 | |
46 def run(self, jp, args, namespace): | |
47 signal.signal(signal.SIGINT, self._on_sigint) | |
48 self._glib_loop = GLib.MainLoop() | |
49 threading.Thread(target=self._glib_loop.run).start() | |
50 loop = asyncio.get_event_loop() | |
51 loop.run_until_complete(jp.main(args=args, namespace=namespace)) | |
52 loop.run_forever() | |
53 | |
54 def quit(self, exit_code): | |
55 loop = asyncio.get_event_loop() | |
56 loop.stop() | |
57 self._glib_loop.quit() | |
58 sys.exit(exit_code) | |
59 | |
60 def call_later(self, delay, callback, *args): | |
61 """call a callback repeatedly | |
62 | |
63 @param delay(int): delay between calls in s | |
64 @param callback(callable): method to call | |
65 if the callback return True, the call will continue | |
66 else the calls will stop | |
67 @param *args: args of the callbac | |
68 """ | |
69 loop = asyncio.get_event_loop() | |
70 loop.call_later(delay, callback, *args) | |
71 | |
72 def _on_sigint(self, sig_number, stack_frame): | |
73 """Called on keyboard interruption | |
74 | |
75 Print user interruption message, set exit code and stop reactor | |
76 """ | |
77 print("\r" + USER_INTER_MSG) | |
78 self.quit(C.EXIT_USER_CANCELLED) | |
79 else: | |
80 import signal | |
81 from twisted.internet import asyncioreactor | |
82 asyncioreactor.install() | |
83 from twisted.internet import reactor, defer | |
84 | |
85 class JPLoop: | |
86 | |
87 def __init__(self): | |
88 # exit code must be set when using quit, so if it's not set | |
89 # something got wrong and we must report it | |
90 self._exit_code = C.EXIT_INTERNAL_ERROR | |
91 | |
92 def run(self, jp, *args): | |
93 self.jp = jp | |
94 signal.signal(signal.SIGINT, self._on_sigint) | |
95 defer.ensureDeferred(self._start(jp, *args)) | |
96 try: | |
97 reactor.run(installSignalHandlers=False) | |
98 except SystemExit as e: | |
99 self._exit_code = e.code | |
100 sys.exit(self._exit_code) | |
101 | |
102 async def _start(self, jp, *args): | |
103 fut = asyncio.ensure_future(jp.main(*args)) | |
104 try: | |
105 await defer.Deferred.fromFuture(fut) | |
106 except BaseException: | |
107 import traceback | |
108 traceback.print_exc() | |
109 jp.quit(1) | |
110 | |
111 def quit(self, exit_code): | |
112 self._exit_code = exit_code | |
113 reactor.stop() | |
114 | |
115 def _timeout_cb(self, args, callback, delay): | |
116 try: | |
117 ret = callback(*args) | |
118 # FIXME: temporary hack to avoid traceback when using XMLUI | |
119 # to be removed once create_task is not used anymore in | |
120 # xmlui_manager (i.e. once sat_frontends.tools.xmlui fully supports | |
121 # async syntax) | |
122 except QuitException: | |
123 return | |
124 if ret: | |
125 reactor.callLater(delay, self._timeout_cb, args, callback, delay) | |
126 | |
127 def call_later(self, delay, callback, *args): | |
128 reactor.callLater(delay, self._timeout_cb, args, callback, delay) | |
129 | |
130 def _on_sigint(self, sig_number, stack_frame): | |
131 """Called on keyboard interruption | |
132 | |
133 Print user interruption message, set exit code and stop reactor | |
134 """ | |
135 print("\r" + USER_INTER_MSG) | |
136 self._exit_code = C.EXIT_USER_CANCELLED | |
137 reactor.callFromThread(reactor.stop) | |
138 | |
139 | |
140 if bridge_name == "embedded": | |
141 raise NotImplementedError | |
142 # from sat.core import sat_main | |
143 # sat = sat_main.SAT() | |
144 | |
145 return JPLoop |