Skip to content

feat(file-transfer): add host file offers - #737

Open
qiin2333 wants to merge 3 commits into
masterfrom
codex/file-transfer-context-menu
Open

feat(file-transfer): add host file offers#737
qiin2333 wants to merge 3 commits into
masterfrom
codex/file-transfer-context-menu

Conversation

@qiin2333

@qiin2333 qiin2333 commented Jun 20, 2026

Copy link
Copy Markdown
Collaborator

改了啥呀

  • 新增短期 file-transfer offer store,主机只登记本地文件路径和 10 分钟 token,不把文件内容塞进控制帧。
  • 新增本机 offer 创建接口和 paired-client 下载接口:/api/v1/file-transfer/offers 创建 offer,/api/v1/file-transfer/<id> 下载文件。
  • 下载端挂到 nvhttp,让已配对客户端走现有 HTTPS/mTLS 通道拉文件。
  • 新增 file_transfer 配置开关、CMake 源文件列表和单测覆盖。
  • 更新 sunshine-control-panel 子模块到 feat(file-transfer): add send-to-client shell entry qiin2333/sunshine-control-panel#44 的分支提交,让 Explorer 右键菜单能发送 offer。
  • 同步最新 master,解决子模块 gitlink 冲突。

为啥要改

  • 右键一键传文件需要“控制消息”和“文件字节”分离:剪贴板同步只负责告诉客户端有文件,真正内容走可认证的 HTTPS 下载。这样大文件不会把剪贴板/控制包撑爆,杂鱼大文件别想卡住控制通道。

验证

  • cargo check in src_assets/common/sunshine-control-panel/src-tauri
  • git diff --check in Sunshine and control-panel
  • git diff --check HEAD~1 HEAD in sync temp clones for Sunshine, control-panel, and moonlight-qt
  • cmake --build build --target sunshine 当前本机失败在 MSYS2 cc.exe/c++.exe,第三方 C 文件和既有 C++ 文件均无诊断返回 1;最小 int main(){return 0;} 也同样失败,判断为本机工具链状态问题,不是新增文件专属错误。

@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

新增主机到客户端文件传输能力:包含内存 offer 存储、HTTP 响应与路由、配置开关、confighttp/nvhttp 入口接入、构建集成和单元测试;同时更新了控制面板子模块指针。

Changes

文件传输功能实现

Layer / File(s) Summary
Offer 存储层 API 与实现
src/file_transfer_store.h, src/file_transfer_store.cpp
定义 offer 数据结构与 TTL/大小常量;实现基于全局互斥锁的内存存储,包含随机 ID 生成、过期清理、路径 canonical 化与 UTF-8 转换,以及创建、查询、清理和统计接口。
HTTP 响应类型与处理实现
src/file_transfer_http.h, src/file_transfer_http.cpp
定义 HTTP 响应承载类型、请求/响应别名与鉴权回调;实现文件路径编码、ID 校验、offer/download 响应工厂、请求处理模板和下载响应写回逻辑。
文件传输配置开关
src/config.h, src/config.cpp
config::input_t 新增 file_transfer 布尔字段;默认配置启用该开关;配置文件解析新增对 "file_transfer" 的读取。
双端路由注册与入口接入
src/confighttp.cpp, src/nvhttp.cpp, src/nvhttp/file_transfer_api.h, src/nvhttp/file_transfer_api.cpp
confighttp::start() 注册本地文件传输路由并在认证后限制来源为 net::PCnvhttp 新增文件传输下载路由并委派给 nvhttp::file_transfer_api::get,后者调用下载处理与响应写回。
构建集成与单元测试
cmake/compile_definitions/common.cmake, tests/unit/test_file_transfer.cpp
CMake 追加文件传输相关源文件;单元测试覆盖存储层、HTTP 层和配置开关禁用场景。

控制面板子模块升级

Layer / File(s) Summary
sunshine-control-panel 子模块版本升级
src_assets/common/sunshine-control-panel
sunshine-control-panel 子模块引用更新到新的提交哈希。

Sequence Diagram(s)

sequenceDiagram
  participant LocalClient
  participant confighttp
  participant file_transfer_store
  participant nvhttp
  participant PairedClient

  LocalClient->>confighttp: POST /api/v1/file-transfer/offers
  confighttp->>confighttp: authenticate() + net::PC 校验
  confighttp->>file_transfer_store: create_single_file_offer(path)
  file_transfer_store-->>confighttp: create_result_t
  confighttp-->>LocalClient: JSON offer response

  PairedClient->>nvhttp: GET /api/v1/file-transfer/{64-hex-id}
  nvhttp->>file_transfer_store: get(id)
  file_transfer_store-->>nvhttp: get_result_t
  nvhttp-->>PairedClient: download response / file stream
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.89% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 标题准确概括了本次新增主机端文件传输 offer 的核心改动。
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.
Description check ✅ Passed 描述与本次文件传输存储、下载接口、配置开关、CMake和子模块更新的改动高度一致。

