Compare commits
No commits in common. "a14921b79e88e1dfeffbaf2d76f38a51259e1e21" and "949d180edd74eda932a268abac34df06cb9dc2c7" have entirely different histories.
a14921b79e
...
949d180edd
|
@ -4,4 +4,3 @@
|
|||
.mypy_cache/
|
||||
__pycache__/
|
||||
*.py[co]
|
||||
/config.json
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue