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

     1  package route
     2  
     3  import (
     4  	"context"
     5  	"net/http"
     6  
     7  	C "github.com/igoogolx/clash/constant"
     8  	"github.com/igoogolx/clash/constant/provider"
     9  	"github.com/igoogolx/clash/tunnel"
    10  
    11  	"github.com/go-chi/chi/v5"
    12  	"github.com/go-chi/render"
    13  	"github.com/samber/lo"
    14  )
    15  
    16  func proxyProviderRouter() http.Handler {
    17  	r := chi.NewRouter()
    18  	r.Get("/", getProviders)
    19  
    20  	r.Route("/{providerName}", func(r chi.Router) {
    21  		r.Use(parseProviderName, findProviderByName)
    22  		r.Get("/", getProvider)
    23  		r.Put("/", updateProvider)
    24  		r.Get("/healthcheck", healthCheckProvider)
    25  		r.Mount("/", proxyProviderProxyRouter())
    26  	})
    27  	return r
    28  }
    29  
    30  func proxyProviderProxyRouter() http.Handler {
    31  	r := chi.NewRouter()
    32  	r.Route("/{name}", func(r chi.Router) {
    33  		r.Use(parseProxyName, findProviderProxyByName)
    34  		r.Get("/", getProxy)
    35  		r.Get("/healthcheck", getProxyDelay)
    36  	})
    37  	return r
    38  }
    39  
    40  func getProviders(w http.ResponseWriter, r *http.Request) {
    41  	providers := tunnel.Providers()
    42  	render.JSON(w, r, render.M{
    43  		"providers": providers,
    44  	})
    45  }
    46  
    47  func getProvider(w http.ResponseWriter, r *http.Request) {
    48  	provider := r.Context().Value(CtxKeyProvider).(provider.ProxyProvider)
    49  	render.JSON(w, r, provider)
    50  }
    51  
    52  func updateProvider(w http.ResponseWriter, r *http.Request) {
    53  	provider := r.Context().Value(CtxKeyProvider).(provider.ProxyProvider)
    54  	if err := provider.Update(); err != nil {
    55  		render.Status(r, http.StatusServiceUnavailable)
    56  		render.JSON(w, r, newError(err.Error()))
    57  		return
    58  	}
    59  	render.NoContent(w, r)
    60  }
    61  
    62  func healthCheckProvider(w http.ResponseWriter, r *http.Request) {
    63  	provider := r.Context().Value(CtxKeyProvider).(provider.ProxyProvider)
    64  	provider.HealthCheck()
    65  	render.NoContent(w, r)
    66  }
    67  
    68  func parseProviderName(next http.Handler) http.Handler {
    69  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    70  		name := getEscapeParam(r, "providerName")
    71  		ctx := context.WithValue(r.Context(), CtxKeyProviderName, name)
    72  		next.ServeHTTP(w, r.WithContext(ctx))
    73  	})
    74  }
    75  
    76  func findProviderByName(next http.Handler) http.Handler {
    77  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    78  		name := r.Context().Value(CtxKeyProviderName).(string)
    79  		providers := tunnel.Providers()
    80  		provider, exist := providers[name]
    81  		if !exist {
    82  			render.Status(r, http.StatusNotFound)
    83  			render.JSON(w, r, ErrNotFound)
    84  			return
    85  		}
    86  
    87  		ctx := context.WithValue(r.Context(), CtxKeyProvider, provider)
    88  		next.ServeHTTP(w, r.WithContext(ctx))
    89  	})
    90  }
    91  
    92  func findProviderProxyByName(next http.Handler) http.Handler {
    93  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    94  		var (
    95  			name = r.Context().Value(CtxKeyProxyName).(string)
    96  			pd   = r.Context().Value(CtxKeyProvider).(provider.ProxyProvider)
    97  		)
    98  		proxy, exist := lo.Find(pd.Proxies(), func(proxy C.Proxy) bool {
    99  			return proxy.Name() == name
   100  		})
   101  
   102  		if !exist {
   103  			render.Status(r, http.StatusNotFound)
   104  			render.JSON(w, r, ErrNotFound)
   105  			return
   106  		}
   107  
   108  		ctx := context.WithValue(r.Context(), CtxKeyProxy, proxy)
   109  		next.ServeHTTP(w, r.WithContext(ctx))
   110  	})
   111  }