fastapi-webrtc 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fastapi_webrtc/__init__.py +70 -0
- fastapi_webrtc/codegen/__init__.py +1 -0
- fastapi_webrtc/codegen/cli.py +117 -0
- fastapi_webrtc/codegen/templates/runtime.ts +1160 -0
- fastapi_webrtc/codegen/typescript.py +621 -0
- fastapi_webrtc/codegen/writer.py +73 -0
- fastapi_webrtc/contract.py +257 -0
- fastapi_webrtc/declarations.py +443 -0
- fastapi_webrtc/engine.py +244 -0
- fastapi_webrtc/engines/__init__.py +2 -0
- fastapi_webrtc/engines/aiortc.py +469 -0
- fastapi_webrtc/errors.py +120 -0
- fastapi_webrtc/events.py +52 -0
- fastapi_webrtc/ice.py +122 -0
- fastapi_webrtc/peer.py +230 -0
- fastapi_webrtc/protocol.py +160 -0
- fastapi_webrtc/py.typed +0 -0
- fastapi_webrtc/router.py +351 -0
- fastapi_webrtc/runtime.py +1280 -0
- fastapi_webrtc/sdp.py +92 -0
- fastapi_webrtc-0.1.0.dist-info/METADATA +245 -0
- fastapi_webrtc-0.1.0.dist-info/RECORD +25 -0
- fastapi_webrtc-0.1.0.dist-info/WHEEL +4 -0
- fastapi_webrtc-0.1.0.dist-info/entry_points.txt +2 -0
- fastapi_webrtc-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Typed WebRTC sessions for FastAPI.
|
|
2
|
+
|
|
3
|
+
Declare sessions on a :class:`WebRtcRouter`; the router provides WebSocket
|
|
4
|
+
signaling, admission through FastAPI dependencies, limits and cleanup, while an
|
|
5
|
+
engine adapter (see :mod:`fastapi_webrtc.engines`) owns the peer connection.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from fastapi_webrtc.declarations import (
|
|
9
|
+
DataChannelSpec,
|
|
10
|
+
Direction,
|
|
11
|
+
MediaPolicy,
|
|
12
|
+
Role,
|
|
13
|
+
Session,
|
|
14
|
+
SessionContext,
|
|
15
|
+
SessionDeclaration,
|
|
16
|
+
SessionLimits,
|
|
17
|
+
)
|
|
18
|
+
from fastapi_webrtc.engine import (
|
|
19
|
+
CandidatePairStats,
|
|
20
|
+
ConnectionStats,
|
|
21
|
+
Engine,
|
|
22
|
+
EngineCapabilities,
|
|
23
|
+
MediaStats,
|
|
24
|
+
)
|
|
25
|
+
from fastapi_webrtc.errors import ErrorCode, SessionClosedError, WebRtcError
|
|
26
|
+
from fastapi_webrtc.events import EventHook, SessionEvent
|
|
27
|
+
from fastapi_webrtc.ice import (
|
|
28
|
+
IceServer,
|
|
29
|
+
IceServers,
|
|
30
|
+
IceServerSource,
|
|
31
|
+
TurnRestCredentials,
|
|
32
|
+
)
|
|
33
|
+
from fastapi_webrtc.peer import Channel, IncomingTrack, OutgoingTrack, Peer
|
|
34
|
+
from fastapi_webrtc.protocol import PROTOCOL_VERSION, SUBPROTOCOL
|
|
35
|
+
from fastapi_webrtc.router import WebRtcRouter
|
|
36
|
+
|
|
37
|
+
__version__ = "0.1.0"
|
|
38
|
+
|
|
39
|
+
__all__ = [
|
|
40
|
+
"PROTOCOL_VERSION",
|
|
41
|
+
"SUBPROTOCOL",
|
|
42
|
+
"CandidatePairStats",
|
|
43
|
+
"Channel",
|
|
44
|
+
"ConnectionStats",
|
|
45
|
+
"DataChannelSpec",
|
|
46
|
+
"Direction",
|
|
47
|
+
"Engine",
|
|
48
|
+
"EngineCapabilities",
|
|
49
|
+
"ErrorCode",
|
|
50
|
+
"EventHook",
|
|
51
|
+
"IceServer",
|
|
52
|
+
"IceServerSource",
|
|
53
|
+
"IceServers",
|
|
54
|
+
"IncomingTrack",
|
|
55
|
+
"MediaPolicy",
|
|
56
|
+
"MediaStats",
|
|
57
|
+
"OutgoingTrack",
|
|
58
|
+
"Peer",
|
|
59
|
+
"Role",
|
|
60
|
+
"Session",
|
|
61
|
+
"SessionClosedError",
|
|
62
|
+
"SessionContext",
|
|
63
|
+
"SessionDeclaration",
|
|
64
|
+
"SessionEvent",
|
|
65
|
+
"SessionLimits",
|
|
66
|
+
"TurnRestCredentials",
|
|
67
|
+
"WebRtcError",
|
|
68
|
+
"WebRtcRouter",
|
|
69
|
+
"__version__",
|
|
70
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Client generation from ``fastapi-webrtc`` session contracts."""
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""``fastapi-webrtc`` command line: export contracts and generate clients."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import hashlib
|
|
5
|
+
import importlib
|
|
6
|
+
import json
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any, cast
|
|
10
|
+
|
|
11
|
+
from fastapi import FastAPI
|
|
12
|
+
|
|
13
|
+
from fastapi_webrtc import __version__
|
|
14
|
+
from fastapi_webrtc.codegen.typescript import (
|
|
15
|
+
DEFAULT_CLIENT_NAME,
|
|
16
|
+
ContractError,
|
|
17
|
+
generate_typescript,
|
|
18
|
+
)
|
|
19
|
+
from fastapi_webrtc.codegen.writer import write_files
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def main(argv: list[str] | None = None) -> int:
|
|
23
|
+
parser = argparse.ArgumentParser(prog="fastapi-webrtc")
|
|
24
|
+
parser.add_argument("--version", action="version", version=__version__)
|
|
25
|
+
commands = parser.add_subparsers(dest="command", required=True)
|
|
26
|
+
|
|
27
|
+
contract = commands.add_parser(
|
|
28
|
+
"contract", help="Export the session contract of a FastAPI application"
|
|
29
|
+
)
|
|
30
|
+
contract.add_argument("--app", required=True, help="module:attribute")
|
|
31
|
+
contract.add_argument("--output", required=True, type=Path)
|
|
32
|
+
contract.add_argument(
|
|
33
|
+
"--check", action="store_true", help="Fail if the file is out of date"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
generate = commands.add_parser(
|
|
37
|
+
"generate", help="Generate the TypeScript browser client of a contract"
|
|
38
|
+
)
|
|
39
|
+
source = generate.add_mutually_exclusive_group(required=True)
|
|
40
|
+
source.add_argument("--contract", type=Path, help="Contract JSON file")
|
|
41
|
+
source.add_argument("--app", help="module:attribute, instead of --contract")
|
|
42
|
+
generate.add_argument("--output", required=True, type=Path)
|
|
43
|
+
generate.add_argument("--client-name", default=DEFAULT_CLIENT_NAME)
|
|
44
|
+
generate.add_argument(
|
|
45
|
+
"--check", action="store_true", help="Fail if generated files are out of date"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
args = parser.parse_args(argv)
|
|
49
|
+
try:
|
|
50
|
+
if args.command == "contract":
|
|
51
|
+
return _contract(args.app, cast(Path, args.output), check=args.check)
|
|
52
|
+
return _generate(args)
|
|
53
|
+
except (ContractError, OSError, ValueError, ImportError, AttributeError) as exc:
|
|
54
|
+
print(f"fastapi-webrtc: {exc}", file=sys.stderr)
|
|
55
|
+
return 2
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _contract(app: str, output: Path, *, check: bool) -> int:
|
|
59
|
+
from fastapi_webrtc.contract import build_contract, dumps
|
|
60
|
+
|
|
61
|
+
content = dumps(build_contract(_load_app(app)))
|
|
62
|
+
if check:
|
|
63
|
+
if not output.is_file() or output.read_bytes() != content.encode("utf-8"):
|
|
64
|
+
print(f"Out of date: {output}", file=sys.stderr)
|
|
65
|
+
return 1
|
|
66
|
+
return 0
|
|
67
|
+
output.parent.mkdir(parents=True, exist_ok=True)
|
|
68
|
+
output.write_text(content, encoding="utf-8", newline="\n")
|
|
69
|
+
return 0
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _generate(args: argparse.Namespace) -> int:
|
|
73
|
+
contract: Any
|
|
74
|
+
if args.app is not None:
|
|
75
|
+
from fastapi_webrtc.contract import build_contract
|
|
76
|
+
|
|
77
|
+
contract = build_contract(_load_app(args.app))
|
|
78
|
+
else:
|
|
79
|
+
contract = json.loads(cast(Path, args.contract).read_text(encoding="utf-8"))
|
|
80
|
+
if not isinstance(contract, dict):
|
|
81
|
+
raise ContractError("The contract must be a JSON object")
|
|
82
|
+
encoded = json.dumps(
|
|
83
|
+
contract, sort_keys=True, separators=(",", ":"), ensure_ascii=False
|
|
84
|
+
).encode("utf-8")
|
|
85
|
+
generation: dict[str, str | None] = {
|
|
86
|
+
"generator": "fastapi-webrtc",
|
|
87
|
+
"generator_version": __version__,
|
|
88
|
+
"contract_sha256": hashlib.sha256(encoded).hexdigest(),
|
|
89
|
+
"contract_hash_encoding": "canonical-json-v1",
|
|
90
|
+
"target": "typescript",
|
|
91
|
+
"client_name": args.client_name,
|
|
92
|
+
}
|
|
93
|
+
files = generate_typescript(contract, client_name=args.client_name)
|
|
94
|
+
changed = write_files(
|
|
95
|
+
cast(Path, args.output), files, check=args.check, generation=generation
|
|
96
|
+
)
|
|
97
|
+
if args.check and changed:
|
|
98
|
+
for path in changed:
|
|
99
|
+
print(f"Out of date: {path}", file=sys.stderr)
|
|
100
|
+
return 1
|
|
101
|
+
return 0
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _load_app(value: str) -> FastAPI:
|
|
105
|
+
module, separator, attribute = value.partition(":")
|
|
106
|
+
if not separator or not module or not attribute:
|
|
107
|
+
raise ContractError("--app must use module:attribute syntax")
|
|
108
|
+
# Console scripts start with their installation directory on sys.path.
|
|
109
|
+
sys.path.insert(0, str(Path.cwd()))
|
|
110
|
+
app = getattr(importlib.import_module(module), attribute)
|
|
111
|
+
if not isinstance(app, FastAPI):
|
|
112
|
+
raise ContractError(f"{value} is not a FastAPI application")
|
|
113
|
+
return app
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
if __name__ == "__main__":
|
|
117
|
+
sys.exit(main())
|