feat(user): support online & last_visit

This commit is contained in:
MingxuanGame
2025-08-01 02:49:49 +00:00
parent c5fc6afc18
commit 86a6fd1b69
4 changed files with 22 additions and 4 deletions

View File

@@ -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"

View File

@@ -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(

View File

@@ -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)

View File

@@ -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)