Skip to content

Accept friend requests reactively via social RTA subscription - #13

Merged
HashimTheArab merged 12 commits into
mainfrom
feat/reactive-friend-requests
Sep 11, 2026
Merged

HashimTheArab merged 12 commits into
mainfrom
feat/reactive-friend-requests

Conversation

@HashimTheArab

@HashimTheArab HashimTheArab commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Friend requests currently wait for the polling interval. Subscribe to each enabled account's Social RTA events so changes can request an earlier sync using the Xbox client's existing WebSocket.

All sync passes share a schedule with at least 20 seconds between completed passes. Events during that gap stay pending and coalesce into one pass. Polling and expiry use the same schedule, so they cannot cause back-to-back scans. A completed scan also resets the polling deadline.

Friend-list reads honor Retry-After, including failures while fetching pending requests. A throttled pending-list read stops the remaining reads in that pass. Throttled reads retry when the delay expires, even without another event. HTTP 429 responses without a usable delay fall back to 20 seconds. Follow and unfollow keep their separate backoff.

Subscription setup stays off the startup path and has a 15-second timeout, so a missing RTA acknowledgment cannot hold the shared subscription lock indefinitely. Polling continues if setup fails. Shutdown waits for removal of only the broadcaster's own registration, preserving other subscribers sharing the Xbox client.

This builds on merged #28 and pins merged go-xsapi lunar commit 5e753424fe8d, which supplies the registration cleanup function.

Validation:

  • go test -race ./... -count=1 and go vet ./... pass.
  • Regression tests fail against the prior scheduler and pass with the fix. They cover all three read-throttling paths, burst coalescing, delayed scans, automatic retries, expiry, and cancellation using a virtual clock and the real HTTP error parser.
  • The existing local WebSocket integration test verifies that broadcaster shutdown preserves another shared-client subscriber.
  • A setup-timeout regression verifies that an unacknowledged subscription ends after 15 seconds while the broadcaster stays running.
  • codex review --base origin/main with gpt-6-astra at high found an unbounded setup handshake. That finding is fixed; the second full review of 5b3e079 reports no actionable regressions and passed its full and focused test runs.

No live Xbox testing was performed.

Summary by CodeRabbit

  • New Features

    • Added independent support for sub-account sessions, including recovery, health tracking, and cleanup.
    • Added relay-aware listening, gallery uploads, social API access, and invite validation for supported accounts.
    • Friend synchronization can now respond promptly to social activity while retaining scheduled syncing.
  • Bug Fixes

    • Improved session startup, shutdown, failure recovery, duplicate handling, and subscription cleanup.
    • Friend synchronization now handles rate limits, retries, and overlapping triggers more reliably.
  • Tests

    • Expanded coverage for social subscriptions, session lifecycle behavior, synchronization triggers, cleanup, and rate limiting.

Friend sync accepted incoming friend requests only on the poll interval, so a
new request waited up to one UpdateInterval to be accepted. Java MCXboxBroadcast
accepts them immediately off an RTA social subscription
(IncomingFriendRequestCountChanged -> acceptPendingFriendRequests).

Subscribe to each account's go-xsapi/v2 social RTA feed and feed its events into
the existing sync loop through a new FriendSyncer.Trigger channel, so an
incoming friend request (or any relationship change) runs an immediate sync pass
in the same goroutine that owns the rate-limit state. Events are coalesced
(non-blocking send to a size-1 channel). The subscription is best-effort: the
periodic syncer remains the backstop, the RTA connection re-subscribes after
transient drops, and a nil Trigger keeps a syncer purely periodic.

Closes #12.
@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_10960a4f-131c-478d-bf55-13a9f8a8c6f7)

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 87bd8a03-ad04-4062-851d-8e30cf0b0a31

📥 Commits

Reviewing files that changed from the base of the PR and between 5d5e73c and 5b3e079.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (5)
  • friend_sync.go
  • friend_sync_rate_test.go
  • go.mod
  • social_subscription.go
  • social_subscription_test.go

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The change adds independent sub-account sessions, relay-aware broadcaster lifecycle handling, and social RTA-triggered friend synchronization. Friend sync now supports immediate triggers, read backoff scheduling, and coordinated subscription cleanup.

Changes

