1 Star 1 Fork 0

carlzyhuang/framework

加入 Gitee
与超过 1400万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
event.go 2.38 KB
一键复制 编辑 原始数据 按行查看 历史
huangzhiyong 提交于 2025-10-24 15:24 +08:00 . 修复路径名称
package eventbus
import (
"fmt"
"reflect"
"runtime/debug"
"sync"
"unsafe"
"gitee.com/carlzyhuang/framework/log"
)
type event interface {
subscribe(f interface{}) error
unsubscribe(f interface{})
publish(arg interface{}) error
}
type subscriber struct {
f interface{}
k uint64
}
type eventT[T any] struct {
sync.RWMutex
subscribers []subscriber // 订阅者列表
subscribersWithErr []subscriber // 订阅者列表(带error返回)
}
// 订阅事件
func (e *eventT[T]) subscribe(f interface{}) error {
e.Lock()
defer e.Unlock()
key := uint64(uintptr((*[2]unsafe.Pointer)(unsafe.Pointer(&f))[1]))
if _, ok := f.(func(T)); ok {
for _, s := range e.subscribers {
if s.k == key {
return fmt.Errorf("repeat subscribe: %d-%s", key, reflect.TypeOf(f).String())
}
}
e.subscribers = append(e.subscribers, subscriber{f: f, k: key})
} else if _, ok := f.(func(T) error); ok {
for _, s := range e.subscribersWithErr {
if s.k == key {
return fmt.Errorf("repeat subscribe: %d-%s", key, reflect.TypeOf(f).String())
}
}
e.subscribersWithErr = append(e.subscribersWithErr, subscriber{f: f, k: key})
} else {
vt := reflect.TypeOf((*T)(nil)).Elem()
return fmt.Errorf("handler[%s] should be func(arg %s) or func(arg %s) error",
reflect.TypeOf(f).String(), vt.Name(), vt.Name())
}
return nil
}
func (e *eventT[T]) unsubscribe(f interface{}) {
e.Lock()
defer e.Unlock()
key := uint64(uintptr((*[2]unsafe.Pointer)(unsafe.Pointer(&f))[1]))
if _, ok := f.(func(T)); ok {
e.subscribers = e.remove(e.subscribers, key)
} else if _, ok := f.(func(T) error); ok {
e.subscribersWithErr = e.remove(e.subscribersWithErr, key)
}
}
func (e *eventT[T]) remove(subscribers []subscriber, key uint64) []subscriber {
for i, s := range subscribers {
if s.k == key {
return append(subscribers[:i], subscribers[i+1:]...)
}
}
return subscribers
}
// 发布事件
func (e *eventT[T]) publish(v interface{}) error {
defer func() {
if err := recover(); err != nil {
log.Errorf("panic: %+v\n%s", err, debug.Stack())
}
}()
arg, ok := v.(T)
if !ok {
return fmt.Errorf("invalid type: %s", reflect.TypeOf(v).String())
}
e.RLock()
defer e.RUnlock()
for _, s := range e.subscribers {
s.f.(func(T))(arg)
}
// 第一个出错就中止
for _, s := range e.subscribersWithErr {
if err := s.f.(func(T) error)(arg); err != nil {
return err
}
}
return nil
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/carlzyhuang/framework.git
git@gitee.com:carlzyhuang/framework.git
carlzyhuang
framework
framework
v0.0.18

搜索帮助