236 lines
7.1 KiB
Python
Raw Normal View History

2026-07-23 01:15:04 +02:00
# retoor <retoor@molodetz.nl>
from __future__ import annotations
from typing import Any
from devplacepy_services.base.compound import (
AttachmentsIn,
AwardsBundleIn,
BookmarksIn,
CacheBumpIn,
CommentCountsIn,
CommentsIn,
FeedPageIn,
FollowBundleIn,
LeaderboardBundleIn,
NotificationPrefsIn,
OnlineUsersIn,
PollsIn,
ReactionsIn,
RecentCommentsIn,
RelationsIn,
SeoMetaIn,
SiteSidebarIn,
UserMediaIn,
UsersByUidsIn,
VoteCountsIn,
)
from devplacepy_services.base.errors import http_error
from devplacepy_services.base.http import internal_request
class BrokerClient:
def __init__(self, name: str, url: str | None = None) -> None:
self.name = name
if url is not None:
self.url = url.rstrip("/")
else:
from devplacepy_services.base.config import broker_url
self.url = broker_url(name).rstrip("/")
async def post(self, path: str, body: dict[str, Any] | None = None) -> Any:
target = f"{self.url}/{path.lstrip('/')}"
response = await internal_request("POST", target, json=body or {})
if response.status_code >= 400:
payload = response.json() if response.content else {}
message = payload.get("error", "Broker request failed")
code = payload.get("code", "broker_error")
raise http_error(response.status_code, message, code)
if not response.content:
return None
return response.json()
async def get(self, path: str, *, params: dict[str, Any] | None = None) -> Any:
target = f"{self.url}/{path.lstrip('/')}"
response = await internal_request("GET", target, params=params)
if response.status_code >= 400:
payload = response.json() if response.content else {}
message = payload.get("error", "Broker request failed")
code = payload.get("code", "broker_error")
raise http_error(response.status_code, message, code)
if not response.content:
return None
return response.json()
main = BrokerClient("main")
devii_tasks = BrokerClient("devii_tasks")
devii_lessons = BrokerClient("devii_lessons")
async def get_setting(key: str, default: str = "") -> str:
payload = await main.get(f"settings/{key}", params={"default": default})
return payload.get("value", default) if isinstance(payload, dict) else default
async def get_int_setting(key: str, default: int) -> int:
raw = await get_setting(key, str(default))
try:
return int(raw)
except (TypeError, ValueError):
return default
async def bump_cache_version(name: str) -> None:
await main.post("/cache/bump", CacheBumpIn(name=name).model_dump())
async def get_users_by_uids(uids: list[str]) -> dict:
return await main.post("/compound/users-by-uids", UsersByUidsIn(uids=uids).model_dump())
async def get_comment_counts_by_post_uids(post_uids: list[str]) -> dict:
return await main.post(
"/compound/comment-counts", CommentCountsIn(post_uids=post_uids).model_dump()
)
async def get_vote_counts(target_uids: list[str]) -> tuple[dict, dict]:
payload = await main.post(
"/compound/vote-counts", VoteCountsIn(target_uids=target_uids).model_dump()
)
return payload.get("ups", {}), payload.get("downs", {})
async def get_reactions_by_targets(
target_type: str, target_uids: list[str], user: dict | None = None
) -> dict:
return await main.post(
"/compound/reactions",
ReactionsIn(target_type=target_type, target_uids=target_uids, user=user).model_dump(),
)
async def get_user_bookmarks(
user_uid: str, target_type: str, target_uids: list[str]
) -> set[str]:
payload = await main.post(
"/compound/bookmarks",
BookmarksIn(
user_uid=user_uid, target_type=target_type, target_uids=target_uids
).model_dump(),
)
return set(payload or [])
async def get_polls_by_post_uids(post_uids: list[str], user: dict | None = None) -> dict:
return await main.post(
"/compound/polls", PollsIn(post_uids=post_uids, user=user).model_dump()
)
async def get_recent_comments_by_post_uids(
post_uids: list[str], limit: int = 3, user: dict | None = None
) -> dict:
return await main.post(
"/compound/recent-comments",
RecentCommentsIn(post_uids=post_uids, limit=limit, user=user).model_dump(),
)
async def load_comments(
target_type: str, target_uid: str, user: dict | None = None
) -> list:
return await main.post(
"/compound/comments",
CommentsIn(target_type=target_type, target_uid=target_uid, user=user).model_dump(),
)
async def get_follow_bundle(
user_uid: str, target_uids: list[str] | None = None
) -> dict:
return await main.post(
"/compound/follow-bundle",
FollowBundleIn(user_uid=user_uid, target_uids=target_uids).model_dump(),
)
async def get_user_relations_bundle(viewer_uid: str | None = None) -> dict:
return await main.post(
"/compound/relations", RelationsIn(viewer_uid=viewer_uid).model_dump()
)
async def get_online_users(cutoff_iso: str, limit: int = 30) -> list:
return await main.post(
"/compound/online-users",
OnlineUsersIn(cutoff_iso=cutoff_iso, limit=limit).model_dump(),
)
async def get_notification_prefs(user_uid: str) -> list:
return await main.post(
"/compound/notification-prefs",
NotificationPrefsIn(user_uid=user_uid).model_dump(),
)
async def get_leaderboard_bundle(
limit: int = 50, offset: int = 0, viewer_uid: str | None = None
) -> dict:
return await main.post(
"/compound/leaderboard",
LeaderboardBundleIn(limit=limit, offset=offset, viewer_uid=viewer_uid).model_dump(),
)
async def get_site_sidebar(authors_limit: int = 5) -> dict:
return await main.post(
"/compound/site-sidebar", SiteSidebarIn(authors_limit=authors_limit).model_dump()
)
async def get_awards_bundle(
receiver_uid: str,
page: int = 1,
per_page: int = 12,
profile_user: dict | None = None,
) -> dict:
return await main.post(
"/compound/awards",
AwardsBundleIn(
receiver_uid=receiver_uid,
page=page,
per_page=per_page,
profile_user=profile_user,
).model_dump(),
)
async def get_attachments_batch(resource_type: str, resource_uids: list[str]) -> dict:
return await main.post(
"/compound/attachments",
AttachmentsIn(resource_type=resource_type, resource_uids=resource_uids).model_dump(),
)
async def get_user_media(
user_uid: str, page: int = 1, per_page: int = 24
) -> dict:
return await main.post(
"/compound/user-media",
UserMediaIn(user_uid=user_uid, page=page, per_page=per_page).model_dump(),
)
async def get_seo_metadata_batch(target_type: str, uids: list[str]) -> dict:
return await main.post(
"/compound/seo-meta", SeoMetaIn(target_type=target_type, uids=uids).model_dump()
)
async def build_feed_page(**kwargs) -> dict:
return await main.post("/compound/feed-page", FeedPageIn(**kwargs).model_dump())