omni-stream 0.1.2

Single-binary streaming storage proxy: axum + tokio + aws-sdk-s3 backend with an embedded React SPA, serving local FS or S3-compatible object storage behind one port.
omni-stream-0.1.2 is not a library.

OmniStream

中文 · English

单二进制的流式文件浏览与预览服务——把任意本地目录或 S3 兼容对象存储 (MinIO / OSS / Ceph / R2 等)一键暴露为可浏览、可预览的 HTTP 服务,浏览器 打开就能浏览目录、看图、刷视频、读代码,无需安装客户端,也无需另搭前端或反代。 后端基于 axum + tokio + aws-sdk-s3,通过 StorageBackend trait 统一抽象 多种存储后端。

内嵌一份开箱即用的 React SPA 前端,启动后,浏览器打开 http://<host>:<port>/ 就能直接浏览目录、按需加载缩略图、就地预览文件。预览功能支持:

  • 图片 —— png / jpg / gif / webp / avif / bmp / svg / ico
  • 视频 —— mp4 / webm / mov / mkv / m4v / ogv,按 Range 流式拖拽
  • 文本 / 代码 —— 按扩展名做语法高亮:json / yaml / toml / md / rs / ts / py / go / sql / shell / proto 等
  • 其它格式 —— 通用 fallback:图标 + 元信息 + 浏览器内置 viewer

预览 S3 / S3-兼容存储上的文件时,所配 access key 必须有 s3:GetObject (文件预览 / 下载 / HEAD)和 s3:ListBucket(目录浏览 / 缩略图列表) 权限——少一项对应操作就 403。本地文件系统后端无此要求,但只能访问 local.root_path 配置的根目录。

HTTP 接口(前端 SPA 都基于此调用,也可以直接用 curl / 自写客户端):

  • GET /api/list?prefix=&page_token= —— 浏览目录
  • GET /api/stat/{*key} —— 取文件元信息
  • GET /api/proxy/{*key} —— 流式拉取,全程透传 Range,自动 200 / 206
  • 嵌入式 SPA fallback —— 任何非 /api/* 路径回落到 index.html,前端路由自洽

1. 安装

推荐:用 cargo 装,二进制自动落到 ~/.cargo/bin/(已在 $PATH 中),可以直接以 omni-stream 命令调用:

cargo install omni-stream    # 需 Rust 1.91+

或从 GitHub Releases 下载已编译二进制:https://github.com/maoXyzt/omni-stream/releases/latest。 覆盖 3 个平台 —— x86_64-unknown-linux-gnu / x86_64-unknown-linux-musl / aarch64-apple-darwin (Windows 用户可自行编译)。对于预编译二进制,解压后给 omni-stream 加可执行权限即可,自行决定 要不要把它放进 $PATH

想从源码构建、修改前后端、参与开发,见 docs/development_guide.md; 发版流程见 docs/how_to_release.md

2. 配置

config.toml 默认查找顺序(找到第一个就用它):

  1. $OMNI_CONFIG(绝对路径,最高优先级)
  2. $XDG_CONFIG_HOME/omni-stream/config.toml
  3. directories::ProjectDirs 平台默认(macOS:~/Library/Application Support/omni-stream/;Linux:~/.config/omni-stream/
  4. ./config.toml(当前目录)

仓库根目录有 config.example.toml 可作模板。最小可用配置:

[server]
host = "127.0.0.1"
port = 8080

[[storages]]
name = "local-data"
type = "local"
active = true
local = { root_path = "/var/lib/omni-stream" }

或 S3 / S3-兼容(MinIO / OSS):

[[storages]]
name = "production-s3"
type = "s3"
active = true
s3 = { endpoint = "http://minio.local:9000", bucket = "data", access_key = "...", secret_key = "...", region = "us-east-1" }

多个 [[storages]] 表项可同时存在;启动时挑 active = true 的那一个,没配 active 就用第一个。 前端页面上也可以切换。

环境变量覆盖(前缀 OMNI_,分隔符 _):

变量 作用
OMNI_SERVER_HOST 覆盖 server.host
OMNI_SERVER_PORT 覆盖 server.port
OMNI_AUTH_ENABLED 覆盖 auth.enabledtrue / false
OMNI_AUTH_TOKEN 覆盖 auth.token(建议把 secret 放这里而不是配置文件)
OMNI_CONFIG 强制使用某个绝对路径的 config.toml
RUST_LOG tracing 过滤,例如 info,tower_http=debug,aws=info

鉴权(可选)

默认状态下 /api/* 是开放的——这只适合局域网信任环境。如果要开启 Bearer token 鉴权,在配置文件中添加:

[auth]
enabled = true
token = "any-long-random-string"

或者只用环境变量(不把 secret 放进配置文件):

OMNI_AUTH_ENABLED=true OMNI_AUTH_TOKEN=$(openssl rand -hex 32) ./omni-stream

启用后:

  • 所有 /api/* 请求必须带 Authorization: Bearer <token>,否则返回 401 + WWW-Authenticate: Bearer realm="omni-stream"
  • token 比对走常时间字节比较,不会因长度 / 内容差异泄漏时序。
  • 嵌入的前端 SPA(//assets/*)保持开放——浏览器要先把页面拉下来,才有 地方让用户输入 token。第一次访问 API 拿到 401,前端会弹出 token 输入框, 存到 localStorage,之后的请求自动带上。
  • TLS 不在本进程职责范围内。要暴露到不信任网络,请在前面挡 nginx / caddy / Cloudflare 反代,让其负责 HTTPS。

3. 启动

cargo install 装的话,omni-stream 已经在 $PATH 里,直接:

# 用 §2 查找顺序里命中的 config.toml
omni-stream

# 或显式指定一份
OMNI_CONFIG=/etc/omni-stream/config.toml omni-stream

# 或显式指定端口
OMNI_SERVER_PORT=8081 omni-stream

# 调试时打开请求日志
RUST_LOG=info,tower_http=debug omni-stream

GitHub Releases 下载的 tarball 解压后没自动入 $PATH,要么 ./omni-stream 当前目录跑,要么自己挪到 /usr/local/bin/ 之类的目录。

启动后浏览器打开 http://<host>:<port>/ 即是嵌入的前端 SPA。Ctrl-C / SIGTERM 触发优雅关停(axum::serve + with_graceful_shutdown)。

4. HTTP 错误码语义

触发 HTTP AppError
鉴权开启但未带 / token 错误 401 (middleware,不走 AppError)
文件不存在 404 NotFound
凭据无 GetObject 权限 / S3 AccessDenied 403 Forbidden
越界 / 非法 Range 416 InvalidRange
路径含 .. 等越权片段 / 把目录当文件请求 400 InvalidPath / Unsupported
其它 IO / SDK / 网络错误 500 Io / Backend

错误体统一是 {"error": "...", "message": "..."} JSON。