github.com/igoogolx/clash@v1.19.8/hub/route/proxies.go (about)

     1  package route
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net/http"
     7  	"strconv"
     8  	"time"
     9  
    10  	"github.com/igoogolx/clash/adapter"
    11  	"github.com/igoogolx/clash/adapter/outboundgroup"
    12  	"github.com/igoogolx/clash/component/profile/cachefile"
    13  	C "github.com/igoogolx/clash/constant"
    14  	"github.com/igoogolx/clash/tunnel"
    15  
    16  	"github.com/go-chi/chi/v5"
    17  	"github.com/go-chi/render"
    18  )
    19  
    20  func proxyRouter() http.Handler {
    21  	r := chi.NewRouter()
    22  	r.Get("/", getProxies)
    23  
    24  	r.Route("/{name}", func(r chi.Router) {
    25  		r.Use(parseProxyName, findProxyByName)
    26  		r.Get("/", getProxy)
    27  		r.Get("/delay", getProxyDelay)
    28  		r.Put("/", updateProxy)
    29  	})
    30  	return r
    31  }
    32  
    33  func parseProxyName(next http.Handler) http.Handler {
    34  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    35  		name := getEscapeParam(r, "name")
    36  		ctx := context.WithValue(r.Context(), CtxKeyProxyName, name)
    37  		next.ServeHTTP(w, r.WithContext(ctx))
    38  	})
    39  }
    40  
    41  func findProxyByName(next http.Handler) http.Handler {
    42  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    43  		name := r.Context().Value(CtxKeyProxyName).(string)
    44  		proxies := tunnel.Proxies()
    45  		proxy, exist := proxies[name]
    46  		if !exist {
    47  			render.Status(r, http.StatusNotFound)
    48  			render.JSON(w, r, ErrNotFound)
    49  			return
    50  		}
    51  
    52  		ctx := context.WithValue(r.Context(), CtxKeyProxy, proxy)
    53  		next.ServeHTTP(w, r.WithContext(ctx))
    54  	})
    55  }
    56  
    57  func getProxies(w http.ResponseWriter, r *http.Request) {
    58  	proxies := tunnel.Proxies()
    59  	render.JSON(w, r, render.M{
    60  		"proxies": proxies,
    61  	})
    62  }
    63  
    64  func getProxy(w http.ResponseWriter, r *http.Request) {
    65  	proxy := r.Context().Value(CtxKeyProxy).(C.Proxy)
    66  	render.JSON(w, r, proxy)
    67  }
    68  
    69  func updateProxy(w http.ResponseWriter, r *http.Request) {
    70  	req := struct {
    71  		Name string `json:"name"`
    72  	}{}
    73  	if err := render.DecodeJSON(r.Body, &req); err != nil {
    74  		render.Status(r, http.StatusBadRequest)
    75  		render.JSON(w, r, ErrBadRequest)
    76  		return
    77  	}
    78  
    79  	proxy := r.Context().Value(CtxKeyProxy).(*adapter.Proxy)
    80  	selector, ok := proxy.ProxyAdapter.(*outboundgroup.Selector)
    81  	if !ok {
    82  		render.Status(r, http.StatusBadRequest)
    83  		render.JSON(w, r, newError("Must be a Selector"))
    84  		return
    85  	}
    86  
    87  	if err := selector.Set(req.Name); err != nil {
    88  		render.Status(r, http.StatusBadRequest)
    89  		render.JSON(w, r, newError(fmt.Sprintf("Selector update error: %s", err.Error())))
    90  		return
    91  	}
    92  
    93  	cachefile.Cache().SetSelected(proxy.Name(), req.Name)
    94  	render.NoContent(w, r)
    95  }
    96  
    97  func getProxyDelay(w http.ResponseWriter, r *http.Request) {
    98  	query := r.URL.Query()
    99  	url := query.Get("url")
   100  	timeout, err := strconv.ParseInt(query.Get("timeout"), 10, 16)
   101  	if err != nil {
   102  		render.Status(r, http.StatusBadRequest)
   103  		render.JSON(w, r, ErrBadRequest)
   104  		return
   105  	}
   106  
   107  	proxy := r.Context().Value(CtxKeyProxy).(C.Proxy)
   108  
   109  	ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(timeout))
   110  	defer cancel()
   111  
   112  	delay, meanDelay, err := proxy.URLTest(ctx, url)
   113  	if ctx.Err() != nil {
   114  		render.Status(r, http.StatusGatewayTimeout)
   115  		render.JSON(w, r, ErrRequestTimeout)
   116  		return
   117  	}
   118  
   119  	if err != nil || delay == 0 {
   120  		render.Status(r, http.StatusServiceUnavailable)
   121  		render.JSON(w, r, newError("An error occurred in the delay test"))
   122  		return
   123  	}
   124  
   125  	render.JSON(w, r, render.M{
   126  		"delay":     delay,
   127  		"meanDelay": meanDelay,
   128  	})
   129  }