ProjectWIND/core/app_admin.go
2025-04-22 12:28:44 +08:00

287 lines
9.9 KiB
Go

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
}