Fix: update proxy config api

This commit is contained in:
gVisor bot 2018-08-12 02:23:46 +08:00
parent 6c38fce2cb
commit a0dd4ffddc
7 changed files with 109 additions and 124 deletions

View file

@ -21,6 +21,22 @@ var (
once sync.Once 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 // Config is clash config manager
type Config struct { type Config struct {
general *General general *General
@ -29,7 +45,7 @@ type Config struct {
lastUpdate time.Time lastUpdate time.Time
event chan<- interface{} event chan<- interface{}
errCh chan interface{} reportCh chan interface{}
observable *observable.Observable observable *observable.Observable
} }
@ -45,9 +61,9 @@ func (c *Config) Subscribe() observable.Subscription {
return sub return sub
} }
// Report return a channel for collecting error message // Report return a channel for collecting report message
func (c *Config) Report() chan<- interface{} { func (c *Config) Report() chan<- interface{} {
return c.errCh return c.reportCh
} }
func (c *Config) readConfig() (*ini.File, error) { func (c *Config) readConfig() (*ini.File, error) {
@ -118,8 +134,8 @@ func (c *Config) UpdateRules() error {
func (c *Config) parseGeneral(cfg *ini.File) error { func (c *Config) parseGeneral(cfg *ini.File) error {
general := cfg.Section("General") general := cfg.Section("General")
port := general.Key("port").RangeInt(C.DefalutHTTPPort, 1, 65535) port := general.Key("port").RangeInt(0, 1, 65535)
socksPort := general.Key("socks-port").RangeInt(C.DefalutSOCKSPort, 1, 65535) socksPort := general.Key("socks-port").RangeInt(0, 1, 65535)
allowLan := general.Key("allow-lan").MustBool() allowLan := general.Key("allow-lan").MustBool()
logLevelString := general.Key("log-level").MustString(C.INFO.String()) logLevelString := general.Key("log-level").MustString(C.INFO.String())
modeString := general.Key("mode").MustString(Rule.String()) modeString := general.Key("mode").MustString(Rule.String())
@ -135,13 +151,11 @@ func (c *Config) parseGeneral(cfg *ini.File) error {
} }
c.general = &General{ c.general = &General{
Base: &Base{ Port: port,
Port: &port, SocksPort: socksPort,
SocketPort: &socksPort, AllowLan: allowLan,
AllowLan: &allowLan, Mode: mode,
}, LogLevel: logLevel,
Mode: mode,
LogLevel: logLevel,
} }
if restAddr := general.Key("external-controller").String(); restAddr != "" { if restAddr := general.Key("external-controller").String(); restAddr != "" {
@ -154,11 +168,32 @@ func (c *Config) parseGeneral(cfg *ini.File) error {
// UpdateGeneral dispatch update event // UpdateGeneral dispatch update event
func (c *Config) UpdateGeneral(general General) { 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: "mode", Payload: general.Mode}
c.event <- &Event{Type: "log-level", Payload: general.LogLevel} 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 { func (c *Config) parseProxies(cfg *ini.File) error {
proxies := make(map[string]C.Proxy) proxies := make(map[string]C.Proxy)
proxiesConfig := cfg.Section("Proxy") proxiesConfig := cfg.Section("Proxy")
@ -270,18 +305,27 @@ func (c *Config) parseRules(cfg *ini.File) error {
return nil return nil
} }
func (c *Config) handleErrorMessage() { func (c *Config) handleResponseMessage() {
for elm := range c.errCh { for elm := range c.reportCh {
event := elm.(Event) event := elm.(*Event)
switch event.Type { switch event.Type {
case "base": case "http-addr":
c.general.Base = event.Payload.(*Base) 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 { func newConfig() *Config {
event := make(chan interface{}) event := make(chan interface{})
reportCh := make(chan interface{})
config := &Config{ config := &Config{
general: &General{}, general: &General{},
proxies: make(map[string]C.Proxy), proxies: make(map[string]C.Proxy),
@ -289,9 +333,10 @@ func newConfig() *Config {
lastUpdate: time.Now(), lastUpdate: time.Now(),
event: event, event: event,
reportCh: reportCh,
observable: observable.NewObservable(event), observable: observable.NewObservable(event),
} }
go config.handleErrorMessage() go config.handleResponseMessage()
return config return config
} }

View file

@ -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
}

View file

@ -1,6 +1,7 @@
package config package config
import ( import (
"fmt"
"strings" "strings"
) )
@ -10,3 +11,10 @@ func trimArr(arr []string) (r []string) {
} }
return return
} }
func genAddr(port int, allowLan bool) string {
if allowLan {
return fmt.Sprintf(":%d", port)
}
return fmt.Sprintf("127.0.0.1:%d", port)
}

View file

@ -9,9 +9,7 @@ import (
) )
const ( const (
Name = "clash" Name = "clash"
DefalutHTTPPort = 7890
DefalutSOCKSPort = 7891
) )
var ( var (

View file

@ -6,7 +6,6 @@ import (
"github.com/Dreamacro/clash/config" "github.com/Dreamacro/clash/config"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/proxy"
"github.com/go-chi/chi" "github.com/go-chi/chi"
"github.com/go-chi/render" "github.com/go-chi/render"
@ -20,21 +19,21 @@ func configRouter() http.Handler {
} }
type configSchema struct { type configSchema struct {
Port int `json:"port"` Port int `json:"port"`
SocketPort int `json:"socket-port"` SocksPort int `json:"socket-port"`
AllowLan bool `json:"allow-lan"` AllowLan bool `json:"allow-lan"`
Mode string `json:"mode"` Mode string `json:"mode"`
LogLevel string `json:"log-level"` LogLevel string `json:"log-level"`
} }
func getConfigs(w http.ResponseWriter, r *http.Request) { func getConfigs(w http.ResponseWriter, r *http.Request) {
general := cfg.General() general := cfg.General()
render.JSON(w, r, configSchema{ render.JSON(w, r, configSchema{
Port: *general.Port, Port: general.Port,
SocketPort: *general.SocketPort, SocksPort: general.SocksPort,
AllowLan: *general.AllowLan, AllowLan: general.AllowLan,
Mode: general.Mode.String(), Mode: general.Mode.String(),
LogLevel: general.LogLevel.String(), LogLevel: general.LogLevel.String(),
}) })
} }
@ -50,15 +49,7 @@ func updateConfigs(w http.ResponseWriter, r *http.Request) {
} }
// update errors // update errors
var proxyErr, modeErr, logLevelErr error var modeErr, logLevelErr error
// update proxy
listener := proxy.Instance()
proxyErr = listener.Update(&config.Base{
AllowLan: general.AllowLan,
Port: general.Port,
SocketPort: general.SocksPort,
})
// update mode // update mode
if general.Mode != nil { if general.Mode != nil {
@ -81,7 +72,6 @@ func updateConfigs(w http.ResponseWriter, r *http.Request) {
} }
hasError, errors := formatErrors(map[string]error{ hasError, errors := formatErrors(map[string]error{
"proxy": proxyErr,
"mode": modeErr, "mode": modeErr,
"log-level": logLevelErr, "log-level": logLevelErr,
}) })
@ -91,5 +81,13 @@ func updateConfigs(w http.ResponseWriter, r *http.Request) {
render.JSON(w, r, errors) render.JSON(w, r, errors)
return return
} }
// update proxy
cfg.UpdateProxy(config.ProxyConfig{
AllowLan: general.AllowLan,
Port: general.Port,
SocksPort: general.SocksPort,
})
w.WriteHeader(http.StatusNoContent) w.WriteHeader(http.StatusNoContent)
} }

View file

@ -50,6 +50,7 @@ func newHub(signal chan struct{}) {
r.Mount("/proxies", proxyRouter()) r.Mount("/proxies", proxyRouter())
r.Mount("/rules", ruleRouter()) r.Mount("/rules", ruleRouter())
log.Infof("RESTful API listening at: %s", addr)
err := http.ListenAndServe(addr, r) err := http.ListenAndServe(addr, r)
if err != nil { if err != nil {
log.Errorf("External controller error: %s", err.Error()) log.Errorf("External controller error: %s", err.Error())

View file

@ -1,7 +1,6 @@
package proxy package proxy
import ( import (
"fmt"
"sync" "sync"
"github.com/Dreamacro/clash/config" "github.com/Dreamacro/clash/config"
@ -16,58 +15,12 @@ var (
) )
type Listener struct { type Listener struct {
httpPort int
socksPort int
allowLan bool
// signal for update // signal for update
httpSignal *C.ProxySignal httpSignal *C.ProxySignal
socksSignal *C.ProxySignal socksSignal *C.ProxySignal
} }
// Info returns the proxies's current configuration func (l *Listener) updateHTTP(addr string) error {
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 {
if l.httpSignal != nil { if l.httpSignal != nil {
signal := l.httpSignal signal := l.httpSignal
signal.Done <- struct{}{} signal.Done <- struct{}{}
@ -75,17 +28,16 @@ func (l *Listener) updateHTTP(port int) error {
l.httpSignal = nil l.httpSignal = nil
} }
signal, err := http.NewHttpProxy(l.genAddr(port)) signal, err := http.NewHttpProxy(addr)
if err != nil { if err != nil {
return err return err
} }
l.httpSignal = signal l.httpSignal = signal
l.httpPort = port
return nil return nil
} }
func (l *Listener) updateSocks(port int) error { func (l *Listener) updateSocks(addr string) error {
if l.socksSignal != nil { if l.socksSignal != nil {
signal := l.socksSignal signal := l.socksSignal
signal.Done <- struct{}{} signal.Done <- struct{}{}
@ -93,32 +45,32 @@ func (l *Listener) updateSocks(port int) error {
l.socksSignal = nil l.socksSignal = nil
} }
signal, err := socks.NewSocksProxy(l.genAddr(port)) signal, err := socks.NewSocksProxy(addr)
if err != nil { if err != nil {
return err return err
} }
l.socksSignal = signal l.socksSignal = signal
l.socksPort = port
return nil 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{}) { func (l *Listener) process(signal chan<- struct{}) {
sub := config.Instance().Subscribe() sub := config.Instance().Subscribe()
signal <- struct{}{} signal <- struct{}{}
reportCH := config.Instance().Report()
for elm := range sub { for elm := range sub {
event := elm.(*config.Event) event := elm.(*config.Event)
if event.Type == "base" { switch event.Type {
base := event.Payload.(config.Base) case "http-addr":
l.Update(&base) 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
} }
} }
} }