add:完善指令处理模块

This commit is contained in:
Sheyiyuan 2025-04-22 12:28:44 +08:00
parent 995fba34b4
commit 9e47650032
11 changed files with 1163 additions and 632 deletions

207
core/api_wsd.go Normal file
View File

@ -0,0 +1,207 @@
package core
import (
"ProjectWIND/database"
"ProjectWIND/wba"
"fmt"
)
//database模块
// //数据库部分允许字符串变量的读写操作,允许读取配置项操作
type databaseInfo struct{}
func (dbi *databaseInfo) varSet(app wba.AppInfo, datamap string, unit string, id string, key string, value string) {
database.Set(app.AppKey.Name, datamap, unit, id, key, value)
}
func (dbi *databaseInfo) SetUserVariable(app wba.AppInfo, msg wba.MessageEventInfo, key string, value string) {
id := fmt.Sprintf("%d", msg.UserId)
dbi.varSet(app, app.AppKey.Name, "user", id, key, value)
}
func (dbi *databaseInfo) SetGroupVariable(app wba.AppInfo, msg wba.MessageEventInfo, key string, value string) {
var id string
if msg.MessageType == "group" {
id = "group_" + fmt.Sprintf("%d", msg.GroupId)
}
if msg.MessageType == "private" {
id = "user_" + fmt.Sprintf("%d", msg.UserId)
}
dbi.varSet(app, app.AppKey.Name, "group", id, key, value)
}
func (dbi *databaseInfo) SetOutUserVariable(app wba.AppInfo, datamap string, msg wba.MessageEventInfo, key string, value string) {
id := fmt.Sprintf("%d", msg.UserId)
dbi.varSet(app, datamap, "user", id, key, value)
}
func (dbi *databaseInfo) SetOutGroupVariable(app wba.AppInfo, datamap string, msg wba.MessageEventInfo, key string, value string) {
var id string
if msg.MessageType == "group" {
id = "group_" + fmt.Sprintf("%d", msg.GroupId)
}
if msg.MessageType == "private" {
id = "user_" + fmt.Sprintf("%d", msg.UserId)
}
dbi.varSet(app, datamap, "group", id, key, value)
}
func (dbi *databaseInfo) UnsafelySetUserVariable(app wba.AppInfo, id string, key string, value string) {
dbi.varSet(app, app.AppKey.Name, "user", id, key, value)
}
func (dbi *databaseInfo) UnsafelySetGroupVariable(app wba.AppInfo, id string, key string, value string) {
dbi.varSet(app, app.AppKey.Name, "group", id, key, value)
}
func (dbi *databaseInfo) UnsafelySetGlobalVariable(app wba.AppInfo, id string, key string, value string) {
dbi.varSet(app, app.AppKey.Name, "global", id, key, value)
}
func (dbi *databaseInfo) UnsafelySetOutUserVariable(app wba.AppInfo, datamap string, id string, key string, value string) {
dbi.varSet(app, datamap, "user", id, key, value)
}
func (dbi *databaseInfo) UnsafelySetOutGroupVariable(app wba.AppInfo, datamap string, id string, key string, value string) {
dbi.varSet(app, datamap, "group", id, key, value)
}
func (dbi *databaseInfo) UnsafelySetOutGlobalVariable(app wba.AppInfo, datamap string, id string, key string, value string) {
dbi.varSet(app, datamap, "global", id, key, value)
}
func (dbi *databaseInfo) varGet(app wba.AppInfo, datamap string, unit string, id string, key string) (string, bool) {
res, ok := database.Get(app.AppKey.Name, datamap, unit, id, key, false)
if !ok {
return "", false
}
resStr, ok := res.(string)
if !ok {
return "", false
}
return resStr, true
}
func (dbi *databaseInfo) GetUserVariable(app wba.AppInfo, msg wba.MessageEventInfo, key string) (string, bool) {
id := fmt.Sprintf("%d", msg.UserId)
return dbi.varGet(app, app.AppKey.Name, "user", id, key)
}
func (dbi *databaseInfo) GetGroupVariable(app wba.AppInfo, msg wba.MessageEventInfo, key string) (string, bool) {
var id string
if msg.MessageType == "group" {
id = "group_" + fmt.Sprintf("%d", msg.GroupId)
}
if msg.MessageType == "private" {
id = "user_" + fmt.Sprintf("%d", msg.UserId)
}
return dbi.varGet(app, app.AppKey.Name, "group", id, key)
}
func (dbi *databaseInfo) GetOutUserVariable(app wba.AppInfo, datamap string, msg wba.MessageEventInfo, key string) (string, bool) {
id := fmt.Sprintf("%d", msg.UserId)
return dbi.varGet(app, datamap, "user", id, key)
}
func (dbi *databaseInfo) GetOutGroupVariable(app wba.AppInfo, datamap string, msg wba.MessageEventInfo, key string) (string, bool) {
var id string
if msg.MessageType == "group" {
id = "group_" + fmt.Sprintf("%d", msg.GroupId)
}
if msg.MessageType == "private" {
id = "user_" + fmt.Sprintf("%d", msg.UserId)
}
return dbi.varGet(app, datamap, "group", id, key)
}
func (dbi *databaseInfo) UnsafelyGetUserVariable(app wba.AppInfo, id string, key string) (string, bool) {
return dbi.varGet(app, app.AppKey.Name, "user", id, key)
}
func (dbi *databaseInfo) UnsafelyGetGroupVariable(app wba.AppInfo, id string, key string) (string, bool) {
return dbi.varGet(app, app.AppKey.Name, "group", id, key)
}
func (dbi *databaseInfo) UnsafelyGetGlobalVariable(app wba.AppInfo, id string, key string) (string, bool) {
return dbi.varGet(app, app.AppKey.Name, "global", id, key)
}
func (dbi *databaseInfo) UnsafelyGetOutUserVariable(app wba.AppInfo, datamap string, id string, key string) (string, bool) {
return dbi.varGet(app, datamap, "user", id, key)
}
func (dbi *databaseInfo) UnsafelyGetOutGroupVariable(app wba.AppInfo, datamap string, id string, key string) (string, bool) {
return dbi.varGet(app, datamap, "group", id, key)
}
func (dbi *databaseInfo) UnsafelyGetOutGlobalVariable(app wba.AppInfo, datamap string, id string, key string) (string, bool) {
return dbi.varGet(app, datamap, "global", id, key)
}
func (dbi *databaseInfo) GetIntConfig(app wba.AppInfo, datamap string, key string) (int64, bool) {
res, ok := database.Get(app.AppKey.Name, datamap, "config", "number", key, true)
if !ok {
return 0, false
}
resInt, ok := res.(int64)
if !ok {
return 0, false
}
return resInt, true
}
func (dbi *databaseInfo) GetStringConfig(app wba.AppInfo, datamap string, key string) (string, bool) {
res, ok := database.Get(app.AppKey.Name, datamap, "config", "string", key, true)
if !ok {
return "", false
}
resStr, ok := res.(string)
if !ok {
return "", false
}
return resStr, true
}
func (dbi *databaseInfo) GetFloatConfig(app wba.AppInfo, datamap string, key string) (float64, bool) {
res, ok := database.Get(app.AppKey.Name, datamap, "config", "float", key, true)
if !ok {
return 0, false
}
resFloat, ok := res.(float64)
if !ok {
return 0, false
}
return resFloat, true
}
func (dbi *databaseInfo) GetIntSliceConfig(app wba.AppInfo, datamap string, key string) ([]int64, bool) {
res, ok := database.Get(app.AppKey.Name, datamap, "config", "number_slice", key, true)
if !ok {
return nil, false
}
resSlice, ok := res.([]int64)
if !ok {
return nil, false
}
return resSlice, true
}
func (dbi *databaseInfo) GetStringSliceConfig(app wba.AppInfo, datamap string, key string) ([]string, bool) {
res, ok := database.Get(app.AppKey.Name, datamap, "config", "string_slice", key, true)
if !ok {
return nil, false
}
resSlice, ok := res.([]string)
if !ok {
return nil, false
}
return resSlice, true
}
func (dbi *databaseInfo) UnsafelyCreatePublicDatamap(app wba.AppInfo, datamapId string) {
appName := app.AppKey.Name
database.CreatePublicDatamap(appName, datamapId)
}
var DatabaseApi databaseInfo

View File

