Skip to content

Commit 2e98f00

Browse files
committed
Add OpaClient to wrap OPA interactions
1 parent 0e68df4 commit 2e98f00

2 files changed

Lines changed: 46 additions & 0 deletions

File tree

src/blueapi/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ class Tag(StrEnum):
298298

299299
class OpaConfig(BlueapiBaseModel):
300300
root: HttpUrl = HttpUrl("http://localhost:8181")
301+
audience: str = "account"
301302

302303

303304
class ApplicationConfig(BlueapiBaseModel):
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import logging
2+
from collections.abc import Mapping
3+
from contextlib import AbstractAsyncContextManager, aclosing, nullcontext
4+
from typing import Any, Self
5+
6+
from aiohttp import ClientSession
7+
8+
from blueapi.config import OpaConfig
9+
10+
LOGGER = logging.getLogger(__name__)
11+
12+
13+
class OpaClient:
14+
def __init__(self, instrument: str, config: OpaConfig):
15+
LOGGER.info("Creating OpaClient for %s with config %s", instrument, config)
16+
self._instrument = instrument
17+
self._config = config
18+
self._session = ClientSession(base_url=config.root.encoded_string())
19+
self._audience = config.audience
20+
21+
async def aclose(self):
22+
LOGGER.info("Closing OPA session")
23+
await self._session.close()
24+
25+
async def _call_opa(self, endpoint: str, data: Mapping[str, Any]) -> bool:
26+
resp = await self._session.post(
27+
endpoint,
28+
json={
29+
"input": {
30+
"beamline": self._instrument,
31+
"audience": self._audience,
32+
**data,
33+
}
34+
},
35+
)
36+
return (await resp.json())["result"]
37+
38+
@classmethod
39+
def for_config(
40+
cls, instrument: str, config: OpaConfig | None
41+
) -> AbstractAsyncContextManager[Self | None]:
42+
if config:
43+
return aclosing(cls(instrument, config))
44+
LOGGER.info("No OPA config provided - not creating OpaClient")
45+
return nullcontext()

0 commit comments

Comments
 (0)