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  }