1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-11-17 01:53:36 -05:00

map based subscriber list

This commit is contained in:
Darien Raymond 2018-07-01 19:30:05 +02:00
parent 4c18b61e6c
commit b23b218a7e
No known key found for this signature in database
GPG Key ID: 7251FFA14BB18169
2 changed files with 36 additions and 30 deletions

View File

@ -5,13 +5,13 @@ import (
"time" "time"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/common/signal/done"
"v2ray.com/core/common/task" "v2ray.com/core/common/task"
) )
type Subscriber struct { type Subscriber struct {
name string buffer chan interface{}
buffer chan interface{} done *done.Instance
removed chan struct{}
} }
func (s *Subscriber) push(msg interface{}) { func (s *Subscriber) push(msg interface{}) {
@ -25,62 +25,66 @@ func (s *Subscriber) Wait() <-chan interface{} {
return s.buffer return s.buffer
} }
func (s *Subscriber) Close() { func (s *Subscriber) Close() error {
close(s.removed) return s.done.Close()
} }
func (s *Subscriber) IsClosed() bool { func (s *Subscriber) IsClosed() bool {
select { return s.done.Done()
case <-s.removed:
return true
default:
return false
}
} }
type Service struct { type Service struct {
sync.RWMutex sync.RWMutex
subs []*Subscriber subs map[string][]*Subscriber
ctask *task.Periodic ctask *task.Periodic
} }
func NewService() *Service { func NewService() *Service {
s := &Service{} s := &Service{
subs: make(map[string][]*Subscriber),
}
s.ctask = &task.Periodic{ s.ctask = &task.Periodic{
Execute: s.cleanup, Execute: s.Cleanup,
Interval: time.Second * 30, Interval: time.Second * 30,
} }
common.Must(s.ctask.Start()) common.Must(s.ctask.Start())
return s return s
} }
func (s *Service) cleanup() error { // Cleanup cleans up internal caches of subscribers.
// Visible for testing only.
func (s *Service) Cleanup() error {
s.Lock() s.Lock()
defer s.Unlock() defer s.Unlock()
if len(s.subs) < 16 { for name, subs := range s.subs {
return nil newSub := make([]*Subscriber, 0, len(s.subs))
} for _, sub := range subs {
if !sub.IsClosed() {
newSub := make([]*Subscriber, 0, len(s.subs)) newSub = append(newSub, sub)
for _, sub := range s.subs { }
if !sub.IsClosed() { }
newSub = append(newSub, sub) if len(newSub) == 0 {
delete(s.subs, name)
} else {
s.subs[name] = newSub
} }
} }
s.subs = newSub if len(s.subs) == 0 {
s.subs = make(map[string][]*Subscriber)
}
return nil return nil
} }
func (s *Service) Subscribe(name string) *Subscriber { func (s *Service) Subscribe(name string) *Subscriber {
sub := &Subscriber{ sub := &Subscriber{
name: name, buffer: make(chan interface{}, 16),
buffer: make(chan interface{}, 16), done: done.New(),
removed: make(chan struct{}),
} }
s.Lock() s.Lock()
s.subs = append(s.subs, sub) subs := append(s.subs[name], sub)
s.subs[name] = subs
s.Unlock() s.Unlock()
return sub return sub
} }
@ -89,8 +93,8 @@ func (s *Service) Publish(name string, message interface{}) {
s.RLock() s.RLock()
defer s.RUnlock() defer s.RUnlock()
for _, sub := range s.subs { for _, sub := range s.subs[name] {
if sub.name == name && !sub.IsClosed() { if !sub.IsClosed() {
sub.push(message) sub.push(message)
} }
} }

View File

@ -30,4 +30,6 @@ func TestPubsub(t *testing.T) {
t.Fail() t.Fail()
default: default:
} }
service.Cleanup()
} }