Fix: update proxy config api

This commit is contained in:
Dreamacro 2018-08-12 02:23:46 +08:00
parent 410b272b50
commit 0208e32933
7 changed files with 109 additions and 124 deletions

View file

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

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

View file

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

View file

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

View file

@ -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())

View file

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