Mercurial > libervia-backend
annotate libervia/cli/cmd_pipe.py @ 4140:13dd5660c28f
tests (unit/frontends): tests for webrtc implementation:
rel 426
| author | Goffi <goffi@goffi.org> |
|---|---|
| date | Wed, 01 Nov 2023 14:04:25 +0100 |
| parents | 47401850dec6 |
| children | 0d7bb4df2343 |
| rev | line source |
|---|---|
| 3137 | 1 #!/usr/bin/env python3 |
| 2 | |
| 815 | 3 |
|
4075
47401850dec6
refactoring: rename `libervia.frontends.jp` to `libervia.cli`
Goffi <goffi@goffi.org>
parents:
4074
diff
changeset
|
4 # Libervia CLI |
| 3479 | 5 # Copyright (C) 2009-2021 Jérôme Poisson (goffi@goffi.org) |
| 815 | 6 |
| 7 # This program is free software: you can redistribute it and/or modify | |
| 8 # it under the terms of the GNU Affero General Public License as published by | |
| 9 # the Free Software Foundation, either version 3 of the License, or | |
| 10 # (at your option) any later version. | |
| 11 | |
| 12 # This program is distributed in the hope that it will be useful, | |
| 13 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 15 # GNU Affero General Public License for more details. | |
| 16 | |
| 17 # You should have received a copy of the GNU Affero General Public License | |
| 18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 19 | |
| 3040 | 20 import asyncio |
| 21 import errno | |
| 22 from functools import partial | |
|
4041
2594e1951cf7
core (bridge): `action_new` now use serialised dict for extra data.
Goffi <goffi@goffi.org>
parents:
4037
diff
changeset
|
23 import socket |
|
2594e1951cf7
core (bridge): `action_new` now use serialised dict for extra data.
Goffi <goffi@goffi.org>
parents:
4037
diff
changeset
|
24 import sys |
|
2594e1951cf7
core (bridge): `action_new` now use serialised dict for extra data.
Goffi <goffi@goffi.org>
parents:
4037
diff
changeset
|
25 |
|
4071
4b842c1fb686
refactoring: renamed `sat` package to `libervia.backend`
Goffi <goffi@goffi.org>
parents:
4042
diff
changeset
|
26 from libervia.backend.core.i18n import _ |
|
4b842c1fb686
refactoring: renamed `sat` package to `libervia.backend`
Goffi <goffi@goffi.org>
parents:
4042
diff
changeset
|
27 from libervia.backend.tools.common import data_format |
|
4075
47401850dec6
refactoring: rename `libervia.frontends.jp` to `libervia.cli`
Goffi <goffi@goffi.org>
parents:
4074
diff
changeset
|
28 from libervia.cli import base |
|
47401850dec6
refactoring: rename `libervia.frontends.jp` to `libervia.cli`
Goffi <goffi@goffi.org>
parents:
4074
diff
changeset
|
29 from libervia.cli import xmlui_manager |
|
47401850dec6
refactoring: rename `libervia.frontends.jp` to `libervia.cli`
Goffi <goffi@goffi.org>
parents:
4074
diff
changeset
|
30 from libervia.cli.constants import Const as C |
|
4074
26b7ed2817da
refactoring: rename `sat_frontends` to `libervia.frontends`
Goffi <goffi@goffi.org>
parents:
4071
diff
changeset
|
31 from libervia.frontends.tools import jid |
| 0 | 32 |
| 817 | 33 __commands__ = ["Pipe"] |
| 0 | 34 |
|
2489
e2a7bb875957
plugin pipe/stream, file transfert: refactoring and improvments:
Goffi <goffi@goffi.org>
parents:
2483
diff
changeset
|
35 START_PORT = 9999 |
|
1670
3690b4d4157e
jp (pipe): pipe commands now use the new CommandAnswering API (with actionNew)
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
36 |
|
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
37 |
| 817 | 38 class PipeOut(base.CommandBase): |
| 39 def __init__(self, host): | |
|
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
40 super(PipeOut, self).__init__(host, "out", help=_("send a pipe a stream")) |
| 393 | 41 |
| 817 | 42 def add_parser_options(self): |
|
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
43 self.parser.add_argument( |
| 3028 | 44 "jid", help=_("the destination jid") |
|
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
45 ) |
|
401
b2caa2615c4c
jp roster name manegement + Pipe transfer
Goffi <goffi@goffi.org>
parents:
393
diff
changeset
|
46 |
| 3040 | 47 async def start(self): |
| 48 """ Create named pipe, and send stdin to it """ | |
| 49 try: | |
|
4037
524856bd7b19
massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents:
3479
diff
changeset
|
50 port = await self.host.bridge.stream_out( |
| 3040 | 51 await self.host.get_full_jid(self.args.jid), |
| 52 self.profile, | |
| 53 ) | |
| 54 except Exception as e: | |
| 55 self.disp(f"can't start stream: {e}", error=True) | |
| 56 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | |
| 57 else: | |
| 58 # FIXME: we use temporarily blocking code here, as it simplify | |
| 59 # asyncio port: "loop.connect_read_pipe(lambda: reader_protocol, | |
| 60 # sys.stdin.buffer)" doesn't work properly when a file is piped in | |
| 61 # (we get a "ValueError: Pipe transport is for pipes/sockets only.") | |
| 62 # while it's working well for simple text sending. | |
|
2489
e2a7bb875957
plugin pipe/stream, file transfert: refactoring and improvments:
Goffi <goffi@goffi.org>
parents:
2483
diff
changeset
|
63 |
| 3040 | 64 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
| 65 s.connect(("127.0.0.1", int(port))) | |
| 66 | |
| 67 while True: | |
| 68 buf = sys.stdin.buffer.read(4096) | |
| 69 if not buf: | |
| 70 break | |
| 71 try: | |
| 72 s.sendall(buf) | |
| 73 except socket.error as e: | |
| 74 if e.errno == errno.EPIPE: | |
| 75 sys.stderr.write(f"e\n") | |
| 76 self.host.quit(1) | |
| 77 else: | |
| 78 raise e | |
| 79 self.host.quit() | |
|
2489
e2a7bb875957
plugin pipe/stream, file transfert: refactoring and improvments:
Goffi <goffi@goffi.org>
parents:
2483
diff
changeset
|
80 |
|
e2a7bb875957
plugin pipe/stream, file transfert: refactoring and improvments:
Goffi <goffi@goffi.org>
parents:
2483
diff
changeset
|
81 |
| 3040 | 82 async def handle_stream_in(reader, writer, host): |
| 83 """Write all received data to stdout""" | |
| 84 while True: | |
| 85 data = await reader.read(4096) | |
| 86 if not data: | |
| 87 break | |
| 88 sys.stdout.buffer.write(data) | |
| 89 try: | |
| 90 sys.stdout.flush() | |
| 91 except IOError as e: | |
| 92 sys.stderr.write(f"{e}\n") | |
| 93 break | |
|
4037
524856bd7b19
massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents:
3479
diff
changeset
|
94 host.quit_from_signal() |
|
401
b2caa2615c4c
jp roster name manegement + Pipe transfer
Goffi <goffi@goffi.org>
parents:
393
diff
changeset
|
95 |
| 817 | 96 |
| 97 class PipeIn(base.CommandAnswering): | |
| 98 def __init__(self, host): | |
|
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
99 super(PipeIn, self).__init__(host, "in", help=_("receive a pipe stream")) |
|
4037
524856bd7b19
massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents:
3479
diff
changeset
|
100 self.action_callbacks = {"STREAM": self.on_stream_action} |
|
587
952322b1d490
Remove trailing whitespaces.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
572
diff
changeset
|
101 |
| 817 | 102 def add_parser_options(self): |
|
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
103 self.parser.add_argument( |
|
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
104 "jids", |
|
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
105 nargs="*", |
|
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
106 help=_('Jids accepted (none means "accept everything")'), |
|
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
107 ) |
| 0 | 108 |
|
4037
524856bd7b19
massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents:
3479
diff
changeset
|
109 def get_xmlui_id(self, action_data): |
|
1670
3690b4d4157e
jp (pipe): pipe commands now use the new CommandAnswering API (with actionNew)
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
110 try: |
|
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
111 xml_ui = action_data["xmlui"] |
|
1670
3690b4d4157e
jp (pipe): pipe commands now use the new CommandAnswering API (with actionNew)
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
112 except KeyError: |
| 3028 | 113 self.disp(_("Action has no XMLUI"), 1) |
|
1670
3690b4d4157e
jp (pipe): pipe commands now use the new CommandAnswering API (with actionNew)
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
114 else: |
| 3040 | 115 ui = xmlui_manager.create(self.host, xml_ui) |
| 116 if not ui.submit_id: | |
| 3028 | 117 self.disp(_("Invalid XMLUI received"), error=True) |
|
4037
524856bd7b19
massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents:
3479
diff
changeset
|
118 self.quit_from_signal(C.EXIT_INTERNAL_ERROR) |
| 3040 | 119 return ui.submit_id |
|
1670
3690b4d4157e
jp (pipe): pipe commands now use the new CommandAnswering API (with actionNew)
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
120 |
|
4037
524856bd7b19
massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents:
3479
diff
changeset
|
121 async def on_stream_action(self, action_data, action_id, security_limit, profile): |
|
524856bd7b19
massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents:
3479
diff
changeset
|
122 xmlui_id = self.get_xmlui_id(action_data) |
|
1670
3690b4d4157e
jp (pipe): pipe commands now use the new CommandAnswering API (with actionNew)
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
123 if xmlui_id is None: |
|
4037
524856bd7b19
massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents:
3479
diff
changeset
|
124 self.host.quit_from_signal(C.EXIT_ERROR) |
|
1670
3690b4d4157e
jp (pipe): pipe commands now use the new CommandAnswering API (with actionNew)
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
125 try: |
|
4042
877145b4ba01
core: don't use `meta_` prefix anymore for `action_extra` in `action_new` signal.
Goffi <goffi@goffi.org>
parents:
4041
diff
changeset
|
126 from_jid = jid.JID(action_data["from_jid"]) |
|
1670
3690b4d4157e
jp (pipe): pipe commands now use the new CommandAnswering API (with actionNew)
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
127 except KeyError: |
| 3040 | 128 self.disp(_("Ignoring action without from_jid data"), error=True) |
|
1670
3690b4d4157e
jp (pipe): pipe commands now use the new CommandAnswering API (with actionNew)
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
129 return |
|
3690b4d4157e
jp (pipe): pipe commands now use the new CommandAnswering API (with actionNew)
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
130 |
|
3690b4d4157e
jp (pipe): pipe commands now use the new CommandAnswering API (with actionNew)
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
131 if not self.bare_jids or from_jid.bare in self.bare_jids: |
|
2489
e2a7bb875957
plugin pipe/stream, file transfert: refactoring and improvments:
Goffi <goffi@goffi.org>
parents:
2483
diff
changeset
|
132 host, port = "localhost", START_PORT |
|
e2a7bb875957
plugin pipe/stream, file transfert: refactoring and improvments:
Goffi <goffi@goffi.org>
parents:
2483
diff
changeset
|
133 while True: |
|
e2a7bb875957
plugin pipe/stream, file transfert: refactoring and improvments:
Goffi <goffi@goffi.org>
parents:
2483
diff
changeset
|
134 try: |
| 3040 | 135 server = await asyncio.start_server( |
| 136 partial(handle_stream_in, host=self.host), host, port) | |
|
2489
e2a7bb875957
plugin pipe/stream, file transfert: refactoring and improvments:
Goffi <goffi@goffi.org>
parents:
2483
diff
changeset
|
137 except socket.error as e: |
|
e2a7bb875957
plugin pipe/stream, file transfert: refactoring and improvments:
Goffi <goffi@goffi.org>
parents:
2483
diff
changeset
|
138 if e.errno == errno.EADDRINUSE: |
|
e2a7bb875957
plugin pipe/stream, file transfert: refactoring and improvments:
Goffi <goffi@goffi.org>
parents:
2483
diff
changeset
|
139 port += 1 |
|
e2a7bb875957
plugin pipe/stream, file transfert: refactoring and improvments:
Goffi <goffi@goffi.org>
parents:
2483
diff
changeset
|
140 else: |
|
e2a7bb875957
plugin pipe/stream, file transfert: refactoring and improvments:
Goffi <goffi@goffi.org>
parents:
2483
diff
changeset
|
141 raise e |
|
e2a7bb875957
plugin pipe/stream, file transfert: refactoring and improvments:
Goffi <goffi@goffi.org>
parents:
2483
diff
changeset
|
142 else: |
|
e2a7bb875957
plugin pipe/stream, file transfert: refactoring and improvments:
Goffi <goffi@goffi.org>
parents:
2483
diff
changeset
|
143 break |
| 3028 | 144 xmlui_data = {"answer": C.BOOL_TRUE, "port": str(port)} |
|
4037
524856bd7b19
massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents:
3479
diff
changeset
|
145 await self.host.bridge.action_launch( |
|
4041
2594e1951cf7
core (bridge): `action_new` now use serialised dict for extra data.
Goffi <goffi@goffi.org>
parents:
4037
diff
changeset
|
146 xmlui_id, data_format.serialise(xmlui_data), profile_key=profile |
|
2594e1951cf7
core (bridge): `action_new` now use serialised dict for extra data.
Goffi <goffi@goffi.org>
parents:
4037
diff
changeset
|
147 ) |
| 3040 | 148 async with server: |
| 149 await server.serve_forever() | |
|
4037
524856bd7b19
massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents:
3479
diff
changeset
|
150 self.host.quit_from_signal() |
|
1670
3690b4d4157e
jp (pipe): pipe commands now use the new CommandAnswering API (with actionNew)
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
151 |
| 3040 | 152 async def start(self): |
|
1670
3690b4d4157e
jp (pipe): pipe commands now use the new CommandAnswering API (with actionNew)
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
153 self.bare_jids = [jid.JID(jid_).bare for jid_ in self.args.jids] |
| 3040 | 154 await self.start_answering() |
| 817 | 155 |
| 156 | |
| 157 class Pipe(base.CommandBase): | |
| 158 subcommands = (PipeOut, PipeIn) | |
| 159 | |
| 160 def __init__(self, host): | |
|
2624
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
161 super(Pipe, self).__init__( |
|
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
162 host, "pipe", use_profile=False, help=_("stream piping through XMPP") |
|
56f94936df1e
code style reformatting using black
Goffi <goffi@goffi.org>
parents:
2562
diff
changeset
|
163 ) |
