Skip to content

Commit d56495e

Browse files
authored
Add file component (#24)
* Add file component * Allow for ignoring file tests locally (#25) * Test components using function * revert match * Add volume in tests * Poetry script for local tests
1 parent 25d3d16 commit d56495e

File tree

14 files changed

+229
-34
lines changed

14 files changed

+229
-34
lines changed

.circleci/config.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ jobs:
2020
- run:
2121
name: Lint
2222
command: poetry run lint
23+
- run:
24+
name: Check format
25+
command: poetry run format_check
2326
- persist_to_workspace:
2427
root: ~/project
2528
paths:

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ You can test the SDK by running
9898
poetry run ci_test
9999
```
100100

101+
In local development you can use
102+
```
103+
poetry run local_test
104+
```
105+
101106
## Format & Lint
102107
You can format code by running
103108
```console

docker-compose-test.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ services:
2525
- "5002:5002"
2626
- "49999:49999"
2727
- "50000-50050:50000-50050/udp"
28+
volumes:
29+
- ./tests/fixtures:/app/jellyfish_resources/file_component_sources
2830

2931
test:
3032
container_name: test

jellyfish/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@
99

1010
# Models
1111
from jellyfish._openapi_client.models import (
12+
ComponentFile,
1213
ComponentHLS,
14+
ComponentOptionsFile,
1315
ComponentOptionsHLS,
1416
ComponentOptionsHLSSubscribeMode,
1517
ComponentOptionsRTSP,
18+
ComponentPropertiesFile,
1619
ComponentPropertiesHLS,
1720
ComponentPropertiesHLSSubscribeMode,
1821
ComponentPropertiesRTSP,
@@ -50,6 +53,9 @@
5053
"ComponentRTSP",
5154
"ComponentOptionsRTSP",
5255
"ComponentPropertiesRTSP",
56+
"ComponentFile",
57+
"ComponentOptionsFile",
58+
"ComponentPropertiesFile",
5359
"events",
5460
"errors",
5561
]

jellyfish/_openapi_client/models/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from .component_options_hls import ComponentOptionsHLS
1010
from .component_options_hls_subscribe_mode import ComponentOptionsHLSSubscribeMode
1111
from .component_options_rtsp import ComponentOptionsRTSP
12+
from .component_properties_file import ComponentPropertiesFile
1213
from .component_properties_hls import ComponentPropertiesHLS
1314
from .component_properties_hls_subscribe_mode import ComponentPropertiesHLSSubscribeMode
1415
from .component_properties_rtsp import ComponentPropertiesRTSP
@@ -40,6 +41,7 @@
4041
"ComponentOptionsHLS",
4142
"ComponentOptionsHLSSubscribeMode",
4243
"ComponentOptionsRTSP",
44+
"ComponentPropertiesFile",
4345
"ComponentPropertiesHLS",
4446
"ComponentPropertiesHLSSubscribeMode",
4547
"ComponentPropertiesRTSP",

jellyfish/_openapi_client/models/component_file.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1-
from typing import Any, Dict, List, Type, TypeVar
1+
from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar, Union
22

33
from attrs import define as _attrs_define
44
from attrs import field as _attrs_field
55

6+
from ..types import UNSET, Unset
7+
8+
if TYPE_CHECKING:
9+
from ..models.component_properties_file import ComponentPropertiesFile
10+
11+
612
T = TypeVar("T", bound="ComponentFile")
713

814

@@ -14,13 +20,18 @@ class ComponentFile:
1420
"""Assigned component ID"""
1521
type: str
1622
"""Component type"""
23+
properties: Union[Unset, "ComponentPropertiesFile"] = UNSET
24+
"""Properties specific to the File component"""
1725
additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
1826
"""@private"""
1927

2028
def to_dict(self) -> Dict[str, Any]:
2129
"""@private"""
2230
id = self.id
2331
type = self.type
32+
properties: Union[Unset, Dict[str, Any]] = UNSET
33+
if not isinstance(self.properties, Unset):
34+
properties = self.properties.to_dict()
2435

2536
field_dict: Dict[str, Any] = {}
2637
field_dict.update(self.additional_properties)
@@ -30,20 +41,32 @@ def to_dict(self) -> Dict[str, Any]:
3041
"type": type,
3142
}
3243
)
44+
if properties is not UNSET:
45+
field_dict["properties"] = properties
3346

