Skip to content

Commit

Permalink
Beta401 (#401)
Browse files Browse the repository at this point in the history
* beta399

* beta400

* beta401
  • Loading branch information
Hoshinonyaruko authored May 10, 2024
1 parent 102b1e7 commit 5f13c12
Show file tree
Hide file tree
Showing 6 changed files with 214 additions and 70 deletions.
6 changes: 4 additions & 2 deletions Processor/ProcessGroupMsgReceive.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ func (p *Processors) ProcessGroupMsgRecive(data *dto.GroupMsgReceiveEvent) error
mylog.Printf("Error storing ID: %v", err)
return nil
}
// 修复不开启idmap-pro问题
LongGroupID64 = GroupID64
}
var selfid64 int64
if config.GetUseUin() {
Expand All @@ -76,7 +78,7 @@ func (p *Processors) ProcessGroupMsgRecive(data *dto.GroupMsgReceiveEvent) error
if !config.GetGlobalGroupMsgRejectReciveEventToMessage() {
notice := &OnebotGroupReceiveNotice{
GroupID: GroupID64,
NoticeType: "interaction",
NoticeType: "group_receive",
PostType: "notice",
SelfID: selfid64,
SubType: "create",
Expand Down Expand Up @@ -150,7 +152,7 @@ func (p *Processors) ProcessGroupMsgRecive(data *dto.GroupMsgReceiveEvent) error
}
//增强配置
if !config.GetNativeOb11() {
groupMsg.RealMessageType = "interaction"
groupMsg.RealMessageType = "group_receive"
groupMsg.IsBindedUserId = IsBindedUserId
groupMsg.IsBindedGroupId = IsBindedGroupId
groupMsg.RealGroupID = data.GroupOpenID
Expand Down
6 changes: 4 additions & 2 deletions Processor/ProcessGroupMsgReject.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ func (p *Processors) ProcessGroupMsgReject(data *dto.GroupMsgRejectEvent) error
mylog.Printf("Error storing ID: %v", err)
return nil
}
// 修复不开启idmap-pro问题
LongGroupID64 = GroupID64
}
var selfid64 int64
if config.GetUseUin() {
Expand All @@ -77,7 +79,7 @@ func (p *Processors) ProcessGroupMsgReject(data *dto.GroupMsgRejectEvent) error
if !config.GetGlobalGroupMsgRejectReciveEventToMessage() {
notice := &OnebotGroupRejectNotice{
GroupID: GroupID64,
NoticeType: "interaction",
NoticeType: "group_reject",
PostType: "notice",
SelfID: selfid64,
SubType: "create",
Expand Down Expand Up @@ -151,7 +153,7 @@ func (p *Processors) ProcessGroupMsgReject(data *dto.GroupMsgRejectEvent) error
}
//增强配置
if !config.GetNativeOb11() {
groupMsg.RealMessageType = "interaction"
groupMsg.RealMessageType = "group_reject"
groupMsg.IsBindedUserId = IsBindedUserId
groupMsg.IsBindedGroupId = IsBindedGroupId
groupMsg.RealGroupID = data.GroupOpenID
Expand Down
222 changes: 158 additions & 64 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,47 +35,141 @@ type CommentBlock struct {
Offset int // 注释与目标键之间的行数
}

// 不支持配置热重载的配置项
var restartRequiredFields = []string{
"WsAddress", "WsToken", "ReconnectTimes", "HeartBeatInterval", "LaunchReconnectTimes",
"AppID", "Uin", "Token", "ClientSecret", "ShardCount", "ShardID", "UseUin",
"TextIntent",
"ServerDir", "Port", "BackupPort", "Lotus", "LotusPassword", "LotusWithoutIdmaps",
"WsServerPath", "EnableWsServer", "WsServerToken",
"IdentifyFile", "IdentifyAppids", "Crt", "Key",
"DeveloperLog", "LogLevel", "SaveLogs",
"DisableWebui", "Username", "Password",
"Title", // 继续检查和增加
}

// LoadConfig 从文件中加载配置并初始化单例配置
func LoadConfig(path string) (*Config, error) {
func LoadConfig(path string, fastload bool) (*Config, error) {
mu.Lock()
defer mu.Unlock()

// 如果单例已经被初始化了,直接返回
if instance != nil {
return instance, nil
}

configData, err := os.ReadFile(path)
if err != nil {
return nil, err
}
//todo remove it 破坏性变更的擦屁股代码
var ischange bool
configData, ischange = replaceVisualPrefixsLine(configData)
if ischange {
err = os.WriteFile(path, configData, 0644)
if err != nil {
// 处理写入错误
return nil, err
}
}
//mylog.Printf("dev_ischange:%v", ischange)

// 检查并替换视觉前缀行,如果有必要,后期会注释
// var isChange bool
// configData, isChange = replaceVisualPrefixsLine(configData)
// if isChange {
// // 如果配置文件已修改,重新写入修正后的数据
// if err = os.WriteFile(path, configData, 0644); err != nil {
// return nil, err // 处理写入错误
// }
// }

// 尝试解析配置数据
conf := &Config{}
err = yaml.Unmarshal(configData, conf)
if err != nil {
if err = yaml.Unmarshal(configData, conf); err != nil {
return nil, err
}

// 确保配置完整性
if err := ensureConfigComplete(path); err != nil {
return nil, err
if !fastload {
// 确保本地配置文件的完整性,添加新的字段
if err = ensureConfigComplete(path); err != nil {
return nil, err
}
} else {
if isValidConfig(conf) {
//log.Printf("instance.Settings:%v", instance.Settings)
// 用现有的instance比对即将覆盖赋值的conf,用[]string返回配置发生了变化的配置项
changedFields := compareConfigChanges("Settings", instance.Settings, conf.Settings)
// 根据changedFields进行进一步的操作,在不支持热重载的字段实现自动重启
if len(changedFields) > 0 {
log.Printf("配置已变更的字段:%v", changedFields)
checkForRestart(changedFields) // 检查变更字段是否需要重启
}
} //conf为空时不对比
}

// 更新单例实例,即使它已经存在 更新前检查是否有效,vscode对文件的更新行为会触发2次文件变动
// 第一次会让configData为空,迅速的第二次才是正常有值的configData
if isValidConfig(conf) {
instance = conf
}

// 设置单例实例
instance = conf
return instance, nil
}

func isValidConfig(conf *Config) bool {
// 确认config不为空且必要字段已设置
return conf != nil && conf.Version != 0
}

// 去除Settings前缀
func stripSettingsPrefix(fieldName string) string {
return strings.TrimPrefix(fieldName, "Settings.")
}

// compareConfigChanges 检查并返回发生变化的配置字段,处理嵌套结构体
func compareConfigChanges(prefix string, oldConfig interface{}, newConfig interface{}) []string {
var changedFields []string

oldVal := reflect.ValueOf(oldConfig)
newVal := reflect.ValueOf(newConfig)

// 解引用指针
if oldVal.Kind() == reflect.Ptr {
oldVal = oldVal.Elem()
}
if newVal.Kind() == reflect.Ptr {
newVal = newVal.Elem()
}

// 遍历所有字段
for i := 0; i < oldVal.NumField(); i++ {
oldField := oldVal.Field(i)
newField := newVal.Field(i)
fieldType := oldVal.Type().Field(i)
fieldName := fieldType.Name

fullFieldName := fieldName
if prefix != "" {
fullFieldName = fmt.Sprintf("%s.%s", prefix, fieldName)
}

// 对于结构体字段递归比较
if oldField.Kind() == reflect.Struct || newField.Kind() == reflect.Struct {
subChanges := compareConfigChanges(fullFieldName, oldField.Interface(), newField.Interface())
changedFields = append(changedFields, subChanges...)
} else {
// 打印将要比较的字段和它们的值
//fmt.Printf("Comparing field: %s\nOld value: %v\nNew value: %v\n", fullFieldName, oldField.Interface(), newField.Interface())
if !reflect.DeepEqual(oldField.Interface(), newField.Interface()) {
//fmt.Println("-> Field changed")
// 去除Settings前缀后添加到变更字段列表
changedField := stripSettingsPrefix(fullFieldName)
changedFields = append(changedFields, changedField)
}
}
}

return changedFields
}

// 检查是否需要重启
func checkForRestart(changedFields []string) {
for _, field := range changedFields {
for _, restartField := range restartRequiredFields {
if field == restartField {
fmt.Println("Configuration change requires restart:", field)
sys.RestartApplication() // 调用重启函数
return
}
}
}
}

func CreateAndWriteConfigTemp() error {
// 读取config.yml
configFile, err := os.ReadFile("config.yml")
Expand Down Expand Up @@ -1426,46 +1520,46 @@ func GetQrSize() int {
return instance.Settings.QrSize
}

func replaceVisualPrefixsLine(configData []byte) ([]byte, bool) {
// 定义新的 visual_prefixs 部分
newVisualPrefixs := ` visual_prefixs : #虚拟前缀 与white_prefixs配合使用 处理流程自动忽略该前缀 remove_prefix remove_at 需为true时生效
- prefix: "" #虚拟前缀开头 例 你有3个指令 帮助 测试 查询 将 prefix 设置为 工具类 后 则可通过 工具类 帮助 触发机器人
whiteList: [""] #开关状态取决于 white_prefix_mode 为每一个二级指令头设计独立的白名单
No_White_Response : ""
- prefix: ""
whiteList: [""]
No_White_Response : ""
- prefix: ""
whiteList: [""]
No_White_Response : "" `

// 将 byte 数组转换为字符串
configStr := string(configData)

// 按行分割 configStr
lines := strings.Split(configStr, "\n")

// 创建一个新的字符串构建器
var newConfigData strings.Builder

// 标记是否进行了替换
replaced := false

// 遍历所有行
for _, line := range lines {
// 检查是否是 visual_prefixs 开头的行
if strings.HasPrefix(strings.TrimSpace(line), "visual_prefixs : [") {
// 替换为新的 visual_prefixs 部分
newConfigData.WriteString(newVisualPrefixs + "\n")
replaced = true
continue // 跳过原有行
}
newConfigData.WriteString(line + "\n")
}

// 返回新配置和是否发生了替换的标记
return []byte(newConfigData.String()), replaced
}
// func replaceVisualPrefixsLine(configData []byte) ([]byte, bool) {
// // 定义新的 visual_prefixs 部分
// newVisualPrefixs := ` visual_prefixs : #虚拟前缀 与white_prefixs配合使用 处理流程自动忽略该前缀 remove_prefix remove_at 需为true时生效
// - prefix: "" #虚拟前缀开头 例 你有3个指令 帮助 测试 查询 将 prefix 设置为 工具类 后 则可通过 工具类 帮助 触发机器人
// whiteList: [""] #开关状态取决于 white_prefix_mode 为每一个二级指令头设计独立的白名单
// No_White_Response : ""
// - prefix: ""
// whiteList: [""]
// No_White_Response : ""
// - prefix: ""
// whiteList: [""]
// No_White_Response : "" `

// // 将 byte 数组转换为字符串
// configStr := string(configData)

// // 按行分割 configStr
// lines := strings.Split(configStr, "\n")

// // 创建一个新的字符串构建器
// var newConfigData strings.Builder

// // 标记是否进行了替换
// replaced := false

// // 遍历所有行
// for _, line := range lines {
// // 检查是否是 visual_prefixs 开头的行
// if strings.HasPrefix(strings.TrimSpace(line), "visual_prefixs : [") {
// // 替换为新的 visual_prefixs 部分
// newConfigData.WriteString(newVisualPrefixs + "\n")
// replaced = true
// continue // 跳过原有行
// }
// newConfigData.WriteString(line + "\n")
// }

// // 返回新配置和是否发生了替换的标记
// return []byte(newConfigData.String()), replaced
// }

// 获取GetWhiteBypassRevers的值
func GetWhiteBypassRevers() bool {
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/aliyun/aliyun-oss-go-sdk v3.0.1+incompatible
github.com/baidubce/bce-sdk-go v0.9.161
github.com/fatih/color v1.15.0
github.com/fsnotify/fsnotify v1.7.0
github.com/gin-gonic/gin v1.9.1
github.com/google/uuid v1.4.0
github.com/gorilla/websocket v1.4.2
Expand Down Expand Up @@ -69,6 +70,6 @@ require (
golang.org/x/net v0.10.0
golang.org/x/sys v0.13.0
golang.org/x/text v0.9.0 // indirect
google.golang.org/protobuf v1.32.0
google.golang.org/protobuf v1.32.0 // indirect
mvdan.cc/xurls v1.1.0
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBD
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
Expand Down
45 changes: 44 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"time"

"github.com/fatih/color"
"github.com/fsnotify/fsnotify"
"github.com/hoshinonyaruko/gensokyo/Processor"
"github.com/hoshinonyaruko/gensokyo/acnode"
"github.com/hoshinonyaruko/gensokyo/botstats"
Expand Down Expand Up @@ -93,10 +94,14 @@ func main() {

// 主逻辑
// 加载配置
conf, err := config.LoadConfig("config.yml")
conf, err := config.LoadConfig("config.yml", false)
if err != nil {
log.Fatalf("error: %v", err)
}

// 配置热重载
go setupConfigWatcher("config.yml")

sys.SetTitle(conf.Settings.Title)
webuiURL := config.ComposeWebUIURL(conf.Settings.Lotus) // 调用函数获取URL
webuiURLv2 := config.ComposeWebUIURLv2(conf.Settings.Lotus) // 调用函数获取URL
Expand Down Expand Up @@ -716,3 +721,41 @@ func allEmpty(addresses []string) bool {
}
return true
}

func setupConfigWatcher(configFilePath string) {
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatalf("Error setting up watcher: %v", err)
}

// 添加一个100毫秒的Debouncing
//fileLoader := &config.ConfigFileLoader{EventDelay: 100 * time.Millisecond}

// Start the goroutine to handle file system events.
go func() {
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return // Exit if channel is closed.
}
if event.Op&fsnotify.Write == fsnotify.Write {
fmt.Println("检测到配置文件变动:", event.Name)
//fileLoader.LoadConfigF(configFilePath)
config.LoadConfig(configFilePath, true)
}
case err, ok := <-watcher.Errors:
if !ok {
return // Exit if channel is closed.
}
log.Println("Watcher error:", err)
}
}
}()

// Add the config file to the list of watched files.
err = watcher.Add(configFilePath)
if err != nil {
log.Fatalf("Error adding watcher: %v", err)
}
}

0 comments on commit 5f13c12

Please sign in to comment.