Skip to content

fix(system-health-check): add additional time providers and update URLs of existing providers#2611

Merged
CharlVS merged 9 commits intodevfrom
bugfix/clock-api-errors
May 14, 2025
Merged

fix(system-health-check): add additional time providers and update URLs of existing providers#2611
CharlVS merged 9 commits intodevfrom
bugfix/clock-api-errors

Conversation

@takenagain
Copy link
Copy Markdown
Contributor

@takenagain takenagain commented May 8, 2025

All platforms

  • Added a Binance time provider, which uses the time endpoint from the Binance API to compare with the current system time.
  • Removed the dead worldclockapi.com provider
  • Updated the worldtimeapi.org URL

Desktop and Mobile

  • Added a NTP time provider which uses the ntp package with multiple fallback servers. Defaults to pool.ntp.org
    • The ntp package is not actively maintained, but appears stable, straightforward, and builds with the latest Flutter and Dart version (tested on macOS, web, and Linux).
    • The NTP implementation is simple enough to fork or copy over to the SDK if desired.
  • Added an HTTP date header extraction provider, as suggested by @DeckerSU

CORS rules and restrictions on web require the server explicitly allow CORS for any domain and explicitly expose the date header. For this reason, the date header extraction is only enabled on native, non-web, platforms (mobile & desktop).

Testing

Requires a local debug build to view the DEX or Bridge pages that are hidden in the preview builds. Modifying system time by 2 or more minutes should trigger the banner. There might be a ~60-second delay, as the periodic system clock check happens once every 60 seconds.

Time Provider Availability by Platform

Provider Native (Desktop/Mobile) Web Description
NTP Time Provider Direct NTP protocol for precise time synchronization
HTTP Head Time Provider Uses HTTP HEAD requests to extract time from response headers
Binance Time Provider Uses Binance API to retrieve server time
TimeAPI.io REST API that returns current UTC time in ISO 8601 format
WorldTimeAPI REST API that returns current UTC time in ISO 8601 format

Provider Priority

Native Platforms (Desktop/Mobile)

  1. NTP Time Provider (most reliable)
  2. HTTP Head Time Provider
  3. Binance Time Provider
  4. TimeAPI.io
  5. WorldTimeAPI

Web Platforms

  1. Binance Time Provider (most reliable)
  2. TimeAPI.io
  3. WorldTimeAPI

Notes

  • REST APIs (TimeAPI.io and WorldTimeAPI) are used as fallbacks but may be subject to outages, rate limits, or API changes.
  • Both TimeAPI and WorldTimeAPI have been observed blocking requests when connected to a VPN or have had outages.

Summary by CodeRabbit

  • New Features

    • Introduced modular time providers for system clock validation, supporting NTP, HTTP APIs, and Binance API sources.
    • Added a registry to manage multiple time providers, improving reliability across platforms.
    • Enhanced periodic system health checks with event-driven scheduling and improved status reporting.
  • Bug Fixes

    • Improved error handling and logging when fetching external time data, ensuring robust fallback and non-blocking behavior if providers fail.
  • Tests

    • Added comprehensive unit tests for all new time providers, the provider registry, and system clock validation logic.
  • Chores

    • Updated dependencies to include the NTP package.
    • Cleaned up and reorganized import statements across multiple files.

@takenagain takenagain requested a review from Copilot May 8, 2025 15:29
@takenagain takenagain self-assigned this May 8, 2025
@takenagain takenagain added the bug Something isn't working label May 8, 2025
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented May 8, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Error: Could not generate a valid Mermaid diagram after multiple attempts.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@github-actions
Copy link
Copy Markdown

github-actions bot commented May 8, 2025

Visit the preview URL for this PR (updated for commit 3b6196e):

https://walletrc--pull-2611-merge-o0slm7rg.web.app

