Skip to content

Conversation

@erskingardner
Copy link
Member

@erskingardner erskingardner commented Aug 7, 2025

Summary by CodeRabbit

  • New Features

    • Introduced unified methods for adding and removing relays across all relay types, allowing more granular relay management for accounts.
  • Improvements

    • Enhanced relay connection handling to ensure connections before publishing events.
    • Improved fallback logic for relay usage during group member addition and message publishing.
    • Streamlined account creation and relay assignment in test scenarios.
    • Simplified event fetching logic to improve performance and reliability.
    • Conditional publishing of relay info based on relay presence during login.
    • Unified relay list publishing to support updates on removed relays.
    • Updated test utilities to use consistent identity creation methods and public keys.
  • Bug Fixes

    • Corrected relay URL formatting in integration tests.
    • Improved test reliability by adding delays and clearer logs during group creation.
  • Tests

    • Expanded and refactored test coverage for relay management and account creation workflows.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 7, 2025

Walkthrough

This set of changes refactors and unifies relay management across account and group operations, introducing generic methods for adding and removing relays by type. The code now conditionally publishes relay information based on relay presence and enhances fallback logic for relay usage. Test utilities and test cases are updated to use streamlined account creation and relay handling.

Changes

Cohort / File(s) Change Summary
Integration Test Adjustments
src/bin/integration_test.rs
Corrected relay URL formatting, added async sleep for test stability, and introduced tracing logs around contact and group member addition steps.
NostrManager Relay Handling
src/nostr_manager/mod.rs
Removed connect_to_relay method. Updated publish_event_to to ensure relay connections before publishing events.
User Relay Query Simplification
src/nostr_manager/query.rs
Limited relay event query to one result and simplified event selection logic.
Contact Tests Refactor
src/whitenoise/accounts/contacts.rs
Simplified test account creation and removed manual key handling in tests.
Group Member Addition and Test Refactor
src/whitenoise/accounts/groups.rs
Added relay fallback logic when adding group members and publishing events. Updated group creation test to use new account creation and contact addition methods.
Account Relay Management and API Expansion
src/whitenoise/accounts/mod.rs
Made relay publishing conditional, separated relay fetching for different relay types, and added async methods for relay management (add/remove for each type). Updated account creation and login logic to use these changes. Added test-only method to fetch account relays from DB.
Unified Relay Management Implementation and Tests
src/whitenoise/accounts/relays.rs
Refactored relay management to generic add/remove methods by relay type, consolidated relay connection logic, and added comprehensive tests for relay operations and edge cases. Removed redundant methods and database update calls, replaced by atomic save.
Test Utilities and API Test Updates
src/whitenoise/mod.rs
Updated test utilities and API tests to use new account creation and relay management logic, reflecting changes in relay handling and identity creation.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Whitenoise
    participant Account
    participant Relay

    Client->>Whitenoise: add_relay_to_account(pubkey, relay, relay_type)
    Whitenoise->>Account: Fetch account by pubkey
    Whitenoise->>Account: Add relay to specified relay set
    Whitenoise->>Relay: ensure_relays_connected(relay)
    Whitenoise->>Account: Save updated account state
    Whitenoise->>Relay: publish_account_relay_info(account, prior_relays)
Loading
sequenceDiagram
    participant Whitenoise
    participant Account
    participant Relay

    Whitenoise->>Account: login(keys)
    Account->>Relay: Query for key package event
    alt Key package not found
        Account->>Relay: Publish key package
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

A rabbit hopped through fields of code,
Tidying relays on every node.
With methods unified and tests anew,
Connections sure, and logic true.
Now every burrow, group, and friend
Finds their relay at journey’s end!
🐇✨

Note

🔌 MCP (Model Context Protocol) integration is now available in Early Access!

Pro users can now connect to remote MCP servers under the Integrations page to get reviews and chat conversations that understand additional development context.


📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between a708596 and ca1ac9a.

