Skip to content

Commit

Permalink
Add file component (#24)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
roznawsk authored Dec 29, 2023
1 parent 25d3d16 commit d56495e
Show file tree
Hide file tree
Showing 14 changed files with 229 additions and 34 deletions.
3 changes: 3 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ jobs:
- run:
name: Lint
command: poetry run lint
- run:
name: Check format
command: poetry run format_check
- persist_to_workspace:
root: ~/project
paths:
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ You can test the SDK by running
poetry run ci_test
```

In local development you can use
```
poetry run local_test
```

## Format & Lint
You can format code by running
```console
Expand Down
2 changes: 2 additions & 0 deletions docker-compose-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ services:
- "5002:5002"
- "49999:49999"
- "50000-50050:50000-50050/udp"
volumes:
- ./tests/fixtures:/app/jellyfish_resources/file_component_sources

test:
container_name: test
Expand Down
6 changes: 6 additions & 0 deletions jellyfish/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@

# Models
from jellyfish._openapi_client.models import (
ComponentFile,
ComponentHLS,
ComponentOptionsFile,
ComponentOptionsHLS,
ComponentOptionsHLSSubscribeMode,
ComponentOptionsRTSP,
ComponentPropertiesFile,
ComponentPropertiesHLS,
ComponentPropertiesHLSSubscribeMode,
ComponentPropertiesRTSP,
Expand Down Expand Up @@ -50,6 +53,9 @@
"ComponentRTSP",
"ComponentOptionsRTSP",
"ComponentPropertiesRTSP",
"ComponentFile",
"ComponentOptionsFile",
"ComponentPropertiesFile",
"events",
"errors",
]
Expand Down
2 changes: 2 additions & 0 deletions jellyfish/_openapi_client/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from .component_options_hls import ComponentOptionsHLS
from .component_options_hls_subscribe_mode import ComponentOptionsHLSSubscribeMode
from .component_options_rtsp import ComponentOptionsRTSP
from .component_properties_file import ComponentPropertiesFile
from .component_properties_hls import ComponentPropertiesHLS
from .component_properties_hls_subscribe_mode import ComponentPropertiesHLSSubscribeMode
from .component_properties_rtsp import ComponentPropertiesRTSP
Expand Down Expand Up @@ -40,6 +41,7 @@
"ComponentOptionsHLS",
"ComponentOptionsHLSSubscribeMode",
"ComponentOptionsRTSP",
"ComponentPropertiesFile",
"ComponentPropertiesHLS",
"ComponentPropertiesHLSSubscribeMode",
"ComponentPropertiesRTSP",
Expand Down
25 changes: 24 additions & 1 deletion jellyfish/_openapi_client/models/component_file.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
from typing import Any, Dict, List, Type, TypeVar
from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar, Union

from attrs import define as _attrs_define
from attrs import field as _attrs_field

from ..types import UNSET, Unset

if TYPE_CHECKING:
from ..models.component_properties_file import ComponentPropertiesFile


T = TypeVar("T", bound="ComponentFile")


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

def to_dict(self) -> Dict[str, Any]:
"""@private"""
id = self.id
type = self.type
properties: Union[Unset, Dict[str, Any]] = UNSET
if not isinstance(self.properties, Unset):
properties = self.properties.to_dict()

field_dict: Dict[str, Any] = {}
field_dict.update(self.additional_properties)
Expand All @@ -30,20 +41,32 @@ def to_dict(self) -> Dict[str, Any]:
"type": type,
}
)
if properties is not UNSET:
field_dict["properties"] = properties

return field_dict

@classmethod
def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
"""@private"""
from ..models.component_properties_file import ComponentPropertiesFile

d = src_dict.copy()
id = d.pop("id")

type = d.pop("type")

_properties = d.pop("properties", UNSET)
properties: Union[Unset, ComponentPropertiesFile]
if isinstance(_properties, Unset):
properties = UNSET
else:
properties = ComponentPropertiesFile.from_dict(_properties)

component_file = cls(
id=id,
type=type,
properties=properties,
)

component_file.additional_properties = d
Expand Down
60 changes: 60 additions & 0 deletions jellyfish/_openapi_client/models/component_properties_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from typing import Any, Dict, List, Type, TypeVar

from attrs import define as _attrs_define
from attrs import field as _attrs_field

T = TypeVar("T", bound="ComponentPropertiesFile")


@_attrs_define
class ComponentPropertiesFile:
"""Properties specific to the File component"""

file_path: str
"""Path to track file. Must be either OPUS encapsulated in Ogg or raw h264"""
additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict)
"""@private"""

def to_dict(self) -> Dict[str, Any]:
"""@private"""
file_path = self.file_path

field_dict: Dict[str, Any] = {}
field_dict.update(self.additional_properties)
field_dict.update(
{
"filePath": file_path,
}
)

return field_dict

@classmethod
def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
"""@private"""
d = src_dict.copy()
file_path = d.pop("filePath")

component_properties_file = cls(
file_path=file_path,
)

component_properties_file.additional_properties = d
return component_properties_file

@property
def additional_keys(self) -> List[str]:
"""@private"""
return list(self.additional_properties.keys())

def __getitem__(self, key: str) -> Any:
return self.additional_properties[key]

