# Linas **Repository Path**: BigPig0/Linas ## Basic Information - **Project Name**: Linas - **Description**: Lithium nas - **Primary Language**: C - **License**: MulanPSL-2.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-10-08 - **Last Updated**: 2026-10-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Linas Lithium NAS —— 一个私有 NAS 系统的功能合集。 Linas 不是一个单一程序,而是一组**功能模块**(媒体库、存储、文件共享、 用户认证、元数据、Web API、备份……)以及一组**独立可执行程序**的集合。 每个功能既可以单独运行,也可以组合在一个进程里(例如 `linas-web`)。 ## 目录结构 ``` Linas/ ├── CMakeLists.txt 顶层构建:查找依赖、构建各模块与程序 ├── cmake/LinasDeps.cmake 依赖查找 ├── conf/ 运行配置(linas.conf / uvlogplus.properties) ├── doc/design.md 系统设计文档 ├── www/ 静态管理前端(浏览器访问 http://host:8080/) ├── src/ 功能模块(编译为静态库 linas_*) │ ├── core/ 核心框架:应用/模块/日志/配置/调度/数据库 │ ├── metadata/ 媒体元数据存储(sqlite) │ ├── media/ 媒体库:扫描、签名识别、EXIF、索引 │ ├── storage/ 存储:磁盘发现与存储池/卷管理 │ ├── auth/ 用户与认证 │ ├── share/ 文件共享(FTP + WebDAV + SFTP,多共享 + 按角色权限) │ ├── webapi/ Web API(REST) │ └── backup/ 备份/同步 └── apps/ 独立可执行程序 ├── linas-media 媒体库服务 ├── linas-storage 存储管理服务 ├── linas-share 文件共享服务 └── linas-web Web 管理服务 ``` ## 技术选型与约定(务必遵守) 1. **网络一律使用 uvnetplus**:所有网络协议(HTTP/HTTPS、FTP、TCP/UDP、 WebSocket、Redis、AMQP、SIP、KCP…)都基于 `uvnetplus` 实现。 若某个新协议 `uvnetplus` 尚未提供,**先在 uvnetplus 中封装**, 再回到 Linas 使用;不在 Linas 里直接写 socket / 裸协议。 2. **数据库一律使用 ludb**:不直接调用 sqlite3 或其它数据库驱动, 统一通过 `linas::CDatabase`(封装自 ludb)访问。 3. **日志一律使用 uvlogplus**:通过 `linas::CLogger` / `LINAS_*` 宏输出, 不直接使用 printf / std::cout 作为日志。 4. **完成一个功能就提交并推送**:每完成一个可工作的功能, 及时 `git commit` 并 `git push`,保持小步前进。 ## 依赖 Linas **只包含自身的代码**,所有依赖都从 CMake 安装前缀查找,不引用任何 其它项目的源码路径: - 自研基础库:`util`、`utilc`、`crypto`、`uvlogplus`、`uvnetplus`、`ludb` - 第三方库:`libuv`、`pugixml`、`cJSON`、`sqlite3`、`lua`、`mbedtls`、`hiredis`、 `rabbitmq-c`、`osip` - 可选:`ffmpeg`(`avformat`/`avcodec`/`swscale`/`avutil`/`x264`)—— 缺失时自动禁用媒体缩略图 ## 编译 ```bash cmake -S $ROOT/Linas -B $ROOT/build/Linas \ -DCMAKE_INSTALL_PREFIX=$INSTALL -DCMAKE_BUILD_TYPE=Release cmake --build $ROOT/build/Linas ``` 产物位于 `build/Linas/bin/`:`linas-media`、`linas-storage`、`linas-share`、`linas-web`。 可选编译项(减小体积): | 选项 | 默认 | 说明 | |---|---|---| | `-DLINAS_WITH_THUMBNAILS=OFF` | ON | 关闭媒体缩略图,不再链接 ffmpeg(可执行文件 ~27MB → ~5.4MB) | | `-DLINAS_STRIP=OFF` | ON | 保留发布版符号表(默认剥离,链接后 ~130MB → ~27MB) | > 体积主要来自静态链接的 ffmpeg;关闭缩略图或剥离符号表可显著减小。 ## 运行 在 `Linas/` 目录下运行(以便使用默认的 `./conf/...` 配置): ```bash # 媒体库:扫描 ./media 并索引到 ./data/linas.db ../build/Linas/bin/linas-media # Web 管理服务:http://127.0.0.1:8080/api/health ../build/Linas/bin/linas-web # 指定配置文件 ../build/Linas/bin/linas-web --config ./conf/linas.conf ``` Web API: | 方法 | 路径 | 说明 | |---|---|---| | GET | `/api/health` | 健康检查(公开) | | POST | `/api/login` | 登录,body `{"username","password"}`,返回令牌(公开) | | POST | `/api/logout` | 注销(公开) | | POST | `/api/refresh` | 令牌续期(公开,需有效令牌) | | GET | `/api/disks` | 磁盘列表 | | GET | `/api/media?limit=&offset=` | 媒体列表(含 `thumb` 缩略图路径) | | GET | `/api/media/thumb?path=` | 缩略图字节流(`path` 须在 `thumbDir` 内) | | GET | `/api/storage/pools` | 存储池列表 | | POST | `/api/storage/pools` | 新建存储池(`{name,path}`) | | DELETE | `/api/storage/pools?name=` | 删除存储池 | | GET | `/api/storage/volumes` | 存储卷列表 | | POST | `/api/storage/volumes` | 新建存储卷(`{pool,name,quota?}`) | | POST | `/api/storage/volumes/quota` | 设置卷软配额(`{name,quota}`,0=不限) | | DELETE | `/api/storage/volumes?name=` | 删除存储卷 | | GET | `/api/storage/smart?device=` | 磁盘 SMART 健康(依赖 smartctl) | | POST | `/api/storage/mount` | 挂载设备(`{device,mountPoint,fsType}`,需 root) | | POST | `/api/storage/unmount` | 卸载(`{mountPoint}`,需 root) | | GET | `/api/users` | 用户列表(管理员) | | POST | `/api/users` | 新建用户 `{username,password,role}`(管理员) | | DELETE | `/api/users?name=` | 删除用户(管理员) | 浏览器打开 `http://host:8080/` 即为内置的静态管理前端(`www/`,由 `[Web] staticDir` 指定):登录后可查看磁盘、媒体(含缩略图)、用户。 除公开接口外,需携带令牌:`Authorization: Bearer `(也支持 `X-Auth-Token` 或查询串 `?token=`)。鉴权由 `[Web] authRequired` 控制。 授权按角色(`admin` / `user`):普通用户只能只读访问磁盘/媒体/存储查询; 用户管理与存储增删仅管理员可用,越权返回 403。 文件共享(`linas-share`)支持多个共享目录,按角色控制访问与写入: 每个共享在 `conf/linas.conf` 中以 `[Share.]` 定义(`path` / `writable` / `roles`),用户来自 auth 模块,管理员可访问全部共享。FTP、WebDAV 与 SFTP 均需 认证(WebDAV 用 Basic,FTP 用 USER/PASS,SFTP 用 SSH 口令或公钥)。 SFTP(`[Share] sftpPort`,默认 2022)把同一套共享通过 SSH 暴露:共享按 `/<相对路径>` 出现在根目录,`roles` / `writable` 决定可见性与写入,不可访问的 共享在目录列举中直接隐藏、越权操作返回 Permission denied。主机密钥首次启动时 用 `ssh-keygen` 自动生成到 `conf/ssh_host_rsa_key`。 公钥认证:`[Share] sftpAuthorizedKeys`(默认 `./conf/authorized_keys.d`,缺失时 自动创建;留空 = 关闭)目录下,`<用户名>` 文件即该用户的 authorized_keys (OpenSSH 格式,`ssh-keygen -y` 的 `.pub` 行或 `~/.ssh/authorized_keys` 内容); 用户须存在于 auth 模块,认证后按该用户的角色授权。注意当前 mbedtls 构建不支持 Ed25519,用户密钥请使用 RSA 或 ECDSA(如 `ssh-keygen -t ecdsa`)。 ```bash sftp -P 2022 admin@127.0.0.1 # 交互式(口令 = auth 模块密码) sftp -P 2022 -i ~/.ssh/id_ecdsa admin@127.0.0.1 # 公钥认证 printf 'ls /\nget /private/a.txt\n' | sftp -b - -P 2022 admin@127.0.0.1 ``` 启用 TLS(`[Share] tls=true` + `tlsCert`/`tlsKey`)后: - **WebDAV → HTTPS-WebDAV**:整个 HTTP 连接走 TLS(推荐,已完整可用)。 - **FTP → FTPS**:显式 FTPS(RFC 4217,`AUTH TLS`),控制通道与数据通道 (`PBSZ`/`PROT P`)均加密,已完整可用。 ```bash # 自签名测试证书 openssl req -x509 -newkey rsa:2048 -keyout conf/server.key -out conf/server.crt \ -days 365 -nodes -subj "/CN=localhost" # FTPS curl --ssl-reqd -k --user admin:admin ftp://127.0.0.1:2121/ # HTTPS-WebDAV curl -k --user admin:admin -X PROPFIND -H 'Depth: 1' https://127.0.0.1:8081/ ``` 另有 WebSocket 进度推送:`ws://host:8080/ws?token=`,实时推送后台 任务进度(如媒体扫描);客户端发送 `{"action":"scan"}` 可触发一次扫描。 ```bash TOKEN=$(curl -s -X POST -d '{"username":"admin","password":"admin"}' \ http://127.0.0.1:8080/api/login | python3 -c 'import sys,json;print(json.load(sys.stdin)["token"])') curl -s -H "Authorization: Bearer $TOKEN" http://127.0.0.1:8080/api/disks ``` ## 模块与程序组装 功能模块通过 `LINAS_REGISTER_MODULE("name", CType)` 自注册;程序用 `app.AddModulesFromConfig("<默认列表>")` 组装,可用 `[Core] modules` 覆盖 (逗号分隔)。因注册在静态初始化阶段完成,程序需整档链接模块库 (`apps/CMakeLists.txt` 已处理)。`/api/health` 会返回当前启用的模块列表。 ## 新增一个功能模块 1. 在 `src//` 下实现一个类,继承 `linas::IModule`,实现 `Name() / Init() / Start() / Stop()`,并用 `LINAS_REGISTER_MODULE("name", CType)` 注册。 2. 在 `src//CMakeLists.txt` 中构建静态库并链接依赖。 3. 在 `src/CMakeLists.txt` 中 `add_subdirectory()`。 4. 在需要的 `apps/*/CMakeLists.txt` 中把该库加入整档链接列表,并在 `main.cpp` 的默认模块列表里加上它的名字。