Mercurial > libervia-backend
annotate sat_frontends/jp/loops.py @ 4062:18719058a914
plugin XEP-0294: "Jingle RTP Feedback Negotiation" implementation:
rel 438
| author | Goffi <goffi@goffi.org> |
|---|---|
| date | Tue, 30 May 2023 17:58:43 +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 |
