uniform
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"log/slog"
|
||||
"net/mail"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.k6n.net/mats/go-cart-actor/internal/ucp"
|
||||
"git.k6n.net/mats/go-cart-actor/pkg/order"
|
||||
"git.k6n.net/mats/platform/config"
|
||||
"git.k6n.net/mats/platform/tax"
|
||||
)
|
||||
|
||||
// selectTaxProvider picks the tax provider from the environment. Default is
|
||||
// NordicTaxProvider with SE as the default country (matching the current
|
||||
// Nordic-only footprint). Set TAX_PROVIDER=static for dev and tests
|
||||
// (no country awareness).
|
||||
func selectTaxProvider() tax.Provider {
|
||||
provider := os.Getenv("TAX_PROVIDER")
|
||||
switch provider {
|
||||
case "static":
|
||||
return tax.NewStatic()
|
||||
case "nordic":
|
||||
return tax.NewNordic(config.EnvString("TAX_DEFAULT_COUNTRY", "SE"))
|
||||
default:
|
||||
return tax.NewNordic(config.EnvString("TAX_DEFAULT_COUNTRY", "SE"))
|
||||
}
|
||||
}
|
||||
|
||||
// selectProvider picks the payment provider from the environment. Default is
|
||||
// the dependency-free mock; set PAYMENT_PROVIDER=stripe + STRIPE_SECRET_KEY for
|
||||
// real Stripe (STRIPE_API_BASE / STRIPE_PAYMENT_METHOD optionally override).
|
||||
func selectProvider(logger *slog.Logger) order.PaymentProvider {
|
||||
if os.Getenv("PAYMENT_PROVIDER") == "stripe" {
|
||||
key := os.Getenv("STRIPE_SECRET_KEY")
|
||||
if key == "" {
|
||||
logger.Warn("PAYMENT_PROVIDER=stripe but STRIPE_SECRET_KEY is empty; falling back to mock")
|
||||
return order.NewMockProvider()
|
||||
}
|
||||
logger.Info("using stripe payment provider")
|
||||
return order.NewStripeProvider(key, os.Getenv("STRIPE_API_BASE"), os.Getenv("STRIPE_PAYMENT_METHOD"))
|
||||
}
|
||||
return order.NewMockProvider()
|
||||
}
|
||||
|
||||
// selectEmailSender picks the flow-email transport. Supports SMTP and
|
||||
// MailerSend. When no sender is configured the hook still exists in
|
||||
// capabilities but errors at run time if a flow tries to use it.
|
||||
func selectEmailSender(logger *slog.Logger) (order.EmailSender, error) {
|
||||
kind := config.EnvString("ORDER_EMAIL_SENDER", "")
|
||||
if kind == "" && os.Getenv("ORDER_EMAIL_SMTP_HOST") == "" {
|
||||
return nil, nil
|
||||
}
|
||||
if kind == "" {
|
||||
kind = "smtp"
|
||||
}
|
||||
|
||||
fromAddr := strings.TrimSpace(os.Getenv("ORDER_EMAIL_FROM_ADDRESS"))
|
||||
if fromAddr == "" {
|
||||
return nil, fmt.Errorf("ORDER_EMAIL_FROM_ADDRESS is required when email sender is configured")
|
||||
}
|
||||
from := mail.Address{
|
||||
Name: strings.TrimSpace(os.Getenv("ORDER_EMAIL_FROM_NAME")),
|
||||
Address: fromAddr,
|
||||
}
|
||||
|
||||
switch kind {
|
||||
case "smtp":
|
||||
sender, err := order.NewSMTPEmailSender(order.SMTPEmailSenderConfig{
|
||||
Host: config.EnvString("ORDER_EMAIL_SMTP_HOST", ""),
|
||||
Port: config.EnvInt("ORDER_EMAIL_SMTP_PORT", 587, func(n int) bool { return n > 0 }),
|
||||
Username: os.Getenv("ORDER_EMAIL_SMTP_USERNAME"),
|
||||
Password: os.Getenv("ORDER_EMAIL_SMTP_PASSWORD"),
|
||||
DefaultFrom: from,
|
||||
Timeout: config.EnvDuration("ORDER_EMAIL_SMTP_TIMEOUT", 10*time.Second),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logger.Info("email sender enabled", "kind", "smtp", "host", config.EnvString("ORDER_EMAIL_SMTP_HOST", ""), "from", from.Address)
|
||||
return sender, nil
|
||||
|
||||
case "mailersend":
|
||||
apiKey := os.Getenv("MAILERSEND_API_KEY")
|
||||
if apiKey == "" {
|
||||
return nil, fmt.Errorf("MAILERSEND_API_KEY is required for mailersend sender")
|
||||
}
|
||||
sender, err := order.NewMailerSendEmailSender(apiKey, from)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logger.Info("email sender enabled", "kind", "mailersend", "from", from.Address)
|
||||
return sender, nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported ORDER_EMAIL_SENDER %q (supported: smtp, mailersend)", kind)
|
||||
}
|
||||
}
|
||||
|
||||
func selectInventoryReservationService() (order.InventoryReservationService, error) {
|
||||
return order.NewHTTPInventoryReservationService(config.EnvString("INVENTORY_URL", "http://localhost:8080"), nil)
|
||||
}
|
||||
|
||||
// loadUCPOrderSigner loads the UCP ECDSA signing key from the path specified in
|
||||
// the UCP_SIGNING_KEY_PATH environment variable. Returns nil if unset or unreadable.
|
||||
func loadUCPOrderSigner() *ucp.SigningConfig {
|
||||
path := os.Getenv("UCP_SIGNING_KEY_PATH")
|
||||
if path == "" {
|
||||
return nil
|
||||
}
|
||||
pemData, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
log.Printf("ucp signing: cannot read key %s: %v", path, err)
|
||||
return nil
|
||||
}
|
||||
cfg, err := ucp.NewSigningConfigFromPEM(pemData, "k6n-ecdsa-2026")
|
||||
if err != nil {
|
||||
log.Printf("ucp signing: invalid key at %s: %v", path, err)
|
||||
return nil
|
||||
}
|
||||
return cfg
|
||||
}
|
||||
Reference in New Issue
Block a user