Skip to content

Make resolveAttachmentFiles a suspend function#6321

Merged
VelikovPetar merged 1 commit intov7from
make-resolveAttachmentFiles-suspend
Apr 1, 2026
Merged

Make resolveAttachmentFiles a suspend function#6321
VelikovPetar merged 1 commit intov7from
make-resolveAttachmentFiles-suspend

Conversation

@gpunto
Copy link
Copy Markdown
Contributor

@gpunto gpunto commented Mar 31, 2026

Goal

AttachmentStorageHelper.resolveAttachmentFiles was annotated @WorkerThread but passed around as a suspend lambda, making it look safe to call from any thread. Callers happened to wrap it in withContext(DispatcherProvider.IO), but the responsibility was misplaced.

Implementation

  • Make resolveAttachmentFiles a suspend function that switches to DispatcherProvider.IO internally
  • Remove the @WorkerThread annotation
  • Remove withContext(DispatcherProvider.IO) wrappers from MessageComposerController.sendMessage and enqueueEditMessage
  • Update tests to use runTest / onBlocking

🎨 UI Changes

None

Testing

Existing tests updated and passing

Summary by CodeRabbit

  • Refactor

    • Improved attachment resolution handling in the message composer by converting to asynchronous suspend-based operations. Removed explicit dispatcher switching for cleaner code while maintaining the same behavioral guarantees.
  • Tests

    • Updated test infrastructure to support coroutine testing for attachment resolution workflows.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 31, 2026

PR checklist ✅

All required conditions are satisfied:

  • Title length is OK (or ignored by label).
  • At least one pr: label exists.
  • Sections ### Goal, ### Implementation, and ### Testing are filled.

🎉 Great job! This PR is ready for review.

@gpunto gpunto added the pr:internal Internal changes / housekeeping label Mar 31, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 31, 2026

SDK Size Comparison 📏

SDK Before After Difference Status
stream-chat-android-client 5.25 MB 5.86 MB 0.61 MB 🔴
stream-chat-android-ui-components 10.60 MB 11.17 MB 0.57 MB 🔴
stream-chat-android-compose 12.81 MB 12.41 MB -0.40 MB 🚀

@gpunto gpunto force-pushed the make-resolveAttachmentFiles-suspend branch from db52dd5 to bbc6a54 Compare March 31, 2026 14:28
@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
50.0% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@gpunto gpunto marked this pull request as ready for review April 1, 2026 07:22
@gpunto gpunto requested a review from a team as a code owner April 1, 2026 07:22
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 1, 2026

Walkthrough

This change refactors attachment file resolution from a synchronous blocking function to an asynchronous suspend function. AttachmentStorageHelper.resolveAttachmentFiles now handles IO dispatcher management internally, allowing callers to remove explicit withContext(DispatcherProvider.IO) wrapping. Tests are updated to support coroutine execution context.

Changes

Cohort / File(s) Summary
Async Helper Refactoring
stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/helper/internal/AttachmentStorageHelper.kt
Converted resolveAttachmentFiles from synchronous @WorkerThread function to suspend function with internal withContext(DispatcherProvider.IO) wrapping. Attachment resolution loop semantics preserved; filtering and metadata reconstruction logic unchanged.
Caller Simplification
stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/MessageComposerController.kt
Removed explicit withContext(DispatcherProvider.IO) around resolveAttachments() calls in sendMessage and enqueueEditMessage. Methods now directly call the suspend function within existing coroutine scopes.
Test Infrastructure
stream-chat-android-ui-common/src/test/kotlin/io/getstream/chat/android/ui/common/helper/internal/AttachmentStorageHelperTest.kt, stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/viewmodel/messages/MessageComposerViewModelTest.kt
Added coroutine test extension and runTest blocks to AttachmentStorageHelperTest. Updated MessageComposerViewModelTest.Fixture mock configuration from on { } to onBlocking { } for suspend function compatibility.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 From blocking paths to suspending calls,
The attachments now flow through async halls,
No more explicit dispatchers to wrangle,
Just suspend functions that elegantly dangle,
Cleaner code hops forward with delight! 🚀

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title 'Make resolveAttachmentFiles a suspend function' directly and concisely describes the primary change made in the changeset.
Description check ✅ Passed The pull request description covers the key required sections: Goal explains the problem, Implementation describes the changes, and Testing confirms updates. UI Changes are noted as 'None'. Some optional template sections (screenshots, checklist items) are omitted but not critical.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch make-resolveAttachmentFiles-suspend

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 and usage tips.

Copy link
Copy Markdown

@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.

🧹 Nitpick comments (2)
stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/MessageComposerController.kt (1)

718-722: Clarify resolveAttachments contract in sendMessage KDoc.

