From a38cc92700fa68e483bdc9f0890f0f2b91a33290 Mon Sep 17 00:00:00 2001 From: Cyberes Date: Fri, 12 Apr 2024 19:15:37 -0600 Subject: [PATCH] add homepage and json status page --- README.md | 4 +++ src/proxy-loadbalancer.go | 9 ++++--- src/proxy/serve.go | 54 +++++++++++++++++++++++++++++++++------ 3 files changed, 56 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 12a56ac..d70f698 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,14 @@ HTTPS proxy servers are not supported. 3. Edit the config. 4. Start the loadbalancer with `./proxy-loadbalancer --config [path to your config.yml]` +## Use + You can run your own "public IP delivery server" `canihazip` or use the default `api.ipify.org` An example systemd service `loadbalancer.service` is provided. +The server displays stats and info at `/json` + ## Special Headers The load balancer accepts special headers to control its behavior. diff --git a/src/proxy-loadbalancer.go b/src/proxy-loadbalancer.go index 1f17da5..7f9f459 100644 --- a/src/proxy-loadbalancer.go +++ b/src/proxy-loadbalancer.go @@ -83,12 +83,15 @@ func main() { } proxyCluster := proxy.NewForwardProxyCluster() - go proxyCluster.ValidateProxiesThread() - proxyCluster.BalancerOnline.Wait() go func() { log.Fatal(http.ListenAndServe(":"+configData.HTTPPort, proxyCluster)) }() - log.Infof("-> Server started on 0.0.0.0:%s and accepting requests <-", configData.HTTPPort) + log.Infof("-> Server started on 0.0.0.0:%s <-", configData.HTTPPort) + + go proxyCluster.ValidateProxiesThread() + proxyCluster.BalancerOnline.Wait() + log.Infoln("-> Proxy server accepting requests <-") + select {} } diff --git a/src/proxy/serve.go b/src/proxy/serve.go index 992b777..110f36a 100644 --- a/src/proxy/serve.go +++ b/src/proxy/serve.go @@ -1,26 +1,64 @@ package proxy import ( + "encoding/json" "fmt" + "math" "math/rand" "net/http" "time" ) +var startTime time.Time + +func init() { + startTime = time.Now() +} + func (p *ForwardProxyCluster) ServeHTTP(w http.ResponseWriter, req *http.Request) { if req.Method == http.MethodConnect { // HTTPS p.proxyHttpsConnect(w, req) } else { // HTTP - if req.URL.Scheme != "http" { - //msg := fmt.Sprintf(`unsupported protocal "%s"`, req.URL.Scheme) - //log.Errorf(msg) - //http.Error(w, msg, http.StatusBadRequest) - rand.New(rand.NewSource(time.Now().Unix())) - fmt.Fprint(w, "proxy-loadbalancer\n\n\n"+retardation[rand.Intn(len(retardation))]) - return + if req.URL.Scheme == "" { + // When the client connects using the server as a web server. + if req.URL.Path == "/" { + rand.New(rand.NewSource(time.Now().Unix())) + fmt.Fprint(w, "proxy-loadbalancer \nSee /json for status info.\n\n\n\n"+retardation[rand.Intn(len(retardation))]) + return + } else if req.URL.Path == "/json" { + p.mu.RLock() + response := map[string]interface{}{ + "uptime": int(math.Round(time.Since(startTime).Seconds())), + "online": p.BalancerOnline.GetCount() == 0, + "proxies": map[string]interface{}{ + "totalOnline": len(p.ourOnlineProxies) + len(p.thirdpartyOnlineProxies), + "ours": p.ourOnlineProxies, + "thirdParty": map[string]interface{}{ + "online": p.thirdpartyOnlineProxies, + "broken": p.thirdpartyBrokenProxies, + }, + }, + } + p.mu.RUnlock() + jsonResponse, err := json.MarshalIndent(response, "", " ") + if err != nil { + log.Errorln(err) + http.Error(w, "Path not found", http.StatusInternalServerError) + return + } + w.Header().Set("Cache-Control", "no-store") + w.Header().Set("Content-Type", "application/json") + w.Write(jsonResponse) + return + } else { + http.Error(w, "Path not found", http.StatusNotFound) + return + } + } else { + // When the client connects using the server as a proxy. + p.proxyHttpConnect(w, req) } - p.proxyHttpConnect(w, req) } }