From 39b539a31c2a2fa101e773df40fca6b684934621 Mon Sep 17 00:00:00 2001 From: ZhymabekRoman Date: Sun, 15 Dec 2024 21:42:05 +0500 Subject: [PATCH] fix(new-freedium): bug fixes, settings restructure, minor UI fixes, overlay loader implement --- .../src/freedium_library/api/__init__.py | 8 + .../src/freedium_library/api/app.py | 16 +- .../src/freedium_library/api/config.py | 15 + .../src/freedium_library/api/container.py | 3 +- .../src/freedium_library/api/main.py | 49 +++- .../src/freedium_library/api/settings.py | 9 +- freedium-library/src/freedium_library/cli.py | 12 +- new-web/bun.lockb | Bin 127135 -> 127135 bytes new-web/src/app.css | 1 + .../ui/drawer/drawer-content.svelte | 12 +- .../ui/drawer/drawer-overlay.svelte | 10 +- new-web/src/lib/elements/ArticlePage.svelte | 265 +++++++++++------- .../src/lib/elements/ProgressOverlay.svelte | 24 ++ new-web/src/lib/elements/ReportProblem.svelte | 108 +++---- new-web/src/routes/+layout.svelte | 2 + new-web/src/routes/[slug]/+page.server.js | 62 +++- tests/smokie_tests.py | 2 +- 17 files changed, 392 insertions(+), 206 deletions(-) create mode 100644 new-web/src/lib/elements/ProgressOverlay.svelte diff --git a/freedium-library/src/freedium_library/api/__init__.py b/freedium-library/src/freedium_library/api/__init__.py index 812c6bc..fa6a43d 100644 --- a/freedium-library/src/freedium_library/api/__init__.py +++ b/freedium-library/src/freedium_library/api/__init__.py @@ -1,4 +1,12 @@ from freedium_library.__init__ import __VERSION__ +from freedium_library.api.container import APIContainer __NAME__ = "Freedium Library API" + +api_container = APIContainer() +api_container.wire( + modules=["freedium_library.api.settings", "freedium_library.api.main"] +) + + __all__ = ["__NAME__", "__VERSION__"] diff --git a/freedium-library/src/freedium_library/api/app.py b/freedium-library/src/freedium_library/api/app.py index 51bb133..965bd47 100644 --- a/freedium-library/src/freedium_library/api/app.py +++ b/freedium-library/src/freedium_library/api/app.py @@ -10,17 +10,23 @@ from freedium_library.api.settings import ApplicationSettings def create_application() -> FastAPI: - container = APIContainer() - container.wire(modules=["freedium_library.api.settings"]) + api_container = APIContainer() - settings = ApplicationSettings(container=container) - config = container.config() + settings = ApplicationSettings(container=api_container) + config = api_container.config() if config.DISABLED_DOCS: logger.warning(f"Documentation is disabled: {config.DISABLED_DOCS}") settings.disable_docs() - app = FastAPI(**settings.to_dict(), lifespan=lifespan) # type: ignore + app = FastAPI( + title=settings.title, + version=settings.version, + openapi_url=settings.openapi_url, + docs_url=settings.docs_url, + redoc_url=settings.redoc_url, + lifespan=lifespan, + ) register_router(app, settings.prefix_path) register_error_handler(app) diff --git a/freedium-library/src/freedium_library/api/config.py b/freedium-library/src/freedium_library/api/config.py index b1810d8..d2e3620 100644 --- a/freedium-library/src/freedium_library/api/config.py +++ b/freedium-library/src/freedium_library/api/config.py @@ -1,10 +1,25 @@ +# freedium-library/src/freedium_library/api/config.py +from typing import Optional + from pydantic import Field from freedium_library.utils.meta.pydantic import BaseConfig, BaseSettingsConfigDict +class ServerConfig(BaseConfig): + model_config = BaseSettingsConfigDict(env_prefix="SERVER_") + + host: str = Field(default="0.0.0.0") + port: int = Field(default=7080) + reload: bool = Field(default=False) + workers: Optional[int] = Field(default=None) + + class APIConfig(BaseConfig): model_config = BaseSettingsConfigDict(env_prefix="API_") DISABLED_DOCS: bool = Field(default=False) PREFIX_PATH: str = Field(default="/api") + HOST: str = Field(default="0.0.0.0") + PORT: int = Field(default=7080) + MAX_WORKERS: int = Field(default=10) diff --git a/freedium-library/src/freedium_library/api/container.py b/freedium-library/src/freedium_library/api/container.py index 7cb7c8f..692f0f8 100644 --- a/freedium-library/src/freedium_library/api/container.py +++ b/freedium-library/src/freedium_library/api/container.py @@ -1,7 +1,8 @@ from dependency_injector import containers, providers -from freedium_library.api.config import APIConfig +from freedium_library.api.config import APIConfig, ServerConfig class APIContainer(containers.DeclarativeContainer): config = providers.Singleton(APIConfig) + server_config = providers.Singleton(ServerConfig) diff --git a/freedium-library/src/freedium_library/api/main.py b/freedium-library/src/freedium_library/api/main.py index fee03b9..ccc3fef 100644 --- a/freedium-library/src/freedium_library/api/main.py +++ b/freedium-library/src/freedium_library/api/main.py @@ -2,23 +2,52 @@ import os from typing import Optional import uvicorn +from dependency_injector.wiring import Provide, inject from loguru import logger +from freedium_library.api.config import APIConfig, ServerConfig +from freedium_library.api.container import APIContainer + +def calculate_workers( + requested_workers: Optional[int] = None, max_workers: int = 10 +) -> int: + if requested_workers is not None: + return requested_workers + + cpu_count = os.cpu_count() or 1 + workers = min(cpu_count + 1, max_workers) + + if workers == 1: + logger.warning("Only one worker, this is not recommended for production.") + elif workers == max_workers: + logger.warning( + f"Using hardcoded maximum workers ({max_workers}), consider passing a lower number." + ) + else: + logger.info(f"Using {workers} workers based on CPU count.") + + return workers + + +@inject def start_server( - host: str = "0.0.0.0", - port: int = 7080, - reload: bool = False, - workers: Optional[int] = None, + server_config: Optional[ServerConfig] = Provide[APIContainer.server_config], + config: APIConfig = Provide[APIContainer.config], ) -> None: - if workers is None: - workers = (os.cpu_count() or 1) + 1 - logger.warning(f"No workers specified, using CPU count {workers}") + if server_config is None: + logger.warning("No server config provided, using defaults.") + server_config = ServerConfig( + host=config.HOST, + port=config.PORT, + ) + + workers = calculate_workers(server_config.workers, config.MAX_WORKERS) uvicorn.run( "freedium_library.api.app:app", - host=host, - port=port, - reload=reload, + host=server_config.host, + port=server_config.port, + reload=server_config.reload, workers=workers, ) diff --git a/freedium-library/src/freedium_library/api/settings.py b/freedium-library/src/freedium_library/api/settings.py index b1d20fe..8280ca4 100644 --- a/freedium-library/src/freedium_library/api/settings.py +++ b/freedium-library/src/freedium_library/api/settings.py @@ -9,15 +9,13 @@ from freedium_library.api.container import APIContainer class ApplicationSettings(BaseModel): - title: str = Field(default=f"{__NAME__} API Service") - version: str = Field(default=__VERSION__) + title: str = Field(default=f"{__NAME__} API Service", frozen=True) + version: str = Field(default=__VERSION__, frozen=True) prefix_path: str = Field(default="/api") openapi_url: Optional[str] = None docs_url: Optional[str] = None redoc_url: Optional[str] = None - model_config = {"arbitrary_types_allowed": True} - @inject def __init__( self, @@ -41,6 +39,3 @@ class ApplicationSettings(BaseModel): self.openapi_url = None self.docs_url = None self.redoc_url = None - - def to_dict(self) -> dict[str, str | None]: - return self.model_dump() diff --git a/freedium-library/src/freedium_library/cli.py b/freedium-library/src/freedium_library/cli.py index e1ccbfb..aa852c8 100644 --- a/freedium-library/src/freedium_library/cli.py +++ b/freedium-library/src/freedium_library/cli.py @@ -1,5 +1,8 @@ import click +from freedium_library.api.config import ServerConfig +from freedium_library.api.main import start_server + @click.command() @click.option("--host", default="0.0.0.0", help="Host address to bind to") @@ -11,6 +14,9 @@ import click default=False, ) def cli(host: str, port: int, hot_reload: bool): - from freedium_library.api.main import start_server - - start_server(host=host, port=port, reload=hot_reload) + server_config = ServerConfig( + host=host, + port=port, + reload=hot_reload, + ) + start_server(server_config=server_config) diff --git a/new-web/bun.lockb b/new-web/bun.lockb index ddd5f1e2e219c633048dc303f40c37b441f11b5d..ba3cab1b5e46cb7f5c2f113a262a68afb9970f69 100755 GIT binary patch delta 26 icmbRLkbV9`_J%EtvOye-afW(ECVEEORf8C-<^ceImI#Ib delta 26 dcmbRLkbV9`_J%EtvOye73=ptgHHfil9sqCx2Lu2B diff --git a/new-web/src/app.css b/new-web/src/app.css index 7561f58..05539f5 100644 --- a/new-web/src/app.css +++ b/new-web/src/app.css @@ -2,6 +2,7 @@ @tailwind components; @tailwind utilities; +body, html { scroll-behavior: smooth; } diff --git a/new-web/src/lib/components/ui/drawer/drawer-content.svelte b/new-web/src/lib/components/ui/drawer/drawer-content.svelte index 4f05317..96adb70 100644 --- a/new-web/src/lib/components/ui/drawer/drawer-content.svelte +++ b/new-web/src/lib/components/ui/drawer/drawer-content.svelte @@ -1,11 +1,11 @@ @@ -13,12 +13,12 @@ -
+
diff --git a/new-web/src/lib/components/ui/drawer/drawer-overlay.svelte b/new-web/src/lib/components/ui/drawer/drawer-overlay.svelte index ccc7322..c722109 100644 --- a/new-web/src/lib/components/ui/drawer/drawer-overlay.svelte +++ b/new-web/src/lib/components/ui/drawer/drawer-overlay.svelte @@ -1,17 +1,17 @@ diff --git a/new-web/src/lib/elements/ArticlePage.svelte b/new-web/src/lib/elements/ArticlePage.svelte index afe7a83..521b2ed 100644 --- a/new-web/src/lib/elements/ArticlePage.svelte +++ b/new-web/src/lib/elements/ArticlePage.svelte @@ -1,4 +1,5 @@ - {article.title} - Freedium + {error ? 'Freedium' : data?.article?.title || 'Freedium'} - Freedium
- -
- - -
-
- {#if !contentLoaded} - -
- - -
- -
- - -
-
-
-
-
- - - -
-
- {:else} - {#if article.postImage} - - {/if} -
-

{formatDate(article.date)}

-

{article.title}

-
- -
-

{article.author.name}

-

{article.author.role}

-
-
-
- -
-
- {#if content} - {@html content} - {:else} -

Error loading content

- {/if} -
-
+
+
+
+ - -
-
+ {error.status === 404 ? 'Article Not Found' : 'Error Loading Article'} + +

+ {getErrorMessage(error)} +

+ {#if error.details && process.env.NODE_ENV === 'development'} +
+					{error.details}
+				
+ {/if} +
+ + Return Home + + +
+ + {:else if showSkeleton} +
+
+ +
+ + +
+ +
+ + +
+
+
+
+
+ + + +
+
+
-
+ +
+ {:else} +
+
+ {#if article.postImage} + + {/if} +
+

{formatDate(article.date)}

+

{article.title}

+
+ +
+

{article.author.name}

+

{article.author.role}

+
+
+
+ +
+
+ {#if content} + {@html content} + {:else} +

Error loading content

+ {/if} +
+
+
+ + +
+ {/if} + + +