Skip to content

refactor(api): robust websocket URL construction#1560

Open
RinZ27 wants to merge 1 commit into
tinyhumansai:mainfrom
RinZ27:refactor/robust-websocket-url
Open

refactor(api): robust websocket URL construction#1560
RinZ27 wants to merge 1 commit into
tinyhumansai:mainfrom
RinZ27:refactor/robust-websocket-url

Conversation

@RinZ27
Copy link
Copy Markdown

@RinZ27 RinZ27 commented May 12, 2026

Refactors the websocket_url construction logic to use the url crate instead of manual string manipulation. Currently, the implementation relies on replacen and trim_end_matches, which can lead to fragile URL building if the input base URL has unexpected formatting or multiple trailing slashes.

Transitioning to a proper URL parser ensures that protocol switching (HTTP/HTTPS to WS/WSS) is handled robustly and that path segments are normalized correctly. This change enhances the reliability of the background WebSocket loop when connecting to the TinyHumans backend.

Verified the new implementation against existing unit tests. All tests for protocol conversion and trailing slash normalization passed successfully.

Summary by CodeRabbit

  • Bug Fixes
    • Enhanced WebSocket URL handling to improve connection reliability and ensure proper scheme mapping for Socket.IO connections.

Review Change Stack

@RinZ27 RinZ27 requested a review from a team May 12, 2026 13:59
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 12, 2026

📝 Walkthrough

Walkthrough

The websocket_url function in src/api/socket.rs is refactored to use url::Url parsing for building Socket.IO websocket URLs. It now properly maps HTTP(S) schemes to their websocket equivalents, rewrites paths to /socket.io/, and sets the required query parameters, with graceful fallback to returning the input unchanged on parse failure.

Changes

WebSocket URL Construction

Layer / File(s) Summary
WebSocket URL parsing with scheme mapping
src/api/socket.rs
The websocket_url function replaces manual string manipulation with url::Url parsing. Scheme mapping converts https to wss and http to ws, path is rewritten to end with /socket.io/, and query string is set to EIO=4&transport=websocket. Parse failures return the input unchanged. Unit tests validate all conversion cases.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A socket needs parsing, not string-chop despair,
With Url::parse, the scheme flows with care,
wss and ws dance in their proper place,
The query string settles with EIO=4 grace,
One function, now cleaner, Socket.IO's embrace!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: refactoring websocket URL construction to be more robust using proper URL parsing instead of string manipulation.
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.


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

🧹 Nitpick comments (1)
src/api/socket.rs (1)

7-9: ⚡ Quick win

Add trace/debug logging on URL parse fallback path.

Line 7 silently returns the raw input on parse failure; add a grep-friendly debug/trace log (e.g., [api]) with error context so WS misconfiguration is diagnosable.

As per coding guidelines, "Use log / tracing at debug / trace level; include stable grep-friendly prefixes ([domain], [rpc])..." and "Add copious debug/trace logs while implementing features..."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/socket.rs` around lines 7 - 9, Replace the silent parse-fallback with
a logged fallback: instead of discarding the parse Err inside the current let
Ok(...) else { return ... } construct, capture the parse error (via match or if
let Err(e) = Url::parse(http_or_https_base)) and emit a debug/trace log using
the project logging facade (log or tracing) with a grep-friendly prefix like
"[api]" that includes the raw http_or_https_base and the parse error, then
return http_or_https_base.to_string(); reference Url::parse and the
http_or_https_base variable when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/api/socket.rs`:
- Around line 7-9: Replace the silent parse-fallback with a logged fallback:
instead of discarding the parse Err inside the current let Ok(...) else { return
... } construct, capture the parse error (via match or if let Err(e) =
Url::parse(http_or_https_base)) and emit a debug/trace log using the project
logging facade (log or tracing) with a grep-friendly prefix like "[api]" that
includes the raw http_or_https_base and the parse error, then return
http_or_https_base.to_string(); reference Url::parse and the http_or_https_base
variable when making the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ac02d834-a2fd-40f0-b204-90bb21ecb5e3

📥 Commits

Reviewing files that changed from the base of the PR and between 15c7442 and a239e0f.

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

@senamakel
Copy link
Copy Markdown
Member

looks great merging shortly dude...

Copy link
Copy Markdown
Contributor

@graycyrus graycyrus left a comment

Choose a reason for hiding this comment

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

Approve with minor nits. Clean, well-scoped refactor — url::Url parsing is a clear improvement over manual string manipulation. All existing tests pass. A few minor observations inline below. None are blocking.

Comment thread src/api/socket.rs
} else {
base.to_string()
let Ok(mut url) = Url::parse(http_or_https_base) else {
return http_or_https_base.to_string();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[minor] Silent fallback on parse failure — CodeRabbit already flagged this, so just +1: a debug!("[api] websocket_url parse failed for {}: {}", http_or_https_base, e) before returning would make misconfiguration diagnosable per project logging guidelines.

Comment thread src/api/socket.rs
"http" => "ws",
other => other,
}
.to_string();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[minor] set_scheme error discardedUrl::set_scheme returns Err(()) if the new scheme is invalid or the URL has an opaque path. In practice "ws"/"wss" are always valid for a parsed HTTP(S) URL, so this is safe — but a trace! on failure would be defensive:

if url.set_scheme(&scheme).is_err() {
    trace!("[api] websocket_url: failed to set scheme to {scheme} for {http_or_https_base}");
}

Comment thread src/api/socket.rs
let scheme = match url.scheme() {
"https" => "wss",
"http" => "ws",
other => other,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[nit] Unnecessary allocation.to_string() allocates a String just for set_scheme which takes &str. You can keep it as &str:

let scheme = match url.scheme() {
    "https" => "wss",
    "http" => "ws",
    other => other,
};

No functional difference, just avoids a small alloc.

Comment thread src/api/socket.rs
};
format!("{}/socket.io/?EIO=4&transport=websocket", ws_base)

let scheme = match url.scheme() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[minor] Consider an idempotency test — if someone passes an already-websocket URL (wss://...), the other => other branch keeps it as-is, which is good. Worth adding a test to lock that in:

#[test]
fn handles_wss_input_directly() {
    let url = websocket_url("wss://api.tinyhumans.ai");
    assert_eq!(url, "wss://api.tinyhumans.ai/socket.io/?EIO=4&transport=websocket");
}

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.

3 participants