# adapter 3个文件的作用
# api.js
这个文件的代码,系统启动后会变成全局 bot 对象,使用 module.exports 将对象暴露出去,bot 对象方法就取决于 module.exports 属性的值
一般这里导入 HTTP 模块,调用对接平台的 HTTP 接口
var okhttp = require('ok-http').create({
connectTimeout: 5000, // 连接服务器超时时间, 5秒
// followRedirects: 'normal' // 重定向规则
// 以下是请求参数的默认配置
baseUrl: 'http://' + require('environment').getProperty('bot.address'), // 基础url, 设置后, 每次请求都会拼接
headers: { // 请求头, 设置后, 每次请求都会携带
'Content-Type': 'application/json',
'X-Application-Controller': 'yoyo-bot'
}
})
/**
* 默认发送信息
* @param Event event: 事件
* @param String message: 回复
*/
function defaultSendMessage(event, content) {
if (event.isTeam) {
sendGroup(event.groupId, content)
} else {
sendUser(event.userId, content)
}
}
/**
* 发送用户消息
* sendUser(String userId, String message)
* @return String messageId: 消息id
*/
function sendUser(userId, message) {
let res = okhttp.post({
url: '/send_private_msg',
data: {
user_id: String(userId),
message: String(message)
}
})
if (res.data.retcode === 0) {
return String(res.data.data.message_id)
} else {
console.warn('用户消息发送失败(API适配器)\n' + res.data.wording)
return ''
}
}
// 此处省略一万行代码...
module.exports = {
sendUser, 发送用户消息: sendUser,
sendGroup, 发送群消息: sendGroup,
recallMessage, 撤回消息: recallMessage,
deleteGroupMember, 踢出群成员: deleteGroupMember,
muteGroupUser, 禁言群成员: muteGroupUser,
muteGroup, 禁言群: muteGroup,
setGroupAdmin, 设置群管理员: setGroupAdmin,
setGroupUserCard, 设置群成员名片: setGroupUserCard,
setGroupName, 设置群名: setGroupName,
leaveGroup, 离开群: leaveGroup,
dissolveGroup, 解散群: dissolveGroup,
handleFriendRequest, 处理好友申请: handleFriendRequest,
handleGroupRequest, 处理群申请: handleGroupRequest,
handleGroupInvitation, 处理群邀请: handleGroupInvitation,
deleteFriend, 删除好友: deleteFriend,
getSelf, 获取自身信息: getSelf,
getUser, 获取用户信息: getUser,
listFriend, 获取好友列表: listFriend,
getGroup, 获取群: getGroup,
listGroup, 获取群列表: listGroup,
getGroupMember, 获取群成员信息: getGroupMember,
listGroupMember, 获取群成员列表: listGroupMember,
getAtCode, 获取at码: getAtCode, atCode: getAtCode,
getImageCode, 获取图片码: getImageCode, imageCode: getImageCode
}
# router.js
描述了事件该如何路由,路由到哪个组件中,事件会经过 route 函数,他的返回值中的 event 对象,一般作为 action 函数的第一个参数
/*
本套事件解析器和路由器, 根据多数聊天平台事件模型, 抽象出来一套标准事件模型
开发指南:
必须遵循 ES5.1 和 ES6.0(部分), ES6如解构赋值, class不被支持, 将来将支持ES11(2020)及以上(画饼)
模块使用require()导入
必须实现以下函数
1. Route route(String json) 所有的event都会经过此函数, 对event进行路由, 无法路由的event返回undefined或null
Route 对象结构, 对事件进行路由
Route = {
component: string; // 路由目标组件, 系统组件有: message-user, message-group, notice-user, notice-group, 共计 4 个
log: log; // 下面有说明
event: object; // 这个对象可以随便放任何属性
type: string; // 类型
groupId: string; // 群id, 没有就为undefined
teamId: string; // 团队id, 没有就为undefined
userId: string; // 用户id, 没有就为undefined
content: string; // 内容, message-user和message-group组件的type为text/文本需要, 主要为关键词过滤服务
}
Log 对象结构, 主要就是为web日志端渲染日志
Log = {
label: string; // 标签
color: string; // 标签的颜色, 16进制
title: string; // 标题
time: string; // 时间
content: string; // 内容
origin: string; // 来源
}
Event 一般定义如下, 可以随便添加属性, 所有属性非强制
Event = {
isTeam: boolean; // 是否是团队消息, function defaultSendMessage() 用到
groupId: string; // 群id, 没有就为undefined
teamId: string; // 团队id, 没有就为undefined
content: string; // 消息内容
userId: string; // 用户id
messageId: string; // 消息id, 用于撤回消息等, 非消息类型为undefined
selfId: string; // 自身id
userName: string; // 用户名
groupName: string; // 群名
selfName: string; // 自身名
image: object; // 如果是图片消息, 可以选择ocr, 识别出图片内容, 如携带text, url, base64, 鉴黄指数等
}
*/
let remarkConfig = { // 配置对象, 这个对象主要是做用户名和群名缓存, 减少对接口的访问
enableCache: true, // 开启缓存
map: new Map(), // 缓存容器
enableRegularRefresh: true, // 开启定时刷新
lastRefreshTime: 0, // 最后刷新时间
duration: 259200000 // 持续时间
}
let enableImageOcr = false // 开启图片文字识别功能
let ocr = enableImageOcr ? require('yoyo-ocr') : undefined // 导入ocr模块
let logColor = { // log label color 对log对象的标签颜色声明
groupMessage: '#CE93D8', // 淡紫色
groupNotice: '#AB47BC', // 深紫色
userMessage: '#64B5F6', // 淡蓝色
userNotice: '#039BE5' // 深蓝色
}
let okhttp = require('ok-http').create({ // 导入模块, 并创建http请求客户端
connectTimeout: 5000
})
// 事件路由, 总的来说就办了3件事, 设置route对象, 设置event对象, 设置log对象
function route(json) {
let data = JSON.parse(json)
let route = {}
let event = {}
let log = {}
route.event = event
route.log = log
// 设置事件的共有属性
// set self
event.selfId = String(data.self_id)
event.selfName = getRemarkFormCache('user', event.selfId)
event.selfDescription = event.selfName + '(' + event.selfId + ')'
// set user
event.userId = String(data.user_id)
event.userName = getRemarkFormCache('user', event.userId)
event.userDescription = event.userName + '(' + event.userId + ')'
// set group
event.groupId = data.group_id ? String(data.group_id) : undefined
event.groupName = event.groupId ? getRemarkFormCache('group', event.groupId) : undefined
event.groupDescription = event.groupId ? event.groupName + '(' + event.groupId + ')' : undefined
// set chat
event.chatId = event.groupId ? event.groupId : event.userId // 设置聊天id, 在qq里这个属性并不常见
event.chatName = event.groupName ? event.groupName : event.userName
event.chatDescription = event.chatName + '(' + event.chatId + ')'
// set log 设置日志
log.time = getNowTime()
log.title = event.chatDescription
log.origin = event.selfDescription
// log.label
// log.color
// log.content
// set route 设置路由
route.groupId = event.groupId
// route.teamId = ??, 给groupId, 系统会自动识别出teamId
if (data.post_type === 'message') {
event.content = data.message
event.messageId = String(data.message_id)
event.isTeam = Boolean(event.groupId)
route.component = event.groupId ? 'message-team' : 'message-user'
route.content = event.content
event.component = 'message'
// set log
log.color = event.groupId ? logColor.groupMessage : logColor.userMessage
log.content = event.groupId ? event.userDescription + ': ' + event.content : event.content
// 先交给自定义事件消息处理, 他处理不了就是文本消息, 除了不了返回false
let isHandle = parseCustomMessage(data, route, event, log)
if (!isHandle) {
parseTextMessage(data, route, event, log)
}
return route
} else if (data.post_type === 'notice') {
route.component = event.groupId ? 'notice-team' : 'notice-user'
event.component = 'notice'
// set log
log.color = event.groupId ? logColor.groupNotice : logColor.userNotice
if (data.notice_type == 'friend_add') {
parseFriendIncrease(data, route, event, log)
} else if (data.notice_type == 'friend_recall' || data.notice_type == 'group_recall') {
parseRecallMessage(data, route, event, log)
} else if(data.notice_type == 'notify' && data.sub_type == 'poke') {
parsePokeEvent(data, route, event, log)
} else if(data.notice_type == 'group_admin' && data.sub_type == 'set') {
parseGroupAdminIncrease(data, route, event, log)
} else if(data.notice_type == 'group_admin' && data.sub_type == 'unset') {
parseGroupAdminDecrease(data, route, event, log)
} else if(data.notice_type == 'group_upload') {
parseGroupFileUpload(data, route, event, log)
} else if(data.notice_type == 'group_increase') {
parseGroupMemberIncrease(data, route, event, log)
} else if(data.notice_type == 'group_decrease') {
parseGroupMemberDecrease(data, route, event, log)
} else if(data.notice_type == 'group_card') {
parseGroupMemberCardUpdate(data, route, event, log)
} else if(data.notice_type == 'group_ban' && data.sub_type == 'ban'/* && data.hasOwnProperty('user_id') == false*/) {
parseGroupUserMuteEvent(data, route, event, log)
} else if(data.notice_type == 'group_ban' && data.sub_type == 'lift_ban') {
parseGroupMemberUnmute(data, route, event, log)
}
return route
} else if (data.post_type === 'request') {
route.component = event.groupId ? 'notice-team' : 'notice-user'
event.component = 'notice'
// set log
route.log.color = event.groupId ? logColor.groupNotice : logColor.userNotice
if (data.request_type == 'friend') {
parseFriendRequest(data, route, event, log)
} else if (data.request_type == 'group' && data.sub_type == 'add') {
parseGroupRequest(data, route, event, log)
} else if (data.request_type == 'group' && data.sub_type == 'invite') {
parseGroupInvite(data, route, event, log)
}
return route
}
}
// 此处省略一万行代码...
# weber.js
这里定义了 HTTP 接口,函数无需暴露,由系统调度
/**
* 获取全部团队通知事件名
* @return String[] names: 全部群通知事件名
*/
function listTeamNoticeName() {
return [
'群文件上传',
'群管理员增加',
'群管理员减少',
'群成员增加',
'群成员减少',
'群成员禁言',
'群成员取消禁言',
'戳一戳',
'群成员荣誉更新',
'群成员名片更新',
'群申请',
'消息撤回'
]
}
/**
* 获取全部好友通知事件名
* @return Object[] objects
*/
function listUserNoticeName() {
return [
'好友增加',
'消息撤回',
'戳一戳',
'好友请求',
'群邀请'
]
}
/**
* 获取全部自定义消息类型
* @return Object[] objects
*/
function listCustomMessageType() {
return [
'图片',
'表情包',
'json'
]
}
/**
* 获取全部好友
* @return User[]
* User{
* id: String,
* name: String,
* profilePhoto: String
* }
*/
function listFriend() {
return bot.listFriend()
}
/**
* 获取全部团队
* @return Team[]
* Team{
* id: String,
* name: String,
* profilePhoto: String
* }
*/
function listTeam() {
return bot.listGroup()
}
/**
* 获取生产者列表
* @return String[]
*/
function listProducer() {
var self = bot.getSelf()
return [
{
tags: [
{
color: '#32CD99',
text:'QQ'
}
],
text: self.name + '(' + self.id + ')'
}
]
}
function getAdapter() {
return {
version: '0.0.1',
name: 'go-cqhttp',
author: 'undefined'
}
}
function deleteFriend(id) {
bot.deleteFriend(id)
}
function leaveGroup(id) {
bot.leaveGroup(id)
bot.dissolveGroup(id)
}