Skip to content

feat(media): high-level media message builders from UploadResponse - #764

Merged
jlucaso1 merged 2 commits into
mainfrom
feat/media-message-builders
Jun 8, 2026
Merged

feat(media): high-level media message builders from UploadResponse#764
jlucaso1 merged 2 commits into
mainfrom
feat/media-message-builders

Conversation

@jlucaso1

@jlucaso1 jlucaso1 commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator

Closes the api-29 gap.

Sending media meant hand-assembling the proto — image_message: Some(Box::new(ImageMessage { url, direct_path, media_key, file_sha256, file_enc_sha256, file_length, ... })) — with the CDN/crypto fields spread across every call site (and Status::send_image/send_video each duplicated ~9 of those assignments).

Adds a media module with image_message / video_message / document_message / audio_message builders that take an UploadResponse plus a typed options struct and fill the CDN fields in one place — including media_key_timestamp and, for video/audio, the streaming_sidecar from the upload. Mirrors WA Web's send-media path, which builds the proto from the upload result internally.

Status::send_image/send_video are refactored to use the builders (so they now also propagate media_key_timestamp + the streaming sidecar, which they previously dropped), and the now-unused UploadResponse::media_key_vec/file_sha256_vec/file_enc_sha256_vec adapters are deleted.

Usage:

let upload = client.upload(&bytes, "image/jpeg").await?;
let msg = media::image_message(upload, ImageOptions { caption: Some("hi".into()), ..Default::default() });
client.send_message(to, msg).await?;

Builders are pure functions (no client needed), so they're trivially testable. Tests cover the CDN-field mapping, mimetype defaulting, the sidecar carry-through, and the type-specific options for all four media types.

Scope note: the builder lives in the high-level crate (not wacore::proto_helpers as the finding suggested) because UploadResponse is defined there; wacore can't depend on it.

Sending media required hand-assembling the proto (image_message: Some(Box::new(
ImageMessage { url, direct_path, media_key, file_sha256, file_enc_sha256,
file_length, ... })) ) with the CDN/crypto fields spread across the call site.

Add a media module with image_message / video_message / document_message /
audio_message builders that take an UploadResponse plus a typed options struct and
fill the CDN fields (incl. media_key_timestamp, and streaming_sidecar for
video/audio) in one place. Mirrors WA Web's send-media path, which builds the proto
from the upload result internally.

Refactor Status::send_image/send_video to use the builders (also propagating
media_key_timestamp + the streaming sidecar, which they previously dropped) and
delete the now-unused UploadResponse::*_vec adapters.

Tests: each builder maps the CDN fields, defaults the mimetype, and carries the
sidecar/type-specific options.
@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8fec471c-a1f2-4eec-8c07-d3516f440fc4

📥 Commits

Reviewing files that changed from the base of the PR and between edb4373 and db0fb23.

📒 Files selected for processing (1)
  • src/media.rs

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added high-level media message builders for images, videos, documents, and audio with options for captions, JPEG thumbnails, MIME types, duration, GIF playback, document metadata, and audio waveforms.
  • Breaking Changes

    • Removed public utility methods that returned byte-array copies from upload response objects; callers must adapt accordingly.

Walkthrough

This PR adds a public media module with typed option structs and builder functions to convert UploadResponsewa::Message for images, videos, documents, and audio. Status::send_image/send_video now use these builders. Three UploadResponse Vec-conversion helpers were removed.

Changes

Media Message Builders

Layer / File(s) Summary
Media builder API and types
src/lib.rs, src/media.rs
Exports media module and defines ImageOptions, VideoOptions, DocumentOptions, AudioOptions. Implements image_message, video_message, document_message, audio_message that map UploadResponse fields (CDN URLs, paths, media keys, hashes, lengths, streaming_sidecar) and options (captions, thumbnails, duration, gif_playback, document/audio metadata) into wa::Message. Includes unit tests for mappings and defaults.
Status image/video refactoring
src/features/status.rs
Replaces manual wa::Message.image_message/video_message construction with calls to crate::media::image_message / crate::media::video_message, passing typed options (caption as String when present, jpeg thumbnail bytes, duration, gif_playback) and relying on builders for mimetype defaults and sidecar propagation.
Upload response helper removal
src/upload.rs
Removes UploadResponse methods media_key_vec, file_sha256_vec, and file_enc_sha256_vec that produced Vec<u8> copies of crypto fields.

Sequence Diagram(s)

