annotate libervia/cli/loops.py @ 4296:ffc43219e0b2

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