✏️ 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 codex/file-transfer-context-menu

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.

@qiin2333
qiin2333 marked this pull request as ready for review June 20, 2026 14:05

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 3

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

Inline comments:
In `@src/file_transfer_http.cpp`:
- Around line 98-100: The X-Sunshine-File-Name header on line 98 directly uses
the raw name variable without sanitization, creating a potential HTTP response
splitting vulnerability if the filename contains control characters like CR or
LF. The Content-Disposition header below it correctly applies
ascii_fallback_filename() to sanitize the filename, but X-Sunshine-File-Name
does not. Fix this by applying the same ascii_fallback_filename(name) function
to the name parameter when emplacing the X-Sunshine-File-Name header to ensure
consistent sanitization across both headers and prevent response header
injection attacks.

In `@src/file_transfer_http.h`:
- Around line 59-63: When the file open fails in the (!in) condition block, the
error response is reusing out.headers which contains headers intended for
successful downloads (such as Content-Length and Content-Disposition). These
headers do not match the JSON error body being returned, causing client parsing
issues. Replace the out.headers parameter in the resp->write call with an
appropriate empty or minimal headers object that matches the JSON error response
content, ensuring the response contract is consistent between headers and body.

In `@src/file_transfer_store.cpp`:
- Around line 33-37: The make_id() function throws a std::runtime_error when
RAND_bytes fails at lines 35-36, but the call to make_id() around lines 113-116
in create_single_file_offer lacks exception handling. This breaks the consistent
error handling pattern used in the rest of create_single_file_offer where errors
are converted to structured returns with error_code checks (see lines 85-98).
Wrap the make_id() call in a try-catch block and convert the caught exception to
a controlled error return { false, "rng_failed", {} } to maintain consistent
error handling and prevent the exception from propagating to the HTTP handling
layer.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6f1dfe1f-e33d-41d1-b526-7655b7eb5f5c

📥 Commits

Reviewing files that changed from the base of the PR and between 7f0c57a and a6cbf94.

📒 Files selected for processing (13)
  • cmake/compile_definitions/common.cmake
  • src/config.cpp
  • src/config.h
  • src/confighttp.cpp
  • src/file_transfer_http.cpp
  • src/file_transfer_http.h
  • src/file_transfer_store.cpp
  • src/file_transfer_store.h
  • src/nvhttp.cpp
  • src/nvhttp/file_transfer_api.cpp
  • src/nvhttp/file_transfer_api.h
  • src_assets/common/sunshine-control-panel
  • tests/unit/test_file_transfer.cpp
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
src/**/*.{cpp,c,h}

⚙️ CodeRabbit configuration file

src/**/*.{cpp,c,h}: Sunshine 核心 C++ 源码,自托管游戏串流服务器。审查要点:内存安全、 线程安全、RAII 资源管理、安全漏洞。注意预处理宏控制的平台相关代码。

Files:

  • src/nvhttp/file_transfer_api.cpp
  • src/nvhttp/file_transfer_api.h
  • src/nvhttp.cpp
  • src/config.h
  • src/config.cpp
  • src/file_transfer_store.h
  • src/confighttp.cpp
  • src/file_transfer_store.cpp
  • src/file_transfer_http.cpp
  • src/file_transfer_http.h
