# 多账号
>[danger] 当前文档为 `1.x` 版本的文档。simple-robot 1.x 版本已经被认定为过时且停止维护,请前往 `2.x` 版本文档:https://www.yuque.com/simpler-robot/simpler-robot-doc
> 核心`1.8.0`开始支持多账号功能。
>[warning] 并不是每一个插件都可以完美支持多账号功能的全部特性,具体注意事项以组件的具体说明为准。
由于多账号功能更新后有不少改动,因此专门使用单独章节介绍。
>[info] 一般来讲,注册一个账号信息需要两个值:账号与请求地址。而大多数情况下,账号是不必要的,因为如果你的请求地址正确,再验证的时候会自动获取到你的账号信息。但是假如你指定了账号的值,那么在获取到信息后会在对**你指定的值**与**获取到的值**进行一次匹配。
## **账号注册**
在启动的时候,至少需要注册一个BOT。而在程序运行期间,有可能需要额外注册一些BOT。那么综上所述,账号注册的方式存在两种:**初始注册** 与 **动态注册**。
### **初始注册**
初始注册即启动的时候就会注册的账号。初始注册的方式有三种,但是都与配置有关,所以你可以在[配置](./配置文件.md)中找到关于账号注册的相关信息。这里我将它们单独拿出来再简单介绍一下:
#### **代码配置**
代码配置中共有6种方法,两个方法名,分别是`registerBot` 与 `registerBotAsDefault`
```java
/**
* 注册一个机器人的信息。
*
* @param botCode bot账号
* @param path 上报地址,为一个完整的请求路径,例如:http://127.0.0.1:12345
*/
public void registerBot(String botCode, String path);
/**
* 注册一个机器人的信息。
一般来讲最终拼接为:http://{ip}:{port}{path}
* @param botCode bot账号
* @param ip 上报地址的ip
* @param port 上报地址的端口
* @param path 如果存在,上报地址的路径
*/
public void registerBot(String botCode, String ip, int port, String path);
/**
* 仅仅注册一个路径信息,需要是一个完整路径,例如一个http路径或者一个ws的连接路径。
* 在启动后需要通过此路径来验证或者连接。
* 一般来说直接使用这个就行了。
*
* @param path 上报路径
*/
public void registerBot(String path);
/**
* 仅注册一个路径信息,信息分为ip、端口、一个可能存在的额外路径。
* 开发者如果需要实现对于ip、端口、额外路径的转化规则,尝试重写{@link #toHttpPath(String, int, String)}方法。默认情况下为转化为http协议路径。
* @param ip ip地址
* @param port 端口
* @param path nullable
*/
public void registerBot(String ip, int port, String path);
/**
* 注册一个机器人的信息。与普通的registerBot不同,此处注册的机器人会直接覆盖当前的默认机器人信息
*
* @param botCode bot账号
* @param path 上报地址,为一个完整的请求路径
*/
public void registerBotAsDefault(String botCode, String path);
/**
* 注册一个机器人的信息。
* @param botCode bot账号
* @param ip 上报地址的ip
* @param port 上报地址的端口
* @param path 如果存在,上报地址的路径
*/
public void registerBotAsDefault(String botCode, String ip, int port, String path);
/**
* 仅仅注册一个路径信息,需要是一个完整路径,例如一个http路径或者一个ws的连接路径。
* 在启动后需要通过此路径来验证或者连接
*
* @param path 上报路径
*/
public void registerBotAsDefault(String path);
/**
* <pre> 仅注册一个路径信息,信息分为ip、端口、一个可能存在的额外路径。
* <pre> 开发者如果需要实现对于ip、端口、额外路径的转化规则,尝试重写{@link #toHttpPath(String, int, String)}方法。默认情况下为转化为http协议路径。
* @param ip ip地址
* @param port 端口
* @param path nullable
*/
public void registerBotAsDefault(String ip, int port, String path);
```
虽然方法很多,但是最终都是同一个结果:注册了一个账号与请求路径的对应信息。其中,账号可以省略。
#### **文件配置**
文件配置中,多账号的配置项名称为`core.bots`,
起始状态所注册的bot账号列表的格式:`{code}:{path},{code}:{path},....`, 其中{code}可以是空的。
其中,`{code}:{path}`为一组信息。
一组账号与地址使用冒号分割,多组信息使用逗号分割
如果为空,则默认注册一个本地ip地址:`:http://127.0.0.1:5700`
**例1**(不省略账号信息):
`11111111:http://127.0.0.1:8080,2222222:http://192.168.0.1:7777`
**例2**(省略账号信息):
`:http://127.0.0.1:8080,:http://192.168.0.1:7777`
>[warning] 在省略了账号信息的时候,请记住它们中间的那个冒号`:`不可以省略哦
配置文件的例子:
```java
core.bots=:http://127.0.0.1:5700
```
#### **注解配置**
注解配置是核心`1.8.0`的新功能,其配置映射格式与文件配置相同,这里举个例子:
```java
@SimpleRobotConfiguration({
@ConfigurationProperty(key = "core.bots", value = ":http://127.0.0.1:5700"),
// 其他配置......
})
public class Test1 {
// do some..
}
```
### **动态注册**
当程序运行期间,你想要注册一个BOT,你也有那么几个选择。
#### **BotRuntime**
`BotRuntime`类是一个框架启动完成后被初始化的类,你可以直接使用`BotRuntime.getRuntime()`来获取他的实例,然后你可以通过它的`getBotManager()`方法来获取一个`BotManager`对象。
#### **BotManager**
除了上述的使用`BotRuntime`类来获取`BotManager`对象以外,理论上你可以直接将`BotManager`对象作为依赖注入的参数放在类字段上或者监听函数的参数上。哦,不要忘记了`@Depend`注解。
当你得到`BotManager`类实例的时候,你会发现他其中包括了5个`registerBot`方法的重载。这5个方法的含义与上述的**代码配置**中提到的注册方法大致相同,所以,直接注册即可。
如果最终验证成功,你便可以使用了。
<br>
## **BotManager**
在接着向下介绍之前,先介绍一下`BotManager`类。
`BotManager`是对多BOT的管理中心,它是一个接口类型,其中所定义的全部API如下:
```java
/**
* 大多数情况下,可能不一定必须指定一个bot,则此方法规定获取一个默认的bot
* @return 获取一个默认bot
*/
BotInfo defaultBot();
/**
* 设置默认bot的账号信息
* @param botCode 默认bot的账号信息
*/
void setDefaultBot(String botCode);
/**
* 通过bot的code获取一个Bot的信息
* 参数有可能为null
* @param botCode 账号
* @return bot信息
*/
BotInfo getBot(String botCode);
/**
* 获取全部的bot信息
* @return bots
*/
BotInfo[] bots();
/**
* 注册一个botInfo。在实现的时候需要注意线程安全问题,概率较小,但是不是没有可能
* @param info bot信息,作为key的code信息将会从其中获取。info中的各项参数不可为null
* @return 是否注册成功
*/
boolean registerBot(BotInfo info);
/**
* 注册一个bot。
* @param code 账号, 可以为null
* @param ip ip地址
* @param port 端口号
* @param path 请求路径
* @return 是否注册成功
*/
boolean registerBot(String code, String ip, int port, String path);
/**
* 注册一个bot。
* @param code 账号, 可以为null
* @param fullPath 完整路径
* @return 是否注册成功
*/
boolean registerBot(String code, String fullPath);
/**
* 注册一个bot。code为null
* @param ip ip地址
* @param port 端口号
* @param path 请求路径
* @return 是否注册成功
*/
boolean registerBot(String ip, int port, String path);
/**
* 注册一个bot。code为null
* @param fullPath 完整路径
* @return 是否注册成功
*/
boolean registerBot(String fullPath);
/**
* 获取注册用的验证函数
*
* @return 验证函数
*/
VerifyFunction getVerifyFunction();
/**
* 获取路径拼接函数
* @return 拼接函数
*/
PathAssembler getPathAssembler();
```
## **使用**
使用多账号来发送消息有很多种办法。一般想要使用指定的BOT来发送消息,首先需要获得这个BOT验证过的`BotInfo`对象。
### **BotInfo**
`BotInfo`对象是对一个已经注册的BOT的信息封装,其中包括这个BOT的账号(`code`)、上报地址(`path`)、登录信息(`LoginInfo`)以及其对应的三大送信器(`BotSender`)。
`BotInfo`为接口类型,其定义如下:
```java
/**
* 获取Bot的账号信息
* @return Bot账号信息
*/
String getBotCode();
/**
* 获取此bot的上报信息
* @return bot上报信息
*/
String getPath();
/**
* 获取此账号的登录信息
* @return 获取登录信息
*/
LoginInfo getInfo();
/**
* 获取当前bot所对应的送信器
* @return 当前账号送信器
*/
BotSender getSender();
```
### **BotSender**
`BotSender`就是一个BOT专属版的`MsgSender`,这个类里只有三个公共常量:
`SENDER`、`GETTER`、`SETTER`
是不是很眼熟?就像平时那样用就好了。
```java
// 获取botInfo
BotInfo bot = botManager.getBot("111");
// 获取BotSender
BotSender sender = bot.getSender();
// 发送消息
sender.SENDER.sendPrivateMsg("22222", "hi");
// 或者,连起来
botManager.getBot("111").getSender().SENDER.sendPrivateMsg("22222", "hi");
```
<br>
*****
>[success] 那么我应该如何获取上面提到的`BotInfo`和`BotSender`呢?
#### **BotManager**
当你得到`BotManager`类实例的时候(上面**动态注册**提到过如何获取了),可以通过以下方法获得一个或多个`BotInfo`对象:
```java
/**
* 大多数情况下,可能不一定必须指定一个bot,则此方法规定获取一个默认的bot
* @return 获取一个默认bot
*/
BotInfo defaultBot();
/**
* 通过bot的code获取一个Bot的信息
* 参数有可能为null
* @param botCode 账号
* @return bot信息
*/
BotInfo getBot(String botCode);
/**
* 获取全部的bot信息
* @return bots
*/
BotInfo[] bots();
```
#### **MsgSender**
送信器`MsgSender`中增加了4个方法以获取`BotInfo`或`BotSender`:
```java
/**
* 获取一个指定的Bot对象
* @param botCode botCode
* @return {@link BotInfo} bot信息
*/
public BotInfo bot(String botCode);
/**
* 获取一个默认的Bot对象
* @return {@link BotInfo} bot信息
*/
public BotInfo bot();
/**
* 获取一个指定bot的送信器
* @param botCode bot账号
* @return bot送信器
*/
public BotSender botSender(String botCode);
/**
* 获取默认的Bot送信器
* @return bot送信器
*/
public BotSender botSender();
```
直接使用就好喽:
```java
@Listen(MsgGetTypes.privateMsg)
@Filter("hello.*")
public void testListen1(PrivateMsg msg, MsgSender sender) {
sender.botSender("22222").SENDER.sendPrivateMsg("66666", "hello~");
}
```
## **送信器机制变动**
看到这里不知道你有没有一些小小的疑问或猜想:如果在`MsgSender`中使用原本的送信器而不去获取指定bot的送信器,那么我到底是哪个BOT发送的消息呢?
<br>
举个例子:
```java
@Listen(MsgGetTypes.privateMsg)
@Filter("hello.*")
public void testListen1(PrivateMsg msg, MsgSender sender) {
sender.SENDER.sendPrivateMsg("66666", "hello~");
}
```
> 这种情况下,我到底是用谁发送的消息呢?
### ThisCodeAble
在核心`1.7.0`之后,我在[监听消息API](./监听消息API.md)中的信息携带者里增加了一个携带者:`接收者信息携带者 ThisCodeAble`。
简单来说,`ThisCodeAble`是一个接口类型,它定义了两个方法:
```java
/**
* 此消息获取的时候,代表的是哪个账号获取到的消息。
* @return 接收到此消息的账号。
*/
String getThisCode();
/**
* 允许重新定义Code以实现在存在多个机器人的时候切换处理。
* @param code code
*/
void setThisCode(String code);
```
允许你去获取或者设置当前消息是由哪个BOT接收到的。而这个接口被`MsgGet`接口所继承。如果有仔细读我的文档的话应该会知道,`MsgGet`是所有监听消息封装类的父类接口,因此所有的监听消息均得到了获取到自身BOT的能力,并且你可以重新设置它。
>[info] 比如最常见的`GroupMsg`与`PrivateMsg`。
为什么要提到这个呢?因为在`1.8.0`更新后,`MsgSender`在一般情况下会随着当前消息的BOT账号的变化而变化。
简单举个例子:
```java
@Listen(MsgGetTypes.privateMsg)
public void testListen1(PrivateMsg msg, MsgSender sender) {
System.out.println(msg.getThisCode()); // 假设当前BOT账号为11111
// 此时,由账号"11111"向好友"12345"发送了一个"hello"
sender.SENDER.sendPrivateMsg("12345", "hello");
// 重新设置BOT账号为22222
msg.setThisCode("22222");
// 此时,由账号"22222"向好友"12345"发送了一个"hello"
sender.SENDER.sendPrivateMsg("12345", "hello");
}
```
即,当前消息中的Msg中的`ThisCode`发生变化的时候,`MsgSender`内部默认的BOT账号会一同发生变化。
>[danger] 上述特性取决于插件是否支持在上报数据中存在BOT信息。CQ HTTP API插件支持上述特性,但是LEMOC无法支持上述特性。
>[warning] 当插件无法支持上述特性的时候,一般来讲`MsgSender`所使用的默认送信BOT为注册的时候所指定的默认BOT。如果没有指定,则为注册的第一个BOT。
- 前言
- 简单介绍
- 我该如何阅读文档
- 视频教程
- 安装与使用
- 开源协议
- 免责&捐助
- 注意事项
- 版本命名规则简介
- 主要功能版本历史
- 功能指引
- 通用API与功能
- 国际化语言
- 异常
- 消息监听
- @Listen
- @OnListen模板
- @Filter
- 消息参数截取
- @Spare
- @Constr
- @Ignore
- @ListenBreak
- @ListenBreakPlugin
- @ListenBody
- 监听响应
- 成功判定与返回值
- 监听上下文
- 动态参数
- 监听消息API
- 异步监听 @Async
- 限流监听 @Limit
- 自定义Http送信器
- 枚举与类型
- 送信器
- SENDER
- SETTER
- GETTER
- 返回值
- 其他位置
- 日志与日志拦截
- 异常处理
- 依赖注入
- 自定义依赖获取
- 批量依赖载入
- 注意事项
- 常量
- 定时任务
- 自定义过滤
- 拦截器
- 拦截器总定义
- 上下文对象总定义
- 监听消息拦截
- 送信器拦截
- 监听函数拦截
- CAT码
- CQ码
- CQCode
- CQ码工具类
- CQ扩展工具类
- AppendList拼接链
- 高级内容
- 阻断机制
- 截断机制
- 自定义枚举类型
- 枚举工厂
- byName注解
- 自定义注解
- 配置
- 文件配置
- 注解配置
- 参数配置
- 多配置
- 多账号
- 自定义账号管理器
- 小心!
- 核心版本与组件如何升级核心
- 核心版本迭代指南
- 核心
- 更新日志
- jar包与依赖
- 监听消息类结构图
- 快速启动
- 模组与扩展
- 模组开发
- 现有模组
- 通用模组-延时任务
- 通用模组-CQ码工具
- 转义器
- CQ码操作工具类
- CQ码模板-CodeTemplate
- CQ码载体-KQCode
- CQ码构建器
- MQ码工具类
- 通用模组-redis-bot管理器
- 通用模组-Debugger
- Debugger-common模块
- Debugger-server模块
- Debugger-client模块
- 通用模组-钉钉机器人
- 组件-Mirai(JVM)
- 快速开始(1.13+)
- springboot-starter
- 注意事项
- 配置
- 额外的内容
- 快速回复
- 额外监听
- CQ码解析
- 组件-酷Q(QQ)-CQ HTTP API(基本失效)
- 快速开始(推荐)
- 快速开始(1.7.x以下,不推荐)
- 快速开始(Springboot启动器)
- 启动器、启动接口与配置类
- 配置
- 文件配置
- 注意事项
- 更新日志
- 额外的内容
- 自定义额外监听
- CQ送信器
- 元事件
- 监听消息类结构图
- 组件-酷Q(QQ)-JCQ(失效)
- 快速开始
- 更新日志
- 额外的内容
- JCQ日志
- 配置
- 注意事项
- 监听消息类结构图
- 组件-酷Q(QQ)-HTTP TO CQ(失效)
- 快速开始(核心1.7.x及以下)
- 启动器、启动接口与配置类
- 配置
- 文件配置
- 注意事项
- 更新日志
- 监听消息类结构图
- 组件-酷Q(QQ)-LEMOC (失效)
- 快速开始(核心1.7.x及以下)
- 配置
- 注意事项
- 更新日志
- 监听消息类结构图
- Springboot快速启动器
- 常见问题汇总
- BUG反馈
- 更新计划总览