Skip to content

Commit

Permalink
Fetched template changes (#33)
Browse files Browse the repository at this point in the history
  • Loading branch information
spietras authored Aug 7, 2024
1 parent f390c58 commit 881cbd5
Show file tree
Hide file tree
Showing 51 changed files with 982 additions and 651 deletions.
2 changes: 1 addition & 1 deletion .copier-answers.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Changes here will be overwritten by Copier; NEVER EDIT MANUALLY
_commit: 0.13.0
_commit: 0.15.0
_src_path: gh:radio-aktywne/template-app-litestar
accountname: radio-aktywne
appname: emipass
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions .github/workflows/image.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ name: Image
- scripts/**
- src/**
- .dockerignore
- .env
- .env.python
- Dockerfile
- flake.lock
- "*.nix"
Expand All @@ -33,7 +33,7 @@ name: Image
- scripts/**
- src/**
- .dockerignore
- .env
- .env.python
- Dockerfile
- flake.lock
- "*.nix"
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ name: Test
- plugins/**
- src/**
- tests/**
- .env
- .env.python
- flake.lock
- "*.nix"
- poetry.lock
Expand All @@ -31,7 +31,7 @@ name: Test
- plugins/**
- src/**
- tests/**
- .env
- .env.python
- flake.lock
- "*.nix"
- poetry.lock
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@ __pycache__/

# Environment
/.venv/

# Environment variables
.env
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"request": "launch",
"module": "emipass",
"justMyCode": false,
"envFile": ".env"
"envFile": ".env.python"
}
]
}
6 changes: 3 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@ RUN poetry build --no-interaction --format wheel && \
poetry run -- python -m pip install --no-deps --no-index --no-cache-dir dist/*.whl && \
rm --recursive --force dist/ ./*.egg-info

# Copy env file
COPY .env .env
# Copy file with environment variables for Python
COPY .env.python .env.python

# Setup main entrypoint
COPY scripts/entrypoint.sh scripts/entrypoint.sh
ENTRYPOINT ["/app/scripts/entrypoint.sh", "poetry", "run", "--", "dotenv", "run", "--", "emipass"]
ENTRYPOINT ["/app/scripts/entrypoint.sh", "poetry", "run", "--", "dotenv", "--file", ".env.python", "run", "--", "emipass"]
CMD []

# Setup ownership
Expand Down
4 changes: 4 additions & 0 deletions Taskfile.dist.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ tasks:
run
--
dotenv
--file
.env.python
run
--
pytest
Expand All @@ -217,6 +219,8 @@ tasks:
run
--
dotenv
--file
.env.python
run
--
emipass
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ services:
- "EMIPASS__STREAMER__STUN__HOST=${EMIPASS__STREAMER__STUN__HOST:-stun.l.google.com}"
- "EMIPASS__STREAMER__STUN__PORT=${EMIPASS__STREAMER__STUN__PORT:-19302}"
- "EMIPASS__STREAMER__TIMEOUT=${EMIPASS__STREAMER__TIMEOUT:-PT1M}"
- "EMIPASS__DEBUG=${EMIPASS__DEBUG:-false}"
network_mode: host
21 changes: 18 additions & 3 deletions docs/docs/02-Usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ For example, you can use [`curl`](https://curl.se) to do that:

```sh
curl \
-X POST \
-H "Content-Type: application/json" \
-d '{"srt": {"host": "example.com", "port": 12345}}' \
--request POST \
--header "Content-Type: application/json" \
--data '{"srt": {"host": "example.com", "port": 12345}}' \
http://localhost:11000/stream
```

Expand Down Expand Up @@ -65,3 +65,18 @@ gst-launch-1.0 \
whipclientsink \
signaller::whip-endpoint="http://localhost:11001/whip/endpoint"
```

## Ping

You can check the status of the app by sending
either a `GET` or `HEAD` request to the `/ping` endpoint.
The app should respond with a `204 No Content` status code.

For example, you can use `curl` to do that:

```sh
curl \
--request HEAD \
--head \
http://localhost:11000/ping
```
3 changes: 3 additions & 0 deletions docs/docs/03-Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,6 @@ You can configure the app at runtime using various environment variables:
- `EMIPASS__STREAMER__TIMEOUT` -
time after which a stream will be stopped if no connections are made
(default: `PT1M`)
- `EMIPASS__DEBUG` -
enable debug mode
(default: `false`)
3 changes: 0 additions & 3 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@
libnice
];

# Can't use PYTHONPATH directly because Poetry overrides it
EXTRAPYTHONPATH = "${python}/${python.sitePackages}";

# These are needed for custom GStreamer plugins
Expand Down Expand Up @@ -143,7 +142,6 @@
su-exec
];

# Can't use PYTHONPATH directly because Poetry overrides it
EXTRAPYTHONPATH = "${python}/${python.sitePackages}";

# These are needed for custom GStreamer plugins
Expand Down Expand Up @@ -203,7 +201,6 @@
libnice
];

# Can't use PYTHONPATH directly because Poetry overrides it
EXTRAPYTHONPATH = "${python}/${python.sitePackages}";

# These are needed for custom GStreamer plugins
Expand Down
322 changes: 161 additions & 161 deletions poetry.lock

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[tool.poetry]
package-mode = true
name = "emipass"
version = "0.6.0"
description = "WebRTC to SRT passthrough 💨"
Expand All @@ -8,23 +9,23 @@ authors = ["radio-aktywne <[email protected]>"]
python = "^3.12"
# Pydantic is used to define data models
pydantic = "^2.8"
pydantic-settings = "^2.3"
# OmegaConf is used to load configuration
omegaconf = "^2.3"
pydantic-settings = "^2.4"
# Typer and Rich are used to build CLIs
typer = "^0.12"
rich = "^13.7"
# Litestar and Uvicorn are used to build async APIs
litestar = "^2.10"
uvicorn = { version = "^0.30", extras = ["standard"] }
# For correct handling of timezones
tzdata = "*"
# Environment variables loader
python-dotenv = "^1.0"
# Streaming utilities
pystreams = { git = "https://github.com/radio-aktywne/package-pystreams.git", tag = "0.9.0" }
# Locking utilities
pylocks = { git = "https://github.com/radio-aktywne/package-pylocks.git", tag = "0.4.0" }
# Storage utilities
pystores = { git = "https://github.com/radio-aktywne/package-pystores.git", tag = "0.5.0" }
# Environment variables loader
python-dotenv = "^1.0"

[tool.poetry.group.test.dependencies]
pytest = "^8.3"
Expand Down
36 changes: 10 additions & 26 deletions src/emipass/__main__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from typing import Optional

import typer

from emipass.api.app import AppBuilder
Expand All @@ -13,46 +11,32 @@


@cli.command()
def main(
config_file: Optional[typer.FileText] = typer.Option(
None,
"--config-file",
"-C",
dir_okay=False,
help="Configuration file.",
),
config_overrides: Optional[list[str]] = typer.Option(
None,
"--config",
"-c",
help="Configuration entries.",
),
) -> None:
def main() -> None:
"""Main entry point."""

console = FallbackConsoleBuilder().build()

try:
config = ConfigBuilder(config_file, config_overrides).build()
except ConfigError as e:
console.print("Failed to load config!")
config = ConfigBuilder().build()
except ConfigError as ex:
console.print("Failed to build config!")
console.print_exception()
raise typer.Exit(1) from e
raise typer.Exit(1) from ex

try:
app = AppBuilder(config).build()
except Exception as e:
except Exception as ex:
console.print("Failed to build app!")
console.print_exception()
raise typer.Exit(2) from e
raise typer.Exit(2) from ex

try:
server = Server(app, config)
server = Server(app, config.server)
server.run()
except Exception as e:
except Exception as ex:
console.print("Failed to run server!")
console.print_exception()
raise typer.Exit(3) from e
raise typer.Exit(3) from ex


if __name__ == "__main__":
Expand Down
70 changes: 42 additions & 28 deletions src/emipass/api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@

from emipass.api.routes.router import router
from emipass.config.models import Config
from emipass.services.streaming.service import StreamingService
from emipass.state import State
from emipass.streaming.streamer import Streamer


class AppBuilder:
Expand All @@ -29,66 +29,80 @@ def __init__(self, config: Config) -> None:
def _get_route_handlers(self) -> list[Router]:
return [router]

def _get_debug(self) -> bool:
return self._config.debug

@asynccontextmanager
async def _suppress_httpx_logging_lifespan(
self, app: Litestar
) -> AsyncGenerator[None]:
logger = logging.getLogger("httpx")
disabled = logger.disabled
logger.disabled = True

try:
yield
finally:
logger.disabled = disabled

def _build_lifespan(
self,
) -> list[Callable[[Litestar], AbstractAsyncContextManager]]:
return [
self._suppress_httpx_logging_lifespan,
]

def _build_openapi_config(self) -> OpenAPIConfig:
return OpenAPIConfig(
# Title of the app
title="emipass app",
# Version of the app
version=metadata.version("emipass"),
description="WebRTC to SRT passthrough 💨",
# Description of the app
summary="WebRTC to SRT passthrough 💨",
# Use handler docstrings as operation descriptions
use_handler_docstrings=True,
# Endpoint to serve the OpenAPI docs from
path="/schema",
)

def _build_pydantic_plugin(self) -> PydanticPlugin:
return PydanticPlugin(
# Use aliases for serialization
prefer_alias=True,
# Allow type coercion
validate_strict=False,
)

def _build_plugins(self) -> list[PluginProtocol]:
return [
self._build_pydantic_plugin(),
]

def _build_streamer(self) -> Streamer:
return Streamer(
def _build_streaming(self) -> StreamingService:
return StreamingService(
config=self._config,
store=MemoryStore[set[int]](set()),
store=MemoryStore(set[int]()),
lock=AsyncioLock(),
)

def _build_initial_state(self) -> State:
config = self._config
streamer = self._build_streamer()
streaming = self._build_streaming()

return State(
{
"config": config,
"streamer": streamer,
"streaming": streaming,
}
)

@asynccontextmanager
async def _suppress_httpx_logging_lifespan(
self, app: Litestar
) -> AsyncGenerator[None]:
logger = logging.getLogger("httpx")
disabled = logger.disabled
logger.disabled = True

try:
yield
finally:
logger.disabled = disabled

def _build_lifespan(
self,
) -> list[Callable[[Litestar], AbstractAsyncContextManager]]:
return [
self._suppress_httpx_logging_lifespan,
]

def build(self) -> Litestar:
return Litestar(
route_handlers=self._get_route_handlers(),
debug=self._get_debug(),
lifespan=self._build_lifespan(),
openapi_config=self._build_openapi_config(),
plugins=self._build_plugins(),
state=self._build_initial_state(),
lifespan=self._build_lifespan(),
)
Loading

0 comments on commit 881cbd5

Please sign in to comment.