forked from ProjectWIND/ProjectWIND
Compare commits
32 Commits
Author | SHA1 | Date | |
---|---|---|---|
c05cdddb1e | |||
![]() |
2141cd9840 | ||
![]() |
33e0d1048c | ||
![]() |
9e47650032 | ||
![]() |
995fba34b4 | ||
![]() |
93538afaeb | ||
![]() |
c9d36abe4a | ||
5e3fc91cc2 | |||
5fd2e7bbdd | |||
![]() |
ea5ac718b7 | ||
5a36235774 | |||
4cc3808ab8 | |||
![]() |
5659914298 | ||
![]() |
8e604fd397 | ||
cdc0316c52 | |||
2452df4da6 | |||
0a3a260eda | |||
![]() |
5a5c3a4c48 | ||
8a49ded455 | |||
![]() |
c63f4c2dd8 | ||
![]() |
944fadc688 | ||
![]() |
7eab31081c | ||
dfc10927b3 | |||
308560facd | |||
![]() |
753c6dc0ca | ||
![]() |
c2382c8a31 | ||
e22b2f980d | |||
bb599fad28 | |||
d5fedc873b | |||
5ff2e78a86 | |||
![]() |
ab7f30660d | ||
![]() |
f7905c7f56 |
8
.gitignore
vendored
8
.gitignore
vendored
@ -1,8 +1,6 @@
|
||||
/tmp
|
||||
/scripts
|
||||
/ProjectWIND
|
||||
/data
|
||||
tmp/
|
||||
data/
|
||||
**/.DS_Store
|
||||
/app_demo/
|
||||
.idea/
|
||||
.vscode/
|
||||
ProjectWIND
|
155
LOG/log.go
155
LOG/log.go
@ -1,40 +1,157 @@
|
||||
package LOG
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/cloudwego/hertz/pkg/common/hlog"
|
||||
"io"
|
||||
"log"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func DEBUG(text string, msg ...interface{}) {
|
||||
pc, file, line, ok := runtime.Caller(3)
|
||||
if !ok {
|
||||
pc, file, line, ok = runtime.Caller(2)
|
||||
}
|
||||
if ok {
|
||||
funcName := runtime.FuncForPC(pc).Name()
|
||||
log.Printf("[DEBUG] [%s:%d %s()] %s\n", file, line, funcName, fmt.Sprintf(text, msg...))
|
||||
} else {
|
||||
log.Printf("[DEBUG] %s\n", fmt.Sprintf(text, msg...))
|
||||
func Trace(text string, msg ...interface{}) {
|
||||
var pc uintptr
|
||||
var file string
|
||||
var line int
|
||||
var ok bool
|
||||
// 从第 2 层开始循环查找调用栈,直到找不到调用信息为止
|
||||
for i := 2; ; i++ {
|
||||
pc, file, line, ok = runtime.Caller(i)
|
||||
if !ok || line <= 0 {
|
||||
pc, file, line, ok = runtime.Caller(i - 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
funcName := runtime.FuncForPC(pc).Name()
|
||||
log.Printf("[Trace] [%s:%d %s()] %s\n", file, line, funcName, fmt.Sprintf(text, msg...))
|
||||
}
|
||||
|
||||
func INFO(text string, msg ...interface{}) {
|
||||
msgText := fmt.Sprintf(text, msg...)
|
||||
log.Println("[INFO] ", msgText)
|
||||
func Debug(text string, msg ...interface{}) {
|
||||
log.Printf("[Debug] %s\n", fmt.Sprintf(text, msg...))
|
||||
}
|
||||
|
||||
func WARN(text string, msg ...interface{}) {
|
||||
func Info(text string, msg ...interface{}) {
|
||||
msgText := fmt.Sprintf(text, msg...)
|
||||
log.Println("[WARN] ", msgText)
|
||||
log.Println("[Info] ", msgText)
|
||||
}
|
||||
|
||||
func ERROR(text string, msg ...interface{}) {
|
||||
func Notice(text string, msg ...interface{}) {
|
||||
msgText := fmt.Sprintf(text, msg...)
|
||||
log.Println("[ERROR] ", msgText)
|
||||
log.Println("[Notice]", msgText)
|
||||
}
|
||||
|
||||
func FATAL(text string, msg ...interface{}) {
|
||||
func Warn(text string, msg ...interface{}) {
|
||||
msgText := fmt.Sprintf(text, msg...)
|
||||
log.Fatalln("[FATAL] ", msgText)
|
||||
log.Println("[Warn] ", msgText)
|
||||
}
|
||||
|
||||
func Error(text string, msg ...interface{}) {
|
||||
msgText := fmt.Sprintf(text, msg...)
|
||||
log.Println("[Error] ", msgText)
|
||||
}
|
||||
|
||||
func Fatal(text string, msg ...interface{}) {
|
||||
msgText := fmt.Sprintf(text, msg...)
|
||||
log.Fatalln("[Fatal] ", msgText)
|
||||
}
|
||||
|
||||
// CustomLogger 是一个实现了 hlog.Logger 接口的自定义日志记录器
|
||||
type CustomLogger struct{}
|
||||
|
||||
func (c *CustomLogger) Trace(v ...interface{}) {
|
||||
Trace(fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
func (c *CustomLogger) Debug(v ...interface{}) {
|
||||
Debug(fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
func (c *CustomLogger) Info(v ...interface{}) {
|
||||
Info(fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
func (c *CustomLogger) Notice(v ...interface{}) {
|
||||
Info(fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
func (c *CustomLogger) Warn(v ...interface{}) {
|
||||
Warn(fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
func (c *CustomLogger) Error(v ...interface{}) {
|
||||
Error(fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
func (c *CustomLogger) Fatal(v ...interface{}) {
|
||||
Fatal(fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
func (c *CustomLogger) CtxTracef(ctx context.Context, format string, v ...interface{}) {
|
||||
|
||||
}
|
||||
|
||||
func (c *CustomLogger) CtxDebugf(ctx context.Context, format string, v ...interface{}) {
|
||||
|
||||
}
|
||||
|
||||
func (c *CustomLogger) CtxInfof(ctx context.Context, format string, v ...interface{}) {
|
||||
|
||||
}
|
||||
|
||||
func (c *CustomLogger) CtxNoticef(ctx context.Context, format string, v ...interface{}) {
|
||||
|
||||
}
|
||||
|
||||
func (c *CustomLogger) CtxWarnf(ctx context.Context, format string, v ...interface{}) {
|
||||
|
||||
}
|
||||
|
||||
func (c *CustomLogger) CtxErrorf(ctx context.Context, format string, v ...interface{}) {
|
||||
|
||||
}
|
||||
|
||||
func (c *CustomLogger) CtxFatalf(ctx context.Context, format string, v ...interface{}) {
|
||||
|
||||
}
|
||||
|
||||
func (c *CustomLogger) SetLevel(level hlog.Level) {
|
||||
|
||||
}
|
||||
|
||||
func (c *CustomLogger) SetOutput(writer io.Writer) {
|
||||
|
||||
}
|
||||
|
||||
// Tracef 实现 hlog.Logger 接口的 Tracef 方法
|
||||
func (c *CustomLogger) Tracef(format string, args ...interface{}) {
|
||||
Trace(format, args...)
|
||||
}
|
||||
|
||||
// Debugf 实现 hlog.Logger 接口的 Debugf 方法
|
||||
func (c *CustomLogger) Debugf(format string, args ...interface{}) {
|
||||
Debug(format, args...)
|
||||
}
|
||||
|
||||
// Infof 实现 hlog.Logger 接口的 Infof 方法
|
||||
func (c *CustomLogger) Infof(format string, args ...interface{}) {
|
||||
Info(format, args...)
|
||||
}
|
||||
|
||||
// Warnf 实现 hlog.Logger 接口的 Warnf 方法
|
||||
func (c *CustomLogger) Warnf(format string, args ...interface{}) {
|
||||
Warn(format, args...)
|
||||
}
|
||||
|
||||
// Errorf 实现 hlog.Logger 接口的 Errorf 方法
|
||||
func (c *CustomLogger) Errorf(format string, args ...interface{}) {
|
||||
Error(format, args...)
|
||||
}
|
||||
|
||||
// Fatalf 实现 hlog.Logger 接口的 Fatalf 方法
|
||||
func (c *CustomLogger) Fatalf(format string, args ...interface{}) {
|
||||
Fatal(format, args...)
|
||||
}
|
||||
|
||||
func (c *CustomLogger) Noticef(format string, args ...interface{}) {
|
||||
Info(format, args...)
|
||||
}
|
||||
|
754
core/api.go
754
core/api.go
@ -1,754 +0,0 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"ProjectWIND/LOG"
|
||||
"ProjectWIND/wba"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type apiInfo struct{}
|
||||
|
||||
//一、Protocol模块
|
||||
|
||||
/*
|
||||
关于Protocol模块的说明
|
||||
|
||||
1.所有API请求按照OneBot11标准,使用JSON格式进行数据交换。api命名为由原文档中蛇形命名法改为双驼峰命名法。
|
||||
|
||||
2.无响应的API请求使用ws协议处理,有响应的API需添加echo字段。
|
||||
|
||||
3.wind会从配置文件中读取API请求的url,请确保正确填写。
|
||||
*/
|
||||
|
||||
//1.无响应API,使用ws协议处理
|
||||
|
||||
// SendMsg 发送消息(自动判断消息类型)
|
||||
func (a *apiInfo) SendMsg(msg wba.MessageEventInfo, message string, autoEscape bool) {
|
||||
// 构建发送消息的JSON数据
|
||||
var messageData wba.APIRequestInfo
|
||||
|
||||
messageType := msg.MessageType
|
||||
|
||||
messageData.Action = "send_msg"
|
||||
switch messageType {
|
||||
case "private":
|
||||
{
|
||||
messageData.Params.UserId = msg.UserId
|
||||
break
|
||||
}
|
||||
case "group":
|
||||
{
|
||||
messageData.Params.GroupId = msg.GroupId
|
||||
break
|
||||
}
|
||||
default:
|
||||
{
|
||||
LOG.ERROR("发送消息(SendMsg)时,消息类型错误: %v", messageType)
|
||||
}
|
||||
}
|
||||
messageData.Params.Message = message
|
||||
messageData.Params.AutoEscape = autoEscape
|
||||
// 发送消息
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("发送消息时,发送失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.INFO("发送消息(SendMsg)(至:%v-%v:%v-%v):%v", msg.MessageType, msg.GroupId, msg.UserId, msg.Sender.Nickname, message)
|
||||
return
|
||||
}
|
||||
|
||||
// SendPrivateMsg 发送私聊消息
|
||||
func (a *apiInfo) SendPrivateMsg(msg wba.MessageEventInfo, message string, autoEscape bool) {
|
||||
// 构建发送消息的JSON数据
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "send_private_msg"
|
||||
messageData.Params.UserId = msg.UserId
|
||||
messageData.Params.Message = message
|
||||
messageData.Params.AutoEscape = autoEscape
|
||||
// 发送消息
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("发送消息(SendPrivateMsg)时,发送失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.INFO("发送消息(SendPrivateMsg)(至:%v-%v:%v-%v):%v", msg.MessageType, msg.GroupId, msg.UserId, msg.Sender.Nickname, message)
|
||||
return
|
||||
}
|
||||
|
||||
// SendGroupMsg 发送群消息
|
||||
func (a *apiInfo) SendGroupMsg(msg wba.MessageEventInfo, message string, autoEscape bool) {
|
||||
// 构建发送消息的JSON数据
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "send_group_msg"
|
||||
messageData.Params.GroupId = msg.GroupId
|
||||
messageData.Params.Message = message
|
||||
messageData.Params.AutoEscape = autoEscape
|
||||
// 发送消息
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("发送消息(SendGroupMsg)时,发送失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.INFO("发送消息(SendGroupMsg)(至:%v-%v:%v-%v):%v", msg.MessageType, msg.GroupId, msg.UserId, msg.Sender.Nickname, message)
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteMsg 撤回消息
|
||||
func (a *apiInfo) DeleteMsg(msg wba.MessageEventInfo) {
|
||||
// 构建删除消息的JSON数据
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "delete_msg"
|
||||
messageData.Params.MessageId = msg.MessageId
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("撤回消息(DeleteMsg)时,发送失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.INFO("撤回消息(DeleteMsg):[id:%v]%v", msg.MessageId, msg.RawMessage)
|
||||
return
|
||||
}
|
||||
|
||||
// SendLike 发送赞
|
||||
func (a *apiInfo) SendLike(userId int64, times int) {
|
||||
// 构建发送赞的JSON数据
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "send_like"
|
||||
messageData.Params.UserId = userId
|
||||
messageData.Params.Times = times
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("发送赞(SendLike)时,发送失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.INFO("发送赞(SendLike)(至:%v):%v", userId, times)
|
||||
return
|
||||
}
|
||||
|
||||
// SetGroupKick 将指定用户移出群聊(需要群主或管理员权限)
|
||||
func (a *apiInfo) SetGroupKick(groupId int64, userId int64, rejectAddRequest bool) {
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "set_group_kick"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Params.UserId = userId
|
||||
messageData.Params.RejectAddRequest = rejectAddRequest
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("移出群聊(SetGroupKick)时,发送失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.INFO("移出群聊(SetGroupKick)(从:%v-%v):%v", groupId, userId, rejectAddRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// SetGroupBan 将指定用户禁言(需要群主或管理员权限)
|
||||
func (a *apiInfo) SetGroupBan(groupId int64, userId int64, duration int32) {
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "set_group_ban"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Params.UserId = userId
|
||||
messageData.Params.Duration = duration
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("禁言群成员(SetGroupBan)时,执行失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.INFO("禁言群成员(SetGroupBan)(在:%v-%v):%v", groupId, userId, duration)
|
||||
return
|
||||
}
|
||||
|
||||
// SetGroupWholeBan 设置全员禁言(需要群主或管理员权限)
|
||||
func (a *apiInfo) SetGroupWholeBan(groupId int64, enable bool) {
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "set_group_whole_ban"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Params.Enable = enable
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("设置全员禁言(SetGroupWholeBan)时,执行失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.INFO("设置全员禁言(SetGroupWholeBan)(在:%v):%v", groupId, enable)
|
||||
return
|
||||
}
|
||||
|
||||
// SetGroupAdmin 设置群管理员(需要群主权限)
|
||||
func (a *apiInfo) SetGroupAdmin(groupId int64, userId int64, enable bool) {
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "set_group_admin"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Params.UserId = userId
|
||||
messageData.Params.Enable = enable
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("设置群管理员(SetGroupAdmin)时,执行失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.INFO("设置群管理员(SetGroupAdmin)(在:%v-%v):%v", groupId, userId, enable)
|
||||
return
|
||||
}
|
||||
|
||||
// SetGroupCard 设置群名片(需要群主或管理员权限)
|
||||
func (a *apiInfo) SetGroupCard(groupId int64, userId int64, card string) {
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "set_group_card"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Params.UserId = userId
|
||||
messageData.Params.Card = card
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("设置群名片(SetGroupCard)时,执行失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.INFO("设置群名片(SetGroupCard)(在:%v-%v):%v", groupId, userId, card)
|
||||
return
|
||||
}
|
||||
|
||||
// SetGroupName 设置群名称(可能需要群主或管理员权限)
|
||||
func (a *apiInfo) SetGroupName(groupId int64, groupName string) {
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "set_group_name"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Params.GroupName = groupName
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("设置群名称(SetGroupName)时,执行失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.INFO("设置群名称(SetGroupName)(在:%v):%v", groupId, groupName)
|
||||
return
|
||||
}
|
||||
|
||||
// SetGroupLeave 退出群聊
|
||||
func (a *apiInfo) SetGroupLeave(groupId int64, isDismiss bool) {
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "set_group_leave"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Params.IsDismiss = isDismiss
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("退出群聊(SetGroupLeave)时,执行失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.INFO("退出群聊(SetGroupLeave)(在:%v):%v", groupId, isDismiss)
|
||||
return
|
||||
}
|
||||
|
||||
// SetGroupSpecialTitle 设置群专属头衔(需要群主权限)
|
||||
func (a *apiInfo) SetGroupSpecialTitle(groupId int64, userId int64, specialTitle string, duration int32) {
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "set_group_special_title"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Params.UserId = userId
|
||||
messageData.Params.SpecialTitle = specialTitle
|
||||
messageData.Params.Duration = duration
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("设置群特殊头衔(SetGroupSpecialTitle)时,执行失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.INFO("设置群特殊头衔(SetGroupSpecialTitle)(在:%v-%v):%v-%v", groupId, userId, specialTitle, duration)
|
||||
return
|
||||
}
|
||||
|
||||
// SetFriendAddRequest 处理加好友请求
|
||||
func (a *apiInfo) SetFriendAddRequest(flag string, approve bool, remark string) {
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "set_friend_add_request"
|
||||
messageData.Params.Flag = flag
|
||||
messageData.Params.Approve = approve
|
||||
messageData.Params.Remark = remark
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("处理加好友请求(SetFriendAddRequest)时,执行失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.INFO("处理加好友请求(SetFriendAddRequest)(在:%v):%v-%v-%v", flag, approve, remark)
|
||||
return
|
||||
}
|
||||
|
||||
// SetGroupAddRequest 处理加群请求/邀请
|
||||
func (a *apiInfo) SetGroupAddRequest(flag string, subType string, approve bool, reason string) {
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "set_group_add_request"
|
||||
messageData.Params.Flag = flag
|
||||
messageData.Params.SubType = subType
|
||||
messageData.Params.Approve = approve
|
||||
messageData.Params.Reason = reason
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("处理加群请求/邀请(SetGroupAddRequest)时,执行失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.INFO("处理加群请求/邀请(SetGroupAddRequest)(在:%v-%v-%v):%v", flag, subType, approve, reason)
|
||||
return
|
||||
}
|
||||
|
||||
// SetRestart 重启
|
||||
func (a *apiInfo) SetRestart(delay int32) {
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "set_restart"
|
||||
messageData.Params.Delay = delay
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("设置重启(SetRestart)时,执行失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.INFO("设置重启(SetRestart):%v", delay)
|
||||
return
|
||||
}
|
||||
|
||||
// CleanCache 清理缓存
|
||||
func (a *apiInfo) CleanCache() {
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "clean_cache"
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("清理缓存(CleanCache)时,执行失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.INFO("清理缓存(CleanCache)")
|
||||
return
|
||||
}
|
||||
|
||||
// 2.有响应API,需添加echo字段
|
||||
|
||||
// GetLoginInfo 获取登录信息
|
||||
func (a *apiInfo) GetLoginInfo() (Response wba.APIResponseInfo) {
|
||||
LOG.INFO("获取登录信息(GetLoginInfo)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_login_info"
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.ERROR("获取登录信息(GetLoginInfo)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("获取登录信息(GetLoginInfo)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetVersionInfo 获取协议信息
|
||||
func (a *apiInfo) GetVersionInfo() (Response wba.APIResponseInfo) {
|
||||
LOG.INFO("获取协议信息(GetVersionInfo)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_version_info"
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.ERROR("获取协议信息(GetVersionInfo)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("获取登录信息(GetVersionInfo)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetMsg 获取消息
|
||||
func (a *apiInfo) GetMsg(messageId int32) (Response wba.APIResponseInfo) {
|
||||
LOG.INFO("获取消息(GetMsg)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_msg"
|
||||
messageData.Params.MessageId = messageId
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.ERROR("获取消息(GetMsg)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("获取消息(GetMsg)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetForwardMsg 获取合并转发消息
|
||||
func (a *apiInfo) GetForwardMsg(id string) (Response wba.APIResponseInfo) {
|
||||
LOG.INFO("获取合并转发消息(GetForwardMsg)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_forward_msg"
|
||||
messageData.Params.Id = id
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.ERROR("获取合并转发消息(GetForwardMsg)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("获取合并转发消息(GetForwardMsg)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetStrangerInfo 获取陌生人信息
|
||||
func (a *apiInfo) GetStrangerInfo(userId int64, noCache bool) (Response wba.APIResponseInfo) {
|
||||
LOG.INFO("获取陌生人信息(GetStrangerInfo)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_stranger_info"
|
||||
messageData.Params.UserId = userId
|
||||
messageData.Params.NoCache = noCache
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.ERROR("获取陌生人信息(GetStrangerInfo)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("获取陌生人信息(GetStrangerInfo)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetFriendList 获取好友列表
|
||||
func (a *apiInfo) GetFriendList() (Response wba.APIResponseInfo) {
|
||||
LOG.INFO("获取好友列表(GetFriendList)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_friend_list"
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.ERROR("获取好友列表(GetFriendList)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("获取好友列表(GetFriendList)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetGroupList 获取群列表
|
||||
func (a *apiInfo) GetGroupList() (Response wba.APIResponseInfo) {
|
||||
LOG.INFO("获取群列表(GetGroupList)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_group_list"
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.ERROR("获取群列表(GetGroupList)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("获取群列表(GetGroupList)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetGroupInfo 获取群信息
|
||||
func (a *apiInfo) GetGroupInfo(groupId int64, noCache bool) (Response wba.APIResponseInfo) {
|
||||
LOG.INFO("获取群信息(GetGroupInfo)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_group_info"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Params.NoCache = noCache
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.ERROR("获取群信息(GetGroupInfo)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("获取群信息(GetGroupInfo)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetGroupMemberInfo 获取群成员信息
|
||||
func (a *apiInfo) GetGroupMemberInfo(groupId int64, userId int64, noCache bool) (Response wba.APIResponseInfo) {
|
||||
LOG.INFO("获取群成员信息(GetGroupMemberInfo)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_group_member_info"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Params.UserId = userId
|
||||
messageData.Params.NoCache = noCache
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.ERROR("获取群成员信息(GetGroupMemberInfo)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("获取群成员信息(GetGroupMemberInfo)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetGroupMemberList 获取群成员列表
|
||||
func (a *apiInfo) GetGroupMemberList(groupId int64) (Response wba.APIResponseInfo) {
|
||||
LOG.INFO("获取群成员列表(GetGroupMemberList)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_group_member_list"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.ERROR("获取群成员列表(GetGroupMemberList)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("获取群成员列表(GetGroupMemberList)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetGroupHonorInfo 获取群荣誉信息
|
||||
func (a *apiInfo) GetGroupHonorInfo(groupId int64, Type string) (Response wba.APIResponseInfo) {
|
||||
LOG.INFO("获取群荣誉信息(GetGroupHonorInfo)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_group_honor_info"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Params.Type = Type
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.ERROR("获取群荣誉信息(GetGroupHonorInfo)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("获取群荣誉信息(GetGroupHonorInfo)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetCookies 获取Cookies
|
||||
func (a *apiInfo) GetCookies(domain string) (Response wba.APIResponseInfo) {
|
||||
LOG.INFO("获取Cookies(GetCookies)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_cookies"
|
||||
messageData.Params.Domain = domain
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.ERROR("获取Cookies(GetCookies)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("获取Cookies(GetCookies)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetCSRFToken 获取CSRF Token
|
||||
func (a *apiInfo) GetCSRFToken() (Response wba.APIResponseInfo) {
|
||||
LOG.INFO("获取CSRF Token(GetCSRFToken)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_csrf_token"
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.ERROR("获取CSRF Token(GetCSRFToken)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("获取CSRF Token(GetCSRFToken)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetCredentials 获取登录令牌
|
||||
func (a *apiInfo) GetCredentials(domain string) (Response wba.APIResponseInfo) {
|
||||
LOG.INFO("获取登录令牌(GetCredentials)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_credentials"
|
||||
messageData.Params.Domain = domain
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.ERROR("获取登录令牌(GetCredentials)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("获取登录令牌(GetCredentials)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetRecord 获取语音
|
||||
func (a *apiInfo) GetRecord(file string, outFormat string) (Response wba.APIResponseInfo) {
|
||||
LOG.INFO("获取语音(GetRecord)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_record"
|
||||
messageData.Params.File = file
|
||||
messageData.Params.OutFormat = outFormat
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.ERROR("获取语音(GetRecord)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("获取语音(GetRecord)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetImage 获取图片
|
||||
func (a *apiInfo) GetImage(file string) (Response wba.APIResponseInfo) {
|
||||
LOG.INFO("获取图片(GetImage)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_image"
|
||||
messageData.Params.File = file
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.ERROR("获取图片(GetImage)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("获取图片(GetImage)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// CanSendImage 检查是否可以发送图片
|
||||
func (a *apiInfo) CanSendImage() (Response wba.APIResponseInfo) {
|
||||
LOG.INFO("检查是否可以发送图片(CanSendImage)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "can_send_image"
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.ERROR("检查是否可以发送图片(CanSendImage)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("检查是否可以发送图片(CanSendImage)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// CanSendRecord 检查是否可以发送语音
|
||||
func (a *apiInfo) CanSendRecord() (Response wba.APIResponseInfo) {
|
||||
LOG.INFO("检查是否可以发送语音(CanSendRecord)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "can_send_record"
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.ERROR("检查是否可以发送语音(CanSendRecord)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("检查是否可以发送语音(CanSendRecord)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetStatus 获取状态
|
||||
func (a *apiInfo) GetStatus() (Response wba.APIResponseInfo) {
|
||||
LOG.INFO("获取状态(GetStatus)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_status"
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.ERROR("获取状态(GetStatus)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.ERROR("获取状态(GetStatus)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
//二、LOG模块
|
||||
|
||||
/*
|
||||
关于LOG模块的说明
|
||||
|
||||
1.日志模块使用go-logging库,日志级别分为DEBUG、INFO、WARN、ERROR。
|
||||
|
||||
2.日志模块提供LogWith方法,可以自定义日志级别,调用级别为DEBUG时,会打印输出调用者的文件名、函数名、行号。
|
||||
|
||||
3.日志模块提供Log方法,默认日志级别为INFO。
|
||||
*/
|
||||
|
||||
func (a *apiInfo) LogWith(level string, content string, args ...interface{}) {
|
||||
switch level {
|
||||
case "DEBUG":
|
||||
LOG.DEBUG(content, args...)
|
||||
return
|
||||
case "WARN":
|
||||
LOG.WARN(content, args...)
|
||||
return
|
||||
case "ERROR":
|
||||
LOG.ERROR(content, args...)
|
||||
return
|
||||
default:
|
||||
LOG.INFO(content, args...)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (a *apiInfo) Log(content string, args ...interface{}) {
|
||||
LOG.INFO(content, args...)
|
||||
}
|
||||
|
||||
//database模块
|
||||
//TODO: 数据库模块待实现
|
||||
|
||||
// 文件管理模块
|
||||
//TODO: 文件管理模块待实现
|
||||
|
||||
//终端连接模块
|
||||
//TODO: 终端模块待实现
|
||||
|
||||
//核心信息调用模块
|
||||
|
||||
var AppApi apiInfo
|
||||
|
||||
func GenerateUUID() (string, error) {
|
||||
uuid := make([]byte, 16)
|
||||
_, err := rand.Read(uuid)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 设置UUID版本号(版本4),将第6字节的高4位设置为0100
|
||||
uuid[6] = (uuid[6] & 0x0F) | 0x40
|
||||
// 设置UUID变体(RFC 4122规范定义的变体),将第8字节的高4位设置为10
|
||||
uuid[8] = (uuid[8] & 0x3F) | 0x80
|
||||
|
||||
return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]), nil
|
||||
}
|
207
core/api_wsd.go
Normal file
207
core/api_wsd.go
Normal 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
|
952
core/api_wsp.go
Normal file
952
core/api_wsp.go
Normal file
@ -0,0 +1,952 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"ProjectWIND/LOG"
|
||||
"ProjectWIND/wba"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type protocolAPI struct{}
|
||||
|
||||
//一、Protocol模块
|
||||
|
||||
/*
|
||||
关于Protocol模块的说明
|
||||
|
||||
1.所有API请求按照OneBot11标准,使用JSON格式进行数据交换。api命名为由原文档中蛇形命名法改为双驼峰命名法。
|
||||
|
||||
2.无响应的API请求使用ws协议处理,有响应的API需添加echo字段。
|
||||
|
||||
3.wind会从配置文件中读取API请求的url,请确保正确填写。
|
||||
*/
|
||||
|
||||
//1.无响应API,使用ws协议处理
|
||||
|
||||
// UnsafelySendMsg 发送消息(自动判断消息类型)
|
||||
//
|
||||
// 注意:该API不安全,除非你知道你在做什么。
|
||||
//
|
||||
// 参数:
|
||||
//
|
||||
// - messageType: 消息类型,可选值为 "private" 和 "group
|
||||
//
|
||||
// - groupId: 群号,当messageType为"group"时必填
|
||||
//
|
||||
// - userId: 用户ID,当messageType为"private"时必填
|
||||
//
|
||||
// - message: 要发送的消息内容,类型为字符串
|
||||
//
|
||||
// - autoEscape: 是否自动转义(解析消息内容中的CQ码),可选值为 true 和 false
|
||||
func (p *protocolAPI) UnsafelySendMsg(messageType string, groupId int64, userId int64, message string, autoEscape bool) {
|
||||
// 构建发送消息的JSON数据
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "send_msg"
|
||||
switch messageType {
|
||||
case "private":
|
||||
{
|
||||
messageData.Params.UserId = userId
|
||||
break
|
||||
}
|
||||
case "group":
|
||||
{
|
||||
messageData.Params.GroupId = groupId
|
||||
break
|
||||
}
|
||||
default:
|
||||
{
|
||||
LOG.Error("发送消息(UnsafelySendMsg)时,消息类型错误: %v", messageType)
|
||||
}
|
||||
}
|
||||
messageData.Params.Message = message
|
||||
messageData.Params.AutoEscape = autoEscape
|
||||
// 发送消息
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("发送消息时,发送失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.Info("发送消息(UnsafelySendMsg)(至:%v-%v:%v):%v", messageType, groupId, userId, message)
|
||||
return
|
||||
}
|
||||
|
||||
// UnsafelySendPrivateMsg 发送私聊消息
|
||||
//
|
||||
// 注意:该API不安全,除非你知道你在做什么。
|
||||
//
|
||||
// 参数:
|
||||
//
|
||||
// - userId: 用户ID
|
||||
//
|
||||
// - message: 要发送的消息内容,类型为字符串
|
||||
//
|
||||
// - autoEscape: 是否自动转义(解析消息内容中的CQ码),可选值为 true 和 false
|
||||
func (p *protocolAPI) UnsafelySendPrivateMsg(userId int64, message string, autoEscape bool) {
|
||||
// 构建发送消息的JSON数据
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "send_private_msg"
|
||||
messageData.Params.UserId = userId
|
||||
messageData.Params.Message = message
|
||||
messageData.Params.AutoEscape = autoEscape
|
||||
// 发送消息
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("发送私聊消息(UnsafelySendPrivateMsg)时,发送失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.Info("发送私聊消息(UnsafelySendPrivateMsg)(至:%v):%v", userId, message)
|
||||
return
|
||||
}
|
||||
|
||||
// UnsafelySendGroupMsg 发送群消息
|
||||
//
|
||||
// 注意:该API不安全,除非你知道你在做什么。
|
||||
//
|
||||
// 参数:
|
||||
//
|
||||
// - groupId: 群号
|
||||
//
|
||||
// - message: 要发送的消息内容,类型为字符串
|
||||
//
|
||||
// - autoEscape: 是否自动转义(解析消息内容中的CQ码),可选值为 true 和 false
|
||||
func (p *protocolAPI) UnsafelySendGroupMsg(groupId int64, message string, autoEscape bool) {
|
||||
// 构建发送消息的JSON数据
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "send_group_msg"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Params.Message = message
|
||||
messageData.Params.AutoEscape = autoEscape
|
||||
// 发送消息
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("发送群消息(UnsafelySendGroupMsg)时,发送失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.Info("发送群消息(UnsafelySendGroupMsg)(至:%v):%v", groupId, message)
|
||||
return
|
||||
}
|
||||
|
||||
// SendMsg 回复消息(自动判断消息类型)
|
||||
//
|
||||
// 参数:
|
||||
//
|
||||
// - msg: 消息事件信息
|
||||
//
|
||||
// - message: 要发送的消息内容,类型为字符串
|
||||
//
|
||||
// - autoEscape: 是否自动转义(解析消息内容中的CQ码),可选值为 true 和 false
|
||||
func (p *protocolAPI) SendMsg(msg wba.MessageEventInfo, message string, autoEscape bool) {
|
||||
// 构建发送消息的JSON数据
|
||||
var messageData wba.APIRequestInfo
|
||||
|
||||
messageType := msg.MessageType
|
||||
|
||||
messageData.Action = "send_msg"
|
||||
switch messageType {
|
||||
case "private":
|
||||
{
|
||||
messageData.Params.UserId = msg.UserId
|
||||
break
|
||||
}
|
||||
case "group":
|
||||
{
|
||||
messageData.Params.GroupId = msg.GroupId
|
||||
break
|
||||
}
|
||||
default:
|
||||
{
|
||||
LOG.Error("回复消息(SendMsg)时,消息类型错误: %v", messageType)
|
||||
}
|
||||
}
|
||||
messageData.Params.Message = message
|
||||
messageData.Params.AutoEscape = autoEscape
|
||||
// 发送消息
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("回复消息时,发送失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.Info("回复消息(SendMsg)(至:%v-%v:%v-%v):%v", msg.MessageType, msg.GroupId, msg.UserId, msg.Sender.Nickname, message)
|
||||
return
|
||||
}
|
||||
|
||||
// SendPrivateMsg 回复私聊消息
|
||||
//
|
||||
// 参数:
|
||||
//
|
||||
// - msg: 原始消息事件信息
|
||||
//
|
||||
// - message: 要发送的消息内容,类型为字符串
|
||||
//
|
||||
// - autoEscape: 是否自动转义,可选值为 true 和 false
|
||||
func (p *protocolAPI) SendPrivateMsg(msg wba.MessageEventInfo, message string, autoEscape bool) {
|
||||
// 构建发送消息的JSON数据
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "send_private_msg"
|
||||
messageData.Params.UserId = msg.UserId
|
||||
messageData.Params.Message = message
|
||||
messageData.Params.AutoEscape = autoEscape
|
||||
// 发送消息
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("回复消息(SendPrivateMsg)时,发送失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.Info("回复消息(SendPrivateMsg)(至:%v-%v:%v-%v):%v", msg.MessageType, msg.GroupId, msg.UserId, msg.Sender.Nickname, message)
|
||||
return
|
||||
}
|
||||
|
||||
// SendGroupMsg 回复群消息
|
||||
//
|
||||
// 参数:
|
||||
//
|
||||
// - msg: 原始消息事件信息
|
||||
//
|
||||
// - message: 要发送的消息内容,类型为字符串
|
||||
//
|
||||
// - autoEscape: 是否自动转义,可选值为 true 和 false
|
||||
func (p *protocolAPI) SendGroupMsg(msg wba.MessageEventInfo, message string, autoEscape bool) {
|
||||
// 构建发送消息的JSON数据
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "send_group_msg"
|
||||
messageData.Params.GroupId = msg.GroupId
|
||||
messageData.Params.Message = message
|
||||
messageData.Params.AutoEscape = autoEscape
|
||||
// 发送消息
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("回复消息(SendGroupMsg)时,发送失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.Info("回复消息(SendGroupMsg)(至:%v-%v:%v-%v):%v", msg.MessageType, msg.GroupId, msg.UserId, msg.Sender.Nickname, message)
|
||||
return
|
||||
}
|
||||
|
||||
// UnsafelyDeleteMsg 撤回消息
|
||||
//
|
||||
// 注意:该API不安全,除非你知道你在做什么。
|
||||
//
|
||||
// 参数:
|
||||
//
|
||||
// - messageId: 要撤回的消息ID
|
||||
func (p *protocolAPI) UnsafelyDeleteMsg(messageId int32) {
|
||||
// 构建删除消息的JSON数据
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "delete_msg"
|
||||
messageData.Params.MessageId = messageId
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("撤回消息(UnsafeDeleteMsg)时,发送失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.Info("撤回消息(UnsafeDeleteMsg):[id:%v]", messageId)
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteMsg 撤回消息
|
||||
//
|
||||
// 参数:
|
||||
//
|
||||
// - msg: 原始消息事件信息
|
||||
func (p *protocolAPI) DeleteMsg(msg wba.MessageEventInfo) {
|
||||
// 构建删除消息的JSON数据
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "delete_msg"
|
||||
messageData.Params.MessageId = msg.MessageId
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("撤回消息(DeleteMsg)时,发送失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.Info("撤回消息(DeleteMsg):[id:%v]%v", msg.MessageId, msg.RawMessage)
|
||||
return
|
||||
}
|
||||
|
||||
// SendLike 发送赞
|
||||
//
|
||||
// 参数:
|
||||
//
|
||||
// - userId: 要赞的用户ID
|
||||
//
|
||||
// - times: 赞的次数
|
||||
func (p *protocolAPI) SendLike(userId int64, times int) {
|
||||
// 构建发送赞的JSON数据
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "send_like"
|
||||
messageData.Params.UserId = userId
|
||||
messageData.Params.Times = times
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("发送赞(SendLike)时,发送失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.Info("发送赞(SendLike)(至:%v):%v", userId, times)
|
||||
return
|
||||
}
|
||||
|
||||
// SetGroupKick 将指定用户移出群聊(需要群主或管理员权限)
|
||||
//
|
||||
// 参数:
|
||||
//
|
||||
// - groupId: 群号
|
||||
//
|
||||
// - userId: 用户ID
|
||||
//
|
||||
// - rejectAddRequest: 是否拒绝该用户的后续加群请求,可选值为 true 和 false
|
||||
func (p *protocolAPI) SetGroupKick(groupId int64, userId int64, rejectAddRequest bool) {
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "set_group_kick"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Params.UserId = userId
|
||||
messageData.Params.RejectAddRequest = rejectAddRequest
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("移出群聊(SetGroupKick)时,发送失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.Info("移出群聊(SetGroupKick)(从:%v-%v):%v", groupId, userId, rejectAddRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// SetGroupBan 将指定用户禁言(需要群主或管理员权限)
|
||||
//
|
||||
// 参数:
|
||||
//
|
||||
// - groupId: 群号
|
||||
//
|
||||
// - userId: 用户ID
|
||||
//
|
||||
// - duration: 禁言时长,单位为秒,0表示取消禁言
|
||||
func (p *protocolAPI) SetGroupBan(groupId int64, userId int64, duration int32) {
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "set_group_ban"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Params.UserId = userId
|
||||
messageData.Params.Duration = duration
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("禁言群成员(SetGroupBan)时,执行失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.Info("禁言群成员(SetGroupBan)(在:%v-%v):%v", groupId, userId, duration)
|
||||
return
|
||||
}
|
||||
|
||||
// SetGroupWholeBan 设置全员禁言(需要群主或管理员权限)
|
||||
//
|
||||
// 参数:
|
||||
//
|
||||
// - groupId: 群号
|
||||
//
|
||||
// - enable: 是否启用全员禁言,可选值为 true 和 false
|
||||
func (p *protocolAPI) SetGroupWholeBan(groupId int64, enable bool) {
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "set_group_whole_ban"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Params.Enable = enable
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("设置全员禁言(SetGroupWholeBan)时,执行失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.Info("设置全员禁言(SetGroupWholeBan)(在:%v):%v", groupId, enable)
|
||||
return
|
||||
}
|
||||
|
||||
// SetGroupAdmin 设置群管理员(需要群主权限)
|
||||
//
|
||||
// 参数:
|
||||
//
|
||||
// - groupId: 群号
|
||||
//
|
||||
// - userId: 用户ID
|
||||
//
|
||||
// - enable: 是否设置为管理员,可选值为 true 和 false
|
||||
func (p *protocolAPI) SetGroupAdmin(groupId int64, userId int64, enable bool) {
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "set_group_admin"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Params.UserId = userId
|
||||
messageData.Params.Enable = enable
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("设置群管理员(SetGroupAdmin)时,执行失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.Info("设置群管理员(SetGroupAdmin)(在:%v-%v):%v", groupId, userId, enable)
|
||||
return
|
||||
}
|
||||
|
||||
// SetGroupCard 设置群名片(可能需要群主或管理员权限)
|
||||
//
|
||||
// 参数:
|
||||
//
|
||||
// - groupId: 群号
|
||||
//
|
||||
// - userId: 用户ID
|
||||
//
|
||||
// - card: 新的群名片
|
||||
func (p *protocolAPI) SetGroupCard(groupId int64, userId int64, card string) {
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "set_group_card"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Params.UserId = userId
|
||||
messageData.Params.Card = card
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("设置群名片(SetGroupCard)时,执行失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.Info("设置群名片(SetGroupCard)(在:%v-%v):%v", groupId, userId, card)
|
||||
return
|
||||
}
|
||||
|
||||
// SetGroupName 设置群名称(可能需要群主或管理员权限)
|
||||
//
|
||||
// 参数:
|
||||
//
|
||||
// - groupId: 群号
|
||||
//
|
||||
// - groupName: 新的群名称
|
||||
func (p *protocolAPI) SetGroupName(groupId int64, groupName string) {
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "set_group_name"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Params.GroupName = groupName
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("设置群名称(SetGroupName)时,执行失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.Info("设置群名称(SetGroupName)(在:%v):%v", groupId, groupName)
|
||||
return
|
||||
}
|
||||
|
||||
// SetGroupLeave 退出群聊
|
||||
//
|
||||
// 参数:
|
||||
//
|
||||
// - groupId: 群号
|
||||
//
|
||||
// - isDismiss: 是否解散群聊,仅当退出的是群主时有效,可选值为 true 和 false
|
||||
func (p *protocolAPI) SetGroupLeave(groupId int64, isDismiss bool) {
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "set_group_leave"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Params.IsDismiss = isDismiss
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("退出群聊(SetGroupLeave)时,执行失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.Info("退出群聊(SetGroupLeave)(在:%v):%v", groupId, isDismiss)
|
||||
return
|
||||
}
|
||||
|
||||
// SetGroupSpecialTitle 设置群专属头衔(需要群主权限)
|
||||
//
|
||||
// 参数:
|
||||
//
|
||||
// - groupId: 群号
|
||||
//
|
||||
// - userId: 用户ID
|
||||
//
|
||||
// - specialTitle: 新的专属头衔
|
||||
func (p *protocolAPI) SetGroupSpecialTitle(groupId int64, userId int64, specialTitle string) {
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "set_group_special_title"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Params.UserId = userId
|
||||
messageData.Params.SpecialTitle = specialTitle
|
||||
messageData.Params.Duration = -1
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("设置群特殊头衔(SetGroupSpecialTitle)时,执行失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.Info("设置群特殊头衔(SetGroupSpecialTitle)(在:%v-%v):%v-%v", groupId, userId, specialTitle)
|
||||
return
|
||||
}
|
||||
|
||||
// SetFriendAddRequest 处理加好友请求
|
||||
//
|
||||
// 参数:
|
||||
//
|
||||
// - flag: 请求标识,由上报的事件中获得
|
||||
//
|
||||
// - approve: 是否同意请求,可选值为 true 和 false
|
||||
//
|
||||
// - remark: 设置好友的备注信息
|
||||
func (p *protocolAPI) SetFriendAddRequest(flag string, approve bool, remark string) {
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "set_friend_add_request"
|
||||
messageData.Params.Flag = flag
|
||||
messageData.Params.Approve = approve
|
||||
messageData.Params.Remark = remark
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("处理加好友请求(SetFriendAddRequest)时,执行失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.Info("处理加好友请求(SetFriendAddRequest)(在:%v):%v-%v-%v", flag, approve, remark)
|
||||
return
|
||||
}
|
||||
|
||||
// SetGroupAddRequest 处理加群请求/邀请
|
||||
//
|
||||
// 参数:
|
||||
//
|
||||
// - flag: 请求标识,由上报的事件中获得
|
||||
//
|
||||
// - subType: 子类型,可能是 "invite" 或 "add", 由上报的事件中获得
|
||||
//
|
||||
// - approve: 是否同意请求,可选值为 true 和 false
|
||||
//
|
||||
// - reason: 拒绝请求的原因,仅当 approve 为 false 时有效
|
||||
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
|
||||
messageData.Params.SubType = subType
|
||||
messageData.Params.Approve = approve
|
||||
messageData.Params.Reason = reason
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("处理加群请求/邀请(SetGroupAddRequest)时,执行失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.Info("处理加群请求/邀请(SetGroupAddRequest)(在:%v-%v-%v):%v", flag, subType, approve, reason)
|
||||
return
|
||||
}
|
||||
|
||||
// SetRestart 重启
|
||||
func (p *protocolAPI) SetRestart(delay int32) {
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "set_restart"
|
||||
messageData.Params.Delay = delay
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("设置重启(SetRestart)时,执行失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.Info("设置重启(SetRestart):%v", delay)
|
||||
return
|
||||
}
|
||||
|
||||
// CleanCache 清理缓存
|
||||
func (p *protocolAPI) CleanCache() {
|
||||
var messageData wba.APIRequestInfo
|
||||
messageData.Action = "clean_cache"
|
||||
_, err := wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("清理缓存(CleanCache)时,执行失败: %v", err)
|
||||
return
|
||||
}
|
||||
LOG.Info("清理缓存(CleanCache)")
|
||||
return
|
||||
}
|
||||
|
||||
// 2.有响应API,需添加echo字段,统一返回响应结构体
|
||||
|
||||
// GetLoginInfo 获取登录信息
|
||||
func (p *protocolAPI) GetLoginInfo() (Response wba.APIResponseInfo) {
|
||||
LOG.Info("获取登录信息(GetLoginInfo)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_login_info"
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.Error("获取登录信息(GetLoginInfo)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("获取登录信息(GetLoginInfo)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetVersionInfo 获取协议信息
|
||||
func (p *protocolAPI) GetVersionInfo() (Response wba.APIResponseInfo) {
|
||||
LOG.Info("获取协议信息(GetVersionInfo)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_version_info"
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.Error("获取协议信息(GetVersionInfo)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("获取登录信息(GetVersionInfo)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetMsg 获取消息
|
||||
func (p *protocolAPI) GetMsg(messageId int32) (Response wba.APIResponseInfo) {
|
||||
LOG.Info("获取消息(GetMsg)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_msg"
|
||||
messageData.Params.MessageId = messageId
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.Error("获取消息(GetMsg)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("获取消息(GetMsg)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetForwardMsg 获取合并转发消息
|
||||
func (p *protocolAPI) GetForwardMsg(id string) (Response wba.APIResponseInfo) {
|
||||
LOG.Info("获取合并转发消息(GetForwardMsg)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_forward_msg"
|
||||
messageData.Params.Id = id
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.Error("获取合并转发消息(GetForwardMsg)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("获取合并转发消息(GetForwardMsg)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetStrangerInfo 获取陌生人信息
|
||||
func (p *protocolAPI) GetStrangerInfo(userId int64, noCache bool) (Response wba.APIResponseInfo) {
|
||||
LOG.Info("获取陌生人信息(GetStrangerInfo)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_stranger_info"
|
||||
messageData.Params.UserId = userId
|
||||
messageData.Params.NoCache = noCache
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.Error("获取陌生人信息(GetStrangerInfo)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("获取陌生人信息(GetStrangerInfo)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetFriendList 获取好友列表
|
||||
func (p *protocolAPI) GetFriendList() (Response wba.APIResponseInfo) {
|
||||
LOG.Info("获取好友列表(GetFriendList)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_friend_list"
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.Error("获取好友列表(GetFriendList)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("获取好友列表(GetFriendList)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetGroupList 获取群列表
|
||||
func (p *protocolAPI) GetGroupList() (Response wba.APIResponseInfo) {
|
||||
LOG.Info("获取群列表(GetGroupList)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_group_list"
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.Error("获取群列表(GetGroupList)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("获取群列表(GetGroupList)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetGroupInfo 获取群信息
|
||||
func (p *protocolAPI) GetGroupInfo(groupId int64, noCache bool) (Response wba.APIResponseInfo) {
|
||||
LOG.Info("获取群信息(GetGroupInfo)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_group_info"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Params.NoCache = noCache
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.Error("获取群信息(GetGroupInfo)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("获取群信息(GetGroupInfo)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetGroupMemberInfo 获取群成员信息
|
||||
func (p *protocolAPI) GetGroupMemberInfo(groupId int64, userId int64, noCache bool) (Response wba.APIResponseInfo) {
|
||||
LOG.Info("获取群成员信息(GetGroupMemberInfo)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_group_member_info"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Params.UserId = userId
|
||||
messageData.Params.NoCache = noCache
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.Error("获取群成员信息(GetGroupMemberInfo)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("获取群成员信息(GetGroupMemberInfo)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetGroupMemberList 获取群成员列表
|
||||
func (p *protocolAPI) GetGroupMemberList(groupId int64) (Response wba.APIResponseInfo) {
|
||||
LOG.Info("获取群成员列表(GetGroupMemberList)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_group_member_list"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.Error("获取群成员列表(GetGroupMemberList)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("获取群成员列表(GetGroupMemberList)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetGroupHonorInfo 获取群荣誉信息
|
||||
func (p *protocolAPI) GetGroupHonorInfo(groupId int64, Type string) (Response wba.APIResponseInfo) {
|
||||
LOG.Info("获取群荣誉信息(GetGroupHonorInfo)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_group_honor_info"
|
||||
messageData.Params.GroupId = groupId
|
||||
messageData.Params.Type = Type
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.Error("获取群荣誉信息(GetGroupHonorInfo)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("获取群荣誉信息(GetGroupHonorInfo)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetCookies 获取Cookies
|
||||
func (p *protocolAPI) GetCookies(domain string) (Response wba.APIResponseInfo) {
|
||||
LOG.Info("获取Cookies(GetCookies)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_cookies"
|
||||
messageData.Params.Domain = domain
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.Error("获取Cookies(GetCookies)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("获取Cookies(GetCookies)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetCSRFToken 获取CSRF Token
|
||||
func (p *protocolAPI) GetCSRFToken() (Response wba.APIResponseInfo) {
|
||||
LOG.Info("获取CSRF Token(GetCSRFToken)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_csrf_token"
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.Error("获取CSRF Token(GetCSRFToken)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("获取CSRF Token(GetCSRFToken)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetCredentials 获取登录令牌
|
||||
func (p *protocolAPI) GetCredentials(domain string) (Response wba.APIResponseInfo) {
|
||||
LOG.Info("获取登录令牌(GetCredentials)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_credentials"
|
||||
messageData.Params.Domain = domain
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.Error("获取登录令牌(GetCredentials)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("获取登录令牌(GetCredentials)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetRecord 获取语音
|
||||
func (p *protocolAPI) GetRecord(file string, outFormat string) (Response wba.APIResponseInfo) {
|
||||
LOG.Info("获取语音(GetRecord)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_record"
|
||||
messageData.Params.File = file
|
||||
messageData.Params.OutFormat = outFormat
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.Error("获取语音(GetRecord)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("获取语音(GetRecord)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetImage 获取图片
|
||||
func (p *protocolAPI) GetImage(file string) (Response wba.APIResponseInfo) {
|
||||
LOG.Info("获取图片(GetImage)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_image"
|
||||
messageData.Params.File = file
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.Error("获取图片(GetImage)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("获取图片(GetImage)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// CanSendImage 检查是否可以发送图片
|
||||
func (p *protocolAPI) CanSendImage() (Response wba.APIResponseInfo) {
|
||||
LOG.Info("检查是否可以发送图片(CanSendImage)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "can_send_image"
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.Error("检查是否可以发送图片(CanSendImage)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("检查是否可以发送图片(CanSendImage)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// CanSendRecord 检查是否可以发送语音
|
||||
func (p *protocolAPI) CanSendRecord() (Response wba.APIResponseInfo) {
|
||||
LOG.Info("检查是否可以发送语音(CanSendRecord)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "can_send_record"
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.Error("检查是否可以发送语音(CanSendRecord)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("检查是否可以发送语音(CanSendRecord)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// GetStatus 获取状态
|
||||
func (p *protocolAPI) GetStatus() (Response wba.APIResponseInfo) {
|
||||
LOG.Info("获取状态(GetStatus)")
|
||||
var messageData wba.APIRequestInfo
|
||||
var err error
|
||||
messageData.Action = "get_status"
|
||||
messageData.Echo, err = GenerateUUID()
|
||||
if err != nil {
|
||||
LOG.Error("获取状态(GetStatus)时,生成UUID失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
Response, err = wsAPI(messageData)
|
||||
if err != nil {
|
||||
LOG.Error("获取状态(GetStatus)时,执行失败: %v", err)
|
||||
return wba.APIResponseInfo{}
|
||||
}
|
||||
return Response
|
||||
}
|
||||
|
||||
// 文件管理模块
|
||||
//TODO: 文件管理模块待实现
|
||||
|
||||
//终端连接模块
|
||||
//TODO: 终端模块待实现
|
||||
|
||||
//核心信息调用模块
|
||||
|
||||
var ProtocolApi protocolAPI
|
||||
|
||||
func GenerateUUID() (string, error) {
|
||||
uuid := make([]byte, 16)
|
||||
_, err := rand.Read(uuid)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 设置UUID版本号(版本4),将第6字节的高4位设置为0100
|
||||
uuid[6] = (uuid[6] & 0x0F) | 0x40
|
||||
// 设置UUID变体(RFC 4122规范定义的变体),将第8字节的高4位设置为10
|
||||
uuid[8] = (uuid[8] & 0x3F) | 0x80
|
||||
|
||||
return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]), nil
|
||||
}
|
143
core/api_wst.go
Normal file
143
core/api_wst.go
Normal file
@ -0,0 +1,143 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"ProjectWIND/LOG"
|
||||
"ProjectWIND/wba"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type toolsAPI struct{}
|
||||
|
||||
//二、LOG模块
|
||||
|
||||
/*
|
||||
关于LOG模块的说明
|
||||
|
||||
1.日志模块级别分为TRACE、DEBUG、INFO、NOTICE、WARN、ERROR五个级别,默认级别为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
|
286
core/app_admin.go
Normal file
286
core/app_admin.go
Normal file
@ -0,0 +1,286 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"ProjectWIND/LOG"
|
||||
"ProjectWIND/wba"
|
||||
"github.com/dop251/goja"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
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[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
|
||||
success = 0
|
||||
if err != nil {
|
||||
LOG.Error("加载应用所在目录失败:%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, file := range appFiles {
|
||||
totalDelta, successDelta := reloadAPP(file, appsDir)
|
||||
total += totalDelta
|
||||
success += successDelta
|
||||
}
|
||||
CmdMap[AppCore.AppKey] = AppCore.CmdMap
|
||||
GlobalCmdAgentSelector.AddCmdMap(CmdMap)
|
||||
return total, success
|
||||
}
|
||||
|
||||
// reloadAPP 重新加载单个应用
|
||||
func reloadAPP(file os.DirEntry, appsDir string) (totalDelta int, successDelta int) {
|
||||
if file.IsDir() {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
ext := filepath.Ext(file.Name())
|
||||
if ext == ".js" {
|
||||
pluginPath := filepath.Join(appsDir, file.Name())
|
||||
jsCode, err := os.ReadFile(pluginPath)
|
||||
if err != nil {
|
||||
LOG.Error("读取应用 %s 时发生错误: %v", pluginPath, err)
|
||||
return 1, 0
|
||||
}
|
||||
|
||||
runtime := goja.New()
|
||||
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()
|
||||
_ = runtime.Set("wba", wbaObj)
|
||||
_ = 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")
|
||||
if appInitVal == nil || goja.IsUndefined(appInitVal) {
|
||||
LOG.Error("应用 %s 缺少AppInit函数", pluginPath)
|
||||
return 1, 0
|
||||
}
|
||||
appInitFunc, ok := goja.AssertFunction(appInitVal)
|
||||
if !ok {
|
||||
LOG.Error("应用 %s 的AppInit不是有效函数", pluginPath)
|
||||
return 1, 0
|
||||
}
|
||||
|
||||
// 调用AppInit获取应用实例
|
||||
jsApp, err := appInitFunc(goja.Undefined())
|
||||
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(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[appInfo.AppKey] = appInfo
|
||||
|
||||
CmdMap[appInfo.AppKey] = appInfo.CmdMap
|
||||
|
||||
ScheduledTaskMap[appInfo.AppKey] = appInfo.ScheduledTasks
|
||||
|
||||
// 注册定时任务
|
||||
for _, task := range appInfo.ScheduledTasks {
|
||||
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)
|
||||
return 1, 1
|
||||
}
|
||||
return 0, 0
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
//go:build linux || darwin
|
||||
// +build linux darwin
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"ProjectWIND/LOG"
|
||||
"ProjectWIND/wba"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"plugin"
|
||||
)
|
||||
|
||||
var CmdMap = make(map[string]wba.Cmd)
|
||||
|
||||
func ReloadApps() (total int, success int) {
|
||||
appsDir := "./data/app/"
|
||||
appFiles, err := os.ReadDir(appsDir)
|
||||
total = 0
|
||||
success = 0
|
||||
if err != nil {
|
||||
LOG.ERROR("加载应用所在目录失败:%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, file := range appFiles {
|
||||
totalDelta, successDelta := reloadAPP(file, appsDir)
|
||||
total += totalDelta
|
||||
success += successDelta
|
||||
}
|
||||
CmdMap = mergeMaps(CmdMap, AppCore.CmdMap)
|
||||
return total, success
|
||||
}
|
||||
|
||||
func reloadAPP(file os.DirEntry, appsDir string) (totalDelta int, successDelta int) {
|
||||
if file.IsDir() {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
ext := filepath.Ext(file.Name())
|
||||
if ext == ".so" {
|
||||
pluginPath := filepath.Join(appsDir, file.Name())
|
||||
p, err := plugin.Open(pluginPath)
|
||||
if err != nil {
|
||||
LOG.ERROR("打开应用 %s 时发生错误: %v", pluginPath, err)
|
||||
return 1, 0
|
||||
}
|
||||
AppInit, err := p.Lookup("AppInit")
|
||||
if err != nil {
|
||||
LOG.ERROR("找不到应用 %s 提供的 AppInit 接口: %v", pluginPath, err)
|
||||
return 1, 0
|
||||
}
|
||||
app := AppInit.(func() wba.AppInfo)()
|
||||
|
||||
err = app.Init(&AppApi)
|
||||
if err != nil {
|
||||
LOG.ERROR("初始化应用 %s 失败: %v", pluginPath, err)
|
||||
}
|
||||
|
||||
CmdMap = mergeMaps(CmdMap, app.Get().CmdMap)
|
||||
LOG.INFO("应用 %s 加载成功", pluginPath)
|
||||
return 1, 1
|
||||
|
||||
}
|
||||
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
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"ProjectWIND/LOG"
|
||||
"ProjectWIND/wba"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var CmdMap = make(map[string]wba.Cmd)
|
||||
|
||||
func ReloadApps() (total int, success int) {
|
||||
appsDir := "./data/app/"
|
||||
appFiles, err := os.ReadDir(appsDir)
|
||||
total = 0
|
||||
success = 0
|
||||
if err != nil {
|
||||
LOG.ERROR("加载应用所在目录失败:%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, file := range appFiles {
|
||||
totalDelta, successDelta := reloadAPP(file, appsDir)
|
||||
total += totalDelta
|
||||
success += successDelta
|
||||
}
|
||||
CmdMap = mergeMaps(CmdMap, AppCore.CmdMap)
|
||||
return total, success
|
||||
}
|
||||
|
||||
func reloadAPP(file os.DirEntry, appsDir string) (totalDelta int, successDelta int) {
|
||||
if file.IsDir() {
|
||||
return 0, 0
|
||||
}
|
||||
ext := filepath.Ext(file.Name())
|
||||
if ext == ".dll" {
|
||||
pluginPath := filepath.Join(appsDir, file.Name())
|
||||
lib, err := syscall.LoadLibrary(pluginPath)
|
||||
if err != nil {
|
||||
LOG.ERROR("加载应用 %s 失败: %v", pluginPath, err)
|
||||
return 1, 0
|
||||
}
|
||||
defer func(handle syscall.Handle) {
|
||||
err := syscall.FreeLibrary(handle)
|
||||
if err != nil {
|
||||
LOG.ERROR("释放应用 %s 时发生错误: %v", pluginPath, err)
|
||||
}
|
||||
}(lib)
|
||||
|
||||
// 获取函数地址
|
||||
sym, err := syscall.GetProcAddress(lib, "AppInit")
|
||||
if err != nil {
|
||||
fmt.Println("找不到应用 %s 提供的 AppInit 接口: %v", err)
|
||||
return 1, 0
|
||||
}
|
||||
|
||||
// 定义函数类型
|
||||
AppInitPtr := (*func() wba.AppInfo)(unsafe.Pointer(&sym))
|
||||
AppInit := *AppInitPtr
|
||||
|
||||
app := AppInit()
|
||||
|
||||
err = app.Init(&AppApi)
|
||||
if err != nil {
|
||||
LOG.ERROR("初始化应用 %s 失败: %v", pluginPath, err)
|
||||
}
|
||||
|
||||
CmdMap = mergeMaps(CmdMap, app.Get().CmdMap)
|
||||
LOG.INFO("应用 %s 加载成功", pluginPath)
|
||||
return 1, 1
|
||||
|
||||
}
|
||||
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
|
||||
}
|
@ -3,31 +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.WindAPI) 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
|
||||
@ -35,20 +31,35 @@ func (app *AppInfo) GetCmd() map[string]wba.Cmd {
|
||||
|
||||
func NewCmd(name string, help string, solve func(args []string, msg wba.MessageEventInfo)) wba.Cmd {
|
||||
return wba.Cmd{
|
||||
NAME: name,
|
||||
DESC: help,
|
||||
SOLVE: solve,
|
||||
Name: name,
|
||||
Desc: help,
|
||||
Solve: solve,
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
LOG.INFO("发送核心版本信息:(至:%v-%v:%v-%v)", msg.MessageType, msg.GroupId, msg.UserId, msg.Sender.Nickname)
|
||||
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)
|
||||
},
|
||||
),
|
||||
},
|
||||
|
@ -6,13 +6,13 @@ import (
|
||||
"github.com/robfig/cron/v3"
|
||||
)
|
||||
|
||||
func RegisterCron(task wba.ScheduledTaskInfo) {
|
||||
func RegisterCron(appNames string, task wba.ScheduledTaskInfo) {
|
||||
// 注册定时任务
|
||||
c := cron.New(cron.WithSeconds())
|
||||
_, err := c.AddFunc(task.Cron, task.Task)
|
||||
if err != nil {
|
||||
LOG.ERROR("添加定时任务 %s 时出错%v:", task.Name, err)
|
||||
LOG.Error("添加定时任务 [%s]%s 时出错%v:", appNames, task.Name, err)
|
||||
}
|
||||
c.Start()
|
||||
LOG.INFO("定时任务 %s 注册成功", task.Name)
|
||||
LOG.Info("定时任务 [%s]%s 注册成功", appNames, task.Name)
|
||||
}
|
||||
|
@ -2,9 +2,11 @@ package core
|
||||
|
||||
import (
|
||||
"ProjectWIND/LOG"
|
||||
"ProjectWIND/database"
|
||||
"ProjectWIND/wba"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -12,25 +14,25 @@ func HandleMessage(msgJson []byte) {
|
||||
var msg wba.MessageEventInfo
|
||||
err := json.Unmarshal(msgJson, &msg)
|
||||
if err != nil {
|
||||
LOG.ERROR("消息事件反序列化失败: %v", err)
|
||||
LOG.Error("消息事件反序列化失败: %v", err)
|
||||
}
|
||||
// 处理消息
|
||||
LOG.INFO("收到消息:(来自:%v-%v:%v-%v)%v", msg.MessageType, msg.GroupId, msg.UserId, msg.Sender.Nickname, msg.RawMessage)
|
||||
//如果消息文本内容为bot,发送框架信息。
|
||||
cmd, args := CmdSplit(msg)
|
||||
_, ok := CmdMap[cmd]
|
||||
if ok {
|
||||
LOG.DEBUG("执行命令:%v %v", cmd, args)
|
||||
CmdMap[cmd].SOLVE(args, msg)
|
||||
LOG.Info("收到消息:(来自:%v-%v:%v-%v)%v", msg.MessageType, msg.GroupId, msg.UserId, msg.Sender.Nickname, msg.RawMessage)
|
||||
isCmd, ok, err := CmdHandle(msg)
|
||||
if err != nil {
|
||||
LOG.Error("命令处理失败: %v", err)
|
||||
}
|
||||
if !isCmd && ok {
|
||||
// 处理消息
|
||||
// TODO: 处理消息
|
||||
}
|
||||
// TODO: 处理消息内容
|
||||
}
|
||||
|
||||
func HandleNotice(msgJson []byte) {
|
||||
var notice wba.NoticeEventInfo
|
||||
err := json.Unmarshal(msgJson, ¬ice)
|
||||
if err != nil {
|
||||
LOG.ERROR("通知事件反序列化失败: %v", err)
|
||||
LOG.Error("通知事件反序列化失败: %v", err)
|
||||
}
|
||||
// TODO: 处理通知
|
||||
}
|
||||
@ -39,7 +41,7 @@ func HandleRequest(msgJson []byte) {
|
||||
var request wba.NoticeEventInfo
|
||||
err := json.Unmarshal(msgJson, &request)
|
||||
if err != nil {
|
||||
LOG.ERROR("请求事件反序列化失败: %v", err)
|
||||
LOG.Error("请求事件反序列化失败: %v", err)
|
||||
}
|
||||
// TODO: 处理请求
|
||||
}
|
||||
@ -48,39 +50,65 @@ func HandleMetaEvent(msgJson []byte) {
|
||||
var meta wba.NoticeEventInfo
|
||||
err := json.Unmarshal(msgJson, &meta)
|
||||
if err != nil {
|
||||
LOG.ERROR("元事件反序列化失败: %v", err)
|
||||
LOG.Error("元事件反序列化失败: %v", err)
|
||||
}
|
||||
// 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{}
|
||||
}
|
||||
func CmdHandle(msg wba.MessageEventInfo) (isCmd bool, ok bool, err error) {
|
||||
// 获取消息的原始文本
|
||||
text := msg.GetText()
|
||||
// 初始化会话工作状态
|
||||
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 = "{}"
|
||||
}
|
||||
//检查有无application.CmdList中的命令前缀
|
||||
if err = GlobalCmdAgentSelector.LoadConfig(session, conf.(string)); err != nil {
|
||||
LOG.Error("加载配置失败: %v", err)
|
||||
return false, false, err
|
||||
}
|
||||
|
||||
// 检查命令前缀
|
||||
for _, prefix := range cmdPrefix {
|
||||
if strings.HasPrefix(text, prefix) {
|
||||
// 解析命令
|
||||
text = strings.TrimPrefix(text, prefix)
|
||||
for cmd := range CmdMap {
|
||||
if strings.HasPrefix(text, cmd) {
|
||||
text = strings.TrimPrefix(text, cmd)
|
||||
text = strings.TrimPrefix(text, " ")
|
||||
return cmd, strings.Split(text, " ")
|
||||
}
|
||||
cmdSlice := strings.Split(text, " ")
|
||||
if text == "" {
|
||||
return false, true, nil
|
||||
}
|
||||
cmd := cmdSlice[0]
|
||||
args := cmdSlice[1:]
|
||||
|
||||
result, count := GlobalCmdAgentSelector.FindCmd(cmd, true)
|
||||
if count == 0 {
|
||||
LOG.Debug("未找到命令: %s", cmd)
|
||||
return false, true, nil
|
||||
}
|
||||
|
||||
// 执行找到的第一个匹配命令
|
||||
cmdFunc := result[0]
|
||||
if err := safeExecuteCmd(cmdFunc, args, msg); err != nil {
|
||||
LOG.Error("执行命令失败: %v", err)
|
||||
return true, false, err
|
||||
}
|
||||
return true, true, nil
|
||||
}
|
||||
}
|
||||
return "", []string{}
|
||||
return false, true, nil
|
||||
}
|
||||
|
||||
func statusCheck(msg wba.MessageEventInfo) bool {
|
||||
//TODO: 检查当前组群工作状态
|
||||
return false
|
||||
func safeExecuteCmd(cmdFunc wba.Cmd, args []string, msg wba.MessageEventInfo) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("%v", r)
|
||||
}
|
||||
}()
|
||||
cmdFunc.Solve(args, msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
var cmdPrefix = []string{"/", "!", "/", "!", ".", "。"}
|
||||
|
48
core/selector_doc.md
Normal file
48
core/selector_doc.md
Normal 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)
|
||||
}
|
||||
```
|
45
core/web_service.go
Normal file
45
core/web_service.go
Normal file
@ -0,0 +1,45 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"ProjectWIND/LOG"
|
||||
"context"
|
||||
"github.com/cloudwego/hertz/pkg/app"
|
||||
"github.com/cloudwego/hertz/pkg/app/server"
|
||||
"github.com/cloudwego/hertz/pkg/common/hlog"
|
||||
"github.com/cloudwego/hertz/pkg/protocol/consts"
|
||||
)
|
||||
|
||||
func WebServer(port string) *server.Hertz {
|
||||
// 设置自定义日志记录器
|
||||
hlog.SetLevel(hlog.LevelFatal)
|
||||
h := server.Default(server.WithHostPorts("0.0.0.0:" + port))
|
||||
LOG.Info("WebUI已启动,监听端口:%v", port)
|
||||
h.Use(LoggingMiddleware())
|
||||
h.GET("/index", func(ctx context.Context, c *app.RequestContext) {
|
||||
//返回webui/index.html
|
||||
c.File("./webui/index.html")
|
||||
})
|
||||
h.GET("/app/api/:appName/*action", func(ctx context.Context, c *app.RequestContext) {
|
||||
appName := c.Param("appName")
|
||||
action := c.Param("action")
|
||||
message := appName + "-" + action + "\n"
|
||||
c.String(consts.StatusOK, message)
|
||||
})
|
||||
return h
|
||||
}
|
||||
|
||||
// LoggingMiddleware 是一个中间件函数,用于记录请求信息
|
||||
func LoggingMiddleware() app.HandlerFunc {
|
||||
return func(c context.Context, ctx *app.RequestContext) {
|
||||
// 获取客户端 IP
|
||||
clientIP := ctx.ClientIP()
|
||||
// 获取请求完整路径
|
||||
fullPath := ctx.Request.URI().PathOriginal()
|
||||
// 继续处理请求
|
||||
ctx.Next(c)
|
||||
// 获取请求处理状态码
|
||||
statusCode := ctx.Response.StatusCode()
|
||||
// 在请求处理后记录结束信息
|
||||
LOG.Debug("收到网络请求 | IP: %s | Path: %s | Status: %d ", clientIP, fullPath, statusCode)
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package core
|
||||
|
||||
import (
|
||||
"ProjectWIND/LOG"
|
||||
"ProjectWIND/typed"
|
||||
"ProjectWIND/wba"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@ -10,45 +11,43 @@ import (
|
||||
"net/url"
|
||||
)
|
||||
|
||||
var gProtocolAddr string
|
||||
var gToken string
|
||||
var gProtocol typed.Protocol
|
||||
|
||||
// WebSocketHandler 接收WebSocket连接处的消息并处理
|
||||
func WebSocketHandler(protocolAddr string, token string) error {
|
||||
func WebSocketHandler(protocol typed.Protocol) error {
|
||||
// 保存全局变量
|
||||
gProtocolAddr = protocolAddr
|
||||
gToken = token
|
||||
gProtocol = protocol
|
||||
// 解析连接URL
|
||||
u, err := url.Parse(protocolAddr)
|
||||
u, err := url.Parse(protocol.Addr)
|
||||
if err != nil {
|
||||
LOG.ERROR("Parse URL error: %v", err)
|
||||
LOG.Error("Parse URL error: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// 创建一个带有Authorization头的HTTP请求
|
||||
req, err := http.NewRequest("GET", u.String(), nil)
|
||||
if err != nil {
|
||||
LOG.FATAL("创建请求出错:%v", err)
|
||||
LOG.Fatal("创建请求出错:%v", err)
|
||||
}
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
req.Header.Set("Authorization", "Bearer "+protocol.Token)
|
||||
// 配置WebSocket连接升级器
|
||||
dialer := websocket.DefaultDialer
|
||||
// 使用升级器建立WebSocket连接
|
||||
conn, _, err := dialer.Dial(req.URL.String(), req.Header)
|
||||
if err != nil {
|
||||
LOG.FATAL("建立WebSocket连接出错:%v", err)
|
||||
LOG.Fatal("建立WebSocket连接出错:%v", err)
|
||||
}
|
||||
defer func(conn *websocket.Conn) {
|
||||
err := conn.Close()
|
||||
if err != nil {
|
||||
LOG.ERROR("Close error: %v", err)
|
||||
LOG.Error("Close error: %v", err)
|
||||
}
|
||||
}(conn)
|
||||
LOG.INFO("已连接到WebSocket服务器: %v", u.String())
|
||||
ProtocolInfo := AppApi.GetVersionInfo()
|
||||
LOG.INFO("协议端信息: %v-%v", ProtocolInfo.Data.AppName, ProtocolInfo.Data.AppVersion)
|
||||
logInfo := AppApi.GetLoginInfo()
|
||||
LOG.INFO("连接到账号: %v(%v)", logInfo.Data.Nickname, logInfo.Data.UserId)
|
||||
LOG.Info("已连接到WebSocket服务器: %v", u.String())
|
||||
ProtocolInfo := ProtocolApi.GetVersionInfo()
|
||||
LOG.Info("协议端信息: %v-%v", ProtocolInfo.Data.AppName, ProtocolInfo.Data.AppVersion)
|
||||
logInfo := ProtocolApi.GetLoginInfo()
|
||||
LOG.Info("连接到账号: %v(%v)", logInfo.Data.Nickname, logInfo.Data.UserId)
|
||||
|
||||
// 定义通道,缓存消息和消息类型,防止消息处理阻塞
|
||||
messageChan := make(chan []byte, 32)
|
||||
@ -57,7 +56,7 @@ func WebSocketHandler(protocolAddr string, token string) error {
|
||||
// 接收消息并放入通道
|
||||
messageType, message, err := conn.ReadMessage()
|
||||
if err != nil {
|
||||
LOG.ERROR("ReadMessage error: %v", err)
|
||||
LOG.Error("ReadMessage error: %v", err)
|
||||
return err
|
||||
}
|
||||
messageChan <- message
|
||||
@ -78,14 +77,14 @@ func WebSocketHandler(protocolAddr string, token string) error {
|
||||
// processMessage 处理接收到的消息
|
||||
func processMessage(messageType int, message []byte) {
|
||||
if messageType != websocket.TextMessage {
|
||||
LOG.ERROR("Invalid message type: %v", messageType)
|
||||
LOG.Error("Invalid message type: %v", messageType)
|
||||
return
|
||||
}
|
||||
//message json解析
|
||||
var messageMap map[string]interface{}
|
||||
err := json.Unmarshal(message, &messageMap)
|
||||
if err != nil {
|
||||
LOG.ERROR("Unmarshal error: %v", err)
|
||||
LOG.Error("Unmarshal error: %v", err)
|
||||
return
|
||||
}
|
||||
// 处理接收到的消息
|
||||
@ -126,28 +125,28 @@ func wsAPI(body wba.APIRequestInfo) (Response wba.APIResponseInfo, err error) {
|
||||
return wba.APIResponseInfo{}, err
|
||||
}
|
||||
// 解析连接URL
|
||||
u, err := url.Parse(gProtocolAddr)
|
||||
u, err := url.Parse(gProtocol.Addr)
|
||||
if err != nil {
|
||||
LOG.ERROR("Parse URL error: %v", err)
|
||||
LOG.Error("Parse URL error: %v", err)
|
||||
return wba.APIResponseInfo{}, err
|
||||
}
|
||||
// 创建一个带有Authorization头的HTTP请求
|
||||
req, err := http.NewRequest("GET", u.String(), nil)
|
||||
if err != nil {
|
||||
LOG.FATAL("创建请求出错:%v", err)
|
||||
LOG.Fatal("创建请求出错:%v", err)
|
||||
}
|
||||
req.Header.Set("Authorization", "Bearer "+gToken)
|
||||
req.Header.Set("Authorization", "Bearer "+gProtocol.Token)
|
||||
// 配置WebSocket连接升级器
|
||||
dialer := websocket.DefaultDialer
|
||||
// 使用升级器建立WebSocket连接
|
||||
conn, _, err := dialer.Dial(req.URL.String(), req.Header)
|
||||
if err != nil {
|
||||
LOG.FATAL("建立WebSocket连接出错:%v", err)
|
||||
LOG.Fatal("建立WebSocket连接出错:%v", err)
|
||||
}
|
||||
defer func(conn *websocket.Conn) {
|
||||
err := conn.Close()
|
||||
if err != nil {
|
||||
LOG.ERROR("Close error: %v", err)
|
||||
LOG.Error("Close error: %v", err)
|
||||
}
|
||||
}(conn)
|
||||
err = conn.WriteMessage(websocket.TextMessage, bodyBytes)
|
||||
|
@ -11,6 +11,9 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const address = "./data/database/datamaps.wdb"
|
||||
const core = "./data/core.json"
|
||||
|
||||
type unit struct {
|
||||
Id string
|
||||
Data map[string]string
|
||||
@ -20,29 +23,67 @@ type User unit
|
||||
type Group unit
|
||||
type Global unit
|
||||
|
||||
type Database struct {
|
||||
Id string
|
||||
Users map[string]User
|
||||
Groups map[string]Group
|
||||
Global map[string]Global
|
||||
type Configs struct {
|
||||
Number map[string]int64
|
||||
String map[string]string
|
||||
Float map[string]float64
|
||||
Number_Slice map[string][]int64
|
||||
String_Slice map[string][]string
|
||||
Hash string
|
||||
}
|
||||
|
||||
func newDatabase(id string) Database {
|
||||
// 创建数据库
|
||||
db := &Database{
|
||||
Id: id,
|
||||
Users: make(map[string]User),
|
||||
Groups: make(map[string]Group),
|
||||
Global: make(map[string]Global),
|
||||
type Datamap struct {
|
||||
Id string
|
||||
Permission string
|
||||
Users map[string]User
|
||||
Groups map[string]Group
|
||||
Global map[string]Global
|
||||
Configs Configs
|
||||
}
|
||||
|
||||
type Database struct {
|
||||
Datamaps map[string]Datamap
|
||||
}
|
||||
|
||||
func newDatamap(id string) Datamap {
|
||||
// 创建数据表
|
||||
db := &Datamap{
|
||||
Id: id,
|
||||
Permission: "private",
|
||||
Users: make(map[string]User),
|
||||
Groups: make(map[string]Group),
|
||||
Global: make(map[string]Global),
|
||||
Configs: Configs{
|
||||
Number: make(map[string]int64),
|
||||
String: make(map[string]string),
|
||||
Float: make(map[string]float64),
|
||||
Number_Slice: make(map[string][]int64),
|
||||
String_Slice: make(map[string][]string),
|
||||
Hash: "",
|
||||
},
|
||||
}
|
||||
return *db
|
||||
}
|
||||
|
||||
func newDatabase() Database {
|
||||
// 创建数据库
|
||||
db := &Database{
|
||||
Datamaps: make(map[string]Datamap),
|
||||
}
|
||||
return *db
|
||||
}
|
||||
|
||||
func (this *Database) addDatamap(id string) {
|
||||
// 创建新数据表
|
||||
db := newDatamap(id)
|
||||
this.Datamaps[id] = db
|
||||
}
|
||||
|
||||
func folderCheck(filename string) {
|
||||
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||
err := os.MkdirAll(filename, 0755)
|
||||
if err != nil {
|
||||
LOG.FATAL("[ERROR]Error occured while create folder: %v", err)
|
||||
LOG.Fatal("创建文件夹时出错: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -54,12 +95,12 @@ func fileCheck(filename string) {
|
||||
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||
file, err := os.Create(filename)
|
||||
if err != nil {
|
||||
LOG.FATAL("[ERROR]Error occured while create file: %v", err)
|
||||
LOG.Fatal("创建文件时出错: %v", err)
|
||||
}
|
||||
defer func(file *os.File) {
|
||||
err := file.Close()
|
||||
if err != nil {
|
||||
LOG.FATAL("[ERROR]Error occured while close file: %v", err)
|
||||
LOG.Fatal("创建文件时出错: %v", err)
|
||||
}
|
||||
}(file)
|
||||
}
|
||||
@ -68,13 +109,13 @@ func fileCheck(filename string) {
|
||||
func writeContent(f *os.File, str string) error {
|
||||
// 写入内容到文件
|
||||
if f == nil {
|
||||
// log.Printf("[ERROR]file is nil")
|
||||
LOG.ERROR("[ERROR]file is nil")
|
||||
// log.Printf("[Error]file is nil")
|
||||
LOG.Error("文件不存在")
|
||||
return errors.New("file is nil")
|
||||
}
|
||||
_, err := f.Write([]byte(str))
|
||||
if err != nil {
|
||||
LOG.ERROR("[ERROR]Error while write content to file: %v", err)
|
||||
LOG.Error("无法写入到文件: %v", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@ -90,17 +131,40 @@ func printContent(file string) (string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func getCorePassword() string {
|
||||
// 获取核心密码
|
||||
filename := core
|
||||
fileCheck(filename)
|
||||
dataJson, err := printContent(filename)
|
||||
if err != nil {
|
||||
LOG.Error("读取文件时出错 %s: %v", filename, err)
|
||||
return ""
|
||||
}
|
||||
config := make(map[string]string)
|
||||
err = json.Unmarshal([]byte(dataJson), config)
|
||||
if err != nil {
|
||||
LOG.Error("反序列化时出错: %v", err)
|
||||
return ""
|
||||
}
|
||||
password, ok := config["password"]
|
||||
if !ok {
|
||||
LOG.Warn("core.json中未找到配置密码项")
|
||||
return ""
|
||||
}
|
||||
return password
|
||||
}
|
||||
|
||||
func saveData(db *Database) error {
|
||||
// 保存数据到文件
|
||||
dataJson, err := json.Marshal(db)
|
||||
if err != nil {
|
||||
LOG.ERROR("[ERROR]:Error while marshal data: %v", err)
|
||||
LOG.Error("序列化数据时出错: %v", err)
|
||||
return err
|
||||
}
|
||||
filename := "./database/" + db.Id + ".wdb"
|
||||
filename := address
|
||||
file, err := os.Create(filename)
|
||||
if err != nil {
|
||||
LOG.ERROR("[ERROR]:Error while create file %s: %v", filename, err)
|
||||
LOG.Error("创建文件时出错 %s: %v", filename, err)
|
||||
return err
|
||||
}
|
||||
writeContent(file, string(dataJson))
|
||||
@ -109,18 +173,16 @@ func saveData(db *Database) error {
|
||||
|
||||
func loadData(db *Database) error {
|
||||
// 读取配置文件
|
||||
filename := "./database/" + db.Id + ".wdb"
|
||||
filename := address
|
||||
fileCheck(filename)
|
||||
dataJson, err := printContent(filename)
|
||||
if err != nil {
|
||||
// log.Printf("[ERROR]:Error while read file %s: %v", filename, err)
|
||||
LOG.ERROR("[ERROR]:Error while read file %s: %v", filename, err)
|
||||
LOG.Error("读文件时出错 %s: %v", filename, err)
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal([]byte(dataJson), db)
|
||||
if err != nil {
|
||||
// log.Printf("[ERROR]:Error while unmarshal data: %v", err)
|
||||
LOG.WARN("[WARNING]:Error while unmarshal data: %v", err)
|
||||
LOG.Warn("反序列化数据时出错: %v", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@ -128,116 +190,247 @@ func loadData(db *Database) error {
|
||||
|
||||
var DB *Database
|
||||
|
||||
func dataGet(db *Database, category string, id string, key string) (string, bool) {
|
||||
// 查询数据
|
||||
switch category {
|
||||
case "user":
|
||||
user, ok := db.Users[id]
|
||||
if !ok {
|
||||
LOG.WARN("[WARNING]:User %s not found", id)
|
||||
return "", false
|
||||
}
|
||||
if user.Data == nil {
|
||||
LOG.WARN("[WARNING]:User %s's data is nil", id)
|
||||
return "", false
|
||||
}
|
||||
value, ok := user.Data[key]
|
||||
if !ok {
|
||||
LOG.WARN("[WARNING]:User %s's data %s not found", id, key)
|
||||
return "", false
|
||||
}
|
||||
return value, true
|
||||
case "group":
|
||||
group, ok := db.Groups[id]
|
||||
if !ok {
|
||||
LOG.WARN("[WARNING]:Group %s not found", id)
|
||||
return "", false
|
||||
}
|
||||
if group.Data == nil {
|
||||
LOG.WARN("[WARNING]:Group %s's data is nil", id)
|
||||
return "", false
|
||||
}
|
||||
value, ok := group.Data[key]
|
||||
if !ok {
|
||||
LOG.WARN("[WARNING]:Group %s's data %s not found", id, key)
|
||||
return "", false
|
||||
}
|
||||
return value, true
|
||||
case "global":
|
||||
global, ok := db.Global[id]
|
||||
if !ok {
|
||||
LOG.WARN("[WARNING]:Global %s not found", id)
|
||||
return "", false
|
||||
}
|
||||
if global.Data == nil {
|
||||
LOG.WARN("[WARNING]:Global data of %s is nil", id)
|
||||
return "", false
|
||||
}
|
||||
value, ok := global.Data[key]
|
||||
if !ok {
|
||||
LOG.WARN("[WARNING]:Global data of %s's %s not found", id, key)
|
||||
return "", false
|
||||
}
|
||||
return value, true
|
||||
default:
|
||||
LOG.ERROR("[ERROR]:Invalid category %s", category)
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
|
||||
func dataSet(db *Database, category string, id string, key string, value string) {
|
||||
func dataSet(datamap string, unit string, id string, key string, value interface{}, isAllowed bool, isMaster bool) {
|
||||
// 修改数据
|
||||
switch category {
|
||||
dm, ok := DB.Datamaps[datamap]
|
||||
if !ok {
|
||||
// 创建新数据表
|
||||
DB.addDatamap(datamap)
|
||||
dm = DB.Datamaps[datamap]
|
||||
}
|
||||
if !isAllowed && !isMaster && dm.Permission != "private" {
|
||||
LOG.Warn("访问权限不足")
|
||||
return
|
||||
}
|
||||
if !isMaster && dm.Permission == "master" {
|
||||
LOG.Warn("访问权限不足")
|
||||
return
|
||||
}
|
||||
switch unit {
|
||||
case "config":
|
||||
switch id {
|
||||
case "number":
|
||||
valueInt64, ok := value.(int64) // 断言value为int64类型
|
||||
if !ok {
|
||||
LOG.Error("配置值无法被断言为int64类型")
|
||||
return
|
||||
}
|
||||
dm.Configs.Number[key] = valueInt64 // 使用断言后的int64值
|
||||
case "string":
|
||||
valueStr, ok := value.(string) // 断言value为string类型
|
||||
if !ok {
|
||||
LOG.Error("配置值无法被断言为string类型")
|
||||
return
|
||||
}
|
||||
dm.Configs.String[key] = valueStr // 使用断言后的string值
|
||||
case "float":
|
||||
valueFloat64, ok := value.(float64) // 断言value为float64类型
|
||||
if !ok {
|
||||
LOG.Error("配置值无法被断言为float64类型")
|
||||
return
|
||||
}
|
||||
dm.Configs.Float[key] = valueFloat64 // 使用断言后的float64值
|
||||
case "number_slice":
|
||||
valueInt64Slice, ok := value.([]int64) // 断言value为[]int64类型
|
||||
if !ok {
|
||||
LOG.Error("配置值无法被断言为[]int64类型")
|
||||
return
|
||||
}
|
||||
dm.Configs.Number_Slice[key] = valueInt64Slice // 使用断言后的[]int64值
|
||||
case "string_slice":
|
||||
valueStrSlice, ok := value.([]string) // 断言value为[]string类型
|
||||
if !ok {
|
||||
LOG.Error("配置值无法被断言为[]string类型")
|
||||
return
|
||||
}
|
||||
dm.Configs.String_Slice[key] = valueStrSlice // 使用断言后的[]string值
|
||||
case "hash":
|
||||
valueStr, ok := value.(string) // 断言value为string类型
|
||||
if !ok {
|
||||
LOG.Error("配置值无法被断言为string类型")
|
||||
return
|
||||
}
|
||||
dm.Configs.Hash = valueStr // 使用断言后的string值
|
||||
default:
|
||||
LOG.Error("不合法的配置项类型 %s", id)
|
||||
}
|
||||
case "user":
|
||||
user, ok := db.Users[id]
|
||||
valueStr, ok := value.(string) // 断言value为string类型
|
||||
if !ok {
|
||||
db.Users[id] = User{
|
||||
LOG.Error("变量值无法被断言为string类型")
|
||||
return
|
||||
}
|
||||
user, ok := dm.Users[id]
|
||||
if !ok {
|
||||
dm.Users[id] = User{
|
||||
Id: id,
|
||||
Data: make(map[string]string),
|
||||
}
|
||||
user = db.Users[id]
|
||||
user = dm.Users[id]
|
||||
}
|
||||
if user.Data == nil {
|
||||
user.Data = make(map[string]string)
|
||||
}
|
||||
user.Data[key] = value
|
||||
user.Data[key] = valueStr // 使用断言后的string值
|
||||
case "group":
|
||||
group, ok := db.Groups[id]
|
||||
valueStr, ok := value.(string) // 断言value为string类型
|
||||
if !ok {
|
||||
db.Groups[id] = Group{
|
||||
LOG.Error("变量值无法被断言为string类型")
|
||||
return
|
||||
}
|
||||
group, ok := dm.Groups[id]
|
||||
if !ok {
|
||||
dm.Groups[id] = Group{
|
||||
Id: id,
|
||||
Data: make(map[string]string),
|
||||
}
|
||||
group = db.Groups[id]
|
||||
group = dm.Groups[id]
|
||||
}
|
||||
if group.Data == nil {
|
||||
group.Data = make(map[string]string)
|
||||
}
|
||||
group.Data[key] = value
|
||||
group.Data[key] = valueStr // 使用断言后的string值
|
||||
case "global":
|
||||
global, ok := db.Global[id]
|
||||
valueStr, ok := value.(string) // 断言value为string类型
|
||||
if !ok {
|
||||
db.Global[id] = Global{
|
||||
LOG.Error("变量值无法被断言为string类型")
|
||||
return
|
||||
}
|
||||
global, ok := dm.Global[id]
|
||||
if !ok {
|
||||
dm.Global[id] = Global{
|
||||
Id: id,
|
||||
Data: make(map[string]string),
|
||||
}
|
||||
global = db.Global[id]
|
||||
global = dm.Global[id]
|
||||
}
|
||||
if global.Data == nil {
|
||||
global.Data = make(map[string]string)
|
||||
}
|
||||
global.Data[key] = value
|
||||
global.Data[key] = valueStr // 使用断言后的string值
|
||||
default:
|
||||
LOG.ERROR("[ERROR]:Invalid category %s", category)
|
||||
LOG.Error("不合法的数据单元 %s", unit)
|
||||
}
|
||||
}
|
||||
|
||||
func dataGet(datamap string, unit string, id string, key string, isAllowed bool, isMaster bool) (interface{}, bool) {
|
||||
dm, ok := DB.Datamaps[datamap]
|
||||
if !ok {
|
||||
LOG.Warn("数据表不存在 %s", datamap)
|
||||
return "", false
|
||||
}
|
||||
if !isAllowed && !isMaster && dm.Permission != "private" {
|
||||
LOG.Warn("访问权限不足")
|
||||
return "", false
|
||||
}
|
||||
if !isMaster && dm.Permission == "master" {
|
||||
LOG.Warn("访问权限不足")
|
||||
return "", false
|
||||
}
|
||||
switch unit {
|
||||
case "config":
|
||||
switch id {
|
||||
case "number":
|
||||
value, ok := dm.Configs.Number[key]
|
||||
if !ok {
|
||||
LOG.Warn("配置项不存在%s", key)
|
||||
return 0, false
|
||||
}
|
||||
return value, true
|
||||
case "string":
|
||||
value, ok := dm.Configs.String[key]
|
||||
if !ok {
|
||||
LOG.Warn("配置项不存在%s", key)
|
||||
return "", false
|
||||
}
|
||||
return value, true
|
||||
case "float":
|
||||
value, ok := dm.Configs.Float[key]
|
||||
if !ok {
|
||||
LOG.Warn("配置项不存在%s", key)
|
||||
return 0.0, false
|
||||
}
|
||||
return value, true
|
||||
case "number_slice":
|
||||
value, ok := dm.Configs.Number_Slice[key]
|
||||
if !ok {
|
||||
LOG.Warn("配置项不存在%s", key)
|
||||
return []int64{}, false
|
||||
}
|
||||
return value, true
|
||||
case "string_slice":
|
||||
value, ok := dm.Configs.String_Slice[key]
|
||||
if !ok {
|
||||
LOG.Warn("配置项不存在%s", key)
|
||||
return []string{}, false
|
||||
}
|
||||
return value, true
|
||||
case "hash":
|
||||
return dm.Configs.Hash, true
|
||||
default:
|
||||
LOG.Error("不合法的配置项类型 %s", id)
|
||||
return "", false
|
||||
}
|
||||
case "user":
|
||||
user, ok := dm.Users[id]
|
||||
if !ok {
|
||||
LOG.Warn("用户 %s 不存在", id)
|
||||
return "", false
|
||||
}
|
||||
if user.Data == nil {
|
||||
LOG.Warn("用户 %s 的数据显示为nil", id)
|
||||
return "", false
|
||||
}
|
||||
value, ok := user.Data[key]
|
||||
if !ok {
|
||||
LOG.Warn("用户 %s 的数据中键 %s 不存在", id, key)
|
||||
return "", false
|
||||
}
|
||||
return value, true
|
||||
case "group":
|
||||
group, ok := dm.Groups[id]
|
||||
if !ok {
|
||||
LOG.Warn("群组 %s 的数据不存在", id)
|
||||
return "", false
|
||||
}
|
||||
if group.Data == nil {
|
||||
LOG.Warn("群组 %s 的数据显示为nil", id)
|
||||
return "", false
|
||||
}
|
||||
value, ok := group.Data[key]
|
||||
if !ok {
|
||||
LOG.Warn("群组 %s 的数据中键 %s 不存在", id, key)
|
||||
return "", false
|
||||
}
|
||||
return value, true
|
||||
case "global":
|
||||
global, ok := dm.Global[id]
|
||||
if !ok {
|
||||
LOG.Warn("全局变量 %s 的数据不存在", id)
|
||||
return "", false
|
||||
}
|
||||
if global.Data == nil {
|
||||
LOG.Warn("全局变量 %s 的数据显示为nil", id)
|
||||
return "", false
|
||||
}
|
||||
value, ok := global.Data[key]
|
||||
if !ok {
|
||||
LOG.Warn("全局变量 %s 的数据中键 %s 不存在", id, key)
|
||||
return "", false
|
||||
}
|
||||
return value, true
|
||||
default:
|
||||
LOG.Error("Invalid unit %s", unit)
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
|
||||
func initializeDatabase() *Database {
|
||||
// 启动并检查程序
|
||||
LOG.INFO("Starting database ...")
|
||||
db := newDatabase("datamap")
|
||||
LOG.Info("正在启动数据库")
|
||||
db := newDatabase()
|
||||
loadData(&db)
|
||||
LOG.INFO("Database started successfully.")
|
||||
LOG.Info("数据库启动完成")
|
||||
return &db
|
||||
}
|
||||
|
||||
@ -249,7 +442,7 @@ func Start() {
|
||||
signal.Notify(dataChan, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
// 定义一个Ticker用于每1小时触发一次保存操作
|
||||
saveTicker := time.NewTicker(600 * time.Second)
|
||||
saveTicker := time.NewTicker(3600 * time.Second)
|
||||
defer saveTicker.Stop()
|
||||
|
||||
// 启动一个goroutine等待信号和定时保存
|
||||
@ -258,12 +451,12 @@ func Start() {
|
||||
select {
|
||||
case <-dataChan:
|
||||
// 接收到信号,保存数据并退出程序
|
||||
LOG.INFO("Received signal, saving data and exiting...")
|
||||
LOG.Info("关闭中,正在保存数据")
|
||||
saveData(DB)
|
||||
os.Exit(0)
|
||||
case <-saveTicker.C:
|
||||
// 定时保存数据
|
||||
LOG.INFO("Saving data automatically...")
|
||||
LOG.Info("自动保存数据")
|
||||
saveData(DB)
|
||||
}
|
||||
}
|
||||
@ -272,12 +465,123 @@ func Start() {
|
||||
select {} // 阻塞
|
||||
}
|
||||
|
||||
func Get(category string, id string, key string) (string, bool) {
|
||||
// 查询数据
|
||||
return dataGet(DB, category, id, key)
|
||||
func CreatePublicDatamap(appName string, id string) {
|
||||
// 查询权限
|
||||
hash := getCorePassword()
|
||||
if hash == "" {
|
||||
// 删除数据表哈希
|
||||
dataSet(appName, "config", "hash", "", "", true, true)
|
||||
}
|
||||
datahash, ok := dataGet(appName, "config", "hash", "", true, true)
|
||||
if !ok {
|
||||
// LOG.Error("[Error]:Error while get hash of %s", appName)
|
||||
LOG.Error("获取应用数据表 %s 的密钥时出错", appName)
|
||||
return
|
||||
}
|
||||
if hash != datahash {
|
||||
LOG.Warn("应用 %s 没有创建公开数据表的权限", appName)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建公开数据表
|
||||
db, ok := DB.Datamaps[id]
|
||||
if !ok {
|
||||
db = newDatamap(id)
|
||||
db.Permission = "public"
|
||||
DB.Datamaps[id] = db
|
||||
} else {
|
||||
LOG.Info("数据表 %s 已经存在", id)
|
||||
}
|
||||
}
|
||||
|
||||
func Set(category string, id string, key string, value string) {
|
||||
// 修改数据
|
||||
dataSet(DB, category, id, key, value)
|
||||
func MasterCreatePublicDatamap(id string) {
|
||||
// 创建核心数据表
|
||||
db, ok := DB.Datamaps[id]
|
||||
if !ok {
|
||||
db = newDatamap(id)
|
||||
db.Permission = "master"
|
||||
DB.Datamaps[id] = db
|
||||
} else {
|
||||
LOG.Info("数据表 %s 已经存在", id)
|
||||
}
|
||||
}
|
||||
|
||||
func MasterCreateMasterDatamap(id string) {
|
||||
// 创建公开数据表
|
||||
db, ok := DB.Datamaps[id]
|
||||
if !ok {
|
||||
db = newDatamap(id)
|
||||
db.Permission = "public"
|
||||
DB.Datamaps[id] = db
|
||||
} else {
|
||||
LOG.Info("数据表 %s 已经存在", id)
|
||||
}
|
||||
}
|
||||
|
||||
// 修改数据(核心)
|
||||
func MasterSet(datamap string, unit string, id string, key string, value interface{}) {
|
||||
dataSet(datamap, unit, id, key, value, true, true)
|
||||
}
|
||||
|
||||
// 查询数据(核心)
|
||||
func MasterGet(datamap string, unit string, id string, key string) (interface{}, bool) {
|
||||
return dataGet(datamap, unit, id, key, true, true)
|
||||
}
|
||||
|
||||
func Get(appName string, datamap string, unit string, id string, key string, isGettingConfig bool) (interface{}, bool) {
|
||||
// 查询数据
|
||||
if unit == "config" && id == "hash" {
|
||||
// app不允许访问hash数据
|
||||
LOG.Error("应用 %s 不允许访问数据库密钥", appName)
|
||||
return "", false
|
||||
}
|
||||
if !isGettingConfig && unit == "config" {
|
||||
// 不允许在非config数据表中访问config数据
|
||||
LOG.Error("应用 %s 不能在常规读写中访问配置项信息,请使用配置项读取功能", appName)
|
||||
return "", false
|
||||
}
|
||||
if appName != datamap {
|
||||
// 需要master密码来访问其他app的数据
|
||||
hash := getCorePassword()
|
||||
if hash == "" {
|
||||
// 删除数据表哈希
|
||||
dataSet(appName, "config", "hash", "", "", true, true)
|
||||
}
|
||||
datahash, ok := dataGet(appName, "config", "hash", "", true, true)
|
||||
if !ok {
|
||||
LOG.Error("获取应用数据表 %s 的密钥时出错", appName)
|
||||
}
|
||||
if hash != datahash {
|
||||
LOG.Warn("应用 %s 未被允许获取数据表 %s 的信息", appName, datamap)
|
||||
return dataGet(appName, unit, id, key, false, false)
|
||||
}
|
||||
|
||||
}
|
||||
return dataGet(appName, unit, id, key, true, true)
|
||||
}
|
||||
|
||||
func Set(appName string, datamap string, unit string, id string, key string, value interface{}) {
|
||||
// 修改数据
|
||||
if unit == "config" {
|
||||
// app不允许修改config数据
|
||||
LOG.Error("应用 %s 不允许修改配置项信息", appName)
|
||||
return
|
||||
}
|
||||
if appName != datamap {
|
||||
// 需要master密码来访问其他app的数据
|
||||
hash := getCorePassword()
|
||||
if hash == "" {
|
||||
// 删除数据表哈希
|
||||
dataSet(appName, "config", "hash", "", "", true, true)
|
||||
}
|
||||
datahash, ok := dataGet(appName, "config", "hash", "", true, true)
|
||||
if !ok {
|
||||
LOG.Error("获取应用数据表 %s 的密钥时出错", appName)
|
||||
}
|
||||
if hash != datahash {
|
||||
LOG.Warn("应用 %s 未被允许修改数据表 %s 的信息", appName, datamap)
|
||||
dataSet(appName, unit, id, key, value, false, false)
|
||||
}
|
||||
}
|
||||
dataSet(appName, unit, id, key, value, true, false)
|
||||
}
|
||||
|
@ -1,40 +0,0 @@
|
||||
```go
|
||||
func Start() //启动默认数据库
|
||||
```
|
||||
|
||||
该函数用于启动数据库,加载数据,启动自动存储
|
||||
|
||||
Tips:需要异步启动数据库,否则进程会被阻塞
|
||||
|
||||
Tips:需要在启动数据库后等待其初始化,建议使用time.Sleep()函数等待至少1秒
|
||||
|
||||
```go
|
||||
func Get(database *database, category string, id string, key string) (string,bool) //获取变量,示例用法:// database.Get("user", "1001", "age") 表示查询db数据库中id为1001的用户个人变量age
|
||||
```
|
||||
|
||||
该函数用于查询设定的变量
|
||||
|
||||
——category部分可以填入"user","group","global",分别表示个人变量,群变量,全局变量
|
||||
|
||||
——id为用户id或群id,全局变量使用时,id可以理解为命名空间
|
||||
|
||||
——key为要查询的变量名
|
||||
|
||||
返回值类型为string,bool,第一个返回值为查询到的变量,第二个返回值表示是否返回成功
|
||||
|
||||
```go
|
||||
func Set(category string, id string, key string, value string) //修改变量,示例用法:
|
||||
// database.Set("user", "1001", "age", "18") 表示将db数据库中id为1001的用户个人变量age设置为"18"
|
||||
// 注意:变量目前只支持string类型,如果需要储存数据或对象,请将它们转化为string类型再进行储存
|
||||
// 该数据库的所有变量将会存放在/data/database/datamap.txt中,请不要乱动这个文件
|
||||
```
|
||||
|
||||
该函数用于新建或修改变量
|
||||
|
||||
——category部分可以填入"user","group","global",分别表示个人变量,群变量,全局变量
|
||||
|
||||
——id为用户id或群id,全局变量使用时,id可以理解为命名空间
|
||||
|
||||
——key为要修改的变量名
|
||||
|
||||
——value为要修改的变量值
|
28
go.mod
28
go.mod
@ -2,9 +2,33 @@ module ProjectWIND
|
||||
|
||||
go 1.23.2
|
||||
|
||||
require github.com/gorilla/websocket v1.5.3
|
||||
require (
|
||||
github.com/cloudwego/hertz v0.9.5
|
||||
github.com/dop251/goja v0.0.0-20250125213203-5ef83b82af17
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||
github.com/bytedance/gopkg v0.1.0 // indirect
|
||||
github.com/bytedance/sonic v1.12.0 // indirect
|
||||
github.com/bytedance/sonic/loader v0.2.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||
github.com/cloudwego/netpoll v0.6.4 // indirect
|
||||
github.com/dlclark/regexp2 v1.11.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
|
||||
github.com/golang/protobuf v1.5.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
|
||||
github.com/nyaruka/phonenumbers v1.0.55 // indirect
|
||||
github.com/tidwall/gjson v1.14.4 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/text v0.3.8 // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
)
|
||||
|
93
go.sum
93
go.sum
@ -1,6 +1,99 @@
|
||||
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
|
||||
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
github.com/bytedance/gopkg v0.1.0 h1:aAxB7mm1qms4Wz4sp8e1AtKDOeFLtdqvGiUe7aonRJs=
|
||||
github.com/bytedance/gopkg v0.1.0/go.mod h1:FtQG3YbQG9L/91pbKSw787yBQPutC+457AvDW77fgUQ=
|
||||
github.com/bytedance/mockey v1.2.12 h1:aeszOmGw8CPX8CRx1DZ/Glzb1yXvhjDh6jdFBNZjsU4=
|
||||
github.com/bytedance/mockey v1.2.12/go.mod h1:3ZA4MQasmqC87Tw0w7Ygdy7eHIc2xgpZ8Pona5rsYIk=
|
||||
github.com/bytedance/sonic v1.12.0 h1:YGPgxF9xzaCNvd/ZKdQ28yRovhfMFZQjuk6fKBzZ3ls=
|
||||
github.com/bytedance/sonic v1.12.0/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
|
||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM=
|
||||
github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||
github.com/cloudwego/hertz v0.9.5 h1:FXV2YFLrNHRdpwT+OoIvv0wEHUC0Bo68CDPujr6VnWo=
|
||||
github.com/cloudwego/hertz v0.9.5/go.mod h1:UUBt8N8hSTStz7NEvLZ5mnALpBSofNL4DoYzIIp8UaY=
|
||||
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||
github.com/cloudwego/netpoll v0.6.4 h1:z/dA4sOTUQof6zZIO4QNnLBXsDFFFEos9OOGloR6kno=
|
||||
github.com/cloudwego/netpoll v0.6.4/go.mod h1:BtM+GjKTdwKoC8IOzD08/+8eEn2gYoiNLipFca6BVXQ=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
|
||||
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/dop251/goja v0.0.0-20250125213203-5ef83b82af17 h1:spJaibPy2sZNwo6Q0HjBVufq7hBUj5jNFOKRoogCBow=
|
||||
github.com/dop251/goja v0.0.0-20250125213203-5ef83b82af17/go.mod h1:MxLav0peU43GgvwVgNbLAj1s/bSGboKkhuULvq/7hx4=
|
||||
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
|
||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||
github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
|
||||
github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 h1:4/hN5RUoecvl+RmJRE2YxKWtnnQls6rQjjW5oV7qg2U=
|
||||
github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/nyaruka/phonenumbers v1.0.55 h1:bj0nTO88Y68KeUQ/n3Lo2KgK7lM1hF7L9NFuwcCl3yg=
|
||||
github.com/nyaruka/phonenumbers v1.0.55/go.mod h1:sDaTZ/KPX5f8qyV9qN+hIm+4ZBARJrupC6LuhshJq1U=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
|
||||
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
|
21
main.go
21
main.go
@ -12,8 +12,14 @@ func main() {
|
||||
//如果没有参数,则启动WebUI
|
||||
if len(os.Args) <= 1 {
|
||||
initCore()
|
||||
fmt.Println("请修改配置文件后,使用-p参数连接协议端开始运行。")
|
||||
return
|
||||
// 启动WebUI
|
||||
h := core.WebServer("8080")
|
||||
go h.Spin()
|
||||
// 连接到数据库
|
||||
go startDatabase()
|
||||
// 连接到协议端
|
||||
go startProtocol()
|
||||
select {}
|
||||
}
|
||||
cmdArgs := os.Args[1:]
|
||||
if cmdArgs[0] == "-h" || cmdArgs[0] == "--help" {
|
||||
@ -42,17 +48,6 @@ func main() {
|
||||
registerService()
|
||||
return
|
||||
}
|
||||
if cmdArgs[0] == "-p" || cmdArgs[0] == "--protocol" {
|
||||
// 连接到协议端
|
||||
go AutoSave()
|
||||
startProtocol()
|
||||
return
|
||||
}
|
||||
if cmdArgs[0] == "-d" || cmdArgs[0] == "--database" {
|
||||
// 连接到数据库
|
||||
startDatabase()
|
||||
return
|
||||
}
|
||||
fmt.Println("未知命令,请使用-h查看帮助。")
|
||||
return
|
||||
}
|
||||
|
55
readme.md
55
readme.md
@ -1,4 +1,4 @@
|
||||
# ProjectWIND
|
||||
# WIND
|
||||
像风一样自由
|
||||
|
||||
<div style="text-align: center;"><img src="./logo.png" alt="ProjectWIND" width="50%" ></div>
|
||||
@ -8,20 +8,38 @@ license: [MIT](./LICENSE)
|
||||
🚧🚧🚧🚧施工中ing…… 🚧🚧🚧🚧
|
||||
> warning: 该项目正在开发中,请勿用于生产环境
|
||||
|
||||
TODO:
|
||||
- ✅ 协议端通信
|
||||
- ✅ 日志输出
|
||||
- ✅ 文件初始化
|
||||
- ✅ 事件处理
|
||||
- ✅ 数据库交互
|
||||
- ❌ 插件系统
|
||||
- ❌ 用户系统
|
||||
- ❌ web ui
|
||||
- ❌ 文档编写
|
||||
|
||||
## WIND 是什么?
|
||||
|
||||
WIND(全称:WIND is not dice)是一个基于 Go 语言开发的bot框架,旨在以高自由度完成各种功能。
|
||||
WIND ( *WIND is not dice* ) 是一个基于 Go 语言开发的bot框架,旨在以高自由度完成各种功能。
|
||||
|
||||
### 特点
|
||||
- 基于 Golang 的核心,轻量高效,跨平台支持
|
||||
- 基于onebot11协议,可对接各种平台
|
||||
- 利用goja实现的js插件系统,高效灵活的插件实现
|
||||
- 定时任务、API事件响应等多种触发方式,满足各种需求
|
||||
- 同时支持webUI和Terminal交互,方便开发调试和维护管理
|
||||
- 支持多用户系统,灵活管理用户权限,高效资源共享,一个核心运行多个bot
|
||||
|
||||
---
|
||||
|
||||
TODO:
|
||||
- [ ] 底层框架
|
||||
- [x] 单协议通信
|
||||
- [ ] 文件资源管理
|
||||
- [ ] 多用户系统
|
||||
- [ ] 数据库管理
|
||||
- [ ] 日志输出
|
||||
- [ ] 配置文件
|
||||
- [ ] 插件管理
|
||||
- [x] 基础事件处理
|
||||
- [ ] 指令管理
|
||||
- [ ] 定时任务管理
|
||||
- [ ] API管理
|
||||
- [ ] web ui
|
||||
- [ ] 文档编写
|
||||
- [ ] 手册编写
|
||||
|
||||
---
|
||||
|
||||
# 项目依赖与致谢
|
||||
|
||||
@ -30,14 +48,19 @@ WIND(全称:WIND is not dice)是一个基于 Go 语言开发的bot框架
|
||||
## 1. goja
|
||||
- **库名称**:goja
|
||||
- **仓库地址**:[https://github.com/dop251/goja](https://github.com/dop251/goja)
|
||||
- **用途说明**:goja 作为一款强大的 JavaScript 解释器,在本项目中承担了处理动态的 JavaScript 脚本逻辑,为项目提供了灵活的脚本扩展能力,使得我们能够在 Go 项目中嵌入 JavaScript 代码来实现一些特定的业务规则处理等功能。它极大地丰富了项目的功能和灵活性,让我们能够更高效地开发出具有特色的功能模块。
|
||||
- **用途说明**:goja 作为一款强大的 JavaScript 解释器,在本项目中承担了处理动态的 JavaScript 脚本逻辑,为项目提供了灵活的脚本扩展能力,使得我们能够在项目中实现js插件的功能。它极大地丰富了项目的功能和灵活性,让跨平台的插件开发变得更加容易。
|
||||
|
||||
## 2. gocron
|
||||
- **库名称**:gocron
|
||||
- **仓库地址**:[https://github.com/go-co-op/gocron](https://github.com/go-co-op/gocron)
|
||||
- **用途说明**:gocron 是一个出色的任务调度库。在本项目里,它被用于[详细的任务调度应用场景,比如定期执行数据同步任务、定时清理临时文件或缓存数据等],确保了项目中的各种定时任务能够精准、可靠地执行。其简洁易用的 API 设计大大降低了我们实现复杂任务调度逻辑的难度,为项目的稳定运行提供了有力保障。
|
||||
- **用途说明**:gocron 是一个出色的任务调度库。在本项目里,它被用作定时任务的调度器,确保了项目中的各种定时任务能够精准、可靠地执行。其简洁易用的 API 设计大大降低了我们实现复杂任务调度逻辑的难度,为项目的稳定运行提供了有力保障。
|
||||
|
||||
非常感谢 `goja` 和 `gocron` 项目团队的开源贡献,使得我们的项目开发能够借助这些优秀的工具快速推进,为用户带来更好的体验。
|
||||
## 3. hertz
|
||||
- **库名称**:hertz
|
||||
- **仓库地址**:[https://github.com/cloudwego/hertz](https://github.com/cloudwego/hertz)
|
||||
- **用途说明**:hertz 是一个基于 Go 语言开发的高性能 HTTP 路由器。在本项目中,它被用作项目的 HTTP 服务器,为项目提供了快速、高效的 HTTP 请求处理能力。让我们能够灵活地对 HTTP 请求进行处理。
|
||||
|
||||
非常感谢以上项目团队的开源贡献,使得我们的项目开发能够借助这些优秀的工具快速推进,为用户带来更好的体验。
|
||||
|
||||
---
|
||||
后面没有了,开发者很懒,什么都没写。
|
@ -1,10 +1,28 @@
|
||||
package typed
|
||||
|
||||
import "ProjectWIND/wba"
|
||||
|
||||
type CoreConfigInfo struct {
|
||||
CoreName string `json:"core_name"`
|
||||
ProtocolAddr string `json:"protocol_addr"`
|
||||
Token string `json:"token"`
|
||||
WebUIPort uint16 `json:"webui_port"`
|
||||
PasswordHash string `json:"password_hash"`
|
||||
ServiceName string `json:"service_name"`
|
||||
CoreName string `json:"core_name"`
|
||||
Protocol Protocol `json:"protocol"`
|
||||
WebUIPort uint16 `json:"webui_port"`
|
||||
PasswordHash string `json:"password_hash"`
|
||||
ServiceName string `json:"service_name"`
|
||||
}
|
||||
|
||||
type Protocol struct {
|
||||
Name string `json:"protocol_name"`
|
||||
Platform string `json:"protocol_platform"`
|
||||
Addr string `json:"protocol_addr"`
|
||||
Token string `json:"token"`
|
||||
Enable bool `json:"enable"`
|
||||
}
|
||||
|
||||
type SessionWorkSpace struct {
|
||||
SessionId string `json:"session_id"`
|
||||
Rule string `json:"rule"`
|
||||
Enable bool `json:"enable"`
|
||||
AppEnable map[wba.AppKey]bool `json:"app_enable"`
|
||||
CmdEnable map[string]bool `json:"cmd_enable"`
|
||||
WorkLevel int32 `json:"work_level"`
|
||||
}
|
||||
|
158
utils.go
158
utils.go
@ -19,11 +19,11 @@ func initCore() string {
|
||||
log.SetFlags(log.Ldate | log.Ltime)
|
||||
log.SetPrefix("[WIND] ")
|
||||
|
||||
LOG.INFO("正在初始化WIND配置文件...")
|
||||
LOG.Info("正在初始化WIND配置文件...")
|
||||
|
||||
err := checkAndUpdateConfig("./data/core.json")
|
||||
if err != nil {
|
||||
LOG.FATAL("初始化时,加载配置文件 ./data/core.json 失败: %v", err)
|
||||
LOG.Fatal("初始化时,加载配置文件 ./data/core.json 失败: %v", err)
|
||||
}
|
||||
// 创建日志文件
|
||||
logFile := fmt.Sprintf("./data/log/WIND_CORE_%s.log", time.Now().Format("20060102150405"))
|
||||
@ -31,30 +31,30 @@ func initCore() string {
|
||||
if os.IsNotExist(err) {
|
||||
file, err := os.Create(logFile)
|
||||
if err != nil {
|
||||
LOG.FATAL("初始化时,创建日志文件失败: %v", err)
|
||||
LOG.Fatal("初始化时,创建日志文件失败: %v", err)
|
||||
}
|
||||
defer func(file *os.File) {
|
||||
err := file.Close()
|
||||
if err != nil {
|
||||
LOG.FATAL("无法关闭日志文件: %v", err)
|
||||
LOG.Fatal("无法关闭日志文件: %v", err)
|
||||
}
|
||||
}(file)
|
||||
}
|
||||
|
||||
file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
||||
if err != nil {
|
||||
LOG.FATAL("初始化时,无法打开日志文件: %v", err)
|
||||
LOG.Fatal("初始化时,无法打开日志文件: %v", err)
|
||||
}
|
||||
defer func(file *os.File) {
|
||||
err := file.Close()
|
||||
if err != nil {
|
||||
LOG.FATAL("无法关闭日志文件: %v", err)
|
||||
LOG.Fatal("无法关闭日志文件: %v", err)
|
||||
}
|
||||
}(file)
|
||||
|
||||
// 设置日志输出到文件
|
||||
log.SetOutput(io.MultiWriter(os.Stdout, file))
|
||||
LOG.INFO("WIND配置文件初始化完成!")
|
||||
LOG.Info("WIND配置文件初始化完成!")
|
||||
return logFile
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ func checkAndUpdateConfig(configPath string) error {
|
||||
// 如果不存在,则创建该文件夹
|
||||
err := os.Mkdir("./data/", 0755)
|
||||
if err != nil {
|
||||
LOG.FATAL("初始化时,创建data文件夹失败: %v", err)
|
||||
LOG.Fatal("初始化时,创建data文件夹失败: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,12 +73,12 @@ func checkAndUpdateConfig(configPath string) error {
|
||||
// 如果不存在,则创建该文件
|
||||
file, err := os.Create("./data/core.json")
|
||||
if err != nil {
|
||||
LOG.FATAL("初始化时,创建 ./data/core.json 配置文件失败: %v", err)
|
||||
LOG.Fatal("初始化时,创建 ./data/core.json 配置文件失败: %v", err)
|
||||
}
|
||||
defer func(file *os.File) {
|
||||
err := file.Close()
|
||||
if err != nil {
|
||||
LOG.FATAL("关闭 ./data/core.json 配置文件失败: %v", err)
|
||||
LOG.Fatal("关闭 ./data/core.json 配置文件失败: %v", err)
|
||||
}
|
||||
}(file)
|
||||
}
|
||||
@ -86,11 +86,17 @@ func checkAndUpdateConfig(configPath string) error {
|
||||
// 检查并更新配置文件
|
||||
var coreConfig typed.CoreConfigInfo
|
||||
|
||||
// 定义默认配置
|
||||
var defaultProtocol typed.Protocol
|
||||
defaultProtocol.Name = "EXAMPLE"
|
||||
defaultProtocol.Platform = "在这里输入协议平台"
|
||||
defaultProtocol.Addr = "在这里输入协议地址,如'ws://127.0.0.1:8080'"
|
||||
defaultProtocol.Token = "在这里输入协议的Token"
|
||||
defaultProtocol.Enable = true
|
||||
|
||||
var defaultConfig typed.CoreConfigInfo
|
||||
defaultConfig.CoreName = "windCore"
|
||||
defaultConfig.WebUIPort = 3211
|
||||
defaultConfig.ProtocolAddr = ""
|
||||
defaultConfig.Protocol = defaultProtocol
|
||||
defaultConfig.ServiceName = "wind"
|
||||
// 读取配置文件
|
||||
file, err := os.Open(configPath)
|
||||
@ -100,7 +106,7 @@ func checkAndUpdateConfig(configPath string) error {
|
||||
defer func(file *os.File) {
|
||||
err := file.Close()
|
||||
if err != nil {
|
||||
LOG.FATAL("无法关闭配置文件 ./data/core.json: %v", err)
|
||||
LOG.Fatal("无法关闭配置文件 ./data/core.json: %v", err)
|
||||
}
|
||||
}(file)
|
||||
|
||||
@ -114,8 +120,8 @@ func checkAndUpdateConfig(configPath string) error {
|
||||
}
|
||||
|
||||
// 检查并更新配置
|
||||
if coreConfig.ProtocolAddr == "" {
|
||||
coreConfig.ProtocolAddr = defaultConfig.ProtocolAddr
|
||||
if coreConfig.Protocol == (typed.Protocol{}) {
|
||||
coreConfig.Protocol = defaultConfig.Protocol
|
||||
}
|
||||
if coreConfig.WebUIPort == 0 {
|
||||
coreConfig.WebUIPort = defaultConfig.WebUIPort
|
||||
@ -129,9 +135,9 @@ func checkAndUpdateConfig(configPath string) error {
|
||||
if coreConfig.PasswordHash == "" {
|
||||
coreConfig.PasswordHash = ""
|
||||
}
|
||||
if coreConfig.Token == "" {
|
||||
coreConfig.Token = ""
|
||||
}
|
||||
//if coreConfig.Token == "" {
|
||||
// coreConfig.Token = ""
|
||||
//}
|
||||
|
||||
formattedJSON, err := json.MarshalIndent(coreConfig, "", " ")
|
||||
if err != nil {
|
||||
@ -141,19 +147,19 @@ func checkAndUpdateConfig(configPath string) error {
|
||||
// 将格式化后的JSON字符串写入文件
|
||||
file, err = os.Create("./data/core.json")
|
||||
if err != nil {
|
||||
LOG.FATAL("初始化时,创建 ./data/core.json 配置文件失败: %v", err)
|
||||
LOG.Fatal("初始化时,创建 ./data/core.json 配置文件失败: %v", err)
|
||||
return err
|
||||
}
|
||||
defer func(file *os.File) {
|
||||
err := file.Close()
|
||||
if err != nil {
|
||||
LOG.FATAL("无法关闭配置文件 ./data/core.json: %v", err)
|
||||
LOG.Fatal("无法关闭配置文件 ./data/core.json: %v", err)
|
||||
}
|
||||
}(file)
|
||||
|
||||
_, err = file.Write(formattedJSON)
|
||||
if err != nil {
|
||||
LOG.FATAL("初始化时,写入 ./data/core.json 配置文件失败: %v", err)
|
||||
LOG.Fatal("初始化时,写入 ./data/core.json 配置文件失败: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
@ -170,42 +176,42 @@ func checkAndUpdateConfig(configPath string) error {
|
||||
|
||||
err = checkDataFolderExistence("./data/app/")
|
||||
if err != nil {
|
||||
LOG.FATAL("创建应用文件夹 ./data/app/ 失败: %v", err)
|
||||
LOG.Fatal("创建应用文件夹 ./data/app/ 失败: %v", err)
|
||||
return err
|
||||
}
|
||||
err = checkDataFolderExistence("./data/images/")
|
||||
if err != nil {
|
||||
LOG.FATAL("创建图片文件夹 ./data/images/ 失败: %v", err)
|
||||
LOG.Fatal("创建图片文件夹 ./data/images/ 失败: %v", err)
|
||||
return err
|
||||
}
|
||||
err = checkDataFolderExistence("./data/files/")
|
||||
if err != nil {
|
||||
LOG.FATAL("创建文件文件夹 ./data/files/ 失败: %v", err)
|
||||
LOG.Fatal("创建文件文件夹 ./data/files/ 失败: %v", err)
|
||||
return err
|
||||
}
|
||||
err = checkDataFolderExistence("./data/videos/")
|
||||
if err != nil {
|
||||
LOG.FATAL("创建视频文件夹 ./data/videos/ 失败: %v", err)
|
||||
LOG.Fatal("创建视频文件夹 ./data/videos/ 失败: %v", err)
|
||||
return err
|
||||
}
|
||||
err = checkDataFolderExistence("./data/audios/")
|
||||
if err != nil {
|
||||
LOG.FATAL("创建音频文件夹 ./data/audios/ 失败: %v", err)
|
||||
LOG.Fatal("创建音频文件夹 ./data/audios/ 失败: %v", err)
|
||||
return err
|
||||
}
|
||||
err = checkDataFolderExistence("./data/database/")
|
||||
if err != nil {
|
||||
LOG.FATAL("创建数据库文件夹 ./data/database/ 失败: %v", err)
|
||||
LOG.Fatal("创建数据库文件夹 ./data/database/ 失败: %v", err)
|
||||
return err
|
||||
}
|
||||
err = checkDataFolderExistence("./data/log/")
|
||||
if err != nil {
|
||||
LOG.FATAL("创建日志文件夹 ./data/log/ 失败: %v", err)
|
||||
LOG.Fatal("创建日志文件夹 ./data/log/ 失败: %v", err)
|
||||
return err
|
||||
}
|
||||
err = checkDataFolderExistence("./data/app/configs/")
|
||||
if err != nil {
|
||||
LOG.FATAL("创建应用配置文件夹 ./data/app/configs/ 失败: %v", err)
|
||||
LOG.Fatal("创建应用配置文件夹 ./data/app/configs/ 失败: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -221,18 +227,18 @@ func startWebUI() {
|
||||
// 打开日志文件
|
||||
file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
||||
if err != nil {
|
||||
LOG.FATAL("打开日志文件失败: %v", err)
|
||||
LOG.Fatal("打开日志文件失败: %v", err)
|
||||
}
|
||||
defer func(file *os.File) {
|
||||
err := file.Close()
|
||||
if err != nil {
|
||||
LOG.FATAL("无法关闭日志文件: %v", err)
|
||||
LOG.Fatal("无法关闭日志文件: %v", err)
|
||||
}
|
||||
}(file)
|
||||
// 设置日志输出到文件
|
||||
log.SetOutput(io.MultiWriter(os.Stdout, file))
|
||||
|
||||
LOG.INFO("正在启动WIND核心服务...")
|
||||
LOG.Info("正在启动WIND核心服务...")
|
||||
// 启动 WebSocket 处理程序
|
||||
|
||||
//TODO: 这里要添加webUI的启动代码
|
||||
@ -248,17 +254,18 @@ func registerService() {
|
||||
// 打开日志文件
|
||||
file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
||||
if err != nil {
|
||||
LOG.FATAL("无法打开日志文件: %v", err)
|
||||
LOG.Fatal("无法打开日志文件: %v", err)
|
||||
}
|
||||
defer func(file *os.File) {
|
||||
err := file.Close()
|
||||
if err != nil {
|
||||
LOG.FATAL("无法关闭日志文件: %v", err)
|
||||
LOG.Fatal("无法关闭日志文件: %v", err)
|
||||
}
|
||||
}(file)
|
||||
// 设置日志输出到文件
|
||||
log.SetOutput(io.MultiWriter(os.Stdout, file))
|
||||
//TODO: 这里要添加注册服务的代码
|
||||
//在/etc/systemd/system/下创建服务文件
|
||||
|
||||
}
|
||||
|
||||
func startProtocol() {
|
||||
@ -270,92 +277,71 @@ func startProtocol() {
|
||||
// 打开日志文件
|
||||
file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
||||
if err != nil {
|
||||
LOG.FATAL("无法打开日志文件: %v", err)
|
||||
LOG.Fatal("无法打开日志文件: %v", err)
|
||||
}
|
||||
defer func(file *os.File) {
|
||||
err := file.Close()
|
||||
if err != nil {
|
||||
LOG.FATAL("无法关闭日志文件: %v", err)
|
||||
LOG.Fatal("无法关闭日志文件: %v", err)
|
||||
}
|
||||
}(file)
|
||||
// 设置日志输出到文件
|
||||
log.SetOutput(io.MultiWriter(os.Stdout, file))
|
||||
ReloadApps()
|
||||
//从配置文件中读取配置信息
|
||||
LOG.INFO("正在启动WIND协议服务...")
|
||||
LOG.Info("正在启动WIND协议服务...")
|
||||
var config typed.CoreConfigInfo
|
||||
file, err = os.Open("./data/core.json")
|
||||
if err != nil {
|
||||
LOG.FATAL("无法打开配置文件 ./data/core.json: %v", err)
|
||||
LOG.Fatal("无法打开配置文件 ./data/core.json: %v", err)
|
||||
}
|
||||
defer func(file *os.File) {
|
||||
err := file.Close()
|
||||
if err != nil {
|
||||
LOG.FATAL("无法关闭配置文件 ./data/core.json: %v", err)
|
||||
LOG.Fatal("无法关闭配置文件 ./data/core.json: %v", err)
|
||||
}
|
||||
}(file)
|
||||
|
||||
decoder := json.NewDecoder(file)
|
||||
err = decoder.Decode(&config)
|
||||
if err != nil {
|
||||
LOG.FATAL("连接协议时,解析配置文件 ./data/core.json 失败: %v", err)
|
||||
LOG.Fatal("连接协议时,解析配置文件 ./data/core.json 失败: %v", err)
|
||||
}
|
||||
LOG.Info("正在启动WebSocket链接程序...")
|
||||
protocol := config.Protocol
|
||||
if protocol.Name == "EXAMPLE" {
|
||||
LOG.Warn("未找到协议配置信息")
|
||||
return
|
||||
}
|
||||
if protocol.Name == "" {
|
||||
LOG.Warn("连接协议 %s 时,协议名称为空", protocol.Name)
|
||||
return
|
||||
}
|
||||
//获取协议地址
|
||||
protocolAddr := config.ProtocolAddr
|
||||
//获取token
|
||||
token := config.Token
|
||||
//链接协议
|
||||
// 启动 WebSocket 处理程序
|
||||
LOG.INFO("正在启动WebSocket链接程序...")
|
||||
err = core.WebSocketHandler(protocolAddr, token)
|
||||
if err != nil {
|
||||
// 如果发生错误,记录错误并退出程序
|
||||
LOG.FATAL("连接协议时,启动 WebSocket 处理程序失败: %v", err)
|
||||
protocolAddr := protocol.Addr
|
||||
if protocolAddr == "" {
|
||||
LOG.Warn("连接协议 %s 时,协议地址为空", protocol.Name)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func AutoSave() {
|
||||
for {
|
||||
time.Sleep(time.Second * 60)
|
||||
LOG.INFO("自动保存")
|
||||
//TODO: 这里要添加自动保存的代码
|
||||
if protocol.Enable == false {
|
||||
LOG.Warn("连接协议 %s 时,协议已禁用", protocol.Name)
|
||||
return
|
||||
}
|
||||
// 启动 WebSocket 处理程序
|
||||
err = core.WebSocketHandler(protocol)
|
||||
if err != nil {
|
||||
LOG.Error("连接协议时 %s,启动 WebSocket 处理程序失败: %v", protocol.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
func ReloadApps() {
|
||||
LOG.INFO("正在重新加载应用...")
|
||||
LOG.Info("正在重新加载应用...")
|
||||
total, success := core.ReloadApps()
|
||||
LOG.INFO("应用重新加载完成,共加载%d个应用,成功加载%d个应用。", total, success)
|
||||
LOG.Info("应用重新加载完成,共加载%d个应用,成功加载%d个应用。", total, success)
|
||||
}
|
||||
|
||||
func startDatabase() {
|
||||
go database.Start()
|
||||
time.Sleep(time.Second * 1)
|
||||
// 读写测试
|
||||
// for i := 0; i < 10; i++ {
|
||||
// data, ok := database.Get("user", "test", "test"+fmt.Sprintf("%d", i))
|
||||
// if !ok {
|
||||
// LOG.ERROR("Failed to get data from database")
|
||||
// continue
|
||||
// }
|
||||
// LOG.INFO("Get data from database: %v", data)
|
||||
// time.Sleep(time.Second * 1)
|
||||
// }
|
||||
// time.Sleep(time.Second * 1)
|
||||
// for i := 0; i < 10; i++ {
|
||||
// database.Set("user", "test", "test"+fmt.Sprintf("%d", i), "test"+fmt.Sprintf("%d", 1000+i))
|
||||
// time.Sleep(time.Second * 1)
|
||||
// }
|
||||
// time.Sleep(time.Second * 1)
|
||||
// for i := 0; i < 10; i++ {
|
||||
// data, ok := database.Get("user", "test", "test"+fmt.Sprintf("%d", i))
|
||||
// if !ok {
|
||||
// LOG.ERROR("Failed to get data from database")
|
||||
// continue
|
||||
// }
|
||||
// LOG.INFO("Get data from database: %v", data)
|
||||
// time.Sleep(time.Second * 1)
|
||||
// }
|
||||
select {}
|
||||
}
|
||||
|
47
wba/abandoned.go
Normal file
47
wba/abandoned.go
Normal file
@ -0,0 +1,47 @@
|
||||
package wba
|
||||
|
||||
//type APP interface {
|
||||
// Get() AppInfo
|
||||
// Init(Wba interface{}) error
|
||||
// //Init(WspApi WindStandardProtocolAPI, WsdApi WindStandardDataBaseAPI, WstApi WindStandardTools) error
|
||||
// //InitWSD(api WindStandardDataBaseAPI) error
|
||||
//}
|
||||
|
||||
//func (ai AppInfo) Get() AppInfo {
|
||||
// return ai
|
||||
//}
|
||||
//
|
||||
//func (ai AppInfo) Init(Wba interface{}) error {
|
||||
// WBA = Wba.(WindStandardTools)
|
||||
// return nil
|
||||
//}
|
||||
|
||||
//func (ai *AppInfo) Init(WspApi WindStandardProtocolAPI, WsdApi WindStandardDataBaseAPI, WstApi WindStandardTools) error {
|
||||
// WSP = WspApi
|
||||
// WSD = WsdApi
|
||||
// WST = WstApi
|
||||
// return nil
|
||||
//}
|
||||
|
||||
//func (ai *AppInfo) InitWSD(api WindStandardDataBaseAPI) error {
|
||||
// WSD = api
|
||||
// return nil
|
||||
//}
|
||||
|
||||
//func WithName(name string) AppInfoOption {
|
||||
// return func(ei *AppInfo) {
|
||||
// ei.AppKey.Name = name
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//func WithVersion(version string) AppInfoOption {
|
||||
// return func(ei *AppInfo) {
|
||||
// ei.AppKey.Version = version
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//func WithAuthor(author string) AppInfoOption {
|
||||
// return func(ei *AppInfo) {
|
||||
// ei.Author = author
|
||||
// }
|
||||
//}
|
103
wba/api_request_response.go
Normal file
103
wba/api_request_response.go
Normal file
@ -0,0 +1,103 @@
|
||||
package wba
|
||||
|
||||
type APIRequestInfo struct {
|
||||
Action string `json:"action,omitempty"`
|
||||
Params ParamsInfo `json:"params"`
|
||||
Echo string `json:"echo,omitempty"`
|
||||
}
|
||||
|
||||
type APIResponseInfo struct {
|
||||
Status string `json:"status,omitempty"`
|
||||
Retcode int64 `json:"retcode,omitempty"`
|
||||
Data ResponseDataInfo `json:"data,omitempty"`
|
||||
Echo string `json:"echo,omitempty"`
|
||||
}
|
||||
|
||||
type APIResponseListInfo struct {
|
||||
Status string `json:"status,omitempty"`
|
||||
Retcode int64 `json:"retcode,omitempty"`
|
||||
Data []ResponseDataInfo `json:"data,omitempty"`
|
||||
Echo string `json:"echo,omitempty"`
|
||||
}
|
||||
|
||||
type ResponseDataInfo struct {
|
||||
UserId int64 `json:"user_id,omitempty"`
|
||||
Nickname string `json:"nickname,omitempty"`
|
||||
Sex string `json:"sex,omitempty"`
|
||||
Age int32 `json:"age,omitempty"`
|
||||
Remark string `json:"remark,omitempty"`
|
||||
GroupId int64 `json:"group_id,omitempty"`
|
||||
GroupName string `json:"group_name,omitempty"`
|
||||
MemberCount int32 `json:"member_count,omitempty"`
|
||||
MaxMemberCount int32 `json:"max_member_count,omitempty"`
|
||||
Card string `json:"card,omitempty"`
|
||||
Area string `json:"area,omitempty"`
|
||||
JoinTime int32 `json:"join_time,omitempty"`
|
||||
LastSentTime int32 `json:"last_sent_time,omitempty"`
|
||||
Level string `json:"level,omitempty"`
|
||||
Role string `json:"role,omitempty"`
|
||||
Unfriendly bool `json:"unfriendly,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
TitleExpireTime int32 `json:"title_expire_time,omitempty"`
|
||||
CardChangeable bool `json:"card_changeable,omitempty"`
|
||||
CurrentTalkative CurrentTalkativeInfo `json:"current_talkative,omitempty"`
|
||||
TalkativeList []CurrentTalkativeInfo `json:"talkative_list,omitempty"`
|
||||
PerformerList []HonorInfo `json:"performer_list,omitempty"`
|
||||
LegendList []HonorInfo `json:"legend_list,omitempty"`
|
||||
StrongNewbieList []HonorInfo `json:"strong_newbie_list,omitempty"`
|
||||
EmoticonList []HonorInfo `json:"emoticon_list,omitempty"`
|
||||
Cookies string `json:"cookies,omitempty"`
|
||||
Token string `json:"token,omitempty"`
|
||||
CsrfToken string `json:"csrf_token,omitempty"`
|
||||
File string `json:"file,omitempty"`
|
||||
OutFormat string `json:"out_format,omitempty"`
|
||||
Yes bool `json:"yes,omitempty"`
|
||||
Online bool `json:"online,omitempty"`
|
||||
Good bool `json:"good,omitempty"`
|
||||
AppName string `json:"app_name,omitempty"`
|
||||
AppVersion string `json:"app_version,omitempty"`
|
||||
ProtocolVersion string `json:"protocol_version,omitempty"`
|
||||
Time int64 `json:"time,omitempty"`
|
||||
MessageType string `json:"message_type,omitempty"`
|
||||
MessageId int32 `json:"message_id,omitempty"`
|
||||
RealId int32 `json:"real_id,omitempty"`
|
||||
Sender SenderInfo `json:"sender,omitempty"`
|
||||
Message []MessageDataInfo `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
type CurrentTalkativeInfo struct {
|
||||
UserId int64 `json:"user_id,omitempty"`
|
||||
Nickname string `json:"nickname,omitempty"`
|
||||
Avatar string `json:"avatar,omitempty"`
|
||||
DayCount int32 `json:"day_count,omitempty"`
|
||||
}
|
||||
|
||||
type HonorInfo struct {
|
||||
UserId int64 `json:"user_id,omitempty"`
|
||||
Nickname string `json:"nickname,omitempty"`
|
||||
Avatar string `json:"avatar,omitempty"`
|
||||
Description string `json:"Description,omitempty"`
|
||||
}
|
||||
|
||||
// SegmentInfo 消息段
|
||||
type SegmentInfo struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Data SegmentDataInfo `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type SegmentDataInfo struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
QQ string `json:"qq,omitempty"`
|
||||
Id int64 `json:"id,omitempty"`
|
||||
UserId int64 `json:"user_id,omitempty"`
|
||||
Nickname string `json:"nickname,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
Url string `json:"url,omitempty"`
|
||||
Lat string `json:"lat,omitempty"`
|
||||
Lon string `json:"lon,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Audio string `json:"audio,omitempty"`
|
||||
Image string `json:"image,omitempty"`
|
||||
Video string `json:"video,omitempty"`
|
||||
Data string `json:"data,omitempty"`
|
||||
}
|
206
wba/app.go
Normal file
206
wba/app.go
Normal file
@ -0,0 +1,206 @@
|
||||
package wba
|
||||
|
||||
import "strings"
|
||||
|
||||
type AppInfo struct {
|
||||
AppKey AppKey
|
||||
Author string
|
||||
Description string
|
||||
Homepage string
|
||||
License string
|
||||
CmdMap map[string]Cmd
|
||||
MessageEventHandler func(msg MessageEventInfo)
|
||||
NoticeEventHandler func(msg NoticeEventInfo)
|
||||
RequestEventHandler func(msg RequestEventInfo)
|
||||
MetaEventHandler func(msg MetaEventInfo)
|
||||
ScheduledTasks map[string]ScheduledTaskInfo
|
||||
API map[string]interface{}
|
||||
}
|
||||
|
||||
func (ai *AppInfo) AddCmd(name string, cmd Cmd) {
|
||||
ai.CmdMap[name] = cmd
|
||||
}
|
||||
|
||||
func (ai *AppInfo) AddNoticeEventHandler(ScheduledTask ScheduledTaskInfo) {
|
||||
ai.ScheduledTasks[ScheduledTask.Name] = ScheduledTask
|
||||
}
|
||||
|
||||
func (ai *AppInfo) AddScheduledTask(task ScheduledTaskInfo) {
|
||||
ai.ScheduledTasks[task.Name] = task
|
||||
}
|
||||
|
||||
type AppInfoOption func(ei *AppInfo)
|
||||
|
||||
func WithDescription(description string) AppInfoOption {
|
||||
return func(ei *AppInfo) {
|
||||
ei.Description = description
|
||||
}
|
||||
}
|
||||
|
||||
func WithWebUrl(webUrl string) AppInfoOption {
|
||||
return func(ei *AppInfo) {
|
||||
ei.Homepage = webUrl
|
||||
}
|
||||
}
|
||||
|
||||
func WithLicense(license string) AppInfoOption {
|
||||
return func(ei *AppInfo) {
|
||||
ei.License = license
|
||||
}
|
||||
}
|
||||
|
||||
func WithSelector(level uint8, selector string, option string) AppInfoOption {
|
||||
return func(ei *AppInfo) {
|
||||
ei.AppKey.Level = level
|
||||
ei.AppKey.Option = option
|
||||
ei.AppKey.Selector = selector
|
||||
}
|
||||
}
|
||||
|
||||
func WithLevel(level uint8) AppInfoOption {
|
||||
if level < 1 {
|
||||
level = 1
|
||||
}
|
||||
return func(ei *AppInfo) {
|
||||
ei.AppKey.Level = level
|
||||
}
|
||||
}
|
||||
|
||||
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{
|
||||
Name: name,
|
||||
Version: version,
|
||||
Level: 2,
|
||||
Selector: name,
|
||||
Option: name,
|
||||
},
|
||||
Author: author,
|
||||
Description: "A simple and easy-to-use bot framework",
|
||||
Homepage: "https://github.com/Sheyiyuan/wind_app_model",
|
||||
License: "MIT",
|
||||
CmdMap: make(map[string]Cmd),
|
||||
ScheduledTasks: map[string]ScheduledTaskInfo{},
|
||||
API: map[string]interface{}{},
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
func (ai *AppInfo) NewCmd(name string, description string, solve func(args []string, msg MessageEventInfo)) Cmd {
|
||||
return Cmd{
|
||||
Name: name,
|
||||
Desc: description,
|
||||
Solve: solve,
|
||||
AppKey: ai.AppKey,
|
||||
}
|
||||
}
|
||||
|
||||
func (ai *AppInfo) NewScheduledTask(name string, description string, cron string, task func()) ScheduledTaskInfo {
|
||||
return ScheduledTaskInfo{
|
||||
Name: name,
|
||||
Desc: description,
|
||||
Cron: cron,
|
||||
Task: task,
|
||||
}
|
||||
}
|
||||
|
||||
type Cmd struct {
|
||||
Name string
|
||||
Desc string
|
||||
Solve func(args []string, msg MessageEventInfo)
|
||||
AppKey AppKey
|
||||
}
|
||||
|
||||
type ScheduledTaskInfo struct {
|
||||
Name string `json:"Name,omitempty"`
|
||||
Desc string `json:"desc,omitempty"`
|
||||
Task func() `json:"task,omitempty"`
|
||||
Cron string `json:"cron,omitempty"`
|
||||
}
|
||||
|
||||
type AppKey struct {
|
||||
Name string `json:"name"`
|
||||
Level Priority `json:"level"`
|
||||
Version string `json:"version"`
|
||||
Selector SelectorLabel `json:"selector"`
|
||||
Option OptionLabel `json:"option"`
|
||||
}
|
||||
|
||||
// Priority 是一个整数类型,用于表示命令的优先级。只能是不小于1且不大于4的整数。
|
||||
type Priority = uint8
|
||||
|
||||
// VersionLabel 是一个字符串类型,用于表示版本标签。
|
||||
type VersionLabel = string
|
||||
|
||||
// SelectorLabel 是一个字符串类型,用于表示选择器的标签。
|
||||
type SelectorLabel = string
|
||||
|
||||
// OptionLabel 是一个字符串类型,用于表示选择器选项的标签。
|
||||
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
|
||||
FixVersion uint8
|
||||
}
|
167
wba/event.go
Normal file
167
wba/event.go
Normal file
@ -0,0 +1,167 @@
|
||||
package wba
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// event.go 这里定义协议事件的结构体
|
||||
|
||||
// MessageEventInfo 消息事件结构体
|
||||
type MessageEventInfo struct {
|
||||
// Time 事件发生的时间戳
|
||||
Time int64 `json:"time,omitempty"`
|
||||
// SelfId 机器人的用户 ID
|
||||
SelfId int64 `json:"self_id,omitempty"`
|
||||
PostType string `json:"post_type,omitempty"`
|
||||
MessageType string `json:"message_type,omitempty"`
|
||||
SubType string `json:"sub_type,omitempty"`
|
||||
MessageId int32 `json:"message_id,omitempty"`
|
||||
GroupId int64 `json:"group_id,omitempty"`
|
||||
UserId int64 `json:"user_id,omitempty"`
|
||||
Anonymous AnonymousInfo `json:"anonymous"`
|
||||
Message []MessageInfo `json:"message,omitempty"`
|
||||
RawMessage string `json:"raw_message,omitempty"`
|
||||
Font int32 `json:"font,omitempty"`
|
||||
Sender SenderInfo `json:"sender"`
|
||||
}
|
||||
|
||||
func (msg *MessageEventInfo) GetAt() []string {
|
||||
var at []string
|
||||
for _, v := range msg.Message {
|
||||
if v.Type == "at" {
|
||||
at = append(at, v.Data.Qq)
|
||||
}
|
||||
}
|
||||
return at
|
||||
}
|
||||
|
||||
func (msg *MessageEventInfo) GetText() string {
|
||||
var text string
|
||||
for _, v := range msg.Message {
|
||||
if v.Type == "text" {
|
||||
text += v.Data.Text
|
||||
}
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
func (msg *MessageEventInfo) JsonMarshal() string {
|
||||
jsonData, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(jsonData)
|
||||
}
|
||||
|
||||
type NoticeEventInfo struct {
|
||||
Time int64 `json:"time,omitempty"`
|
||||
SelfId int64 `json:"self_id,omitempty"`
|
||||
PostType string `json:"post_type,omitempty"`
|
||||
NoticeType string `json:"notice_type,omitempty"`
|
||||
GroupId int64 `json:"group_id,omitempty"`
|
||||
UserId int64 `json:"user_id,omitempty"`
|
||||
File FileInfo `json:"file,omitempty"`
|
||||
SubType string `json:"sub_type,omitempty"`
|
||||
OperatorId int64 `json:"operator_id,omitempty"`
|
||||
Duration int64 `json:"duration,omitempty"`
|
||||
MessageId int64 `json:"message,omitempty"`
|
||||
TargetId int64 `json:"target_id,omitempty"`
|
||||
HonorType string `json:"honor_type,omitempty"`
|
||||
}
|
||||
|
||||
type RequestEventInfo struct {
|
||||
Time int64 `json:"time,omitempty"`
|
||||
SelfId int64 `json:"self_id,omitempty"`
|
||||
PostType string `json:"post_type,omitempty"`
|
||||
RequestType string `json:"request_type,omitempty"`
|
||||
SubType string `json:"sub_type,omitempty"`
|
||||
UserId int64 `json:"user_id,omitempty"`
|
||||
Comment string `json:"comment,omitempty"`
|
||||
Flag string `json:"flag,omitempty"`
|
||||
GroupId int64 `json:"group_id,omitempty"`
|
||||
}
|
||||
|
||||
type MetaEventInfo struct {
|
||||
Time int64 `json:"time,omitempty"`
|
||||
SelfId int64 `json:"self_id,omitempty"`
|
||||
PostType string `json:"post_type,omitempty"`
|
||||
MetaEventType string `json:"meta_event_type,omitempty"`
|
||||
SubType string `json:"sub_type,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Interval int64 `json:"interval,omitempty"`
|
||||
}
|
||||
|
||||
type FileInfo struct {
|
||||
Id string `json:"id,omitempty"`
|
||||
Name string `json:"Name,omitempty"`
|
||||
Size int64 `json:"size,omitempty"`
|
||||
Busid int64 `json:"bucket,omitempty"`
|
||||
}
|
||||
|
||||
type SenderInfo struct {
|
||||
UserId int64 `json:"user_id,omitempty"`
|
||||
Nickname string `json:"nickname,omitempty"`
|
||||
Card string `json:"card,omitempty"`
|
||||
Sex string `json:"sex,omitempty"`
|
||||
Age int32 `json:"age,omitempty"`
|
||||
Area string `json:"area,omitempty"`
|
||||
Level string `json:"level,omitempty"`
|
||||
Role string `json:"role,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
}
|
||||
|
||||
type AnonymousInfo struct {
|
||||
Id string `json:"id,omitempty"`
|
||||
Name string `json:"Name,omitempty"`
|
||||
Flag string `json:"flag,omitempty"`
|
||||
}
|
||||
|
||||
type MessageInfo struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Data MessageDataInfo `json:"data"`
|
||||
}
|
||||
|
||||
type MessageDataInfo struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Text string `json:"text,omitempty"`
|
||||
Id string `json:"id,omitempty"`
|
||||
File string `json:"file,omitempty"`
|
||||
Url string `json:"url,omitempty"`
|
||||
Magic string `json:"magic,omitempty"`
|
||||
Qq string `json:"qq,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Content any `json:"content,omitempty"` // Content string or []MessageDataInfo
|
||||
Image string `json:"image,omitempty"`
|
||||
Audio string `json:"audio,omitempty"`
|
||||
Lat string `json:"lat,omitempty"`
|
||||
Lon string `json:"lon,omitempty"`
|
||||
Data string `json:"data,omitempty"`
|
||||
UserId int64 `json:"user_id,omitempty"`
|
||||
Nickname string `json:"name,omitempty"`
|
||||
}
|
||||
|
||||
type ParamsInfo struct {
|
||||
Message string `json:"message,omitempty"`
|
||||
UserId int64 `json:"user_id,omitempty"`
|
||||
GroupId int64 `json:"group_id,omitempty"`
|
||||
AutoEscape bool `json:"auto_escape,omitempty"`
|
||||
MessageId int32 `json:"message_id,omitempty"`
|
||||
Id string `json:"id,omitempty"`
|
||||
RejectAddRequest bool `json:"reject_add_request,omitempty"`
|
||||
Duration int32 `json:"duration,omitempty"`
|
||||
Enable bool `json:"enable,omitempty"`
|
||||
Card string `json:"card,omitempty"`
|
||||
GroupName string `json:"group_name,omitempty"`
|
||||
IsDismiss bool `json:"is_dismiss,omitempty"`
|
||||
SpecialTitle string `json:"special_title,omitempty"`
|
||||
Flag string `json:"flag,omitempty"`
|
||||
Approve bool `json:"approve,omitempty"`
|
||||
Remark string `json:"remark,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
SubType string `json:"sub_type,omitempty"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
NoCache bool `json:"no_cache,omitempty"`
|
||||
File string `json:"file,omitempty"`
|
||||
Times int `json:"times,omitempty"`
|
||||
Domain string `json:"domain,omitempty"`
|
||||
OutFormat string `json:"out_format,omitempty"`
|
||||
Delay int32 `json:"delay,omitempty"`
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
# WBA 文档
|
||||
|
||||
WBA是用于对接WIND核心和APP通信的接口,规定了应用结构规范,并提供了与wind核心交互的接口定义。
|
||||
WBA是用于对接Bot协议、WIND核心和APP通信的接口,规定了应用结构规范,并提供了与wind核心交互的接口定义。
|
||||
|
||||
## 目录
|
||||
- [1. 应用结构规范](#1-应用结构规范)
|
||||
|
360
wba/selector.go
Normal file
360
wba/selector.go
Normal 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
|
||||
}
|
425
wba/wind.go
425
wba/wind.go
@ -1,425 +0,0 @@
|
||||
package wba
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type APP interface {
|
||||
Get() AppInfo
|
||||
Init(api WindAPI) error
|
||||
}
|
||||
|
||||
type WindAPI interface {
|
||||
SendMsg(msg MessageEventInfo, message string, autoEscape bool)
|
||||
SendPrivateMsg(msg MessageEventInfo, message string, autoEscape bool)
|
||||
SendGroupMsg(msg MessageEventInfo, message string, autoEscape bool)
|
||||
DeleteMsg(msg MessageEventInfo)
|
||||
SendLike(userId int64, times int)
|
||||
SetGroupKick(groupId int64, userId int64, rejectAddRequest bool)
|
||||
SetGroupBan(groupId int64, userId int64, duration int32)
|
||||
SetGroupWholeBan(groupId int64, enable bool)
|
||||
SetGroupAdmin(groupId int64, userId int64, enable bool)
|
||||
SetGroupLeave(groupId int64, isDismiss bool)
|
||||
SetGroupCard(groupId int64, userId int64, card string)
|
||||
SetGroupName(groupId int64, groupName string)
|
||||
SetGroupSpecialTitle(groupId int64, userId int64, specialTitle string, duration int32)
|
||||
SetFriendAddRequest(flag string, approve bool, remark string)
|
||||
SetGroupAddRequest(flag string, subType string, approve bool, reason string)
|
||||
GetLoginInfo() APIResponseInfo
|
||||
GetVersionInfo() APIResponseInfo
|
||||
GetMsg(msgId int32) APIResponseInfo
|
||||
GetForwardMsg(msgId string) APIResponseInfo
|
||||
GetGroupList() APIResponseInfo
|
||||
GetGroupMemberList(groupId int64) APIResponseInfo
|
||||
GetGroupMemberInfo(groupId int64, userId int64, noCache bool) APIResponseInfo
|
||||
GetFriendList() APIResponseInfo
|
||||
GetStrangerInfo(userId int64, noCache bool) APIResponseInfo
|
||||
GetGroupInfo(groupId int64, noCache bool) APIResponseInfo
|
||||
GetGroupHonorInfo(groupId int64, Type string) APIResponseInfo
|
||||
GetStatus() APIResponseInfo
|
||||
GetCookies(domain string) APIResponseInfo
|
||||
GetCSRFToken() APIResponseInfo
|
||||
GetCredentials(domain string) APIResponseInfo
|
||||
GetImage(file string) APIResponseInfo
|
||||
GetRecord(file string, outFormat string) APIResponseInfo
|
||||
CanSendImage() APIResponseInfo
|
||||
CanSendRecord() APIResponseInfo
|
||||
SetRestart(delay int32)
|
||||
CleanCache()
|
||||
LogWith(level string, log string, args ...interface{})
|
||||
Log(log string, args ...interface{})
|
||||
}
|
||||
|
||||
type AppInfo struct {
|
||||
Name string
|
||||
Version string
|
||||
Author string
|
||||
Description string
|
||||
Namespace string
|
||||
Homepage string
|
||||
License string
|
||||
AppType string
|
||||
Rule string
|
||||
CmdMap map[string]Cmd
|
||||
MessageEventHandler func(msg MessageEventInfo)
|
||||
NoticeEventHandler func(msg NoticeEventInfo)
|
||||
RequestEventHandler func(msg RequestEventInfo)
|
||||
MetaEventHandler func(msg MetaEventInfo)
|
||||
ScheduledTasks map[string]ScheduledTaskInfo
|
||||
API map[string]interface{}
|
||||
}
|
||||
|
||||
func (ai AppInfo) Get() AppInfo {
|
||||
return ai
|
||||
}
|
||||
|
||||
func (ai *AppInfo) Init(api WindAPI) error {
|
||||
Wind = api
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ai *AppInfo) AddCmd(name string, cmd Cmd) {
|
||||
ai.CmdMap[name] = cmd
|
||||
}
|
||||
|
||||
func (ai *AppInfo) AddNoticeEventHandler(ScheduledTask ScheduledTaskInfo) {
|
||||
ai.ScheduledTasks[ScheduledTask.Name] = ScheduledTask
|
||||
}
|
||||
|
||||
type AppInfoOption func(ei *AppInfo)
|
||||
|
||||
func WithName(name string) AppInfoOption {
|
||||
return func(ei *AppInfo) {
|
||||
ei.Name = name
|
||||
}
|
||||
}
|
||||
|
||||
func WithVersion(version string) AppInfoOption {
|
||||
return func(ei *AppInfo) {
|
||||
ei.Version = version
|
||||
}
|
||||
}
|
||||
|
||||
func WithAuthor(author string) AppInfoOption {
|
||||
return func(ei *AppInfo) {
|
||||
ei.Author = author
|
||||
}
|
||||
}
|
||||
|
||||
func WithDescription(description string) AppInfoOption {
|
||||
return func(ei *AppInfo) {
|
||||
ei.Description = description
|
||||
}
|
||||
}
|
||||
|
||||
func WithNamespace(namespace string) AppInfoOption {
|
||||
return func(ei *AppInfo) {
|
||||
ei.Namespace = namespace
|
||||
}
|
||||
}
|
||||
|
||||
func WithWebUrl(webUrl string) AppInfoOption {
|
||||
return func(ei *AppInfo) {
|
||||
ei.Homepage = webUrl
|
||||
}
|
||||
}
|
||||
|
||||
func WithLicense(license string) AppInfoOption {
|
||||
return func(ei *AppInfo) {
|
||||
ei.License = license
|
||||
}
|
||||
}
|
||||
|
||||
func WithAppType(appType string) AppInfoOption {
|
||||
return func(ei *AppInfo) {
|
||||
ei.AppType = appType
|
||||
}
|
||||
}
|
||||
|
||||
func WithRule(rule string) AppInfoOption {
|
||||
return func(ei *AppInfo) {
|
||||
ei.Rule = fmt.Sprintf("rule_%s", rule)
|
||||
}
|
||||
}
|
||||
|
||||
func NewApp(opts ...AppInfoOption) AppInfo {
|
||||
Ext := AppInfo{
|
||||
Name: "Wind",
|
||||
Version: "v1.0.0",
|
||||
Author: "Wind",
|
||||
Description: "A simple and easy-to-use bot framework",
|
||||
Namespace: "PUBLIC",
|
||||
Homepage: "https://github.com/Sheyiyuan/wind_app_model",
|
||||
License: "MIT",
|
||||
AppType: "fun",
|
||||
Rule: "none",
|
||||
CmdMap: make(map[string]Cmd),
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(&Ext)
|
||||
}
|
||||
return Ext
|
||||
}
|
||||
|
||||
func NewCmd(name string, description string, solve func(args []string, msg MessageEventInfo)) Cmd {
|
||||
return Cmd{
|
||||
NAME: name,
|
||||
DESC: description,
|
||||
SOLVE: solve,
|
||||
}
|
||||
}
|
||||
|
||||
func NewScheduledTask(name string, description string, cron string, task func()) ScheduledTaskInfo {
|
||||
return ScheduledTaskInfo{
|
||||
Name: name,
|
||||
Desc: description,
|
||||
Cron: cron,
|
||||
Task: task,
|
||||
}
|
||||
}
|
||||
|
||||
type Cmd struct {
|
||||
NAME string
|
||||
DESC string
|
||||
SOLVE func(args []string, msg MessageEventInfo)
|
||||
}
|
||||
|
||||
type MessageEventInfo struct {
|
||||
Time int64 `json:"time,omitempty"`
|
||||
SelfId int64 `json:"self_id,omitempty"`
|
||||
PostType string `json:"post_type,omitempty"`
|
||||
MessageType string `json:"message_type,omitempty"`
|
||||
SubType string `json:"sub_type,omitempty"`
|
||||
MessageId int32 `json:"message_id,omitempty"`
|
||||
GroupId int64 `json:"group_id,omitempty"`
|
||||
UserId int64 `json:"user_id,omitempty"`
|
||||
Anonymous AnonymousInfo `json:"anonymous"`
|
||||
Message []MessageInfo `json:"message,omitempty"`
|
||||
RawMessage string `json:"raw_message,omitempty"`
|
||||
Font int32 `json:"font,omitempty"`
|
||||
Sender SenderInfo `json:"sender"`
|
||||
}
|
||||
|
||||
type NoticeEventInfo struct {
|
||||
Time int64 `json:"time,omitempty"`
|
||||
SelfId int64 `json:"self_id,omitempty"`
|
||||
PostType string `json:"post_type,omitempty"`
|
||||
NoticeType string `json:"notice_type,omitempty"`
|
||||
GroupId int64 `json:"group_id,omitempty"`
|
||||
UserId int64 `json:"user_id,omitempty"`
|
||||
File FileInfo `json:"file,omitempty"`
|
||||
SubType string `json:"sub_type,omitempty"`
|
||||
OperatorId int64 `json:"operator_id,omitempty"`
|
||||
Duration int64 `json:"duration,omitempty"`
|
||||
MessageId int64 `json:"message,omitempty"`
|
||||
TargetId int64 `json:"target_id,omitempty"`
|
||||
HonorType string `json:"honor_type,omitempty"`
|
||||
}
|
||||
|
||||
type RequestEventInfo struct {
|
||||
Time int64 `json:"time,omitempty"`
|
||||
SelfId int64 `json:"self_id,omitempty"`
|
||||
PostType string `json:"post_type,omitempty"`
|
||||
RequestType string `json:"request_type,omitempty"`
|
||||
SubType string `json:"sub_type,omitempty"`
|
||||
UserId int64 `json:"user_id,omitempty"`
|
||||
Comment string `json:"comment,omitempty"`
|
||||
Flag string `json:"flag,omitempty"`
|
||||
GroupId int64 `json:"group_id,omitempty"`
|
||||
}
|
||||
|
||||
type MetaEventInfo struct {
|
||||
Time int64 `json:"time,omitempty"`
|
||||
SelfId int64 `json:"self_id,omitempty"`
|
||||
PostType string `json:"post_type,omitempty"`
|
||||
MetaEventType string `json:"meta_event_type,omitempty"`
|
||||
SubType string `json:"sub_type,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Interval int64 `json:"interval,omitempty"`
|
||||
}
|
||||
|
||||
type FileInfo struct {
|
||||
Id string `json:"id,omitempty"`
|
||||
Name string `json:"Name,omitempty"`
|
||||
Size int64 `json:"size,omitempty"`
|
||||
Busid int64 `json:"bucket,omitempty"`
|
||||
}
|
||||
|
||||
type SenderInfo struct {
|
||||
UserId int64 `json:"user_id,omitempty"`
|
||||
Nickname string `json:"nickname,omitempty"`
|
||||
Card string `json:"card,omitempty"`
|
||||
Sex string `json:"sex,omitempty"`
|
||||
Age int32 `json:"age,omitempty"`
|
||||
Area string `json:"area,omitempty"`
|
||||
Level string `json:"level,omitempty"`
|
||||
Role string `json:"role,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
}
|
||||
|
||||
type AnonymousInfo struct {
|
||||
Id string `json:"id,omitempty"`
|
||||
Name string `json:"Name,omitempty"`
|
||||
Flag string `json:"flag,omitempty"`
|
||||
}
|
||||
|
||||
type MessageInfo struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Data MessageDataInfo `json:"data"`
|
||||
}
|
||||
|
||||
type MessageDataInfo struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Text string `json:"text,omitempty"`
|
||||
Id string `json:"id,omitempty"`
|
||||
File string `json:"file,omitempty"`
|
||||
Url string `json:"url,omitempty"`
|
||||
Magic string `json:"magic,omitempty"`
|
||||
Qq string `json:"qq,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
Image string `json:"image,omitempty"`
|
||||
Audio string `json:"audio,omitempty"`
|
||||
Lat string `json:"lat,omitempty"`
|
||||
Lon string `json:"lon,omitempty"`
|
||||
Data string `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type ParamsInfo struct {
|
||||
Message string `json:"message,omitempty"`
|
||||
UserId int64 `json:"user_id,omitempty"`
|
||||
GroupId int64 `json:"group_id,omitempty"`
|
||||
AutoEscape bool `json:"auto_escape,omitempty"`
|
||||
MessageId int32 `json:"message_id,omitempty"`
|
||||
Id string `json:"id,omitempty"`
|
||||
RejectAddRequest bool `json:"reject_add_request,omitempty"`
|
||||
Duration int32 `json:"duration,omitempty"`
|
||||
Enable bool `json:"enable,omitempty"`
|
||||
Card string `json:"card,omitempty"`
|
||||
GroupName string `json:"group_name,omitempty"`
|
||||
IsDismiss bool `json:"is_dismiss,omitempty"`
|
||||
SpecialTitle string `json:"special_title,omitempty"`
|
||||
Flag string `json:"flag,omitempty"`
|
||||
Approve bool `json:"approve,omitempty"`
|
||||
Remark string `json:"remark,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
SubType string `json:"sub_type,omitempty"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
NoCache bool `json:"no_cache,omitempty"`
|
||||
File string `json:"file,omitempty"`
|
||||
Times int `json:"times,omitempty"`
|
||||
Domain string `json:"domain,omitempty"`
|
||||
OutFormat string `json:"out_format,omitempty"`
|
||||
Delay int32 `json:"delay,omitempty"`
|
||||
}
|
||||
|
||||
type APIRequestInfo struct {
|
||||
Action string `json:"action,omitempty"`
|
||||
Params ParamsInfo `json:"params"`
|
||||
Echo string `json:"echo,omitempty"`
|
||||
}
|
||||
|
||||
type APIResponseInfo struct {
|
||||
Status string `json:"status,omitempty"`
|
||||
Retcode int64 `json:"retcode,omitempty"`
|
||||
Data ResponseDataInfo `json:"data,omitempty"`
|
||||
Echo string `json:"echo,omitempty"`
|
||||
}
|
||||
|
||||
type APIResponseListInfo struct {
|
||||
Status string `json:"status,omitempty"`
|
||||
Retcode int64 `json:"retcode,omitempty"`
|
||||
Data []ResponseDataInfo `json:"data,omitempty"`
|
||||
Echo string `json:"echo,omitempty"`
|
||||
}
|
||||
|
||||
type ResponseDataInfo struct {
|
||||
UserId int64 `json:"user_id,omitempty"`
|
||||
Nickname string `json:"nickname,omitempty"`
|
||||
Sex string `json:"sex,omitempty"`
|
||||
Age int32 `json:"age,omitempty"`
|
||||
Remark string `json:"remark,omitempty"`
|
||||
GroupId int64 `json:"group_id,omitempty"`
|
||||
GroupName string `json:"group_name,omitempty"`
|
||||
MemberCount int32 `json:"member_count,omitempty"`
|
||||
MaxMemberCount int32 `json:"max_member_count,omitempty"`
|
||||
Card string `json:"card,omitempty"`
|
||||
Area string `json:"area,omitempty"`
|
||||
JoinTime int32 `json:"join_time,omitempty"`
|
||||
LastSentTime int32 `json:"last_sent_time,omitempty"`
|
||||
Level string `json:"level,omitempty"`
|
||||
Role string `json:"role,omitempty"`
|
||||
Unfriendly bool `json:"unfriendly,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
TitleExpireTime int32 `json:"title_expire_time,omitempty"`
|
||||
CardChangeable bool `json:"card_changeable,omitempty"`
|
||||
CurrentTalkative CurrentTalkativeInfo `json:"current_talkative,omitempty"`
|
||||
TalkativeList []CurrentTalkativeInfo `json:"talkative_list,omitempty"`
|
||||
PerformerList []HonorInfo `json:"performer_list,omitempty"`
|
||||
LegendList []HonorInfo `json:"legend_list,omitempty"`
|
||||
StrongNewbieList []HonorInfo `json:"strong_newbie_list,omitempty"`
|
||||
EmoticonList []HonorInfo `json:"emoticon_list,omitempty"`
|
||||
Cookies string `json:"cookies,omitempty"`
|
||||
Token string `json:"token,omitempty"`
|
||||
CsrfToken string `json:"csrf_token,omitempty"`
|
||||
File string `json:"file,omitempty"`
|
||||
OutFormat string `json:"out_format,omitempty"`
|
||||
Yes bool `json:"yes,omitempty"`
|
||||
Online bool `json:"online,omitempty"`
|
||||
Good bool `json:"good,omitempty"`
|
||||
AppName string `json:"app_name,omitempty"`
|
||||
AppVersion string `json:"app_version,omitempty"`
|
||||
ProtocolVersion string `json:"protocol_version,omitempty"`
|
||||
Time int64 `json:"time,omitempty"`
|
||||
MessageType string `json:"message_type,omitempty"`
|
||||
MessageId int32 `json:"message_id,omitempty"`
|
||||
RealId int32 `json:"real_id,omitempty"`
|
||||
Sender SenderInfo `json:"sender,omitempty"`
|
||||
Message []MessageDataInfo `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
type CurrentTalkativeInfo struct {
|
||||
UserId int64 `json:"user_id,omitempty"`
|
||||
Nickname string `json:"nickname,omitempty"`
|
||||
Avatar string `json:"avatar,omitempty"`
|
||||
DayCount int32 `json:"day_count,omitempty"`
|
||||
}
|
||||
|
||||
type HonorInfo struct {
|
||||
UserId int64 `json:"user_id,omitempty"`
|
||||
Nickname string `json:"nickname,omitempty"`
|
||||
Avatar string `json:"avatar,omitempty"`
|
||||
Description string `json:"Description,omitempty"`
|
||||
}
|
||||
|
||||
// SegmentInfo 消息段
|
||||
type SegmentInfo struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Data SegmentDataInfo `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type SegmentDataInfo struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
QQ string `json:"qq,omitempty"`
|
||||
Id int64 `json:"id,omitempty"`
|
||||
UserId int64 `json:"user_id,omitempty"`
|
||||
Nickname string `json:"nickname,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
Url string `json:"url,omitempty"`
|
||||
Lat string `json:"lat,omitempty"`
|
||||
Lon string `json:"lon,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Audio string `json:"audio,omitempty"`
|
||||
Image string `json:"image,omitempty"`
|
||||
Video string `json:"video,omitempty"`
|
||||
Data string `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
type ScheduledTaskInfo struct {
|
||||
Name string `json:"Name,omitempty"`
|
||||
Desc string `json:"desc,omitempty"`
|
||||
Task func() `json:"task,omitempty"`
|
||||
Cron string `json:"cron,omitempty"`
|
||||
}
|
||||
|
||||
var Wind WindAPI
|
462
wba/wind_standard_protocol.go
Normal file
462
wba/wind_standard_protocol.go
Normal file
@ -0,0 +1,462 @@
|
||||
package wba
|
||||
|
||||
// WindStandardProtocolAPI Wind标准协议API,提供了onebot11标准中的API接口。
|
||||
type WindStandardProtocolAPI interface {
|
||||
// UnsafelySendMsg [不安全][需要master权限]按照QQ号或群号发送消息到指定的群组或用户。
|
||||
// 参数:
|
||||
// - msgType: 消息类型,如 "group" 或 "private"。
|
||||
// - groupId: 群组 ID,若为私聊则为 0。
|
||||
// - userId: 用户 ID,若为群聊则为 0。
|
||||
// - message: 要发送的消息内容。
|
||||
// - autoEscape: 消息内容是否作为纯文本发送(即不解析 CQ 码)。
|
||||
UnsafelySendMsg(msgType string, groupId int64, userId int64, message string, autoEscape bool)
|
||||
|
||||
// UnsafelySendPrivateMsg [不安全][需要master权限]按照QQ号发送私聊消息给指定用户。
|
||||
// 参数:
|
||||
// - userId: 用户 ID。
|
||||
// - message: 要发送的消息内容。
|
||||
// - autoEscape: 消息内容是否作为纯文本发送(即不解析 CQ 码)。
|
||||
UnsafelySendPrivateMsg(userId int64, message string, autoEscape bool)
|
||||
|
||||
// UnsafelySendGroupMsg [不安全][需要master权限]按照群号发送群聊消息到指定群组。
|
||||
// 参数:
|
||||
// - groupId: 群组 ID。
|
||||
// - message: 要发送的消息内容。
|
||||
// - autoEscape: 消息内容是否作为纯文本发送(即不解析 CQ 码)。
|
||||
UnsafelySendGroupMsg(groupId int64, message string, autoEscape bool)
|
||||
|
||||
// SendMsg 按照提供的消息事件信息回复指定消息。
|
||||
// 参数:
|
||||
// - msg: 消息事件信息。
|
||||
// - message: 要回复的消息内容。
|
||||
// - autoEscape: 是否自动转义消息内容。
|
||||
SendMsg(msg MessageEventInfo, message string, autoEscape bool)
|
||||
|
||||
// SendPrivateMsg 按照提供的消息事件信息回复私聊消息。
|
||||
// 参数:
|
||||
// - msg: 消息事件信息。
|
||||
// - message: 要回复的消息内容。
|
||||
// - autoEscape: 消息内容是否作为纯文本发送(即不解析 CQ 码)。
|
||||
SendPrivateMsg(msg MessageEventInfo, message string, autoEscape bool)
|
||||
|
||||
// SendGroupMsg 按照提供的消息事件信息回复群聊消息。
|
||||
// 参数:
|
||||
// - msg: 消息事件信息。
|
||||
// - message: 要回复的消息内容。
|
||||
// - autoEscape: 消息内容是否作为纯文本发送(即不解析 CQ 码)。
|
||||
SendGroupMsg(msg MessageEventInfo, message string, autoEscape bool)
|
||||
|
||||
// UnsafelyDeleteMsg [不安全][需要master权限]撤回指定消息。
|
||||
// 参数:
|
||||
// - msgId: 消息 ID。
|
||||
UnsafelyDeleteMsg(msgId int32)
|
||||
|
||||
// DeleteMsg 按照提供的消息事件信息撤回指定的消息。
|
||||
// 参数:
|
||||
// - msg: 消息事件信息。
|
||||
DeleteMsg(msg MessageEventInfo)
|
||||
|
||||
// SendLike 给指定用户发送点赞,支持指定点赞次数。
|
||||
// 参数:
|
||||
// - userId: 用户 ID。
|
||||
// - times: 赞的次数,每个好友每天最多 10 次。
|
||||
SendLike(userId int64, times int)
|
||||
|
||||
// SetGroupKick 将指定用户踢出指定群组,支持拒绝该用户再次加入。
|
||||
// 参数:
|
||||
// - groupId: 群组 ID。
|
||||
// - userId: 用户 ID。
|
||||
// - rejectAddRequest: 是否拒绝该用户再次加入。
|
||||
SetGroupKick(groupId int64, userId int64, rejectAddRequest bool)
|
||||
|
||||
// SetGroupBan 禁言指定用户在指定群组的发言,支持指定禁言时长。
|
||||
// 参数:
|
||||
// - groupId: 群组 ID。
|
||||
// - userId: 用户 ID。
|
||||
// - duration: 禁言时长,单位为秒,0 表示取消禁言。
|
||||
SetGroupBan(groupId int64, userId int64, duration int32)
|
||||
|
||||
// SetGroupWholeBan 开启或关闭指定群组的全员禁言。
|
||||
// 参数:
|
||||
// - groupId: 群组 ID。
|
||||
// - enable: 是否开启全员禁言。
|
||||
SetGroupWholeBan(groupId int64, enable bool)
|
||||
|
||||
// SetGroupAdmin 设置或取消指定用户在指定群组的管理员权限。
|
||||
// 参数:
|
||||
// - groupId: 群组 ID。
|
||||
// - userId: 用户 ID。
|
||||
// - enable: 是否设置为管理员。
|
||||
SetGroupAdmin(groupId int64, userId int64, enable bool)
|
||||
|
||||
// SetGroupLeave 退出指定群组。
|
||||
// 参数:
|
||||
// - groupId: 群组 ID。
|
||||
// - isDismiss: 是否解散,如果登录号是群主,则仅在此项为 true 时能够解散。
|
||||
SetGroupLeave(groupId int64, isDismiss bool)
|
||||
|
||||
// SetGroupCard 设置指定用户在指定群组的群名片。
|
||||
// 参数:
|
||||
// - groupId: 群组 ID。
|
||||
// - userId: 用户 ID。
|
||||
// - card: 群名片内容。
|
||||
SetGroupCard(groupId int64, userId int64, card string)
|
||||
|
||||
// SetGroupName 设置指定群组的名称。
|
||||
// 参数:
|
||||
// - groupId: 群组 ID。
|
||||
// - groupName: 群组名称。
|
||||
SetGroupName(groupId int64, groupName string)
|
||||
|
||||
// SetGroupSpecialTitle 设置指定用户在指定群组的专属头衔,支持指定头衔有效期。
|
||||
// 参数:
|
||||
// - groupId: 群组 ID。
|
||||
// - userId: 用户 ID。
|
||||
// - specialTitle: 专属头衔内容。
|
||||
SetGroupSpecialTitle(groupId int64, userId int64, specialTitle string)
|
||||
|
||||
// SetFriendAddRequest 处理好友添加请求,支持同意或拒绝并添加备注。
|
||||
// 参数:
|
||||
// - flag: 请求标识(需从上报的数据中获得)。
|
||||
// - approve: 是否同意请求。
|
||||
// - remark: 备注信息(仅在同意时有效)。
|
||||
SetFriendAddRequest(flag string, approve bool, remark string)
|
||||
|
||||
// SetGroupAddRequest 处理群组添加请求,支持同意或拒绝并添加理由。
|
||||
// 参数:
|
||||
// - flag: 请求标识。
|
||||
// - subType: 请求子类型。
|
||||
// - approve: 是否同意请求。
|
||||
// - reason: 拒绝理由。
|
||||
SetGroupAddRequest(flag string, subType string, approve bool, reason string)
|
||||
|
||||
// GetLoginInfo 获取当前登录的账号信息。
|
||||
// 返回: API 响应信息。
|
||||
GetLoginInfo() APIResponseInfo
|
||||
|
||||
// GetVersionInfo 获取当前程序的版本信息。
|
||||
// 返回: API 响应信息。
|
||||
GetVersionInfo() APIResponseInfo
|
||||
|
||||
// GetMsg 获取指定消息 ID 的消息内容。
|
||||
// 参数:
|
||||
// - msgId: 消息 ID。
|
||||
// 返回: API 响应信息。
|
||||
GetMsg(msgId int32) APIResponseInfo
|
||||
|
||||
// GetForwardMsg 获取指定转发消息 ID 的消息内容。
|
||||
// 参数:
|
||||
// - msgId: 转发消息 ID。
|
||||
// 返回: API 响应信息。
|
||||
GetForwardMsg(msgId string) APIResponseInfo
|
||||
|
||||
// GetGroupList 获取当前登录账号加入的所有群组列表。
|
||||
// 返回: API 响应信息。
|
||||
GetGroupList() APIResponseInfo
|
||||
|
||||
// GetGroupMemberList 获取指定群组的所有成员列表。
|
||||
// 参数:
|
||||
// - groupId: 群组 ID。
|
||||
// 返回: API 响应信息。
|
||||
GetGroupMemberList(groupId int64) APIResponseInfo
|
||||
|
||||
// GetGroupMemberInfo 获取指定群组中指定用户的详细信息,支持缓存控制。
|
||||
// 参数:
|
||||
// - groupId: 群组 ID。
|
||||
// - userId: 用户 ID。
|
||||
// - noCache: 是否不使用缓存。
|
||||
// 返回: API 响应信息。
|
||||
GetGroupMemberInfo(groupId int64, userId int64, noCache bool) APIResponseInfo
|
||||
|
||||
// GetFriendList 获取当前登录账号的所有好友列表。
|
||||
// 返回: API 响应信息。
|
||||
GetFriendList() APIResponseInfo
|
||||
|
||||
// GetStrangerInfo 获取指定用户的详细信息,支持缓存控制。
|
||||
// 参数:
|
||||
// - userId: 用户 ID。
|
||||
// - noCache: 是否不使用缓存。
|
||||
// 返回: API 响应信息。
|
||||
GetStrangerInfo(userId int64, noCache bool) APIResponseInfo
|
||||
|
||||
// GetGroupInfo 获取指定群组的详细信息,支持缓存控制。
|
||||
// 参数:
|
||||
// - groupId: 群组 ID。
|
||||
// - noCache: 是否不使用缓存。
|
||||
// 返回: API 响应信息。
|
||||
GetGroupInfo(groupId int64, noCache bool) APIResponseInfo
|
||||
|
||||
// GetGroupHonorInfo 获取指定群组的荣誉信息。
|
||||
// 参数:
|
||||
// - groupId: 群组 ID。
|
||||
// - Type: 荣誉类型。
|
||||
// 返回: API 响应信息。
|
||||
GetGroupHonorInfo(groupId int64, Type string) APIResponseInfo
|
||||
|
||||
// GetStatus 获取当前程序的运行状态信息。
|
||||
// 返回: API 响应信息。
|
||||
GetStatus() APIResponseInfo
|
||||
|
||||
// // GetCookies 获取指定域名的 Cookies 信息。
|
||||
// 参数:
|
||||
// - domain: 域名。
|
||||
// 返回: API 响应信息。
|
||||
GetCookies(domain string) APIResponseInfo
|
||||
|
||||
// GetCSRFToken 获取 CSRF 令牌。
|
||||
// 返回: API 响应信息。
|
||||
GetCSRFToken() APIResponseInfo
|
||||
|
||||
// GetCredentials 获取指定域名的凭证信息。
|
||||
// 参数:
|
||||
// - domain: 域名。
|
||||
// 返回: API 响应信息。
|
||||
GetCredentials(domain string) APIResponseInfo
|
||||
|
||||
// GetImage 获取指定文件的图片信息。
|
||||
// 参数:
|
||||
// - file: 文件路径或标识符。
|
||||
// 返回: API 响应信息。
|
||||
GetImage(file string) APIResponseInfo
|
||||
|
||||
// GetRecord 获取指定文件的语音记录信息,支持指定输出格式。
|
||||
// 参数:
|
||||
// - file: 文件路径或标识符。
|
||||
// - outFormat: 输出格式。
|
||||
// 返回: API 响应信息。
|
||||
GetRecord(file string, outFormat string) APIResponseInfo
|
||||
|
||||
// CanSendImage 检查是否可以发送图片。
|
||||
// 返回: API 响应信息。
|
||||
CanSendImage() APIResponseInfo
|
||||
|
||||
// CanSendRecord 检查是否可以发送语音记录。
|
||||
// 返回: API 响应信息。
|
||||
CanSendRecord() APIResponseInfo
|
||||
|
||||
// SetRestart 设置程序在指定延迟后重启。
|
||||
// 参数:
|
||||
// - delay: 延迟时间,单位为秒。
|
||||
SetRestart(delay int32)
|
||||
|
||||
// CleanCache 清理程序的缓存。
|
||||
CleanCache()
|
||||
}
|
||||
|
||||
type WindStandardDataBaseAPI interface {
|
||||
// SetUserVariable 设置用户变量
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - msg: 消息事件信息。
|
||||
// - key: 变量名称。
|
||||
// - value: 变量值。
|
||||
SetUserVariable(app AppInfo, msg MessageEventInfo, key string, value string)
|
||||
|
||||
// SetGroupVariable 设置群组变量
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - msg: 消息事件信息。
|
||||
// - key: 变量名称。
|
||||
// - value: 变量值。
|
||||
SetGroupVariable(app AppInfo, msg MessageEventInfo, key string, value string)
|
||||
|
||||
// SetOutUserVariable [需要master权限]设置其他数据库中的用户变量
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - msg: 消息事件信息。
|
||||
// - key: 变量名称。
|
||||
// - value: 变量值。
|
||||
// - datamap: 数据表名称。
|
||||
SetOutUserVariable(app AppInfo, datamap string, msg MessageEventInfo, key string, value string)
|
||||
|
||||
// SetOutGroupVariable [需要master权限]设置其他数据库中的群组变量
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - msg: 消息事件信息。
|
||||
// - key: 变量名称。
|
||||
// - value: 变量值。
|
||||
// - datamap: 数据表名称。
|
||||
SetOutGroupVariable(app AppInfo, datamap string, msg MessageEventInfo, key string, value string)
|
||||
|
||||
// UnsafelySetUserVariable [不安全][需要master权限]设置用户变量
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - id: 数据单元 ID。
|
||||
// - key: 变量名称。
|
||||
// - value: 变量值。
|
||||
UnsafelySetUserVariable(app AppInfo, id string, key string, value string)
|
||||
|
||||
// UnsafelySetGroupVariable [不安全][需要master权限]设置群组变量
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - id: 数据单元 ID。
|
||||
// - key: 变量名称。
|
||||
// - value: 变量值。
|
||||
UnsafelySetGroupVariable(app AppInfo, id string, key string, value string)
|
||||
|
||||
// UnsafelySetGlobalVariable [不安全][需要master权限]设置全局变量
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - id: 数据单元 ID。
|
||||
// - key: 变量名称。
|
||||
// - value: 变量值。
|
||||
UnsafelySetGlobalVariable(app AppInfo, id string, key string, value string)
|
||||
|
||||
// UnsafelySetOutUserVariable [不安全][需要master权限]设置其他数据库中的用户变量
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - id: 数据单元 ID。
|
||||
// - key: 变量名称。
|
||||
// - value: 变量值。
|
||||
// - datamap: 数据表名称。
|
||||
UnsafelySetOutUserVariable(app AppInfo, datamap string, id string, key string, value string)
|
||||
|
||||
// UnsafelySetOutGroupVariable [不安全][需要master权限]设置其他数据库中的群组变量
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - id: 数据单元 ID。
|
||||
// - key: 变量名称。
|
||||
// - value: 变量值。
|
||||
// - datamap: 数据表名称。
|
||||
UnsafelySetOutGroupVariable(app AppInfo, datamap string, id string, key string, value string)
|
||||
|
||||
// UnsafelySetOutGlobalVariable [不安全][需要master权限]设置其他数据库中的全局变量
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - id: 数据单元 ID。
|
||||
// - key: 变量名称。
|
||||
// - value: 变量值。
|
||||
// - datamap: 数据表名称。
|
||||
UnsafelySetOutGlobalVariable(app AppInfo, datamap string, id string, key string, value string)
|
||||
|
||||
// GetUserVariable 获取用户变量
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - msg: 消息变量名称。
|
||||
// - key: 变量名称。
|
||||
// 返回: 变量值,是否存在。
|
||||
GetUserVariable(app AppInfo, msg MessageEventInfo, key string) (string, bool)
|
||||
|
||||
// GetGroupVariable 获取群组变量
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - msg: 消息变量名称。
|
||||
// - key: 变量名称。
|
||||
// 返回: 变量值,是否存在。
|
||||
GetGroupVariable(app AppInfo, msg MessageEventInfo, key string) (string, bool)
|
||||
|
||||
// GetOutUserVariable [需要master权限]获取其他数据库中的用户变量
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - msg: 消息变量名称。
|
||||
// - key: 变量名称。
|
||||
// - datamap:数据表名称。
|
||||
// 返回: 变量值,是否存在。
|
||||
GetOutUserVariable(app AppInfo, datamap string, msg MessageEventInfo, key string) (string, bool)
|
||||
|
||||
// GetOutGroupVariable [需要master权限]获取其他数据库中的群组变量
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - msg: 消息变量名称。
|
||||
// - key: 变量名称。
|
||||
// - datamap:数据表名称。
|
||||
// 返回: 变量值,是否存在。
|
||||
GetOutGroupVariable(app AppInfo, datamap string, msg MessageEventInfo, key string) (string, bool)
|
||||
|
||||
// UnsafelyGetUserVariable [不安全][需要master权限]获取用户变量
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - id: 数据单元 ID。
|
||||
// - key: 变量名称。
|
||||
// 返回: 变量值,是否存在。
|
||||
UnsafelyGetUserVariable(app AppInfo, id string, key string) (string, bool)
|
||||
|
||||
// UnsafelyGetGroupVariable [不安全][需要master权限]获取群组变量
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - id: 数据单元 ID。
|
||||
// - key: 变量名称。
|
||||
// 返回: 变量值,是否存在。
|
||||
UnsafelyGetGroupVariable(app AppInfo, id string, key string) (string, bool)
|
||||
|
||||
// UnsafelyGetGlobalVariable [不安全][需要master权限]获取全局变量
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - id: 数据单元 ID。
|
||||
// - key: 变量名称。
|
||||
// 返回: 变量值,是否存在。
|
||||
UnsafelyGetGlobalVariable(app AppInfo, id string, key string) (string, bool)
|
||||
|
||||
// UnsafelyGetOutUserVariable [不安全][需要master权限]获取其他数据库中的用户变量
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - id: 数据单元 ID。
|
||||
// - key: 变量名称。
|
||||
// - datamap:数据表名称。
|
||||
// 返回: 变量值,是否存在。
|
||||
UnsafelyGetOutUserVariable(app AppInfo, datamap string, id string, key string) (string, bool)
|
||||
|
||||
// UnsafelyGetOutGroupVariable [不安全][需要master权限]获取其他数据库中的群组变量
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - id: 数据单元 ID。
|
||||
// - key: 变量名称。
|
||||
// - datamap:数据表名称。
|
||||
// 返回: 变量值,是否存在。
|
||||
UnsafelyGetOutGroupVariable(app AppInfo, datamap string, id string, key string) (string, bool)
|
||||
|
||||
// UnsafelyGetOutGlobalVariable [不安全][需要master权限]获取其他数据库中的全局变量
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - id: 数据单元 ID。
|
||||
// - key: 变量名称。
|
||||
// - datamap:数据表名称。
|
||||
// 返回: 变量值,是否存在。
|
||||
UnsafelyGetOutGlobalVariable(app AppInfo, datamap string, id string, key string) (string, bool)
|
||||
|
||||
// GetIntConfig 获取指定数据单元的整数型配置。
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - datamap: 数据单元名称。
|
||||
// - key: 配置名称。
|
||||
// 返回: 配置值,是否存在。
|
||||
GetIntConfig(app AppInfo, datamap string, key string) (int64, bool)
|
||||
|
||||
// GetStringConfig 获取指定数据单元的字符串型配置。
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - datamap: 数据单元名称。
|
||||
// - key: 配置名称。
|
||||
// 返回: 配置值,是否存在。
|
||||
GetStringConfig(app AppInfo, datamap string, key string) (string, bool)
|
||||
|
||||
// GetFloatConfig 获取指定数据单元的浮点型配置。
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - datamap: 数据单元名称。
|
||||
// - key: 配置名称。
|
||||
// 返回: 配置值,是否存在。
|
||||
GetFloatConfig(app AppInfo, datamap string, key string) (float64, bool)
|
||||
|
||||
// GetIntSliceConfig 获取指定数据单元的整数型切片配置。
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - datamap: 数据单元名称。
|
||||
// - key: 配置名称。
|
||||
// 返回: 配置值,是否存在。
|
||||
GetIntSliceConfig(app AppInfo, datamap string, key string) ([]int64, bool)
|
||||
|
||||
// GetStringSliceConfig 获取指定数据单元的字符串型切片配置。
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - datamap: 数据单元名称。
|
||||
// - key: 配置名称。
|
||||
// 返回: 配置值,是否存在。
|
||||
GetStringSliceConfig(app AppInfo, datamap string, key string) ([]string, bool)
|
||||
|
||||
// UnsafelyCreatePublicDatamap [不安全][需要master权限]创建公共数据表
|
||||
// 参数:
|
||||
// - app: 应用信息。
|
||||
// - datamapId: 数据表名称。
|
||||
UnsafelyCreatePublicDatamap(app AppInfo, datamapId string)
|
||||
}
|
62
wba/wind_standard_tools.go
Normal file
62
wba/wind_standard_tools.go
Normal file
@ -0,0 +1,62 @@
|
||||
package wba
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type WindStandardTools interface {
|
||||
// MsgUnmarshal 解析消息JSON字符串为 MessageEventInfo 结构体。
|
||||
//
|
||||
// 参数:
|
||||
//
|
||||
// - message: 要解析的消息JSON字符串。
|
||||
//
|
||||
// 返回值:
|
||||
//
|
||||
// - msg: 解析后的消息结构体。
|
||||
MsgUnmarshal(message string) (msg MessageEventInfo)
|
||||
|
||||
// LogWith 使用指定日志级别记录日志,支持可变参数占位符。
|
||||
//
|
||||
// 参数:
|
||||
// - level: 日志级别: "trace", "debug", "info", "notice", "warn", "error"。
|
||||
// - log: 日志内容。
|
||||
// - args: 可变参数,用于格式化日志内容。
|
||||
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小于version2,0表示version1等于version2,1表示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)
|
||||
}
|
BIN
webui/index.html.hertz.gz
Normal file
BIN
webui/index.html.hertz.gz
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user