cmake/**

⚙️ CodeRabbit configuration file

cmake/**: CMake 构建系统文件。审查跨平台兼容性、现代 CMake 实践。

Files:

  • cmake/compile_definitions/common.cmake
tests/**

⚙️ CodeRabbit configuration file

tests/**: 测试文件。验证测试覆盖率、边界情况和断言正确性。

Files:

  • tests/unit/test_file_transfer.cpp
🔇 Additional comments (10)
src_assets/common/sunshine-control-panel (1)

1-1: 子模块更新符合预期,构建系统兼容性已验证。

此更改将 sunshine-control-panel 子模块从 de175aa 更新至 c371acf,启用了 Windows 文件传输功能。验证确认新提交包含所有必需的构建文件:package.json 中的 build:renderer 脚本、src-tauri/Cargo.toml 及完整的目录结构均完整无缺。

src/file_transfer_store.h (1)

16-56: LGTM!

cmake/compile_definitions/common.cmake (1)

139-144: LGTM!

tests/unit/test_file_transfer.cpp (1)

33-102: LGTM!

src/config.h (1)

222-222: 该变更片段已核对,当前无需补充评论。

src/config.cpp (1)

558-558: 该变更片段已核对,当前无需补充评论。

Also applies to: 1457-1457

src/confighttp.cpp (1)

44-44: 该变更片段已核对,当前无需补充评论。

Also applies to: 3015-3039

src/nvhttp/file_transfer_api.h (1)

1-15: 该变更片段已核对,当前无需补充评论。

src/nvhttp/file_transfer_api.cpp (1)

1-13: 该变更片段已核对,当前无需补充评论。

src/nvhttp.cpp (1)

47-47: 该变更片段已核对,当前无需补充评论。

Also applies to: 954-957

Comment thread src/file_transfer_http.cpp Outdated
Comment thread src/file_transfer_http.h
Comment thread src/file_transfer_store.cpp

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

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

Inline comments:
In `@src_assets/common/sunshine-control-panel`:
- Line 1: The submodule pointer is referencing a commit that is not on the
branch configured in .gitmodules, causing the tauri submodule to diverge from
the intended history. Update the submodule reference in the
sunshine-control-panel submodule so it points to a commit that belongs to the
configured tauri branch, or adjust the .gitmodules branch setting if the new tip
is intentional. Use the submodule entry and .gitmodules branch configuration to
keep the checkout consistent for clone and CI flows.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f0f3885f-7899-4a2e-8481-2869c8a3bd0d

📥 Commits

Reviewing files that changed from the base of the PR and between 385668b and e449ed3.

📒 Files selected for processing (4)
  • src/config.cpp
  • src/config.h
  • src/confighttp.cpp
  • src_assets/common/sunshine-control-panel
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/config.h
  • src/confighttp.cpp
  • src/config.cpp
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Windows

@@ -1 +1 @@
Subproject commit a0432e073266acb29b50cba2dc3dc76cf64415dc
Subproject commit 8b8dada639d76c6fa28b578b4a1539d1e9d98641

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.

🩺 Stability & Availability | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# 验证子模块提交在上游仓库可达
COMMIT="8b8dada639d76c6fa28b578b4a1539d1e9d98641"
REPO="https://github.com/qiin2333/sunshine-control-panel.git"

# 列出所有远端引用,检查该提交是否被任一引用包含
git ls-remote "$REPO" | grep -i "$COMMIT" && echo "提交是某引用的 tip" || echo "非引用 tip(可能仍在历史中,需进一步检查)"

# 通过 GitHub API 确认提交对象存在
gh api "repos/qiin2333/sunshine-control-panel/commits/${COMMIT}" \
  --jq '{sha: .sha, date: .commit.committer.date, message: .commit.message}' \
  && echo "提交存在于上游仓库" || echo "提交在上游仓库不存在或不可访问"

# 确认该提交是否包含在 tauri 分支历史中
gh api "repos/qiin2333/sunshine-control-panel/compare/tauri...${COMMIT}" \
  --jq '{status: .status, ahead_by: .ahead_by, behind_by: .behind_by}' \
  && echo "已对比 tauri 分支" || echo "无法对比 tauri 分支"

Repository: AlkaidLab/foundation-sunshine

Length of output: 578


修正子模块指针:该提交不属于 .gitmodules 指定的 tauri 分支。

验证确认提交 8b8dada639d76c6fa28b578b4a1539d1e9d98641 存在,但它是 codex/file-transfer-context-menu 分支的 tip,且与 .gitmodules 配置的 tauri 分支历史分叉diverged)。

该提交包含 tauri 的合并记录但未位于 tauri 分支上。这种配置会导致 git clone --recurse-submodules 或 CI 构建时产生状态不一致(无法保证检出 tauri 分支时自动包含此提交)。若目标是特定功能分支,建议同时更新 .gitmodules 中的 branch 配置,或确认构建流程不依赖显式 checkout tauri 的行为。

🤖 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_assets/common/sunshine-control-panel` at line 1, The submodule pointer is
referencing a commit that is not on the branch configured in .gitmodules,
causing the tauri submodule to diverge from the intended history. Update the
submodule reference in the sunshine-control-panel submodule so it points to a
commit that belongs to the configured tauri branch, or adjust the .gitmodules
branch setting if the new tip is intentional. Use the submodule entry and
.gitmodules branch configuration to keep the checkout consistent for clone and
CI flows.

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