def __setitem__(self, key: str, value: Any) -> None:
self.additional_properties[key] = value

def __delitem__(self, key: str) -> None:
del self.additional_properties[key]

def __contains__(self, key: str) -> bool:
return key in self.additional_properties
51 changes: 48 additions & 3 deletions jellyfish/_openapi_client/models/component_properties_rtsp.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,77 @@
from typing import Any, Dict, List, Type, TypeVar
from typing import Any, Dict, List, Type, TypeVar, Union

from attrs import define as _attrs_define
from attrs import field as _attrs_field

from ..types import UNSET, Unset

T = TypeVar("T", bound="ComponentPropertiesRTSP")


@_attrs_define
class ComponentPropertiesRTSP:
"""Properties specific to the RTSP component"""

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

def to_dict(self) -> Dict[str, Any]:
"""@private"""
source_uri = self.source_uri
keep_alive_interval = self.keep_alive_interval
pierce_nat = self.pierce_nat
reconnect_delay = self.reconnect_delay
rtp_port = self.rtp_port

field_dict: Dict[str, Any] = {}
field_dict.update(self.additional_properties)
field_dict.update({})
field_dict.update(
{
"sourceUri": source_uri,
}
)
if keep_alive_interval is not UNSET:
field_dict["keepAliveInterval"] = keep_alive_interval
if pierce_nat is not UNSET:
field_dict["pierceNat"] = pierce_nat
if reconnect_delay is not UNSET:
field_dict["reconnectDelay"] = reconnect_delay
if rtp_port is not UNSET:
field_dict["rtpPort"] = rtp_port

return field_dict

@classmethod
def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
"""@private"""
d = src_dict.copy()
component_properties_rtsp = cls()
source_uri = d.pop("sourceUri")

keep_alive_interval = d.pop("keepAliveInterval", UNSET)

pierce_nat = d.pop("pierceNat", UNSET)

reconnect_delay = d.pop("reconnectDelay", UNSET)

rtp_port = d.pop("rtpPort", UNSET)

component_properties_rtsp = cls(
source_uri=source_uri,
keep_alive_interval=keep_alive_interval,
pierce_nat=pierce_nat,
reconnect_delay=reconnect_delay,
rtp_port=rtp_port,
)

component_properties_rtsp.additional_properties = d
return component_properties_rtsp
Expand Down
15 changes: 11 additions & 4 deletions jellyfish/api/_room_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
from jellyfish._openapi_client.models import (
AddComponentJsonBody,
AddPeerJsonBody,
ComponentFile,
ComponentHLS,
ComponentOptionsFile,
ComponentOptionsHLS,
ComponentOptionsRTSP,
ComponentRTSP,
Expand Down Expand Up @@ -119,17 +121,22 @@ def delete_peer(self, room_id: str, peer_id: str) -> None:
return self._request(room_delete_peer, id=peer_id, room_id=room_id)

def add_component(
self, room_id: str, options: Union[ComponentOptionsHLS, ComponentOptionsRTSP]
) -> Union[ComponentHLS, ComponentRTSP]:
self,
room_id: str,
options: Union[ComponentOptionsFile, ComponentOptionsHLS, ComponentOptionsRTSP],
) -> Union[ComponentFile, ComponentHLS, ComponentRTSP]:
"""Creates component in the room"""

if isinstance(options, ComponentOptionsHLS):
if isinstance(options, ComponentOptionsFile):
component_type = "file"
elif isinstance(options, ComponentOptionsHLS):
component_type = "hls"
elif isinstance(options, ComponentOptionsRTSP):
component_type = "rtsp"
else:
raise ValueError(
"options must be either ComponentOptionsHLS or ComponentOptionsRTSP"
"options must be ComponentFile, ComponentOptionsHLS"
"or ComponentOptionsRTSP"
)

json_body = AddComponentJsonBody(type=component_type, options=options)
Expand Down
8 changes: 8 additions & 0 deletions poetry_scripts.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,18 @@ def run_tests():
check_exit_code("docker compose -f docker-compose-test.yaml down")


def run_local_test():
check_exit_code('poetry run pytest -m "not file_component_sources"')


def run_formatter():
check_exit_code("ruff format .")


def run_format_check():
check_exit_code("ruff format . --check")


def run_linter():
check_exit_code("ruff check .")

Expand Down
7 changes: 7 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ build-backend = "poetry.core.masonry.api"

[tool.poetry.scripts]
ci_test = "poetry_scripts:run_tests"
local_test = "poetry_scripts:run_local_test"
format = "poetry_scripts:run_formatter"
format_check = "poetry_scripts:run_format_check"
lint = "poetry_scripts:run_linter"
fix_lint = "poetry_scripts:run_linter_fix"
generate_docs = "poetry_scripts:generate_docs"
Expand All @@ -54,3 +56,8 @@ ignore = []

[tool.ruff.extend-per-file-ignores]
"jellyfish/_openapi_client/**" = ["E501"]

[tool.pytest.ini_options]
markers = [
"file_component_sources: Tests requiring files uploaded for File Component"
]
Binary file added tests/fixtures/audio.ogg
Binary file not shown.
Binary file added tests/fixtures/video.h264
Binary file not shown.
Loading

0 comments on commit d56495e

Please sign in to comment.