package setup import ( "context" "crypto/tls" "crypto/x509" "fmt" "os" "sync" "github.com/dariuszjaniak/warp/server/internal/federationapi" "github.com/dariuszjaniak/warp/server/internal/roomserver" "github.com/dariuszjaniak/warp/server/internal/storage" ) // fanout is the roomserver's emit stage when more than one thing listens: // the sync notifier, which wakes long polls, and the federation queue, // which sends events to other servers. // // Each listener is held to the roomserver's rule for a Notifier — never // block — so calling them in turn under the room lock is fine. type fanout struct { mu sync.RWMutex listeners []roomserver.Notifier } func (f *fanout) add(n roomserver.Notifier) { f.mu.Lock() defer f.mu.Unlock() f.listeners = append(f.listeners, n) } // EventPersisted implements roomserver.Notifier. func (f *fanout) EventPersisted(ctx context.Context, n roomserver.Notification) { f.mu.RLock() defer f.mu.RUnlock() for _, l := range f.listeners { l.EventPersisted(ctx, n) } } // federationStatus adapts the module to the admin API. type federationStatus struct { module *federationapi.Module } func (s federationStatus) Running() bool { return s.module.Running() } func (s federationStatus) Destinations(ctx context.Context) ([]storage.DestinationSummary, error) { return s.module.Queue().Destinations(ctx) } func (s federationStatus) ResetBackoff(ctx context.Context, serverName string) error { return s.module.Queue().ResetBackoff(ctx, serverName) } // federationTLS builds the client TLS configuration for outbound // federation: the system roots, plus a configured CA bundle. func federationTLS(caFile string) (*tls.Config, error) { cfg := &tls.Config{MinVersion: tls.VersionTLS12} if caFile == "" { return cfg, nil } pool, err := x509.SystemCertPool() if err != nil || pool == nil { pool = x509.NewCertPool() } pem, err := os.ReadFile(caFile) if err != nil { return nil, fmt.Errorf("read federation.tls_ca_file: %w", err) } if !pool.AppendCertsFromPEM(pem) { return nil, fmt.Errorf("federation.tls_ca_file %s contains no PEM certificates", caFile) } cfg.RootCAs = pool return cfg, nil }