Compare commits
1 Commits
0.2.0
...
b4e6cecdfe
Author | SHA1 | Date | |
---|---|---|---|
b4e6cecdfe
|
@@ -9,7 +9,7 @@ RUN adduser -D luser
|
|||||||
USER luser
|
USER luser
|
||||||
WORKDIR /home/luser
|
WORKDIR /home/luser
|
||||||
COPY --chown=luser:users ./requirements-dev.txt ./requirements-dev.txt
|
COPY --chown=luser:users ./requirements-dev.txt ./requirements-dev.txt
|
||||||
COPY --chown=luser:users ./requirements-run.txt ./requirements-run.txt
|
COPY --chown=luser:users ./requirements-dev.txt ./requirements-run.txt
|
||||||
WORKDIR /home/luser/
|
WORKDIR /home/luser/
|
||||||
RUN python -m venv .venv
|
RUN python -m venv .venv
|
||||||
RUN --mount=type=cache,target=/home/luser/.cache/pip,uid=1000,gid=1000 .venv/bin/pip wheel -w /home/luser/wheel -r requirements-dev.txt pygraphviz
|
RUN --mount=type=cache,target=/home/luser/.cache/pip,uid=1000,gid=1000 .venv/bin/pip wheel -w /home/luser/wheel -r requirements-dev.txt pygraphviz
|
||||||
|
@@ -1,14 +0,0 @@
|
|||||||
server {
|
|
||||||
listen 8080;
|
|
||||||
http2 on;
|
|
||||||
|
|
||||||
server_name localhost;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
proxy_pass http://granian:8000;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_read_timeout 60s;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -29,7 +29,7 @@ dependencies = [
|
|||||||
"PyYAML",
|
"PyYAML",
|
||||||
"pygraphviz",
|
"pygraphviz",
|
||||||
"aiofiles",
|
"aiofiles",
|
||||||
"httpx[http2]"
|
"aiohttp[speedups]",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
|
@@ -7,21 +7,30 @@
|
|||||||
--index-url https://gitea.woggioni.net/api/packages/woggioni/pypi/simple
|
--index-url https://gitea.woggioni.net/api/packages/woggioni/pypi/simple
|
||||||
--extra-index-url https://pypi.org/simple
|
--extra-index-url https://pypi.org/simple
|
||||||
|
|
||||||
|
aiodns==3.2.0
|
||||||
|
# via aiohttp
|
||||||
aiofiles==24.1.0
|
aiofiles==24.1.0
|
||||||
# via bugis (pyproject.toml)
|
# via bugis (pyproject.toml)
|
||||||
anyio==4.6.2.post1
|
aiohappyeyeballs==2.4.3
|
||||||
# via httpx
|
# via aiohttp
|
||||||
|
aiohttp[speedups]==3.10.10
|
||||||
|
# via bugis (pyproject.toml)
|
||||||
|
aiosignal==1.3.1
|
||||||
|
# via aiohttp
|
||||||
asttokens==2.4.1
|
asttokens==2.4.1
|
||||||
# via stack-data
|
# via stack-data
|
||||||
|
attrs==24.2.0
|
||||||
|
# via aiohttp
|
||||||
|
brotli==1.1.0
|
||||||
|
# via aiohttp
|
||||||
build==1.2.2.post1
|
build==1.2.2.post1
|
||||||
# via bugis (pyproject.toml)
|
# via bugis (pyproject.toml)
|
||||||
certifi==2024.8.30
|
certifi==2024.8.30
|
||||||
# via
|
# via requests
|
||||||
# httpcore
|
|
||||||
# httpx
|
|
||||||
# requests
|
|
||||||
cffi==1.17.1
|
cffi==1.17.1
|
||||||
# via cryptography
|
# via
|
||||||
|
# cryptography
|
||||||
|
# pycares
|
||||||
charset-normalizer==3.4.0
|
charset-normalizer==3.4.0
|
||||||
# via requests
|
# via requests
|
||||||
click==8.1.7
|
click==8.1.7
|
||||||
@@ -36,25 +45,16 @@ docutils==0.21.2
|
|||||||
# via readme-renderer
|
# via readme-renderer
|
||||||
executing==2.1.0
|
executing==2.1.0
|
||||||
# via stack-data
|
# via stack-data
|
||||||
|
frozenlist==1.5.0
|
||||||
|
# via
|
||||||
|
# aiohttp
|
||||||
|
# aiosignal
|
||||||
granian==1.6.1
|
granian==1.6.1
|
||||||
# via bugis (pyproject.toml)
|
# via bugis (pyproject.toml)
|
||||||
h11==0.14.0
|
|
||||||
# via httpcore
|
|
||||||
h2==4.1.0
|
|
||||||
# via httpx
|
|
||||||
hpack==4.0.0
|
|
||||||
# via h2
|
|
||||||
httpcore==1.0.6
|
|
||||||
# via httpx
|
|
||||||
httpx[http2]==0.27.2
|
|
||||||
# via bugis (pyproject.toml)
|
|
||||||
hyperframe==6.0.1
|
|
||||||
# via h2
|
|
||||||
idna==3.10
|
idna==3.10
|
||||||
# via
|
# via
|
||||||
# anyio
|
|
||||||
# httpx
|
|
||||||
# requests
|
# requests
|
||||||
|
# yarl
|
||||||
importlib-metadata==8.5.0
|
importlib-metadata==8.5.0
|
||||||
# via twine
|
# via twine
|
||||||
ipdb==0.13.13
|
ipdb==0.13.13
|
||||||
@@ -87,6 +87,10 @@ more-itertools==10.5.0
|
|||||||
# via
|
# via
|
||||||
# jaraco-classes
|
# jaraco-classes
|
||||||
# jaraco-functools
|
# jaraco-functools
|
||||||
|
multidict==6.1.0
|
||||||
|
# via
|
||||||
|
# aiohttp
|
||||||
|
# yarl
|
||||||
mypy==1.13.0
|
mypy==1.13.0
|
||||||
# via bugis (pyproject.toml)
|
# via bugis (pyproject.toml)
|
||||||
mypy-extensions==1.0.0
|
mypy-extensions==1.0.0
|
||||||
@@ -103,12 +107,16 @@ pkginfo==1.10.0
|
|||||||
# via twine
|
# via twine
|
||||||
prompt-toolkit==3.0.48
|
prompt-toolkit==3.0.48
|
||||||
# via ipython
|
# via ipython
|
||||||
|
propcache==0.2.0
|
||||||
|
# via yarl
|
||||||
ptyprocess==0.7.0
|
ptyprocess==0.7.0
|
||||||
# via pexpect
|
# via pexpect
|
||||||
pure-eval==0.2.3
|
pure-eval==0.2.3
|
||||||
# via stack-data
|
# via stack-data
|
||||||
pwo==0.0.4
|
pwo==0.0.4
|
||||||
# via bugis (pyproject.toml)
|
# via bugis (pyproject.toml)
|
||||||
|
pycares==4.4.0
|
||||||
|
# via aiodns
|
||||||
pycparser==2.22
|
pycparser==2.22
|
||||||
# via cffi
|
# via cffi
|
||||||
pygments==2.18.0
|
pygments==2.18.0
|
||||||
@@ -139,10 +147,6 @@ secretstorage==3.3.3
|
|||||||
# via keyring
|
# via keyring
|
||||||
six==1.16.0
|
six==1.16.0
|
||||||
# via asttokens
|
# via asttokens
|
||||||
sniffio==1.3.1
|
|
||||||
# via
|
|
||||||
# anyio
|
|
||||||
# httpx
|
|
||||||
stack-data==0.6.3
|
stack-data==0.6.3
|
||||||
# via ipython
|
# via ipython
|
||||||
traitlets==5.14.3
|
traitlets==5.14.3
|
||||||
@@ -165,5 +169,7 @@ watchdog==5.0.3
|
|||||||
# via bugis (pyproject.toml)
|
# via bugis (pyproject.toml)
|
||||||
wcwidth==0.2.13
|
wcwidth==0.2.13
|
||||||
# via prompt-toolkit
|
# via prompt-toolkit
|
||||||
|
yarl==1.16.0
|
||||||
|
# via aiohttp
|
||||||
zipp==3.20.2
|
zipp==3.20.2
|
||||||
# via importlib-metadata
|
# via importlib-metadata
|
||||||
|
@@ -7,51 +7,57 @@
|
|||||||
--index-url https://gitea.woggioni.net/api/packages/woggioni/pypi/simple
|
--index-url https://gitea.woggioni.net/api/packages/woggioni/pypi/simple
|
||||||
--extra-index-url https://pypi.org/simple
|
--extra-index-url https://pypi.org/simple
|
||||||
|
|
||||||
|
aiodns==3.2.0
|
||||||
|
# via aiohttp
|
||||||
aiofiles==24.1.0
|
aiofiles==24.1.0
|
||||||
# via bugis (pyproject.toml)
|
# via bugis (pyproject.toml)
|
||||||
anyio==4.6.2.post1
|
aiohappyeyeballs==2.4.3
|
||||||
# via httpx
|
# via aiohttp
|
||||||
certifi==2024.8.30
|
aiohttp[speedups]==3.10.10
|
||||||
# via
|
# via bugis (pyproject.toml)
|
||||||
# httpcore
|
aiosignal==1.3.1
|
||||||
# httpx
|
# via aiohttp
|
||||||
|
attrs==24.2.0
|
||||||
|
# via aiohttp
|
||||||
|
brotli==1.1.0
|
||||||
|
# via aiohttp
|
||||||
|
cffi==1.17.1
|
||||||
|
# via pycares
|
||||||
click==8.1.7
|
click==8.1.7
|
||||||
# via granian
|
# via granian
|
||||||
|
frozenlist==1.5.0
|
||||||
|
# via
|
||||||
|
# aiohttp
|
||||||
|
# aiosignal
|
||||||
granian==1.6.1
|
granian==1.6.1
|
||||||
# via bugis (pyproject.toml)
|
# via bugis (pyproject.toml)
|
||||||
h11==0.14.0
|
|
||||||
# via httpcore
|
|
||||||
h2==4.1.0
|
|
||||||
# via httpx
|
|
||||||
hpack==4.0.0
|
|
||||||
# via h2
|
|
||||||
httpcore==1.0.6
|
|
||||||
# via httpx
|
|
||||||
httpx[http2]==0.27.2
|
|
||||||
# via bugis (pyproject.toml)
|
|
||||||
hyperframe==6.0.1
|
|
||||||
# via h2
|
|
||||||
idna==3.10
|
idna==3.10
|
||||||
# via
|
# via yarl
|
||||||
# anyio
|
|
||||||
# httpx
|
|
||||||
markdown==3.7
|
markdown==3.7
|
||||||
# via bugis (pyproject.toml)
|
# via bugis (pyproject.toml)
|
||||||
|
multidict==6.1.0
|
||||||
|
# via
|
||||||
|
# aiohttp
|
||||||
|
# yarl
|
||||||
|
propcache==0.2.0
|
||||||
|
# via yarl
|
||||||
pwo==0.0.4
|
pwo==0.0.4
|
||||||
# via bugis (pyproject.toml)
|
# via bugis (pyproject.toml)
|
||||||
|
pycares==4.4.0
|
||||||
|
# via aiodns
|
||||||
|
pycparser==2.22
|
||||||
|
# via cffi
|
||||||
pygments==2.18.0
|
pygments==2.18.0
|
||||||
# via bugis (pyproject.toml)
|
# via bugis (pyproject.toml)
|
||||||
pygraphviz==1.14
|
pygraphviz==1.14
|
||||||
# via bugis (pyproject.toml)
|
# via bugis (pyproject.toml)
|
||||||
pyyaml==6.0.2
|
pyyaml==6.0.2
|
||||||
# via bugis (pyproject.toml)
|
# via bugis (pyproject.toml)
|
||||||
sniffio==1.3.1
|
|
||||||
# via
|
|
||||||
# anyio
|
|
||||||
# httpx
|
|
||||||
typing-extensions==4.12.2
|
typing-extensions==4.12.2
|
||||||
# via pwo
|
# via pwo
|
||||||
uvloop==0.21.0
|
uvloop==0.21.0
|
||||||
# via granian
|
# via granian
|
||||||
watchdog==5.0.3
|
watchdog==5.0.3
|
||||||
# via bugis (pyproject.toml)
|
# via bugis (pyproject.toml)
|
||||||
|
yarl==1.16.0
|
||||||
|
# via aiohttp
|
||||||
|
@@ -2,50 +2,56 @@
|
|||||||
# This file is autogenerated by pip-compile with Python 3.12
|
# This file is autogenerated by pip-compile with Python 3.12
|
||||||
# by the following command:
|
# by the following command:
|
||||||
#
|
#
|
||||||
# pip-compile --output-file=requirements.txt pyproject.toml
|
# pip-compile pyproject.toml
|
||||||
#
|
#
|
||||||
--index-url https://gitea.woggioni.net/api/packages/woggioni/pypi/simple
|
--index-url https://gitea.woggioni.net/api/packages/woggioni/pypi/simple
|
||||||
--extra-index-url https://pypi.org/simple
|
--extra-index-url https://pypi.org/simple
|
||||||
|
|
||||||
|
aiodns==3.2.0
|
||||||
|
# via aiohttp
|
||||||
aiofiles==24.1.0
|
aiofiles==24.1.0
|
||||||
# via bugis (pyproject.toml)
|
# via bugis (pyproject.toml)
|
||||||
anyio==4.6.2.post1
|
aiohappyeyeballs==2.4.3
|
||||||
# via httpx
|
# via aiohttp
|
||||||
certifi==2024.8.30
|
aiohttp[speedups]==3.10.10
|
||||||
# via
|
|
||||||
# httpcore
|
|
||||||
# httpx
|
|
||||||
h11==0.14.0
|
|
||||||
# via httpcore
|
|
||||||
h2==4.1.0
|
|
||||||
# via httpx
|
|
||||||
hpack==4.0.0
|
|
||||||
# via h2
|
|
||||||
httpcore==1.0.6
|
|
||||||
# via httpx
|
|
||||||
httpx[http2]==0.27.2
|
|
||||||
# via bugis (pyproject.toml)
|
# via bugis (pyproject.toml)
|
||||||
hyperframe==6.0.1
|
aiosignal==1.3.1
|
||||||
# via h2
|
# via aiohttp
|
||||||
idna==3.10
|
attrs==24.2.0
|
||||||
|
# via aiohttp
|
||||||
|
brotli==1.1.0
|
||||||
|
# via aiohttp
|
||||||
|
cffi==1.17.1
|
||||||
|
# via pycares
|
||||||
|
frozenlist==1.5.0
|
||||||
# via
|
# via
|
||||||
# anyio
|
# aiohttp
|
||||||
# httpx
|
# aiosignal
|
||||||
|
idna==3.10
|
||||||
|
# via yarl
|
||||||
markdown==3.7
|
markdown==3.7
|
||||||
# via bugis (pyproject.toml)
|
# via bugis (pyproject.toml)
|
||||||
|
multidict==6.1.0
|
||||||
|
# via
|
||||||
|
# aiohttp
|
||||||
|
# yarl
|
||||||
|
propcache==0.2.0
|
||||||
|
# via yarl
|
||||||
pwo==0.0.4
|
pwo==0.0.4
|
||||||
# via bugis (pyproject.toml)
|
# via bugis (pyproject.toml)
|
||||||
|
pycares==4.4.0
|
||||||
|
# via aiodns
|
||||||
|
pycparser==2.22
|
||||||
|
# via cffi
|
||||||
pygments==2.18.0
|
pygments==2.18.0
|
||||||
# via bugis (pyproject.toml)
|
# via bugis (pyproject.toml)
|
||||||
pygraphviz==1.14
|
pygraphviz==1.14
|
||||||
# via bugis (pyproject.toml)
|
# via bugis (pyproject.toml)
|
||||||
pyyaml==6.0.2
|
pyyaml==6.0.2
|
||||||
# via bugis (pyproject.toml)
|
# via bugis (pyproject.toml)
|
||||||
sniffio==1.3.1
|
|
||||||
# via
|
|
||||||
# anyio
|
|
||||||
# httpx
|
|
||||||
typing-extensions==4.12.2
|
typing-extensions==4.12.2
|
||||||
# via pwo
|
# via pwo
|
||||||
watchdog==5.0.3
|
watchdog==5.0.3
|
||||||
# via bugis (pyproject.toml)
|
# via bugis (pyproject.toml)
|
||||||
|
yarl==1.16.0
|
||||||
|
# via aiohttp
|
||||||
|
@@ -14,14 +14,14 @@ from pwo import Maybe
|
|||||||
from .server import Server
|
from .server import Server
|
||||||
from asyncio import get_running_loop
|
from asyncio import get_running_loop
|
||||||
from .asgi_utils import decode_headers
|
from .asgi_utils import decode_headers
|
||||||
from typing import Optional, Awaitable, Callable, Any, Mapping
|
from typing import Optional
|
||||||
|
|
||||||
log = logging.getLogger('access')
|
log = logging.getLogger('access')
|
||||||
log.propagate = False
|
log.propagate = False
|
||||||
|
|
||||||
_server: Optional[Server] = None
|
_server: Optional[Server] = None
|
||||||
|
|
||||||
async def application(scope, receive, send : Callable[[Mapping[str, Any]], Awaitable[None]]):
|
async def application(scope, receive, send):
|
||||||
global _server
|
global _server
|
||||||
if scope['type'] == 'lifespan':
|
if scope['type'] == 'lifespan':
|
||||||
while True:
|
while True:
|
||||||
|
@@ -1,19 +1,17 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from aiofiles import open as async_open
|
from aiofiles import open as async_open
|
||||||
|
from aiohttp import ClientSession
|
||||||
from .configuration import Configuration
|
from .configuration import Configuration
|
||||||
|
from yarl import URL
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from _typeshed import StrOrBytesPath
|
from _typeshed import StrOrBytesPath
|
||||||
from httpx import AsyncClient, URL
|
|
||||||
from typing import Callable, Awaitable
|
|
||||||
from urllib.parse import urljoin
|
|
||||||
|
|
||||||
chunk_size = 0x10000
|
async def render_plant_uml(path: 'StrOrBytesPath') -> bytes:
|
||||||
async def render_plant_uml(client: AsyncClient, path: 'StrOrBytesPath', send : Callable[[bytes], Awaitable[None]]):
|
async with ClientSession() as session:
|
||||||
url = URL(urljoin(Configuration.instance.plant_uml_server_address, 'svg'))
|
url = URL(Configuration.instance.plant_uml_server_address) / 'svg'
|
||||||
async with async_open(path, 'rb') as file:
|
async with async_open(path, 'rb') as file:
|
||||||
source = await file.read()
|
source = await file.read()
|
||||||
response = await client.post(url, content=source)
|
async with session.post(url, data=source) as response:
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
async for chunk in response.aiter_bytes(chunk_size=chunk_size):
|
return await response.read()
|
||||||
await send(chunk)
|
|
||||||
|
@@ -6,7 +6,7 @@ from io import BytesIO
|
|||||||
from mimetypes import init as mimeinit, guess_type
|
from mimetypes import init as mimeinit, guess_type
|
||||||
from os import getcwd
|
from os import getcwd
|
||||||
from os.path import join, normpath, splitext, relpath, basename
|
from os.path import join, normpath, splitext, relpath, basename
|
||||||
from typing import Callable, TYPE_CHECKING, Optional, Awaitable, AsyncGenerator, Any, Mapping
|
from typing import Callable, TYPE_CHECKING, Optional, Awaitable, AsyncGenerator, Any
|
||||||
|
|
||||||
import pygraphviz as pgv
|
import pygraphviz as pgv
|
||||||
from aiofiles import open as async_open
|
from aiofiles import open as async_open
|
||||||
@@ -14,7 +14,6 @@ from aiofiles.base import AiofilesContextManager
|
|||||||
from aiofiles.os import listdir
|
from aiofiles.os import listdir
|
||||||
from aiofiles.ospath import exists, isdir, isfile, getmtime
|
from aiofiles.ospath import exists, isdir, isfile, getmtime
|
||||||
from aiofiles.threadpool.binary import AsyncBufferedReader
|
from aiofiles.threadpool.binary import AsyncBufferedReader
|
||||||
from httpx import AsyncClient
|
|
||||||
from pwo import Maybe
|
from pwo import Maybe
|
||||||
|
|
||||||
from .asgi_utils import encode_headers
|
from .asgi_utils import encode_headers
|
||||||
@@ -57,10 +56,7 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class Server:
|
class Server:
|
||||||
root_dir: 'StrOrBytesPath'
|
|
||||||
prefix: Optional['StrOrBytesPath']
|
|
||||||
_loop: AbstractEventLoop
|
_loop: AbstractEventLoop
|
||||||
_client: AsyncClient
|
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
root_dir: 'StrOrBytesPath' = getcwd(),
|
root_dir: 'StrOrBytesPath' = getcwd(),
|
||||||
@@ -71,16 +67,13 @@ class Server:
|
|||||||
self.file_watcher = FileWatcher(cwd)
|
self.file_watcher = FileWatcher(cwd)
|
||||||
self.prefix = prefix and normpath(f'{prefix.decode()}')
|
self.prefix = prefix and normpath(f'{prefix.decode()}')
|
||||||
self._loop = loop
|
self._loop = loop
|
||||||
self._client = AsyncClient()
|
|
||||||
|
|
||||||
async def handle_request(self,
|
async def handle_request(self,
|
||||||
method: str,
|
method: str,
|
||||||
url_path: str,
|
url_path: str,
|
||||||
etag: Optional[str],
|
etag: Optional[str],
|
||||||
query_string: Optional[str],
|
query_string: Optional[str], send,
|
||||||
send: Callable[[Mapping[str, Any]], Awaitable[None]],
|
pathsend: bool = False):
|
||||||
pathsend: bool = False
|
|
||||||
):
|
|
||||||
if method != 'GET':
|
if method != 'GET':
|
||||||
await send({
|
await send({
|
||||||
'type': 'http.response.start',
|
'type': 'http.response.start',
|
||||||
@@ -181,6 +174,7 @@ class Server:
|
|||||||
})
|
})
|
||||||
elif is_plant_uml(path):
|
elif is_plant_uml(path):
|
||||||
logger.debug("Starting PlantUML rendering for file '%s'", path)
|
logger.debug("Starting PlantUML rendering for file '%s'", path)
|
||||||
|
body = await render_plant_uml(path)
|
||||||
logger.debug("Completed PlantUML rendering for file '%s'", path)
|
logger.debug("Completed PlantUML rendering for file '%s'", path)
|
||||||
await send({
|
await send({
|
||||||
'type': 'http.response.start',
|
'type': 'http.response.start',
|
||||||
@@ -191,15 +185,9 @@ class Server:
|
|||||||
'Cache-Control': 'no-cache'
|
'Cache-Control': 'no-cache'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
await render_plant_uml(self._client, path, lambda chunk: send({
|
|
||||||
'type': 'http.response.body',
|
|
||||||
'body': chunk,
|
|
||||||
'more_body': True
|
|
||||||
}))
|
|
||||||
await send({
|
await send({
|
||||||
'type': 'http.response.body',
|
'type': 'http.response.body',
|
||||||
'body': '',
|
'body': body
|
||||||
'more_body': False
|
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
async def read_file(file_path, buffer_size=0x10000):
|
async def read_file(file_path, buffer_size=0x10000):
|
||||||
@@ -404,4 +392,3 @@ class Server:
|
|||||||
|
|
||||||
async def stop(self):
|
async def stop(self):
|
||||||
await self.file_watcher.stop()
|
await self.file_watcher.stop()
|
||||||
await self._client.aclose()
|
|
||||||
|
Reference in New Issue
Block a user