mcp and ucp
This commit is contained in:
@@ -16,6 +16,7 @@ import (
|
||||
"git.k6n.net/mats/go-cart-actor/pkg/cart"
|
||||
"git.k6n.net/mats/go-cart-actor/pkg/promotions"
|
||||
promotionmcp "git.k6n.net/mats/go-cart-actor/pkg/promotions/mcp"
|
||||
"git.k6n.net/mats/go-cart-actor/internal/ucp"
|
||||
"git.k6n.net/mats/go-cart-actor/pkg/proxy"
|
||||
"git.k6n.net/mats/go-cart-actor/pkg/voucher"
|
||||
"git.k6n.net/mats/go-redis-inventory/pkg/inventory"
|
||||
@@ -66,6 +67,26 @@ func normalizeListenAddr(v string) string {
|
||||
return ":" + v
|
||||
}
|
||||
|
||||
// loadUCPCartSigner 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 loadUCPCartSigner() *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
|
||||
}
|
||||
|
||||
func getCountryFromHost(host string) string {
|
||||
if strings.Contains(strings.ToLower(host), "-no") {
|
||||
return "no"
|
||||
@@ -278,6 +299,15 @@ func main() {
|
||||
mux.Handle("/mcp", promotionMCP.Handler())
|
||||
mux.Handle("/mcp/", promotionMCP.Handler())
|
||||
|
||||
// UCP REST adapter — Universal Commerce Protocol
|
||||
cartUCP := ucp.CartHandler(pool)
|
||||
if signer := loadUCPCartSigner(); signer != nil {
|
||||
cartUCP = ucp.WithSigning(cartUCP, signer)
|
||||
log.Print("ucp signing enabled")
|
||||
}
|
||||
mux.Handle("/ucp/v1/carts", cartUCP)
|
||||
mux.Handle("/ucp/v1/carts/", cartUCP)
|
||||
|
||||
// Stateless promotion evaluation: POST a (possibly partial) eval context and
|
||||
// get back the resulting totals plus the applied/pending effect breakdown,
|
||||
// without creating or mutating a real cart.
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"os/signal"
|
||||
"time"
|
||||
|
||||
"git.k6n.net/mats/go-cart-actor/internal/ucp"
|
||||
"git.k6n.net/mats/go-cart-actor/pkg/actor"
|
||||
"git.k6n.net/mats/go-cart-actor/pkg/checkout"
|
||||
"git.k6n.net/mats/go-cart-actor/pkg/proxy"
|
||||
@@ -48,6 +49,26 @@ var redisAddress = os.Getenv("REDIS_ADDRESS")
|
||||
var redisPassword = os.Getenv("REDIS_PASSWORD")
|
||||
var cartInternalUrl = os.Getenv("CART_INTERNAL_URL") // e.g., http://cart-service:8081
|
||||
|
||||
// loadUCPCheckoutSigner 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 loadUCPCheckoutSigner() *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
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
controlPlaneConfig := actor.DefaultServerConfig()
|
||||
@@ -160,6 +181,22 @@ func main() {
|
||||
|
||||
syncedServer.Serve(mux)
|
||||
|
||||
// UCP REST adapter — Universal Commerce Protocol checkout sessions
|
||||
// When an order service URL is configured, the complete endpoint creates
|
||||
// real orders via the order service's from-checkout API.
|
||||
var ucpOrderSvc ucp.OrderApplier
|
||||
if orderServiceURL := os.Getenv("ORDER_SERVICE_URL"); orderServiceURL != "" {
|
||||
ucpOrderSvc = ucp.NewOrderHTTPClient(orderServiceURL)
|
||||
log.Printf("ucp order applier enabled: %s", orderServiceURL)
|
||||
}
|
||||
checkoutUCP := ucp.CheckoutHandler(pool, ucpOrderSvc)
|
||||
if signer := loadUCPCheckoutSigner(); signer != nil {
|
||||
checkoutUCP = ucp.WithSigning(checkoutUCP, signer)
|
||||
log.Print("ucp signing enabled")
|
||||
}
|
||||
mux.Handle("/ucp/v1/checkout-sessions", checkoutUCP)
|
||||
mux.Handle("/ucp/v1/checkout-sessions/", checkoutUCP)
|
||||
|
||||
mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
|
||||
grainCount, capacity := pool.LocalUsage()
|
||||
if grainCount >= capacity {
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.k6n.net/mats/go-cart-actor/internal/ucp"
|
||||
"git.k6n.net/mats/go-cart-actor/pkg/actor"
|
||||
"git.k6n.net/mats/go-cart-actor/pkg/flow"
|
||||
"git.k6n.net/mats/go-cart-actor/pkg/idempotency"
|
||||
@@ -155,6 +156,15 @@ func main() {
|
||||
mux.HandleFunc("POST /api/orders/{id}/returns", s.handleReturn)
|
||||
mux.HandleFunc("POST /api/orders/{id}/refunds", s.handleRefund)
|
||||
|
||||
// UCP REST adapter — Universal Commerce Protocol order lifecycle.
|
||||
orderUCP := ucp.OrderHandler(s.applier)
|
||||
if signer := loadUCPOrderSigner(); signer != nil {
|
||||
orderUCP = ucp.WithSigning(orderUCP, signer)
|
||||
logger.Info("ucp signing enabled")
|
||||
}
|
||||
mux.Handle("/ucp/v1/orders", orderUCP)
|
||||
mux.Handle("/ucp/v1/orders/", orderUCP)
|
||||
|
||||
// Saga / flow admin (backoffice editor).
|
||||
mux.HandleFunc("GET /sagas/capabilities", s.handleCapabilities)
|
||||
mux.HandleFunc("GET /sagas/flows", s.handleListFlows)
|
||||
@@ -444,6 +454,26 @@ func selectProvider(logger *slog.Logger) order.PaymentProvider {
|
||||
return order.NewMockProvider()
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
func envOr(key, def string) string {
|
||||
if v := os.Getenv(key); v != "" {
|
||||
return v
|
||||
|
||||
Reference in New Issue
Block a user