fix: resolve infinite loading spinner on Logs page#2126
Open
Fizmatik wants to merge 1 commit intohiddify:mainfrom
Open
fix: resolve infinite loading spinner on Logs page#2126Fizmatik wants to merge 1 commit intohiddify:mainfrom
Fizmatik wants to merge 1 commit intohiddify:mainfrom
Conversation
The Logs page shows an infinite loading spinner because the gRPC-based log stream never emits an initial value. This regression was introduced when log watching was migrated from file-based polling to gRPC streams. Root cause: BehaviorSubject without a seed value, combined with no fallback when gRPC is unavailable, leaves the UI in AsyncLoading state permanently. Changes: - Seed BehaviorSubject with empty list for immediate stream emission - Yield current buffer immediately in watchLogs() so UI never hangs - Add file-based fallback (polling) when core is not initialized, matching the behavior of the previous working implementation - Use List.of() at all emission points to prevent mutable aliasing - Set cancelOnError: false and remove explicit cancel from onError so transient gRPC errors don't permanently kill log collection - Set proper Timestamp on file-sourced log entries - Reset file position and notify logController on clearLogs()
Fizmatik
pushed a commit
to Fizmatik/hiddify-app
that referenced
this pull request
Apr 16, 2026
- Submodule: switch to enable-route-rules-v2 (based on upstream/main, not old v3 branch) — fixes Android SetupOptions API mismatch - Cherry-pick PR hiddify#2126: fix infinite loading spinner on Logs page (file fallback when gRPC unavailable, seeded BehaviorSubject, cancelOnError: false for stream resilience)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The Logs page shows an infinite loading spinner and never displays any log entries. This regression was introduced when log watching was migrated from file-based polling to gRPC streams.
Root cause:
BehaviorSubjectwas created without a seed value, sologController.streamnever emitted an initial value. The UI stays inAsyncLoadingstate permanently, renderingSliverLoadingBodyPlaceholder(the spinner).Changes
BehaviorSubjectwith empty list — ensures the stream always has an initial value for subscriberswatchLogs()so the UI transitions toAsyncDataright awayList.of()at all emission points — prevents mutable list aliasing where the same list reference was shared between the stream,BehaviorSubject, and UI consumerscancelOnError: falseand remove explicit cancel fromonErrorhandler — transient gRPC errors no longer permanently kill log collectionTimestampon file-sourced log entries to avoid displaying epoch dateslogControlleronclearLogs()Comparison with previous (working) implementation
The old
ffi_singbox_service.dartusedWatcherto poll the log file and always yielded an initial value:The new gRPC-based implementation omitted both the initial yield and any fallback, causing the regression.
Test plan