snapshot of https://github.com/centrifugal/centrifugo.git (master, 2026-09-16; blobs > 131072B omitted)
This commit is contained in:
31
internal/pubsub/config.go
Normal file
31
internal/pubsub/config.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package pubsub
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/centrifugal/centrifugo/v6/internal/configtypes"
|
||||
)
|
||||
|
||||
// Config configures PubSub creation.
|
||||
type Config struct {
|
||||
// Type selects the backend: "redis" (default) or "nats".
|
||||
Type string
|
||||
// Channel is the notification channel/subject name. Prefix is applied automatically.
|
||||
Channel string
|
||||
// Redis connection config. Used when Type is "redis".
|
||||
Redis configtypes.RedisEmptyPrefixed
|
||||
// Nats connection config. Used when Type is "nats".
|
||||
Nats configtypes.NatsEmptyPrefixed
|
||||
}
|
||||
|
||||
// New creates a PubSub instance from config.
|
||||
func New(cfg Config) (PubSub, error) {
|
||||
switch cfg.Type {
|
||||
case "", "redis":
|
||||
return NewRedisPubSub(cfg.Redis, cfg.Channel)
|
||||
case "nats":
|
||||
return NewNatsPubSub(cfg.Nats, cfg.Channel)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown pubsub type: %q", cfg.Type)
|
||||
}
|
||||
}
|
||||
75
internal/pubsub/nats.go
Normal file
75
internal/pubsub/nats.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package pubsub
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/centrifugal/centrifugo/v6/internal/configtypes"
|
||||
|
||||
"github.com/nats-io/nats.go"
|
||||
)
|
||||
|
||||
// NatsPubSub implements PubSub using NATS.
|
||||
type NatsPubSub struct {
|
||||
conn *nats.Conn
|
||||
subject string
|
||||
}
|
||||
|
||||
// NewNatsPubSub creates a new NATS-backed PubSub.
|
||||
// The subject is constructed as prefix + subjectName.
|
||||
func NewNatsPubSub(cfg configtypes.NatsEmptyPrefixed, subjectName string) (*NatsPubSub, error) {
|
||||
url := cfg.URL
|
||||
if url == "" {
|
||||
url = nats.DefaultURL
|
||||
}
|
||||
options := []nats.Option{
|
||||
nats.ReconnectBufSize(-1),
|
||||
nats.MaxReconnects(-1),
|
||||
}
|
||||
if dialTimeout := cfg.DialTimeout.ToDuration(); dialTimeout > 0 {
|
||||
options = append(options, nats.Timeout(dialTimeout))
|
||||
}
|
||||
if writeTimeout := cfg.WriteTimeout.ToDuration(); writeTimeout > 0 {
|
||||
options = append(options, nats.FlusherTimeout(writeTimeout))
|
||||
}
|
||||
if cfg.TLS.Enabled {
|
||||
tlsConfig, err := cfg.TLS.ToGoTLSConfig("nats_pubsub")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating NATS TLS config: %w", err)
|
||||
}
|
||||
options = append(options, nats.Secure(tlsConfig))
|
||||
}
|
||||
nc, err := nats.Connect(url, options...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error connecting to NATS for pubsub: %w", err)
|
||||
}
|
||||
return &NatsPubSub{
|
||||
conn: nc,
|
||||
subject: cfg.Prefix + subjectName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Publish sends data to the NATS subject.
|
||||
func (n *NatsPubSub) Publish(_ context.Context, data []byte) error {
|
||||
return n.conn.Publish(n.subject, data)
|
||||
}
|
||||
|
||||
// Subscribe listens on the NATS subject and calls handler for each message.
|
||||
// Blocks until ctx is cancelled.
|
||||
func (n *NatsPubSub) Subscribe(ctx context.Context, handler func(data []byte)) error {
|
||||
sub, err := n.conn.Subscribe(n.subject, func(msg *nats.Msg) {
|
||||
handler(msg.Data)
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error subscribing to NATS subject: %w", err)
|
||||
}
|
||||
defer func() { _ = sub.Unsubscribe() }()
|
||||
<-ctx.Done()
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
// Close closes the NATS connection.
|
||||
func (n *NatsPubSub) Close() error {
|
||||
n.conn.Close()
|
||||
return nil
|
||||
}
|
||||
15
internal/pubsub/pubsub.go
Normal file
15
internal/pubsub/pubsub.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package pubsub
|
||||
|
||||
import "context"
|
||||
|
||||
// PubSub provides lightweight publish/subscribe on a single channel.
|
||||
// Used for shared poll notifications — not for general-purpose messaging.
|
||||
type PubSub interface {
|
||||
// Publish sends data to the configured channel/subject.
|
||||
Publish(ctx context.Context, data []byte) error
|
||||
// Subscribe listens on the configured channel/subject and calls handler
|
||||
// for each message. Blocks until ctx is cancelled. Reconnects automatically.
|
||||
Subscribe(ctx context.Context, handler func(data []byte)) error
|
||||
// Close releases all resources.
|
||||
Close() error
|
||||
}
|
||||
51
internal/pubsub/redis.go
Normal file
51
internal/pubsub/redis.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package pubsub
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/centrifugal/centrifugo/v6/internal/configtypes"
|
||||
"github.com/centrifugal/centrifugo/v6/internal/redisshard"
|
||||
)
|
||||
|
||||
// RedisPubSub implements PubSub using Redis PUB/SUB via redisshard.
|
||||
type RedisPubSub struct {
|
||||
shards []*redisshard.RedisShard
|
||||
channel string
|
||||
}
|
||||
|
||||
// NewRedisPubSub creates a new Redis-backed PubSub.
|
||||
// The channel name is constructed as prefix + channelName.
|
||||
func NewRedisPubSub(cfg configtypes.RedisEmptyPrefixed, channelName string) (*RedisPubSub, error) {
|
||||
shards, err := redisshard.BuildRedisShards(cfg.Redis)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error building Redis shards for pubsub: %w", err)
|
||||
}
|
||||
if len(shards) == 0 {
|
||||
return nil, fmt.Errorf("no Redis shards configured for pubsub")
|
||||
}
|
||||
return &RedisPubSub{
|
||||
shards: shards,
|
||||
channel: cfg.Prefix + channelName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Publish sends data to the Redis PUB/SUB channel.
|
||||
// Uses the first shard (notification channel is a single channel).
|
||||
func (r *RedisPubSub) Publish(ctx context.Context, data []byte) error {
|
||||
return r.shards[0].Publish(ctx, r.channel, data)
|
||||
}
|
||||
|
||||
// Subscribe listens on the Redis PUB/SUB channel and calls handler for each message.
|
||||
// Blocks until ctx is cancelled.
|
||||
func (r *RedisPubSub) Subscribe(ctx context.Context, handler func(data []byte)) error {
|
||||
return r.shards[0].Subscribe(ctx, r.channel, handler)
|
||||
}
|
||||
|
||||
// Close releases all Redis shard connections.
|
||||
func (r *RedisPubSub) Close() error {
|
||||
for _, s := range r.shards {
|
||||
s.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user