📒 Files selected for processing (3)
  • src/whitenoise/accounts/groups.rs (7 hunks)
  • src/whitenoise/accounts/mod.rs (5 hunks)
  • src/whitenoise/accounts/relays.rs (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/whitenoise/accounts/mod.rs
  • src/whitenoise/accounts/groups.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: check (ubuntu-latest, native)
🔇 Additional comments (4)
src/whitenoise/accounts/relays.rs (4)

107-135: LGTM on relay status fetching

The implementation properly combines all relay types, handles errors gracefully by defaulting to Disconnected status, and provides comprehensive status information.


157-251: Excellent architectural improvement with unified relay management

The generic add_relay_to_account and remove_relay_from_account methods successfully unify relay handling across all types. The implementation follows a consistent, robust pattern:

  1. Account validation
  2. Atomic relay set updates
  3. Database persistence
  4. In-memory cache synchronization
  5. Appropriate connection management
  6. Relay list publishing with proper prior relay handling

This design significantly reduces code duplication and ensures consistent behavior across relay types.


266-307: Well-designed relay list publishing with improved parameter naming

The enhanced publish_relay_list_for_account method correctly addresses the need to publish updated relay lists to prior relays when removing relays. The renamed target_relays parameter is more descriptive than the previous name and clearly indicates its purpose.


320-751: Comprehensive and well-structured test suite

The test coverage is excellent, systematically testing:

  • All relay types uniformly through the helper function pattern
  • Add/remove operations with proper state verification
  • Database consistency between in-memory and persistent state
  • Edge cases and error conditions
  • Type conversions and status fetching

The helper function await_test_relay_type effectively eliminates duplication while ensuring thorough testing across all relay types.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor-relay-methods

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.
    • Explain this complex logic.
    • 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 explain this code block.
  • 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 explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

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

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 generate unit tests to generate unit tests for 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
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: 2

🧹 Nitpick comments (1)
src/whitenoise/accounts/mod.rs (1)

1106-1140: Consider documenting deprecation if these methods will be removed

These convenience methods provide a cleaner API for relay management. According to the AI summary, these will be removed in a later refactor. If that's the plan, consider adding deprecation warnings or documentation.

If these methods are temporary, add documentation:

+    /// Convenience method to add a Nostr (NIP-65) relay
+    /// Note: This method may be deprecated in favor of the generic add_relay_to_account method
     pub async fn add_nip65_relay(&self, account: &Account, relay: RelayUrl) -> Result<()> {
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 1610086 and 790b1c1.

📒 Files selected for processing (8)
  • src/bin/integration_test.rs (3 hunks)
  • src/nostr_manager/mod.rs (2 hunks)
  • src/nostr_manager/query.rs (1 hunks)
  • src/whitenoise/accounts/contacts.rs (2 hunks)
  • src/whitenoise/accounts/groups.rs (6 hunks)
  • src/whitenoise/accounts/mod.rs (5 hunks)
  • src/whitenoise/accounts/relays.rs (4 hunks)
  • src/whitenoise/mod.rs (3 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
src/bin/integration_test.rs

📄 CodeRabbit Inference Engine (.cursor/rules/integration-test.mdc)

The integration test in src/bin/integration_test.rs should ALWAYS be run with the just int-test command and not run on its own with different log and data directories.

Files:

  • src/bin/integration_test.rs
🧠 Learnings (1)
📚 Learning: applies to src/bin/integration_test.rs : the integration test in src/bin/integration_test.rs should ...
Learnt from: CR
PR: parres-hq/whitenoise#0
File: .cursor/rules/integration-test.mdc:0-0
Timestamp: 2025-08-07T12:20:56.734Z
Learning: Applies to src/bin/integration_test.rs : The integration test in src/bin/integration_test.rs should ALWAYS be run with the `just int-test` command and not run on its own with different log and data directories.

Applied to files:

  • src/bin/integration_test.rs
🧬 Code Graph Analysis (2)
src/nostr_manager/query.rs (1)
src/_OLD/OLD_commands/accounts/fetch_relays_list.rs (1)
  • fetch_relays_list (27-126)
src/nostr_manager/mod.rs (1)
src/nostr_manager/subscriptions.rs (1)
  • NostrManager (9-154)
🔇 Additional comments (22)
src/whitenoise/accounts/contacts.rs (2)

531-531: LGTM! Test simplification improves consistency.

The replacement of manual account creation with create_identity() standardizes test setup and ensures tests use the actual production code path for identity creation.


639-639: LGTM! Consistent test improvement.

This change aligns with the standardization effort across test modules, using the unified create_identity() method for test account setup.

src/bin/integration_test.rs (3)

270-270: LGTM! WebSocket URL standardization.

Removing the trailing slash from the WebSocket URL improves consistency and avoids potential connection issues.


380-381: LGTM! Improves test reliability with proper initialization timing.

The added sleep ensures account4 is fully initialized and has published its events before proceeding with contact/member operations. This prevents race conditions in the integration test.


397-404: LGTM! Enhanced test observability.

The added tracing logs provide clear runtime feedback on contact addition and group member operations, making the integration test easier to debug and monitor.

src/nostr_manager/query.rs (2)

39-42: LGTM! Efficient query optimization.

Adding .limit(1) to the filter reduces network overhead and memory usage while maintaining correctness, as relays typically return the most recent event when limited.


49-52: LGTM! Simplified event selection logic.

The change from finding the maximum created_at timestamp to taking the first event aligns perfectly with the .limit(1) optimization. The clone() is appropriate for providing ownership to relay_urls_from_event().

src/whitenoise/mod.rs (3)

698-710: LGTM!

The refactoring to use login() method for account creation and the change to use account.pubkey instead of keys.public_key for contact addition are both consistent and correct improvements.


887-892: LGTM!

The refactoring to use create_identity() simplifies the test setup and the change to use account.pubkey is consistent with using the account as the primary interface.


916-924: LGTM!

The refactoring to use create_identity() and the updated comments correctly reflect that the expected error behavior changes since nostr_mls is now initialized. The switch to account.pubkey is consistent.

src/nostr_manager/mod.rs (1)

209-227: Excellent reliability improvement!

The addition of ensure_relays_connected before publishing events is a significant improvement that prevents publish failures due to disconnected relays. This change aligns with the pattern already used in subscription methods and centralizes relay connection management.

src/whitenoise/accounts/groups.rs (4)

257-261: Good fallback implementation!

Adding fallback to default relays when key_package_relays is empty prevents failures and ensures robust key package fetching.


308-332: Excellent fallback and error handling!

The refactored relay handling for evolution event publishing is a significant improvement:

  • Clear fallback logic from group relays to account relays to prevent failures
  • Proper error handling when no relays are available
  • Good logging for debugging
  • Clean conditional logic that's easy to follow

360-364: Consistent fallback pattern!

The fallback to default relays for empty inbox_relays is consistent with the other relay fallback logic in this method and ensures welcome messages can be delivered reliably.


450-464: Clean test refactoring!

The changes to use create_mock_whitenoise() and create_identity() for account creation significantly simplify the test setup and make it more consistent with the broader refactoring efforts.

src/whitenoise/accounts/mod.rs (2)

334-340: LGTM! Good optimization for conditional key package publishing

The change to only publish key packages when they're not found locally is a good optimization that reduces unnecessary network operations.


1088-1104: LGTM! Well-structured test helper method

The test-only helper method is properly gated with #[cfg(test)] and provides clean access to relay data for testing purposes.

src/whitenoise/accounts/relays.rs (5)

157-200: LGTM! Well-structured unified relay management

The generic add_relay_to_account method properly handles all relay types uniformly, maintains consistency between database and in-memory state, and ensures relay connections before publishing.


253-268: LGTM! Clean relay info publishing implementation

The method properly publishes relay lists for all relay types and correctly handles the optional prior_relays parameter for overwriting relay events on removed relays.


325-362: Excellent comprehensive test coverage!

The test properly covers all relay types (Nostr, Inbox, KeyPackage) using a helper function to avoid code duplication. Good test structure!


697-700: Good use of #[should_panic] for invalid input testing

Testing panic behavior for invalid relay types ensures the API contract is enforced.


702-754: Excellent database consistency verification!

This test thoroughly verifies that in-memory and database states remain synchronized after relay operations, which is critical for data integrity.

Copy link
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: 1

🧹 Nitpick comments (1)
src/whitenoise/accounts/mod.rs (1)

1085-1137: Well-implemented convenience methods with minor optimization opportunity.

The relay management convenience methods provide a clean, consistent API. The delegation pattern and naming conventions are excellent.

Consider these minor improvements:

  1. Parameter optimization: The methods only use account.pubkey, so they could accept PublicKey directly:
-pub async fn add_nip65_relay(&self, account: &Account, relay: RelayUrl) -> Result<()> {
-    self.add_relay_to_account(account.pubkey, relay, RelayType::Nostr)
+pub async fn add_nip65_relay(&self, pubkey: PublicKey, relay: RelayUrl) -> Result<()> {
+    self.add_relay_to_account(pubkey, relay, RelayType::Nostr)
  1. Account validation: Consider adding validation to ensure the account belongs to the current user (if not handled in the generic methods).

The current implementation is still perfectly functional as-is.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 790b1c1 and a708596.

📒 Files selected for processing (1)
  • src/whitenoise/accounts/mod.rs (5 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: check (ubuntu-latest, native)
🔇 Additional comments (3)
src/whitenoise/accounts/mod.rs (3)

641-696: Excellent refactor addressing redundant relay publishing!

This implementation successfully addresses the redundant relay publishing issue from previous reviews. The logic correctly:

  1. Fetches each relay type separately from appropriate sources
  2. Falls back to defaults when empty and tracks publishing needs
  3. Publishes relay info only once if any relay type requires it

This is much more efficient than the previous approach of multiple identical calls to publish_account_relay_info.


674-675: LGTM! Consistent with relay fetching refactor.

The Account struct initialization now correctly uses the fetched relay sets instead of always defaulting, which is consistent with the improved relay fetching logic above.


689-695: Perfect implementation of the suggested fix!

This conditional publishing logic exactly addresses the concern from previous reviews. By using a single OR condition to check all relay type flags, it eliminates the redundant multiple calls to publish_account_relay_info while maintaining the same functionality.

Comment on lines +334 to +340
// TODO: This should only query local nostr cached events, not fetch from relays
let key_package_event = self
.fetch_key_package_event_from(account.key_package_relays.clone(), pubkey)
.await?;
if key_package_event.is_none() {
self.publish_key_package_for_account(&account).await?;
}
Copy link
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

Address TODO: Avoid network calls during login.

The TODO comment indicates this should only query local cached events, but fetch_key_package_event_from suggests it may be making network calls to relays. Network operations during login can significantly slow down the user experience.

Consider implementing a local-only query method or clarify if this method actually hits the network:


🏁 Script executed:

#!/bin/bash
# Search for the implementation of fetch_key_package_event_from to verify if it makes network calls
ast-grep --pattern $'fetch_key_package_event_from($$$) {
  $$$
}'

Length of output: 66


🏁 Script executed:

#!/bin/bash
# Locate the definition and usages of fetch_key_package_event_from to confirm if it performs network calls
rg -n "fn fetch_key_package_event_from" -C 5

Length of output: 826


🏁 Script executed:

#!/bin/bash
# Extract the full body of fetch_key_package_event_from to inspect its behavior
sed -n '138,200p' src/whitenoise/accounts/contacts.rs

Length of output: 2259


🏁 Script executed:

#!/bin/bash
# Locate the implementation of fetch_user_key_package to determine if it performs network calls
rg -n "fn fetch_user_key_package" -C 5

Length of output: 620


Avoid network calls in login’s key-package lookup

The fetch_key_package_event_from method in accounts/contacts.rs (lines 138–142) delegates to self.nostr.fetch_user_key_package (see nostr_manager/query.rs at line 149), which issues an actual relay query. This contradicts the TODO and risks slowing down login.

Please:

  • Introduce a local-only lookup (e.g., fetch_cached_key_package_event) that reads from the local cache/DB without outbound network calls.
  • In the login flow (src/whitenoise/accounts/mod.rs:334–340), use this local-only method first.
  • Defer any relay fetch for missing key packages to after login (e.g., background task), so login isn’t blocked by network latency.

Files to update:

  • src/whitenoise/accounts/mod.rs (login logic)
  • src/whitenoise/accounts/contacts.rs (add local-only fetch)
  • src/nostr_manager/query.rs (relay-based fetch for background use)
🤖 Prompt for AI Agents
In src/whitenoise/accounts/mod.rs lines 334-340, replace the current call to
fetch_key_package_event_from, which performs a network relay query, with a new
local-only method fetch_cached_key_package_event that reads from the local cache
or database without network calls. Implement this new local-only fetch method in
src/whitenoise/accounts/contacts.rs to return cached key package events. Modify
src/nostr_manager/query.rs to keep the relay-based fetch method for use in
background tasks after login. Adjust the login flow to use the local-only fetch
first and defer any relay fetches for missing key packages to a background
process to avoid blocking login on network latency.

Copy link
Contributor

@josefinalliende josefinalliende left a comment

Choose a reason for hiding this comment

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

Cool! 🎉 I tested it locally from the 431-relay-management-update branch with the last commit of this PR and I can add local relay and it connects (previously it didn't).

I still initially had no relays, I had to add it manually (for an existing account with data). But I'm not sure if maybe my relay list actually got screwed up and got published as empty so it is correct that now I don't have relays 🤔

After adding a relay, if I close the emulator and open the app again, the added relay appears 🎉

Captura de pantalla 2025-08-07 a la(s) 4 09 31 p m

Copy link
Contributor

@jgmontoya jgmontoya left a comment

Choose a reason for hiding this comment

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

Some comments/questions/suggestions :D

&self,
account: &Account,
relay_type: RelayType,
prior_relays: &Option<DashSet<RelayUrl>>, // If provided, this means at least one relay was removed. We need to publish to the prior relays as well.
Copy link
Contributor

Choose a reason for hiding this comment

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

I can see how this got here as removing a relay is the use case that made this required, however I'd rename it so it's more descriptive of what it does. What do you think about something like 'relays_to_use', or 'target_relays' or something like that? So basically we know that whatever we pass here means we're publishing to those relays.

Copy link
Contributor

@delcin-raj delcin-raj left a comment

Choose a reason for hiding this comment

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

Left some comments.

// Fetch key packages for all members
for pk in members.iter() {
let contact = self.load_contact(pk).await?;
let relays_to_use = if contact.key_package_relays.is_empty() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice catch!

self.setup_subscriptions(&account).await?;

self.publish_key_package_for_account(&account).await?;
// TODO: This should only query local nostr cached events, not fetch from relays
Copy link
Contributor

Choose a reason for hiding this comment

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

Keypackage events are regularly updated. For this alone we have to fetch from the nostr relays, I think we agreed on this earlier.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants