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 }