snapshot of https://github.com/centrifugal/centrifugo.git (master, 2026-09-16; blobs > 131072B omitted)
Some checks failed
test / Lint (push) Failing after 3s
test / Test with Go 1.26.8 (push) Failing after 2s

This commit is contained in:
upstream-mirror
2026-09-16 01:17:21 +05:00
commit b352a9a30d
472 changed files with 108375 additions and 0 deletions

31
internal/pubsub/config.go Normal file
View 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
View 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
View 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
View 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
}