使用 Unit 来处理消息
# 使用 Unit 来处理消息
Units 是 Hyperai.Units 模块提供的功能,HyperaiShell 内置该模块。
# 在这之前你需要了解...
- 自动引入命名空间
- 去看看前面基础知识中对于中间码的介绍
# 一个 Unit 类
Unit 类通常具有以下特性
- 实现
UnitBase
- 公开(public),非抽象(abstract)
- 使用构造函数注入服务
- 使用方法注入事件参数
- 用特性(attribute)标记消息处理函数
- Unit 之间相互独立,互不干扰
作为 Unit 将能对消息进行处理。生产 Unit 不需要手动注册,HyperaiShell 会自动搜索并添加符合条件的 Unit。这有点类似于 Aspnet MVC 中的 Controller。而消息处理过程被称作 Action。
# 实现 Unit 类
继承 UnitBase
即可。如果提示找不到 UnitBase
类,我建议你换一个 ide 让智能提示来引入命名空间。
# 实现消息处理函数即 Action
一个 Action 函数具有以下特性
- 公开(public),非抽象(abstract)
- 无返回值(void)
- 可以异步修饰
- 使用 attribute 来修饰并指出其特性
- 函数名表意。Action 没有特性(attribute)用来表示其显示名,其函数名会被拿来用作 Action 名字参考
以下是一个 Action 的示例
[Receive(MessageEventType.Group)]
[Extract("!fuck {who}")]
[CheckTicket("ability.to.fuck")]
public async Task Fuck(Member sender, Group group, long who)
{
FuckRecord record = null;
using(sender.For<FuckRecord>(() => new FuckRecord(0), out record))
{
await group.SendAsync($"[hyper.at({sender.Identity})] fucked [hyper.at({who})] the {++record.Count}th time.").MakeMessageChain());
}
}
2
3
4
5
6
7
8
9
10
11
(以上代码不保证在版本迭代后依旧可用。)
(FuckRecord
不属于 HyperaiShell。)
# ReceiveAttribute
表示接收处理特定类型的消息事件。
ReceiveAttribute
接收一个构造参数用来指示目标事件类型。
消息事件的类型枚举在 MessageEventType
中列出。
# ExtractAttribute
匹配特定文本并解释出特定字段用于方法注入。
ExtractAttribute
接收一个字符串参数,该字符串表示一个模式。模式中可以含有以下匹配符
- *,表示任意数量的任意字符,会被编译成正则表达式中的“(.*)”
- {name},表示文本提取,该段文本将被命名为
name
并用在方法的注入当中。
注意
name
只能含有下划线字母和数字,不允许数字开头;必须与方法的注入形参同名,形参类型可以是任意值类型也可以是 MessageChain
。
当类型为 MessageChain
时可以表示任意长度任意数量的消息组件。
在客户端发送消息的时候,需要输入特定命令,但其具有一个非文本类型字段时可以用“{}”占位。例如:“!image.save {}”,然后在下一条消息中单独发送图片。届时 Action 将收到一个仅包含一个 Image
的 MessageChain
类型。由于 string
与 MessageChain
可以互相转换,该参数也可以是以 HyperCode 表达的字符串。有关于 HyperCode 的内容请参阅本文档对应章节。
# CheckTicketAttribute
使用 attribute 的方式来检查发送者权限。权限功能由 Hyperai.Authorization 模块提供并由 HyperaiShell 转为 attribute 方式。
其本质是 FilterByAttribute
,有关于自定义筛选器的内容请参阅 Hyperai.Units 模块的特定章节。
当 CheckTicketAttribute
接收到一个字符串数组时,其检查模式会变成 any,也就是只要有一个符合即通过。如果想要表示多个权限同时具有请将该数组写成多个独立的 CheckTicketAttribute
。(利用的是 FilterByAttribute
全部达成才通过的特性。)
# 在 Unit 中注入服务
聪明的读者在看完依赖注入相关内容并了解到其使用构造函数注入后就已经会了。我相信你是个聪明的人。
# Action 能够注入什么
除了上文提到的 ExtractAttribute
中能注入的来自消息的内容,Action 还可以注入 MessageContext
中的字段(即 MessageContext
中的属性,拗口= =)。
MessageContext
提供有关于该事件相关的大部分对象。其封装传递回收都由 Hyperai.Units 模块完成,具体请参阅模块文档。
提示
除了在方法中注入 MessageContext
外该对象本身还可以通过 UnitBase.Context
直接访问。
ExtractAttribute
作为模式匹配提取了文本参数并用于注入,MessageContext
提供消息事件相关对象,并用于注入,两者具有不同优先级。通常模式匹配提取的字段参数只会找对应的 Action 形参名,只有名字相同才会从模式匹配字段中寻找内容,否则在 MessageContext
中按照形参类型匹配 MessageContext
中的对应类型。类型需要于实际类型完全匹配而非与 MessageContext
中声明的类型匹配,例如 MessageContext.User
类型为 User
但实际传递的可以是 Friend
。此时形参类型需要为 Friend
而非 User
。
(在部分版本中直接注入 User
是可行的,但这么做没什么意义。)