Broadcaster session lifecycle and reactive friend sync

Layer / File(s) Summary
Independent session and account lifecycle
broadcaster.go
Broadcaster startup, sub-account publication, relay handling, presence, invites, gallery uploads, health tracking, recovery, cleanup, and Wait now support independent account sessions.
Friend sync execution and rate handling
friend_sync.go, friend_sync_rate_test.go
Friend sync uses trigger-driven scheduling, read-quota backoff, minimum intervals, retry passes, and coalesced polling and expiry work.
Social subscription trigger flow
social_subscription.go, go.mod
Social subscriptions return per-registration cleanup functions. Social events produce coalesced friend-sync triggers. Reactive sync applies when auto-follow or auto-unfollow is enabled.
Broadcaster sync wiring and shutdown
broadcaster.go
Primary and sub-account syncers receive social triggers. Broadcaster shutdown waits for subscription cleanup before closing related resources.
Subscription and lifecycle validation
social_subscription_test.go, social_subscription_integration_test.go
Tests cover trigger behavior, event coalescing, bounded setup, cleanup, mutation backoff, polling fallback, and shared social-client subscriptions.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~60 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant SocialRTA
  participant Broadcaster
  participant FriendSyncer
  participant XboxSocialAPI
  SocialRTA->>Broadcaster: deliver friend event
  Broadcaster->>FriendSyncer: signal Trigger
  FriendSyncer->>XboxSocialAPI: run immediate friend sync
  Broadcaster->>SocialRTA: clean up subscription on shutdown
Loading

Merge Risk: ⚪ Minimal · up to 5b3e0

Reactive friend synchronization retains polling fallback, respects read backoff, and cleans up registrations without disrupting shared social clients. No unresolved merge-blocking risk was identified.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 18 functions across 6 files. (1 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the primary change: reactive friend-request handling through Social RTA subscriptions.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 18 functions across 6 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/reactive-friend-requests

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

Comment @coderabbitai help to get the list of available commands.

The social subscription created for reactive friend sync was never released.
b.ctx only scopes the subscribe handshake; once subscribed, go-xsapi keeps the
subscription active and appends a handler on each later Subscribe. A library
caller that reuses an external xsapi.Client across broadcaster restarts would
accumulate stale handlers, and events would keep dispatching after the syncer
stopped (Close only closes clients the broadcaster created itself).

Bind each subscription's lifetime to the broadcaster: a dedicated goroutine
unsubscribes once b.ctx is canceled, and Close waits on socialWg so the
subscriptions are undone before it returns. A reused client is left clean, so a
subsequent broadcaster re-subscribes without duplicating handlers.
@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_caa1aad2-6d61-4f4a-b7d8-465aa061634b)

A closed Trigger would receive forever, spinning Run through runSync and
bypassing UpdateInterval. Use a two-value receive and nil the channel out when
it is closed so the case stops firing.
@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_26fb78ff-a3f5-48bc-97ba-ecc8731d1370)

@HashimTheArab

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

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.

Closing one broadcaster called social CloseContext, which unsubscribes the
shared RTA subscription and clears every handler on the client. That could
disable other Social().Subscribe users on a shared xsapi.Client.

Use the new go-xsapi social Client.Unsubscribe(ctx, handler) to remove only the
broadcaster's own handler; the RTA subscription is torn down only when its last
handler is gone. Bumps the go-xsapi replace to the commit that adds Unsubscribe.

Depends on HashimTheArab/go-xsapi#20; the replace pins that branch commit and
should be re-pinned to lunar once it merges.
@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_5c691dae-ff5c-4292-a0d0-423cdc2e51d3)

@HashimTheArab
HashimTheArab changed the base branch from main to agent/xsapi-owned-clients September 11, 2026 07:52
Base automatically changed from agent/xsapi-owned-clients to main September 11, 2026 07:54
@HashimTheArab

Copy link
Copy Markdown
Owner Author

cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit c907b9e. Configure here.

Comment thread broadcaster.go
@HashimTheArab
HashimTheArab merged commit 9a169c9 into main Sep 11, 2026
1 check passed
@HashimTheArab
HashimTheArab deleted the feat/reactive-friend-requests branch September 11, 2026 10:16
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.

1 participant