123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- package route
- import (
- "context"
- "fmt"
- "net/http"
- "strconv"
- "time"
- "github.com/metacubex/mihomo/adapter"
- "github.com/metacubex/mihomo/adapter/outboundgroup"
- "github.com/metacubex/mihomo/common/utils"
- "github.com/metacubex/mihomo/component/profile/cachefile"
- C "github.com/metacubex/mihomo/constant"
- "github.com/metacubex/mihomo/tunnel"
- "github.com/go-chi/chi/v5"
- "github.com/go-chi/render"
- )
- var (
- SwitchProxiesCallback func(sGroup string, sProxy string)
- )
- func proxyRouter() http.Handler {
- r := chi.NewRouter()
- r.Get("/", getProxies)
- r.Route("/{name}", func(r chi.Router) {
- r.Use(parseProxyName, findProxyByName)
- r.Get("/", getProxy)
- r.Get("/delay", getProxyDelay)
- r.Put("/", updateProxy)
- })
- return r
- }
- func parseProxyName(next http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- name := getEscapeParam(r, "name")
- ctx := context.WithValue(r.Context(), CtxKeyProxyName, name)
- next.ServeHTTP(w, r.WithContext(ctx))
- })
- }
- func findProxyByName(next http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- name := r.Context().Value(CtxKeyProxyName).(string)
- proxies := tunnel.ProxiesWithProviders()
- proxy, exist := proxies[name]
- if !exist {
- render.Status(r, http.StatusNotFound)
- render.JSON(w, r, ErrNotFound)
- return
- }
- ctx := context.WithValue(r.Context(), CtxKeyProxy, proxy)
- next.ServeHTTP(w, r.WithContext(ctx))
- })
- }
- func getProxies(w http.ResponseWriter, r *http.Request) {
- proxies := tunnel.ProxiesWithProviders()
- render.JSON(w, r, render.M{
- "proxies": proxies,
- })
- }
- func getProxy(w http.ResponseWriter, r *http.Request) {
- proxy := r.Context().Value(CtxKeyProxy).(C.Proxy)
- render.JSON(w, r, proxy)
- }
- func updateProxy(w http.ResponseWriter, r *http.Request) {
- req := struct {
- Name string `json:"name"`
- }{}
- if err := render.DecodeJSON(r.Body, &req); err != nil {
- render.Status(r, http.StatusBadRequest)
- render.JSON(w, r, ErrBadRequest)
- return
- }
- proxy := r.Context().Value(CtxKeyProxy).(*adapter.Proxy)
- selector, ok := proxy.ProxyAdapter.(outboundgroup.SelectAble)
- if !ok {
- render.Status(r, http.StatusBadRequest)
- render.JSON(w, r, newError("Must be a Selector"))
- return
- }
- if err := selector.Set(req.Name); err != nil {
- render.Status(r, http.StatusBadRequest)
- render.JSON(w, r, newError(fmt.Sprintf("Selector update error: %s", err.Error())))
- return
- }
- cachefile.Cache().SetSelected(proxy.Name(), req.Name)
- if SwitchProxiesCallback != nil {
- // refresh tray menu
- go SwitchProxiesCallback(proxy.Name(), req.Name)
- }
- render.NoContent(w, r)
- }
- func getProxyDelay(w http.ResponseWriter, r *http.Request) {
- query := r.URL.Query()
- url := query.Get("url")
- timeout, err := strconv.ParseInt(query.Get("timeout"), 10, 16)
- if err != nil {
- render.Status(r, http.StatusBadRequest)
- render.JSON(w, r, ErrBadRequest)
- return
- }
- expectedStatus, err := utils.NewUnsignedRanges[uint16](query.Get("expected"))
- if err != nil {
- render.Status(r, http.StatusBadRequest)
- render.JSON(w, r, ErrBadRequest)
- return
- }
- proxy := r.Context().Value(CtxKeyProxy).(C.Proxy)
- ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(timeout))
- defer cancel()
- delay, err := proxy.URLTest(ctx, url, expectedStatus)
- if ctx.Err() != nil {
- render.Status(r, http.StatusGatewayTimeout)
- render.JSON(w, r, ErrRequestTimeout)
- return
- }
- if err != nil || delay == 0 {
- render.Status(r, http.StatusServiceUnavailable)
- if err != nil && delay != 0 {
- render.JSON(w, r, err)
- } else {
- render.JSON(w, r, newError("An error occurred in the delay test"))
- }
- return
- }
- render.JSON(w, r, render.M{
- "delay": delay,
- })
- }
|