119 lines
2.3 KiB
Go
119 lines
2.3 KiB
Go
package proxy
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"github.com/Dreamacro/clash/config"
|
|
C "github.com/Dreamacro/clash/constant"
|
|
"github.com/Dreamacro/clash/proxy/http"
|
|
"github.com/Dreamacro/clash/proxy/redir"
|
|
"github.com/Dreamacro/clash/proxy/socks"
|
|
)
|
|
|
|
var (
|
|
listener *Listener
|
|
once sync.Once
|
|
)
|
|
|
|
type Listener struct {
|
|
// signal for update
|
|
httpSignal *C.ProxySignal
|
|
socksSignal *C.ProxySignal
|
|
redirSignal *C.ProxySignal
|
|
}
|
|
|
|
func (l *Listener) updateHTTP(addr string) error {
|
|
if l.httpSignal != nil {
|
|
signal := l.httpSignal
|
|
signal.Done <- struct{}{}
|
|
<-signal.Closed
|
|
l.httpSignal = nil
|
|
}
|
|
|
|
signal, err := http.NewHttpProxy(addr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
l.httpSignal = signal
|
|
return nil
|
|
}
|
|
|
|
func (l *Listener) updateSocks(addr string) error {
|
|
if l.socksSignal != nil {
|
|
signal := l.socksSignal
|
|
signal.Done <- struct{}{}
|
|
<-signal.Closed
|
|
l.socksSignal = nil
|
|
}
|
|
|
|
signal, err := socks.NewSocksProxy(addr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
l.socksSignal = signal
|
|
return nil
|
|
}
|
|
|
|
func (l *Listener) updateRedir(addr string) error {
|
|
if l.redirSignal != nil {
|
|
signal := l.redirSignal
|
|
signal.Done <- struct{}{}
|
|
<-signal.Closed
|
|
l.redirSignal = nil
|
|
}
|
|
|
|
signal, err := redir.NewRedirProxy(addr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
l.redirSignal = signal
|
|
return nil
|
|
}
|
|
|
|
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)
|
|
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
|
|
case "redir-addr":
|
|
addr := event.Payload.(string)
|
|
err := l.updateRedir(addr)
|
|
reportCH <- &config.Event{Type: "redir-addr", Payload: err == nil}
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// Run ensure config monitoring
|
|
func (l *Listener) Run() {
|
|
signal := make(chan struct{})
|
|
go l.process(signal)
|
|
<-signal
|
|
}
|
|
|
|
func newListener() *Listener {
|
|
return &Listener{}
|
|
}
|
|
|
|
// Instance return singleton instance of Listener
|
|
func Instance() *Listener {
|
|
once.Do(func() {
|
|
listener = newListener()
|
|
})
|
|
return listener
|
|
}
|