TaskApp integration#139
Conversation
There was a problem hiding this comment.
Pull request overview
This PR migrates task storage from the local RuneLite-profile-based SaveData system to a remote backend at osrstaskapp.com ("TaskApp"). The local task/ package is replaced by a new taskapp/ package with an HTTP client, an auth interceptor, response DTOs, and state storage that mirrors the server's user profile. Several auxiliary changes (config sections for credentials, generalized HttpClient, debouncer using Runnable) support this.
Changes:
- New
taskapppackage:TaskAppClient(extendsHttpClient),TaskAppAuthInterceptor,TaskAppStateStorage,TaskListStorage, response DTOs, and a refactoredTaskServicewhose mutating methods now returnCompletableFutures and go through the remote API. - Removal of the entire local
SaveDatasystem (SaveDataStorage,SaveDataUpdater,V0/V1/V2SaveData,SaveData,BaseSaveData) and of the LMS-toggle config; LMS is now driven by the user's TaskApp profile. - Config gains TaskApp credentials (
username/password) and reorganized sections;HttpClientAPI is generalized (HttpUrl-basedget/post/put/patch);SyncService.sync()is stubbed out with a TODO; UI components that mutated tasks now chainCompletableFutureand hop back to the client thread.
Reviewed changes
Copilot reviewed 36 out of 37 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| src/main/resources/com/collectionlogmaster/ui/sprites/transparent.png | New transparent sprite asset. |
| src/main/java/com/collectionlogmaster/util/SimpleDebouncer.java | Replaces the Callback interface with Runnable and makes delay configurable. |
| src/main/java/com/collectionlogmaster/util/HttpClient.java | Generalized API with HttpUrl + get/post/put/patch; constructor takes OkHttpClient so it can be extended. |
| src/main/java/com/collectionlogmaster/util/GsonOverride.java | Adds LOWER_CASE_WITH_UNDERSCORES naming policy for TaskApp DTOs. |
| src/main/java/com/collectionlogmaster/ui/TaskOverlay.java | Import update for new taskapp package. |
| src/main/java/com/collectionlogmaster/ui/component/TaskList.java | Import update. |
| src/main/java/com/collectionlogmaster/ui/component/TaskInfo.java | Adopts async toggleComplete, hops to client thread for revalidate. |
| src/main/java/com/collectionlogmaster/ui/component/TaskDashboard.java | Awaits async generate()/complete() from TaskService. |
| src/main/java/com/collectionlogmaster/ui/component/TaskComponent.java | Same async/client-thread pattern for toggleComplete. |
| src/main/java/com/collectionlogmaster/ui/component/MainTabbedContainer.java | Import update. |
| src/main/java/com/collectionlogmaster/taskapp/TaskService.java | Reworked as a thin layer over TaskAppClient + TaskAppStateStorage; pickRandomTask, local mutation, LMS config handling removed. |
| src/main/java/com/collectionlogmaster/taskapp/TaskListStorage.java | New: fetches task list via TaskAppClient (no local fallback). |
| src/main/java/com/collectionlogmaster/taskapp/TaskAppStateStorage.java | New: fetches user profile and mutates a shared TaskAppState. |
| src/main/java/com/collectionlogmaster/taskapp/TaskAppState.java | New DTO mirroring user profile. |
| src/main/java/com/collectionlogmaster/taskapp/TaskAppClient.java | New: builds URLs (dev vs prod), wraps HTTP endpoints. |
| src/main/java/com/collectionlogmaster/taskapp/TaskAppAuthInterceptor.java | New: blocking JWT auth interceptor (.join() inside chain). |
| src/main/java/com/collectionlogmaster/taskapp/response/*.java | New response DTOs (LoginResponse, TaskListResponse, UserProfileResponse, GenerateTaskResponse). |
| src/main/java/com/collectionlogmaster/taskapp/domain/CompletedTask.java | New domain type. |
| src/main/java/com/collectionlogmaster/task/* (deleted) | Old TaskListStorage and SaveDataStorage removed. |
| src/main/java/com/collectionlogmaster/domain/savedata/* (deleted) | Entire local save-data + migration removed (no upgrade path). |
| src/main/java/com/collectionlogmaster/synchronization/SyncService.java | sync() body commented out / replaced with stub message. |
| src/main/java/com/collectionlogmaster/command/TaskmanCommandManager.java | Adopts new HttpClient API. |
| src/main/java/com/collectionlogmaster/command/DevCommandsManager.java | Mutates new TaskAppStateStorage (no longer persisted). |
| src/main/java/com/collectionlogmaster/CollectionLogMasterPlugin.java | Import update. |
| src/main/java/com/collectionlogmaster/CollectionLogMasterConfig.java | Adds TaskApp credentials section; removes LMS toggle; reorganizes sections. |
Comments suppressed due to low confidence (5)
src/main/java/com/collectionlogmaster/taskapp/TaskService.java:52
- Removing the entire SaveData migration system (SaveDataStorage, SaveDataUpdater, V0/V1/V2 classes) means existing users who previously stored progress in their RuneLite profile config will lose all of their completed-task progress when this version ships, because there is no longer any code that reads the legacy
save-dataconfig keys and migrates them into the new TaskApp backend. Consider keeping the legacy reader long enough to perform a one-time push of locally stored completed tasks to the TaskApp on first login.
src/main/java/com/collectionlogmaster/taskapp/TaskService.java:70 - Re-authentication when credentials change is currently disabled (the debounce call is commented out and only a TODO remains). The result is that after a user updates their username/password in the config, the auth interceptor will keep using the previously cached token until it expires 12 hours later, and new credentials will silently not take effect. At minimum, invalidate
jwtToken/tokenExpiresAton a credential change so the next request triggers a fresh login.
src/main/java/com/collectionlogmaster/taskapp/TaskService.java:175 complete()(no-arg) passestaskAppStateStorage.get().getActiveTaskId()straight tocomplete(String taskId), which forwards it totaskAppClient.updateTask(taskId, true). If there is no active task,activeTaskIdis null and the PATCH URL becomes.../user/tasks/null— a request that will either fail server-side or do something unexpected. The old implementation explicitly guarded againstactiveTask == null; restore the null check and return a completed future early.
src/main/java/com/collectionlogmaster/taskapp/TaskService.java:171generate()no longer enforces the "no task generated when one is already active" and "no tasks left" guards that the old implementation had (it logged a warning and returned null). The new flow blindly callstaskAppClient.generateTask(); presumably the server enforces these, but if the server does not, or if it returns an error, the future will complete exceptionally and the.thenAccept(...)inTaskDashboard.generateTask()will silently swallow the failure (no.exceptionally/whenComplete). At minimum, attach an error handler so users see a clear failure message instead of a stuck "rolling" UI.
src/main/java/com/collectionlogmaster/taskapp/TaskService.java:78- Three extra blank lines (76-78) and a commented-out
loginDebouncer.debounce(...)left from in-progress code. Clean up before merging.
This issue also appears on line 69 of the same file.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // TODO: implement syncing | ||
| client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", "Sync disabled", null); | ||
| // int updatedCount = 0; | ||
| // for (TaskTier tier : TaskTier.values()) { | ||
| // for (Task task : taskService.getTierTasks(tier)) { | ||
| // Boolean isVerified = syncService.verify(task); | ||
| // if (isVerified == null) { | ||
| // continue; | ||
| // } | ||
| // | ||
| // boolean taskChanged = isVerified != taskService.isComplete(task.getId()); | ||
| // if (!taskChanged) { | ||
| // continue; | ||
| // } | ||
| // | ||
| // taskService.toggleComplete(task.getId()); | ||
| // | ||
| // String newStatus = isVerified ? "<col=27ae60>complete</col>" : "<col=c0392b>incomplete</col>"; | ||
| // String msg = String.format("%s tier task '%s' marked as %s", tier.displayName, task.getName(), newStatus); | ||
| // client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", msg, ""); | ||
| // | ||
| // updatedCount++; | ||
| // } | ||
| // } | ||
| // | ||
| // String msg = String.format("Task synchronization finalized; %d tasks updated", updatedCount); | ||
| // client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", msg, null); |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
No description provided.