3447
return field_dict
3548

3649
@classmethod
3750
def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
3851
"""@private"""
52+
from ..models.component_properties_file import ComponentPropertiesFile
53+
3954
d = src_dict.copy()
4055
id = d.pop("id")
4156

4257
type = d.pop("type")
4358

59+
_properties = d.pop("properties", UNSET)
60+
properties: Union[Unset, ComponentPropertiesFile]
61+
if isinstance(_properties, Unset):
62+
properties = UNSET
63+
else:
64+
properties = ComponentPropertiesFile.from_dict(_properties)
65+
4466
component_file = cls(
4567
id=id,
4668
type=type,
69+
properties=properties,
4770
)
4871

4972
component_file.additional_properties = d
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
from typing import Any, Dict, List, Type, TypeVar
2+
3+
from attrs import define as _attrs_define
4+
from attrs import field as _attrs_field
5+
6+
T = TypeVar("T", bound="ComponentPropertiesFile")
7+
8+
9+
@_attrs_define
10+
class ComponentPropertiesFile:
11+
"""Properties specific to the File component"""
12+
13+
file_path: str
14+
"""Path to track file. Must be either OPUS encapsulated in Ogg or raw h264"""
15+
additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
16+
"""@private"""
17+
18+
def to_dict(self) -> Dict[str, Any]:
19+
"""@private"""
20+
file_path = self.file_path
21+
22+
field_dict: Dict[str, Any] = {}
23+
field_dict.update(self.additional_properties)
24+
field_dict.update(
25+
{
26+
"filePath": file_path,
27+
}
28+
)
29+
30+
return field_dict
31+
32+
@classmethod
33+
def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
34+
"""@private"""
35+
d = src_dict.copy()
36+
file_path = d.pop("filePath")
37+
38+
component_properties_file = cls(
39+
file_path=file_path,
40+
)
41+
42+
component_properties_file.additional_properties = d
43+
return component_properties_file
44+
45+
@property
46+
def additional_keys(self) -> List[str]:
47+
"""@private"""
48+
return list(self.additional_properties.keys())
49+
50+
def __getitem__(self, key: str) -> Any:
51+
return self.additional_properties[key]
52+
53+
def __setitem__(self, key: str, value: Any) -> None:
54+
self.additional_properties[key] = value
55+
56+
def __delitem__(self, key: str) -> None:
57+
del self.additional_properties[key]
58+
59+
def __contains__(self, key: str) -> bool:
60+
return key in self.additional_properties

jellyfish/_openapi_client/models/component_properties_rtsp.py

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,77 @@
1-
from typing import Any, Dict, List, Type, TypeVar
1+
from typing import Any, Dict, List, Type, TypeVar, Union
22

33
from attrs import define as _attrs_define
44
from attrs import field as _attrs_field
55

6+
from ..types import UNSET, Unset
7+
68
T = TypeVar("T", bound="ComponentPropertiesRTSP")
79

810

911
@_attrs_define
1012
class ComponentPropertiesRTSP:
1113
"""Properties specific to the RTSP component"""
1214

15+
source_uri: str
16+
"""URI of RTSP source stream"""
17+
keep_alive_interval: Union[Unset, int] = UNSET
18+
"""Interval (in ms) in which keep-alive RTSP messages will be sent to the remote stream source"""
19+
pierce_nat: Union[Unset, bool] = UNSET
20+
"""Whether to attempt to create client-side NAT binding by sending an empty datagram from client to source, after the completion of RTSP setup"""
21+
reconnect_delay: Union[Unset, int] = UNSET
22+
"""Delay (in ms) between successive reconnect attempts"""
23+
rtp_port: Union[Unset, int] = UNSET
24+
"""Local port RTP stream will be received at"""
1325
additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
1426
"""@private"""
1527

