From ef9ed26d8fa943e3c730690335a1103fa82c997e Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 11 Jan 2018 18:17:11 +0100 Subject: [PATCH] events: add event manager --- cmd/hydroxide/hydroxide.go | 9 +++-- events/events.go | 68 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 events/events.go diff --git a/cmd/hydroxide/hydroxide.go b/cmd/hydroxide/hydroxide.go index 931a678..f9b241a 100644 --- a/cmd/hydroxide/hydroxide.go +++ b/cmd/hydroxide/hydroxide.go @@ -15,6 +15,7 @@ import ( "github.com/emersion/hydroxide/auth" "github.com/emersion/hydroxide/carddav" + "github.com/emersion/hydroxide/events" "github.com/emersion/hydroxide/protonmail" smtpbackend "github.com/emersion/hydroxide/smtp" ) @@ -155,6 +156,8 @@ func main() { port = "8080" } + eventsManager := events.NewManager() + sessions := auth.NewManager(newClient) handlers := make(map[string]http.Handler) @@ -183,9 +186,9 @@ func main() { h, ok := handlers[username] if !ok { - events := make(chan *protonmail.Event) - go receiveEvents(c, "", events) - h = carddav.NewHandler(c, privateKeys, events) + ch := make(chan *protonmail.Event) + eventsManager.Register(c, username, ch) + h = carddav.NewHandler(c, privateKeys, ch) handlers[username] = h } diff --git a/events/events.go b/events/events.go new file mode 100644 index 0000000..6f513ff --- /dev/null +++ b/events/events.go @@ -0,0 +1,68 @@ +package events + +import ( + "log" + "sync" + "time" + + "github.com/emersion/hydroxide/protonmail" +) + +const pollInterval = time.Minute + +type receiver struct { + channels []chan<- *protonmail.Event + locker sync.Mutex +} + +func (r *receiver) receiveEvents(c *protonmail.Client, last string) { + t := time.NewTicker(pollInterval) + defer t.Stop() + + for range t.C { + event, err := c.GetEvent(last) + if err != nil { + log.Println("cannot receive event:", err) + continue + } + + if event.ID == last { + continue + } + last = event.ID + + r.locker.Lock() + for _, ch := range r.channels { + ch <- event + } + r.locker.Unlock() + } +} + +type Manager struct { + receivers map[string]*receiver + locker sync.Mutex +} + +func NewManager() *Manager { + return &Manager{ + receivers: make(map[string]*receiver), + } +} + +func (m *Manager) Register(c *protonmail.Client, username string, ch chan<- *protonmail.Event) { + m.locker.Lock() + defer m.locker.Unlock() + + if r, ok := m.receivers[username]; ok { + r.locker.Lock() + r.channels = append(r.channels, ch) + r.locker.Unlock() + } else { + r = &receiver{ + channels: []chan<- *protonmail.Event{ch}, + } + go r.receiveEvents(c, "") + m.receivers[username] = r + } +}