(expires Fri, 16 May 2025 14:35:39 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: f66a4ff03faa546f12f0ae5a841bd9eff2714dcc

@takenagain takenagain requested a review from Copilot May 8, 2025 15:35
@takenagain
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented May 8, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This pull request enhances system time validation by introducing additional time providers, updates existing provider URLs, and removes unused providers. Key changes include adding new test suites for system health providers, integrating a new NTP dependency in pubspec.yaml, and refactoring the system health bloc and its associated repository and provider implementations.

Reviewed Changes

Copilot reviewed 26 out of 26 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
test_units/main.dart Added new system health test imports and grouped system health tests.
pubspec.yaml Added ntp dependency.
Various views files Removed unused imports related to system_health_state.
lib/services/initializer/app_bootstrapper.dart & lib/main.dart Updated initialization to include mm2Api and ensure logger initialization.
lib/bloc/system_health/* Refactored system health bloc, events, and states for improved periodic checks.
lib/bloc/system_health/system_clock_repository.dart Refactored system clock validation logic to use provider registry.
lib/bloc/system_health/providers/* Introduced and adjusted multiple time providers (NTP, HTTP Head, HTTP, Binance) with improved error handling.
lib/bloc/app_bloc_root.dart Updated the system health bloc initialization to include the periodic check event.
Comments suppressed due to low confidence (1)

lib/bloc/system_health/system_clock_repository.dart:42

  • DateTime.timestamp() is not a valid method for obtaining the current time. Consider replacing it with DateTime.now() to correctly compute the time difference.
final localTime = DateTime.timestamp();

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (7)
lib/bloc/app_bloc_root.dart (1)

414-417: CoinIcon is marked as deprecated

The pipeline failure indicates that CoinIcon is deprecated and shouldn't be used. Consider updating to use AssetIcon from the SDK's komodo_ui package instead.

- await CoinIcon.precacheCoinIcon(context, abbr)
+ await AssetIcon.precacheCoinIcon(context, abbr)

Note: You'll need to add the appropriate import for AssetIcon.

🧰 Tools
🪛 GitHub Actions: takenagain is validating code guidelines 🚀

[info] 415-415: 'CoinIcon' is deprecated and shouldn't be used. CoinIcon is deprecated. Use AssetIcon from the SDK's komodo_ui package instead

lib/bloc/system_health/providers/binance_time_provider.dart (1)

38-63: Consider adding delay between retries.

While the retry mechanism is well-implemented with good error handling and logging, there's no delay between retry attempts. This could potentially overwhelm the server if it's experiencing temporary high load.

Consider adding an exponential backoff delay between retries:

while (retries < maxRetries) {
  try {
    final serverTime = await _fetchServerTime();
    _logger.fine('Successfully retrieved time from Binance API');
    return serverTime;
  } on SocketException catch (e, s) {
    _logger.warning('Socket error with Binance API', e, s);
  } on TimeoutException catch (e, s) {
    _logger.warning('Timeout with Binance API', e, s);
  } on FormatException catch (e, s) {
    _logger.severe('Failed to parse response from Binance API', e, s);
  } on Exception catch (e, s) {
    _logger.severe('Error fetching time from Binance API', e, s);
  }
  retries++;
+ // Add exponential backoff delay
+ if (retries < maxRetries) {
+   final delayDuration = Duration(milliseconds: 100 * (1 << retries));
+   await Future.delayed(delayDuration);
+ }
}
test_units/tests/system_health/http_head_time_provider_test.dart (1)

66-80: Redundant test targets & unused import

The “all servers fail” case (status 500) duplicates the “status is not 200” test and does not add new behaviour checks.
Additionally, the explicit TimeoutException import is unused (the provider handles it internally), so it can be removed to keep the test clean.

lib/bloc/system_health/providers/http_time_provider.dart (1)

69-75: Error responses leak into normal flow – prefer throwing

Returning an artificial http.Response with status 500 inside _httpGet() disguises network errors as “successful” HTTP calls, forcing the caller to inspect statusCode every time and making debugging harder.
Consider re-throwing the original exception so getCurrentUtcTime() can catch/log specific failures, keeping the happy path clean.

lib/bloc/system_health/system_clock_repository.dart (1)

23-26: Idle _httpClient field – unnecessary resource management

_httpClient is created and closed, yet never used after refactor (all providers manage their own clients). Removing it will simplify the class and avoid closing a client that providers might still rely on if the same instance was passed in.

lib/bloc/system_health/providers/http_head_time_provider.dart (1)

11-18: Consider diversifying & randomising the default server list

The hard-coded list contains several CDNs that may block HEAD requests or omit the Date header, causing repeated failures.
Randomising the order once per call (or shuffling on construction) will distribute load and reduce the chance of hitting a consistently bad first host.
Optionally allow the caller to inject their own list via constructor to simplify testing.

lib/bloc/system_health/system_health_bloc.dart (1)

42-44: Minor: make the periodic interval configurable & testable

const Duration(seconds: 60) is baked into the bloc, which makes unit testing slow and prevents apps with different requirements from tweaking the cadence.
Expose the duration via the constructor with a sensible default:

-class SystemHealthBloc extends Bloc<SystemHealthEvent, SystemHealthState> {
-  SystemHealthBloc(this._systemClockRepository, this._api)
+class SystemHealthBloc extends Bloc<SystemHealthEvent, SystemHealthState> {
+  SystemHealthBloc(
+    this._systemClockRepository,
+    this._api, {
+    Duration checkInterval = const Duration(seconds: 60),
+  })  : _checkInterval = checkInterval,
+        super(SystemHealthInitial()) {
@@
-    _timer = Timer.periodic(const Duration(seconds: 60), (timer) {
+    _timer = Timer.periodic(_checkInterval, (timer) {
       add(SystemHealthCheckRequested());
     });
   }
 
+  final Duration _checkInterval;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9b46ffe and dada2cd.

⛔ Files ignored due to path filters (1)
  • pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (25)
  • lib/bloc/app_bloc_root.dart (2 hunks)
  • lib/bloc/system_health/providers/binance_time_provider.dart (1 hunks)
  • lib/bloc/system_health/providers/http_head_time_provider.dart (1 hunks)
  • lib/bloc/system_health/providers/http_time_provider.dart (1 hunks)
  • lib/bloc/system_health/providers/ntp_time_provider.dart (1 hunks)
  • lib/bloc/system_health/providers/time_provider.dart (1 hunks)
  • lib/bloc/system_health/providers/time_provider_registry.dart (1 hunks)
  • lib/bloc/system_health/system_clock_repository.dart (1 hunks)
  • lib/bloc/system_health/system_health_bloc.dart (3 hunks)
  • lib/bloc/system_health/system_health_event.dart (1 hunks)
  • lib/bloc/system_health/system_health_state.dart (1 hunks)
  • lib/main.dart (3 hunks)
  • lib/services/initializer/app_bootstrapper.dart (1 hunks)
  • lib/shared/ui/clock_warning_banner.dart (1 hunks)
  • lib/views/bridge/bridge_exchange_form.dart (0 hunks)
  • lib/views/dex/simple/form/maker/maker_form_trade_button.dart (0 hunks)
  • lib/views/dex/simple/form/taker/taker_form_content.dart (0 hunks)
  • lib/views/market_maker_bot/add_market_maker_bot_trade_button.dart (0 hunks)
  • pubspec.yaml (1 hunks)
  • test_units/main.dart (2 hunks)
  • test_units/tests/system_health/http_head_time_provider_test.dart (1 hunks)
  • test_units/tests/system_health/http_time_provider_test.dart (1 hunks)
  • test_units/tests/system_health/ntp_time_provider_test.dart (1 hunks)
  • test_units/tests/system_health/system_clock_repository_test.dart (1 hunks)
  • test_units/tests/system_health/time_provider_registry_test.dart (1 hunks)
💤 Files with no reviewable changes (4)
  • lib/views/market_maker_bot/add_market_maker_bot_trade_button.dart
  • lib/views/bridge/bridge_exchange_form.dart
  • lib/views/dex/simple/form/maker/maker_form_trade_button.dart
  • lib/views/dex/simple/form/taker/taker_form_content.dart
🧰 Additional context used
🪛 GitHub Actions: takenagain is validating code guidelines 🚀
lib/bloc/app_bloc_root.dart

[info] 415-415: 'CoinIcon' is deprecated and shouldn't be used. CoinIcon is deprecated. Use AssetIcon from the SDK's komodo_ui package instead

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Build Desktop (windows)
  • GitHub Check: Build Mobile (Android)
  • GitHub Check: Build Mobile (iOS)
🔇 Additional comments (27)
lib/services/initializer/app_bootstrapper.dart (1)

12-12: Method signature change adds Mm2Api parameter

The ensureInitialized method now accepts an additional Mm2Api mm2Api parameter. This change ensures that the bootstrapper has access to the MM2 API instance early in the initialization process.

lib/main.dart (4)

5-5: Reordered import parameters without functional change

The order of kIsWasm and kIsWeb has been swapped in the import statement. This change has no functional impact.


32-32: Moved import statement

The import of custom_feedback_form.dart has been moved to after the performance analytics imports, maintaining proper import organization.


58-63: Restructured initialization sequence to introduce MM2 API earlier

The initialization sequence has been improved:

  1. Added explanatory comments about foundational dependencies
  2. Created MM2 API instance immediately after KomodoDefiSdk initialization
  3. Passed both dependencies to the AppBootstrapper's ensureInitialized method

This restructuring aligns with the updated parameter requirements in AppBootstrapper and consolidates initialization logic.


65-65:

Details

❓ Verification inconclusive

Good documentation of technical debt

The comment about "Strange inter-dependencies" appropriately documents a potential architectural issue with the current component relationships.

It would be valuable to understand the nature of these dependencies better:


🏁 Script executed:

#!/bin/bash
# Look for any circular dependencies between these components
echo "Checking dependency relationships between key components..."
rg "TrezorRepo|TrezorCoinsBloc|CoinsRepo|WalletsRepository" -A 5 -B 5 --no-filename | grep -v "import" | sort | uniq

Length of output: 33761


Dependency Analysis: No Direct Circular Dependencies Found

The grep across the codebase for TrezorRepo, TrezorCoinsBloc, CoinsRepo, and WalletsRepository did not reveal any direct circular imports or references. That said, these repositories are injected extensively—in blocs like BridgeBloc, MarketMakerTradeFormBloc, NftReceiveBloc, and many UI components—indicating tight coupling across modules.

• Manually review the constructors and factory methods of these classes to catch any indirect cycles that the grep may have missed.
• Consider introducing facades or service layers (e.g. domain-specific interfaces) to encapsulate repository interactions and reduce cross-module coupling.

pubspec.yaml (1)

164-164: Dependency added for NTP time provider

The addition of the ntp package (v2.0.0) supports the new NTP time provider mentioned in the PR objectives, which will be used for more accurate time synchronization on native desktop and mobile platforms.

lib/shared/ui/clock_warning_banner.dart (1)

1-7: Import cleanup aligns with system health bloc refactoring

The import changes are part of a broader refactoring where system health state handling was centralized in system_health_bloc.dart. The SystemHealthState class is now accessed through this import rather than from a separate file.

lib/bloc/app_bloc_root.dart (2)

287-287: SystemHealthBloc now starts periodic checks automatically

The SystemHealthBloc is now configured to immediately dispatch a SystemHealthPeriodicCheckStarted event upon creation, which initiates automatic periodic system health checks at startup. This is consistent with the new time provider system described in the PR objectives.


303-305: FaucetBloc creation reformatted for consistency

The code has been reformatted to use a multi-line style without changing its logic or parameters.

lib/bloc/system_health/system_health_state.dart (2)

1-2: Refactored to use part directive for better organization

The file has been converted to be a part of system_health_bloc.dart using the part directive, which improves organization by consolidating related components into a cohesive library structure.


11-12: Field position reorganized with no functional change

The positioning of the isValid field was moved from above to below the constructor, maintaining the same functionality while improving code readability.

lib/bloc/system_health/providers/time_provider.dart (1)

1-15: Well-designed abstract base class for time providers

This is a clean and well-structured abstract class that provides a clear contract for time providers. The class includes appropriate documentation, a well-defined async method to get UTC time, a name getter, and a disposable interface with a sensible default implementation.

A few observations:

  • Good use of nullable return type to handle failure cases
  • Clear documentation that explains the purpose of each method
  • Proper disposal pattern included from the start
test_units/main.dart (2)

27-31: Appropriate imports for new system health test files

The new imports for the system health tests are well organized and follow the existing import pattern in the file.


94-101: Well-structured test group for system health time providers

The new test group for 'SystemHealth' logically groups all the time provider tests together. The organization looks good and matches the pattern of other test groups in this file.

test_units/tests/system_health/ntp_time_provider_test.dart (1)

1-19: Good negative test case for NTP time provider

This test effectively verifies the failure handling of the NTP time provider by using an invalid server address with a short timeout and minimal retries.

I appreciate the informative comment about a true success test requiring a real NTP server. This shows good testing practice by acknowledging the limitations of unit tests for this component.

Consider adding a comment to this test file explaining why you're using such a short timeout (10ms). Is this intentionally short to ensure the test runs quickly, or is there another reason? This would help future developers understand the test configuration.

lib/bloc/system_health/system_health_event.dart (1)

5-12: Well-structured event classes with clear responsibilities

The refactoring from a single event to three specialized events improves the design by:

  1. Following better naming conventions (past tense for completed actions)
  2. Creating a clearer separation of concerns between one-time checks and periodic checks
  3. Providing explicit control over the periodic check lifecycle

This design allows for more granular control over system health checks and aligns with standard BLoC pattern practices.

test_units/tests/system_health/time_provider_registry_test.dart (2)

5-28: Good test coverage with clear structure.

The test suite for TimeProviderRegistry provides comprehensive coverage of the core functionality - checking default providers, custom provider injection, and proper disposal of resources. The tests are well-structured with clear expectations and follow Dart testing best practices.


30-41: Good mock implementation.

The _MockTimeProvider class is properly implemented with all required overrides from the TimeProvider abstract class. The optional onDispose callback is a nice touch that makes testing the disposal behavior straightforward.

lib/bloc/system_health/providers/time_provider_registry.dart (3)

9-18: Well-designed registry with proper dependency injection.

The TimeProviderRegistry class follows good design principles by allowing injection of custom providers, HTTP client, and API timeout. Default values are provided when not specified, which makes the class flexible and easy to use.


28-68: Good platform-aware provider initialization with clear documentation.

The provider initialization logic correctly handles platform differences between web/WASM and native platforms. The comments clearly explain the rationale behind platform-specific provider selection, which helps future maintainers understand why certain providers are excluded on specific platforms.


70-76: Proper resource cleanup in dispose method.

The dispose method correctly iterates through all providers and calls their dispose methods, ensuring proper cleanup of resources like sockets or streams.

test_units/tests/system_health/http_time_provider_test.dart (2)

8-62: Comprehensive test coverage for HttpTimeProvider.

The test suite thoroughly covers the functionality of HttpTimeProvider, including successful time retrieval, handling of non-200 responses, missing fields, invalid date formats, and exceptions. Good practice using proper setup and teardown for test isolation.


64-76: Clean MockClient implementation.

The MockClient class is well-implemented with configurable response and exception behavior, making it easy to test various HTTP response scenarios.

lib/bloc/system_health/providers/binance_time_provider.dart (3)

11-18: Good configurable parameters with sensible defaults.

The BinanceTimeProvider constructor allows for extensive customization while providing sensible defaults, making it both flexible and easy to use out of the box.


65-87: Well-implemented server time fetching with proper error handling.

The _fetchServerTime method properly handles HTTP requests, validates responses, and parses the JSON data with appropriate error handling. The method correctly converts the Unix timestamp to a UTC DateTime object.


89-92: Proper resource cleanup in dispose method.

The dispose method correctly closes the HTTP client to prevent resource leaks.

lib/bloc/system_health/providers/http_time_provider.dart (1)

112-122: ⚠️ Potential issue

Compile-time error: missing break causes illegal fall-through

Dart switch statements must end each case with break, continue, return, or throw.
The TimeFormat.iso8601 branch currently falls through into TimeFormat.custom, which will trigger a compile-time error (and, if it compiled, would throw a FormatException for every ISO-8601 string).

         case TimeFormat.iso8601:
           if (formattedTime.endsWith('+00:00')) {
             formattedTime = formattedTime.replaceAll('+00:00', 'Z');
           } else if (!formattedTime.endsWith('Z')) {
             formattedTime += 'Z';
           }
-        case TimeFormat.custom:
+          break;
+
+        case TimeFormat.custom:
           throw const FormatException('Custom time format not supported');
⛔ Skipped due to learnings
Learnt from: takenagain
PR: KomodoPlatform/komodo-wallet#2608
File: lib/views/fiat/fiat_form.dart:235-254
Timestamp: 2025-05-01T20:52:26.713Z
Learning: In Dart, non-empty switch case statements do not require explicit `break` statements at the end as they don't fall through to the next case by default. Adding unnecessary breaks is against the "unnecessary_breaks" linter rule (https://dart.dev/tools/linter-rules/unnecessary_breaks).


final timer = Stopwatch()..start();
await logger.init();
await initializeLogger(mm2Api);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Added initialization of logger with MM2 API

A new asynchronous call to initializeLogger(mm2Api) has been added after the base logger initialization. This integrates MM2 API logging into the bootstrap process.

Verify that the initializeLogger method properly handles any potential exceptions that might occur during initialization:


🏁 Script executed:

#!/bin/bash
# Check implementation of initializeLogger method
fd "initializeLogger" --type f -x cat {} \; | grep -A 15 "initializeLogger.*mm2Api"

Length of output: 86


To inspect how initializeLogger handles errors, let’s locate its definition and surrounding logic:


🏁 Script executed:

#!/bin/bash
# Search for all definitions and usages of initializeLogger in Dart files
rg -n -C3 "initializeLogger" --glob "*.dart"

Length of output: 1108


Let’s inspect the full initializeLogger implementation to confirm its error handling:


🏁 Script executed:

#!/bin/bash
# Display the implementation of initializeLogger with context
rg -n "Future<void> initializeLogger" -A50 --glob "*.dart" lib/services/logger/get_logger.dart

Length of output: 2247


Ensure exception safety in initializeLogger

The current initializeLogger(mm2Api) implementation in lib/services/logger/get_logger.dart only guards the storage read call with .catchError, but leaves both the MM2 API version fetch and session metadata setup unprotected. Any exception thrown by mm2Api.version() or DragonLogs.setSessionMetadata would bubble up and could crash the bootstrap process.

Recommend wrapping the core initialization steps in a try/catch and handling/reporting failures gracefully.

• Affected file:

  • lib/services/logger/get_logger.dart (around lines 33–49)

• Suggested pattern:

Future<void> initializeLogger(Mm2Api mm2Api) async {
  try {
    final platformInfo = PlatformInfo.getInstance();
    final localeName = await getStorage()
        .read('locale')
        .catchError((_) => null) as String? ?? '';

    final mm2Version = await mm2Api.version();
    DragonLogs.setSessionMetadata({
      'appVersion': packageInformation.packageVersion,
      'mm2Version': mm2Version,
      'appLanguage': localeName,
      // …other metadata
    });

    Logger.root.level = kReleaseMode ? Level.INFO : Level.ALL;
    Logger.root.onRecord.listen(_logToUniversalLogger);
  } catch (e, st) {
    // TODO: report to crashlytics or fallback cleanly
    debugPrint('Logger initialization failed: $e');
  }
}

takenagain added 2 commits May 8, 2025 21:45
previous check was a regression that wouldn't show the banner for incorrect clock if there were still peers connected
@takenagain takenagain requested a review from Copilot May 8, 2025 20:01
@takenagain
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented May 8, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR improves the system health check functionality by adding new time providers, updating existing provider URLs, and removing dead ones. Key changes include adding Binance, NTP, and HTTP head time providers along with corresponding tests; updating the SystemHealthBloc to use periodic checks; and modifying dependency registration in the app bootstrap and main entry point.

Reviewed Changes

Copilot reviewed 26 out of 26 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
test_units/main.dart Added tests for new and updated system health components
pubspec.yaml Added the ntp package dependency
lib/views/* Removed unused system_health_state imports to avoid duplication
lib/services/initializer/app_bootstrapper.dart Updated ensureInitialized signature and logger initialization
lib/main.dart Updated bootstrap and removal of duplicate mm2Api instantiation
lib/bloc/system_health/system_health_state.dart Updated state representation (duplicate field issue detected)
lib/bloc/system_health/system_health_bloc.dart Refactored periodic check logic and event handling
lib/bloc/system_health/system_clock_repository.dart Modified clock validation logic using time providers
lib/bloc/system_health/providers/* Added new time provider implementations and registry
Comments suppressed due to low confidence (1)

lib/bloc/system_health/system_clock_repository.dart:39

  • Usage of 'DateTime.timestamp()' appears to be a mistake; use 'DateTime.now()' to get the current local time.
final localTime = DateTime.timestamp();

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (3)
lib/bloc/system_health/providers/http_head_time_provider.dart (2)

26-28: Doc comment does not describe the field

The comment says “The name of the provider” but the field actually holds the logger instance.

-  /// The name of the provider (for logging and identification)
+  /// Logger used for diagnostic output
   final Logger _logger;

76-88: Consider a GET fallback for servers that disallow HEAD

Some CDNs or WAF configurations reject HEAD requests with 405 Method Not Allowed.
A lightweight GET (with range: bytes=0-0 or accept: */*) as a fallback can salvage the time retrieval without noticeable overhead:

