github.com/metacubex/mihomo@v1.18.5/hub/route/provider.go (about) 1 package route 2 3 import ( 4 "context" 5 "net/http" 6 7 C "github.com/metacubex/mihomo/constant" 8 "github.com/metacubex/mihomo/constant/provider" 9 "github.com/metacubex/mihomo/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 } 112 113 func ruleProviderRouter() http.Handler { 114 r := chi.NewRouter() 115 r.Get("/", getRuleProviders) 116 r.Route("/{name}", func(r chi.Router) { 117 r.Use(parseRuleProviderName, findRuleProviderByName) 118 r.Put("/", updateRuleProvider) 119 }) 120 return r 121 } 122 123 func getRuleProviders(w http.ResponseWriter, r *http.Request) { 124 ruleProviders := tunnel.RuleProviders() 125 render.JSON(w, r, render.M{ 126 "providers": ruleProviders, 127 }) 128 } 129 130 func updateRuleProvider(w http.ResponseWriter, r *http.Request) { 131 provider := r.Context().Value(CtxKeyProvider).(provider.RuleProvider) 132 if err := provider.Update(); err != nil { 133 render.Status(r, http.StatusServiceUnavailable) 134 render.JSON(w, r, newError(err.Error())) 135 return 136 } 137 render.NoContent(w, r) 138 } 139 140 func parseRuleProviderName(next http.Handler) http.Handler { 141 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 142 name := getEscapeParam(r, "name") 143 ctx := context.WithValue(r.Context(), CtxKeyProviderName, name) 144 next.ServeHTTP(w, r.WithContext(ctx)) 145 }) 146 } 147 148 func findRuleProviderByName(next http.Handler) http.Handler { 149 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 150 name := r.Context().Value(CtxKeyProviderName).(string) 151 providers := tunnel.RuleProviders() 152 provider, exist := providers[name] 153 if !exist { 154 render.Status(r, http.StatusNotFound) 155 render.JSON(w, r, ErrNotFound) 156 return 157 } 158 159 ctx := context.WithValue(r.Context(), CtxKeyProvider, provider) 160 next.ServeHTTP(w, r.WithContext(ctx)) 161 }) 162 }