You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: eventbus.go
    path of file: ./repos/mayfly-go/server/pkg/eventbus
    
    the code of the file until where you have to start completion: package eventbus

import (
	"context"
	"errors"
	"mayfly-go/pkg/logx"
	"sync"
)

// BusSubscriber defines subscription-related bus behavior
type BusSubscriber interface {
	Subscribe(topic string, subId string, fn EventHandleFunc) error
	SubscribeAsync(topic string, subId string, fn EventHandleFunc, transactional bool) error
	SubscribeOnce(topic string, subId string, fn EventHandleFunc) error
	Unsubscribe(
    
func (bus *EventBus) Publish(ctx context.Context, topic string, val any) {
	bus.lock.Lock() // will unlock if handler is not found or always after setUpPublish
	defer bus.lock.Unlock()
	logx.Debugf("主题-[%s]-发布了事件", topic)
	event := &Event{
		Topic: topic,
		Val:   val,
	}
	subscriberManager := bus.subscriberManager[topic]
	if subscriberManager == nil {
		return
	}

	handlers := subscriberManager.handlers
	if len(handlers) == 0 {
		return
	}

	for subId, handler := range handlers {
		logx.Debugf("订阅者-[%s]-开始执行主题-[%s]-发布的事件", subId, topic)
		if handler.once {
			subscriberManager.delSubscriber(subId)
		}
		if !handler.async {
			bus.doPublish(ctx, handler, event)
		} else {
			bus.wg.Add(1)
			if handler.transactional {
				bus.lock.Unlock()
				handler.Lock()
				bus.lock.Lock()
			}
			go bus.doPublishAsync(ctx, handler, event)
		}
	}
}