diff --git a/protocol/api.go b/core/api.go similarity index 99% rename from protocol/api.go rename to core/api.go index d6c70e6..193cee8 100644 --- a/protocol/api.go +++ b/core/api.go @@ -1,4 +1,4 @@ -package protocol +package core import ( "ProjectWIND/typed" diff --git a/core/appAdmin.go b/core/appAdmin.go new file mode 100644 index 0000000..3005ac1 --- /dev/null +++ b/core/appAdmin.go @@ -0,0 +1,58 @@ +package core + +import ( + "ProjectWIND/LOG" + "os" + "path/filepath" + "plugin" +) + +func reloadApps() { + appsDir := "./data/app/" + appFiles, err := os.ReadDir(appsDir) + total := 0 + success := 0 + if err != nil { + LOG.ERROR("Error reading apps directory:%v", err) + return + } + + for _, file := range appFiles { + totalDelta, successDelta := reloadAPP(file, appsDir) + total += totalDelta + success += successDelta + } +} + +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" || (ext == ".dll" && os.PathSeparator == '\\') { + pluginPath := filepath.Join(appsDir, file.Name()) + p, err := plugin.Open(pluginPath) + if err != nil { + LOG.ERROR("Error opening app %s: %v\n", pluginPath, err) + return 1, 0 + } + + initSymbol, err := p.Lookup("init") + if err != nil { + LOG.ERROR("Error finding init function in app %s: %v\n", pluginPath, err) + return 1, 0 + } + + initFunc, ok := initSymbol.(func()) + if !ok { + LOG.ERROR("init symbol in app %s is not a function\n", pluginPath) + return 1, 0 + } + + initFunc() + LOG.INFO("App %s initialized successfully\n", pluginPath) + return 1, 1 + } + return 0, 0 +} diff --git a/core/cmdList.go b/core/cmdList.go new file mode 100644 index 0000000..1100e41 --- /dev/null +++ b/core/cmdList.go @@ -0,0 +1,31 @@ +package core + +import ( + "ProjectWIND/LOG" + "ProjectWIND/typed" +) + +var CmdList = map[string]typed.ExtInfo{ + "bot": ExtCore, + "help": ExtCore, +} + +var ExtCore = typed.ExtInfo{ + Run: func(cmd string, args []string, msg typed.MessageEventInfo) error { + if cmd == "help" { + err := SendMsg(msg, "假装有帮助信息", false) + LOG.INFO("发送核心帮助信息:(至:%v-%v:%v-%v)", msg.MessageType, msg.GroupId, msg.UserId, msg.Sender.Nickname) + if err != nil { + return err + } + } + if cmd == "bot" { + err := SendMsg(msg, "WIND 0.1.0", false) + LOG.INFO("发送核心版本信息:(至:%v-%v:%v-%v)", msg.MessageType, msg.GroupId, msg.UserId, msg.Sender.Nickname) + if err != nil { + return err + } + } + return nil + }, +} diff --git a/core/events_handler.go b/core/events_handler.go new file mode 100644 index 0000000..ffc8803 --- /dev/null +++ b/core/events_handler.go @@ -0,0 +1,87 @@ +package core + +import ( + "ProjectWIND/LOG" + "ProjectWIND/typed" + "encoding/json" + "fmt" + "strings" +) + +func HandleMessage(msgJson []byte) { + var msg typed.MessageEventInfo + err := json.Unmarshal(msgJson, &msg) + if err != nil { + LOG.ERROR("Unmarshalling message: %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 := CmdList[cmd] + if ok { + err = CmdList[cmd].Run(cmd, args, msg) + if err != nil { + LOG.ERROR("消息发送失败: %v", err) + } + } + // TODO: 处理消息内容 +} + +func HandleNotice(msgJson []byte) { + var notice typed.NoticeEventInfo + err := json.Unmarshal(msgJson, ¬ice) + if err != nil { + LOG.ERROR("Unmarshalling notice: %v", err) + } + // TODO: 处理通知 +} + +func HandleRequest(msgJson []byte) { + var request typed.NoticeEventInfo + err := json.Unmarshal(msgJson, &request) + if err != nil { + LOG.ERROR("Unmarshalling request: %v", err) + } + // TODO: 处理请求 +} + +func HandleMetaEvent(msgJson []byte) { + var meta typed.NoticeEventInfo + err := json.Unmarshal(msgJson, &meta) + if err != nil { + LOG.ERROR("Unmarshalling meta: %v", err) + } + // TODO: 处理元事件 +} + +func CmdSplit(msg typed.MessageEventInfo) (string, []string) { + text := msg.RawMessage + if strings.HasPrefix(text, fmt.Sprintf("[CQ:at,qq=%d]", msg.SelfId)) { + text = strings.TrimPrefix(text, fmt.Sprintf("[CQ:at,qq=%d]", msg.SelfId)) + } else { + if statusCheck(msg) { + return "", []string{} + } + } + //检查有无application.CmdList中的命令前缀 + for _, prefix := range cmdPrefix { + if strings.HasPrefix(text, prefix) { + text = strings.TrimPrefix(text, prefix) + for cmd := range CmdList { + if strings.HasPrefix(text, cmd) { + text = strings.TrimPrefix(text, cmd) + return cmd, strings.Split(text, " ") + } + } + } + } + return "", []string{} +} + +func statusCheck(msg typed.MessageEventInfo) bool { + //TODO: 检查当前组群工作状态 + return false +} + +var cmdPrefix = []string{"/", "!", "/", "!", ".", "。"} diff --git a/protocol/web_socket.go b/core/web_socket.go similarity index 99% rename from protocol/web_socket.go rename to core/web_socket.go index a72d3d3..d23371f 100644 --- a/protocol/web_socket.go +++ b/core/web_socket.go @@ -1,4 +1,4 @@ -package protocol +package core import ( "ProjectWIND/LOG" diff --git a/main.go b/main.go index bc0fa51..e28911d 100644 --- a/main.go +++ b/main.go @@ -40,6 +40,7 @@ func main() { if cmdArgs[0] == "-p" || cmdArgs[0] == "--protocol" { // 连接到协议端 startProtocol() + go AutoSave() return } fmt.Println("Invalid command.") diff --git a/protocol/events_handler.go b/protocol/events_handler.go deleted file mode 100644 index f963374..0000000 --- a/protocol/events_handler.go +++ /dev/null @@ -1,46 +0,0 @@ -package protocol - -import ( - "ProjectWIND/LOG" - "ProjectWIND/typed" - "encoding/json" -) - -func HandleMessage(msgJson []byte) { - var msg typed.MessageEventInfo - err := json.Unmarshal(msgJson, &msg) - if err != nil { - LOG.FATAL("Unmarshalling message: %v", err) - } - // 处理消息 - LOG.INFO("收到消息:(来自:%v-%v:%v-%v)%v", msg.MessageType, msg.GroupId, msg.UserId, msg.Sender.Nickname, msg.RawMessage) - // TODO: 处理消息内容 - -} - -func HandleNotice(msgJson []byte) { - var notice typed.NoticeEventInfo - err := json.Unmarshal(msgJson, ¬ice) - if err != nil { - LOG.ERROR("Unmarshalling notice: %v", err) - } - // TODO: 处理通知 -} - -func HandleRequest(msgJson []byte) { - var request typed.NoticeEventInfo - err := json.Unmarshal(msgJson, &request) - if err != nil { - LOG.ERROR("Unmarshalling request: %v", err) - } - // TODO: 处理请求 -} - -func HandleMetaEvent(msgJson []byte) { - var meta typed.NoticeEventInfo - err := json.Unmarshal(msgJson, &meta) - if err != nil { - LOG.ERROR("Unmarshalling meta: %v", err) - } - // TODO: 处理元事件 -} diff --git a/typed/typed.go b/typed/typed.go index f64c555..ce40384 100644 --- a/typed/typed.go +++ b/typed/typed.go @@ -1,6 +1,6 @@ package typed -type ConfigInfo struct { +type CoreConfigInfo struct { CoreName string `json:"core_name"` ProtocolAddr string `json:"protocol_addr"` WebUIPort uint16 `json:"webui_port"` @@ -139,3 +139,27 @@ type ParamsInfo struct { File string `json:"file,omitempty"` Times int `json:"times,omitempty"` } + +type ExtInfo struct { + Inform func() extInformation + Run func(cmd string, args []string, msg MessageEventInfo) error + Init func() error + CmdList func() []string +} + +func (e *ExtInfo) SetInform(name string, version string, author string) { + inform := extInformation{ + Name: name, + Version: version, + Author: author, + } + e.Inform = func() extInformation { + return inform + } +} + +type extInformation struct { + Name string + Version string + Author string +} diff --git a/utils.go b/utils.go index fb01a4c..22ce811 100644 --- a/utils.go +++ b/utils.go @@ -2,7 +2,7 @@ package main import ( "ProjectWIND/LOG" - "ProjectWIND/protocol" + "ProjectWIND/core" "ProjectWIND/typed" "encoding/json" "errors" @@ -20,9 +20,9 @@ func initCore() string { LOG.INFO("正在初始化WIND配置文件...") - err := checkAndUpdateConfig("./data/config.json") + err := checkAndUpdateConfig("./data/core.json") if err != nil { - LOG.FATAL("Failed to initialize config file: %v", err) + LOG.FATAL("Failed to initialize core.json file: %v", err) } // 创建日志文件 logFile := fmt.Sprintf("./data/log/WIND_CORE_%s.log", time.Now().Format("20060102150405")) @@ -67,26 +67,26 @@ func checkAndUpdateConfig(configPath string) error { } } - // 检查./data/文件夹中是否存在config.json文件 - if _, err := os.Stat("./data/config.json"); os.IsNotExist(err) { + // 检查./data/文件夹中是否存在core.json文件 + if _, err := os.Stat("./data/core.json"); os.IsNotExist(err) { // 如果不存在,则创建该文件 - file, err := os.Create("./data/config.json") + file, err := os.Create("./data/core.json") if err != nil { - LOG.FATAL("Failed to create config file: %v", err) + LOG.FATAL("Failed to create core.json file: %v", err) } defer func(file *os.File) { err := file.Close() if err != nil { - LOG.FATAL("Failed to close config file: %v", err) + LOG.FATAL("Failed to close core.json file: %v", err) } }(file) } // 检查并更新配置文件 - var config typed.ConfigInfo + var coreConfig typed.CoreConfigInfo // 定义默认配置 - var defaultConfig typed.ConfigInfo + var defaultConfig typed.CoreConfigInfo defaultConfig.CoreName = "windCore" defaultConfig.WebUIPort = 3211 defaultConfig.ProtocolAddr = "" @@ -99,13 +99,13 @@ func checkAndUpdateConfig(configPath string) error { defer func(file *os.File) { err := file.Close() if err != nil { - LOG.FATAL("Failed to close config file: %v", err) + LOG.FATAL("Failed to close core.json file: %v", err) } }(file) // 解码JSON配置 decoder := json.NewDecoder(file) - err = decoder.Decode(&config) + err = decoder.Decode(&coreConfig) if err != nil { if !errors.Is(err, io.EOF) { return err @@ -113,43 +113,43 @@ func checkAndUpdateConfig(configPath string) error { } // 检查并更新配置 - if config.ProtocolAddr == "" { - config.ProtocolAddr = defaultConfig.ProtocolAddr + if coreConfig.ProtocolAddr == "" { + coreConfig.ProtocolAddr = defaultConfig.ProtocolAddr } - if config.WebUIPort == 0 { - config.WebUIPort = defaultConfig.WebUIPort + if coreConfig.WebUIPort == 0 { + coreConfig.WebUIPort = defaultConfig.WebUIPort } - if config.CoreName == "" { - config.CoreName = defaultConfig.CoreName + if coreConfig.CoreName == "" { + coreConfig.CoreName = defaultConfig.CoreName } - if config.ServiceName == "" { - config.ServiceName = defaultConfig.ServiceName + if coreConfig.ServiceName == "" { + coreConfig.ServiceName = defaultConfig.ServiceName } - if config.PasswordHash == "" { - config.PasswordHash = "" + if coreConfig.PasswordHash == "" { + coreConfig.PasswordHash = "" } - formattedJSON, err := json.MarshalIndent(config, "", " ") + formattedJSON, err := json.MarshalIndent(coreConfig, "", " ") if err != nil { return err } // 将格式化后的JSON字符串写入文件 - file, err = os.Create("./data/config.json") + file, err = os.Create("./data/core.json") if err != nil { - LOG.FATAL("Error creating config file:%v", err) + LOG.FATAL("Error creating core.json file:%v", err) return err } defer func(file *os.File) { err := file.Close() if err != nil { - LOG.FATAL("Failed to close config file: %v", err) + LOG.FATAL("Failed to close core.json file: %v", err) } }(file) _, err = file.Write(formattedJSON) if err != nil { - LOG.FATAL("Error writing to config file: %v", err) + LOG.FATAL("Error writing to core.json file: %v", err) return err } @@ -259,15 +259,15 @@ func startProtocol() { log.SetOutput(io.MultiWriter(os.Stdout, file)) //从配置文件中读取配置信息 LOG.INFO("正在启动WIND协议服务...") - var config typed.ConfigInfo - file, err = os.Open("./data/config.json") + var config typed.CoreConfigInfo + file, err = os.Open("./data/core.json") if err != nil { - LOG.FATAL("Failed to open config file: %v", err) + LOG.FATAL("Failed to open core.json file: %v", err) } defer func(file *os.File) { err := file.Close() if err != nil { - LOG.FATAL("Failed to close config file: %v", err) + LOG.FATAL("Failed to close core.json file: %v", err) } }(file) @@ -281,10 +281,18 @@ func startProtocol() { //链接协议 // 启动 WebSocket 处理程序 LOG.INFO("正在启动WebSocket链接程序...") - err = protocol.WebSocketHandler(protocolAddr) + err = core.WebSocketHandler(protocolAddr) if err != nil { // 如果发生错误,记录错误并退出程序 LOG.FATAL("Failed to start WebSocket link program: %v", err) } return } + +func AutoSave() { + for { + LOG.INFO("自动保存") + //TODO: 这里要添加自动保存的代码 + time.Sleep(time.Second * 60) + } +}