Skip to content

imengying/fq_Rust

Repository files navigation

fq_Rust

番茄小说纯 Rust 实现。

当前主线已经统一成单一 Rust 运行链:

  • Rust 负责对外 HTTP API、上游请求编排、缓存和内容解密
  • Rust 负责 registerkey 请求、缓存和解密 key 解析
  • Rust 原生 rnidbg signer 已内嵌进 fq-api
  • signer 资源和运行时已编进 fq-api,启动时自动解包到临时目录
  • Java signer、Maven 构建链、unidbg jar 回退路径已删除

代码结构

  • crates/api: Rust API 服务
  • crates/signer-native: Rust 原生 signer 库
  • assets/fq-signer: 构建期嵌入的 signer 资源
  • vendor/rnidbg: 裁剪后的 rnidbg 运行时最小子集
  • vendor/rnidbg/android/sdk23: 项目默认内嵌的运行时目录
  • configs/config.yaml: 默认配置
  • .github/workflows/ci.yml: 编译与测试

当前目录分层约定:

  • crates/: 所有 Rust 源码
  • assets/: 会被打进二进制的静态资源
  • vendor/: 提交到仓库的第三方源码
  • tools/: 导入和维护脚本

当前 vendor/rnidbg 只保留项目实际会编译和运行到的部分:

  • android/sdk23
  • emulator
  • sparse_list
  • unicorn

其中 unicorn 也已经进一步裁成当前项目使用的 AArch64 构建子集,不再保留其它架构目标源码。

对外接口

  • GET /search
  • GET /book/{book_id}
  • GET /toc/{book_id}
  • GET /chapter/{book_id}/{chapter_id}

配置

配置加载顺序:

  1. configs/config.yaml

关键项:

  • fq.upstream: 番茄上游地址与超时
  • fq.signer.restart_cooldown_ms: 内嵌 signer 重建节流
  • fq.signer.android_sdk_api: 模拟上报给库的 Android SDK level
  • fq.cache.postgres_url: 可选 PostgreSQL 章节主缓存
  • fq.prefetch: 章节分桶预取
  • fq.auto_heal: 连续错误后的 registerkey 失效、设备轮换、signer 重启自愈
  • fq.device_profile: 当前生效设备信息
  • fq.device_pool: 可选设备池

可用环境变量:

  • FQRS_DB_URL
  • DB_URL
  • FQRS_SIGNER_ANDROID_SDK_API
  • FQRS_DEVICE_POOL_STARTUP_NAME
  • FQRS_UPSTREAM_DROP_HEADERS
  • FQRS_UPSTREAM_DROP_QUERY_PARAMS
  • FQRS_COOKIE_OVERRIDE
  • FQRS_USER_AGENT_OVERRIDE
  • FQRS_DEVICE_JSON_OVERRIDE
  • FQ_SIGNER_RESOURCE_ROOT
  • RNIDBG_BASE_PATH

兼容保留:

  • 默认不需要配置任何资源路径
  • UNIDBG_RESOURCE_ROOT 仍可用,但只是 FQ_SIGNER_RESOURCE_ROOT 的旧名字兼容
  • 当前二进制默认内嵌的是更接近原版 unidbg 行为的 sdk23 运行时
  • 当前默认 fq.signer.android_sdk_api: 23
  • RNIDBG_BASE_PATH 只在你明确指定外部运行时目录时才需要

本地运行

  1. 修改 configs/config.yaml
  2. 构建:
cargo build --release --workspace

如果想一次性补齐依赖、跑测试和构建,也可以直接用脚本:

./start.sh deps
./start.sh test
./start.sh build

脚本在 root 环境下默认会把 Rust 安装到系统目录:

CARGO_HOME=/usr/local/cargo
RUSTUP_HOME=/usr/local/rustup

并自动写入 /usr/local/bin 链接和 /etc/profile.d/fq-rust-env.sh。 如果你明确不想装到系统目录,可以显式传:

SYSTEM_RUST_INSTALL=false ./start.sh build
  1. 启动:
./target/release/fq-api

启动后可直接请求:

curl "http://127.0.0.1:9999/search?key=斗破苍穹&page=1&size=20&tabType=3"
curl "http://127.0.0.1:9999/book/7185502456775208503"
curl "http://127.0.0.1:9999/toc/7185502456775208503"
curl "http://127.0.0.1:9999/chapter/7185502456775208503/7185502456775209001"

如果你要做上游请求头 A/B 实验,可以临时裁掉最终发出的部分请求头:

FQRS_UPSTREAM_DROP_HEADERS=x-soter ./target/release/fq-api
FQRS_UPSTREAM_DROP_HEADERS=x-medusa,x-soter ./target/release/fq-api
FQRS_UPSTREAM_DROP_HEADERS=authorization,x-soter ./target/release/fq-api

