Class Api<P,R>

java.lang.Object
io.github.theword.queqiao.core.api.Api<P,R>
Type Parameters:
P - 负载类型
R - 返回类型
Direct Known Subclasses:
GetStatusApi, PlatformApi, SendCommandApi, SendRconCommandApi

public abstract class Api<P,R> extends Object
协议 API 抽象基类

一个 Api 就是一个可被客户端调用的协议接口。它自描述——名字由 name() 声明, 别名由 aliases() 声明,而不是在外部注册表里配对,因此新增 api 不需要修改路由代码。

负载解析由框架代劳:execute(JsonElement) 是 final 模板方法, 负责把原始 JSON 解析成 payloadType 并做错误映射; 子类只需实现 doExecute(Object) 处理已经解析好的负载。

平台结果统一转换:平台能力统一返回 PlatformResult, 子类用 requireSuccess(PlatformResult) 取成功数据即可,失败会自动转成 ProtocolException。通用映射由 mapPlatformResult(PlatformResult) 提供, 只有需要特殊协议语义的 Api 才覆盖它——不要在 doExecute 里写完整的 switch。

依赖由子类自行注入:本基类只持有 Logger 这一项基础设施, 不持有任何平台能力。Logger 是输出通道而非能力——持有它无法对世界产生副作用, 因此不构成"每个 Api 都能看见全部能力"的隐式耦合;真正需要平台能力的 Api 请继承 PlatformApi,其余依赖仍在子类构造器里显式接收。

日志使用约定:基类提供 logger 是为了让每个 Api 都有能力打日志, 而不是要求每个 Api 都必须打日志。只在有诊断价值的位置输出, 不要为每次调用机械补一行日志。级别建议:

  • debug —— 正常流程细节(收到请求、命中缓存);可能被高频轮询的接口一律用 debug
  • info —— 状态变更(如已广播、已执行 Rcon 命令)
  • warn —— 被拒绝的请求(参数非法、平台不支持)
  • error —— 未预期异常;此类日志由 ProtocolRouter 统一记录,子类一般不必重复

线程安全约束(重要):Api 实例由 ProtocolRouter 在构造阶段创建一次, 随后在多个连接、多个线程之间共享。因此实现必须无状态—— 不得持有任何随请求变化的字段。全部输入应来自方法参数,输出通过返回值表达。 违反该约束会引入静默的数据竞争:不同连接的请求会互相污染中间状态。

不访问静态全局状态:所有依赖(含 Logger)应由构造器注入, 否则协议层将无法脱离全局上下文独立测试。

  • Field Details

    • logger

      protected final org.slf4j.Logger logger
      日志实现

      基类唯一持有的非负载依赖,由创建方注入。 子类直接使用本字段,不应再自己保存一份。

  • Constructor Details

    • Api

      protected Api(Class<P> payloadType, org.slf4j.Logger logger)
      Parameters:
      payloadType - 负载类型,不得为 null
      logger - 日志实现,不得为 null
  • Method Details

    • name

      public abstract String name()
      协议 api 字段的主名字,例如 "broadcast"
      Returns:
      api 名字
    • aliases

      public Set<String> aliases()
      别名

      用于"同一操作有多个协议名"的情况,例如 broadcast 与 send_msg 由同一个 Api 实例服务。

      Returns:
      别名集合,默认空集合
    • execute

      public final R execute(com.google.gson.JsonElement data) throws ProtocolException
      处理一个请求

      模板方法:解析负载 → 委托 doExecute(Object)。子类不应覆盖。

      Parameters:
      data - 原始 JSON 负载,可为 null
      Returns:
      处理结果
      Throws:
      ProtocolException - 请求不合法或处理失败
    • doExecute

      protected abstract R doExecute(P payload) throws ProtocolException
      处理已经解析好的负载
      Parameters:
      payload - 负载,永不为 null
      Returns:
      处理结果
      Throws:
      ProtocolException - 处理失败
    • requireSuccess

      protected final <T> T requireSuccess(PlatformResult<T> result) throws ProtocolException
      取出平台操作的成功数据;失败时抛出由 mapPlatformResult(PlatformResult) 映射的协议异常
      Type Parameters:
      T - 数据类型
      Parameters:
      result - 平台结果,不得为 null
      Returns:
      成功数据(可能为 null,Void 场景)
      Throws:
      ProtocolException - 平台结果非成功时
    • mapPlatformResult

      protected ProtocolException mapPlatformResult(PlatformResult<?> result)
      把平台失败结果映射为协议异常

      默认映射(Java 8 的传统 switch;状态码语义以 ProtocolException 现有工厂为准):

      覆盖而非替换:子类只处理自己关心的结果码,其余交回 super, 从而避免每个 Api 重复编写完整的 switch。

      Parameters:
      result - 平台失败结果,不得为 null
      Returns:
      对应的协议异常