Skip to content

Commit

Permalink
feat(web-ui): add web-ui service
Browse files Browse the repository at this point in the history
  • Loading branch information
sassanh committed Oct 7, 2024
1 parent fdce923 commit b53b971
Show file tree
Hide file tree
Showing 14 changed files with 317 additions and 94 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- chore: use dynamic version field in `pyproject.toml` based on `hatch.build.hooks.vcs` and publish dev packages on pypi for all pushes to the main branch and all pull requests targeting the main branch
- chore: remove what has remained from poetry in the codebase
- refactor(core): avoid truncating or coloring logs in log files
- feat(web-ui): add web-ui service

## Version 1.0.0

Expand Down
12 changes: 9 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ dependencies = [
"pulsectl >=23.5.2",
"aiohttp >=3.9.1",
"semver >=3.0.2",
"docker>=7.1.0",
"python-dotenv >=1.0.1",
"sentry-sdk >=1.43.0",
"pvorca >=0.2.1",
"platformdirs >=4.2.0",
"dill >=0.3.8",
"simpleaudio >=1.0.4",
"python-redux >=0.16.1",
"python-redux >=0.17.1",
"python-debouncer >=0.1.5",
"python-strtobool >=1.0.0",
"python-fake >=0.1.3",
Expand All @@ -37,8 +38,8 @@ dependencies = [
"fasteners >=0.19",
# gRPC
"betterproto [compiler] >=2.0.0b7",
"docker >=7.1.0",
"gpiozero>=2.0.1 ; platform_machine != 'aarch64'",
"gpiozero >=2.0.1 ; platform_machine != 'aarch64'",
"quart >=0.19.6",
]

[build-system]
Expand Down Expand Up @@ -73,6 +74,7 @@ dev-dependencies = [
"grpcio-tools >=1.66.1",
]


[tool.uv.sources]
pyfakefs = { git = "https://github.com/pytest-dev/pyfakefs.git" }

Expand Down Expand Up @@ -253,6 +255,10 @@ extraPaths = ["."]
root = "ubo_app/services/080-docker"
extraPaths = ["."]

[[tool.pyright.executionEnvironments]]
root = "ubo_app/services/090-web-ui"
extraPaths = ["."]

[tool.pytest.ini_options]
asyncio_mode = "auto"
filterwarnings = [
Expand Down
9 changes: 4 additions & 5 deletions scripts/test_on_device.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ function run_on_pod() {
return 1
fi
if [ $# -eq 1 ]; then
ssh ubo-development-pod "sudo XDG_RUNTIME_DIR=/run/user/\$(id -u ubo) -u ubo bash -c 'cd; source \$HOME/.profile && source /etc/profile && ($1)'"
ssh ubo-development-pod "sudo XDG_RUNTIME_DIR=/run/user/\$(id -u ubo) -u ubo bash -c 'cd; source /etc/profile && source \$HOME/.profile && ($1)'"
return 0
fi
return 1
Expand All @@ -41,7 +41,6 @@ function run_on_pod_as_root() {
return 1
}


if [ "$copy" == "True" ]; then
# Since rsync is not called with -r, it treats ./scripts as an empty directory and its content are ignored, it could be any other random directory inside "./". It is needed solely to create the root directory with ubo:ubo ownership.
(echo './scripts'; git ls-files --others --exclude-standard --cached) | rsync --rsync-path="sudo rsync" --delete --info=progress2 -ae ssh --files-from=- --ignore-missing-args ./ ubo-development-pod:/home/ubo/test-runner/ --chown ubo:ubo
Expand All @@ -52,9 +51,9 @@ if [ "$run" == "True" ] || [ "$deps" == "True" ]; then
curl -LsSf https://astral.sh/uv/install.sh | sh) &&"; fi)
$(if [ "$run" == "True" ]; then echo "killall -9 pytest || true && systemctl --user stop ubo-app || true &&"; fi)
cd ~/test-runner &&
uv config virtualenvs.options.system-site-packages true --local &&
uv env use python3.11 &&
$(if [ "$deps" == "True" ]; then echo "uv install --no-interaction --extras=dev --with=dev &&"; fi)
uv venv --system-site-packages &&
uv python pin python3.11 &&
$(if [ "$deps" == "True" ]; then echo "SETUPTOOLS_SCM_PRETEND_VERSION=$(uvx hatch version) uv sync --frozen &&"; fi)
$(if [ "$run" == "True" ]; then echo "uv run poe test --verbosity=2 --capture=no --make-screenshots -n1 $* || true &&"; fi)
true"
fi
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"is_paused": false
},
"docker": {
"_id": "d3fbf47a7e5b1e7f9ca5499d004ae545",
"_id": "baf3897a3e70f16a55485822de1b372a",
"_type": "DockerState",
"home_assistant": {
"_type": "ImageState",
Expand Down Expand Up @@ -1106,6 +1106,7 @@
"is_pending": false,
"status": null
},
"web_ui": null,
"wifi": {
"_type": "WiFiState",
"connections": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"is_paused": false
},
"docker": {
"_id": "d3fbf47a7e5b1e7f9ca5499d004ae545",
"_id": "baf3897a3e70f16a55485822de1b372a",
"_type": "DockerState",
"home_assistant": {
"_type": "ImageState",
Expand Down Expand Up @@ -1176,6 +1176,7 @@
"is_pending": false,
"status": null
},
"web_ui": null,
"wifi": {
"_type": "WiFiState",
"connections": [],
Expand Down
1 change: 1 addition & 0 deletions tests/integration/test_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
'users',
'voice',
'vscode',
'web_ui',
'wifi',
]

Expand Down
4 changes: 4 additions & 0 deletions ubo_app/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
GRPC_LISTEN_HOST = os.environ.get('UBO_GRPC_LISTEN_HOST', '127.0.0.1')
GRPC_LISTEN_PORT = int(os.environ.get('UBO_GRPC_LISTEN_PORT', '50051'))

WEB_UI_LISTEN_HOST = os.environ.get('UBO_WEB_UI_LISTEN_HOST', '127.0.0.1')
WEB_UI_LISTEN_PORT = int(os.environ.get('UBO_WEB_UI_LISTEN_PORT', '21215'))
WEB_UI_DEBUG_MODE = str_to_bool(os.environ.get('UBO_WEB_UI_DEBUG_MODE', 'False')) == 1

UPDATE_ASSETS_PATH = Path(f'{INSTALLATION_PATH}/_update/')
UPDATE_LOCK_PATH = UPDATE_ASSETS_PATH / 'update_is_ready.lock'

Expand Down
4 changes: 2 additions & 2 deletions ubo_app/load_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def find_spec(
(
registered_path
for frame in stack[-2::-1]
for registered_path in REGISTERED_PATHS
for registered_path in REGISTERED_PATHS.copy()
if frame.filename.startswith(registered_path.as_posix())
),
None,
Expand Down Expand Up @@ -386,7 +386,7 @@ def load_services(service_ids: Sequence[str] | None = None, delay: float = 0) ->
directory_path = Path(services_directory_path).absolute()
if directory_path.is_dir():
for service_path in sorted(directory_path.iterdir()):
if not service_path.is_dir() or service_path in REGISTERED_PATHS:
if not service_path.is_dir() or service_path in REGISTERED_PATHS.copy():
continue
current_path = Path().absolute()
os.chdir(service_path.as_posix())
Expand Down
15 changes: 15 additions & 0 deletions ubo_app/services/090-web-ui/reducer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# ruff: noqa: D100, D101, D102, D103, D104, D107
from __future__ import annotations

from typing import TYPE_CHECKING

if TYPE_CHECKING:
from redux import BaseAction, ReducerResult


def reducer(
state: None,
action: BaseAction,
) -> ReducerResult[None, None, None]:
_ = action
return state
33 changes: 33 additions & 0 deletions ubo_app/services/090-web-ui/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""Implementation of the web-ui service."""

import asyncio
from pathlib import Path

from quart import Quart
from redux import FinishEvent

from ubo_app.constants import WEB_UI_DEBUG_MODE, WEB_UI_LISTEN_HOST, WEB_UI_LISTEN_PORT
from ubo_app.store.main import store


async def init_service() -> None:
"""Initialize the web-ui service."""
app = Quart('ubo-app')
app.debug = False
shutdown_event: asyncio.Event = asyncio.Event()

@app.get('/')
async def hello_world() -> str:
return (Path(__file__).parent / 'static' / 'index.html').read_text()

store.subscribe_event(FinishEvent, shutdown_event.set)

async def wait_for_shutdown() -> None:
await shutdown_event.wait()

await app.run_task(
host=WEB_UI_LISTEN_HOST,
port=WEB_UI_LISTEN_PORT,
debug=WEB_UI_DEBUG_MODE,
shutdown_trigger=wait_for_shutdown,
)
8 changes: 8 additions & 0 deletions ubo_app/services/090-web-ui/static/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<html>
<title>ubo - web-ui</title>

<body>
<p>Hello World!</p>
</body>

</html>
22 changes: 22 additions & 0 deletions ubo_app/services/090-web-ui/ubo_handle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# ruff: noqa: D100, D101, D102, D103, D104, D107, N999
from __future__ import annotations

from typing import TYPE_CHECKING

if TYPE_CHECKING:
from ubo_handle import Service, register


async def setup(service: Service) -> None:
from reducer import reducer
from setup import init_service

service.register_reducer(reducer)
await init_service()


register(
service_id='web_ui',
label='Web UI',
setup=setup,
)
7 changes: 7 additions & 0 deletions ubo_app/store/services/web-ui.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# ruff: noqa: D100, D101, D102, D103, D104, D107, N999
from __future__ import annotations

from immutable import Immutable


class WebUIState(Immutable): ...
Loading

0 comments on commit b53b971

Please sign in to comment.