/* Handle routes for load balancer API. */ package cmd import ( "encoding/json" "fmt" "log" "net/http" "strings" configs "github.com/bugout-dev/moonstream/nodes/node_balancer/configs" ) // pingRoute response with status of load balancer server itself func pingRoute(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") response := PingResponse{Status: "ok"} json.NewEncoder(w).Encode(response) } // lbHandler load balances the incoming requests to nodes func lbHandler(w http.ResponseWriter, r *http.Request) { attempts := GetAttemptsFromContext(r) if attempts > configs.NB_CONNECTION_RETRIES { log.Printf("Max attempts reached from %s %s, terminating\n", r.RemoteAddr, r.URL.Path) http.Error(w, "Service not available", http.StatusServiceUnavailable) return } var blockchain string switch { case strings.HasPrefix(r.URL.Path, "/nb/ethereum"): blockchain = "ethereum" case strings.HasPrefix(r.URL.Path, "/nb/polygon"): blockchain = "polygon" default: http.Error(w, fmt.Sprintf("Unacceptable blockchain provided %s", blockchain), http.StatusBadRequest) return } clientId := w.Header().Get(configs.MOONSTREAM_CLIENT_ID_HEADER) if clientId == "" { // TODO(kompotkot): After all internal crawlers and services start // providing client id header, then replace to http.Error clientId = "none" } // Chose one node var node *Node cpool, err := GetClientPool(blockchain) if err != nil { http.Error(w, fmt.Sprintf("Unacceptable blockchain provided %s", blockchain), http.StatusBadRequest) return } node = cpool.GetClientNode(clientId) if node == nil { node = blockchainPool.GetNextNode(blockchain) if node == nil { http.Error(w, "There are no nodes available", http.StatusServiceUnavailable) return } cpool.AddClientNode(clientId, node) } // Save origin path, to use in proxyErrorHandler if node will not response r.Header.Add("X-Origin-Path", r.URL.Path) switch { case strings.HasPrefix(r.URL.Path, fmt.Sprintf("/nb/%s/ping", blockchain)): r.URL.Path = "/ping" node.StatusReverseProxy.ServeHTTP(w, r) return case strings.HasPrefix(r.URL.Path, fmt.Sprintf("/nb/%s/jsonrpc", blockchain)): r.URL.Path = "/" node.GethReverseProxy.ServeHTTP(w, r) return default: http.Error(w, fmt.Sprintf("Unacceptable path for %s blockchain %s", blockchain, r.URL.Path), http.StatusBadRequest) return } }