@ -2,15 +2,12 @@ package core
import (
"ProjectWIND/LOG"
"ProjectWIND/database"
"ProjectWIND/wba"
"crypto/rand"
"encoding/json"
"fmt"
"strings"
)
type apiInfo struct{}
type protocolAPI struct{}
//一、Protocol模块
@ -41,7 +38,7 @@ type apiInfo struct{}
// - message: 要发送的消息内容,类型为字符串
//
// - autoEscape: 是否自动转义解析消息内容中的CQ码可选值为 true 和 false
func (a *apiInfo) UnsafelySendMsg(messageType string, groupId int64, userId int64, message string, autoEscape bool) {
func (p *protocolAPI) UnsafelySendMsg(messageType string, groupId int64, userId int64, message string, autoEscape bool) {
// 构建发送消息的JSON数据
var messageData wba.APIRequestInfo
messageData.Action = "send_msg"
@ -84,7 +81,7 @@ func (a *apiInfo) UnsafelySendMsg(messageType string, groupId int64, userId int6
// - message: 要发送的消息内容,类型为字符串
//
// - autoEscape: 是否自动转义解析消息内容中的CQ码可选值为 true 和 false
func (a *apiInfo) UnsafelySendPrivateMsg(userId int64, message string, autoEscape bool) {
func (p *protocolAPI) UnsafelySendPrivateMsg(userId int64, message string, autoEscape bool) {
// 构建发送消息的JSON数据
var messageData wba.APIRequestInfo
messageData.Action = "send_private_msg"
@ -112,7 +109,7 @@ func (a *apiInfo) UnsafelySendPrivateMsg(userId int64, message string, autoEscap
// - message: 要发送的消息内容,类型为字符串
//
// - autoEscape: 是否自动转义解析消息内容中的CQ码可选值为 true 和 false
func (a *apiInfo) UnsafelySendGroupMsg(groupId int64, message string, autoEscape bool) {
func (p *protocolAPI) UnsafelySendGroupMsg(groupId int64, message string, autoEscape bool) {
// 构建发送消息的JSON数据
var messageData wba.APIRequestInfo
messageData.Action = "send_group_msg"
@ -138,7 +135,7 @@ func (a *apiInfo) UnsafelySendGroupMsg(groupId int64, message string, autoEscape
// - message: 要发送的消息内容,类型为字符串
//
// - autoEscape: 是否自动转义解析消息内容中的CQ码可选值为 true 和 false
func (a *apiInfo) SendMsg(msg wba.MessageEventInfo, message string, autoEscape bool) {
func (p *protocolAPI) SendMsg(msg wba.MessageEventInfo, message string, autoEscape bool) {
// 构建发送消息的JSON数据
var messageData wba.APIRequestInfo
@ -182,7 +179,7 @@ func (a *apiInfo) SendMsg(msg wba.MessageEventInfo, message string, autoEscape b
// - message: 要发送的消息内容,类型为字符串
//
// - autoEscape: 是否自动转义,可选值为 true 和 false
func (a *apiInfo) SendPrivateMsg(msg wba.MessageEventInfo, message string, autoEscape bool) {
func (p *protocolAPI) SendPrivateMsg(msg wba.MessageEventInfo, message string, autoEscape bool) {
// 构建发送消息的JSON数据
var messageData wba.APIRequestInfo
messageData.Action = "send_private_msg"
@ -208,7 +205,7 @@ func (a *apiInfo) SendPrivateMsg(msg wba.MessageEventInfo, message string, autoE
// - message: 要发送的消息内容,类型为字符串
//
// - autoEscape: 是否自动转义,可选值为 true 和 false
func (a *apiInfo) SendGroupMsg(msg wba.MessageEventInfo, message string, autoEscape bool) {
func (p *protocolAPI) SendGroupMsg(msg wba.MessageEventInfo, message string, autoEscape bool) {
// 构建发送消息的JSON数据
var messageData wba.APIRequestInfo
messageData.Action = "send_group_msg"
@ -232,7 +229,7 @@ func (a *apiInfo) SendGroupMsg(msg wba.MessageEventInfo, message string, autoEsc
// 参数:
//
// - messageId: 要撤回的消息ID
func (a *apiInfo) UnsafelyDeleteMsg(messageId int32) {
func (p *protocolAPI) UnsafelyDeleteMsg(messageId int32) {
// 构建删除消息的JSON数据
var messageData wba.APIRequestInfo
messageData.Action = "delete_msg"
@ -251,7 +248,7 @@ func (a *apiInfo) UnsafelyDeleteMsg(messageId int32) {
// 参数:
//
// - msg: 原始消息事件信息
func (a *apiInfo) DeleteMsg(msg wba.MessageEventInfo) {
func (p *protocolAPI) DeleteMsg(msg wba.MessageEventInfo) {
// 构建删除消息的JSON数据
var messageData wba.APIRequestInfo
messageData.Action = "delete_msg"
@ -272,7 +269,7 @@ func (a *apiInfo) DeleteMsg(msg wba.MessageEventInfo) {
// - userId: 要赞的用户ID
//
// - times: 赞的次数
func (a *apiInfo) SendLike(userId int64, times int) {
func (p *protocolAPI) SendLike(userId int64, times int) {
// 构建发送赞的JSON数据
var messageData wba.APIRequestInfo
messageData.Action = "send_like"
@ -296,7 +293,7 @@ func (a *apiInfo) SendLike(userId int64, times int) {
// - userId: 用户ID
//
// - rejectAddRequest: 是否拒绝该用户的后续加群请求,可选值为 true 和 false
func (a *apiInfo) SetGroupKick(groupId int64, userId int64, rejectAddRequest bool) {
func (p *protocolAPI) SetGroupKick(groupId int64, userId int64, rejectAddRequest bool) {
var messageData wba.APIRequestInfo
messageData.Action = "set_group_kick"
messageData.Params.GroupId = groupId
@ -320,7 +317,7 @@ func (a *apiInfo) SetGroupKick(groupId int64, userId int64, rejectAddRequest boo
// - userId: 用户ID
//
// - duration: 禁言时长单位为秒0表示取消禁言
func (a *apiInfo) SetGroupBan(groupId int64, userId int64, duration int32) {
func (p *protocolAPI) SetGroupBan(groupId int64, userId int64, duration int32) {
var messageData wba.APIRequestInfo
messageData.Action = "set_group_ban"
messageData.Params.GroupId = groupId
@ -342,7 +339,7 @@ func (a *apiInfo) SetGroupBan(groupId int64, userId int64, duration int32) {
// - groupId: 群号
//
// - enable: 是否启用全员禁言,可选值为 true 和 false
func (a *apiInfo) SetGroupWholeBan(groupId int64, enable bool) {
func (p *protocolAPI) SetGroupWholeBan(groupId int64, enable bool) {
var messageData wba.APIRequestInfo
messageData.Action = "set_group_whole_ban"
messageData.Params.GroupId = groupId
@ -365,7 +362,7 @@ func (a *apiInfo) SetGroupWholeBan(groupId int64, enable bool) {
// - userId: 用户ID
//
// - enable: 是否设置为管理员,可选值为 true 和 false
func (a *apiInfo) SetGroupAdmin(groupId int64, userId int64, enable bool) {
func (p *protocolAPI) SetGroupAdmin(groupId int64, userId int64, enable bool) {
var messageData wba.APIRequestInfo
messageData.Action = "set_group_admin"
messageData.Params.GroupId = groupId
@ -389,7 +386,7 @@ func (a *apiInfo) SetGroupAdmin(groupId int64, userId int64, enable bool) {
// - userId: 用户ID
//
// - card: 新的群名片
func (a *apiInfo) SetGroupCard(groupId int64, userId int64, card string) {
func (p *protocolAPI) SetGroupCard(groupId int64, userId int64, card string) {
var messageData wba.APIRequestInfo
messageData.Action = "set_group_card"
messageData.Params.GroupId = groupId
@ -411,7 +408,7 @@ func (a *apiInfo) SetGroupCard(groupId int64, userId int64, card string) {
// - groupId: 群号
//
// - groupName: 新的群名称
func (a *apiInfo) SetGroupName(groupId int64, groupName string) {
func (p *protocolAPI) SetGroupName(groupId int64, groupName string) {
var messageData wba.APIRequestInfo
messageData.Action = "set_group_name"
messageData.Params.GroupId = groupId
@ -432,7 +429,7 @@ func (a *apiInfo) SetGroupName(groupId int64, groupName string) {
// - groupId: 群号
//
// - isDismiss: 是否解散群聊,仅当退出的是群主时有效,可选值为 true 和 false
func (a *apiInfo) SetGroupLeave(groupId int64, isDismiss bool) {
func (p *protocolAPI) SetGroupLeave(groupId int64, isDismiss bool) {
var messageData wba.APIRequestInfo
messageData.Action = "set_group_leave"
messageData.Params.GroupId = groupId
@ -455,7 +452,7 @@ func (a *apiInfo) SetGroupLeave(groupId int64, isDismiss bool) {
// - userId: 用户ID
//
// - specialTitle: 新的专属头衔
func (a *apiInfo) SetGroupSpecialTitle(groupId int64, userId int64, specialTitle string) {
func (p *protocolAPI) SetGroupSpecialTitle(groupId int64, userId int64, specialTitle string) {
var messageData wba.APIRequestInfo
messageData.Action = "set_group_special_title"
messageData.Params.GroupId = groupId
@ -480,7 +477,7 @@ func (a *apiInfo) SetGroupSpecialTitle(groupId int64, userId int64, specialTitle
// - approve: 是否同意请求,可选值为 true 和 false
//
// - remark: 设置好友的备注信息
func (a *apiInfo) SetFriendAddRequest(flag string, approve bool, remark string) {
func (p *protocolAPI) SetFriendAddRequest(flag string, approve bool, remark string) {
var messageData wba.APIRequestInfo
messageData.Action = "set_friend_add_request"
messageData.Params.Flag = flag
@ -506,7 +503,7 @@ func (a *apiInfo) SetFriendAddRequest(flag string, approve bool, remark string)
// - approve: 是否同意请求,可选值为 true 和 false
//
// - reason: 拒绝请求的原因,仅当 approve 为 false 时有效
func (a *apiInfo) SetGroupAddRequest(flag string, subType string, approve bool, reason string) {
func (p *protocolAPI) SetGroupAddRequest(flag string, subType string, approve bool, reason string) {
var messageData wba.APIRequestInfo
messageData.Action = "set_group_add_request"
messageData.Params.Flag = flag
@ -523,7 +520,7 @@ func (a *apiInfo) SetGroupAddRequest(flag string, subType string, approve bool,
}
// SetRestart 重启
func (a *apiInfo) SetRestart(delay int32) {
func (p *protocolAPI) SetRestart(delay int32) {
var messageData wba.APIRequestInfo
messageData.Action = "set_restart"
messageData.Params.Delay = delay
@ -537,7 +534,7 @@ func (a *apiInfo) SetRestart(delay int32) {
}
// CleanCache 清理缓存
func (a *apiInfo) CleanCache() {
func (p *protocolAPI) CleanCache() {
var messageData wba.APIRequestInfo
messageData.Action = "clean_cache"
_, err := wsAPI(messageData)
@ -552,7 +549,7 @@ func (a *apiInfo) CleanCache() {
// 2.有响应API需添加echo字段统一返回响应结构体
// GetLoginInfo 获取登录信息
func (a *apiInfo) GetLoginInfo() (Response wba.APIResponseInfo) {
func (p *protocolAPI) GetLoginInfo() (Response wba.APIResponseInfo) {
LOG.Info("获取登录信息(GetLoginInfo)")
var messageData wba.APIRequestInfo
var err error
@ -571,7 +568,7 @@ func (a *apiInfo) GetLoginInfo() (Response wba.APIResponseInfo) {
}
// GetVersionInfo 获取协议信息
func (a *apiInfo) GetVersionInfo() (Response wba.APIResponseInfo) {
func (p *protocolAPI) GetVersionInfo() (Response wba.APIResponseInfo) {
LOG.Info("获取协议信息(GetVersionInfo)")
var messageData wba.APIRequestInfo
var err error
@ -590,7 +587,7 @@ func (a *apiInfo) GetVersionInfo() (Response wba.APIResponseInfo) {
}
// GetMsg 获取消息
func (a *apiInfo) GetMsg(messageId int32) (Response wba.APIResponseInfo) {
func (p *protocolAPI) GetMsg(messageId int32) (Response wba.APIResponseInfo) {
LOG.Info("获取消息(GetMsg)")
var messageData wba.APIRequestInfo
var err error
@ -610,7 +607,7 @@ func (a *apiInfo) GetMsg(messageId int32) (Response wba.APIResponseInfo) {
}
// GetForwardMsg 获取合并转发消息
func (a *apiInfo) GetForwardMsg(id string) (Response wba.APIResponseInfo) {
func (p *protocolAPI) GetForwardMsg(id string) (Response wba.APIResponseInfo) {
LOG.Info("获取合并转发消息(GetForwardMsg)")
var messageData wba.APIRequestInfo
var err error
@ -630,7 +627,7 @@ func (a *apiInfo) GetForwardMsg(id string) (Response wba.APIResponseInfo) {
}
// GetStrangerInfo 获取陌生人信息
func (a *apiInfo) GetStrangerInfo(userId int64, noCache bool) (Response wba.APIResponseInfo) {
func (p *protocolAPI) GetStrangerInfo(userId int64, noCache bool) (Response wba.APIResponseInfo) {
LOG.Info("获取陌生人信息(GetStrangerInfo)")
var messageData wba.APIRequestInfo
var err error
@ -651,7 +648,7 @@ func (a *apiInfo) GetStrangerInfo(userId int64, noCache bool) (Response wba.APIR
}
// GetFriendList 获取好友列表
func (a *apiInfo) GetFriendList() (Response wba.APIResponseInfo) {
func (p *protocolAPI) GetFriendList() (Response wba.APIResponseInfo) {
LOG.Info("获取好友列表(GetFriendList)")
var messageData wba.APIRequestInfo
var err error
@ -670,7 +667,7 @@ func (a *apiInfo) GetFriendList() (Response wba.APIResponseInfo) {
}
// GetGroupList 获取群列表
func (a *apiInfo) GetGroupList() (Response wba.APIResponseInfo) {
func (p *protocolAPI) GetGroupList() (Response wba.APIResponseInfo) {
LOG.Info("获取群列表(GetGroupList)")
var messageData wba.APIRequestInfo
var err error
@ -689,7 +686,7 @@ func (a *apiInfo) GetGroupList() (Response wba.APIResponseInfo) {
}
// GetGroupInfo 获取群信息
func (a *apiInfo) GetGroupInfo(groupId int64, noCache bool) (Response wba.APIResponseInfo) {
func (p *protocolAPI) GetGroupInfo(groupId int64, noCache bool) (Response wba.APIResponseInfo) {
LOG.Info("获取群信息(GetGroupInfo)")
var messageData wba.APIRequestInfo
var err error
@ -710,7 +707,7 @@ func (a *apiInfo) GetGroupInfo(groupId int64, noCache bool) (Response wba.APIRes
}
// GetGroupMemberInfo 获取群成员信息
func (a *apiInfo) GetGroupMemberInfo(groupId int64, userId int64, noCache bool) (Response wba.APIResponseInfo) {
func (p *protocolAPI) GetGroupMemberInfo(groupId int64, userId int64, noCache bool) (Response wba.APIResponseInfo) {
LOG.Info("获取群成员信息(GetGroupMemberInfo)")
var messageData wba.APIRequestInfo
var err error
@ -732,7 +729,7 @@ func (a *apiInfo) GetGroupMemberInfo(groupId int64, userId int64, noCache bool)
}
// GetGroupMemberList 获取群成员列表
func (a *apiInfo) GetGroupMemberList(groupId int64) (Response wba.APIResponseInfo) {
func (p *protocolAPI) GetGroupMemberList(groupId int64) (Response wba.APIResponseInfo) {
LOG.Info("获取群成员列表(GetGroupMemberList)")
var messageData wba.APIRequestInfo
var err error
@ -752,7 +749,7 @@ func (a *apiInfo) GetGroupMemberList(groupId int64) (Response wba.APIResponseInf
}
// GetGroupHonorInfo 获取群荣誉信息
func (a *apiInfo) GetGroupHonorInfo(groupId int64, Type string) (Response wba.APIResponseInfo) {
func (p *protocolAPI) GetGroupHonorInfo(groupId int64, Type string) (Response wba.APIResponseInfo) {
LOG.Info("获取群荣誉信息(GetGroupHonorInfo)")
var messageData wba.APIRequestInfo
var err error
@ -773,7 +770,7 @@ func (a *apiInfo) GetGroupHonorInfo(groupId int64, Type string) (Response wba.AP
}
// GetCookies 获取Cookies
func (a *apiInfo) GetCookies(domain string) (Response wba.APIResponseInfo) {
func (p *protocolAPI) GetCookies(domain string) (Response wba.APIResponseInfo) {
LOG.Info("获取Cookies(GetCookies)")
var messageData wba.APIRequestInfo
var err error
@ -793,7 +790,7 @@ func (a *apiInfo) GetCookies(domain string) (Response wba.APIResponseInfo) {
}
// GetCSRFToken 获取CSRF Token
func (a *apiInfo) GetCSRFToken() (Response wba.APIResponseInfo) {
func (p *protocolAPI) GetCSRFToken() (Response wba.APIResponseInfo) {
LOG.Info("获取CSRF Token(GetCSRFToken)")
var messageData wba.APIRequestInfo
var err error
@ -812,7 +809,7 @@ func (a *apiInfo) GetCSRFToken() (Response wba.APIResponseInfo) {
}
// GetCredentials 获取登录令牌
func (a *apiInfo) GetCredentials(domain string) (Response wba.APIResponseInfo) {
func (p *protocolAPI) GetCredentials(domain string) (Response wba.APIResponseInfo) {
LOG.Info("获取登录令牌(GetCredentials)")
var messageData wba.APIRequestInfo
var err error
@ -832,7 +829,7 @@ func (a *apiInfo) GetCredentials(domain string) (Response wba.APIResponseInfo) {
}
// GetRecord 获取语音
func (a *apiInfo) GetRecord(file string, outFormat string) (Response wba.APIResponseInfo) {
func (p *protocolAPI) GetRecord(file string, outFormat string) (Response wba.APIResponseInfo) {
LOG.Info("获取语音(GetRecord)")
var messageData wba.APIRequestInfo
var err error
@ -853,7 +850,7 @@ func (a *apiInfo) GetRecord(file string, outFormat string) (Response wba.APIResp
}
// GetImage 获取图片
func (a *apiInfo) GetImage(file string) (Response wba.APIResponseInfo) {
func (p *protocolAPI) GetImage(file string) (Response wba.APIResponseInfo) {
LOG.Info("获取图片(GetImage)")
var messageData wba.APIRequestInfo
var err error
@ -873,7 +870,7 @@ func (a *apiInfo) GetImage(file string) (Response wba.APIResponseInfo) {
}
// CanSendImage 检查是否可以发送图片
func (a *apiInfo) CanSendImage() (Response wba.APIResponseInfo) {
func (p *protocolAPI) CanSendImage() (Response wba.APIResponseInfo) {
LOG.Info("检查是否可以发送图片(CanSendImage)")
var messageData wba.APIRequestInfo
var err error
@ -892,7 +889,7 @@ func (a *apiInfo) CanSendImage() (Response wba.APIResponseInfo) {
}
// CanSendRecord 检查是否可以发送语音
func (a *apiInfo) CanSendRecord() (Response wba.APIResponseInfo) {
func (p *protocolAPI) CanSendRecord() (Response wba.APIResponseInfo) {
LOG.Info("检查是否可以发送语音(CanSendRecord)")
var messageData wba.APIRequestInfo
var err error
@ -911,7 +908,7 @@ func (a *apiInfo) CanSendRecord() (Response wba.APIResponseInfo) {
}
// GetStatus 获取状态
func (a *apiInfo) GetStatus() (Response wba.APIResponseInfo) {
func (p *protocolAPI) GetStatus() (Response wba.APIResponseInfo) {
LOG.Info("获取状态(GetStatus)")
var messageData wba.APIRequestInfo
var err error
@ -929,273 +926,6 @@ func (a *apiInfo) GetStatus() (Response wba.APIResponseInfo) {
return Response
}
//二、LOG模块
/*
关于LOG模块的说明
1.日志模块级别分为TRACEDEBUGINFONOTICEWARNERROR五个级别默认级别为INFO
2.日志模块提供LogWith方法可以自定义日志级别
3.日志模块提供Log方法默认日志级别为INFO
*/
// LogWith 打印日志(带级别)
//
// 参数:
// - level: 日志级别,支持"TRACE"、"DEBUG"、"INFO"、"NOTICE"、 "WARN"、"ERROR"
// - content: 日志内容
// - args: 可选参数,用于格式化日志内容
//
// 返回值:
// - 无
func (a *apiInfo) LogWith(level string, content string, args ...interface{}) {
level = strings.ToLower(level)
switch level {
case "trace":
LOG.Trace(content, args...)
return
case "debug":
LOG.Debug(content, args...)
return
case "notice":
LOG.Notice(content, args...)
return
case "warn":
LOG.Warn(content, args...)
return
case "error":
LOG.Error(content, args...)
return
default:
LOG.Info(content, args...)
return
}
}
// Log 打印日志
//
// 参数:
// - content: 日志内容
// - args: 可选参数,用于格式化日志内容
func (a *apiInfo) Log(content string, args ...interface{}) {
LOG.Info(content, args...)
}
// MsgUnmarshal 解析消息
//
// 参数:
// - messageJSON: 从数据库中获取的JSON序列化后的消息字符串
//
// 返回值:
// - wba.MessageEventInfo: 解析后的消息事件信息,解析失败时返回空结构体
func (a *apiInfo) MsgUnmarshal(messageJSON string) (msg wba.MessageEventInfo) {
err := json.Unmarshal([]byte(messageJSON), &msg)
if err != nil {
return wba.MessageEventInfo{}
}
return msg
}
//database模块
// //数据库部分允许字符串变量的读写操作,允许读取配置项操作
type databaseInfo struct{}
func (dbi *databaseInfo) varSet(app wba.AppInfo, datamap string, unit string, id string, key string, value string) {
database.Set(app.AppKey.Name, datamap, unit, id, key, value)
}
func (dbi *databaseInfo) SetUserVariable(app wba.AppInfo, msg wba.MessageEventInfo, key string, value string) {
id := fmt.Sprintf("%d", msg.UserId)
dbi.varSet(app, app.AppKey.Name, "user", id, key, value)
}
func (dbi *databaseInfo) SetGroupVariable(app wba.AppInfo, msg wba.MessageEventInfo, key string, value string) {
var id string
if msg.MessageType == "group" {
id = "group_" + fmt.Sprintf("%d", msg.GroupId)
}
if msg.MessageType == "private" {
id = "user_" + fmt.Sprintf("%d", msg.UserId)
}
dbi.varSet(app, app.AppKey.Name, "group", id, key, value)
}
func (dbi *databaseInfo) SetOutUserVariable(app wba.AppInfo, datamap string, msg wba.MessageEventInfo, key string, value string) {
id := fmt.Sprintf("%d", msg.UserId)
dbi.varSet(app, datamap, "user", id, key, value)
}
func (dbi *databaseInfo) SetOutGroupVariable(app wba.AppInfo, datamap string, msg wba.MessageEventInfo, key string, value string) {
var id string
if msg.MessageType == "group" {
id = "group_" + fmt.Sprintf("%d", msg.GroupId)
}
if msg.MessageType == "private" {
id = "user_" + fmt.Sprintf("%d", msg.UserId)
}
dbi.varSet(app, datamap, "group", id, key, value)
}
func (dbi *databaseInfo) UnsafelySetUserVariable(app wba.AppInfo, id string, key string, value string) {
dbi.varSet(app, app.AppKey.Name, "user", id, key, value)
}
func (dbi *databaseInfo) UnsafelySetGroupVariable(app wba.AppInfo, id string, key string, value string) {
dbi.varSet(app, app.AppKey.Name, "group", id, key, value)
}
func (dbi *databaseInfo) UnsafelySetGlobalVariable(app wba.AppInfo, id string, key string, value string) {
dbi.varSet(app, app.AppKey.Name, "global", id, key, value)
}
func (dbi *databaseInfo) UnsafelySetOutUserVariable(app wba.AppInfo, datamap string, id string, key string, value string) {
dbi.varSet(app, datamap, "user", id, key, value)
}
func (dbi *databaseInfo) UnsafelySetOutGroupVariable(app wba.AppInfo, datamap string, id string, key string, value string) {
dbi.varSet(app, datamap, "group", id, key, value)
}
func (dbi *databaseInfo) UnsafelySetOutGlobalVariable(app wba.AppInfo, datamap string, id string, key string, value string) {
dbi.varSet(app, datamap, "global", id, key, value)
}
func (dbi *databaseInfo) varGet(app wba.AppInfo, datamap string, unit string, id string, key string) (string, bool) {
res, ok := database.Get(app.AppKey.Name, datamap, unit, id, key, false)
if !ok {
return "", false
}
resStr, ok := res.(string)
if !ok {
return "", false
}
return resStr, true
}
func (dbi *databaseInfo) GetUserVariable(app wba.AppInfo, msg wba.MessageEventInfo, key string) (string, bool) {
id := fmt.Sprintf("%d", msg.UserId)
return dbi.varGet(app, app.AppKey.Name, "user", id, key)
}
func (dbi *databaseInfo) GetGroupVariable(app wba.AppInfo, msg wba.MessageEventInfo, key string) (string, bool) {
var id string
if msg.MessageType == "group" {
id = "group_" + fmt.Sprintf("%d", msg.GroupId)
}
if msg.MessageType == "private" {
id = "user_" + fmt.Sprintf("%d", msg.UserId)
}
return dbi.varGet(app, app.AppKey.Name, "group", id, key)
}
func (dbi *databaseInfo) GetOutUserVariable(app wba.AppInfo, datamap string, msg wba.MessageEventInfo, key string) (string, bool) {
id := fmt.Sprintf("%d", msg.UserId)
return dbi.varGet(app, datamap, "user", id, key)
}
func (dbi *databaseInfo) GetOutGroupVariable(app wba.AppInfo, datamap string, msg wba.MessageEventInfo, key string) (string, bool) {
var id string
if msg.MessageType == "group" {
id = "group_" + fmt.Sprintf("%d", msg.GroupId)
}
if msg.MessageType == "private" {
id = "user_" + fmt.Sprintf("%d", msg.UserId)
}
return dbi.varGet(app, datamap, "group", id, key)
}
func (dbi *databaseInfo) UnsafelyGetUserVariable(app wba.AppInfo, id string, key string) (string, bool) {
return dbi.varGet(app, app.AppKey.Name, "user", id, key)
}
func (dbi *databaseInfo) UnsafelyGetGroupVariable(app wba.AppInfo, id string, key string) (string, bool) {
return dbi.varGet(app, app.AppKey.Name, "group", id, key)
}
func (dbi *databaseInfo) UnsafelyGetGlobalVariable(app wba.AppInfo, id string, key string) (string, bool) {
return dbi.varGet(app, app.AppKey.Name, "global", id, key)
}
func (dbi *databaseInfo) UnsafelyGetOutUserVariable(app wba.AppInfo, datamap string, id string, key string) (string, bool) {
return dbi.varGet(app, datamap, "user", id, key)
}
func (dbi *databaseInfo) UnsafelyGetOutGroupVariable(app wba.AppInfo, datamap string, id string, key string) (string, bool) {
return dbi.varGet(app, datamap, "group", id, key)
}
func (dbi *databaseInfo) UnsafelyGetOutGlobalVariable(app wba.AppInfo, datamap string, id string, key string) (string, bool) {
return dbi.varGet(app, datamap, "global", id, key)
}
func (dbi *databaseInfo) GetIntConfig(app wba.AppInfo, datamap string, key string) (int64, bool) {
res, ok := database.Get(app.AppKey.Name, datamap, "config", "number", key, true)
if !ok {
return 0, false
}
resInt, ok := res.(int64)
if !ok {
return 0, false
}
return resInt, true
}
func (dbi *databaseInfo) GetStringConfig(app wba.AppInfo, datamap string, key string) (string, bool) {
res, ok := database.Get(app.AppKey.Name, datamap, "config", "string", key, true)
if !ok {
return "", false
}
resStr, ok := res.(string)
if !ok {
return "", false
}
return resStr, true
}
func (dbi *databaseInfo) GetFloatConfig(app wba.AppInfo, datamap string, key string) (float64, bool) {
res, ok := database.Get(app.AppKey.Name, datamap, "config", "float", key, true)
if !ok {
return 0, false
}
resFloat, ok := res.(float64)
if !ok {
return 0, false
}
return resFloat, true
}
func (dbi *databaseInfo) GetIntSliceConfig(app wba.AppInfo, datamap string, key string) ([]int64, bool) {
res, ok := database.Get(app.AppKey.Name, datamap, "config", "number_slice", key, true)
if !ok {
return nil, false
}
resSlice, ok := res.([]int64)
if !ok {
return nil, false
}
return resSlice, true
}
func (dbi *databaseInfo) GetStringSliceConfig(app wba.AppInfo, datamap string, key string) ([]string, bool) {
res, ok := database.Get(app.AppKey.Name, datamap, "config", "string_slice", key, true)
if !ok {
return nil, false
}
resSlice, ok := res.([]string)
if !ok {
return nil, false
}
return resSlice, true
}
func (dbi *databaseInfo) UnsafelyCreatePublicDatamap(app wba.AppInfo, datamapId string) {
appName := app.AppKey.Name
database.CreatePublicDatamap(appName, datamapId)
}
// 文件管理模块
//TODO: 文件管理模块待实现
@ -1204,8 +934,7 @@ func (dbi *databaseInfo) UnsafelyCreatePublicDatamap(app wba.AppInfo, datamapId
//核心信息调用模块
var AppApi apiInfo
var DatabaseApi databaseInfo
var ProtocolApi protocolAPI
func GenerateUUID() (string, error) {
uuid := make([]byte, 16)

143
core/api_wst.go Normal file
View File

@ -0,0 +1,143 @@
package core
import (
"ProjectWIND/LOG"
"ProjectWIND/wba"
"encoding/json"
"strconv"
"strings"
)
type toolsAPI struct{}
//二、LOG模块
/*
关于LOG模块的说明
1.日志模块级别分为TRACEDEBUGINFONOTICEWARNERROR五个级别默认级别为INFO
2.日志模块提供LogWith方法可以自定义日志级别
3.日志模块提供Log方法默认日志级别为INFO
*/
// LogWith 打印日志(带级别)
//
// 参数:
// - level: 日志级别,支持"TRACE"、"DEBUG"、"INFO"、"NOTICE"、 "WARN"、"ERROR"
// - content: 日志内容
// - args: 可选参数,用于格式化日志内容
//
// 返回值:
// - 无
func (t *toolsAPI) LogWith(level string, content string, args ...interface{}) {
level = strings.ToLower(level)
switch level {
case "trace":
LOG.Trace(content, args...)
return
case "debug":
LOG.Debug(content, args...)
return
case "notice":
LOG.Notice(content, args...)
return
case "warn":
LOG.Warn(content, args...)
return
case "error":
LOG.Error(content, args...)
return
default:
LOG.Info(content, args...)
return
}
}
// Log 打印日志
//
// 参数:
// - content: 日志内容
// - args: 可选参数,用于格式化日志内容
func (t *toolsAPI) Log(content string, args ...interface{}) {
LOG.Info(content, args...)
}
// MsgUnmarshal 解析消息
//
// 参数:
// - messageJSON: 从数据库中获取的JSON序列化后的消息字符串
//
// 返回值:
// - wba.MessageEventInfo: 解析后的消息事件信息,解析失败时返回空结构体
func (t *toolsAPI) MsgUnmarshal(messageJSON string) (msg wba.MessageEventInfo) {
err := json.Unmarshal([]byte(messageJSON), &msg)
if err != nil {
return wba.MessageEventInfo{}
}
return msg
}
func (t *toolsAPI) SessionLabelAnalysis(sessionLabel wba.SessionLabel) wba.SessionInfo {
platform := strings.Split(sessionLabel, ":")[0]
sessionTypeAndId := strings.Split(sessionLabel, ":")[1]
sessionType := strings.Split(sessionTypeAndId, "-")[0]
sessionId := strings.Split(sessionTypeAndId, "-")[1]
Id, err := strconv.ParseInt(sessionId, 10, 64)
if err != nil {
return wba.SessionInfo{}
}
return wba.SessionInfo{
Platform: platform,
SessionType: sessionType,
SessionId: Id,
}
}
func (t *toolsAPI) VersionCompare(version1, version2 wba.VersionLabel) int {
version1Info := VersionLabelAnalysis(version1)
version2Info := VersionLabelAnalysis(version2)
if version1Info.BigVersion < version2Info.BigVersion {
return -1
} else if version1Info.BigVersion > version2Info.BigVersion {
return 1
} else {
if version1Info.SmallVersion < version2Info.SmallVersion {
return -1
} else if version1Info.SmallVersion > version2Info.SmallVersion {
return 1
} else {
if version1Info.FixVersion < version2Info.FixVersion {
return -1
} else if version1Info.FixVersion > version2Info.FixVersion {
return 1
} else {
return 0
}
}
}
}
func VersionLabelAnalysis(versionLabel wba.VersionLabel) wba.VersionInfo {
version := strings.Split(versionLabel, ".")
bigVersion, err := strconv.ParseUint(version[0], 10, 8)
if err != nil {
return wba.VersionInfo{}
}
smallVersion, err := strconv.ParseUint(version[1], 10, 8)
if err != nil {
return wba.VersionInfo{}
}
fixVersion, err := strconv.ParseUint(version[2], 10, 8)
if err != nil {
return wba.VersionInfo{}
}
return wba.VersionInfo{
BigVersion: uint8(bigVersion),
SmallVersion: uint8(smallVersion),
FixVersion: uint8(fixVersion),
}
}
var ToolsApi toolsAPI

View File

@ -3,21 +3,45 @@ package core
import (
"ProjectWIND/LOG"
"ProjectWIND/wba"
"github.com/dop251/goja"
"os"
"path/filepath"
"reflect"
"strings"
"github.com/dop251/goja"
)
var CmdMap = make([]map[string]wba.Cmd, 4)
type CamelCaseFieldNameMapper struct{}
func (CamelCaseFieldNameMapper) FieldName(_ reflect.Type, f reflect.StructField) string {
name := f.Name
if len(name) == 0 {
return name
}
// 首字母小写
return strings.ToLower(name[:1]) + name[1:]
}
func (CamelCaseFieldNameMapper) MethodName(_ reflect.Type, m reflect.Method) string {
name := m.Name
if len(name) == 0 {
return name
}
// 首字母小写
return strings.ToLower(name[:1]) + name[1:]
}
var GlobalCmdAgentSelector = wba.NewCmdAgentSelector()
var CmdMap = make(map[wba.AppKey]wba.CmdList)
var AppMap = make(map[wba.AppKey]wba.AppInfo)
var ScheduledTaskMap = make(map[wba.AppKey]map[string]wba.ScheduledTaskInfo)
// ReloadApps 重新加载应用
func ReloadApps() (total int, success int) {
// 清空AppMap和CmdMap
CmdMap = make([]map[string]wba.Cmd, 4)
CmdMap = make(map[wba.AppKey]wba.CmdList)
AppMap = make(map[wba.AppKey]wba.AppInfo)
ScheduledTaskMap = make(map[wba.AppKey]map[string]wba.ScheduledTaskInfo)
GlobalCmdAgentSelector = wba.NewCmdAgentSelector()
appsDir := "./data/app/"
appFiles, err := os.ReadDir(appsDir)
total = 0
@ -32,7 +56,8 @@ func ReloadApps() (total int, success int) {
total += totalDelta
success += successDelta
}
CmdMap[0] = AppCore.CmdMap
CmdMap[AppCore.AppKey] = AppCore.CmdMap
GlobalCmdAgentSelector.AddCmdMap(CmdMap)
return total, success
}
@ -52,103 +77,124 @@ func reloadAPP(file os.DirEntry, appsDir string) (totalDelta int, successDelta i
}
runtime := goja.New()
_, err = runtime.RunString(string(jsCode))
if err != nil {
LOG.Error("执行应用 %s 失败: %v", pluginPath, err)
return 1, 0
runtime.SetFieldNameMapper(CamelCaseFieldNameMapper{})
runtime.Set("console", map[string]interface{}{
"log": func(v ...interface{}) {
LOG.Info("JS log: %v", v...)
},
"error": func(v ...interface{}) {
LOG.Error("JS error: %v", v...)
},
})
// 添加错误捕获
safeRun := func(fn func() error) {
defer func() {
if r := recover(); r != nil {
LOG.Error("JS执行错误: %v", r)
}
}()
if err := fn(); err != nil {
LOG.Error("JS执行错误: %v", err)
}
}
// 修改JS代码执行部分
safeRun(func() error {
_, err := runtime.RunString(string(jsCode))
return err
})
// 创建JS可用的wbaObj对象
wbaObj := runtime.NewObject()
wsp := runtime.NewObject()
wsd := runtime.NewObject()
wst := runtime.NewObject()
//wsp := runtime.NewObject()
//wsd := runtime.NewObject()
//wst := runtime.NewObject()
_ = runtime.Set("wba", wbaObj)
_ = wbaObj.Set("NewApp", wba.NewApp)
_ = wbaObj.Set("WithName", wba.WithName)
_ = wbaObj.Set("WithAuthor", wba.WithAuthor)
_ = wbaObj.Set("WithVersion", wba.WithVersion)
_ = wbaObj.Set("WithDescription", wba.WithDescription)
_ = wbaObj.Set("WithWebUrl", wba.WithWebUrl)
_ = wbaObj.Set("WithLicense", wba.WithLicense)
_ = wbaObj.Set("WithAppType", wba.WithAppType)
_ = wbaObj.Set("WithRule", wba.WithRule)
_ = wbaObj.Set("wsp", wsp)
_ = wbaObj.Set("wsd", wsd)
_ = wbaObj.Set("wst", wst)
//WSP注册
_ = wsp.Set("UnsafelySendMsg", AppApi.UnsafelySendMsg)
_ = wsp.Set("UnsafelySendPrivateMsg", AppApi.UnsafelySendPrivateMsg)
_ = wsp.Set("UnsafelySendGroupMsg", AppApi.UnsafelySendGroupMsg)
_ = wsp.Set("SendMsg", AppApi.SendMsg)
_ = wsp.Set("SendPrivateMsg", AppApi.SendPrivateMsg)
_ = wsp.Set("SendGroupMsg", AppApi.SendGroupMsg)
_ = wsp.Set("UnsafelyDeleteMsg", AppApi.UnsafelyDeleteMsg)
_ = wsp.Set("DeleteMsg", AppApi.DeleteMsg)
_ = wsp.Set("SendLike", AppApi.SendLike)
_ = wsp.Set("SetGroupKick", AppApi.SetGroupKick)
_ = wsp.Set("SetGroupBan", AppApi.SetGroupBan)
_ = wsp.Set("SetGroupWholeBan", AppApi.SetGroupWholeBan)
_ = wsp.Set("SetGroupAdmin", AppApi.SetGroupAdmin)
_ = wsp.Set("SetGroupLeave", AppApi.SetGroupLeave)
_ = wsp.Set("SetGroupCard", AppApi.SetGroupCard)
_ = wsp.Set("SetGroupName", AppApi.SetGroupName)
_ = wsp.Set("SetGroupSpecialTitle", AppApi.SetGroupSpecialTitle)
_ = wsp.Set("SetFriendAddRequest", AppApi.SetFriendAddRequest)
_ = wsp.Set("SetGroupAddRequest", AppApi.SetGroupAddRequest)
_ = wsp.Set("GetLoginInfo", AppApi.GetLoginInfo)
_ = wsp.Set("GetVersionInfo", AppApi.GetVersionInfo)
_ = wsp.Set("GetMsg", AppApi.GetMsg)
_ = wsp.Set("GetGroupInfo", AppApi.GetGroupInfo)
_ = wsp.Set("GetForwardMsg", AppApi.GetForwardMsg)
_ = wsp.Set("GetStrangerInfo", AppApi.GetStrangerInfo)
_ = wsp.Set("GetGroupList", AppApi.GetGroupList)
_ = wsp.Set("GetGroupMemberList", AppApi.GetGroupMemberList)
_ = wsp.Set("GetFriendList", AppApi.GetFriendList)
_ = wsp.Set("GetGroupMemberInfo", AppApi.GetGroupMemberInfo)
_ = wsp.Set("GetGroupHonorInfo", AppApi.GetGroupHonorInfo)
_ = wsp.Set("GetStatus", AppApi.GetStatus)
_ = wsp.Set("GetCookies", AppApi.GetCookies)
_ = wsp.Set("GetCSRFToken", AppApi.GetCSRFToken)
_ = wsp.Set("GetCredentials", AppApi.GetCredentials)
_ = wsp.Set("GetImage", AppApi.GetImage)
_ = wsp.Set("GetRecord", AppApi.GetRecord)
_ = wsp.Set("CanSendImage", AppApi.CanSendImage)
_ = wsp.Set("CanSendRecord", AppApi.CanSendRecord)
_ = wsp.Set("SetRestart", AppApi.SetRestart)
_ = wsp.Set("CleanCache", AppApi.CleanCache)
_ = wsp.Set("GetVersionInfo", AppApi.GetVersionInfo)
//WST注册
_ = wst.Set("LogWith", AppApi.LogWith)
_ = wst.Set("Log", AppApi.Log)
_ = wst.Set("MsgMarshal", AppApi.MsgUnmarshal)
//WSD注册
_ = wsd.Set("SetUserVariable", DatabaseApi.SetUserVariable)
_ = wsd.Set("SetGroupVariable", DatabaseApi.SetGroupVariable)
_ = wsd.Set("SetOutUserVariable", DatabaseApi.SetOutUserVariable)
_ = wsd.Set("SetOutGroupVariable", DatabaseApi.SetOutGroupVariable)
_ = wsd.Set("UnsafelySetUserVariable", DatabaseApi.UnsafelySetUserVariable)
_ = wsd.Set("UnsafelySetGroupVariable", DatabaseApi.UnsafelySetGroupVariable)
_ = wsd.Set("UnsafelySetGlobalVariable", DatabaseApi.UnsafelySetGlobalVariable)
_ = wsd.Set("UnsafelySetOutUserVariable", DatabaseApi.UnsafelySetOutUserVariable)
_ = wsd.Set("UnsafelySetOutGroupVariable", DatabaseApi.UnsafelySetOutGroupVariable)
_ = wsd.Set("UnsafelySetOutGlobalVariable", DatabaseApi.UnsafelySetOutGlobalVariable)
_ = wsd.Set("GetUserVariable", DatabaseApi.GetUserVariable)
_ = wsd.Set("GetGroupVariable", DatabaseApi.GetGroupVariable)
_ = wsd.Set("GetOutUserVariable", DatabaseApi.GetOutUserVariable)
_ = wsd.Set("GetOutGroupVariable", DatabaseApi.GetOutGroupVariable)
_ = wsd.Set("UnsafelyGetUserVariable", DatabaseApi.UnsafelyGetUserVariable)
_ = wsd.Set("UnsafelyGetGroupVariable", DatabaseApi.UnsafelyGetGroupVariable)
_ = wsd.Set("UnsafelyGetGlobalVariable", DatabaseApi.UnsafelyGetGlobalVariable)
_ = wsd.Set("UnsafelyGetOutUserVariable", DatabaseApi.UnsafelyGetOutUserVariable)
_ = wsd.Set("UnsafelyGetOutGroupVariable", DatabaseApi.UnsafelyGetOutGroupVariable)
_ = wsd.Set("UnsafelyGetOutGlobalVariable", DatabaseApi.UnsafelyGetOutGlobalVariable)
_ = wsd.Set("GetIntConfig", DatabaseApi.GetIntConfig)
_ = wsd.Set("GetFloatConfig", DatabaseApi.GetFloatConfig)
_ = wsd.Set("GetStringConfig", DatabaseApi.GetStringConfig)
_ = wsd.Set("GetIntSliceConfig", DatabaseApi.GetIntSliceConfig)
_ = wsd.Set("GetStringSliceConfig", DatabaseApi.GetStringSliceConfig)
_ = wsd.Set("UnsafelyCreatePublicDatamap", DatabaseApi.UnsafelyCreatePublicDatamap)
_ = wbaObj.Set("newApp", wba.NewApp)
_ = wbaObj.Set("withName", wba.WithSelector)
_ = wbaObj.Set("withDescription", wba.WithDescription)
_ = wbaObj.Set("withWebUrl", wba.WithWebUrl)
_ = wbaObj.Set("withLicense", wba.WithLicense)
_ = wbaObj.Set("wsp", ProtocolApi)
_ = wbaObj.Set("wsd", DatabaseApi)
_ = wbaObj.Set("wst", ToolsApi)
//_ = wbaObj.Set("wsp", wsp)
//_ = wbaObj.Set("wsd", wsd)
//_ = wbaObj.Set("wst", wst)
////WSP注册
//_ = wsp.Set("unsafelySendMsg", ProtocolApi.UnsafelySendMsg)
//_ = wsp.Set("unsafelySendPrivateMsg", ProtocolApi.UnsafelySendPrivateMsg)
//_ = wsp.Set("unsafelySendGroupMsg", ProtocolApi.UnsafelySendGroupMsg)
//_ = wsp.Set("sendMsg", ProtocolApi.SendMsg)
//_ = wsp.Set("sendPrivateMsg", ProtocolApi.SendPrivateMsg)
//_ = wsp.Set("sendGroupMsg", ProtocolApi.SendGroupMsg)
//_ = wsp.Set("unsafelyDeleteMsg", ProtocolApi.UnsafelyDeleteMsg)
//_ = wsp.Set("deleteMsg", ProtocolApi.DeleteMsg)
//_ = wsp.Set("sendLike", ProtocolApi.SendLike)
//_ = wsp.Set("setGroupKick", ProtocolApi.SetGroupKick)
//_ = wsp.Set("setGroupBan", ProtocolApi.SetGroupBan)
//_ = wsp.Set("setGroupWholeBan", ProtocolApi.SetGroupWholeBan)
//_ = wsp.Set("setGroupAdmin", ProtocolApi.SetGroupAdmin)
//_ = wsp.Set("setGroupLeave", ProtocolApi.SetGroupLeave)
//_ = wsp.Set("setGroupCard", ProtocolApi.SetGroupCard)
//_ = wsp.Set("setGroupName", ProtocolApi.SetGroupName)
//_ = wsp.Set("setGroupSpecialTitle", ProtocolApi.SetGroupSpecialTitle)
//_ = wsp.Set("setFriendAddRequest", ProtocolApi.SetFriendAddRequest)
//_ = wsp.Set("setGroupAddRequest", ProtocolApi.SetGroupAddRequest)
//_ = wsp.Set("getLoginInfo", ProtocolApi.GetLoginInfo)
//_ = wsp.Set("getVersionInfo", ProtocolApi.GetVersionInfo)
//_ = wsp.Set("getMsg", ProtocolApi.GetMsg)
//_ = wsp.Set("getGroupInfo", ProtocolApi.GetGroupInfo)
//_ = wsp.Set("getForwardMsg", ProtocolApi.GetForwardMsg)
//_ = wsp.Set("getStrangerInfo", ProtocolApi.GetStrangerInfo)
//_ = wsp.Set("getGroupList", ProtocolApi.GetGroupList)
//_ = wsp.Set("getGroupMemberList", ProtocolApi.GetGroupMemberList)
//_ = wsp.Set("getFriendList", ProtocolApi.GetFriendList)
//_ = wsp.Set("getGroupMemberInfo", ProtocolApi.GetGroupMemberInfo)
//_ = wsp.Set("getGroupHonorInfo", ProtocolApi.GetGroupHonorInfo)
//_ = wsp.Set("getStatus", ProtocolApi.GetStatus)
//_ = wsp.Set("getCookies", ProtocolApi.GetCookies)
//_ = wsp.Set("getCSRFToken", ProtocolApi.GetCSRFToken)
//_ = wsp.Set("getCredentials", ProtocolApi.GetCredentials)
//_ = wsp.Set("getImage", ProtocolApi.GetImage)
//_ = wsp.Set("getRecord", ProtocolApi.GetRecord)
//_ = wsp.Set("canSendImage", ProtocolApi.CanSendImage)
//_ = wsp.Set("canSendRecord", ProtocolApi.CanSendRecord)
//_ = wsp.Set("cetRestart", ProtocolApi.SetRestart)
//_ = wsp.Set("cleanCache", ProtocolApi.CleanCache)
//_ = wsp.Set("getVersionInfo", ProtocolApi.GetVersionInfo)
////WST注册
//_ = wst.Set("logWith", ToolsApi.LogWith)
//_ = wst.Set("log", ToolsApi.Log)
//_ = wst.Set("msgMarshal", ToolsApi.MsgUnmarshal)
////WSD注册
//_ = wsd.Set("setUserVariable", DatabaseApi.SetUserVariable)
//_ = wsd.Set("setGroupVariable", DatabaseApi.SetGroupVariable)
//_ = wsd.Set("setOutUserVariable", DatabaseApi.SetOutUserVariable)
//_ = wsd.Set("setOutGroupVariable", DatabaseApi.SetOutGroupVariable)
//_ = wsd.Set("unsafelySetUserVariable", DatabaseApi.UnsafelySetUserVariable)
//_ = wsd.Set("unsafelySetGroupVariable", DatabaseApi.UnsafelySetGroupVariable)
//_ = wsd.Set("unsafelySetGlobalVariable", DatabaseApi.UnsafelySetGlobalVariable)
//_ = wsd.Set("unsafelySetOutUserVariable", DatabaseApi.UnsafelySetOutUserVariable)
//_ = wsd.Set("unsafelySetOutGroupVariable", DatabaseApi.UnsafelySetOutGroupVariable)
//_ = wsd.Set("unsafelySetOutGlobalVariable", DatabaseApi.UnsafelySetOutGlobalVariable)
//_ = wsd.Set("getUserVariable", DatabaseApi.GetUserVariable)
//_ = wsd.Set("getGroupVariable", DatabaseApi.GetGroupVariable)
//_ = wsd.Set("getOutUserVariable", DatabaseApi.GetOutUserVariable)
//_ = wsd.Set("getOutGroupVariable", DatabaseApi.GetOutGroupVariable)
//_ = wsd.Set("unsafelyGetUserVariable", DatabaseApi.UnsafelyGetUserVariable)
//_ = wsd.Set("unsafelyGetGroupVariable", DatabaseApi.UnsafelyGetGroupVariable)
//_ = wsd.Set("unsafelyGetGlobalVariable", DatabaseApi.UnsafelyGetGlobalVariable)
//_ = wsd.Set("unsafelyGetOutUserVariable", DatabaseApi.UnsafelyGetOutUserVariable)
//_ = wsd.Set("unsafelyGetOutGroupVariable", DatabaseApi.UnsafelyGetOutGroupVariable)
//_ = wsd.Set("unsafelyGetOutGlobalVariable", DatabaseApi.UnsafelyGetOutGlobalVariable)
//_ = wsd.Set("getIntConfig", DatabaseApi.GetIntConfig)
//_ = wsd.Set("getFloatConfig", DatabaseApi.GetFloatConfig)
//_ = wsd.Set("getStringConfig", DatabaseApi.GetStringConfig)
//_ = wsd.Set("getIntSliceConfig", DatabaseApi.GetIntSliceConfig)
//_ = wsd.Set("getStringSliceConfig", DatabaseApi.GetStringSliceConfig)
//_ = wsd.Set("unsafelyCreatePublicDatamap", DatabaseApi.UnsafelyCreatePublicDatamap)
// 获取AppInit函数
appInitVal := runtime.Get("AppInit")
@ -169,49 +215,68 @@ func reloadAPP(file os.DirEntry, appsDir string) (totalDelta int, successDelta i
return 1, 0
}
// 调用Init方法
initVal := jsApp.ToObject(runtime).Get("Init")
initFunc, ok := goja.AssertFunction(initVal)
if !ok {
LOG.Error("应用 %s 缺少有效的Init方法", pluginPath)
return 1, 0
}
_, err = initFunc(wbaObj)
if err != nil {
LOG.Trace("应用初始化失败: %v", err)
return 1, 0
}
// 调用Get方法
getVal := jsApp.ToObject(runtime).Get("Get")
getFunc, ok := goja.AssertFunction(getVal)
if !ok {
LOG.Error("应用 %s 缺少有效的Get方法", pluginPath)
return 1, 0
}
appInfoVal, err := getFunc(jsApp)
if err != nil {
LOG.Error("获取应用信息失败: %v", err)
return 1, 0
}
//// 调用Init方法
//initVal := jsApp.ToObject(runtime).Get("Init")
//initFunc, ok := goja.AssertFunction(initVal)
//if !ok {
// LOG.Error("应用 %s 缺少有效的Init方法 %#v", pluginPath, initFunc)
// return 1, 0
//}
//
//_, err = initFunc(wbaObj)
//if err != nil {
// LOG.Trace("应用初始化失败: %v", err)
// return 1, 0
//}
//
//// 调用Get方法
//getVal := jsApp.ToObject(runtime).Get("Get")
//getFunc, ok := goja.AssertFunction(getVal)
//if !ok {
// LOG.Error("应用 %s 缺少有效的Get方法", pluginPath)
// return 1, 0
//}
//
//appInfoVal, err := getFunc(jsApp)
//if err != nil {
// LOG.Error("获取应用信息失败: %v", err)
// return 1, 0
//}
// 转换应用信息
var appInfo wba.AppInfo
if err := runtime.ExportTo(appInfoVal, &appInfo); err != nil {
if err := runtime.ExportTo(jsApp, &appInfo); err != nil {
LOG.Error("应用信息转换失败: %v", err)
return 1, 0
}
// 初始化map字段
if appInfo.CmdMap == nil {
appInfo.CmdMap = make(map[string]wba.Cmd)
}
if appInfo.ScheduledTasks == nil {
appInfo.ScheduledTasks = make(map[string]wba.ScheduledTaskInfo)
}
AppMap[wba.AppKey{Name: appInfo.AppKey.Name, Type: appInfo.AppKey.Type, Version: appInfo.AppKey.Version, Level: checkAppLevel(appInfo)}] = appInfo
cmdIndex := AppTypeToInt(appInfo.AppKey.Type)
// 合并命令
CmdMap[cmdIndex] = mergeMaps(CmdMap[cmdIndex], appInfo.CmdMap)
AppMap[appInfo.AppKey] = appInfo
CmdMap[appInfo.AppKey] = appInfo.CmdMap
ScheduledTaskMap[appInfo.AppKey] = appInfo.ScheduledTasks
// 注册定时任务
for _, task := range appInfo.ScheduledTasks {
RegisterCron(appInfo.AppKey.Name, task)
taskCopy := task
RegisterCron(appInfo.AppKey.Name, wba.ScheduledTaskInfo{
Name: taskCopy.Name,
Desc: taskCopy.Desc,
Cron: taskCopy.Cron,
Task: func() {
safeRun(func() error {
taskCopy.Task()
return nil
})
},
})
}
LOG.Info("JS应用 %s 加载成功", pluginPath)
@ -219,31 +284,3 @@ func reloadAPP(file os.DirEntry, appsDir string) (totalDelta int, successDelta i
}
return 0, 0
}
func mergeMaps(map1, map2 map[string]wba.Cmd) map[string]wba.Cmd {
// 合并map1和map2到map3中
map3 := make(map[string]wba.Cmd)
for key, value := range map1 {
map3[key] = value
}
for key, value := range map2 {
map3[key] = value
}
return map3
}
func AppTypeToInt(appType string) int32 {
appType = strings.ToLower(appType)
switch appType {
case "system":
return 1
case "rule":
return 2
default:
return 3
}
}
func checkAppLevel(appInfo wba.AppInfo) int32 {
return 0
}

View File

@ -3,35 +3,27 @@ package core
import (
"ProjectWIND/LOG"
"ProjectWIND/wba"
"errors"
)
type CmdListInfo map[string]wba.Cmd
type AppInfo struct {
CmdMap map[string]wba.Cmd
AppKey wba.AppKey
}
func (app AppInfo) Get() AppInfo {
return app
}
func (app *AppInfo) Run(cmd string, args []string, msg wba.MessageEventInfo) error {
_, ok := app.CmdMap[cmd]
if !ok {
return errors.New("cmd not found")
}
app.CmdMap[cmd].Solve(args, msg)
return nil
}
func (app *AppInfo) Init(Api wba.WindStandardProtocolAPI) error {
return nil
}
func (app *AppInfo) InitWSD(Api wba.WindStandardDataBaseAPI) error {
return nil
}
//func (app AppInfo) Get() AppInfo {
// return app
//}
//
//func (app *AppInfo) Run(cmd string, args []string, msg wba.MessageEventInfo) error {
// _, ok := app.CmdMap[cmd]
// if !ok {
// return errors.New("cmd not found")
// }
// app.CmdMap[cmd].Solve(args, msg)
// return nil
//}
func (app *AppInfo) GetCmd() map[string]wba.Cmd {
return app.CmdMap
@ -46,14 +38,29 @@ func NewCmd(name string, help string, solve func(args []string, msg wba.MessageE
}
var AppCore = AppInfo{
AppKey: wba.AppKey{
Name: "core",
Level: 0,
Version: "1.0.0",
Selector: "core",
Option: "core",
},
CmdMap: CmdListInfo{
"bot": NewCmd(
"bot",
"显示WIND版本信息",
func(args []string, msg wba.MessageEventInfo) {
AppApi.SendMsg(msg, "WIND 0.1.0", false)
ProtocolApi.SendMsg(msg, "WIND 0.1.0", false)
LOG.Info("发送核心版本信息:(至:%v-%v:%v-%v)", msg.MessageType, msg.GroupId, msg.UserId, msg.Sender.Nickname)
},
),
"help": NewCmd(
"help",
"显示帮助信息",
func(args []string, msg wba.MessageEventInfo) {
ProtocolApi.SendMsg(msg, "帮助信息", false)
LOG.Info("发送帮助信息:(至:%v-%v:%v-%v)", msg.MessageType, msg.GroupId, msg.UserId, msg.Sender.Nickname)
},
),
},
}

View File

@ -3,7 +3,6 @@ package core
import (
"ProjectWIND/LOG"
"ProjectWIND/database"
"ProjectWIND/typed"
"ProjectWIND/wba"
"encoding/json"
"fmt"
@ -19,8 +18,14 @@ func HandleMessage(msgJson []byte) {
}
// 处理消息
LOG.Info("收到消息:(来自:%v-%v:%v-%v)%v", msg.MessageType, msg.GroupId, msg.UserId, msg.Sender.Nickname, msg.RawMessage)
CmdHandle(msg)
fmt.Printf("%#v\n", msg.Message)
isCmd, ok, err := CmdHandle(msg)
if err != nil {
LOG.Error("命令处理失败: %v", err)
}
if !isCmd && ok {
// 处理消息
// TODO: 处理消息
}
}
func HandleNotice(msgJson []byte) {
@ -50,102 +55,60 @@ func HandleMetaEvent(msgJson []byte) {
// TODO: 处理元事件
}
func CmdSplit(msg wba.MessageEventInfo) (string, []string) {
//text := msg.RawMessage
//if strings.HasPrefix(text, fmt.Sprintf("[CQ:at,qq=%d]", msg.SelfId)) {
// text = strings.TrimPrefix(text, fmt.Sprintf("[CQ:at,qq=%d]", msg.SelfId))
//} else {
// if !statusCheck(msg) {
// return "", []string{}
// }
//}
////检查有无application.CmdMap中的命令前缀
//for _, prefix := range cmdPrefix {
// if strings.HasPrefix(text, prefix) {
// text = strings.TrimPrefix(text, prefix)
// for cmdList := range CmdMap {
// for cmd := range CmdMap[cmdList] {
// if strings.HasPrefix(text, cmd) {
// text = strings.TrimPrefix(text, cmd)
// text = strings.TrimPrefix(text, " ")
// return cmd, strings.Split(text, " ")
// }
// }
// }
// }
//}
return "", []string{}
}
func CmdHandle(msg wba.MessageEventInfo) {
func CmdHandle(msg wba.MessageEventInfo) (isCmd bool, ok bool, err error) {
// 获取消息的原始文本
text := msg.GetText()
// 初始化会话工作状态
WorkStatus := typed.SessionWorkSpace{}
if msg.MessageType == "group" {
// 如果消息类型是群消息
// 从数据库中获取工作状态信息
WorkStatusJson, ok := database.MasterGet("WorkStatus", "global", strconv.FormatInt(msg.SelfId, 10), strconv.FormatInt(msg.GroupId, 10))
// 尝试将获取到的工作状态信息反序列化为 WorkStatus 结构体
err := json.Unmarshal([]byte(WorkStatusJson.(string)), &WorkStatus)
// 如果获取失败或反序列化失败
if !ok || err != nil {
// 初始化一个新的工作状态
WorkStatus = typed.SessionWorkSpace{
SessionId: fmt.Sprintf("%d-%d", msg.SelfId, msg.GroupId),
Rule: "coc",
Enable: true,
AppEnable: make(map[wba.AppKey]bool),
CmdEnable: make(map[string]bool),
WorkLevel: 0,
}
// 将新的工作状态序列化为 JSON 字符串
WorkStatusJson, err := json.Marshal(WorkStatus)
if err != nil {
// 如果序列化失败,记录错误信息
LOG.Error("命令处理过程中WorkStatusJson序列化失败: %v", err)
}
// 将序列化后的工作状态保存到数据库中
database.MasterSet("WorkStatus", "global", strconv.FormatInt(msg.SelfId, 10), strconv.FormatInt(msg.GroupId, 10), string(WorkStatusJson))
session := wba.SessionInfo{}
session = session.Load("QQ", msg)
// 从数据库加载配置
conf, ok := database.MasterGet("GCAS_Config", session.SessionType, strconv.FormatInt(session.SessionId, 10), "GCAS_Config")
if !ok {
conf = "{}"
}
if err = GlobalCmdAgentSelector.LoadConfig(session, conf.(string)); err != nil {
LOG.Error("加载配置失败: %v", err)
return false, false, err
}
// 调用 CmdSplit 函数将消息文本拆分为命令和参数
cmd, args := CmdSplit(msg)
// 检查命令前缀
for _, prefix := range cmdPrefix {
if strings.HasPrefix(text, prefix) {
// 解析命令
text = strings.TrimPrefix(text, prefix)
cmdSlice := strings.Split(text, " ")
if text == "" {
return false, true, nil
}
cmd := cmdSlice[0]
args := cmdSlice[1:]
// 检查是否找到了有效的命令
if cmd != "" {
// 遍历命令映射表 CmdMap
for _, cmdList := range CmdMap {
for cmdKey, Cmd := range cmdList {
// 如果找到了匹配的命令
if cmdKey == cmd {
// 检查会话工作状态
if WorkStatus.SessionId != "" {
if !WorkStatus.Enable {
// 如果会话未启用,忽略该命令
LOG.Debug("忽略指令:%s,当前会话中bot未启用", cmd)
continue
result, count := GlobalCmdAgentSelector.FindCmd(cmd, true)
if count == 0 {
LOG.Debug("未找到命令: %s", cmd)
return false, true, nil
}
// 检查 APP 或命令是否启用,以及工作级别和规则是否匹配
if !WorkStatus.AppEnable[Cmd.AppKey] || !WorkStatus.CmdEnable[cmd] || WorkStatus.WorkLevel > Cmd.AppKey.Level || (WorkStatus.Rule != Cmd.AppKey.Rule && WorkStatus.Rule != "none") {
// 如果不满足条件,忽略该命令
LOG.Debug("忽略指令:%s,当前会话中APP或命令未启用", cmd)
continue
// 执行找到的第一个匹配命令
cmdFunc := result[0]
if err := safeExecuteCmd(cmdFunc, args, msg); err != nil {
LOG.Error("执行命令失败: %v", err)
return true, false, err
}
return true, true, nil
}
}
// 执行命令
Cmd.Solve(args, msg)
// 记录执行的命令和参数
LOG.Info("执行命令:%v %v", cmd, args)
return false, true, nil
}
func safeExecuteCmd(cmdFunc wba.Cmd, args []string, msg wba.MessageEventInfo) (err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("%v", r)
}
}
} else {
// 如果未找到有效的命令,记录未找到命令的信息
LOG.Info("未找到命令:%v", strings.Split(text, " ")[0])
}
}()
cmdFunc.Solve(args, msg)
return nil
}
var cmdPrefix = []string{"/", "!", "", "", ".", "。"}

48
core/selector_doc.md Normal file
View File

@ -0,0 +1,48 @@
# Selector设计思路与使用说明
## 问题背景
在骰子执行指令时,我们经常遇到这样一些问题:
- 不同的插件可能使用相同的指令(很多跑团对应规则都有同名的指令),但是参数和功能完全不同,导致指令无法正常执行。并且当其中有系统级指令时,可能会导致其他严重问题,此时需要一个机制来区分指令。
- 当我们在进行trpg时日志开启后可能需要屏蔽某些无关的指令和自定义回复此时需要一个机制来过滤指令和回复即权限控制
- 在不同的群聊中,各种插件的开启情况各不相同,此时需要一个机制来管理不同组群插件的开启和关闭情况(包括前两条中的权限控制问题)。
为解决上述问题,我们设计了一个指令选择器,用于管理和选择指令。
## 设计思路
选择器的设计思路如下:
- 每个组群有一个独立的总选择器(Agent Selector),用于管理该组群的指令和回复。
- 每个选择器有若干个层级(Level),在查找可用指令(Cmd)时,从最高层级(0)开始查找,直到找到可用指令为止。
- 每个层级有若干个选择器(Selector),每个选择器中包含若干个选项(Option),每个选项对应一个指令集(CmdSet)。每个选择器只能同时选择一个选项,选择后其余选项中的指令集将被屏蔽。
- 指令集是由若干个应用(App)中的指令组成的,一个应用只能归属于一个指令集,一个指令集可以包含多个应用的指令。
数据结构如下:
```go
type AgentSelector struct {
Session wba.Session
Selectors []Selector
}
type Selector struct {
Level int
Name string
Options []*Option
}
type Option struct {
Name string
CmdSets map[string]CmdSet
}
type CmdSet struct {
map[string]wba.Command
}
type Cmmand struct {
Name string
Desc string
App AppKey
Solve func(*wba.Context)
}
```

View File

@ -44,9 +44,9 @@ func WebSocketHandler(protocol typed.Protocol) error {
}
}(conn)
LOG.Info("已连接到WebSocket服务器: %v", u.String())
ProtocolInfo := AppApi.GetVersionInfo()
ProtocolInfo := ProtocolApi.GetVersionInfo()
LOG.Info("协议端信息: %v-%v", ProtocolInfo.Data.AppName, ProtocolInfo.Data.AppVersion)
logInfo := AppApi.GetLoginInfo()
logInfo := ProtocolApi.GetLoginInfo()
LOG.Info("连接到账号: %v%v", logInfo.Data.Nickname, logInfo.Data.UserId)
// 定义通道,缓存消息和消息类型,防止消息处理阻塞

View File

@ -1,5 +1,7 @@
package wba
import "strings"
type AppInfo struct {
AppKey AppKey
Author string
@ -64,6 +66,13 @@ func WithLevel(level uint8) AppInfoOption {
}
}
func toCamelCase(s string) string {
if s == "" {
return s
}
return strings.ToLower(s[:1]) + s[1:]
}
func NewApp(name string, version string, author string, opts ...AppInfoOption) AppInfo {
Ext := AppInfo{
AppKey: AppKey{
@ -84,6 +93,15 @@ func NewApp(name string, version string, author string, opts ...AppInfoOption) A
for _, opt := range opts {
opt(&Ext)
}
// 添加JS风格方法
Ext.API = map[string]interface{}{
toCamelCase("NewCmd"): Ext.NewCmd,
toCamelCase("AddCmd"): Ext.AddCmd,
toCamelCase("NewScheduledTask"): Ext.NewScheduledTask,
toCamelCase("AddScheduledTask"): Ext.AddScheduledTask,
}
return Ext
}
@ -127,7 +145,7 @@ type AppKey struct {
Option OptionLabel `json:"option"`
}
// Priority 是一个整数类型用于表示命令的优先级。只能是不小于1的整数。
// Priority 是一个整数类型用于表示命令的优先级。只能是不小于1且不大于4的整数。
type Priority = uint8
// VersionLabel 是一个字符串类型,用于表示版本标签。
@ -142,15 +160,45 @@ type OptionLabel = string
// SessionLabel 是一个字符串类型,用于表示聊天会话的标签,格式为[平台:类型-ID],如"QQ:group-1145141919810"
type SessionLabel = string
// CmdSetLabel 是一个字符串类型,用于表示命令集的标签。
type CmdSetLabel = string
// CmdLabel 是一个字符串类型,用于表示命令的标签。
type CmdLabel = string
// CmdList 是一个字符串到 wba.Cmd 的映射,用于存储命令的列表。
type CmdList = map[string]Cmd
// SessionInfo 是一个结构体,用于存储会话信息。
//
// 字段:
// - Platform: 表示会话的平台,如"QQ"、"Telegram"等。
// - SessionType: 表示会话的类型,如"group"、"private"等。
// - SessionId: 表示会话的ID如群号、私聊号等。
type SessionInfo struct {
Platform string
SessionType string
SessionId int64
}
func (s *SessionInfo) Load(platform string, msg MessageEventInfo) SessionInfo {
s.Platform = platform
s.SessionType = msg.MessageType
if s.SessionType == "group" {
s.SessionId = msg.GroupId
}
if s.SessionType == "private" {
s.SessionId = msg.UserId
}
return *s
}
// VersionInfo 是一个结构体,用于存储版本信息。
//
// 字段:
// - BigVersion: 表示大版本号。
// - SmallVersion: 表示小版本号。
// - FixVersion: 表示修复版本号。
type VersionInfo struct {
BigVersion uint8
SmallVersion uint8

360
wba/selector.go Normal file
View File

@ -0,0 +1,360 @@
package wba
import (
"ProjectWIND/LOG"
"encoding/json"
"fmt"
)
type CmdAgentSelector struct {
Session SessionInfo
Selectors [4]map[SelectorLabel]Selector
cmdTable map[CmdLabel]map[CmdSetLabel]struct{}
cmdSetTable map[CmdSetLabel]map[OptionLabel]struct{}
optionTable map[OptionLabel][]map[SelectorLabel]struct{}
}
type Selector struct {
Level Priority
Name SelectorLabel
Options map[OptionLabel]Option
currentOption OptionLabel
}
type Option struct {
Name string
CmdSets map[CmdSetLabel]CmdSet
}
type CmdSet struct {
Name CmdSetLabel
Cmds map[CmdLabel]CmdInfo
Enabled bool
}
type CmdInfo struct {
Name CmdLabel
Cmd Cmd
Enabled bool
}
// NewCmdAgentSelector 创建一个新的 CmdAgentSelector 实例并初始化。
//
// 参数:
//
// - session: 所属会话信息。
func NewCmdAgentSelector() CmdAgentSelector {
c := CmdAgentSelector{
Session: SessionInfo{},
Selectors: [4]map[SelectorLabel]Selector{},
cmdTable: make(map[CmdLabel]map[CmdSetLabel]struct{}),
cmdSetTable: make(map[CmdSetLabel]map[OptionLabel]struct{}),
optionTable: make(map[OptionLabel][]map[SelectorLabel]struct{}),
}
for i := 0; i < 4; i++ {
c.Selectors[i] = make(map[SelectorLabel]Selector)
c.optionTable[fmt.Sprintf("%d", i)] = make([]map[SelectorLabel]struct{}, 4)
}
return c
}
func (a *CmdAgentSelector) LoadConfig(session SessionInfo, config string) error {
a.Session = session
conf := CmdAgentSelector{}
err := json.Unmarshal([]byte(config), &conf)
if err != nil {
return err
}
for i := 0; i < 4; i++ {
for selectorName, selector := range a.Selectors[i] {
selector.currentOption = conf.Selectors[i][selectorName].currentOption
for optionName, option := range selector.Options {
for cmdSetName, cmdSet := range option.CmdSets {
for cmdName, cmd := range cmdSet.Cmds {
cmd.Enabled = conf.Selectors[i][selectorName].Options[optionName].CmdSets[cmdSetName].Cmds[cmdName].Enabled
}
}
}
}
}
return nil
}
// AddCmdMap 添加一个命令映射(map[AppKey]CmdList)到 CmdAgentSelector 中。
//
// 参数:
//
// - cmdMap: 命令映射,键为 AppKey值为 CmdList。
func (a *CmdAgentSelector) AddCmdMap(cmdMap map[AppKey]CmdList) {
for appKey, cmds := range cmdMap {
a.AddCmdSet(appKey, cmds)
}
}
// AddCmdSet 添加一个命令集(即APP)到 CmdAgentSelector 中。
//
// 参数:
//
// - appKey: 应用键,包含应用名称、级别、选择器和选项。
// - cmds: 命令列表,键为命令名称,值为 CmdInfo。
func (a *CmdAgentSelector) AddCmdSet(appKey AppKey, cmds CmdList) {
for cmdName, cmd := range cmds {
// 确保所有必要的map已初始化
if a.cmdTable == nil {
a.cmdTable = make(map[CmdLabel]map[CmdSetLabel]struct{})
}
if a.cmdSetTable == nil {
a.cmdSetTable = make(map[CmdSetLabel]map[OptionLabel]struct{})
}
if a.optionTable == nil {
a.optionTable = make(map[OptionLabel][]map[SelectorLabel]struct{})
}
// 初始化嵌套map
if a.cmdTable[cmdName] == nil {
a.cmdTable[cmdName] = make(map[CmdSetLabel]struct{})
}
if a.cmdSetTable[appKey.Name] == nil {
a.cmdSetTable[appKey.Name] = make(map[OptionLabel]struct{})
}
if a.optionTable[appKey.Option] == nil {
a.optionTable[appKey.Option] = make([]map[SelectorLabel]struct{}, 4)
}
if a.optionTable[appKey.Option][appKey.Level] == nil {
a.optionTable[appKey.Option][appKey.Level] = make(map[SelectorLabel]struct{})
}
// 确保Selector层级的map已初始化
if a.Selectors[appKey.Level] == nil {
a.Selectors[appKey.Level] = make(map[SelectorLabel]Selector)
}
if a.Selectors[appKey.Level][appKey.Selector].Options == nil {
selector := a.Selectors[appKey.Level][appKey.Selector]
selector.Options = make(map[OptionLabel]Option)
a.Selectors[appKey.Level][appKey.Selector] = selector
}
if a.Selectors[appKey.Level][appKey.Selector].Options[appKey.Option].CmdSets == nil {
selector := a.Selectors[appKey.Level][appKey.Selector]
option := selector.Options[appKey.Option]
option.CmdSets = make(map[CmdSetLabel]CmdSet)
selector.Options[appKey.Option] = option
a.Selectors[appKey.Level][appKey.Selector] = selector
}
if a.Selectors[appKey.Level][appKey.Selector].Options[appKey.Option].CmdSets[appKey.Name].Cmds == nil {
selector := a.Selectors[appKey.Level][appKey.Selector]
option := selector.Options[appKey.Option]
cmdSet := option.CmdSets[appKey.Name]
cmdSet.Cmds = make(map[CmdLabel]CmdInfo)
option.CmdSets[appKey.Name] = cmdSet
selector.Options[appKey.Option] = option
a.Selectors[appKey.Level][appKey.Selector] = selector
}
a.cmdTable[cmdName][appKey.Name] = struct{}{}
a.cmdSetTable[appKey.Name][appKey.Option] = struct{}{}
a.optionTable[appKey.Option][appKey.Level][appKey.Selector] = struct{}{}
a.Selectors[appKey.Level][appKey.Selector].Options[appKey.Option].CmdSets[appKey.Name].Cmds[cmdName] = CmdInfo{
Cmd: cmd,
Enabled: true,
}
LOG.Debug("add cmd: %s, app: %s, option: %s, cmdSet: %s", cmdName, appKey.Name, appKey.Option, appKey.Selector)
}
a.Selectors[appKey.Level][appKey.Selector].Options[appKey.Option].CmdSets[appKey.Name] = CmdSet{
Name: appKey.Name,
Cmds: a.Selectors[appKey.Level][appKey.Selector].Options[appKey.Option].CmdSets[appKey.Name].Cmds,
Enabled: true,
}
if a.Selectors[appKey.Level][appKey.Selector].currentOption == "" {
a.Selectors[appKey.Level][appKey.Selector] = Selector{
Level: appKey.Level,
Name: appKey.Selector,
Options: a.Selectors[appKey.Level][appKey.Selector].Options,
currentOption: appKey.Option,
}
}
}
// FindCmd 根据命令名称和是否只查找启用的命令,查找符合条件的命令。
//
// 参数:
//
// - cmdName: 要查找的命令名称。
// - onlyEnabled: 是否只查找启用的命令。
//
// 返回值:
//
// - result: 找到的命令列表(越靠前的优先级越高)。
// - count: 找到的命令数量。
func (a *CmdAgentSelector) FindCmd(cmdName string, onlyEnabled bool) (result []Cmd, count int) {
result = make([]Cmd, 0)
count = 0
cmdSets := a.cmdTable[cmdName]
for cmdSet := range cmdSets {
options := a.cmdSetTable[cmdSet]
for option := range options {
selectors := a.optionTable[option]
for i := 0; i < len(a.Selectors); i++ {
for selector := range selectors[i] {
if option != a.Selectors[i][selector].currentOption && onlyEnabled {
continue
}
cmdInfo := a.Selectors[i][selector].Options[option].CmdSets[cmdSet].Cmds[cmdName]
if onlyEnabled && !cmdInfo.Enabled {
continue
}
result = append(result, cmdInfo.Cmd)
count++
}
}
}
}
return result, count
}
// FindCmdSet 根据命令集名称和是否只查找启用的命令集,查找符合条件的命令集。
//
// 参数:
//
// - cmdSetName: 要查找的命令集名称。
// - onlyEnabled: 是否只查找启用的命令集。
//
// 返回值:
//
// - result: 找到的命令集列表(越靠前的优先级越高)。
// - count: 找到的命令集数量。
func (a *CmdAgentSelector) FindCmdSet(cmdSetName string, onlyEnabled bool) (result []CmdSet, count int) {
result = make([]CmdSet, 0)
count = 0
options := a.cmdSetTable[cmdSetName]
for option := range options {
selectors := a.optionTable[option]
for i := 0; i < len(a.Selectors); i++ {
for selector := range selectors[i] {
if option != a.Selectors[i][selector].currentOption && onlyEnabled {
continue
}
cmdSet := a.Selectors[i][selector].Options[option].CmdSets[cmdSetName]
result = append(result, cmdSet)
count++
}
}
}
return result, count
}
// FindOption 根据选项名称,查找符合条件的选项。
//
// 参数:
//
// - optionName: 要查找的选项名称。
//
// 返回值:
//
// - result: 找到的选项列表(越靠前的优先级越高)。
// - count: 找到的选项数量。
func (a *CmdAgentSelector) FindOption(optionName string) (result []Option, count int) {
result = make([]Option, 0)
count = 0
selectors := a.optionTable[optionName]
for i := 0; i < len(a.Selectors); i++ {
for selector := range selectors[i] {
if optionName != a.Selectors[i][selector].currentOption {
continue
}
option := a.Selectors[i][selector].Options[optionName]
result = append(result, option)
count++
}
}
return result, count
}
// FindSelector 根据选择器名称,查找符合条件的选择器。
//
// 参数:
//
// - selectorName: 要查找的选择器名称。
//
// 返回值:
//
// - result: 找到的选择器列表(越靠前的优先级越高)。
// - count: 找到的选择器数量。
func (a *CmdAgentSelector) FindSelector(selectorName string) (result []Selector, count int) {
result = make([]Selector, 0)
count = 0
selectors := a.optionTable[selectorName]
for i := 0; i < len(a.Selectors); i++ {
for selector := range selectors[i] {
if selectorName != a.Selectors[i][selector].currentOption {
continue
}
selector := a.Selectors[i][selector]
result = append(result, selector)
count++
}
}
return result, count
}
// GetCurrentOption 获取当前选择器的当前选项。
//
// 参数:
//
// - level: 选择器的级别。
// - selectorName: 选择器的名称。
//
// 返回值:
//
// - result: 当前选项当isExist为false时此结果为 Option 对应的空值。
// - isExist: 是否存在当前选项。
func (a *CmdAgentSelector) GetCurrentOption(level int, selectorName string) (result Option, isExist bool) {
result, ok := a.Selectors[level][selectorName].Options[a.Selectors[level][selectorName].currentOption]
if !ok {
return Option{}, false
}
return result, true
}
// ToggleCmd 切换命令的启用状态。
//
// 参数:
//
// - enabled: 要设置的启用状态。
// - level: 选择器的级别。
// - selectorName: 选择器的名称。
// - optionName: 选项的名称。
// - cmdSetName: 命令集的名称。
// - cmdName: 命令的名称。
//
// 返回值:
//
// - state: 命令的启用状态。
// - preState: 命令的之前的启用状态。
// - err: 错误信息,当发生错误时返回。
func (a *CmdAgentSelector) ToggleCmd(enabled bool, level Priority, selectorName SelectorLabel, optionName OptionLabel, cmdSetName CmdSetLabel, cmdName CmdLabel) (state bool, preState bool, err error) {
if level < 0 || level > 3 {
return false, false, fmt.Errorf("level must be between 0 and 3")
}
selector, ok := a.Selectors[level][selectorName]
if !ok {
return false, false, fmt.Errorf("selector %s not found", selectorName)
}
option, ok := selector.Options[optionName]
if !ok {
return false, false, fmt.Errorf("option %s not found", optionName)
}
cmdSet, ok := option.CmdSets[cmdName]
if !ok {
return false, false, fmt.Errorf("cmdSet %s not found", cmdName)
}
cmdInfo, ok := cmdSet.Cmds[cmdName]
if !ok {
return false, false, fmt.Errorf("cmd %s not found", cmdName)
}
preState = cmdInfo.Enabled
cmdInfo.Enabled = enabled
a.Selectors[level][selectorName].Options[optionName].CmdSets[cmdSetName].Cmds[cmdName] = cmdInfo
return enabled, preState, nil
}

View File

@ -2,8 +2,6 @@ package wba
import (
"fmt"
"strconv"
"strings"
)
type WindStandardTools interface {
@ -11,13 +9,15 @@ type WindStandardTools interface {
//
// 参数:
//
// - message: 要解析的消息字符串。
// - message: 要解析的消息JSON字符串。
//
// 返回值:
//
// - msg: 解析后的消息结构体。
MsgUnmarshal(message string) (msg MessageEventInfo)
// LogWith 使用指定日志级别记录日志,支持可变参数占位符。
//
// 参数:
// - level: 日志级别: "trace", "debug", "info", "notice", "warn", "error"。
// - log: 日志内容。
@ -25,49 +25,38 @@ type WindStandardTools interface {
LogWith(level string, log string, args ...interface{})
// Log 记录日志,级别为 "info",支持可变参数占位符。
//
// 参数:
// - log: 日志内容。
// - args: 可变参数,用于格式化日志内容。
Log(log string, args ...interface{})
// VersionLabelAnalysis 解析版本标签为 VersionInfo 结构体。
//
// 参数:
// - versionLabel: 版本标签字符串,格式为 "大版本.小版本.修复版本"。
// 返回值:
// - versionInfo: 解析后的版本信息结构体。
VersionLabelAnalysis(versionLabel VersionLabel) (versionInfo VersionInfo)
// VersionCompare 比较两个版本标签的大小。
//
// 参数:
// - version1: 第一个版本标签字符串。
// - version2: 第二个版本标签字符串。
// 返回值:
// - result: 比较结果,-1表示version1小于version20表示version1等于version21表示version1大于version2。
VersionCompare(version1, version2 VersionLabel) (result int)
// SessionLabelAnalysis 解析会话标签为 SessionInfo 结构体。
//
// 参数:
// - sessionLabel: 会话标签字符串,格式为 "平台:会话类型-会话ID"。
// 返回值:
// - sessionInfo: 解析后的会话信息结构体。
SessionLabelAnalysis(sessionLabel SessionLabel) (sessionInfo SessionInfo)
}
func (v VersionInfo) String() string {
return fmt.Sprintf("%d.%d.%d", v.BigVersion, v.SmallVersion, v.FixVersion)
}
func VersionLabelAnalysis(versionLabel VersionLabel) VersionInfo {
version := strings.Split(versionLabel, ".")
bigVersion, err := strconv.ParseUint(version[0], 10, 8)
if err != nil {
return VersionInfo{}
}
smallVersion, err := strconv.ParseUint(version[1], 10, 8)
if err != nil {
return VersionInfo{}
}
fixVersion, err := strconv.ParseUint(version[2], 10, 8)
if err != nil {
return VersionInfo{}
}
return VersionInfo{
BigVersion: uint8(bigVersion),
SmallVersion: uint8(smallVersion),
FixVersion: uint8(fixVersion),
}
}
func SessionLabelAnalysis(sessionLabel SessionLabel) SessionInfo {
platform := strings.Split(sessionLabel, ":")[0]
sessionTypeAndId := strings.Split(sessionLabel, ":")[1]
sessionType := strings.Split(sessionTypeAndId, "-")[0]
sessionId := strings.Split(sessionTypeAndId, "-")[1]
Id, err := strconv.ParseInt(sessionId, 10, 64)
if err != nil {
return SessionInfo{}
}
return SessionInfo{
Platform: platform,
SessionType: sessionType,
SessionId: Id,
}
}