说明:

  • 这个变量是逗号分隔、大小写不敏感
  • 它作用在最终发出的上游请求头,不改 signer 原始输出格式
  • 适合快速排查 HTTP 200body 为空时,究竟是哪组头触发了上游策略

如果你要做上游 query 参数 A/B 实验,也可以临时裁掉最终请求 URL 里的部分参数:

FQRS_UPSTREAM_DROP_QUERY_PARAMS=need_version ./target/release/fq-api
FQRS_UPSTREAM_DROP_QUERY_PARAMS=need_version,book_type,player_so_load ./target/release/fq-api

说明:

  • 这个变量同样是逗号分隔、大小写不敏感
  • 它会在 signer 计算签名前先修改最终 URL,所以签名和实际请求保持一致

如果你要做设备画像 / 区域 A/B 实验,可以直接用环境变量覆盖当前生效设备和设备池里的所有 profile:

FQRS_COOKIE_OVERRIDE='install_id=573270579220059' ./target/release/fq-api
FQRS_USER_AGENT_OVERRIDE='com.dragon.read.oversea.gp/68132 (Linux; U; Android 13; zh_CN; Pixel 7; Build/TQ3A.230805.001;tt-ok/3.12.13.4-tiktok)' ./target/release/fq-api
FQRS_DEVICE_JSON_OVERRIDE='{"device":{"cdid":"override-cdid","device_type":"Pixel 7","device_brand":"Google","rom_version":"TQ3A.230805.001","device_id":"1778337441136410","install_id":"573270579220059"}}' ./target/release/fq-api

说明:

  • FQRS_COOKIE_OVERRIDE 直接替换 cookie
  • FQRS_USER_AGENT_OVERRIDE 直接替换 user-agent
  • FQRS_DEVICE_JSON_OVERRIDE 用 JSON 做局部覆盖,未提供的字段保持原配置
  • 这 3 个 override 会同时作用到当前 profile 和设备池里的 profile,避免轮换后实验失效

实验导入外部运行时

仓库当前默认内嵌的是 sdk23。下面这套流程主要用于实验性导入外部运行时,例如从 Android 12 / API 31 GSI 提取一套 sdk31 目录;它不会自动替换主线默认底座。

  1. 从官方 Android 12 / API 31 GSI 解压出 system.img
  2. system.img 挂载成只读目录
  3. 运行脚本生成 rnidbg 目录:
tools/import_rnidbg_sdk.sh /path/to/mounted/system vendor/rnidbg/android/sdk31

生成后运行:

cargo build --release --workspace
./target/release/fq-api

如果你仍然想强制用某个外部目录覆盖内嵌版本,再显式指定:

RNIDBG_BASE_PATH="$PWD/vendor/rnidbg/android/sdk31" ./target/release/fq-api

脚本只会复制当前项目需要的最小文件集:

  • system/bin/ls
  • system/bin/sh
  • system/lib64/libc++.so
  • system/lib64/libc.so
  • system/lib64/libcrypto.so
  • system/lib64/libdl.so
  • system/lib64/liblog.so
  • system/lib64/libm.so
  • system/lib64/libssl.so
  • system/lib64/libstdc++.so
  • system/lib64/libz.so

常见挂载方式:

simg2img system.img system.raw.img
mkdir -p /tmp/android12-system
sudo mount -o loop,ro system.raw.img /tmp/android12-system
tools/import_rnidbg_sdk.sh /tmp/android12-system vendor/rnidbg/android/sdk31
sudo umount /tmp/android12-system

GitHub Actions 生成外部运行时目录

仓库还带了一个手动 workflow:

用法:

  1. 在 GitHub Actions 页面手动运行 Build rnidbg SDK
  2. 填入 system_image_url
  3. 如果输入是 zip,必要时再填 image_entry
  4. workflow 会:
    • 下载 system image
    • 自动解 zip
    • 自动把 sparse image 转成 raw
    • loop 只读挂载
    • 调用 tools/import_rnidbg_sdk.sh
    • 上传 ${sdk_name}.tar.gz artifact

这条 workflow 适合生成实验用外部运行时目录;当前主线默认仍然使用 sdk23 底座。

GitHub Actions

主工作流是 .github/workflows/ci.yml

  • cargo test --workspace
  • cargo build --workspace --release
  • 上传 fq-api

Docker

当前按单镜像部署:

  • 只构建 Rust
  • 运行阶段不再需要 Java
  • 运行阶段只包含 fq-api 和配置文件
  • signer 资源与运行时目录由二进制自解包
  • 运行阶段使用 gcr.io/distroless/cc-debian12:nonroot

本地启动:

docker compose up --build

相关文件:

Docker Hub 发布

工作流在 docker-publish.yml

会推送多架构镜像:

  • <DOCKERHUB_USERNAME>/fq-rust

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors