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

View File

@@ -0,0 +1,48 @@
package confighelpers
import (
"fmt"
"github.com/centrifugal/centrifugo/v6/internal/configtypes"
"github.com/centrifugal/centrifugo/v6/internal/jwtutils"
"github.com/centrifugal/centrifugo/v6/internal/jwtverify"
)
func MakeVerifierConfig(tokenConf configtypes.Token) (jwtverify.VerifierConfig, error) {
cfg := jwtverify.VerifierConfig{}
cfg.HMACSecretKey = tokenConf.HMACSecretKey
cfg.HMACPreviousSecretKey = tokenConf.HMACPreviousSecretKey
cfg.HMACPreviousSecretKeyValidUntil = tokenConf.HMACPreviousSecretKeyValidUntil
rsaPublicKey := tokenConf.RSAPublicKey
if rsaPublicKey != "" {
pubKey, err := jwtutils.ParseRSAPublicKeyFromPEM([]byte(rsaPublicKey))
if err != nil {
return jwtverify.VerifierConfig{}, fmt.Errorf("error parsing RSA public key: %w", err)
}
cfg.RSAPublicKey = pubKey
}
ecdsaPublicKey := tokenConf.ECDSAPublicKey
if ecdsaPublicKey != "" {
pubKey, err := jwtutils.ParseECDSAPublicKeyFromPEM([]byte(ecdsaPublicKey))
if err != nil {
return jwtverify.VerifierConfig{}, fmt.Errorf("error parsing ECDSA public key: %w", err)
}
cfg.ECDSAPublicKey = pubKey
}
cfg.JWKSPublicEndpoint = tokenConf.JWKSPublicEndpoint
cfg.Audience = tokenConf.Audience
cfg.AudienceRegex = tokenConf.AudienceRegex
cfg.Issuer = tokenConf.Issuer
cfg.IssuerRegex = tokenConf.IssuerRegex
cfg.InsecureSkipJWKSEndpointSafetyCheck = tokenConf.InsecureSkipJWKSEndpointSafetyCheck
if tokenConf.UserIDClaim != "" {
cfg.UserIDClaim = tokenConf.UserIDClaim
}
return cfg, nil
}

View File

@@ -0,0 +1,19 @@
package confighelpers
import (
"github.com/centrifugal/centrifugo/v6/internal/configtypes"
"github.com/centrifugal/centrifuge"
)
// CentrifugeRedisMapBroker creates a centrifuge.RedisMapBroker from config types.
func CentrifugeRedisMapBroker(n *centrifuge.Node, prefix string, shards []*centrifuge.RedisShard, cfg configtypes.RedisMapBrokerCommon) (*centrifuge.RedisMapBroker, error) {
return centrifuge.NewRedisMapBroker(n, centrifuge.RedisMapBrokerConfig{
Shards: shards,
Prefix: prefix,
CleanupInterval: cfg.CleanupInterval.ToDuration(),
CleanupBatchSize: cfg.CleanupBatchSize,
IdempotentResultTTL: cfg.IdempotentResultTTL.ToDuration(),
SkipPubSub: cfg.SkipPubSub,
})
}

View File

@@ -0,0 +1,195 @@
package confighelpers
import (
"fmt"
"net"
"strings"
"github.com/centrifugal/centrifugo/v6/internal/configtypes"
"github.com/centrifugal/centrifuge"
)
func CentrifugeRedisBroker(n *centrifuge.Node, prefix string, shards []*centrifuge.RedisShard, cfg configtypes.RedisBrokerCommon, skipPubSub bool) (*centrifuge.RedisBroker, error) {
return centrifuge.NewRedisBroker(n, centrifuge.RedisBrokerConfig{
Shards: shards,
Prefix: prefix,
UseLists: cfg.UseLists,
SkipPubSub: skipPubSub,
})
}
func CentrifugeRedisPresenceManager(n *centrifuge.Node, prefix string, shards []*centrifuge.RedisShard, cfg configtypes.RedisPresenceManagerCommon) (*centrifuge.RedisPresenceManager, error) {
presenceManagerConfig := centrifuge.RedisPresenceManagerConfig{
Shards: shards,
Prefix: prefix,
PresenceTTL: cfg.PresenceTTL.ToDuration(),
UseHashFieldTTL: cfg.PresenceHashFieldTTL,
}
if cfg.PresenceUserMapping {
presenceManagerConfig.EnableUserMapping = func(_ string) bool {
return true
}
}
return centrifuge.NewRedisPresenceManager(n, presenceManagerConfig)
}
func addRedisShardCommonSettings(shardConf *centrifuge.RedisShardConfig, redisConf configtypes.Redis) error {
shardConf.DB = redisConf.DB
shardConf.User = redisConf.User
shardConf.Password = redisConf.Password
shardConf.ClientName = redisConf.ClientName
if redisConf.TLS.Enabled {
tlsConfig, err := redisConf.TLS.ToGoTLSConfig("redis")
if err != nil {
return fmt.Errorf("error creating Redis TLS config: %v", err)
}
shardConf.TLSConfig = tlsConfig
}
shardConf.ConnectTimeout = redisConf.ConnectTimeout.ToDuration()
shardConf.IOTimeout = redisConf.IOTimeout.ToDuration()
shardConf.ForceRESP2 = redisConf.ForceResp2
return nil
}
func getRedisShardConfigs(redisConf configtypes.Redis) ([]centrifuge.RedisShardConfig, error) {
var shardConfigs []centrifuge.RedisShardConfig
clusterShards := redisConf.ClusterAddress
var useCluster bool
if len(clusterShards) > 0 {
useCluster = true
}
if useCluster {
for _, clusterAddress := range clusterShards {
clusterAddresses := strings.Split(clusterAddress, ",")
for _, address := range clusterAddresses {
if _, _, err := net.SplitHostPort(address); err != nil {
return nil, fmt.Errorf("malformed Redis Cluster address: %s", address)
}
}
conf := &centrifuge.RedisShardConfig{
ClusterAddresses: clusterAddresses,
}
if err := addRedisShardCommonSettings(conf, redisConf); err != nil {
return nil, err
}
shardConfigs = append(shardConfigs, *conf)
}
return shardConfigs, nil
}
sentinelShards := redisConf.SentinelAddress
var useSentinel bool
if len(sentinelShards) > 0 {
useSentinel = true
}
if useSentinel {
for _, sentinelAddress := range sentinelShards {
sentinelAddresses := strings.Split(sentinelAddress, ",")
for _, address := range sentinelAddresses {
if _, _, err := net.SplitHostPort(address); err != nil {
return nil, fmt.Errorf("malformed Redis Sentinel address: %s", address)
}
}
conf := &centrifuge.RedisShardConfig{
SentinelAddresses: sentinelAddresses,
}
if err := addRedisShardCommonSettings(conf, redisConf); err != nil {
return nil, err
}
conf.SentinelUser = redisConf.SentinelUser
conf.SentinelPassword = redisConf.SentinelPassword
conf.SentinelMasterName = redisConf.SentinelMasterName
if conf.SentinelMasterName == "" {
return nil, fmt.Errorf("master name must be set when using Redis Sentinel")
}
conf.SentinelClientName = redisConf.SentinelClientName
if redisConf.SentinelTLS.Enabled {
tlsConfig, err := redisConf.SentinelTLS.ToGoTLSConfig("redis_sentinel")
if err != nil {
return nil, fmt.Errorf("error creating Redis Sentinel TLS config: %v", err)
}
conf.SentinelTLSConfig = tlsConfig
}
shardConfigs = append(shardConfigs, *conf)
}
return shardConfigs, nil
}
redisAddresses := redisConf.Address
if len(redisAddresses) == 0 {
redisAddresses = []string{"127.0.0.1:6379"}
}
for _, redisAddress := range redisAddresses {
conf := &centrifuge.RedisShardConfig{
Address: redisAddress,
}
if err := addRedisShardCommonSettings(conf, redisConf); err != nil {
return nil, err
}
shardConfigs = append(shardConfigs, *conf)
}
return shardConfigs, nil
}
func CentrifugeRedisShards(n *centrifuge.Node, redisConf configtypes.Redis) ([]*centrifuge.RedisShard, string, error) {
redisShardConfigs, err := getRedisShardConfigs(redisConf)
if err != nil {
return nil, "", err
}
redisShards := make([]*centrifuge.RedisShard, 0, len(redisShardConfigs))
modes := make([]string, 0, len(redisShardConfigs))
for _, shardConf := range redisShardConfigs {
redisShard, err := centrifuge.NewRedisShard(n, shardConf)
if err != nil {
return nil, "", err
}
modes = append(modes, string(redisShard.Mode()))
redisShards = append(redisShards, redisShard)
}
mode := mergeModes(modes)
if len(redisShards) > 1 {
mode = fmt.Sprintf("sharded(%d):%s", len(modes), mode)
}
return redisShards, mode, nil
}
// [cluster,cluster,standalone,sentinel,sentinel] => "cluster-x2,standalone,sentinel-x2".
func mergeModes(modes []string) string {
if len(modes) == 0 {
return ""
}
var result []string
count := 1
for i := 1; i < len(modes); i++ {
if modes[i] == modes[i-1] {
count++
} else {
if count > 1 {
result = append(result, fmt.Sprintf("%s-x%d", modes[i-1], count))
} else {
result = append(result, modes[i-1])
}
count = 1
}
}
if count > 1 {
result = append(result, fmt.Sprintf("%s-x%d", modes[len(modes)-1], count))
} else {
result = append(result, modes[len(modes)-1])
}
return strings.Join(result, ",")
}

View File

@@ -0,0 +1,46 @@
package confighelpers
import "testing"
func TestMergeModes(t *testing.T) {
tests := []struct {
input []string
expected string
}{
{
input: []string{"cluster", "cluster", "standalone", "sentinel", "sentinel", "cluster"},
expected: "cluster-x2,standalone,sentinel-x2,cluster",
},
{
input: []string{"standalone"},
expected: "standalone",
},
{
input: []string{"sentinel", "sentinel", "sentinel"},
expected: "sentinel-x3",
},
{
input: []string{"cluster", "standalone", "sentinel"},
expected: "cluster,standalone,sentinel",
},
{
input: []string{},
expected: "",
},
{
input: []string{"a", "a", "a", "b", "b", "c", "a"},
expected: "a-x3,b-x2,c,a",
},
{
input: []string{"a", "b", "b", "b", "c", "c", "d", "d", "d", "d"},
expected: "a,b-x3,c-x2,d-x4",
},
}
for _, test := range tests {
got := mergeModes(test.input)
if got != test.expected {
t.Errorf("mergeModes(%v) = %q; want %q", test.input, got, test.expected)
}
}
}