1
0
Fork 0

Compare commits

..

No commits in common. "a14921b79e88e1dfeffbaf2d76f38a51259e1e21" and "949d180edd74eda932a268abac34df06cb9dc2c7" have entirely different histories.

4 changed files with 26 additions and 63 deletions

1
svc/.gitignore vendored
View File

@ -4,4 +4,3 @@
.mypy_cache/
__pycache__/
*.py[co]
/config.json

View File

@ -1,5 +1,7 @@
import io
import logging
import os
from pathlib import Path
from typing import Optional
from PIL import Image
@ -15,11 +17,16 @@ log = logging.getLogger(__name__)
logging.basicConfig(level=logging.DEBUG)
HUDCTRL_URLS_FILE = os.environ.get('HUDCTRL_URLS_FILE')
app = fastapi.FastAPI(
docs_url='/api-doc/',
)
svc = HUDService()
if HUDCTRL_URLS_FILE:
svc.urls_file = Path(HUDCTRL_URLS_FILE)
class PNGImageResponse(fastapi.Response):
@ -54,8 +61,7 @@ async def get_monitor_config():
@app.put('/display/monitors')
async def put_monitor_config(
bgtasks: fastapi.BackgroundTasks,
monitors: str = fastapi.Body(..., media_type='text/plain'),
monitors: str = fastapi.Body(..., media_type='text/plain')
):
try:
svc.monitor_config = MonitorConfig.from_string(monitors)
@ -65,7 +71,6 @@ async def put_monitor_config(
fastapi.status.HTTP_400_BAD_REQUEST,
detail=f'Invalid monitor config: {e}',
)
bgtasks.add_task(svc.save_config)
return {'monitor_config': svc.monitor_config}
@ -137,14 +142,8 @@ async def get_screenshot(
'/screen/{name}/navigate',
response_class=fastapi.responses.PlainTextResponse,
)
async def navigate(
bgtasks: fastapi.BackgroundTasks,
name: str,
url: str = fastapi.Form(...),
):
async def navigate(name: str, url: str = fastapi.Form(...)):
await svc.navigate(name, url)
svc.urls[name] = url
bgtasks.add_task(svc.save_config)
@app.on_event('shutdown')

View File

@ -1,12 +0,0 @@
from typing import Optional
import pydantic
from .xrandr import Monitor
class Configuration(pydantic.BaseModel):
monitors: list[Monitor] = pydantic.Field(default_factory=list)
urls: dict[str, str] = pydantic.Field(default_factory=dict)
host: Optional[str] = None
port: Optional[int] = None

View File

@ -2,23 +2,18 @@ import asyncio
import base64
import json
import logging
import os
from pathlib import Path
from typing import Dict, Optional
import pydantic
from aiomarionette import Marionette, WindowRect
from .config import Configuration
from .xrandr import MonitorConfig
log = logging.getLogger(__name__)
CONFIG_PATH = os.environ.get('HUDCTRL_CONFIG_PATH', 'config.json')
class NoMonitorConfig(Exception):
'''Raised when no monitor config has been provided yet'''
@ -39,7 +34,7 @@ class HUDService:
self.urls: Dict[str, str] = {}
self.windows: Dict[str, str] = {}
self.config_file = Path(CONFIG_PATH)
self.urls_file = Path('urls.json')
self.lock = asyncio.Lock()
async def get_screen(self, name: str) -> HUDScreen:
@ -109,27 +104,29 @@ class HUDService:
if tasks:
await asyncio.wait(tasks)
def load_config(self) -> None:
def load_urls(self) -> None:
try:
f = self.config_file.open(encoding='utf-8')
f = self.urls_file.open(encoding='utf-8')
except FileNotFoundError:
return
except OSError as e:
log.error('Could not load config: %s', e)
log.error('Could not load URL list: %s', e)
return
log.info('Loading config from %s', f.name)
log.info('Loading URL list from %s', self.urls_file)
with f:
try:
config = Configuration.parse_obj(json.load(f))
value = json.load(f)
except ValueError as e:
log.error('Failed to load config: %s', e)
log.error('Failed to load URL list: %s', e)
return
self.urls = config.urls
if config.monitors:
self.monitor_config = MonitorConfig()
self.monitor_config.monitors = config.monitors
self.host = config.host
self.port = config.port
if isinstance(value, dict):
self.urls = value
else:
log.error(
'Invalid URL list: found %r, expected %r',
type(value),
dict,
)
async def navigate(self, name: str, url: str) -> None:
assert self.marionette
@ -143,19 +140,6 @@ class HUDService:
await self.marionette.switch_to_window(self.windows[name])
await self.marionette.refresh()
def save_config(self) -> None:
log.info('Saving configuration to %s', self.config_file)
config = Configuration(
monitors=self.monitor_config.monitors
if self.monitor_config
else [],
urls=self.urls,
host=self.host,
port=self.port,
)
f = self.config_file.open('w', encoding='utf-8')
f.write(config.json())
async def set_display(self, host: str, port: int) -> None:
if self.marionette:
log.warning('Closing existing Marionette connection')
@ -170,17 +154,10 @@ class HUDService:
if self.marionette is not None:
await self.marionette.close()
self.marionette = None
self.save_config()
async def startup(self) -> None:
asyncio.create_task(self._startup())
async def _startup(self) -> None:
await asyncio.to_thread(self.load_config)
if self.host and self.port:
await self.set_display(self.host, self.port)
if self.monitor_config:
await self.initialize()
loop = asyncio.get_running_loop()
await loop.run_in_executor(None, self.load_urls)
async def take_screenshot(self, screen: str) -> bytes:
assert self.marionette