golang 实现 EventTarget

36 阅读1分钟
package event

type Event struct {
  Type string
  data interface{}
}

func NewEvent(eventType string, data interface{}) Event {
  return Event{
    Type: eventType,
    data: data,
  }
}

func (e *Event) Data() interface{} {
  return e.Data
}

type EventChan chan Event

type EventTarget struct {
  listeners map[string][]func(Event)
  mu sync.RWMutex
}

func NewEventTarget() *EventTarget {
  return &EventTarget{
    listeners: make(map[string][]func(Event)),
  }
}

func (et *EventTarget) AddListener(eventType string, listener func(Event)) {
  et.mu.Lock()
  defer et.mu.Unlock()
  
  if _, ok := et.listeners[eventType]; !ok {
    et.listeners[eventType] = make([]func(Event), 0)
  }
  et.listeners[eventType] = append(et.listeners[eventType], listener)
}

func (et *EventTarget) RemoveListener(eventType string, listener func(Event)) {
  et.mu.Lock()
  defer et.mu.Unlock()
  if listeners, ok := et.listeners[eventType]; ok {
    for i, l := range listeners {
      if fmt.Sprintf("%p", l) == fmt.Sprintf("%p", listener) {
        et.listeners[eventType] = append(listeners[:i], listeners[i+1:]...)
        break
      }
    }
  }
}

func (et *EventTarget) Dispatch(event Event) {
  et.mu.RLock()
  et.mu.RUnlock()
  if listeners, ok := et.listeners[event.Type]; ok {
    for _, l := range listeners {
      l(event)
    }
  }
}

func (et *EventTarget) WaitForEvent(eventType string, timeout time.Duration) (Event, error) {
  eventChan := make(EventChan, 1)
  listener := func(event Event) {
    select {
      case eventChan <- event
      default:
    }
  }
  et.AddListener(eventType, listener)
  defer et.RemoveListener(eventType, listener)
  select {
    case targetEvent := <- eventChan:
      return targetEvent, nil
    case <-time.After(timeout):
      return Event{}, errors.New(fmt.Sprintf("timeout %v", timeout))
  }
}