sequenceDiagram
  participant Status
  participant UploadResponse
  participant image_message
  participant video_message
  participant wa_Message
  Status->>UploadResponse: supply upload metadata (url, path, keys, hashes, length, sidecar)
  Status->>image_message: call with ImageOptions (caption, jpeg_thumbnail)
  image_message->>wa_Message: build ImageMessage with CDN/crypto fields, caption, mimetype default
  Status->>video_message: call with VideoOptions (caption, jpeg_thumbnail, duration, gif_playback)
  video_message->>wa_Message: build VideoMessage with streaming_sidecar, seconds, gif_playback, CDN/crypto fields
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

You should review the media builders first, then the status call sites, then the upload helper removal.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately captures the main objective: introducing high-level media message builders that construct messages from UploadResponse objects.
Description check ✅ Passed The description clearly explains the problem being solved, the solution approach, usage examples, and implementation details—all directly relevant to the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/media-message-builders

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.

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

Benchmark Results

67 unchanged benchmark(s)
Benchmark Current Baseline Change
reporting_token_benchmark::content_extraction_group::bench_content_extraction simple:setup_simple_message() 2,925 2,925 +0.0%
reporting_token_benchmark::content_extraction_group::bench_content_extraction extended:setup_extended_message() 8,446 8,446 +0.0%
reporting_token_benchmark::key_derivation_group::bench_key_derivation 31,317 31,317 +0.0%
reporting_token_benchmark::token_calculation_group::bench_token_calculation 13,827 13,827 +0.0%
reporting_token_benchmark::full_generation_group::bench_full_token_generation simple:setup_full_gen_simple() 49,485 49,485 +0.0%
reporting_token_benchmark::full_generation_group::bench_full_token_generation extended:setup_full_gen_extended() 55,001 55,001 +0.0%
reporting_token_benchmark::message_encoding_group::bench_message_encoding simple:setup_simple_message() 1,679 1,679 +0.0%
reporting_token_benchmark::message_encoding_group::bench_message_encoding extended:setup_extended_message() 4,393 4,393 +0.0%
send_receive_benchmark::dm_send::bench_dm_send text:setup_dm_send() 113,073 113,210 -0.1%
send_receive_benchmark::dm_recv::bench_dm_recv text:setup_dm_recv() 1,656,622 1,656,618 +0.0%
send_receive_benchmark::group_send::bench_group_send group_10:setup_group_send_10() 651,742 651,762 -0.0%
send_receive_benchmark::group_send::bench_group_send group_50:setup_group_send_50() 875,820 875,811 +0.0%
send_receive_benchmark::group_send::bench_group_send group_256:setup_group_send_256() 2,083,581 2,083,614 -0.0%
send_receive_benchmark::group_send_skdm::bench_group_send_skdm skdm_10:setup_group_skdm_10() 748,299 749,074 -0.1%
send_receive_benchmark::group_send_skdm::bench_group_send_skdm skdm_50:setup_group_skdm_50() 1,329,635 1,329,631 +0.0%
send_receive_benchmark::group_send_skdm::bench_group_send_skdm skdm_256:setup_group_skdm_256() 4,378,906 4,375,531 +0.1%
send_receive_benchmark::group_recv::bench_group_recv text:setup_group_recv() 518,286 520,574 -0.4%
binary_benchmark::marshal_group::bench_marshal_allocating 45,381 45,381 +0.0%
binary_benchmark::marshal_group::bench_marshal_auto_allocating 45,431 45,431 +0.0%
binary_benchmark::marshal_group::bench_marshal_exact_allocating 66,334 66,334 +0.0%
binary_benchmark::marshal_group::bench_marshal_reusing_buffer 43,492 43,492 +0.0%
binary_benchmark::marshal_group::bench_marshal_reusing_buffer_vec_writer 45,487 45,487 +0.0%
binary_benchmark::marshal_group::bench_marshal_long_string 4,945 4,945 +0.0%
binary_benchmark::marshal_group::bench_marshal_auto_long_string 4,976 4,976 +0.0%
binary_benchmark::marshal_group::bench_marshal_exact_long_string 6,747 6,747 +0.0%
binary_benchmark::marshal_group::bench_marshal_huge_bytes_allocating 528,544 528,544 +0.0%
binary_benchmark::marshal_group::bench_marshal_auto_huge_bytes_allocating 528,165 528,165 +0.0%
binary_benchmark::marshal_group::bench_marshal_exact_huge_bytes_allocating 529,411 529,411 +0.0%
binary_benchmark::marshal_group::bench_marshal_many_children_allocating 5,417,732 5,417,732 +0.0%
binary_benchmark::marshal_group::bench_marshal_auto_many_children_allocating 5,362,047 5,362,047 +0.0%
binary_benchmark::marshal_group::bench_marshal_exact_many_children_allocating 13,276,365 13,276,365 +0.0%
binary_benchmark::unmarshal_group::bench_unmarshal small:setup_small_marshaled() 1,850 1,850 +0.0%
binary_benchmark::unmarshal_group::bench_unmarshal large:setup_large_marshaled() 29,217 29,217 +0.0%
binary_benchmark::unpack_group::bench_unpack_uncompressed 618 618 +0.0%
binary_benchmark::unpack_group::bench_unpack_compressed 672,890 672,890 +0.0%
binary_benchmark::attr_parser_group::bench_attr_parser attr_lookup:setup_attr_marshaled() 3,736 3,736 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip small:setup_small_marshaled() 3,840 3,840 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip large:setup_large_marshaled() 48,274 48,274 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip_auto small:setup_small_marshaled() 3,866 3,866 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip_auto large:setup_large_marshaled() 48,335 48,335 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip_exact small:setup_small_marshaled() 5,206 5,206 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip_exact large:setup_large_marshaled() 66,659 66,659 +0.0%
binary_benchmark::child_iteration_group::bench_get_children_by_tag 310,312 310,312 +0.0%
binary_benchmark::jid_optimization_group::bench_jid_to_owned_access jid_access:setup_jid_heavy_marshaled() 8,291 8,291 +0.0%
numeric_attr_benchmark::bench_group::bench_baseline_u32 254 254 +0.0%
numeric_attr_benchmark::bench_group::bench_proposed_u32 91 91 +0.0%
numeric_attr_benchmark::bench_group::bench_baseline_u64 292 292 +0.0%
numeric_attr_benchmark::bench_group::bench_proposed_u64 137 137 +0.0%
numeric_attr_benchmark::bench_group::bench_baseline_i64 317 317 +0.0%
numeric_attr_benchmark::bench_group::bench_proposed_i64 145 145 +0.0%
numeric_attr_benchmark::bench_group::bench_baseline_loop_100_u64 27,425 27,425 +0.0%
numeric_attr_benchmark::bench_group::bench_proposed_loop_100_u64 10,725 10,725 +0.0%
libsignal_benchmark::dm_group::bench_dm_session_establishment setup:setup_dm_users() 4,142,765 4,138,532 +0.1%
libsignal_benchmark::dm_group::bench_dm_encrypt_first_message first_msg:setup_dm_session() 100,133 100,133 +0.0%
libsignal_benchmark::dm_group::bench_dm_decrypt_first_message decrypt_prekey:setup_dm_with_first_message() 4,264,189 4,264,189 +0.0%
libsignal_benchmark::dm_group::bench_dm_encrypt_subsequent_message subsequent:setup_established_dm_session() 100,399 100,399 +0.0%
libsignal_benchmark::group_messaging_group::bench_group_create_distribution_message create:setup_group_sender() 210,262 210,262 +0.0%
libsignal_benchmark::group_messaging_group::bench_group_encrypt_message encrypt:setup_group_with_distribution() 496,908 496,921 -0.0%
libsignal_benchmark::group_messaging_group::bench_group_decrypt_message decrypt:setup_group_with_encrypted_message() 509,739 506,906 +0.6%
libsignal_benchmark::conversation_group::bench_full_dm_conversation full:setup_conversation_data() 11,978,008 11,979,068 -0.0%
libsignal_benchmark::signature_group::bench_signature_creation sign:setup_keypair_with_message() 2,466,138 2,466,138 +0.0%
libsignal_benchmark::signature_group::bench_signature_verification verify:setup_keypair_with_message() 4,938,562 4,899,632 +0.8%
libsignal_benchmark::signature_group::bench_key_generation keygen 2,043,397 2,043,397 +0.0%
libsignal_benchmark::session_optimization_group::bench_decrypt_with_previous_session previous_session:setup_with_archived_sessions() 37,404 37,414 -0.0%
libsignal_benchmark::session_optimization_group::bench_out_of_order_decryption out_of_order:setup_out_of_order_messages() 3,617,967 3,617,967 +0.0%
libsignal_benchmark::session_optimization_group::bench_promote_matching_session promote:setup_promote_matching_session() 230,658 230,648 +0.0%
libsignal_benchmark::session_optimization_group::bench_message_key_eviction eviction:setup_message_key_eviction() 9,980,959 9,980,959 +0.0%
No significant changes detected.

The example called client.upload(&bytes, "image/jpeg") but upload takes
(Vec<u8>, MediaType, UploadOptions), so the no_run doctest failed to compile and
broke Build & Test (which runs doctests; the --all-targets/--lib jobs skip them).
Replace it with a minimal builder-only example that doesn't depend on the
upload/send signatures.

@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: edb43737c3

ℹ️ 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".

Comment thread src/media.rs Outdated
@jlucaso1
jlucaso1 merged commit 2239ee8 into main Jun 8, 2026
12 checks passed
@jlucaso1
jlucaso1 deleted the feat/media-message-builders branch June 8, 2026 14:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant