package route import ( "context" "github.com/go-chi/chi/v5" "github.com/go-chi/render" "net/http" "strconv" "time" "github.com/Dreamacro/clash/adapter" "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/tunnel" ) func GroupRouter() http.Handler { r := chi.NewRouter() r.Get("/", getGroups) r.Route("/{name}", func(r chi.Router) { r.Use(parseProxyName, findProxyByName) r.Get("/", getGroup) r.Get("/delay", getGroupDelay) }) return r } func getGroups(w http.ResponseWriter, r *http.Request) { var gs []C.Proxy for _, p := range tunnel.Proxies() { if _, ok := p.(*adapter.Proxy).ProxyAdapter.(C.Group); ok { gs = append(gs, p) } } render.JSON(w, r, render.M{ "proxies": gs, }) } func getGroup(w http.ResponseWriter, r *http.Request) { proxy := r.Context().Value(CtxKeyProxy).(C.Proxy) if _, ok := proxy.(*adapter.Proxy).ProxyAdapter.(C.Group); ok { render.JSON(w, r, proxy) return } render.Status(r, http.StatusNotFound) render.JSON(w, r, ErrNotFound) } func getGroupDelay(w http.ResponseWriter, r *http.Request) { proxy := r.Context().Value(CtxKeyProxy).(C.Proxy) group, ok := proxy.(*adapter.Proxy).ProxyAdapter.(C.Group) if !ok { render.Status(r, http.StatusNotFound) render.JSON(w, r, ErrNotFound) return } query := r.URL.Query() url := query.Get("url") timeout, err := strconv.ParseInt(query.Get("timeout"), 10, 32) if err != nil { render.Status(r, http.StatusBadRequest) render.JSON(w, r, ErrBadRequest) return } expectedStatus, err := utils.NewIntRanges[uint16](query.Get("expected")) if err != nil { render.Status(r, http.StatusBadRequest) render.JSON(w, r, ErrBadRequest) return } ctx, cancel := context.WithTimeout(r.Context(), time.Millisecond*time.Duration(timeout)) defer cancel() dm, err := group.URLTest(ctx, url, expectedStatus) if err != nil { render.Status(r, http.StatusGatewayTimeout) render.JSON(w, r, newError(err.Error())) return } render.JSON(w, r, dm) }