1628
def to_dict(self) -> Dict[str, Any]:
1729
"""@private"""
30+
source_uri = self.source_uri
31+
keep_alive_interval = self.keep_alive_interval
32+
pierce_nat = self.pierce_nat
33+
reconnect_delay = self.reconnect_delay
34+
rtp_port = self.rtp_port
1835

1936
field_dict: Dict[str, Any] = {}
2037
field_dict.update(self.additional_properties)
21-
field_dict.update({})
38+
field_dict.update(
39+
{
40+
"sourceUri": source_uri,
41+
}
42+
)
43+
if keep_alive_interval is not UNSET:
44+
field_dict["keepAliveInterval"] = keep_alive_interval
45+
if pierce_nat is not UNSET:
46+
field_dict["pierceNat"] = pierce_nat
47+
if reconnect_delay is not UNSET:
48+
field_dict["reconnectDelay"] = reconnect_delay
49+
if rtp_port is not UNSET:
50+
field_dict["rtpPort"] = rtp_port
2251

2352
return field_dict
2453

2554
@classmethod
2655
def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
2756
"""@private"""
2857
d = src_dict.copy()
29-
component_properties_rtsp = cls()
58+
source_uri = d.pop("sourceUri")
59+
60+
keep_alive_interval = d.pop("keepAliveInterval", UNSET)
61+
62+
pierce_nat = d.pop("pierceNat", UNSET)
63+
64+
reconnect_delay = d.pop("reconnectDelay", UNSET)
65+
66+
rtp_port = d.pop("rtpPort", UNSET)
67+
68+
component_properties_rtsp = cls(
69+
source_uri=source_uri,
70+
keep_alive_interval=keep_alive_interval,
71+
pierce_nat=pierce_nat,
72+
reconnect_delay=reconnect_delay,
73+
rtp_port=rtp_port,
74+
)
3075

3176
component_properties_rtsp.additional_properties = d
3277
return component_properties_rtsp

jellyfish/api/_room_api.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
from jellyfish._openapi_client.models import (
1717
AddComponentJsonBody,
1818
AddPeerJsonBody,
19+
ComponentFile,
1920
ComponentHLS,
21+
ComponentOptionsFile,
2022
ComponentOptionsHLS,
2123
ComponentOptionsRTSP,
2224
ComponentRTSP,
@@ -119,17 +121,22 @@ def delete_peer(self, room_id: str, peer_id: str) -> None:
119121
return self._request(room_delete_peer, id=peer_id, room_id=room_id)
120122

121123
def add_component(
122-
self, room_id: str, options: Union[ComponentOptionsHLS, ComponentOptionsRTSP]
123-
) -> Union[ComponentHLS, ComponentRTSP]:
124+
self,
125+
room_id: str,
126+
options: Union[ComponentOptionsFile, ComponentOptionsHLS, ComponentOptionsRTSP],
127+
) -> Union[ComponentFile, ComponentHLS, ComponentRTSP]:
124128
"""Creates component in the room"""
125129

126-
if isinstance(options, ComponentOptionsHLS):
130+
if isinstance(options, ComponentOptionsFile):
131+
component_type = "file"
132+
elif isinstance(options, ComponentOptionsHLS):
127133
component_type = "hls"
128134
elif isinstance(options, ComponentOptionsRTSP):
129135
component_type = "rtsp"
130136
else:
131137
raise ValueError(
132-
"options must be either ComponentOptionsHLS or ComponentOptionsRTSP"
138+
"options must be ComponentFile, ComponentOptionsHLS"
139+
"or ComponentOptionsRTSP"
133140
)
134141

135142
json_body = AddComponentJsonBody(type=component_type, options=options)

poetry_scripts.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,18 @@ def run_tests():
2020
check_exit_code("docker compose -f docker-compose-test.yaml down")
2121

2222

23+
def run_local_test():
24+
check_exit_code('poetry run pytest -m "not file_component_sources"')
25+
26+
2327
def run_formatter():
2428
check_exit_code("ruff format .")
2529

2630

31+
def run_format_check():
32+
check_exit_code("ruff format . --check")
33+
34+
2735
def run_linter():
2836
check_exit_code("ruff check .")
2937

0 commit comments

Comments
 (0)