Sula:用 Scryer Prolog 编写的 Gemini 协议服务器
摘要
Sula 是一个用 Scryer Prolog 编写的 Gemini 协议服务器,具有通过 rustls 实现的 TLS、内容协商和优雅关闭功能,但需要修补过的 Scryer Prolog 构建版本。
暂无内容
查看缓存全文
缓存时间: 2026/08/05 19:56
# Sula
来源:https://sagredo.dev/projects/sula/
> `/'su\.la/` 取自西班牙语中“胶囊”的后缀,Cápsula。
sula 徽标
Git(https://git.sagredo.dev/?p=sula.git;a=summary)
一个用 Scryer Prolog(https://www.scryer.pl/)编写的 Gemini(https://geminiprotocol.net/)协议服务器。
## 要求
sula 依赖于打了补丁的 Scryer Prolog,可在 此处(https://git.sagredo.dev/scryer-prolog)找到(分支 `js/fixes`)。所需的补丁包括:
- 原生 `'$copy_stream'/2` 内置谓词,用于将二进制文件体流式传输给 TLS 客户端,而无需将内容物化到 Prolog 堆上。
- 对 `library(pio)` 的 `buffer_prepare_for_n/5` 的修复,使得从进程管道(以及其他 `at_end_of_stream/1` 永远不会报告 true 的流)惰性读取时,在 EOF 处终止而不是空转。
- 在 `socket_server_accept/4` 中加入非阻塞轮询循环,检查 Scryer 的 `INTERRUPT` 标志,以便 `SIGINT` 变成可捕获的 `'$interrupt_thrown'` 异常,而不是被阻塞的系统调用卡住。
- 移植到 `rustls`。
- 修改 `tls_server_negotiate` 以包含可选的客户端证书。
构建并安装打过补丁的 Scryer:
``
git clone https://git.sagredo.dev/scryer-prolog -b js/fixes
cd scryer-prolog
cargo install --path .
``
`openssl(1)` 也必须位于 `PATH` 中——它在启动时被调用,从配置的身份证书中读取 `CN`,并验证它与配置的主机名匹配。
## 运行
``
./sula.pl --addr HOST:PORT --hostname NAME --content DIR --certs DIR
``
`sula.pl` 是一个多语言脚本:bash 检测到 `PATH` 上的 `scryer-prolog`,并以 `sula:run, halt` 作为入口目标执行它。
示例:
``
./sula.pl \
--addr 127.0.0.1:1965 \
--hostname gmi.example.dev \
--content ./site \
--certs .
``
### 命令行选项
所有选项接受任意顺序。任何未识别的选项都会被静默丢弃。
选项含义默认值`--addr HOST:PORT`监听 socket 的绑定地址和端口`127.0.0.1:1965``--hostname NAME`证书的预期 `CN`。不匹配时启动中止`localhost``--content DIR`服务文件的根目录`./site``--certs DIR`包含 `cert.pem` 和 `key.pem` 的目录`.`### 停止服务器
`Ctrl+C` 触发干净关闭:监听 socket 被关闭,顶层 catch 记录 `Shutting down`,进程以 0 退出。
## 特性
- TLS 通过 `rustls`,PKCS#12 身份文件。
- 主机名验证:启动时,`cert_is_for_hostname/2` 调用 `openssl x509`,并断言证书的 `CN` 与 `--hostname` 匹配。
- 通过 `mime/2` 按扩展名进行内容协商,内容在启动时从 `/etc/mime.types`(由 `mime.pl` 中的 DCG 解析)填充。为 `.gmi` 添加了 `text/gemini`。
- 文本响应通过 `format/3` 发送;二进制响应在原生代码中通过 `copy_stream/2`(文件 → TLS socket,不经过 Prolog 堆)流式传输。
- 每连接错误处理:TLS 握手失败和流中间客户端断开连接会被记录,循环继续。其他错误会重新抛出并显示在顶层。
- 通过打补丁的 Scryer `socket_server_accept/4` 在 `SIGINT` 时优雅关闭。
## 布局
``
sula.pl 多语言启动器 + 主 sula 模块(run/0,请求循环)。
config.pl CLI 解析(DCG)和配置访问器(cert/1,addr/1,…)。
cert.pl 证书加载 + 主机名对 CN 检查。
mime.pl /etc/mime.types 解析器(DCG)和 mime/2 事实。
request.pl 请求行读取器。
gemini_uri.pl Gemini URI DCG(gemini://host[:port]/path[?query])。
ip.pl IP 地址识别(作为 Gemini 主机被拒绝)。
response.pl 响应状态码 DCG。
log.pl 带标签的 log_msg/3。
banner.pl 读取 banner.txt 并通过 display_banner/1 逐行输出。
``
## 计划中的功能
- 使用密钥和证书而不是 identity.p12
- 客户端证书
- 从配置文件加载配置
- 保存和加载用户
- 运行 CGI 脚本
- 所有状态码
- 速率限制
- 虚拟主机
- 文件日志
- 多线程或类似?
- 热重载?
相似文章
yserver: 一个用Rust从头编写的现代X11服务器
yserver是一个用Rust从头编写的现代X11服务器,能够运行MATE、XFCE和Cinnamon等完整的桌面环境,同时去掉了遗留的负担。它支持多种X扩展,并已在多种硬件上测试过。
alireza0/s-ui
S-UI 是一个基于 SagerNet/Sing-Box 构建的高级 Web 面板,用于管理多协议代理配置,具备流量路由、订阅链接和多语言支持等功能。
Ursula:基于线程每核心、多Raft架构的HTTP事件流Rust运行时
Ursula是一个开源、自托管的分布式服务器,用于可重放、仅追加的事件时间线,运行于HTTP和SSE之上,采用线程每核心、多Raft架构,并搭配S3存储以实现低延迟和持久性。
@itsharmanjot: 四个AI CLI现在通过一个SQLite文件互相通信:Claude Code、Gemini CLI、Codex CLI、OpenCode……
Squad是一个开源的Rust工具,让四大AI CLI(Claude Code、Gemini CLI、Codex CLI、OpenCode)通过一个单一的SQLite文件在同一个代码库上协作,无需守护进程或服务器。
我构建了LOLM:一个更低成本、支持实时控制决策和密封运行收据的LLM智能体
LOLM的构建者宣布推出Qira开发的Transformer-SSM混合语言模型与智能体系统,具备实时决策控制器、运行收据、CLI、编码沙箱、MCP支持以及更低成本的托管访问。