Work on live score reload with user queue update

This commit is contained in:
nise.moe 2024-02-22 15:10:06 +01:00
parent 8d208feb24
commit ee619161d2
6 changed files with 152 additions and 133 deletions

View File

@ -25,8 +25,6 @@ class UserDetailsController(
private val userQueueService: UpdateUserQueueService
) {
data class UserDetailsResponse(
val user_details: UserDetails,
val queue_details: UserQueueDetails,

View File

@ -218,10 +218,10 @@ class ImportScores(
// Update the frontend
messagingTemplate.convertAndSend(
"/topic/live-user/${userId}",
currentQueueDetails
UpdateUserQueueService.UserQueueWebsocketPacket(message = "UPDATE_PROGRESS", data = currentQueueDetails)
)
this.insertAndProcessNewScore(topScore.beatmap.id, topScore)
this.insertAndProcessNewScore(topScore.beatmap.id, topScore, isUserQueue = true)
}
current += 1
}
@ -518,7 +518,7 @@ class ImportScores(
dslContext.batch(queries).execute()
}
private fun insertAndProcessNewScore(beatmapId: Int, score: OsuApiModels.Score) {
private fun insertAndProcessNewScore(beatmapId: Int, score: OsuApiModels.Score, isUserQueue: Boolean = false) {
// Check if the score is already in the database
val scoreExists = dslContext.fetchExists(SCORES, SCORES.REPLAY_ID.eq(score.best_id))
if (scoreExists) {
@ -627,11 +627,20 @@ class ImportScores(
return
}
if(processedReplay.ur != null && processedReplay.ur < 25.0) {
if(processedReplay.adjusted_ur != null && processedReplay.adjusted_ur < 25.0) {
if(isUserQueue) {
messagingTemplate.convertAndSend(
"/topic/live-user/${score.user_id}",
UpdateUserQueueService.UserQueueWebsocketPacket(message = "UPDATE_SCORES")
)
}
if(!isUserQueue) {
this.logger.info("Inserting user into queue for update: ${score.user_id}")
this.logger.info("UR: ${processedReplay.ur} on their replay with id = ${score.best_id}")
this.updateUserQueueService.insertUser(score.user_id)
}
}
for (judgement in processedReplay.judgements) {
dslContext.insertInto(SCORES_JUDGEMENTS)

View File

@ -19,6 +19,11 @@ class UpdateUserQueueService(
private val USER_UPDATE_INTERVAL_HOURS = 4
data class UserQueueWebsocketPacket(
val message: String,
val data: UserQueueDetails? = null
)
/**
* Retrieves the user queue details for the given user ID.
*
@ -38,28 +43,10 @@ class UpdateUserQueueService(
.limit(1)
.fetchOneInto(OffsetDateTime::class.java)
val lastCompletedUpdateUser = dslContext.select(USERS.SYS_LAST_UPDATE)
.from(USERS)
.where(USERS.USER_ID.eq(userId))
.fetchOneInto(OffsetDateTime::class.java)
// Select the most recent
val lastCompletedUpdate = lastCompletedUpdateQueue?.let {
if (lastCompletedUpdateUser != null) {
if (lastCompletedUpdateUser.isAfter(lastCompletedUpdateQueue)) {
lastCompletedUpdateUser
} else {
lastCompletedUpdateQueue
}
} else {
lastCompletedUpdateQueue
}
} ?: lastCompletedUpdateUser
var canUpdate = !isProcessing
if(lastCompletedUpdate != null) {
if(lastCompletedUpdateQueue != null) {
val now = OffsetDateTime.now(ZoneOffset.UTC)
val hoursSinceLastUpdate = now.hour - lastCompletedUpdate.hour
val hoursSinceLastUpdate = now.hour - lastCompletedUpdateQueue.hour
if(hoursSinceLastUpdate < USER_UPDATE_INTERVAL_HOURS)
canUpdate = false
@ -78,7 +65,7 @@ class UpdateUserQueueService(
return UserQueueDetails(
isProcessing,
lastCompletedUpdate,
lastCompletedUpdateQueue,
canUpdate,
currentProgress?.progressCurrent,
currentProgress?.progressTotal
@ -123,7 +110,7 @@ class UpdateUserQueueService(
// Notify the user that their queue has been processed with fresh info
messagingTemplate.convertAndSend(
"/topic/live-user/${userId}",
this.getUserQueueDetails(userId)
UpdateUserQueueService.UserQueueWebsocketPacket(message = "UPDATE_PROGRESS", data = this.getUserQueueDetails(userId))
)
}

View File

@ -26,5 +26,5 @@
</div>
<router-outlet></router-outlet>
<div class="text-center version">
v20240218
v20240222
</div>

View File

@ -47,14 +47,14 @@
</a>
</ng-container>
<ng-container *ngIf="!this.userInfo.queue_details.canUpdate">
<span class="btn-info">can't force update now</span>
<span class="btn-warning">wait a bit to force update</span>
</ng-container>
<span style="margin-left: 4px">|</span>
last update: {{ this.userInfo.queue_details.lastCompletedUpdate ? this.calculateTimeAgo(this.userInfo.queue_details.lastCompletedUpdate) : 'never'}}
</ng-container>
<ng-template #updateProgress>
<div class="progress">
<span class="btn-warning">updating now!</span> <span style="margin-left: 4px">|</span> progress: {{ this.userInfo.queue_details.progressCurrent ? this.userInfo.queue_details.progressCurrent : "?" }}/{{ this.userInfo.queue_details.progressTotal ? this.userInfo.queue_details.progressTotal : "?" }}
<span class="btn-info">updating now!</span> <span style="margin-left: 4px">|</span> progress: {{ this.userInfo.queue_details.progressCurrent != null ? this.userInfo.queue_details.progressCurrent : "?" }}/{{ this.userInfo.queue_details.progressTotal != null ? this.userInfo.queue_details.progressTotal : "?" }}
<ng-container *ngIf="!this.userInfo.queue_details.progressTotal && !this.userInfo.queue_details.progressCurrent; else loading">
<span style="font-weight: bold">(in queue)</span>
</ng-container>
@ -64,6 +64,7 @@
</div>
</ng-template>
<ng-container *ngIf="this.userInfo.suspicious_scores.length > 0">
<h4>Suspicious Scores ({{ this.userInfo.suspicious_scores.length }})</h4>
<div class="table">
<table class="table">
@ -77,7 +78,7 @@
<th>
PP
</th>
<th>Links</th>
<th></th>
</tr>
</thead>
<tbody>
@ -101,7 +102,7 @@
<a [routerLink]="['/s/' + score.replay_id]" class="btn btn-outline-secondary btn-sm mb-2">
Details
</a>
<a [href]="'https://osu.ppy.sh/scores/osu/' + score.replay_id" class="btn btn-outline-secondary btn-sm"
<a [href]="'https://osu.ppy.sh/scores/osu/' + score.replay_id" class="btn btn-outline-secondary btn-sm" style="margin-left: 5px"
target="_blank">
osu!web
</a>
@ -110,7 +111,9 @@
</tbody>
</table>
</div>
</ng-container>
<ng-container *ngIf="this.userInfo.similar_replays.length > 0">
<h4 class="mt-2">Similar Replays ({{ this.userInfo.similar_replays.length }})</h4>
<table class="table">
<thead>
@ -163,7 +166,7 @@
</tr>
</tbody>
</table>
</ng-container>
</div>
</ng-container>
</div>

View File

@ -21,6 +21,11 @@ interface UserInfo {
total_scores: number;
}
interface UserQueueWebsocketPacket {
message: string;
data?: UserQueueDetails;
}
@Component({
selector: 'app-view-user',
standalone: true,
@ -38,8 +43,6 @@ interface UserInfo {
})
export class ViewUserComponent implements OnInit, OnChanges, OnDestroy {
userUpdateIntervalHours = 4
isLoading = false;
notFound = false;
userId: string | null = null;
@ -70,6 +73,12 @@ export class ViewUserComponent implements OnInit, OnChanges, OnDestroy {
this.activatedRoute.params.subscribe(params => {
this.userId = params['userId'];
if (this.userId) {
this.loadUser();
}
});
}
private loadUser(isScoreUpdate = false) {
this.getUserInfo().pipe(
catchError(error => {
this.userInfo = null;
@ -85,12 +94,12 @@ export class ViewUserComponent implements OnInit, OnChanges, OnDestroy {
(response: UserInfo) => {
this.notFound = false;
this.userInfo = response;
if(!isScoreUpdate) {
this.title.setTitle(`${this.userInfo.user_details.username}`);
this.subscribeToUser();
}
);
}
});
);
}
ngOnDestroy(): void {
@ -136,7 +145,20 @@ export class ViewUserComponent implements OnInit, OnChanges, OnDestroy {
this.liveUserSub = this.rxStompService
.watch(`/topic/live-user/${this.userInfo?.user_details.user_id}`)
.subscribe((message: Message) => {
this.userInfo!.queue_details = JSON.parse(message.body);
let queueDetails: UserQueueWebsocketPacket = JSON.parse(message.body);
if(queueDetails.message == "UPDATE_SCORES") {
this.loadUser(true);
} else {
if(queueDetails.data != null) {
if(queueDetails.data.progressCurrent != null && queueDetails.data.progressTotal != null) {
if (queueDetails.data.progressCurrent >= queueDetails.data.progressTotal) {
this.loadUser(true);
this.liveUserSub?.unsubscribe();
}
}
this.userInfo!.queue_details = queueDetails.data;
}
}
});
}