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.
@@ -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())