github.com/chwjbn/xclash@v0.2.0/hub/route/configs.go (about) 1 package route 2 3 import ( 4 "net/http" 5 "path/filepath" 6 7 "github.com/chwjbn/xclash/component/resolver" 8 "github.com/chwjbn/xclash/config" 9 "github.com/chwjbn/xclash/constant" 10 "github.com/chwjbn/xclash/hub/executor" 11 P "github.com/chwjbn/xclash/listener" 12 "github.com/chwjbn/xclash/log" 13 "github.com/chwjbn/xclash/tunnel" 14 15 "github.com/go-chi/chi/v5" 16 "github.com/go-chi/render" 17 ) 18 19 func configRouter() http.Handler { 20 r := chi.NewRouter() 21 r.Get("/", getConfigs) 22 r.Put("/", updateConfigs) 23 r.Patch("/", patchConfigs) 24 return r 25 } 26 27 type configSchema struct { 28 Port *int `json:"port"` 29 SocksPort *int `json:"socks-port"` 30 RedirPort *int `json:"redir-port"` 31 TProxyPort *int `json:"tproxy-port"` 32 MixedPort *int `json:"mixed-port"` 33 AllowLan *bool `json:"allow-lan"` 34 BindAddress *string `json:"bind-address"` 35 Mode *tunnel.TunnelMode `json:"mode"` 36 LogLevel *log.LogLevel `json:"log-level"` 37 IPv6 *bool `json:"ipv6"` 38 } 39 40 func getConfigs(w http.ResponseWriter, r *http.Request) { 41 general := executor.GetGeneral() 42 render.JSON(w, r, general) 43 } 44 45 func pointerOrDefault(p *int, def int) int { 46 if p != nil { 47 return *p 48 } 49 50 return def 51 } 52 53 func patchConfigs(w http.ResponseWriter, r *http.Request) { 54 general := &configSchema{} 55 if err := render.DecodeJSON(r.Body, general); err != nil { 56 render.Status(r, http.StatusBadRequest) 57 render.JSON(w, r, ErrBadRequest) 58 return 59 } 60 61 if general.AllowLan != nil { 62 P.SetAllowLan(*general.AllowLan) 63 } 64 65 if general.BindAddress != nil { 66 P.SetBindAddress(*general.BindAddress) 67 } 68 69 ports := P.GetPorts() 70 71 tcpIn := tunnel.TCPIn() 72 udpIn := tunnel.UDPIn() 73 74 P.ReCreateHTTP(pointerOrDefault(general.Port, ports.Port), tcpIn) 75 P.ReCreateSocks(pointerOrDefault(general.SocksPort, ports.SocksPort), tcpIn, udpIn) 76 P.ReCreateRedir(pointerOrDefault(general.RedirPort, ports.RedirPort), tcpIn, udpIn) 77 P.ReCreateTProxy(pointerOrDefault(general.TProxyPort, ports.TProxyPort), tcpIn, udpIn) 78 P.ReCreateMixed(pointerOrDefault(general.MixedPort, ports.MixedPort), tcpIn, udpIn) 79 80 if general.Mode != nil { 81 tunnel.SetMode(*general.Mode) 82 } 83 84 if general.LogLevel != nil { 85 log.SetLevel(*general.LogLevel) 86 } 87 88 if general.IPv6 != nil { 89 resolver.DisableIPv6 = !*general.IPv6 90 } 91 92 render.NoContent(w, r) 93 } 94 95 type updateConfigRequest struct { 96 Path string `json:"path"` 97 Payload string `json:"payload"` 98 } 99 100 func updateConfigs(w http.ResponseWriter, r *http.Request) { 101 req := updateConfigRequest{} 102 if err := render.DecodeJSON(r.Body, &req); err != nil { 103 render.Status(r, http.StatusBadRequest) 104 render.JSON(w, r, ErrBadRequest) 105 return 106 } 107 108 force := r.URL.Query().Get("force") == "true" 109 var cfg *config.Config 110 var err error 111 112 if req.Payload != "" { 113 cfg, err = executor.ParseWithBytes([]byte(req.Payload)) 114 if err != nil { 115 render.Status(r, http.StatusBadRequest) 116 render.JSON(w, r, newError(err.Error())) 117 return 118 } 119 } else { 120 if req.Path == "" { 121 req.Path = constant.Path.Config() 122 } 123 if !filepath.IsAbs(req.Path) { 124 render.Status(r, http.StatusBadRequest) 125 render.JSON(w, r, newError("path is not a absolute path")) 126 return 127 } 128 129 cfg, err = executor.ParseWithPath(req.Path) 130 if err != nil { 131 render.Status(r, http.StatusBadRequest) 132 render.JSON(w, r, newError(err.Error())) 133 return 134 } 135 } 136 137 executor.ApplyConfig(cfg, force) 138 render.NoContent(w, r) 139 }