修复多人游戏成绩上传报错

This commit is contained in:
咕谷酱
2025-08-22 02:26:39 +08:00
parent cc4ad91b40
commit 71e5f1815e
2 changed files with 51 additions and 17 deletions

View File

@@ -292,6 +292,9 @@ class ScoreResp(ScoreBase):
@classmethod
async def from_db(cls, session: AsyncSession, score: Score) -> "ScoreResp":
# 确保 score 对象完全加载,避免懒加载问题
await session.refresh(score)
s = cls.model_validate(score.model_dump())
assert score.id
await score.awaitable_attrs.beatmap

View File

@@ -97,6 +97,9 @@ async def submit_score(
item_id: int | None = None,
room_id: int | None = None,
):
# 立即获取用户ID避免后续的懒加载问题
user_id = current_user.id
if not info.passed:
info.rank = Rank.F
score_token = (
@@ -106,14 +109,14 @@ async def submit_score(
.where(ScoreToken.id == token)
)
).first()
if not score_token or score_token.user_id != current_user.id:
if not score_token or score_token.user_id != user_id:
raise HTTPException(status_code=404, detail="Score token not found")
if score_token.score_id:
score = (
await db.exec(
select(Score).where(
Score.id == score_token.score_id,
Score.user_id == current_user.id,
Score.user_id == user_id,
)
)
).first()
@@ -169,6 +172,7 @@ async def submit_score(
.where(Score.id == score_id)
)).first()
assert score is not None
resp = await ScoreResp.from_db(db, score)
total_users = (await db.exec(select(func.count()).select_from(User))).first()
assert total_users is not None
@@ -195,14 +199,15 @@ async def submit_score(
await db.commit()
# 成绩提交后刷新用户缓存 - 移至后台任务避免阻塞主流程
# 预先获取用户ID避免在后台任务中触发延迟加载
user_id = current_user.id
# 预先获取游戏模式,避免在后台任务中触发延迟加载
score_gamemode = score.gamemode
if user_id is not None:
background_task.add_task(
_refresh_user_cache_background,
redis,
user_id,
score.gamemode
score_gamemode
)
background_task.add_task(process_user_achievement, resp.id)
return resp
@@ -414,10 +419,13 @@ async def create_solo_score(
current_user: User = Security(get_client_user),
):
assert current_user.id is not None
# 立即获取用户ID避免懒加载问题
user_id = current_user.id
background_task.add_task(_preload_beatmap_for_pp_calculation, beatmap_id)
async with db:
score_token = ScoreToken(
user_id=current_user.id,
user_id=user_id,
beatmap_id=beatmap_id,
ruleset_id=GameMode.from_int(ruleset_id),
)
@@ -469,6 +477,9 @@ async def create_playlist_score(
current_user: User = Security(get_client_user),
):
assert current_user.id is not None
# 立即获取用户ID避免懒加载问题
user_id = current_user.id
room = await session.get(Room, room_id)
if not room:
raise HTTPException(status_code=404, detail="Room not found")
@@ -498,7 +509,7 @@ async def create_playlist_score(
agg = await session.exec(
select(ItemAttemptsCount).where(
ItemAttemptsCount.room_id == room_id,
ItemAttemptsCount.user_id == current_user.id,
ItemAttemptsCount.user_id == user_id,
)
)
agg = agg.first()
@@ -516,7 +527,7 @@ async def create_playlist_score(
# 这里应该不用验证mod了吧。。。
background_task.add_task(_preload_beatmap_for_pp_calculation, beatmap_id)
score_token = ScoreToken(
user_id=current_user.id,
user_id=user_id,
beatmap_id=beatmap_id,
ruleset_id=GameMode.from_int(ruleset_id),
playlist_item_id=playlist_id,
@@ -545,6 +556,10 @@ async def submit_playlist_score(
fetcher: Fetcher = Depends(get_fetcher),
):
assert current_user.id is not None
# 立即获取用户ID避免懒加载问题
user_id = current_user.id
item = (
await session.exec(
select(Playlist).where(
@@ -558,8 +573,6 @@ async def submit_playlist_score(
if not room:
raise HTTPException(status_code=404, detail="Room not found")
room_category = room.category
user_id = current_user.id
score_resp = await submit_score(
background_task,
info,
@@ -611,6 +624,9 @@ async def index_playlist_scores(
),
current_user: User = Security(get_current_user, scopes=["public"]),
):
# 立即获取用户ID避免懒加载问题
user_id = current_user.id
room = await session.get(Room, room_id)
if not room:
raise HTTPException(status_code=404, detail="Room not found")
@@ -637,7 +653,7 @@ async def index_playlist_scores(
score_resp = [await ScoreResp.from_db(session, score.score) for score in scores]
for score in score_resp:
score.position = await get_position(room_id, playlist_id, score.id, session)
if score.user_id == current_user.id:
if score.user_id == user_id:
user_score = score
if room.category == RoomCategory.DAILY_CHALLENGE:
@@ -675,6 +691,9 @@ async def show_playlist_score(
current_user: User = Security(get_client_user),
redis: Redis = Depends(get_redis),
):
# 立即获取用户ID避免懒加载问题
user_id = current_user.id
room = await session.get(Room, room_id)
if not room:
raise HTTPException(status_code=404, detail="Room not found")
@@ -781,11 +800,14 @@ async def pin_score(
score_id: int = Path(description="成绩 ID"),
current_user: User = Security(get_client_user),
):
# 立即获取用户ID避免懒加载问题
user_id = current_user.id
score_record = (
await db.exec(
select(Score).where(
Score.id == score_id,
Score.user_id == current_user.id,
Score.user_id == user_id,
col(Score.passed).is_(True),
)
)
@@ -823,9 +845,12 @@ async def unpin_score(
score_id: int = Path(description="成绩 ID"),
current_user: User = Security(get_client_user),
):
# 立即获取用户ID避免懒加载问题
user_id = current_user.id
score_record = (
await db.exec(
select(Score).where(Score.id == score_id, Score.user_id == current_user.id)
select(Score).where(Score.id == score_id, Score.user_id == user_id)
)
).first()
if not score_record:
@@ -836,7 +861,7 @@ async def unpin_score(
changed_score = (
await db.exec(
select(Score).where(
Score.user_id == current_user.id,
Score.user_id == user_id,
Score.pinned_order > score_record.pinned_order,
Score.gamemode == score_record.gamemode,
)
@@ -864,9 +889,12 @@ async def reorder_score_pin(
before_score_id: int | None = Body(default=None, description="放在该成绩之前"),
current_user: User = Security(get_client_user),
):
# 立即获取用户ID避免懒加载问题
user_id = current_user.id
score_record = (
await db.exec(
select(Score).where(Score.id == score_id, Score.user_id == current_user.id)
select(Score).where(Score.id == score_id, Score.user_id == user_id)
)
).first()
if not score_record:
@@ -957,6 +985,9 @@ async def download_score_replay(
current_user: User = Security(get_current_user, scopes=["public"]),
storage_service: StorageService = Depends(get_storage_service),
):
# 立即获取用户ID避免懒加载问题
user_id = current_user.id
score = (await db.exec(select(Score).where(Score.id == score_id))).first()
if not score:
raise HTTPException(status_code=404, detail="Score not found")
@@ -967,11 +998,11 @@ async def download_score_replay(
raise HTTPException(status_code=404, detail="Replay file not found")
is_friend = (
score.user_id == current_user.id
score.user_id == user_id
or (
await db.exec(
select(exists()).where(
Relationship.user_id == current_user.id,
Relationship.user_id == user_id,
Relationship.target_id == score.user_id,
Relationship.type == RelationshipType.FOLLOW,
)