feat(user): support online & last_visit
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
from datetime import UTC, datetime
|
from datetime import UTC, datetime
|
||||||
from typing import TYPE_CHECKING, NotRequired, TypedDict
|
from typing import TYPE_CHECKING, NotRequired, TypedDict
|
||||||
|
|
||||||
|
from app.dependencies.database import get_redis
|
||||||
from app.models.model import UTCBaseModel
|
from app.models.model import UTCBaseModel
|
||||||
from app.models.score import GameMode
|
from app.models.score import GameMode
|
||||||
from app.models.user import Country, Page, RankHistory
|
from app.models.user import Country, Page, RankHistory
|
||||||
@@ -157,7 +158,7 @@ class User(AsyncAttrs, UserBase, table=True):
|
|||||||
|
|
||||||
class UserResp(UserBase):
|
class UserResp(UserBase):
|
||||||
id: int | None = None
|
id: int | None = None
|
||||||
is_online: bool = True # TODO
|
is_online: bool = False
|
||||||
groups: list = [] # TODO
|
groups: list = [] # TODO
|
||||||
country: Country = Field(default_factory=lambda: Country(code="CN", name="China"))
|
country: Country = Field(default_factory=lambda: Country(code="CN", name="China"))
|
||||||
favourite_beatmapset_count: int = 0 # TODO
|
favourite_beatmapset_count: int = 0 # TODO
|
||||||
@@ -225,6 +226,8 @@ class UserResp(UserBase):
|
|||||||
.limit(200)
|
.limit(200)
|
||||||
)
|
)
|
||||||
).one()
|
).one()
|
||||||
|
redis = get_redis()
|
||||||
|
u.is_online = await redis.exists(f"metadata:online:{obj.id}")
|
||||||
u.cover_url = (
|
u.cover_url = (
|
||||||
obj.cover.get(
|
obj.cover.get(
|
||||||
"url", "https://assets.ppy.sh/user-profile-covers/default.jpeg"
|
"url", "https://assets.ppy.sh/user-profile-covers/default.jpeg"
|
||||||
|
|||||||
@@ -482,7 +482,6 @@ async def process_user(
|
|||||||
previous_score_best_mod = await get_user_best_score_with_mod_in_beatmap(
|
previous_score_best_mod = await get_user_best_score_with_mod_in_beatmap(
|
||||||
session, score.beatmap_id, user.id, mod_for_save, score.gamemode
|
session, score.beatmap_id, user.id, mod_for_save, score.gamemode
|
||||||
)
|
)
|
||||||
print(previous_score_best, previous_score_best_mod)
|
|
||||||
add_to_db = False
|
add_to_db = False
|
||||||
mouthly_playcount = (
|
mouthly_playcount = (
|
||||||
await session.exec(
|
await session.exec(
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class OsuDotDirectFetcher(BaseFetcher):
|
|||||||
async def get_or_fetch_beatmap_raw(
|
async def get_or_fetch_beatmap_raw(
|
||||||
self, redis: redis.Redis, beatmap_id: int
|
self, redis: redis.Redis, beatmap_id: int
|
||||||
) -> str:
|
) -> str:
|
||||||
if redis.exists(f"beatmap:{beatmap_id}:raw"):
|
if await redis.exists(f"beatmap:{beatmap_id}:raw"):
|
||||||
return await redis.get(f"beatmap:{beatmap_id}:raw") # pyright: ignore[reportReturnType]
|
return await redis.get(f"beatmap:{beatmap_id}:raw") # pyright: ignore[reportReturnType]
|
||||||
raw = await self.get_beatmap_raw(beatmap_id)
|
raw = await self.get_beatmap_raw(beatmap_id)
|
||||||
await redis.set(f"beatmap:{beatmap_id}:raw", raw, ex=60 * 60 * 24)
|
await redis.set(f"beatmap:{beatmap_id}:raw", raw, ex=60 * 60 * 24)
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from collections.abc import Coroutine
|
from collections.abc import Coroutine
|
||||||
|
from datetime import UTC, datetime
|
||||||
from typing import override
|
from typing import override
|
||||||
|
|
||||||
from app.database import Relationship, RelationshipType
|
from app.database import Relationship, RelationshipType
|
||||||
from app.dependencies.database import engine
|
from app.database.lazer_user import User
|
||||||
|
from app.dependencies.database import engine, get_redis
|
||||||
from app.models.metadata_hub import MetadataClientState, OnlineStatus, UserActivity
|
from app.models.metadata_hub import MetadataClientState, OnlineStatus, UserActivity
|
||||||
|
|
||||||
from .hub import Client, Hub
|
from .hub import Client, Hub
|
||||||
@@ -54,6 +56,18 @@ class MetadataHub(Hub[MetadataClientState]):
|
|||||||
async def _clean_state(self, state: MetadataClientState) -> None:
|
async def _clean_state(self, state: MetadataClientState) -> None:
|
||||||
if state.pushable:
|
if state.pushable:
|
||||||
await asyncio.gather(*self.broadcast_tasks(int(state.connection_id), None))
|
await asyncio.gather(*self.broadcast_tasks(int(state.connection_id), None))
|
||||||
|
redis = get_redis()
|
||||||
|
if await redis.exists(f"metadata:online:{state.connection_id}"):
|
||||||
|
await redis.delete(f"metadata:online:{state.connection_id}")
|
||||||
|
async with AsyncSession(engine) as session:
|
||||||
|
async with session.begin():
|
||||||
|
user = (
|
||||||
|
await session.exec(
|
||||||
|
select(User).where(User.id == int(state.connection_id))
|
||||||
|
)
|
||||||
|
).one()
|
||||||
|
user.last_visit = datetime.now(UTC)
|
||||||
|
await session.commit()
|
||||||
|
|
||||||
@override
|
@override
|
||||||
def create_state(self, client: Client) -> MetadataClientState:
|
def create_state(self, client: Client) -> MetadataClientState:
|
||||||
@@ -93,6 +107,8 @@ class MetadataHub(Hub[MetadataClientState]):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
await asyncio.gather(*tasks)
|
await asyncio.gather(*tasks)
|
||||||
|
redis = get_redis()
|
||||||
|
await redis.set(f"metadata:online:{user_id}", "")
|
||||||
|
|
||||||
async def UpdateStatus(self, client: Client, status: int) -> None:
|
async def UpdateStatus(self, client: Client, status: int) -> None:
|
||||||
status_ = OnlineStatus(status)
|
status_ = OnlineStatus(status)
|
||||||
|
|||||||
Reference in New Issue
Block a user