major refactor
This commit is contained in:
229
pool-server.go
229
pool-server.go
@@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
@@ -274,7 +273,7 @@ or panic-on-error helper:
|
||||
id := MustNewCartId()
|
||||
*/
|
||||
|
||||
func CookieCartIdHandler(fn func(w http.ResponseWriter, r *http.Request, cartId CartId) error) func(w http.ResponseWriter, r *http.Request) error {
|
||||
func CookieCartIdHandler(fn func(cartId CartId, w http.ResponseWriter, r *http.Request) error) func(w http.ResponseWriter, r *http.Request) error {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
var id CartId
|
||||
cookie, err := r.Cookie("cartid")
|
||||
@@ -308,12 +307,12 @@ func CookieCartIdHandler(fn func(w http.ResponseWriter, r *http.Request, cartId
|
||||
id = parsed
|
||||
}
|
||||
}
|
||||
if ownershipProxyAfterExtraction != nil {
|
||||
if handled, err := ownershipProxyAfterExtraction(id, w, r); handled || err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return fn(w, r, id)
|
||||
// if ownershipProxyAfterExtraction != nil {
|
||||
// if handled, err := ownershipProxyAfterExtraction(id, w, r); handled || err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
return fn(id, w, r)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,103 +333,113 @@ func (s *PoolServer) RemoveCartCookie(w http.ResponseWriter, r *http.Request, ca
|
||||
return nil
|
||||
}
|
||||
|
||||
func CartIdHandler(fn func(w http.ResponseWriter, r *http.Request, cartId CartId) error) func(w http.ResponseWriter, r *http.Request) error {
|
||||
func CartIdHandler(fn func(cartId CartId, w http.ResponseWriter, r *http.Request) error) func(w http.ResponseWriter, r *http.Request) error {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
raw := r.PathValue("id")
|
||||
// If no id supplied, generate a new one
|
||||
if raw == "" {
|
||||
id := MustNewCartId()
|
||||
w.Header().Set("Set-Cart-Id", id.String())
|
||||
if ownershipProxyAfterExtraction != nil {
|
||||
if handled, err := ownershipProxyAfterExtraction(id, w, r); handled || err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return fn(w, r, id)
|
||||
|
||||
return fn(id, w, r)
|
||||
}
|
||||
// Parse base62 cart id
|
||||
id, ok := ParseCartId(raw)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid cart id format")
|
||||
}
|
||||
if ownershipProxyAfterExtraction != nil {
|
||||
if handled, err := ownershipProxyAfterExtraction(id, w, r); handled || err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return fn(w, r, id)
|
||||
|
||||
return fn(id, w, r)
|
||||
}
|
||||
}
|
||||
|
||||
var ownershipProxyAfterExtraction func(cartId CartId, w http.ResponseWriter, r *http.Request) (handled bool, err error)
|
||||
func (s *PoolServer) ProxyHandler(fn func(w http.ResponseWriter, r *http.Request, cartId CartId) error) func(cartId CartId, w http.ResponseWriter, r *http.Request) error {
|
||||
return func(cartId CartId, w http.ResponseWriter, r *http.Request) error {
|
||||
if ownerHost, ok := s.pool.OwnerHost(cartId); ok {
|
||||
ok, err := ownerHost.Proxy(cartId, w, r)
|
||||
if ok || err != nil {
|
||||
log.Printf("proxy failed: %v", err)
|
||||
// todo take ownership!!
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
// Local ownership or no owner known, proceed with local handling
|
||||
|
||||
return fn(w, r, cartId)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//var ownershipProxyAfterExtraction func(cartId CartId, w http.ResponseWriter, r *http.Request) (handled bool, err error)
|
||||
|
||||
func (s *PoolServer) Serve() *http.ServeMux {
|
||||
// Install ownership proxy hook that runs AFTER id extraction (cookie OR path)
|
||||
ownershipProxyAfterExtraction = func(cartId CartId, w http.ResponseWriter, r *http.Request) (bool, error) {
|
||||
if cartId.String() == "" {
|
||||
return false, nil
|
||||
}
|
||||
owner := s.pool.OwnerHost(cartId)
|
||||
if owner == "" || owner == s.pool.Hostname() {
|
||||
// Set / refresh cartowner cookie pointing to the local host (claim or already owned).
|
||||
localHost := owner
|
||||
if localHost == "" {
|
||||
localHost = s.pool.Hostname()
|
||||
}
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "cartowner",
|
||||
Value: localHost,
|
||||
Path: "/",
|
||||
HttpOnly: true,
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
})
|
||||
return false, nil
|
||||
}
|
||||
// For remote ownership set cartowner cookie to remote host for sticky sessions.
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "cartowner",
|
||||
Value: owner,
|
||||
Path: "/",
|
||||
HttpOnly: true,
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
})
|
||||
// Proxy logic (simplified): reuse existing request to owning host on same port.
|
||||
target := "http://" + owner + r.URL.Path
|
||||
if q := r.URL.RawQuery; q != "" {
|
||||
target += "?" + q
|
||||
}
|
||||
req, err := http.NewRequestWithContext(r.Context(), r.Method, target, r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, "proxy build error", http.StatusBadGateway)
|
||||
return true, err
|
||||
}
|
||||
for k, v := range r.Header {
|
||||
for _, vv := range v {
|
||||
req.Header.Add(k, vv)
|
||||
}
|
||||
}
|
||||
req.Header.Set("X-Forwarded-Host", r.Host)
|
||||
req.Header.Set("X-Cart-Id", cartId.String())
|
||||
req.Header.Set("X-Cart-Owner", owner)
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
http.Error(w, "proxy upstream error", http.StatusBadGateway)
|
||||
return true, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
for k, v := range resp.Header {
|
||||
for _, vv := range v {
|
||||
w.Header().Add(k, vv)
|
||||
}
|
||||
}
|
||||
w.Header().Set("X-Cart-Owner-Routed", "true")
|
||||
w.WriteHeader(resp.StatusCode)
|
||||
_, copyErr := io.Copy(w, resp.Body)
|
||||
if copyErr != nil {
|
||||
return true, copyErr
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
// // Install ownership proxy hook that runs AFTER id extraction (cookie OR path)
|
||||
// ownershipProxyAfterExtraction = func(cartId CartId, w http.ResponseWriter, r *http.Request) (bool, error) {
|
||||
// if cartId.String() == "" {
|
||||
// return false, nil
|
||||
// }
|
||||
// owner := s.pool.OwnerHost(cartId)
|
||||
// if owner == "" || owner == s.pool.Hostname() {
|
||||
// // Set / refresh cartowner cookie pointing to the local host (claim or already owned).
|
||||
// localHost := owner
|
||||
// if localHost == "" {
|
||||
// localHost = s.pool.Hostname()
|
||||
// }
|
||||
// http.SetCookie(w, &http.Cookie{
|
||||
// Name: "cartowner",
|
||||
// Value: localHost,
|
||||
// Path: "/",
|
||||
// HttpOnly: true,
|
||||
// SameSite: http.SameSiteLaxMode,
|
||||
// })
|
||||
// return false, nil
|
||||
// }
|
||||
// // For remote ownership set cartowner cookie to remote host for sticky sessions.
|
||||
// http.SetCookie(w, &http.Cookie{
|
||||
// Name: "cartowner",
|
||||
// Value: owner,
|
||||
// Path: "/",
|
||||
// HttpOnly: true,
|
||||
// SameSite: http.SameSiteLaxMode,
|
||||
// })
|
||||
// // Proxy logic (simplified): reuse existing request to owning host on same port.
|
||||
// target := "http://" + owner + r.URL.Path
|
||||
// if q := r.URL.RawQuery; q != "" {
|
||||
// target += "?" + q
|
||||
// }
|
||||
// req, err := http.NewRequestWithContext(r.Context(), r.Method, target, r.Body)
|
||||
// if err != nil {
|
||||
// http.Error(w, "proxy build error", http.StatusBadGateway)
|
||||
// return true, err
|
||||
// }
|
||||
// for k, v := range r.Header {
|
||||
// for _, vv := range v {
|
||||
// req.Header.Add(k, vv)
|
||||
// }
|
||||
// }
|
||||
// req.Header.Set("X-Forwarded-Host", r.Host)
|
||||
// req.Header.Set("X-Cart-Id", cartId.String())
|
||||
// req.Header.Set("X-Cart-Owner", owner)
|
||||
// resp, err := http.DefaultClient.Do(req)
|
||||
// if err != nil {
|
||||
// http.Error(w, "proxy upstream error", http.StatusBadGateway)
|
||||
// return true, err
|
||||
// }
|
||||
// defer resp.Body.Close()
|
||||
// for k, v := range resp.Header {
|
||||
// for _, vv := range v {
|
||||
// w.Header().Add(k, vv)
|
||||
// }
|
||||
// }
|
||||
// w.Header().Set("X-Cart-Owner-Routed", "true")
|
||||
// w.WriteHeader(resp.StatusCode)
|
||||
// _, copyErr := io.Copy(w, resp.Body)
|
||||
// if copyErr != nil {
|
||||
// return true, copyErr
|
||||
// }
|
||||
// return true, nil
|
||||
// }
|
||||
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("OPTIONS /", func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -440,29 +449,29 @@ func (s *PoolServer) Serve() *http.ServeMux {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
|
||||
mux.HandleFunc("GET /", ErrorHandler(CookieCartIdHandler(s.HandleGet)))
|
||||
mux.HandleFunc("GET /add/{sku}", ErrorHandler(CookieCartIdHandler(s.HandleAddSku)))
|
||||
mux.HandleFunc("POST /", ErrorHandler(CookieCartIdHandler(s.HandleAddRequest)))
|
||||
mux.HandleFunc("POST /set", ErrorHandler(CookieCartIdHandler(s.HandleSetCartItems)))
|
||||
mux.HandleFunc("DELETE /{itemId}", ErrorHandler(CookieCartIdHandler(s.HandleDeleteItem)))
|
||||
mux.HandleFunc("PUT /", ErrorHandler(CookieCartIdHandler(s.HandleQuantityChange)))
|
||||
mux.HandleFunc("DELETE /", ErrorHandler(CookieCartIdHandler(s.RemoveCartCookie)))
|
||||
mux.HandleFunc("POST /delivery", ErrorHandler(CookieCartIdHandler(s.HandleSetDelivery)))
|
||||
mux.HandleFunc("DELETE /delivery/{deliveryId}", ErrorHandler(CookieCartIdHandler(s.HandleRemoveDelivery)))
|
||||
mux.HandleFunc("PUT /delivery/{deliveryId}/pickupPoint", ErrorHandler(CookieCartIdHandler(s.HandleSetPickupPoint)))
|
||||
mux.HandleFunc("GET /checkout", ErrorHandler(CookieCartIdHandler(s.HandleCheckout)))
|
||||
mux.HandleFunc("GET /confirmation/{orderId}", ErrorHandler(CookieCartIdHandler(s.HandleConfirmation)))
|
||||
mux.HandleFunc("GET /", ErrorHandler(CookieCartIdHandler(s.ProxyHandler(s.HandleGet))))
|
||||
mux.HandleFunc("GET /add/{sku}", ErrorHandler(CookieCartIdHandler(s.ProxyHandler(s.HandleAddSku))))
|
||||
mux.HandleFunc("POST /", ErrorHandler(CookieCartIdHandler(s.ProxyHandler(s.HandleAddRequest))))
|
||||
mux.HandleFunc("POST /set", ErrorHandler(CookieCartIdHandler(s.ProxyHandler(s.HandleSetCartItems))))
|
||||
mux.HandleFunc("DELETE /{itemId}", ErrorHandler(CookieCartIdHandler(s.ProxyHandler(s.HandleDeleteItem))))
|
||||
mux.HandleFunc("PUT /", ErrorHandler(CookieCartIdHandler(s.ProxyHandler(s.HandleQuantityChange))))
|
||||
mux.HandleFunc("DELETE /", ErrorHandler(CookieCartIdHandler(s.ProxyHandler(s.RemoveCartCookie))))
|
||||
mux.HandleFunc("POST /delivery", ErrorHandler(CookieCartIdHandler(s.ProxyHandler(s.HandleSetDelivery))))
|
||||
mux.HandleFunc("DELETE /delivery/{deliveryId}", ErrorHandler(CookieCartIdHandler(s.ProxyHandler(s.HandleRemoveDelivery))))
|
||||
mux.HandleFunc("PUT /delivery/{deliveryId}/pickupPoint", ErrorHandler(CookieCartIdHandler(s.ProxyHandler(s.HandleSetPickupPoint))))
|
||||
mux.HandleFunc("GET /checkout", ErrorHandler(CookieCartIdHandler(s.ProxyHandler(s.HandleCheckout))))
|
||||
mux.HandleFunc("GET /confirmation/{orderId}", ErrorHandler(CookieCartIdHandler(s.ProxyHandler(s.HandleConfirmation))))
|
||||
|
||||
mux.HandleFunc("GET /byid/{id}", ErrorHandler(CartIdHandler(s.HandleGet)))
|
||||
mux.HandleFunc("GET /byid/{id}/add/{sku}", ErrorHandler(CartIdHandler(s.HandleAddSku)))
|
||||
mux.HandleFunc("POST /byid/{id}", ErrorHandler(CartIdHandler(s.HandleAddRequest)))
|
||||
mux.HandleFunc("DELETE /byid/{id}/{itemId}", ErrorHandler(CartIdHandler(s.HandleDeleteItem)))
|
||||
mux.HandleFunc("PUT /byid/{id}", ErrorHandler(CartIdHandler(s.HandleQuantityChange)))
|
||||
mux.HandleFunc("POST /byid/{id}/delivery", ErrorHandler(CartIdHandler(s.HandleSetDelivery)))
|
||||
mux.HandleFunc("DELETE /byid/{id}/delivery/{deliveryId}", ErrorHandler(CartIdHandler(s.HandleRemoveDelivery)))
|
||||
mux.HandleFunc("PUT /byid/{id}/delivery/{deliveryId}/pickupPoint", ErrorHandler(CartIdHandler(s.HandleSetPickupPoint)))
|
||||
mux.HandleFunc("GET /byid/{id}/checkout", ErrorHandler(CartIdHandler(s.HandleCheckout)))
|
||||
mux.HandleFunc("GET /byid/{id}/confirmation", ErrorHandler(CartIdHandler(s.HandleConfirmation)))
|
||||
mux.HandleFunc("GET /byid/{id}", ErrorHandler(CartIdHandler(s.ProxyHandler(s.HandleGet))))
|
||||
mux.HandleFunc("GET /byid/{id}/add/{sku}", ErrorHandler(CartIdHandler(s.ProxyHandler(s.HandleAddSku))))
|
||||
mux.HandleFunc("POST /byid/{id}", ErrorHandler(CartIdHandler(s.ProxyHandler(s.HandleAddRequest))))
|
||||
mux.HandleFunc("DELETE /byid/{id}/{itemId}", ErrorHandler(CartIdHandler(s.ProxyHandler(s.HandleDeleteItem))))
|
||||
mux.HandleFunc("PUT /byid/{id}", ErrorHandler(CartIdHandler(s.ProxyHandler(s.HandleQuantityChange))))
|
||||
mux.HandleFunc("POST /byid/{id}/delivery", ErrorHandler(CartIdHandler(s.ProxyHandler(s.HandleSetDelivery))))
|
||||
mux.HandleFunc("DELETE /byid/{id}/delivery/{deliveryId}", ErrorHandler(CartIdHandler(s.ProxyHandler(s.HandleRemoveDelivery))))
|
||||
mux.HandleFunc("PUT /byid/{id}/delivery/{deliveryId}/pickupPoint", ErrorHandler(CartIdHandler(s.ProxyHandler(s.HandleSetPickupPoint))))
|
||||
mux.HandleFunc("GET /byid/{id}/checkout", ErrorHandler(CartIdHandler(s.ProxyHandler(s.HandleCheckout))))
|
||||
mux.HandleFunc("GET /byid/{id}/confirmation", ErrorHandler(CartIdHandler(s.ProxyHandler(s.HandleConfirmation))))
|
||||
|
||||
return mux
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user