这是Rust 的简单 Redis 客户端和 RESP 解析器:
use redust::{resp::{Data, from_data}, Connection}; |
背景
Redis现有客户端库很多:
- redis: 迄今为止最受欢迎且绝对是最符合人体工程学的库。然而,我对它的 pubsub 支持感到沮丧。虽然通常可以接受,但在消费消息的同时执行订阅操作是不可能的。我喜欢图书馆,但这个问题的解决方法对我来说是不可接受的。
- redis-async: 非常接近我想要的。高级 pubsub API 非常符合人体工程学,并提供低级 Tokio 编解码器,以便在需要时与底层 TCP 连接进行更密切的交互。不幸的是,高级 API 是围绕 2 种不同的连接类型(常规和 pubsub)设计的;这使得与连接池一起使用具有挑战性。
- simple_redis: pubsub API 不符合人体工程学。
- redis-subscribe: 旨在解决 redis crate 的问题;但是,它需要一个完全独立的连接,类似于 redis-async。
我的目标是使开发人员 API 和内部结构尽可能简单。这表现为一个单独的 Connection 结构体,它实现了 Stream + Sink 并带有一些方便的方法来向 Redis 发送和接收命令。
要与 Redis 交互,有多种选择。对于最常见的用例,我添加了一种方便的方法来处理发送单个命令和接收单个响应。我还添加了一种流水线方法。由于连接实现了 Stream + Sink,开发者可以忽略这些便捷的方法,直接与底层的框架 TCP 流进行交互。
通过发送 subscribe 命令然后从连接的流中接收来启用 Pubsub。由于此操作不消耗连接,因此它仍可用于调度其他命令。
显然,干净的 API 的一部分是能够与原生 Rust 结构交互。这意味着以用户友好的方式处理 RESP,以便面向开发人员的 API 不必担心它。
RESP
RESP(REdis序列化协议)是客户端库用来与Redis通信的底层二进制(ish)协议。
大多数Redis客户端库定义了它们自己的特性,用于将东西转换为RESP。为了最大限度地符合人体工程学,库的开发者需要在标准库的大范围内实现这一特性。当涉及到由其他板块导出的类型时,库的用户就会陷入困境,除非开发者也在这些类型上实现了特质。
为了获得最佳的开发体验,Serde似乎是一个显而易见的选择,所以我花了大量时间来研究如何为RESP实现Serde(向Serde-json致敬,它是一个超级彻底的例子)。大多数Rust生态系统都在某种程度上支持serde,serde本身也处理标准库中的大多数类型。
RESP不支持serde中的一些类型,所以我的实现需要有一定的主见(特别是在涉及键值配对时)。
项目点击标题