graph2, changes, rpdata-server: Added changes subscription.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package changes
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
@@ -80,10 +81,12 @@ func Submit(model, op, author string, listed bool, keys []models.ChangeKey, obje
|
||||
change.Chapters = append(change.Chapters, object)
|
||||
case []models.Chapter:
|
||||
change.Chapters = append(change.Chapters, object...)
|
||||
default:
|
||||
log.Printf("Warning: unrecognized object in change: %#+v", object)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Push to subscribers
|
||||
pushToSubscribers(change)
|
||||
|
||||
err = collection.Insert(&change)
|
||||
if err != nil {
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
package changes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"git.aiterp.net/rpdata/api/models"
|
||||
)
|
||||
|
||||
var subMutex sync.Mutex
|
||||
var subList []*subscription
|
||||
|
||||
type subscription struct {
|
||||
Keys map[string]bool
|
||||
Channel chan<- models.Change
|
||||
WildCard bool
|
||||
}
|
||||
|
||||
// Subscribe subscribes to all changes.
|
||||
func Subscribe(ctx context.Context, keys []models.ChangeKey, wildcard bool) <-chan models.Change {
|
||||
channel := make(chan models.Change, 64)
|
||||
sub := &subscription{
|
||||
Keys: make(map[string]bool, len(keys)),
|
||||
Channel: channel,
|
||||
WildCard: wildcard,
|
||||
}
|
||||
|
||||
for _, key := range keys {
|
||||
sub.Keys[mapKey(key)] = true
|
||||
}
|
||||
|
||||
subMutex.Lock()
|
||||
subList = append(subList, sub)
|
||||
subMutex.Unlock()
|
||||
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
|
||||
subMutex.Lock()
|
||||
for i := range subList {
|
||||
if subList[i] == sub {
|
||||
subList = append(subList[:i], subList[i+1:]...)
|
||||
}
|
||||
}
|
||||
subMutex.Unlock()
|
||||
}()
|
||||
|
||||
return channel
|
||||
}
|
||||
|
||||
func pushToSubscribers(change models.Change) {
|
||||
keys := make([]string, len(change.Keys))
|
||||
for i := range change.Keys {
|
||||
keys[i] = mapKey(change.Keys[i])
|
||||
}
|
||||
|
||||
subMutex.Lock()
|
||||
SubLoop:
|
||||
for _, sub := range subList {
|
||||
if sub.WildCard && change.Listed {
|
||||
select {
|
||||
case sub.Channel <- change:
|
||||
default:
|
||||
}
|
||||
} else {
|
||||
for _, key := range keys {
|
||||
if sub.Keys[key] {
|
||||
select {
|
||||
case sub.Channel <- change:
|
||||
default:
|
||||
}
|
||||
|
||||
continue SubLoop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
subMutex.Unlock()
|
||||
}
|
||||
|
||||
func mapKey(ck models.ChangeKey) string {
|
||||
return ck.Model.String() + "." + ck.ID
|
||||
}
|
||||
|
||||
func init() {
|
||||
subList = make([]*subscription, 0, 16)
|
||||
}
|
||||
Reference in New Issue
Block a user