Skip to content

9. 贡献

SlimeNull edited this page Jun 9, 2023 · 2 revisions

这个库对于使用者来说是非常友好的, 但是对于开发者可能就不是很友好了. 因为它的封装, 背后有着很麻烦的逻辑.

🧬 项目结构

|
├─Action                       ├─用户要使用到的各种 CqAction
│  ├─Model                     |  ├─操作的模型
│  │  ├─Params                 |  ├─CqAction 进行调用时所需要的具体参数 (用户不可见)
│  │  └─ResultData             |  ├─CqActionResult 返回时要读取的具体数据 (用户不可见)
│  ├─Result                    |  ├─用户要使用到的各种 CqActionResult
│  └─Sender                    |  └─用来发送 CqAction 的各个协议实现
├─DataStructure                ├─CqAction 参数或返回数据中所使用到的各种结构
│  └─Model                     |  └─CqAction 参数或返回数据中所使用到的各种结构的实际传输声明 (用户不可见)
├─Enumeration                  ├─所有枚举类型
├─Extension                    ├─所有拓展方法
├─JsonConverter                ├─程序集所需要使用的 JSON 转换器 (用户不可见)
├─Message                      ├─用户会用到的各种消息类型
│  ├─CqCodeDef                 |  ├─CQ 码操作类
│  ├─DataModel                 |  ├─消息的实际传输数据模型 (用户不可见)
│  └─JsonConverter             |  └─某些特殊消息需要使用到的 JSON 转换器 (用户不可见)
├─Model                        ├─公共的数据模型
├─Post                         ├─消息上报的各种类型
│  ├─Base                      |  ├─一些基类
│  ├─JsonConverter             |  ├─上报的 JSON 转换器
│  ├─Model                     |  ├─上报的模型
│  │  └─Base                   |  |  └─上报模型基类
│  └─QuickOperation            |  └─上报的快速操作
└─Utils                        └─各种工具类

🪧 命名空间

using EleCho.GoCqHttpSdk;            // 基础命名空间, 包含 CqSession, 拓展方法等
using EleCho.GoCqHttpSdk.Action;     // 所有 Action 声明
using EleCho.GoCqHttpSdk.Post;       // 所有上报声明
using EleCho.GoCqHttpSdk.Message;    // 所有消息声明

🪄 主要逻辑

因为 go-cqhttp 给的数据, JSON 都是小驼峰, 并且为了用户操作上的便捷, 所以 JSON 解析上使用了以下方法:

  1. 分为用户的操作类和具体调用时使用的 Model 类
  2. 在调用接口, 或者解析上报的时候, 两种类会相互转换
  3. 一些原始 Model 类中的 data 字段, 或者 params 字段, 他们在用户的操作类中直接作为类型成员存在, 而不独立分出一个 dataparams 成员存放.

同时, 为了用户操作的便捷, 用户所操作的类与实际传输使用的类, 字段格式是不一样的, 例如在 Music 消息中 sub_type 表示该 Music 消息的音乐类型, 于是在用户的操作类中, 它使用 MusicType 命名.

消息

首先是 go-cqhttp 中的基础消息类型, 也就是 CQ 码(CQ Code):

它的 JSON 格式是这样的:

{
    "type": "消息类型",
    "data": {
        // 消息的数据
    }
}

如果让用户访问 data 然后访问它的成员, 肯定有些繁琐, 所以在用户操作的类中, 是这样的:

public class CqXxxMsg : CqMsg
{
    public override string Type => "消息类型";  // Type 是不允许用户修改的, 一个类型对应一个 Type
    
    // 直接将消息数据作为消息的成员
}

上报

上报的原始数据 JSON 格式中, 并没有专门为数据抽出一个 data 字段, 所以不做特殊处理.

Action

Action 在 go-cqhttp 中的 JSON 格式与消息类似, 它为参数抽出了一个 params 字段, 然后将所有参数放在这个字段中. 所以在这方面, 做了与消息类型近似的处理, 也就是直接将参数独立出来, 而不是放在 params 字段中.

同样, ActionResult(Action 调用的返回结果) 也将数据放在了 data 字段中, 所以同样做了特殊处理.

📚 编写规范

下面是编写时可能提供帮助的一些规范:

虽然库的有些内部代码真的很丑(例如命名), 但这是为了外部访问的便捷而做出的妥协, 实属无奈之举.

编写步骤

编写一个 Action 的参考步骤:

  1. 添加 CqActionType 成员
  2. 添加 Consts.ActionType 成员
  3. CqEnum 中实现 CqActionType 转字符串
  4. 编写它的 CqAction
  5. 编写它的 CqActionParamsModel 类 (internal, 有一个全参构造函数, 成员名称为原始名称)
  6. 编写它的 CqActionResult 类 (不能有公开构造函数, 因为用户不能创建它的实例)
  7. 编写它的 CqActionResultDataModel 类 (internal, 只有 JSON 构造函数, 成员名称为原始名称)
  8. 实现 CqActionResult.FromRaw
  9. 实现 CqActionResultDataModel.FromRaw
  10. CqActionSessionExtensions 中添加对应拓展方法

编写一个 CqMsg 的参考步骤:

  1. 添加 CqMsgType 成员
  2. 编写它的 CqMsg
  3. 编写它的 CqMsgDataModel 类 (internal, 一个无参构造函数, 一个全参构造函数)
  4. 实现它在 CqMsgModelConverter 中的转换
  5. 实现它在 CqCode.ModelChainFromCqCodeString 中的转换

命名规范

  • 尽量将缩写改为全称, 尽量将奇怪的名称改为正常的名称
    例如: SetGroupBan -> BanGroupMember (禁言群成员)
  • 尽量将错误的名称改为正确的名称
    例如: CheckUrlSafely -> CheckUrlSafety (检查链接安全性)

类型声明提示

  • 在原文档中以 number 标识的类型, 统一使用 long, 否则可能会溢出
  • 在原文档中, 消息 ID 有的地方声明为 int32, 有的地方声明为 int64, 在本库中, 将统一使用 int64