Skip to content

Commit 0a85483

Browse files
authored
Add method for validating the go2rtc server version is supported (#5)
* Add method for validating the go2rtc server version is supported * Silence ruff * Add fixture * Use awesomeversion * Run linters * Improve test coverage
1 parent 2b1f6db commit 0a85483

7 files changed

Lines changed: 122 additions & 2 deletions

File tree

go2rtc_client/models.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,30 @@
55
from dataclasses import dataclass, field
66
from typing import Literal
77

8+
from awesomeversion import AwesomeVersion
9+
from mashumaro import field_options
810
from mashumaro.mixins.orjson import DataClassORJSONMixin
11+
from mashumaro.types import SerializationStrategy
12+
13+
14+
class _AwesomeVersionSerializer(SerializationStrategy):
15+
def serialize(self, value: AwesomeVersion) -> str:
16+
return str(value)
17+
18+
def deserialize(self, value: str) -> AwesomeVersion:
19+
return AwesomeVersion(value)
20+
21+
22+
@dataclass
23+
class ApplicationInfo(DataClassORJSONMixin):
24+
"""Application info model.
25+
26+
Currently only the server version is exposed.
27+
"""
28+
29+
version: AwesomeVersion = field(
30+
metadata=field_options(serialization_strategy=_AwesomeVersionSerializer())
31+
)
932

1033

1134
@dataclass

go2rtc_client/rest.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,21 @@
77

88
from aiohttp import ClientError, ClientResponse, ClientSession
99
from aiohttp.client import _RequestOptions
10+
from awesomeversion import AwesomeVersion
1011
from mashumaro.codecs.basic import BasicDecoder
1112
from mashumaro.mixins.dict import DataClassDictMixin
1213
from yarl import URL
1314

1415
from .exceptions import handle_error
15-
from .models import Stream, WebRTCSdpAnswer, WebRTCSdpOffer
16+
from .models import ApplicationInfo, Stream, WebRTCSdpAnswer, WebRTCSdpOffer
1617

1718
if TYPE_CHECKING:
1819
from collections.abc import Mapping
1920

2021
_LOGGER = logging.getLogger(__name__)
2122

2223
_API_PREFIX = "/api"
24+
_SUPPORTED_VERSION: Final = AwesomeVersion("1.9.4")
2325

2426

2527
class _BaseClient:
@@ -58,6 +60,19 @@ async def request(
5860
return resp
5961

6062

63+
class _ApplicationClient:
64+
PATH: Final = _API_PREFIX
65+
66+
def __init__(self, client: _BaseClient) -> None:
67+
"""Initialize Client."""
68+
self._client = client
69+
70+
async def get_info(self) -> ApplicationInfo:
71+
"""Get application info."""
72+
resp = await self._client.request("GET", self.PATH)
73+
return ApplicationInfo.from_dict(await resp.json())
74+
75+
6176
class _WebRTCClient:
6277
"""Client for WebRTC module."""
6378

@@ -123,5 +138,11 @@ class Go2RtcRestClient:
123138
def __init__(self, websession: ClientSession, server_url: str) -> None:
124139
"""Initialize Client."""
125140
self._client = _BaseClient(websession, server_url)
141+
self.application: Final = _ApplicationClient(self._client)
126142
self.streams: Final = _StreamClient(self._client)
127143
self.webrtc: Final = _WebRTCClient(self._client)
144+
145+
async def validate_server_version(self) -> bool:
146+
"""Validate the server version is compatible."""
147+
application_info = await self.application.get_info()
148+
return application_info.version == _SUPPORTED_VERSION

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ classifiers = [
1919
requires-python = ">=3.12.0"
2020
dependencies = [
2121
"aiohttp~=3.10",
22+
"awesomeversion>=24.6.0",
2223
"mashumaro~=3.13",
2324
"orjson>=3.10.7",
2425
]

tests/__snapshots__/test_rest.ambr

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
# serializer version: 1
2+
# name: test_application_info
3+
dict({
4+
'version': <AwesomeVersion SemVer '1.9.4'>,
5+
})
6+
# ---
7+
# name: test_application_info.1
8+
dict({
9+
'version': '1.9.4',
10+
})
11+
# ---
212
# name: test_streams_get[empty]
313
dict({
414
})
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"config_path": "/home/erik/go2rtc/go2rtc.yaml",
3+
"host": "127.0.0.1:1984",
4+
"revision": "a4885c2",
5+
"rtsp": { "listen": ":8554", "default_query": "video\u0026audio" },
6+
"version": "1.9.4"
7+
}

tests/test_rest.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
from __future__ import annotations
44

5+
import json
56
from typing import TYPE_CHECKING
67

78
from aiohttp.hdrs import METH_PUT
9+
from awesomeversion import AwesomeVersion
810
import pytest
911

1012
from go2rtc_client.models import WebRTCSdpOffer
11-
from go2rtc_client.rest import _StreamClient, _WebRTCClient
13+
from go2rtc_client.rest import _ApplicationClient, _StreamClient, _WebRTCClient
1214
from tests import load_fixture
1315

1416
from . import URL
@@ -20,6 +22,23 @@
2022
from go2rtc_client import Go2RtcRestClient
2123

2224

25+
async def test_application_info(
26+
responses: aioresponses,
27+
rest_client: Go2RtcRestClient,
28+
snapshot: SnapshotAssertion,
29+
) -> None:
30+
"""Test webrtc offer."""
31+
responses.get(
32+
f"{URL}{_ApplicationClient.PATH}",
33+
status=200,
34+
body=load_fixture("application_info_answer.json"),
35+
)
36+
resp = await rest_client.application.get_info()
37+
assert isinstance(resp.version, AwesomeVersion)
38+
assert resp == snapshot
39+
assert resp.to_dict() == snapshot
40+
41+
2342
@pytest.mark.parametrize(
2443
"filename",
2544
[
@@ -69,6 +88,34 @@ async def test_streams_add(
6988
responses.assert_called_once_with(url, method=METH_PUT, params=params)
7089

7190

91+
@pytest.mark.parametrize(
92+
("server_version", "expected_result"),
93+
[
94+
("0.0.0", False),
95+
("1.9.3", False),
96+
("1.9.4", True),
97+
("1.9.5", False),
98+
("2.0.0", False),
99+
("BLAH", False),
100+
],
101+
)
102+
async def test_version_supported(
103+
responses: aioresponses,
104+
rest_client: Go2RtcRestClient,
105+
server_version: str,
106+
expected_result: bool,
107+
) -> None:
108+
"""Test webrtc offer."""
109+
payload = json.loads(load_fixture("application_info_answer.json"))
110+
payload["version"] = server_version
111+
responses.get(
112+
f"{URL}{_ApplicationClient.PATH}",
113+
status=200,
114+
payload=payload,
115+
)
116+
assert await rest_client.validate_server_version() == expected_result
117+
118+
72119
async def test_webrtc_offer(
73120
responses: aioresponses,
74121
rest_client: Go2RtcRestClient,

uv.lock

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)