Update.
This commit is contained in:
+152
-117
@@ -1,5 +1,7 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
from __future__ import annotations
|
||||
|
||||
import ssl
|
||||
from enum import Enum
|
||||
from typing import Any, Dict, List, Literal, Optional, TypedDict, Union
|
||||
|
||||
@@ -119,7 +121,40 @@ class Api:
|
||||
self.user_id: Optional[int] = None
|
||||
self.token_id: Optional[int] = None
|
||||
self.token_key: Optional[str] = None
|
||||
self.session: Optional[aiohttp.ClientSession] = None
|
||||
self._session: Optional[aiohttp.ClientSession] = None
|
||||
self._owns_session: bool = False
|
||||
|
||||
async def __aenter__(self):
|
||||
"""Async context manager entry - creates shared HTTP session."""
|
||||
ssl_context = ssl.create_default_context()
|
||||
ssl_context.check_hostname = False
|
||||
ssl_context.verify_mode = ssl.CERT_NONE
|
||||
connector = aiohttp.TCPConnector(ssl=ssl_context)
|
||||
self._session = aiohttp.ClientSession(connector=connector)
|
||||
self._owns_session = True
|
||||
return self
|
||||
|
||||
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
||||
"""Async context manager exit - closes shared HTTP session."""
|
||||
await self.close()
|
||||
|
||||
async def _get_session(self) -> aiohttp.ClientSession:
|
||||
"""Returns or creates a shared HTTP session for connection reuse."""
|
||||
if self._session is None:
|
||||
ssl_context = ssl.create_default_context()
|
||||
ssl_context.check_hostname = False
|
||||
ssl_context.verify_mode = ssl.CERT_NONE
|
||||
connector = aiohttp.TCPConnector(ssl=ssl_context)
|
||||
self._session = aiohttp.ClientSession(connector=connector)
|
||||
self._owns_session = True
|
||||
return self._session
|
||||
|
||||
async def close(self):
|
||||
"""Closes the HTTP session if owned by this instance."""
|
||||
if self._session and self._owns_session:
|
||||
await self._session.close()
|
||||
self._session = None
|
||||
self._owns_session = False
|
||||
|
||||
def patch_auth(
|
||||
self, request_dict: Optional[Dict[str, Any]] = None
|
||||
@@ -177,25 +212,25 @@ class Api:
|
||||
"""
|
||||
if not self.username or not self.password:
|
||||
raise Exception("No authentication details supplied.")
|
||||
async with aiohttp.ClientSession() as session:
|
||||
response = await session.post(
|
||||
url=self.patch_url("users/auth-token"),
|
||||
data={
|
||||
"username": self.username,
|
||||
"password": self.password,
|
||||
"app": self.app_id,
|
||||
},
|
||||
)
|
||||
obj: LoginResponse = await response.json()
|
||||
if not obj.get("success"):
|
||||
return False
|
||||
self.auth = obj.get("auth_token")
|
||||
if not self.auth:
|
||||
return False
|
||||
self.user_id = self.auth.get("user_id")
|
||||
self.token_id = self.auth.get("id")
|
||||
self.token_key = self.auth.get("key")
|
||||
return bool(self.auth)
|
||||
session = await self._get_session()
|
||||
response = await session.post(
|
||||
url=self.patch_url("users/auth-token"),
|
||||
data={
|
||||
"username": self.username,
|
||||
"password": self.password,
|
||||
"app": self.app_id,
|
||||
},
|
||||
)
|
||||
obj: LoginResponse = await response.json()
|
||||
if not obj.get("success"):
|
||||
return False
|
||||
self.auth = obj.get("auth_token")
|
||||
if not self.auth:
|
||||
return False
|
||||
self.user_id = self.auth.get("user_id")
|
||||
self.token_id = self.auth.get("id")
|
||||
self.token_key = self.auth.get("key")
|
||||
return bool(self.auth)
|
||||
|
||||
async def ensure_login(self) -> bool:
|
||||
"""Ensures the user is logged in before making a request."""
|
||||
@@ -224,20 +259,20 @@ class Api:
|
||||
}
|
||||
```
|
||||
"""
|
||||
async with aiohttp.ClientSession() as session:
|
||||
response = await session.post(
|
||||
url=self.patch_url(f"users"),
|
||||
data=self.patch_auth(
|
||||
{
|
||||
"email": email,
|
||||
"username": username,
|
||||
"password": password,
|
||||
"plat": 3,
|
||||
}
|
||||
),
|
||||
)
|
||||
obj = await response.json()
|
||||
return obj.get("success", False)
|
||||
session = await self._get_session()
|
||||
response = await session.post(
|
||||
url=self.patch_url("users"),
|
||||
data=self.patch_auth(
|
||||
{
|
||||
"email": email,
|
||||
"username": username,
|
||||
"password": password,
|
||||
"plat": 3,
|
||||
}
|
||||
),
|
||||
)
|
||||
obj = await response.json()
|
||||
return obj.get("success", False)
|
||||
|
||||
async def get_comments_from_user(self, username: str) -> List[Comment]:
|
||||
"""
|
||||
@@ -270,13 +305,13 @@ class Api:
|
||||
"""
|
||||
if not await self.ensure_login():
|
||||
return False
|
||||
async with aiohttp.ClientSession() as session:
|
||||
response = await session.post(
|
||||
url=self.patch_url(f"devrant/rants/{rant_id}/comments"),
|
||||
data=self.patch_auth({"comment": comment, "plat": 2}),
|
||||
)
|
||||
obj = await response.json()
|
||||
return obj.get("success", False)
|
||||
session = await self._get_session()
|
||||
response = await session.post(
|
||||
url=self.patch_url(f"devrant/rants/{rant_id}/comments"),
|
||||
data=self.patch_auth({"comment": comment, "plat": 2}),
|
||||
)
|
||||
obj = await response.json()
|
||||
return obj.get("success", False)
|
||||
|
||||
async def get_comment(self, id_: int) -> Optional[Comment]:
|
||||
"""
|
||||
@@ -288,12 +323,12 @@ class Api:
|
||||
Returns:
|
||||
Optional[Comment]: A dictionary representing the comment, or None if not found.
|
||||
"""
|
||||
async with aiohttp.ClientSession() as session:
|
||||
response = await session.get(
|
||||
url=self.patch_url(f"comments/{id_}"), params=self.patch_auth()
|
||||
)
|
||||
obj = await response.json()
|
||||
return obj.get("comment") if obj.get("success") else None
|
||||
session = await self._get_session()
|
||||
response = await session.get(
|
||||
url=self.patch_url(f"comments/{id_}"), params=self.patch_auth()
|
||||
)
|
||||
obj = await response.json()
|
||||
return obj.get("comment") if obj.get("success") else None
|
||||
|
||||
async def delete_comment(self, id_: int) -> bool:
|
||||
"""
|
||||
@@ -307,12 +342,12 @@ class Api:
|
||||
"""
|
||||
if not await self.ensure_login():
|
||||
return False
|
||||
async with aiohttp.ClientSession() as session:
|
||||
response = await session.delete(
|
||||
url=self.patch_url(f"comments/{id_}"), params=self.patch_auth()
|
||||
)
|
||||
obj = await response.json()
|
||||
return obj.get("success", False)
|
||||
session = await self._get_session()
|
||||
response = await session.delete(
|
||||
url=self.patch_url(f"comments/{id_}"), params=self.patch_auth()
|
||||
)
|
||||
obj = await response.json()
|
||||
return obj.get("success", False)
|
||||
|
||||
async def get_profile(self, id_: int) -> Optional[UserProfile]:
|
||||
"""
|
||||
@@ -324,12 +359,12 @@ class Api:
|
||||
Returns:
|
||||
Optional[UserProfile]: A dictionary with the user's profile data.
|
||||
"""
|
||||
async with aiohttp.ClientSession() as session:
|
||||
response = await session.get(
|
||||
url=self.patch_url(f"users/{id_}"), params=self.patch_auth()
|
||||
)
|
||||
obj = await response.json()
|
||||
return obj.get("profile") if obj.get("success") else None
|
||||
session = await self._get_session()
|
||||
response = await session.get(
|
||||
url=self.patch_url(f"users/{id_}"), params=self.patch_auth()
|
||||
)
|
||||
obj = await response.json()
|
||||
return obj.get("profile") if obj.get("success") else None
|
||||
|
||||
async def search(self, term: str) -> List[Rant]:
|
||||
"""
|
||||
@@ -341,13 +376,13 @@ class Api:
|
||||
Returns:
|
||||
List[Rant]: A list of rant objects from the search results.
|
||||
"""
|
||||
async with aiohttp.ClientSession() as session:
|
||||
response = await session.get(
|
||||
url=self.patch_url("devrant/search"),
|
||||
params=self.patch_auth({"term": term}),
|
||||
)
|
||||
obj = await response.json()
|
||||
return obj.get("results", []) if obj.get("success") else []
|
||||
session = await self._get_session()
|
||||
response = await session.get(
|
||||
url=self.patch_url("devrant/search"),
|
||||
params=self.patch_auth({"term": term}),
|
||||
)
|
||||
obj = await response.json()
|
||||
return obj.get("results", []) if obj.get("success") else []
|
||||
|
||||
async def get_rant(self, id: int) -> Dict[str, Any]:
|
||||
"""
|
||||
@@ -359,12 +394,12 @@ class Api:
|
||||
Returns:
|
||||
Dict[str, Any]: The full API response object.
|
||||
"""
|
||||
async with aiohttp.ClientSession() as session:
|
||||
response = await session.get(
|
||||
self.patch_url(f"devrant/rants/{id}"),
|
||||
params=self.patch_auth(),
|
||||
)
|
||||
return await response.json()
|
||||
session = await self._get_session()
|
||||
response = await session.get(
|
||||
self.patch_url(f"devrant/rants/{id}"),
|
||||
params=self.patch_auth(),
|
||||
)
|
||||
return await response.json()
|
||||
|
||||
async def get_rants(
|
||||
self, sort: str = "recent", limit: int = 20, skip: int = 0
|
||||
@@ -380,13 +415,13 @@ class Api:
|
||||
Returns:
|
||||
List[Rant]: A list of rant objects.
|
||||
"""
|
||||
async with aiohttp.ClientSession() as session:
|
||||
response = await session.get(
|
||||
url=self.patch_url("devrant/rants"),
|
||||
params=self.patch_auth({"sort": sort, "limit": limit, "skip": skip}),
|
||||
)
|
||||
obj = await response.json()
|
||||
return obj.get("rants", []) if obj.get("success") else []
|
||||
session = await self._get_session()
|
||||
response = await session.get(
|
||||
url=self.patch_url("devrant/rants"),
|
||||
params=self.patch_auth({"sort": sort, "limit": limit, "skip": skip}),
|
||||
)
|
||||
obj = await response.json()
|
||||
return obj.get("rants", []) if obj.get("success") else []
|
||||
|
||||
async def get_user_id(self, username: str) -> Optional[int]:
|
||||
"""
|
||||
@@ -398,13 +433,13 @@ class Api:
|
||||
Returns:
|
||||
Optional[int]: The user's ID, or None if not found.
|
||||
"""
|
||||
async with aiohttp.ClientSession() as session:
|
||||
response = await session.get(
|
||||
url=self.patch_url("get-user-id"),
|
||||
params=self.patch_auth({"username": username}),
|
||||
)
|
||||
obj = await response.json()
|
||||
return obj.get("user_id") if obj.get("success") else None
|
||||
session = await self._get_session()
|
||||
response = await session.get(
|
||||
url=self.patch_url("get-user-id"),
|
||||
params=self.patch_auth({"username": username}),
|
||||
)
|
||||
obj = await response.json()
|
||||
return obj.get("user_id") if obj.get("success") else None
|
||||
|
||||
async def mentions(self) -> List[Notification]:
|
||||
"""
|
||||
@@ -431,13 +466,13 @@ class Api:
|
||||
"""
|
||||
if not await self.ensure_login():
|
||||
return False
|
||||
async with aiohttp.ClientSession() as session:
|
||||
response = await session.post(
|
||||
url=self.patch_url(f"comments/{comment_id}"),
|
||||
data=self.patch_auth({"comment": comment}),
|
||||
)
|
||||
obj = await response.json()
|
||||
return obj.get("success", False)
|
||||
session = await self._get_session()
|
||||
response = await session.post(
|
||||
url=self.patch_url(f"comments/{comment_id}"),
|
||||
data=self.patch_auth({"comment": comment}),
|
||||
)
|
||||
obj = await response.json()
|
||||
return obj.get("success", False)
|
||||
|
||||
async def vote_rant(
|
||||
self, rant_id: int, vote: Literal[-1, 0, 1], reason: Optional[VoteReason] = None
|
||||
@@ -455,15 +490,15 @@ class Api:
|
||||
"""
|
||||
if not await self.ensure_login():
|
||||
return False
|
||||
async with aiohttp.ClientSession() as session:
|
||||
response = await session.post(
|
||||
url=self.patch_url(f"devrant/rants/{rant_id}/vote"),
|
||||
data=self.patch_auth(
|
||||
{"vote": vote, "reason": reason.value if reason else None}
|
||||
),
|
||||
)
|
||||
obj = await response.json()
|
||||
return obj.get("success", False)
|
||||
session = await self._get_session()
|
||||
response = await session.post(
|
||||
url=self.patch_url(f"devrant/rants/{rant_id}/vote"),
|
||||
data=self.patch_auth(
|
||||
{"vote": vote, "reason": reason.value if reason else None}
|
||||
),
|
||||
)
|
||||
obj = await response.json()
|
||||
return obj.get("success", False)
|
||||
|
||||
async def vote_comment(
|
||||
self,
|
||||
@@ -484,15 +519,15 @@ class Api:
|
||||
"""
|
||||
if not await self.ensure_login():
|
||||
return False
|
||||
async with aiohttp.ClientSession() as session:
|
||||
response = await session.post(
|
||||
url=self.patch_url(f"comments/{comment_id}/vote"),
|
||||
data=self.patch_auth(
|
||||
{"vote": vote, "reason": reason.value if reason else None}
|
||||
),
|
||||
)
|
||||
obj = await response.json()
|
||||
return obj.get("success", False)
|
||||
session = await self._get_session()
|
||||
response = await session.post(
|
||||
url=self.patch_url(f"comments/{comment_id}/vote"),
|
||||
data=self.patch_auth(
|
||||
{"vote": vote, "reason": reason.value if reason else None}
|
||||
),
|
||||
)
|
||||
obj = await response.json()
|
||||
return obj.get("success", False)
|
||||
|
||||
async def notifs(self) -> List[Notification]:
|
||||
"""
|
||||
@@ -503,9 +538,9 @@ class Api:
|
||||
"""
|
||||
if not await self.ensure_login():
|
||||
return []
|
||||
async with aiohttp.ClientSession() as session:
|
||||
response = await session.get(
|
||||
url=self.patch_url("users/me/notif-feed"), params=self.patch_auth()
|
||||
)
|
||||
obj = await response.json()
|
||||
return obj.get("data", {}).get("items", [])
|
||||
session = await self._get_session()
|
||||
response = await session.get(
|
||||
url=self.patch_url("users/me/notif-feed"), params=self.patch_auth()
|
||||
)
|
||||
obj = await response.json()
|
||||
return obj.get("data", {}).get("items", [])
|
||||
|
||||
Reference in New Issue
Block a user