diff --git a/config/config.go b/config/config.go index 06e17a18d..f0a127a3a 100644 --- a/config/config.go +++ b/config/config.go @@ -21,6 +21,22 @@ var ( once sync.Once ) +// General config +type General struct { + Port int + SocksPort int + AllowLan bool + Mode Mode + LogLevel C.LogLevel +} + +// ProxyConfig is update proxy schema +type ProxyConfig struct { + Port *int + SocksPort *int + AllowLan *bool +} + // Config is clash config manager type Config struct { general *General @@ -29,7 +45,7 @@ type Config struct { lastUpdate time.Time event chan<- interface{} - errCh chan interface{} + reportCh chan interface{} observable *observable.Observable } @@ -45,9 +61,9 @@ func (c *Config) Subscribe() observable.Subscription { return sub } -// Report return a channel for collecting error message +// Report return a channel for collecting report message func (c *Config) Report() chan<- interface{} { - return c.errCh + return c.reportCh } func (c *Config) readConfig() (*ini.File, error) { @@ -118,8 +134,8 @@ func (c *Config) UpdateRules() error { func (c *Config) parseGeneral(cfg *ini.File) error { general := cfg.Section("General") - port := general.Key("port").RangeInt(C.DefalutHTTPPort, 1, 65535) - socksPort := general.Key("socks-port").RangeInt(C.DefalutSOCKSPort, 1, 65535) + port := general.Key("port").RangeInt(0, 1, 65535) + socksPort := general.Key("socks-port").RangeInt(0, 1, 65535) allowLan := general.Key("allow-lan").MustBool() logLevelString := general.Key("log-level").MustString(C.INFO.String()) modeString := general.Key("mode").MustString(Rule.String()) @@ -135,13 +151,11 @@ func (c *Config) parseGeneral(cfg *ini.File) error { } c.general = &General{ - Base: &Base{ - Port: &port, - SocketPort: &socksPort, - AllowLan: &allowLan, - }, - Mode: mode, - LogLevel: logLevel, + Port: port, + SocksPort: socksPort, + AllowLan: allowLan, + Mode: mode, + LogLevel: logLevel, } if restAddr := general.Key("external-controller").String(); restAddr != "" { @@ -154,11 +168,32 @@ func (c *Config) parseGeneral(cfg *ini.File) error { // UpdateGeneral dispatch update event func (c *Config) UpdateGeneral(general General) { - c.event <- &Event{Type: "base", Payload: *general.Base} + c.UpdateProxy(ProxyConfig{ + Port: &general.Port, + SocksPort: &general.SocksPort, + AllowLan: &general.AllowLan, + }) c.event <- &Event{Type: "mode", Payload: general.Mode} c.event <- &Event{Type: "log-level", Payload: general.LogLevel} } +// UpdateProxy dispatch update proxy event +func (c *Config) UpdateProxy(pc ProxyConfig) { + if pc.AllowLan != nil { + c.general.AllowLan = *pc.AllowLan + } + + if (pc.AllowLan != nil || pc.Port != nil) && *pc.Port != 0 { + c.general.Port = *pc.Port + c.event <- &Event{Type: "http-addr", Payload: genAddr(*pc.Port, c.general.AllowLan)} + } + + if (pc.AllowLan != nil || pc.SocksPort != nil) && *pc.SocksPort != 0 { + c.general.SocksPort = *pc.SocksPort + c.event <- &Event{Type: "socks-addr", Payload: genAddr(*pc.SocksPort, c.general.AllowLan)} + } +} + func (c *Config) parseProxies(cfg *ini.File) error { proxies := make(map[string]C.Proxy) proxiesConfig := cfg.Section("Proxy") @@ -270,18 +305,27 @@ func (c *Config) parseRules(cfg *ini.File) error { return nil } -func (c *Config) handleErrorMessage() { - for elm := range c.errCh { - event := elm.(Event) +func (c *Config) handleResponseMessage() { + for elm := range c.reportCh { + event := elm.(*Event) switch event.Type { - case "base": - c.general.Base = event.Payload.(*Base) + case "http-addr": + if event.Payload.(bool) == false { + c.general.Port = 0 + } + break + case "socks-addr": + if event.Payload.(bool) == false { + c.general.SocksPort = 0 + } + break } } } func newConfig() *Config { event := make(chan interface{}) + reportCh := make(chan interface{}) config := &Config{ general: &General{}, proxies: make(map[string]C.Proxy), @@ -289,9 +333,10 @@ func newConfig() *Config { lastUpdate: time.Now(), event: event, + reportCh: reportCh, observable: observable.NewObservable(event), } - go config.handleErrorMessage() + go config.handleResponseMessage() return config } diff --git a/config/general.go b/config/general.go deleted file mode 100644 index 121414476..000000000 --- a/config/general.go +++ /dev/null @@ -1,17 +0,0 @@ -package config - -import ( - C "github.com/Dreamacro/clash/constant" -) - -type General struct { - *Base - Mode Mode - LogLevel C.LogLevel -} - -type Base struct { - Port *int - SocketPort *int - AllowLan *bool -} diff --git a/config/utils.go b/config/utils.go index cc2b99d47..793fcfe78 100644 --- a/config/utils.go +++ b/config/utils.go @@ -1,6 +1,7 @@ package config import ( + "fmt" "strings" ) @@ -10,3 +11,10 @@ func trimArr(arr []string) (r []string) { } return } + +func genAddr(port int, allowLan bool) string { + if allowLan { + return fmt.Sprintf(":%d", port) + } + return fmt.Sprintf("127.0.0.1:%d", port) +} diff --git a/constant/config.go b/constant/config.go index 3b8016b85..b09375877 100644 --- a/constant/config.go +++ b/constant/config.go @@ -9,9 +9,7 @@ import ( ) const ( - Name = "clash" - DefalutHTTPPort = 7890 - DefalutSOCKSPort = 7891 + Name = "clash" ) var ( diff --git a/hub/configs.go b/hub/configs.go index 8082bcc7c..2cbe2e3c6 100644 --- a/hub/configs.go +++ b/hub/configs.go @@ -6,7 +6,6 @@ import ( "github.com/Dreamacro/clash/config" C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/proxy" "github.com/go-chi/chi" "github.com/go-chi/render" @@ -20,21 +19,21 @@ func configRouter() http.Handler { } type configSchema struct { - Port int `json:"port"` - SocketPort int `json:"socket-port"` - AllowLan bool `json:"allow-lan"` - Mode string `json:"mode"` - LogLevel string `json:"log-level"` + Port int `json:"port"` + SocksPort int `json:"socket-port"` + AllowLan bool `json:"allow-lan"` + Mode string `json:"mode"` + LogLevel string `json:"log-level"` } func getConfigs(w http.ResponseWriter, r *http.Request) { general := cfg.General() render.JSON(w, r, configSchema{ - Port: *general.Port, - SocketPort: *general.SocketPort, - AllowLan: *general.AllowLan, - Mode: general.Mode.String(), - LogLevel: general.LogLevel.String(), + Port: general.Port, + SocksPort: general.SocksPort, + AllowLan: general.AllowLan, + Mode: general.Mode.String(), + LogLevel: general.LogLevel.String(), }) } @@ -50,15 +49,7 @@ func updateConfigs(w http.ResponseWriter, r *http.Request) { } // update errors - var proxyErr, modeErr, logLevelErr error - - // update proxy - listener := proxy.Instance() - proxyErr = listener.Update(&config.Base{ - AllowLan: general.AllowLan, - Port: general.Port, - SocketPort: general.SocksPort, - }) + var modeErr, logLevelErr error // update mode if general.Mode != nil { @@ -81,7 +72,6 @@ func updateConfigs(w http.ResponseWriter, r *http.Request) { } hasError, errors := formatErrors(map[string]error{ - "proxy": proxyErr, "mode": modeErr, "log-level": logLevelErr, }) @@ -91,5 +81,13 @@ func updateConfigs(w http.ResponseWriter, r *http.Request) { render.JSON(w, r, errors) return } + + // update proxy + cfg.UpdateProxy(config.ProxyConfig{ + AllowLan: general.AllowLan, + Port: general.Port, + SocksPort: general.SocksPort, + }) + w.WriteHeader(http.StatusNoContent) } diff --git a/hub/server.go b/hub/server.go index 009b122dd..2a4f78914 100644 --- a/hub/server.go +++ b/hub/server.go @@ -50,6 +50,7 @@ func newHub(signal chan struct{}) { r.Mount("/proxies", proxyRouter()) r.Mount("/rules", ruleRouter()) + log.Infof("RESTful API listening at: %s", addr) err := http.ListenAndServe(addr, r) if err != nil { log.Errorf("External controller error: %s", err.Error()) diff --git a/proxy/listener.go b/proxy/listener.go index d72ed6c65..91c1c9285 100644 --- a/proxy/listener.go +++ b/proxy/listener.go @@ -1,7 +1,6 @@ package proxy import ( - "fmt" "sync" "github.com/Dreamacro/clash/config" @@ -16,58 +15,12 @@ var ( ) type Listener struct { - httpPort int - socksPort int - allowLan bool - // signal for update httpSignal *C.ProxySignal socksSignal *C.ProxySignal } -// Info returns the proxies's current configuration -func (l *Listener) Info() (info C.General) { - return C.General{ - Port: &l.httpPort, - SocksPort: &l.socksPort, - AllowLan: &l.allowLan, - } -} - -func (l *Listener) Update(base *config.Base) error { - if base.AllowLan != nil { - l.allowLan = *base.AllowLan - } - - var socksErr, httpErr error - if base.AllowLan != nil || base.Port != nil { - newHTTPPort := l.httpPort - if base.Port != nil { - newHTTPPort = *base.Port - } - httpErr = l.updateHTTP(newHTTPPort) - } - - if base.AllowLan != nil || base.SocketPort != nil { - newSocksPort := l.socksPort - if base.SocketPort != nil { - newSocksPort = *base.SocketPort - } - socksErr = l.updateSocks(newSocksPort) - } - - if socksErr != nil && httpErr != nil { - return fmt.Errorf("%s\n%s", socksErr.Error(), httpErr.Error()) - } else if socksErr != nil { - return socksErr - } else if httpErr != nil { - return httpErr - } else { - return nil - } -} - -func (l *Listener) updateHTTP(port int) error { +func (l *Listener) updateHTTP(addr string) error { if l.httpSignal != nil { signal := l.httpSignal signal.Done <- struct{}{} @@ -75,17 +28,16 @@ func (l *Listener) updateHTTP(port int) error { l.httpSignal = nil } - signal, err := http.NewHttpProxy(l.genAddr(port)) + signal, err := http.NewHttpProxy(addr) if err != nil { return err } l.httpSignal = signal - l.httpPort = port return nil } -func (l *Listener) updateSocks(port int) error { +func (l *Listener) updateSocks(addr string) error { if l.socksSignal != nil { signal := l.socksSignal signal.Done <- struct{}{} @@ -93,32 +45,32 @@ func (l *Listener) updateSocks(port int) error { l.socksSignal = nil } - signal, err := socks.NewSocksProxy(l.genAddr(port)) + signal, err := socks.NewSocksProxy(addr) if err != nil { return err } l.socksSignal = signal - l.socksPort = port return nil } -func (l *Listener) genAddr(port int) string { - host := "127.0.0.1" - if l.allowLan { - host = "" - } - return fmt.Sprintf("%s:%d", host, port) -} - func (l *Listener) process(signal chan<- struct{}) { sub := config.Instance().Subscribe() signal <- struct{}{} + reportCH := config.Instance().Report() for elm := range sub { event := elm.(*config.Event) - if event.Type == "base" { - base := event.Payload.(config.Base) - l.Update(&base) + switch event.Type { + case "http-addr": + addr := event.Payload.(string) + err := l.updateHTTP(addr) + reportCH <- &config.Event{Type: "http-addr", Payload: err == nil} + break + case "socks-addr": + addr := event.Payload.(string) + err := l.updateSocks(addr) + reportCH <- &config.Event{Type: "socks-addr", Payload: err == nil} + break } } }