Now that caller-side IO wrapping is removed, document that custom resolvers must handle their own dispatcher switching if they do blocking/IO work.

📝 Suggested KDoc addition
 /**
  * Sends a given message using our Stream API. Based on [isInEditMode], we either edit an existing message, or we
  * send a new message, using [ChatClient]. In case the message is a moderated message the old one is deleted before
  * the replacing one is sent.
  *
  * It also dismisses any current message actions.
  *
  * `@param` message The message to send.
+ * `@param` callback Callback invoked with the send/edit result.
+ * `@param` resolveAttachments Optional suspending resolver invoked before send/edit. If it performs
+ * blocking or IO work, it should switch dispatcher internally.
  */

As per coding guidelines: "Document public APIs with KDoc, including thread expectations and state notes".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/MessageComposerController.kt`
around lines 718 - 722, Update the KDoc for the public function sendMessage
(MessageComposerController.sendMessage) to document the contract for the
resolveAttachments suspend parameter: explain that resolveAttachments is invoked
as provided by the caller and must itself handle dispatcher switching if it
performs blocking or IO work (it will not be wrapped by the API), note it is a
suspend function and may be called on the caller thread, and include a short
thread/state expectation sentence so implementers know to use
withContext(Dispatchers.IO) or similar for blocking operations.
stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/helper/internal/AttachmentStorageHelper.kt (1)

92-103: Add explicit threading contract to resolveAttachmentFiles KDoc.

Since dispatching moved inside this public API, document that callers can invoke it from any context and IO is switched internally.

📝 Suggested KDoc tweak
 /**
  * Resolves deferred attachments by copying their source content into local cache files.
  *
  * Attachments that already have a non-null [Attachment.upload] are returned unchanged.
  * For others, the original content URI is read from [EXTRA_SOURCE_URI] and copied to a
  * local cache file. Attachments whose source URI cannot be resolved (e.g. the content
  * URI is no longer accessible or the cache write fails) are **dropped** from the result.
+ *
+ * Threading: Safe to call from any coroutine context. File IO is dispatched internally
+ * to [DispatcherProvider.IO].
  *
  * `@param` attachments The attachments to resolve.
  * `@return` Attachments with [Attachment.upload] populated for every entry that had a source URI.
  */

As per coding guidelines: "Document public APIs with KDoc, including thread expectations and state notes".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/helper/internal/AttachmentStorageHelper.kt`
around lines 92 - 103, The KDoc for resolveAttachmentFiles lacks an explicit
threading contract; update the public KDoc for the resolveAttachmentFiles
function to state callers may invoke it from any coroutine context and that the
function internally switches to the IO dispatcher for blocking/IO work (so
callers don't need to dispatch themselves), and include a short state note that
attachments with missing/unresolvable source URIs are dropped; reference
resolveAttachmentFiles and mention the internal IO dispatch behavior in that
KDoc.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/MessageComposerController.kt`:
- Around line 718-722: Update the KDoc for the public function sendMessage
(MessageComposerController.sendMessage) to document the contract for the
resolveAttachments suspend parameter: explain that resolveAttachments is invoked
as provided by the caller and must itself handle dispatcher switching if it
performs blocking or IO work (it will not be wrapped by the API), note it is a
suspend function and may be called on the caller thread, and include a short
thread/state expectation sentence so implementers know to use
withContext(Dispatchers.IO) or similar for blocking operations.

In
`@stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/helper/internal/AttachmentStorageHelper.kt`:
- Around line 92-103: The KDoc for resolveAttachmentFiles lacks an explicit
threading contract; update the public KDoc for the resolveAttachmentFiles
function to state callers may invoke it from any coroutine context and that the
function internally switches to the IO dispatcher for blocking/IO work (so
callers don't need to dispatch themselves), and include a short state note that
attachments with missing/unresolvable source URIs are dropped; reference
resolveAttachmentFiles and mention the internal IO dispatch behavior in that
KDoc.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 92f77cf3-9021-4bf9-b533-2760eba380fd

📥 Commits

Reviewing files that changed from the base of the PR and between 02c8e65 and bbc6a54.

📒 Files selected for processing (4)
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/viewmodel/messages/MessageComposerViewModelTest.kt
  • stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/MessageComposerController.kt
  • stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/helper/internal/AttachmentStorageHelper.kt
  • stream-chat-android-ui-common/src/test/kotlin/io/getstream/chat/android/ui/common/helper/internal/AttachmentStorageHelperTest.kt

@VelikovPetar VelikovPetar merged commit 9ce7d4f into v7 Apr 1, 2026
15 of 16 checks passed
@VelikovPetar VelikovPetar deleted the make-resolveAttachmentFiles-suspend branch April 1, 2026 14:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:internal Internal changes / housekeeping

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants