refactor: modernize codebase for Go 1.26 and fix adapter issues

- Upgrade Go version from 1.24 to 1.26.1 with updated dependencies
- Replace interface{} with any type throughout codebase
- Add message deduplication in OneBot11 adapter to prevent duplicate event processing
- URL-encode access token in WebSocket connections to handle special characters
- Remove duplicate bot startup hooks in DI providers (now handled by botManager.StartAll)
- Use slices.Clone and errgroup.Go patterns for cleaner concurrent code
- Apply omitzero JSON tags for optional fields (Go 1.24+ feature)
This commit is contained in:
lafay
2026-03-18 01:22:49 +08:00
parent f3a72264af
commit f3220a2381
32 changed files with 2262 additions and 296 deletions

View File

@@ -3,6 +3,7 @@ package engine
import (
"context"
"runtime/debug"
"slices"
"sort"
"sync"
"sync/atomic"
@@ -238,8 +239,7 @@ func (d *Dispatcher) handleEvent(ctx context.Context, event protocol.Event) {
func (d *Dispatcher) createHandlerChain(ctx context.Context, event protocol.Event) func(context.Context, protocol.Event) {
return func(ctx context.Context, e protocol.Event) {
d.mu.RLock()
handlers := make([]protocol.EventHandler, len(d.handlers))
copy(handlers, d.handlers)
handlers := slices.Clone(d.handlers)
d.mu.RUnlock()
for i, handler := range handlers {

View File

@@ -4,6 +4,7 @@ import (
"context"
"crypto/rand"
"encoding/hex"
"slices"
"sync"
"sync/atomic"
"time"
@@ -63,8 +64,7 @@ func NewEventBus(logger *zap.Logger, bufferSize int) *EventBus {
// Start 启动事件总线
func (eb *EventBus) Start() {
eb.wg.Add(1)
go eb.dispatch()
eb.wg.Go(eb.dispatch)
eb.logger.Info("Event bus started")
}
@@ -193,8 +193,6 @@ func (eb *EventBus) Unsubscribe(eventType protocol.EventType, ch chan protocol.E
// dispatch 分发事件到订阅者
func (eb *EventBus) dispatch() {
defer eb.wg.Done()
eb.logger.Info("Event bus dispatch loop started")
for {
@@ -220,8 +218,7 @@ func (eb *EventBus) dispatchEvent(event protocol.Event) {
key := string(event.GetType())
subs := eb.subscriptions[key]
// 复制订阅者列表避免锁竞争
subsCopy := make([]*Subscription, len(subs))
copy(subsCopy, subs)
subsCopy := slices.Clone(subs)
eb.mu.RUnlock()
eb.logger.Info("Dispatching event",

View File

@@ -260,14 +260,14 @@ func (m *MetricsMiddleware) Process(ctx context.Context, event protocol.Event, n
}
// GetMetrics 获取指标
func (m *MetricsMiddleware) GetMetrics() map[string]interface{} {
func (m *MetricsMiddleware) GetMetrics() map[string]any {
m.mu.RLock()
defer m.mu.RUnlock()
metrics := make(map[string]interface{})
metrics := make(map[string]any)
for eventType, count := range m.eventCounts {
avgTime := m.eventTimes[eventType] / time.Duration(count)
metrics[eventType] = map[string]interface{}{
metrics[eventType] = map[string]any{
"count": count,
"avg_time": avgTime.String(),
}

View File

@@ -599,12 +599,12 @@ func OnlyToMe() HandlerMiddleware {
selfID := event.GetSelfID()
// 检查消息段中是否包含@机器人的消息
if segments, ok := data["message_segments"].([]interface{}); ok {
if segments, ok := data["message_segments"].([]any); ok {
for _, seg := range segments {
if segMap, ok := seg.(map[string]interface{}); ok {
if segMap, ok := seg.(map[string]any); ok {
segType, _ := segMap["type"].(string)
if segType == "at" || segType == "mention" {
segData, _ := segMap["data"].(map[string]interface{})
segData, _ := segMap["data"].(map[string]any)
// 检查是否@了机器人
if userID, ok := segData["user_id"]; ok {
if userIDStr := fmt.Sprintf("%v", userID); userIDStr == selfID {

View File

@@ -329,15 +329,13 @@ func (j *IntervalJob) Start(ctx context.Context) error {
j.nextRun = time.Now().Add(j.interval)
j.mu.Unlock()
j.wg.Add(1)
go j.run()
j.wg.Go(j.run)
j.logger.Info("Interval job started", zap.Duration("interval", j.interval))
return nil
}
func (j *IntervalJob) run() {
defer j.wg.Done()
// 立即执行一次(可选,根据需求调整)
// if err := j.handler(j.ctx); err != nil {
@@ -428,16 +426,13 @@ func (j *OnceJob) Start(ctx context.Context) error {
j.nextRun = time.Now().Add(j.delay)
j.mu.Unlock()
j.wg.Add(1)
go j.run()
j.wg.Go(j.run)
j.logger.Info("Once job started", zap.Duration("delay", j.delay))
return nil
}
func (j *OnceJob) run() {
defer j.wg.Done()
select {
case <-j.timer.C:
if err := j.handler(j.ctx); err != nil {