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  }