mirror of https://github.com/v2ray/v2ray-core
pubsub
parent
a540d7dc99
commit
b6ed26aedf
|
@ -10,6 +10,7 @@ import (
|
||||||
type SpaceController struct {
|
type SpaceController struct {
|
||||||
packetDispatcher internal.PacketDispatcherWithContext
|
packetDispatcher internal.PacketDispatcherWithContext
|
||||||
dnsCache internal.DnsCacheWithContext
|
dnsCache internal.DnsCacheWithContext
|
||||||
|
pubsub internal.PubsubWithContext
|
||||||
}
|
}
|
||||||
|
|
||||||
func New() *SpaceController {
|
func New() *SpaceController {
|
||||||
|
@ -24,8 +25,12 @@ func (this *SpaceController) Bind(object interface{}) {
|
||||||
if dnsCache, ok := object.(internal.DnsCacheWithContext); ok {
|
if dnsCache, ok := object.(internal.DnsCacheWithContext); ok {
|
||||||
this.dnsCache = dnsCache
|
this.dnsCache = dnsCache
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if pubsub, ok := object.(internal.PubsubWithContext); ok {
|
||||||
|
this.pubsub = pubsub
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *SpaceController) ForContext(tag string) app.Space {
|
func (this *SpaceController) ForContext(tag string) app.Space {
|
||||||
return internal.NewSpace(tag, this.packetDispatcher, this.dnsCache)
|
return internal.NewSpace(tag, this.packetDispatcher, this.dnsCache, this.pubsub)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/v2ray/v2ray-core/app"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PubsubWithContext interface {
|
||||||
|
Publish(context app.Context, topic string, message app.PubsubMessage)
|
||||||
|
Subscribe(context app.Context, topic string, handler app.TopicHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
type contextedPubsub struct {
|
||||||
|
context app.Context
|
||||||
|
pubsub PubsubWithContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *contextedPubsub) Publish(topic string, message app.PubsubMessage) {
|
||||||
|
this.pubsub.Publish(this.context, topic, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *contextedPubsub) Subscribe(topic string, handler app.TopicHandler) {
|
||||||
|
this.pubsub.Subscribe(this.context, topic, handler)
|
||||||
|
}
|
|
@ -7,14 +7,16 @@ import (
|
||||||
type Space struct {
|
type Space struct {
|
||||||
packetDispatcher PacketDispatcherWithContext
|
packetDispatcher PacketDispatcherWithContext
|
||||||
dnsCache DnsCacheWithContext
|
dnsCache DnsCacheWithContext
|
||||||
|
pubsub PubsubWithContext
|
||||||
tag string
|
tag string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSpace(tag string, packetDispatcher PacketDispatcherWithContext, dnsCache DnsCacheWithContext) *Space {
|
func NewSpace(tag string, packetDispatcher PacketDispatcherWithContext, dnsCache DnsCacheWithContext, pubsub PubsubWithContext) *Space {
|
||||||
return &Space{
|
return &Space{
|
||||||
tag: tag,
|
tag: tag,
|
||||||
packetDispatcher: packetDispatcher,
|
packetDispatcher: packetDispatcher,
|
||||||
dnsCache: dnsCache,
|
dnsCache: dnsCache,
|
||||||
|
pubsub: pubsub,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,3 +45,16 @@ func (this *Space) DnsCache() app.DnsCache {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *Space) HasPubsub() bool {
|
||||||
|
return this.pubsub != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Space) Pubsub() app.Pubsub {
|
||||||
|
return &contextedPubsub{
|
||||||
|
pubsub: this.pubsub,
|
||||||
|
context: &contextImpl{
|
||||||
|
callerTag: this.tag,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package app
|
||||||
|
|
||||||
|
type PubsubMessage []byte
|
||||||
|
type TopicHandler func(PubsubMessage)
|
||||||
|
|
||||||
|
type Pubsub interface {
|
||||||
|
Publish(topic string, message PubsubMessage)
|
||||||
|
Subscribe(topic string, handler TopicHandler)
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
package pubsub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/v2ray/v2ray-core/app"
|
||||||
|
"github.com/v2ray/v2ray-core/app/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TopicHandlerList struct {
|
||||||
|
sync.RWMutex
|
||||||
|
handlers []app.TopicHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTopicHandlerList(handlers ...app.TopicHandler) *TopicHandlerList {
|
||||||
|
return &TopicHandlerList{
|
||||||
|
handlers: handlers,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *TopicHandlerList) Add(handler app.TopicHandler) {
|
||||||
|
this.Lock()
|
||||||
|
this.handlers = append(this.handlers, handler)
|
||||||
|
this.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *TopicHandlerList) Dispatch(message app.PubsubMessage) {
|
||||||
|
this.RLock()
|
||||||
|
for _, handler := range this.handlers {
|
||||||
|
go handler(message)
|
||||||
|
}
|
||||||
|
this.RUnlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
type Pubsub struct {
|
||||||
|
topics map[string]*TopicHandlerList
|
||||||
|
sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() internal.PubsubWithContext {
|
||||||
|
return &Pubsub{
|
||||||
|
topics: make(map[string]*TopicHandlerList),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Pubsub) Publish(context app.Context, topic string, message app.PubsubMessage) {
|
||||||
|
this.RLock()
|
||||||
|
list, found := this.topics[topic]
|
||||||
|
this.RUnlock()
|
||||||
|
|
||||||
|
if found {
|
||||||
|
list.Dispatch(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Pubsub) Subscribe(context app.Context, topic string, handler app.TopicHandler) {
|
||||||
|
this.Lock()
|
||||||
|
defer this.Unlock()
|
||||||
|
if list, found := this.topics[topic]; found {
|
||||||
|
list.Add(handler)
|
||||||
|
} else {
|
||||||
|
this.topics[topic] = NewTopicHandlerList(handler)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package pubsub_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/v2ray/v2ray-core/app"
|
||||||
|
. "github.com/v2ray/v2ray-core/app/pubsub"
|
||||||
|
apptesting "github.com/v2ray/v2ray-core/app/testing"
|
||||||
|
v2testing "github.com/v2ray/v2ray-core/testing"
|
||||||
|
"github.com/v2ray/v2ray-core/testing/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPubsub(t *testing.T) {
|
||||||
|
v2testing.Current(t)
|
||||||
|
|
||||||
|
messages := make(map[string]app.PubsubMessage)
|
||||||
|
|
||||||
|
pubsub := New()
|
||||||
|
pubsub.Subscribe(&apptesting.Context{}, "t1", func(message app.PubsubMessage) {
|
||||||
|
messages["t1"] = message
|
||||||
|
})
|
||||||
|
|
||||||
|
pubsub.Subscribe(&apptesting.Context{}, "t2", func(message app.PubsubMessage) {
|
||||||
|
messages["t2"] = message
|
||||||
|
})
|
||||||
|
|
||||||
|
message := app.PubsubMessage([]byte("This is a pubsub message."))
|
||||||
|
pubsub.Publish(&apptesting.Context{}, "t2", message)
|
||||||
|
<-time.Tick(time.Second)
|
||||||
|
|
||||||
|
_, found := messages["t1"]
|
||||||
|
assert.Bool(found).IsFalse()
|
||||||
|
|
||||||
|
actualMessage, found := messages["t2"]
|
||||||
|
assert.Bool(found).IsTrue()
|
||||||
|
assert.StringLiteral(string(actualMessage)).Equals(string(message))
|
||||||
|
}
|
|
@ -13,4 +13,7 @@ type Space interface {
|
||||||
|
|
||||||
HasDnsCache() bool
|
HasDnsCache() bool
|
||||||
DnsCache() DnsCache
|
DnsCache() DnsCache
|
||||||
|
|
||||||
|
HasPubsub() bool
|
||||||
|
Pubsub() Pubsub
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
package command
|
||||||
|
|
||||||
|
type ResponseCmd byte
|
Loading…
Reference in New Issue