1package route 2 3import ( 4 "context" 5 "net/http" 6 7 "github.com/Dreamacro/clash/adapters/provider" 8 "github.com/Dreamacro/clash/tunnel" 9 10 "github.com/go-chi/chi/v5" 11 "github.com/go-chi/render" 12) 13 14func proxyProviderRouter() http.Handler { 15 r := chi.NewRouter() 16 r.Get("/", getProviders) 17 18 r.Route("/{name}", func(r chi.Router) { 19 r.Use(parseProviderName, findProviderByName) 20 r.Get("/", getProvider) 21 r.Put("/", updateProvider) 22 r.Get("/healthcheck", healthCheckProvider) 23 }) 24 return r 25} 26 27func getProviders(w http.ResponseWriter, r *http.Request) { 28 providers := tunnel.Providers() 29 render.JSON(w, r, render.M{ 30 "providers": providers, 31 }) 32} 33 34func getProvider(w http.ResponseWriter, r *http.Request) { 35 provider := r.Context().Value(CtxKeyProvider).(provider.ProxyProvider) 36 render.JSON(w, r, provider) 37} 38 39func updateProvider(w http.ResponseWriter, r *http.Request) { 40 provider := r.Context().Value(CtxKeyProvider).(provider.ProxyProvider) 41 if err := provider.Update(); err != nil { 42 render.Status(r, http.StatusServiceUnavailable) 43 render.JSON(w, r, newError(err.Error())) 44 return 45 } 46 render.NoContent(w, r) 47} 48 49func healthCheckProvider(w http.ResponseWriter, r *http.Request) { 50 provider := r.Context().Value(CtxKeyProvider).(provider.ProxyProvider) 51 provider.HealthCheck() 52 render.NoContent(w, r) 53} 54 55func parseProviderName(next http.Handler) http.Handler { 56 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 57 name := getEscapeParam(r, "name") 58 ctx := context.WithValue(r.Context(), CtxKeyProviderName, name) 59 next.ServeHTTP(w, r.WithContext(ctx)) 60 }) 61} 62 63func findProviderByName(next http.Handler) http.Handler { 64 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 65 name := r.Context().Value(CtxKeyProviderName).(string) 66 providers := tunnel.Providers() 67 provider, exist := providers[name] 68 if !exist { 69 render.Status(r, http.StatusNotFound) 70 render.JSON(w, r, ErrNotFound) 71 return 72 } 73 74 ctx := context.WithValue(r.Context(), CtxKeyProvider, provider) 75 next.ServeHTTP(w, r.WithContext(ctx)) 76 }) 77} 78