diff --git a/flake.lock b/flake.lock index add9b0c..5234a63 100644 --- a/flake.lock +++ b/flake.lock @@ -7,11 +7,11 @@ ] }, "locked": { - "lastModified": 1696343447, - "narHash": "sha256-B2xAZKLkkeRFG5XcHHSXXcP7To9Xzr59KXeZiRf4vdQ=", + "lastModified": 1698882062, + "narHash": "sha256-HkhafUayIqxXyHH1X8d9RDl1M2CkFgZLjKD3MzabiEo=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "c9afaba3dfa4085dbd2ccb38dfade5141e33d9d4", + "rev": "8c9fa2545007b49a5db5f650ae91f227672c3877", "type": "github" }, "original": { @@ -42,11 +42,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1697059129, - "narHash": "sha256-9NJcFF9CEYPvHJ5ckE8kvINvI84SZZ87PvqMbH6pro0=", + "lastModified": 1700390070, + "narHash": "sha256-de9KYi8rSJpqvBfNwscWdalIJXPo8NjdIZcEJum1mH0=", "owner": "nixos", "repo": "nixpkgs", - "rev": "5e4c2ada4fcd54b99d56d7bd62f384511a7e2593", + "rev": "e4ad989506ec7d71f7302cc3067abd82730a4beb", "type": "github" }, "original": { @@ -56,11 +56,28 @@ "type": "github" } }, + "nixpkgs-for-iosl": { + "locked": { + "lastModified": 1700515317, + "narHash": "sha256-DSnKT3glZCKE0/Rc6ainSJUbUGC248HNKVRSbo9kxkM=", + "owner": "Luis-Hebendanz", + "repo": "nixpkgs", + "rev": "bcd6be7a5ab22c94c775945fb16a61b5867f15d2", + "type": "github" + }, + "original": { + "owner": "Luis-Hebendanz", + "ref": "iosl", + "repo": "nixpkgs", + "type": "github" + } + }, "root": { "inputs": { "flake-parts": "flake-parts", "floco": "floco", "nixpkgs": "nixpkgs", + "nixpkgs-for-iosl": "nixpkgs-for-iosl", "treefmt-nix": "treefmt-nix" } }, @@ -71,11 +88,11 @@ ] }, "locked": { - "lastModified": 1695822946, - "narHash": "sha256-IQU3fYo0H+oGlqX5YrgZU3VRhbt2Oqe6KmslQKUO4II=", + "lastModified": 1699786194, + "narHash": "sha256-3h3EH1FXQkIeAuzaWB+nK0XK54uSD46pp+dMD3gAcB4=", "owner": "numtide", "repo": "treefmt-nix", - "rev": "720bd006d855b08e60664e4683ccddb7a9ff614a", + "rev": "e82f32aa7f06bbbd56d7b12186d555223dc399d1", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 9e1a4e3..6c73ad1 100644 --- a/flake.nix +++ b/flake.nix @@ -7,6 +7,7 @@ nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; floco.url = "github:aakropotkin/floco"; floco.inputs.nixpkgs.follows = "nixpkgs"; + nixpkgs-for-iosl.url = "github:Luis-Hebendanz/nixpkgs/iosl"; flake-parts.url = "github:hercules-ci/flake-parts"; flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs"; treefmt-nix.url = "github:numtide/treefmt-nix"; diff --git a/pkgs/clan-cli/.vscode/settings.json b/pkgs/clan-cli/.vscode/settings.json index e5c2632..0c7964c 100644 --- a/pkgs/clan-cli/.vscode/settings.json +++ b/pkgs/clan-cli/.vscode/settings.json @@ -18,5 +18,5 @@ "python.linting.mypyPath": "mypy", "python.linting.mypyEnabled": true, "python.linting.enabled": true, - "python.defaultInterpreterPath": "python" + "python.defaultInterpreterPath": "/nix/store/k34qdl5397mwg3k00jsl3xcynij7n0z9-python3-3.11.6-env/bin/python" } \ No newline at end of file diff --git a/pkgs/clan-cli/clan_cli/types.py b/pkgs/clan-cli/clan_cli/clan_types.py similarity index 100% rename from pkgs/clan-cli/clan_cli/types.py rename to pkgs/clan-cli/clan_cli/clan_types.py diff --git a/pkgs/clan-cli/clan_cli/dirs.py b/pkgs/clan-cli/clan_cli/dirs.py index 5f11577..ce5ff14 100644 --- a/pkgs/clan-cli/clan_cli/dirs.py +++ b/pkgs/clan-cli/clan_cli/dirs.py @@ -4,8 +4,8 @@ import sys from pathlib import Path from typing import Optional +from .clan_types import FlakeName from .errors import ClanError -from .types import FlakeName log = logging.getLogger(__name__) diff --git a/pkgs/clan-cli/clan_cli/webui/api_inputs.py b/pkgs/clan-cli/clan_cli/webui/api_inputs.py index 70539e7..1148c7b 100644 --- a/pkgs/clan-cli/clan_cli/webui/api_inputs.py +++ b/pkgs/clan-cli/clan_cli/webui/api_inputs.py @@ -5,8 +5,8 @@ from typing import Any from pydantic import AnyUrl, BaseModel, validator from pydantic.tools import parse_obj_as +from ..clan_types import validate_path from ..dirs import clan_data_dir, clan_flakes_dir -from ..types import validate_path DEFAULT_URL = parse_obj_as(AnyUrl, "http://localhost:8000") diff --git a/pkgs/clan-cli/clan_cli/webui/app.py b/pkgs/clan-cli/clan_cli/webui/app.py index 88ff380..f33bbf1 100644 --- a/pkgs/clan-cli/clan_cli/webui/app.py +++ b/pkgs/clan-cli/clan_cli/webui/app.py @@ -1,4 +1,6 @@ import logging +from contextlib import asynccontextmanager +from typing import Any from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware @@ -8,7 +10,7 @@ from fastapi.staticfiles import StaticFiles from ..errors import ClanError from .assets import asset_path from .error_handlers import clan_error_handler -from .routers import health, root +from .routers import health, root, socket_manager2 origins = [ "http://localhost:3000", @@ -17,8 +19,15 @@ origins = [ log = logging.getLogger(__name__) +@asynccontextmanager +async def lifespan(app: FastAPI) -> Any: + await socket_manager2.brd.connect() + yield + await socket_manager2.brd.disconnect() + + def setup_app() -> FastAPI: - app = FastAPI() + app = FastAPI(lifespan=lifespan) app.add_middleware( CORSMiddleware, allow_origins=origins, @@ -29,9 +38,11 @@ def setup_app() -> FastAPI: app.include_router(health.router) + app.include_router(socket_manager2.router) + # Needs to be last in register. Because of wildcard route app.include_router(root.router) - app.add_exception_handler(ClanError, clan_error_handler) + app.add_exception_handler(ClanError, clan_error_handler) # type: ignore app.mount("/static", StaticFiles(directory=asset_path()), name="static") diff --git a/pkgs/clan-cli/clan_cli/webui/routers/messenger.html b/pkgs/clan-cli/clan_cli/webui/routers/messenger.html new file mode 100644 index 0000000..cdc6618 --- /dev/null +++ b/pkgs/clan-cli/clan_cli/webui/routers/messenger.html @@ -0,0 +1,205 @@ + + +
+ + + + + + + + + + diff --git a/pkgs/clan-cli/clan_cli/webui/routers/socket_manager2.py b/pkgs/clan-cli/clan_cli/webui/routers/socket_manager2.py new file mode 100644 index 0000000..66391f6 --- /dev/null +++ b/pkgs/clan-cli/clan_cli/webui/routers/socket_manager2.py @@ -0,0 +1,52 @@ +# Requires: `starlette`, `uvicorn`, `jinja2` +# Run with `uvicorn example:app` +import logging +import os + +import anyio +from broadcaster import Broadcast +from fastapi import APIRouter, WebSocket +from fastapi.responses import HTMLResponse + +log = logging.getLogger(__name__) +router = APIRouter() + + +brd = Broadcast("memory://") + + +@router.get("/ws2_example") +async def get() -> HTMLResponse: + html = open(f"{os.getcwd()}/webui/routers/messenger.html").read() + return HTMLResponse(html) + + +@router.websocket("/ws2") +async def chatroom_ws(websocket: WebSocket) -> None: + await websocket.accept() + + async with anyio.create_task_group() as task_group: + # run until first is complete + async def run_chatroom_ws_receiver() -> None: + await chatroom_ws_receiver(websocket=websocket) + task_group.cancel_scope.cancel() + + task_group.start_soon(run_chatroom_ws_receiver) + log.warning("Started chatroom_ws_sender") + + await chatroom_ws_sender(websocket) + + +async def chatroom_ws_receiver(websocket: WebSocket) -> None: + async for message in websocket.iter_text(): + log.warning(f"Received message: {message}") + await brd.publish(channel="chatroom", message=message) + + +async def chatroom_ws_sender(websocket: WebSocket) -> None: + async with brd.subscribe(channel="chatroom") as subscriber: + if subscriber is None: + log.error("Subscriber is None") + return + async for event in subscriber: # type: ignore + await websocket.send_text(event.message) diff --git a/pkgs/clan-cli/default.nix b/pkgs/clan-cli/default.nix index a9f4b66..42347b6 100644 --- a/pkgs/clan-cli/default.nix +++ b/pkgs/clan-cli/default.nix @@ -36,6 +36,8 @@ , mypy , sqlalchemy , websockets +, deal +, broadcaster }: let @@ -45,6 +47,8 @@ let uvicorn # optional dependencies: if not enabled, webui subcommand will not work sqlalchemy websockets + broadcaster + deal ]; pytestDependencies = runtimeDependencies ++ dependencies ++ [ diff --git a/pkgs/clan-cli/flake-module.nix b/pkgs/clan-cli/flake-module.nix index 2f912d0..5e3719c 100644 --- a/pkgs/clan-cli/flake-module.nix +++ b/pkgs/clan-cli/flake-module.nix @@ -1,6 +1,6 @@ { inputs, ... }: { - perSystem = { self', pkgs, ... }: { + perSystem = { self', pkgs, system, ... }: { devShells.clan-cli = pkgs.callPackage ./shell.nix { inherit (self'.packages) clan-cli ui-assets nix-unit; }; @@ -8,6 +8,8 @@ clan-cli = pkgs.python3.pkgs.callPackage ./default.nix { inherit (self'.packages) ui-assets; inherit (inputs) nixpkgs; + inherit (inputs.nixpkgs-for-iosl.legacyPackages.${system}.python3Packages) deal; + inherit (inputs.nixpkgs-for-iosl.legacyPackages.${system}.python3Packages) broadcaster; }; inherit (self'.packages.clan-cli) clan-openapi; default = self'.packages.clan-cli; diff --git a/pkgs/clan-cli/pyproject.toml b/pkgs/clan-cli/pyproject.toml index ab64f5d..3f48ba3 100644 --- a/pkgs/clan-cli/pyproject.toml +++ b/pkgs/clan-cli/pyproject.toml @@ -49,6 +49,11 @@ ignore_missing_imports = true module = "pytest.*" ignore_missing_imports = true +[[tool.mypy.overrides]] +module = "anyio.*" +ignore_missing_imports = true + + [[tool.mypy.overrides]] module = "setuptools.*" ignore_missing_imports = true diff --git a/pkgs/nix-unit/default.nix b/pkgs/nix-unit/default.nix index 507ed57..fe917f0 100644 --- a/pkgs/nix-unit/default.nix +++ b/pkgs/nix-unit/default.nix @@ -1,43 +1,9 @@ -{ stdenv -, lib -, nixVersions -, fetchFromGitHub -, nlohmann_json -, boost -, meson -, pkg-config -, ninja -, cmake -, clang-tools -}: - -stdenv.mkDerivation { - pname = "nix-unit"; - version = "0.1"; - src = fetchFromGitHub { - owner = "adisbladis"; - repo = "nix-unit"; - rev = "3ed2378bddad85257fc508a291408f9ed9673d01"; - sha256 = "sha256-HvMq0TJGYSx37zHm4j2d+JUZx4/6X7xKEt/0DeCiwjQ="; +{ callPackage }: +let + nix-unit-src = builtins.fetchGit { + url = "https://github.com/adisbladis/nix-unit"; + rev = "7e2ee1c70f930b9b65b9fc33c3f3eca0dfae00d1"; }; - buildInputs = [ - nlohmann_json - nixVersions.stable - boost - ]; - nativeBuildInputs = [ - meson - pkg-config - ninja - # nlohmann_json can be only discovered via cmake files - cmake - ] ++ (lib.optional stdenv.cc.isClang [ clang-tools ]); +in +callPackage nix-unit-src { } - meta = { - description = "Nix unit test runner"; - homepage = "https://github.com/adisbladis/nix-unit"; - license = lib.licenses.gpl3; - maintainers = with lib.maintainers; [ adisbladis ]; - platforms = lib.platforms.unix; - }; -}