package http import ( "crypto/tls" "fmt" "net" "strings" "github.com/opencloud-eu/opencloud/pkg/broker" "github.com/opencloud-eu/opencloud/pkg/registry" netx "github.com/opencloud-eu/opencloud/pkg/x/net" mhttps "github.com/go-micro/plugins/v4/server/http" mtracer "github.com/go-micro/plugins/v4/wrapper/trace/opentelemetry" "go-micro.dev/v4" occrypto "github.com/opencloud-eu/opencloud/pkg/crypto" ) // Service simply wraps the go-micro web service. type Service struct { micro.Service } // NewService initializes a new http service. func NewService(opts ...Option) (Service, error) { noopBroker := broker.NoOp{} sopts := newOptions(opts...) var listener net.Listener var err error if sopts.TLSConfig.Enabled { var cert tls.Certificate var err error if sopts.TLSConfig.Cert != "" { cert, err = tls.LoadX509KeyPair(sopts.TLSConfig.Cert, sopts.TLSConfig.Key) if err != nil { sopts.Logger.Error().Err(err). Str("cert", sopts.TLSConfig.Cert). Str("key", sopts.TLSConfig.Key). Msg("error loading server certifcate and key") return Service{}, fmt.Errorf("error loading server certificate and key: %w", err) } } else { // Generate a self-signed server certificate on the fly. This requires the clients // to connect with InsecureSkipVerify. sopts.Logger.Warn().Str("address", sopts.Address). Msg("No server certificate configured. Generating a temporary self-signed certificate") cert, err = occrypto.GenTempCertForAddr(sopts.Address) if err != nil { return Service{}, fmt.Errorf("error creating temporary self-signed certificate: %w", err) } } tlsConfig := &tls.Config{ Certificates: []tls.Certificate{cert}, } // Create TLS listener listener, err = tls.Listen("tcp", sopts.Address, tlsConfig) if err != nil { return Service{}, fmt.Errorf("error starting TLS listener: %w", err) } } else { // Create Non-TLS listener listener, err = net.Listen("tcp", sopts.Address) if err != nil { return Service{}, fmt.Errorf("error starting TCP listener: %w", err) } } mServer := mhttps.NewServer( // Wrap listener with timeoutListener to set a read timeout mhttps.Listener(netx.TimeoutListener{ Listener: listener, ReadTimeout: sopts.TimeoutConfig.Read, }), ) wopts := []micro.Option{ micro.Server(mServer), micro.Broker(noopBroker), micro.Address(sopts.Address), micro.Name(strings.Join([]string{sopts.Namespace, sopts.Name}, ".")), micro.Version(sopts.Version), micro.Context(sopts.Context), micro.Flags(sopts.Flags...), micro.Registry(registry.GetRegistry()), micro.RegisterTTL(registry.GetRegisterTTL()), micro.RegisterInterval(registry.GetRegisterInterval()), micro.WrapClient(mtracer.NewClientWrapper( mtracer.WithTraceProvider(sopts.TraceProvider), )), micro.WrapHandler(mtracer.NewHandlerWrapper( mtracer.WithTraceProvider(sopts.TraceProvider), )), micro.WrapSubscriber(mtracer.NewSubscriberWrapper( mtracer.WithTraceProvider(sopts.TraceProvider), )), } if sopts.TLSConfig.Enabled { wopts = append(wopts, micro.Metadata(map[string]string{"use_tls": "true"})) } return Service{micro.NewService(wopts...)}, nil }