首先要确定接入社交媒体的类型,例如:
QQ类型为qq,
QQ频道类型为qb,
微信类型为wx,
tg客户端类型为tg,
tg官方机器人类型为tb,
这里确定的社交媒体类型不要与内置类型冲突,尽量使用2个字母代指。以下以tt类型为例。
一、HTTP方式连接时的适配器插件编写
即:社交媒体可以设置消息回调地址并提供http api调用的接入方式
(1)autMan会创建一个http服务,用于接收社交媒体的回调消息,地址为:http://autMan地址:端口/媒体类型/receive,例如:http://127.0.0.1:8080/tt/receive,将此地址设置到社交媒体的回调地址里即可,autMan接收的社交媒体的所有消息及事件全部转发给适配器处理,autMan创建的http api仅用于中转。
(2)autMan还会创建一个ws服务,用于和适配器之间进行通信,地址为http://autMan地址:端口/媒体类型/adapter,例如:http://127.0.0.1:8080/tt/adapter
(3)适配器编写时,需要连接到autMan的ws服务地址,建立消息通路。然后等待社交媒体的消息,autMan通过http服务接收到社交媒体的消息时会立即通过ws通道将原始消息转发给适配器(注:适配器也可以启动自己的http api服务用于直接接收社交媒体的回调消息,不经过autMan中转)。适配器要对社交媒体的原始消息进行处理,处理成autMan数据格式(如下:)
Event string `json:"event"` //事件类型
EventData interface{} `json:"event_data"` //事件数据
GuildId string `json:"guild_id"` //社交圈子id
GuildName string `json:"guild_name"` //社交圈子名称
BotId string `json:"bot_id"` //机器人id
BotName string `json:"bot_name"` //机器人名称
ChatId string `json:"chat_id"` //群组id
ChatName string `json:"chat_name"` //群组名称
UserId string `json:"user_id"` //用户id
UserName string `json:"user_name"` //用户名称
ImType string `json:"im_type"` //im类型
MessageId string `json:"message_id"` //消息id
Content string `json:"content"` //消息内容
autMan经过处理后会发送响应数据到适配器
AutAction string `json:"aut_action"`
AutEcho string `json:"aut_echo"`
AutParams interface{} `json:"aut_params"`
适配器将响应数据翻译成社交媒体api要求的格式进行发送即可。
适配器发送回执也是上面的数据格式,比如发送消息成功后,回执autMan 已发送消息的ID,aut_params里直接写id
二、社交媒体为反向WS接入时的适配器插件编写
(1)autMan会创建一个ws服务,用于接收社交媒体的回调消息,地址为:http://autMan地址:端口/媒体类型/receive,例如:http://127.0.0.1:8080/tt/receive,将此地址设置到社交媒体的反向ws地址里即可,autMan接收的社交媒体的所有消息及事件全部转发给适配器处理,autMan创建的ws服务仅用于中转。
(2)autMan还会创建一个ws服务,用于和适配器之间进行通信,地址为http://autMan地址:端口/媒体类型/adapter,例如:http://127.0.0.1:8080/tt/adapter
(3)适配器编写时,需要连接到autMan的ws服务地址,建立消息通路。然后等待社交媒体的消息,autMan接收到社交媒体的消息时会立即通过ws通道将原始消息转发给适配器(注:适配器也可以启动自己的ws服务用于直接接收社交媒体的回调消息和写入响应消息,不经过autMan中转)。适配器要对社交媒体的原始消息进行处理,处理格式同上,autMan经过处理后会发送响应数据到适配器,适配器将响应数据翻译成社交媒体要求的格式后再次发送到autMan ws通道,autMan将会直接将响应消息直接转发社交媒体。如果适配器直接创建了与社交媒体的通信,可直接将响应数据发送到社交媒体。
三、社交媒体提交WS服务时的适配器插件编写
(1)autMan会创建一个ws连接,用于接收社交媒体的回调消息,设置tt数据桶里的url参数为ws连接地址,autMan接收的社交媒体的所有消息及事件全部转发给适配器处理,autMan创建的ws连接仅用于中转。
(2)autMan还会创建一个ws服务,用于和适配器之间进行通信,地址为http://autMan地址:端口/媒体类型/adapter,例如:http://127.0.0.1:8080/tt/adapter
(3)适配器编写时,需要连接到autMan的ws服务地址,建立消息通路。然后等待社交媒体的消息,autMan接收到社交媒体的消息时会立即通过ws通道将原始消息转发给适配器(注:适配器也可以自行连接到社交媒体的ws服务用于直接接收社交媒体的回调消息和写入响应消息,不经过autMan中转)。适配器要对社交媒体的原始消息进行处理,处理格式同上,autMan经过处理后会发送响应数据到适配器,适配器将响应数据翻译成社交媒体要求的格式后再次发送到autMan ws通道,autMan将会直接将响应消息直接转发社交媒体。如果适配器直接创建了与社交媒体的通信,可直接将响应数据发送到社交媒体。
四、示例适配器
下面是某qq框架正向ws接入autMan的适配器,命名为adapter_q1_ws.py,放到plugin/adapters下面即可
'''
@Name: ncqq正向ws接入autMan的适配器
@Author: hdbjlizhe
@Date: 2024-08-25
@FilePath: plugin/adapters/adapter_q1_ws.py
@Description: 启用ncqq的正向ws,下面主函数的url地址为ws://autMan地址:端口/q1/adapter
@Bugs: 适用于autMan版本>=3.0.2,
@Commands:启用命令:set q1 enable true,重启生效
'''
import json
import asyncio
import websockets
async def receive_aut_data(websocket_aut, websocket_im):
async for message in websocket_aut:
#print(f"Received: {message}",flush=True)
# 处理接收到的字符串转为json格式对象
try:
message_json = json.loads(message)
except json.JSONDecodeError as e:
print(f"JSON解析错误: {message}",flush=True)
continue
# 判断消息类型
if "aut_echo" in message_json:#通信控制消息
if message_json["aut_action"]=="reply_message" or message_json["aut_action"]=="push_message":
aut_echo=message_json["aut_echo"]
reply_message = {
"action":"send_private_msg",
"echo":aut_echo,
"params":{
"user_id":int(message_json["aut_params"]["user_id"]),
"message":message_json['aut_params']['content']
},
}
if "chat_id" in message_json["aut_params"] and message_json["aut_params"]["chat_id"]!="":
reply_message["action"]="send_group_msg"
reply_message["params"]["group_id"]=int(message_json["aut_params"]["chat_id"]),
#print(json.dumps(reply_message),flush=True) # 发送回执消息给机器人main
await asyncio.wait_for(websocket_im.send(json.dumps(reply_message)),timeout=1)
elif message_json["aut_action"]=="delete_message" and "aut_params" in message_json and "message_id" in message_json["aut_params"]:
reply_message = {
"action":"delete_msg",
"params":{
"message_id":int(message_json["aut_params"]["message_id"])
},
}
#print(json.dumps(reply_message),flush=True) # 发送回执消息给机器人main
await asyncio.wait_for(websocket_im.send(json.dumps(reply_message)),timeout=1)
async def receive_im_data(websocket_aut, websocket_im):
async for message in websocket_im:
#print(f"Received: {message}",flush=True)
# 处理接收到的字符串转为json格式对象
try:
message_json = json.loads(message)
except json.JSONDecodeError as e:
print(f"JSON解析错误: {message}",flush=True)
continue
# 判断消息类型
if "self_id"in message_json and "message" in message_json:#传过来的消息
# 获取消息内容
commsg={
"bot_id":f"{message_json['self_id']}",
"user_id":f"{message_json['sender']['user_id']}",
"user_name":message_json["sender"]["nickname"],
"im_type":"q1",
"message_id":f"{message_json['message_id']}",
"content":message_json["message"],
"raw_message":message_json["raw_message"]
}
if message_json["message_type"] == "group":
if message_json['group_id']==735467280:
continue
commsg["chat_id"] = f"{message_json['group_id']}"
await asyncio.wait_for(websocket_aut.send(json.dumps(commsg)),timeout=1)
elif "retcode" in message_json and "data" in message_json and "message_id" in message_json["data"]:#im回执消息
reply_message={
"aut_echo":message_json['echo'],
"aut_params":f"{message_json['data']['message_id']}",
}
#print(json.dumps(reply_message),flush=True) # 发送回执消息给机器人main
await asyncio.wait_for(websocket_aut.send(json.dumps(reply_message)),timeout=1)
async def main():
# 与autMan的通信地址ws
uri_aut = "ws://192.168.31.10:9999/q1/adapter"
# 与im的通信地址ws
uri_im = "ws://192.168.31.49:3001"
async with websockets.connect(uri_aut) as websocket_aut , websockets.connect(uri_im) as websocket_im:
# 创建任务
aut_task = asyncio.create_task(receive_aut_data(websocket_aut,websocket_im))
im_task = asyncio.create_task(receive_im_data(websocket_aut,websocket_im))
# 等待任务完成(可以根据需要修改)
await asyncio.gather(aut_task,im_task)
asyncio.run(main())
ncqq反向ws接入autMan的适配器
'''
@Name: ncqq反向ws接入autMan的适配器
@Author: hdbjlizhe
@Date: 2024-08-25
@FilePath: plugin/adapters/adapter_q2_wsr.py
@Description: ncqq的反向ws为ws://autMan地址:端口/q2/receive,下面主函数的url地址为ws://autMan地址:端口/q2/adapter
@Bugs: 适用于autMan版本>=3.0.2,存在websocket长文本传输不完整而卡住的问题。请有能力的同学帮忙解决。
@Commands:启用命令:set q2 enable true,重启生效
'''
import json
import asyncio
import websockets
async def receive_data(websocket):
async for message in websocket:
#print(f"Received: {message}",flush=True)
# 处理接收到的字符串转为json格式对象
try:
message_json = json.loads(message)
except json.JSONDecodeError as e:
print(f"JSON解析错误: {message}",flush=True)
continue
# 判断消息类型
if "self_id"in message_json and "message" in message_json:#传过来的消息
# 获取消息内容
commsg={
"bot_id":f"{message_json['self_id']}",
"user_id":f"{message_json['sender']['user_id']}",
"user_name":message_json["sender"]["nickname"],
"im_type":"q2",
"message_id":f"{message_json['message_id']}",
"content":message_json["message"],
"raw_message":message_json["raw_message"]
}
if message_json["message_type"] == "group":
if message_json['group_id']==735467280:
continue
commsg["chat_id"] = f"{message_json['group_id']}"
await asyncio.wait_for(websocket.send(json.dumps(commsg)),timeout=1)
elif "aut_echo" in message_json:#通信控制消息
if message_json["aut_action"]=="reply_message" or message_json["aut_action"]=="push_message":
aut_echo=message_json["aut_echo"]
reply_message = {
"action":"send_private_msg",
"echo":aut_echo,
"params":{
"user_id":int(message_json["aut_params"]["user_id"]),
"message":message_json['aut_params']['content']
},
}
if "chat_id" in message_json["aut_params"] and message_json["aut_params"]["chat_id"]!="":
reply_message["action"]="send_group_msg"
reply_message["params"]["group_id"]=int(message_json["aut_params"]["chat_id"]),
#print(json.dumps(reply_message),flush=True) # 发送回执消息给机器人main
await asyncio.wait_for(websocket.send(json.dumps(reply_message)),timeout=1)
elif message_json["aut_action"]=="delete_message" and "aut_params" in message_json and "message_id" in message_json["aut_params"]:
reply_message = {
"action":"delete_msg",
"params":{
"message_id":int(message_json["aut_params"]["message_id"])
},
}
#print(json.dumps(reply_message),flush=True) # 发送回执消息给机器人main
await asyncio.wait_for(websocket.send(json.dumps(reply_message)),timeout=1)
elif "retcode" in message_json and "data" in message_json and "message_id" in message_json["data"]:#im回执消息
reply_message={
"aut_echo":message_json['echo'],
"aut_params":f"{message_json['data']['message_id']}",
}
#print(json.dumps(reply_message),flush=True) # 发送回执消息给机器人main
await asyncio.wait_for(websocket.send(json.dumps(reply_message)),timeout=1)
async def main():
uri = "ws://192.168.31.10:9999/q2/adapter"
async with websockets.connect(uri) as websocket:
# 创建任务
consumer_task = asyncio.create_task(receive_data(websocket))
# 等待任务完成(可以根据需要修改)
await asyncio.gather(consumer_task)
asyncio.run(main())
ncqq正向ws接入autMan的适配器,nodejs版本
/*
@Name: ncqq正向ws接入autMan的适配器,nodejs版本
@Author: hdbjlizhe
@Date: 2024-08-25
@FilePath: plugin/adapters/adapter_q3_ws.js
@Description: 启用ncqq的正向ws,下面主函数的url地址为ws://autMan地址:端口/qq/adapter
@Bugs: 适用于autMan版本>=3.0.2,
@Commands:启用命令:set q3 enable true,重启生效
*/
const WebSocket = require('ws');
function receiveAutData(websocketAut, websocketIm) {
websocketAut.on('message', (message) => {
console.log(`Received from autMan: ${message}`);
try {
const messageJson = JSON.parse(message);
if ("aut_echo" in messageJson) {
if (messageJson["aut_action"] === "reply_message" || messageJson["aut_action"] === "push_message") {
const autEcho = messageJson["aut_echo"];
const replyMessage = {
action: "send_private_msg",
echo: autEcho,
params: {
user_id: parseInt(messageJson["aut_params"]["user_id"]),
message: messageJson['aut_params']['content']
}
};
if ("chat_id" in messageJson["aut_params"] && messageJson["aut_params"]["chat_id"]!== "") {
replyMessage.action = "send_group_msg";
replyMessage.params.group_id = parseInt(messageJson["aut_params"]["chat_id"]);
}
websocketIm.send(JSON.stringify(replyMessage));
} else if (messageJson["aut_action"] === "delete_message" && "aut_params" in messageJson && "message_id" in messageJson["aut_params"]) {
const replyMessage = {
action: "delete_msg",
params: {
message_id: parseInt(messageJson["aut_params"]["message_id"])
}
};
websocketIm.send(JSON.stringify(replyMessage));
}
}
} catch (error) {
console.log(`JSON parsing error from autMan: ${message}`);
}
});
}
function receiveImData(websocketAut, websocketIm) {
websocketIm.on('message', (message) => {
console.log(`Received from ncqq: ${message}`);
try {
const messageJson = JSON.parse(message);
if ("self_id" in messageJson && "message" in messageJson) {
const commsg = {
bot_id: messageJson['self_id'].toString(),
user_id: messageJson['sender']['user_id'].toString(),
user_name: messageJson["sender"]["nickname"],
im_type: "q3",
message_id: messageJson['message_id'].toString(),
content: messageJson["message"],
raw_message: messageJson["raw_message"]
};
if (messageJson["message_type"] === "group") {
if (messageJson['group_id']==735467280) {
return;
}
commsg["chat_id"] = messageJson['group_id'].toString();
}
websocketAut.send(JSON.stringify(commsg));
} else if ("retcode" in messageJson && "data" in messageJson && "message_id" in messageJson["data"]) {
const replyMessage = {
aut_echo: messageJson['echo'],
aut_params: messageJson['data']['message_id'].toString()
};
websocketAut.send(JSON.stringify(replyMessage));
}
} catch (error) {
console.log(`JSON parsing error from ncqq: ${message}`);
}
});
}
function main() {
const uriAut = "ws://192.168.31.10:9999/q3/adapter";
const uriIm = "ws://192.168.31.49:3001";
const websocketAut = new WebSocket(uriAut);
const websocketIm = new WebSocket(uriIm);
websocketAut.on('open', () => {
console.log('Connected to autMan');
});
websocketIm.on('open', () => {
console.log('Connected to ncqq');
});
receiveAutData(websocketAut, websocketIm);
receiveImData(websocketAut, websocketIm);
}
main();
ncqq使用http接口接入autMan的适配器
'''
@Name: ncqq使用http接口接入autMan的适配器
@Author: hdbjlizhe
@Date: 2024-08-25
@FilePath: plugin/adapters/adapter_qq_ws.py
@Description: 启用ncqq的http接口服务,修改代码中im_http_api地址,设置ncqq的http回调地址为http://autMan地址:端口/q4/receive,下面主函数的url地址为ws://autMan地址:端口/q4/adapter
@Bugs: 适用于autMan版本>=3.0.2,
@Commands:启用命令:set q4 enable true,重启生效
'''
import aiohttp
import json
import asyncio
import websockets
# ncqq的http接口地址
im_http_api="http://192.168.31.49:3000"
async def receive_aut_data(websocket_aut):
async for message in websocket_aut:
#print(f"Received: {message}",flush=True)
# 处理接收到的字符串转为json格式对象
try:
message_json = json.loads(message)
except json.JSONDecodeError as e:
print(f"JSON解析错误: {message}",flush=True)
continue
# 判断消息类型
# 判断消息类型
if "self_id"in message_json and "message" in message_json:#传过来的消息
# 获取消息内容
commsg={
"bot_id":f"{message_json['self_id']}",
"user_id":f"{message_json['sender']['user_id']}",
"user_name":message_json["sender"]["nickname"],
"im_type":"q4",
"message_id":f"{message_json['message_id']}",
"content":message_json["message"],
"raw_message":message_json["raw_message"]
}
if message_json["message_type"] == "group":
if message_json['group_id']==735467280:
continue
commsg["chat_id"] = f"{message_json['group_id']}"
await asyncio.wait_for(websocket_aut.send(json.dumps(commsg)),timeout=1)
elif "aut_echo" in message_json:#通信控制消息
if message_json["aut_action"]=="reply_message" or message_json["aut_action"]=="push_message":
aut_echo=message_json["aut_echo"]
reply_message = {
"action":"/send_private_msg",
"params":{
"user_id":int(message_json["aut_params"]["user_id"]),
"message":message_json['aut_params']['content']
},
}
if "chat_id" in message_json["aut_params"] and message_json["aut_params"]["chat_id"]!="":
reply_message["action"]="/send_group_msg"
reply_message["params"]["group_id"]=int(message_json["aut_params"]["chat_id"]),
#print(json.dumps(reply_message),flush=True) # 发送回执消息给机器人main
message_id = await post_data(reply_message["action"],reply_message["params"])
if message_id!=None:
reply_message={
"aut_echo":aut_echo,
"aut_params":f"{message_id}",
}
#print(json.dumps(reply_message),flush=True) # 发送回执消息给机器人main
await asyncio.wait_for(websocket_aut.send(json.dumps(reply_message)),timeout=1)
elif message_json["aut_action"]=="delete_message" and "aut_params" in message_json and "message_id" in message_json["aut_params"]:
reply_message = {
"action":"delete_msg",
"params":{
"message_id":int(message_json["aut_params"]["message_id"])
},
}
#print(json.dumps(reply_message),flush=True) # 发送回执消息给机器人main
await post_data(reply_message["action"],reply_message["params"])
async def post_data(url, data):
async with aiohttp.ClientSession() as session:
async with session.post(im_http_api + url, json=data) as response:
if response.status == 200:
try:
# Assuming JSON response with "messageid" field
content = await response.json()
message_id = content['data']['message_id']
#print(f"Messageid: {message_id}", flush=True)
return message_id
except (aiohttp.client_exceptions.ContentTypeError, KeyError):
# Handle non-JSON response or missing "messageid" field
print(f"Error: Unexpected response format for {url}")
return None
else:
print(f"POST {url} failed with status {response.status}", flush=True)
return None # Indicate error
async def main():
# 与autMan的通信地址ws
uri_aut = "ws://192.168.31.10:9999/q4/adapter"
async with websockets.connect(uri_aut) as websocket_aut:
# 创建任务
aut_task = asyncio.create_task(receive_aut_data(websocket_aut))
# 等待任务完成(可以根据需要修改)
await asyncio.gather(aut_task)
asyncio.run(main())
标签:教程,适配器,autMan,json,params,aut,message,id
From: https://blog.csdn.net/sinat_36129516/article/details/143231398