Skip to content

perf: run media sanitizing and file crypto off the main isolate - #703

Merged
grunch merged 2 commits into
mainfrom
perf/media-crypto-off-main-isolate
Aug 31, 2026
Merged

perf: run media sanitizing and file crypto off the main isolate#703
grunch merged 2 commits into
mainfrom
perf/media-crypto-off-main-isolate

Conversation

@grunch

@grunch grunch commented Aug 31, 2026

Copy link
Copy Markdown
Member

Summary

Item 3.5 of the performance plan. Three CPU-heavy media paths ran on the UI isolate:

  • Image sanitizing (package:image, pure Dart): decode + re-encode of a 12 MP photo takes 1–5 s, per image sent (media_validation_service.dart).
  • Whole-file ChaCha20-Poly1305 (pointycastle, files up to 25 MB): per media send, per download, and per history auto-download (encryption_service.dart).
  • Macro-pattern scan (O(n·m) over the whole file) in document validation.

Changes

  • validateAndSanitizeImage / validateAndSanitizeImageLight keep their public signatures but execute through Isolate.run (byte buffers and MediaValidationResult/exceptions transfer across the boundary; propagation pinned by test).
  • EncryptionService.encryptToBlobAsync / decryptFromBlobAsync: Isolate.run over the existing sync implementations (which stay for callers that need them and for the isolate itself). The encrypted image/file upload services now use the async variants in both directions.
  • The macro scan runs through Isolate.run at both call sites.

Left for 3.4 (worker isolate): per-message NIP-44/Schnorr work — batching those into a long-lived worker is the remaining phase-3 item, done after the caches (#700, #701, #702) so the isolate doesn't inherit redundant work.

Test plan

  • New test/services/media_crypto_isolate_test.dart (RED on main): async blob roundtrip + cross-compat with sync, tampered-blob failure across the isolate, PNG light/heavy sanitize results, garbage-input error propagation
  • file_messaging_test.dart + chat suites — green
  • Full flutter test — all green
  • flutter analyze — no new issues
  • Manual: send a large photo in chat — UI stays responsive during sanitize+encrypt; open received media — decrypts correctly

🤖 Generated with Claude Code

https://claude.ai/code/session_018fTxqxhpdL5siTgKZqwtur

Image sanitizing uses package:image (pure Dart): decode + re-encode of a
phone photo takes seconds, and it ran on the UI isolate for every image
sent. Whole-file ChaCha20-Poly1305 (pointycastle, up to 25 MB) ran there
too for every media send, download and history auto-download, as did the
O(n*m) macro-pattern scan over document bytes.

- MediaValidationService.validateAndSanitizeImage / ...Light keep their
  signatures but execute through Isolate.run.
- EncryptionService gains encryptToBlobAsync / decryptFromBlobAsync
  (Isolate.run over the existing sync implementations); the encrypted
  image/file upload services use them for both directions.
- FileValidationService's macro scan runs through Isolate.run.

Byte buffers and simple exception objects transfer across the isolate
boundary; error propagation is pinned by test.
@coderabbitai

coderabbitai Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

Next included review available in 25 minutes.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4926df94-3ec3-47ff-9d27-14e899aafbfd

📥 Commits

Reviewing files that changed from the base of the PR and between 473a1e9 and 63b4eba.

📒 Files selected for processing (6)
  • lib/services/encrypted_file_upload_service.dart
  • lib/services/encrypted_image_upload_service.dart
  • lib/services/encryption_service.dart
  • lib/services/file_validation_service.dart
  • lib/services/media_validation_service.dart
  • test/services/media_crypto_isolate_test.dart

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.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-31T00:35:03.349081Z 03032dc PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 03032dcd66

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


// 2. Encrypt with ChaCha20-Poly1305
final encryptionResult = EncryptionService.encryptChaCha20Poly1305(
final encryptedBlob = await EncryptionService.encryptToBlobAsync(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve the file nonce after switching encryption APIs

This replacement removes the only declaration of encryptionResult, but the result construction below still evaluates _bytesToHex(encryptionResult.nonce). Any build that includes this service therefore fails with an undefined identifier, preventing encrypted file uploads from compiling; derive the nonce from the blob prefix or return it alongside the blob from the async API.

Useful? React with 👍 / 👎.


// 3. Encrypt with ChaCha20-Poly1305
final encryptionResult = EncryptionService.encryptChaCha20Poly1305(
final encryptedBlob = await EncryptionService.encryptToBlobAsync(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve the image nonce after switching encryption APIs

This replacement likewise eliminates encryptionResult, while EncryptedImageUploadResult is still initialized with _bytesToHex(encryptionResult.nonce) below. Consequently, targets containing this service cannot compile and encrypted-image uploads are unavailable; extract the nonce from encryptedBlob or expose it from the asynchronous encryption operation.

Useful? React with 👍 / 👎.

@Catrya Catrya left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

tACK

@grunch
grunch merged commit 65a5801 into main Aug 31, 2026
2 checks passed
@grunch
grunch deleted the perf/media-crypto-off-main-isolate branch August 31, 2026 20:53
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.

2 participants