func()

in banyand/liaison/http/server.go [135:244]


func (p *server) PreRun(_ context.Context) error {
	p.l = logger.GetLogger(p.Name())
	p.l.Info().Str("level", p.l.GetLevel().String()).Msg("Logger initialized")

	// Log flag values after parsing
	p.l.Debug().Bool("tls", p.tls).Str("certFile", p.certFile).Str("keyFile", p.keyFile).Msg("Flag values after parsing")

	// Initialize TLSReloader if TLS is enabled
	p.l.Debug().Bool("tls", p.tls).Msg("HTTP TLS flag is set")
	if p.tls {
		p.l.Debug().Str("certFile", p.certFile).Str("keyFile", p.keyFile).Msg("Initializing TLSReloader for HTTP")
		var err error
		p.tlsReloader, err = pkgtls.NewReloader(p.certFile, p.keyFile, p.l)
		if err != nil {
			p.l.Error().Err(err).Msg("Failed to initialize TLSReloader for HTTP")
			return err
		}
	} else {
		p.l.Warn().Msg("HTTP TLS is disabled, skipping TLSReloader initialization")
	}

	// Initialize gRPC client with cert file
	if p.grpcCert != "" {
		p.l.Debug().Str("grpcCert", p.grpcCert).Msg("Initializing TLS credentials for gRPC connection")

		// Create a client cert reloader that only watches the cert file
		var err error
		p.grpcTLSReloader, err = pkgtls.NewClientCertReloader(p.grpcCert, p.l)
		if err != nil {
			p.l.Error().Err(err).Msg("Failed to initialize gRPC TLS reloader")
			return err
		}

		// Start the reloader
		if err = p.grpcTLSReloader.Start(); err != nil {
			p.l.Error().Err(err).Msg("Failed to start gRPC TLS reloader")
			return err
		}

		// Get the update channel from the reloader
		certUpdateCh := p.grpcTLSReloader.GetUpdateChannel()

		p.l.Info().Msg("Starting certificate update notification listener")

		// Start a goroutine to watch for certificate update events
		go func() {
			p.l.Info().Msg("Certificate update notification goroutine started")

			for {
				select {
				case <-certUpdateCh:
					// Certificate was updated, let's debounce to handle potential multiple notifications
					p.l.Info().Msg("Received certificate update notification")

					// Debounce multiple notifications that might come in rapid succession
					func() {
						p.l.Info().Msg("Processing certificate update after debounce")

						// Cancel existing gRPC connections
						prevGRPCCancel := p.grpcCancel
						if prevGRPCCancel != nil {
							defer func() {
								p.l.Info().Msg("Canceling existing gRPC connections")
								prevGRPCCancel()
							}()
						}

						// Create a new context for the new connections
						p.grpcCtx, p.grpcCancel = context.WithCancel(context.Background())

						// Force a short delay to ensure all resources are properly cleaned up
						time.Sleep(200 * time.Millisecond)

						// Re-create the gateway with updated credentials
						if p.gwMux != nil {
							p.l.Info().Msg("Re-creating gateway with updated credentials")
						}

						// Reinitialize the gRPC client (which will get fresh credentials from the reloader)
						if err := p.initGRPCClient(); err != nil {
							p.l.Error().Err(err).Msg("Failed to reinitialize gRPC client after credential update")
						} else {
							p.l.Info().Msg("Successfully reinitialized gRPC client with new credentials")
						}
					}()

				case <-p.stopCh:
					p.l.Info().Msg("Stopping certificate update notification listener")
					return
				}
			}
		}()
	}

	p.handlerWrapper = &atomicHandler{}

	// Configure the HTTP server with dynamic TLS if enabled
	p.srv = &http.Server{
		Addr:              p.listenAddr,
		Handler:           p.handlerWrapper,
		ReadHeaderTimeout: 3 * time.Second,
		WriteTimeout:      30 * time.Second,
		IdleTimeout:       60 * time.Second,
	}
	if p.tls {
		p.srv.TLSConfig = p.tlsReloader.GetTLSConfig()
	}

	return nil
}