diff --git a/nise-backend/src/main/kotlin/com/nisemoe/nise/controller/UserDetailsController.kt b/nise-backend/src/main/kotlin/com/nisemoe/nise/controller/UserDetailsController.kt index cdf1942..09d61f5 100644 --- a/nise-backend/src/main/kotlin/com/nisemoe/nise/controller/UserDetailsController.kt +++ b/nise-backend/src/main/kotlin/com/nisemoe/nise/controller/UserDetailsController.kt @@ -25,8 +25,6 @@ class UserDetailsController( private val userQueueService: UpdateUserQueueService ) { - - data class UserDetailsResponse( val user_details: UserDetails, val queue_details: UserQueueDetails, diff --git a/nise-backend/src/main/kotlin/com/nisemoe/nise/scheduler/ImportScores.kt b/nise-backend/src/main/kotlin/com/nisemoe/nise/scheduler/ImportScores.kt index c26f9ec..0dbab4f 100644 --- a/nise-backend/src/main/kotlin/com/nisemoe/nise/scheduler/ImportScores.kt +++ b/nise-backend/src/main/kotlin/com/nisemoe/nise/scheduler/ImportScores.kt @@ -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,10 +627,19 @@ class ImportScores( return } - if(processedReplay.ur != null && processedReplay.ur < 25.0) { - 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) + 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) { diff --git a/nise-backend/src/main/kotlin/com/nisemoe/nise/service/UpdateUserQueueService.kt b/nise-backend/src/main/kotlin/com/nisemoe/nise/service/UpdateUserQueueService.kt index 172b9e4..0d2a886 100644 --- a/nise-backend/src/main/kotlin/com/nisemoe/nise/service/UpdateUserQueueService.kt +++ b/nise-backend/src/main/kotlin/com/nisemoe/nise/service/UpdateUserQueueService.kt @@ -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)) ) } diff --git a/nise-frontend/src/app/app.component.html b/nise-frontend/src/app/app.component.html index 8dd5b87..f2cb6a2 100644 --- a/nise-frontend/src/app/app.component.html +++ b/nise-frontend/src/app/app.component.html @@ -26,5 +26,5 @@
- v20240218 + v20240222
diff --git a/nise-frontend/src/app/view-user/view-user.component.html b/nise-frontend/src/app/view-user/view-user.component.html index c553ceb..d1833e4 100644 --- a/nise-frontend/src/app/view-user/view-user.component.html +++ b/nise-frontend/src/app/view-user/view-user.component.html @@ -47,14 +47,14 @@ - can't force update now + wait a bit to force update | last update: {{ this.userInfo.queue_details.lastCompletedUpdate ? this.calculateTimeAgo(this.userInfo.queue_details.lastCompletedUpdate) : 'never'}}
- updating now! | progress: {{ this.userInfo.queue_details.progressCurrent ? this.userInfo.queue_details.progressCurrent : "?" }}/{{ this.userInfo.queue_details.progressTotal ? this.userInfo.queue_details.progressTotal : "?" }} + updating now! | progress: {{ this.userInfo.queue_details.progressCurrent != null ? this.userInfo.queue_details.progressCurrent : "?" }}/{{ this.userInfo.queue_details.progressTotal != null ? this.userInfo.queue_details.progressTotal : "?" }} (in queue) @@ -64,29 +64,74 @@
-

Suspicious Scores ({{ this.userInfo.suspicious_scores.length }})

-
+ +

Suspicious Scores ({{ this.userInfo.suspicious_scores.length }})

+
+ + + + + + + + + + + + + + + + + + + +
BeatmapDate + cvUR + + PP +
+ + {{ score.date }}{{ score.ur | number: '1.2-2' }}{{ score.pp | number: '1.0-1' }} + + Details + + + osu!web + +
+
+
+ + +

Similar Replays ({{ this.userInfo.similar_replays.length }})

- - - - + + + + - + - - - - + + +
BeatmapDate - cvUR - - PP - LinksReplay 1 DetailsReplay 2 DetailsSimilarity
{{ score.date }}{{ score.ur | number: '1.2-2' }}{{ score.pp | number: '1.0-1' }} - - Details + + + {{ score.replay_date_1 }} +
+ User: {{ score.username_1 }} +
+ PP: {{ score.replay_pp_1 | number: '1.0-0' }}
- - osu!web +
+ + {{ score.replay_date_2 }} +
+ User: {{ score.username_2 }} +
+ PP: {{ score.replay_pp_2 | number: '1.0-0' }} +
+
{{ score.similarity | number: '1.0-2' }} + + Details
-
- -

Similar Replays ({{ this.userInfo.similar_replays.length }})

- - - - - - - - - - - - - - - - - - - -
BeatmapReplay 1 DetailsReplay 2 DetailsSimilarity
- - - - {{ score.replay_date_1 }} -
- User: {{ score.username_1 }} -
- PP: {{ score.replay_pp_1 | number: '1.0-0' }} -
-
- - {{ score.replay_date_2 }} -
- User: {{ score.username_2 }} -
- PP: {{ score.replay_pp_2 | number: '1.0-0' }} -
-
{{ score.similarity | number: '1.0-2' }} - - Details - -
- + diff --git a/nise-frontend/src/app/view-user/view-user.component.ts b/nise-frontend/src/app/view-user/view-user.component.ts index eb965e2..ca5cd27 100644 --- a/nise-frontend/src/app/view-user/view-user.component.ts +++ b/nise-frontend/src/app/view-user/view-user.component.ts @@ -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,29 +73,35 @@ export class ViewUserComponent implements OnInit, OnChanges, OnDestroy { this.activatedRoute.params.subscribe(params => { this.userId = params['userId']; if (this.userId) { - this.getUserInfo().pipe( - catchError(error => { - this.userInfo = null; - if(error.status == 404) { - this.notFound = true; - } - return EMPTY; - }), - finalize(() => { - this.isLoading = false; - }) - ).subscribe( - (response: UserInfo) => { - this.notFound = false; - this.userInfo = response; - this.title.setTitle(`${this.userInfo.user_details.username}`); - this.subscribeToUser(); - } - ); + this.loadUser(); } }); } + private loadUser(isScoreUpdate = false) { + this.getUserInfo().pipe( + catchError(error => { + this.userInfo = null; + if (error.status == 404) { + this.notFound = true; + } + return EMPTY; + }), + finalize(() => { + this.isLoading = false; + }) + ).subscribe( + (response: UserInfo) => { + this.notFound = false; + this.userInfo = response; + if(!isScoreUpdate) { + this.title.setTitle(`${this.userInfo.user_details.username}`); + this.subscribeToUser(); + } + } + ); + } + ngOnDestroy(): void { this.liveUserSub?.unsubscribe(); } @@ -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; + } + } }); }