levilamina::service · 服务¶
跨模组服务:一问一答。
和总线互补,总线是广播,不返回任何东西。名字是独占的:一个名字只有一个提供方,再去占会被宿主拒绝,宿主的日志会写出谁占着这个名字;这比后注册的悄悄胜出好排查得多。
call 返回一个裸的 String,call_json 直接反序列化成你要的类型,解析失败是明确的错误,不会变成某个 unwrap_or 的兜底值。
错误在 CallError 里分了类:服务不存在和服务拒绝是两回事。前者通常意味着缺少依赖或者名字拼错,后者是业务逻辑的拒绝。
函数¶
service::call¶
| Rust | |
|---|---|
调用一个服务,返回原始的回答文本。
- 参数:
- name :
&str - request :
&str
- name :
- 返回值类型:
CallResult<String> - 对应槽位:
service_call
service::call_json¶
| Rust | |
|---|---|
调用一个服务,把回答从 JSON 反序列化成 T。
推荐用这种形式。它省掉了 from_str、as_array、get、unwrap_or(0) 这一串样板代码,并把格式不对的回答变成真正的错误,不会变成一个看上去再正常不过的 0。
| Rust | |
|---|---|
- 参数:
- name :
&str - request :
&str
- name :
- 返回值类型:
CallResult<T> - 对应槽位:
service_call
service::call_with¶
| Rust | |
|---|---|
同上,请求那一侧也通过 serde 序列化。
- 参数:
- name :
&str - request :
&Q
- name :
- 返回值类型:
CallResult<T> - 对应槽位:
service_call
service::call_optional¶
| Rust | |
|---|---|
调用,遇到 NotFound 返回 None,其他错误照常抛出。
用于可选的集成:依赖装了就用,没装就降级。这类代码以前写成 let Ok(x) = call(..) else { return default },服务的错误也一起被吞掉了。
- 参数:
- name :
&str - request :
&str
- name :
- 返回值类型:
CallResult<Option<String>> - 对应槽位:
service_call
service::exists¶
| Rust | |
|---|---|
有没有模组提供这个名字。
早先的一代在 service_list 的 JSON 文本里做子串匹配,一个名字是另一个名字的前缀时就会误判,比如 plot 会命中 plot:worlds。这里是真正解析以后再判断。
- 参数:
- name :
&str
- name :
- 返回值类型:
bool - 对应槽位:
service_list
service::list_json¶
| Rust | |
|---|---|
服务列表的原始 JSON,不做解析。
用于 list 解析不了,或者宿主加了这一层不认识的字段的时候。
- 返回值类型:
String - 对应槽位:
service_list
service::list¶
| Rust | |
|---|---|
当前已注册的所有服务。
- 返回值类型:
Vec<ServiceInfo> - 对应槽位:
service_list
service::caller¶
| Rust | |
|---|---|
正在运行的这个服务回调,是谁调用的;见 abi.h 里的 service_caller。
这是提供方对一个请求唯一能信任的东西。请求体想写谁就写谁,按它判断所有者或执行操作的玩家,凭的只是发送方的一面之词;这个函数去问宿主,宿主知道调用栈上是谁的 service::call。嵌套调用时,报告最内层的那一次。
在回调之外、调用没有带模组句柄,或者宿主太旧、没有这个槽位时,返回 None。最后一种情况很重要:想要归属的提供方必须决定拿不到归属时怎么办,「不算到任何人头上」和「拒绝」都说得过去,「算到空名字头上」就说不过去了。
- 返回值类型:
Option<String> - 对应槽位:
service_caller
service::register¶
| Rust | |
|---|---|
注册一个服务。
| Rust | |
|---|---|
几条宿主一侧的规则,这里改不了,值得知道:
- 回调在调用方的线程上同步运行,所以里面不能放任何慢的操作;
- 名字已被占用时直接失败,不会把占用者挤掉;
-
模组被禁用期间,服务仍然可以调用,否则在另一个模组的
on_load里解析它就会失败;禁用期间要不要拒绝,由提供方自己决定。 -
参数:
- name :
&str - provider :
impl FnMut(&str, &str) -> std::result::Result<String - String> + Send + 'static, : ``
- name :
- 返回值类型:
Result<Registration> - 对应槽位:
service_register
service::register_json¶
| Rust | |
|---|---|
注册一个请求和回答都是 JSON 的服务。
它省掉了两边的 to_string 和 from_str 样板代码;反序列化失败会变成一个明确的业务错误返回给调用方,不需要提供方自己写 unwrap_or_default。
- 参数:
- name :
&str - mut provider :
F
- name :
- 返回值类型:
Result<Registration> - 对应槽位:
service_register
Registration¶
服务注册的句柄。丢弃它就会注销。
Registration::forget 让它一直存活到模组卸载,卸载时宿主会清掉剩下的注册。
- 实现的 trait:
Drop
Registration::id¶
| Rust | |
|---|---|
- 返回值类型:
u64
Registration::name¶
| Rust | |
|---|---|
- 返回值类型:
&str
Registration::forget¶
| Rust | |
|---|---|
CallError¶
调用失败的原因。
- 实现的 trait:
Debug、Clone、PartialEq、Eq、Display、Error
CallResult¶
| Rust | |
|---|---|
一次调用的结果。
ServiceInfo¶
| Rust | |
|---|---|
一个服务的注册记录。
- 实现的 trait:
Debug、Clone、PartialEq、Eq、serde::Deserialize