-    final response = await _httpClient.head(Uri.parse(url)).timeout(timeout);
+    http.Response response;
+    try {
+      response = await _httpClient.head(Uri.parse(url)).timeout(timeout);
+    } on HttpException catch (_) {
+      // Some servers return 405 for HEAD – retry with a minimal GET.
+      response = await _httpClient
+              .get(Uri.parse(url), headers: {'range': 'bytes=0-0'})
+              .timeout(timeout);
+    }

This is optional, yet it noticeably improves resilience in the wild.
If you adopt it, remember to keep the same status-code and header-parsing logic.

lib/bloc/system_health/providers/http_time_provider.dart (1)

61-83: Minor: _parseTimeFromJson need not be async

After the refactor above, every statement in this method is synchronous. You can:

-Future<DateTime> _parseTimeFromJson(Map<String, dynamic> jsonResponse) async {
+DateTime _parseTimeFromJson(Map<String, dynamic> jsonResponse) {
   ...
-  return _parseDateTime(timeStr);
+  return _parseDateTime(timeStr);
 }

Eliminating unnecessary Futures reduces overhead and simplifies call-sites.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dada2cd and 3d66ca6.

📒 Files selected for processing (13)
  • lib/bloc/system_health/providers/binance_time_provider.dart (1 hunks)
  • lib/bloc/system_health/providers/http_head_time_provider.dart (1 hunks)
  • lib/bloc/system_health/providers/http_time_provider.dart (1 hunks)
  • lib/bloc/system_health/providers/ntp_time_provider.dart (1 hunks)
  • lib/bloc/system_health/providers/time_provider.dart (1 hunks)
  • lib/bloc/system_health/system_clock_repository.dart (1 hunks)
  • lib/bloc/system_health/system_health_bloc.dart (2 hunks)
  • lib/services/initializer/app_bootstrapper.dart (1 hunks)
  • test_units/tests/system_health/http_head_time_provider_test.dart (1 hunks)
  • test_units/tests/system_health/http_time_provider_test.dart (1 hunks)
  • test_units/tests/system_health/ntp_time_provider_test.dart (1 hunks)
  • test_units/tests/system_health/system_clock_repository_test.dart (1 hunks)
  • test_units/tests/system_health/time_provider_registry_test.dart (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • lib/bloc/system_health/providers/time_provider.dart
  • lib/bloc/system_health/providers/binance_time_provider.dart
  • lib/services/initializer/app_bootstrapper.dart
  • test_units/tests/system_health/time_provider_registry_test.dart
  • test_units/tests/system_health/http_time_provider_test.dart
  • lib/bloc/system_health/system_clock_repository.dart
  • lib/bloc/system_health/system_health_bloc.dart
🧰 Additional context used
🧠 Learnings (2)
test_units/tests/system_health/system_clock_repository_test.dart (2)
Learnt from: takenagain
PR: KomodoPlatform/komodo-wallet#2611
File: test_units/tests/system_health/system_clock_repository_test.dart:72-77
Timestamp: 2025-05-08T19:08:38.518Z
Learning: In Dart, `DateTime.timestamp()` constructs a DateTime with the current UTC date and time, equivalent to `DateTime.now().toUtc()`. It was introduced in Dart 3.0.
Learnt from: takenagain
PR: KomodoPlatform/komodo-wallet#2611
File: lib/bloc/system_health/system_clock_repository.dart:41-45
Timestamp: 2025-05-08T19:06:13.560Z
Learning: `DateTime.timestamp()` constructor was introduced in Dart 3.0 and constructs a DateTime with the current UTC date and time. It's equivalent to `DateTime.now().toUtc()` but more concise.
lib/bloc/system_health/providers/http_time_provider.dart (1)
Learnt from: takenagain
PR: KomodoPlatform/komodo-wallet#2608
File: lib/views/fiat/fiat_form.dart:235-254
Timestamp: 2025-05-01T20:52:26.713Z
Learning: In Dart, non-empty switch case statements do not require explicit `break` statements at the end as they don't fall through to the next case by default. Adding unnecessary breaks is against the "unnecessary_breaks" linter rule (https://dart.dev/tools/linter-rules/unnecessary_breaks).
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Build Mobile (Android)
  • GitHub Check: Build Desktop (windows)
  • GitHub Check: Build Mobile (iOS)
🔇 Additional comments (7)
test_units/tests/system_health/ntp_time_provider_test.dart (1)

5-22: Well-structured test for failure scenario.

The test appropriately focuses on the error case that can be deterministically tested without external dependencies. I appreciate the clear comment explaining why a success test would be better as an integration test since it would require a real NTP server.

lib/bloc/system_health/providers/ntp_time_provider.dart (2)

8-36: Well-designed provider with good defaults and clear interface.

This implementation provides good default NTP servers with appropriate fallbacks, configurable timeout and retry settings, and a clear interface following the TimeProvider contract.


37-76: Robust error handling with comprehensive logging.

The getCurrentUtcTime method implementation demonstrates excellent practices:

  • Server iteration with retries for each server
  • Proper exception categorization and handling
  • Detailed logging at appropriate levels (fine for success, warning for retries, severe for complete failure)
  • Clear timeout exception if all servers fail
test_units/tests/system_health/http_head_time_provider_test.dart (2)

8-92: Comprehensive test coverage for HttpHeadTimeProvider.

The test suite effectively covers all scenarios:

  • Success case with valid date header
  • Error cases: missing header, non-200 status, server failures, timeouts, and invalid date format
  • Proper setup and teardown of test environment

This ensures robustness of the HttpHeadTimeProvider implementation.


94-111: Well-implemented MockClient for controlled testing.

The MockClient class is elegantly designed to:

  • Support configurable responses
  • Simulate timeouts
  • Override the necessary BaseClient methods

This enables deterministic testing of the HTTP interactions without relying on actual network calls.

test_units/tests/system_health/system_clock_repository_test.dart (2)

7-91: Well-structured tests with comprehensive scenario coverage.

The test suite effectively verifies the SystemClockRepository behavior:

  • Valid time provider returns true
  • Invalid time (too different) returns false
  • Provider exceptions are handled gracefully
  • Provider ordering is respected (stops after first valid response)

This thorough testing ensures the repository behaves correctly in various scenarios.


93-131: Effective mock implementations for controlled testing.

The mock classes (MockTimeProviderRegistry and MockTimeProvider) are well-designed:

  • They implement just what's needed for testing
  • Allow configuring return values and exceptions
  • Track call counts to verify ordering behavior

This approach enables precise verification of the repository's interaction with its dependencies.

@takenagain takenagain marked this pull request as ready for review May 9, 2025 13:55
@takenagain takenagain marked this pull request as draft May 9, 2025 13:56
@takenagain takenagain force-pushed the bugfix/clock-api-errors branch from df2e07e to 3b6196e Compare May 9, 2025 14:31
@takenagain takenagain marked this pull request as ready for review May 9, 2025 14:36
@takenagain takenagain added the QA Ready for QA Testing label May 9, 2025
Copy link
Copy Markdown
Collaborator

@smk762 smk762 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!
Confirmed banner visible when time is over or under actual by 2 mins.
Confirmed banner removed once time is prperly sync'd

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working QA Ready for QA Testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants