Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: proxy unhandled requests #67

Merged
merged 1 commit into from
Jan 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type Config struct {
ChainID string
RPCEndpoints []string
WSEndpoints []string
LCDEndpoints []string
MantlemintDB string
IndexerDB string
DisableSync bool
Expand Down Expand Up @@ -67,6 +68,12 @@ func newConfig() Config {
return strings.Split(endpoints, ",")
}(),

// LCDEndpoints is where to forward unhandled queries to a node
LCDEndpoints: func() []string {
endpoints := getValidEnv("LCD_ENDPOINTS")
return strings.Split(endpoints, ",")
}(),

// MantlemintDB is the db name for mantlemint. Defaults to mantlemint
MantlemintDB: func() string {
mantlemintDB := getValidEnv("MANTLEMINT_DB")
Expand Down
43 changes: 43 additions & 0 deletions rpc/proxy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package rpc

import (
"github.com/tendermint/tendermint/libs/rand"
"net/http"
"net/http/httptest"
"net/http/httputil"
"net/url"
)

type ProxyMiddleware struct {
lcdUrls []string
proxies []*httputil.ReverseProxy
}

func NewProxyMiddleware(lcdUrls []string) ProxyMiddleware {
var proxies []*httputil.ReverseProxy
for _, u := range lcdUrls {
lcdUrl, err := url.Parse(u)
if err != nil {
panic(err)
}
proxies = append(proxies, httputil.NewSingleHostReverseProxy(lcdUrl))
}
return ProxyMiddleware{
lcdUrls: lcdUrls,
proxies: proxies,
}
}

func (pm ProxyMiddleware) HandleRequest(writer http.ResponseWriter, request *http.Request, handler http.Handler) {
recorder := httptest.NewRecorder()
handler.ServeHTTP(recorder, request)
if recorder.Code != http.StatusOK {
// randomly pick a proxy from the list
proxyToUse := rand.NewRand().Intn(len(pm.proxies))
pm.proxies[proxyToUse].ServeHTTP(writer, request)
return
}
writer.WriteHeader(recorder.Code)
writer.Write(recorder.Body.Bytes())
return
}
8 changes: 8 additions & 0 deletions rpc/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,14 @@ func StartRPC(
})
})

pm := NewProxyMiddleware(mantlemintConfig.LCDEndpoints)
// proxy middleware to handle unimplemented queries
apiSrv.Router.Use(func(next http.Handler) http.Handler {
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
pm.HandleRequest(writer, request, next)
})
})

// start api server in goroutine
go func() {
if err := apiSrv.Start(cfg); err != nil {
Expand Down