Skip to content

Commit

Permalink
Update: add config route
Browse files Browse the repository at this point in the history
  • Loading branch information
Dreamacro committed Jul 15, 2018
1 parent 0eef9bb commit 3cacfb8
Show file tree
Hide file tree
Showing 12 changed files with 318 additions and 76 deletions.
11 changes: 9 additions & 2 deletions constant/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import (

const (
Name = "clash"
DefalutHTTPPort = "7890"
DefalutSOCKSPort = "7891"
DefalutHTTPPort = 7890
DefalutSOCKSPort = 7891
)

var (
Expand All @@ -26,6 +26,13 @@ var (
MMDBPath string
)

type General struct {
Mode *string `json:"mode,omitempty"`
AllowLan *bool `json:"allow-lan,omitempty"`
Port *int `json:"port,omitempty"`
SocksPort *int `json:"socks-port,omitempty"`
}

func init() {
currentUser, err := user.Current()
if err != nil {
Expand Down
7 changes: 7 additions & 0 deletions constant/proxy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package constant

// ProxySignal is used to handle graceful shutdown of proxy
type ProxySignal struct {
Done chan<- struct{}
Closed <-chan struct{}
}
31 changes: 31 additions & 0 deletions hub/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package hub

import (
"github.com/Dreamacro/clash/proxy"
T "github.com/Dreamacro/clash/tunnel"
)

var (
tunnel = T.GetInstance()
listener = proxy.Instance()
)

type Error struct {
Error string `json:"error"`
}

type Errors struct {
Errors map[string]string `json:"errors"`
}

func formatErrors(errorsMap map[string]error) (bool, Errors) {
errors := make(map[string]string)
hasError := false
for key, err := range errorsMap {
if err != nil {
errors[key] = err.Error()
hasError = true
}
}
return hasError, Errors{Errors: errors}
}
57 changes: 41 additions & 16 deletions hub/configs.go
Original file line number Diff line number Diff line change
@@ -1,32 +1,39 @@
package hub

import (
"fmt"
"net/http"

"github.com/Dreamacro/clash/tunnel"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/proxy"
T "github.com/Dreamacro/clash/tunnel"

"github.com/go-chi/chi"
"github.com/go-chi/render"
)

func configRouter() http.Handler {
r := chi.NewRouter()
r.Put("/", updateConfig)
r.Get("/", getConfigs)
r.Put("/", updateConfigs)
return r
}

type General struct {
Mode string `json:mode`
var modeMapping = map[string]T.Mode{
"Global": T.Global,
"Rule": T.Rule,
"Direct": T.Direct,
}

var modeMapping = map[string]tunnel.Mode{
"global": tunnel.Global,
"rule": tunnel.Rule,
"direct": tunnel.Direct,
func getConfigs(w http.ResponseWriter, r *http.Request) {
info := listener.Info()
mode := tunnel.GetMode().String()
info.Mode = &mode
render.JSON(w, r, info)
}

func updateConfig(w http.ResponseWriter, r *http.Request) {
general := &General{}
func updateConfigs(w http.ResponseWriter, r *http.Request) {
general := &C.General{}
err := render.DecodeJSON(r.Body, general)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
Expand All @@ -36,14 +43,32 @@ func updateConfig(w http.ResponseWriter, r *http.Request) {
return
}

mode, ok := modeMapping[general.Mode]
if !ok {
// update errors
var proxyErr, modeErr error

// update proxy
listener := proxy.Instance()
proxyErr = listener.Update(general.AllowLan, general.Port, general.SocksPort)

// update mode
if general.Mode != nil {
mode, ok := modeMapping[*general.Mode]
if !ok {
modeErr = fmt.Errorf("Mode error")
} else {
tunnel.SetMode(mode)
}
}

hasError, errors := formatErrors(map[string]error{
"proxy": proxyErr,
"mode": modeErr,
})

if hasError {
w.WriteHeader(http.StatusBadRequest)
render.JSON(w, r, Error{
Error: "Mode error",
})
render.JSON(w, r, errors)
return
}
tun.SetMode(mode)
w.WriteHeader(http.StatusNoContent)
}
6 changes: 3 additions & 3 deletions hub/proxys.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ type GetProxysResponse struct {
}

func getProxys(w http.ResponseWriter, r *http.Request) {
_, rawProxys := tun.Config()
_, rawProxys := tunnel.Config()
proxys := make(map[string]interface{})
for name, proxy := range rawProxys {
proxys[name] = transformProxy(proxy)
Expand All @@ -71,7 +71,7 @@ func getProxys(w http.ResponseWriter, r *http.Request) {

func getProxy(w http.ResponseWriter, r *http.Request) {
name := chi.URLParam(r, "name")
_, proxys := tun.Config()
_, proxys := tunnel.Config()
proxy, exist := proxys[name]
if !exist {
w.WriteHeader(http.StatusNotFound)
Expand All @@ -98,7 +98,7 @@ func updateProxy(w http.ResponseWriter, r *http.Request) {
}

name := chi.URLParam(r, "name")
_, proxys := tun.Config()
_, proxys := tunnel.Config()
proxy, exist := proxys[name]
if !exist {
w.WriteHeader(http.StatusNotFound)
Expand Down
4 changes: 2 additions & 2 deletions hub/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type GetRulesResponse struct {
}

func getRules(w http.ResponseWriter, r *http.Request) {
rulesCfg, _ := tun.Config()
rulesCfg, _ := tunnel.Config()

var rules []Rule
for _, rule := range rulesCfg {
Expand All @@ -41,7 +41,7 @@ func getRules(w http.ResponseWriter, r *http.Request) {
}

func updateRules(w http.ResponseWriter, r *http.Request) {
err := tun.UpdateConfig()
err := tunnel.UpdateConfig()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
render.JSON(w, r, Error{
Expand Down
26 changes: 9 additions & 17 deletions hub/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,18 @@ import (
"net/http"
"time"

"github.com/Dreamacro/clash/tunnel"
T "github.com/Dreamacro/clash/tunnel"

"github.com/go-chi/chi"
"github.com/go-chi/render"
log "github.com/sirupsen/logrus"
)

var (
tun = tunnel.GetInstance()
)

type Traffic struct {
Up int64 `json:"up"`
Down int64 `json:"down"`
}

type Error struct {
Error string `json:"error"`
}

func NewHub(addr string) {
r := chi.NewRouter()

Expand All @@ -44,7 +36,7 @@ func traffic(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)

tick := time.NewTicker(time.Second)
t := tun.Traffic()
t := tunnel.Traffic()
for range tick.C {
up, down := t.Now()
if err := json.NewEncoder(w).Encode(Traffic{
Expand Down Expand Up @@ -73,11 +65,11 @@ func getLogs(w http.ResponseWriter, r *http.Request) {
req.Level = "info"
}

mapping := map[string]tunnel.LogLevel{
"info": tunnel.INFO,
"debug": tunnel.DEBUG,
"error": tunnel.ERROR,
"warning": tunnel.WARNING,
mapping := map[string]T.LogLevel{
"info": T.INFO,
"debug": T.DEBUG,
"error": T.ERROR,
"warning": T.WARNING,
}

level, ok := mapping[req.Level]
Expand All @@ -89,7 +81,7 @@ func getLogs(w http.ResponseWriter, r *http.Request) {
return
}

src := tun.Log()
src := tunnel.Log()
sub, err := src.Subscribe()
defer src.UnSubscribe(sub)
if err != nil {
Expand All @@ -101,7 +93,7 @@ func getLogs(w http.ResponseWriter, r *http.Request) {
}
render.Status(r, http.StatusOK)
for elm := range sub {
log := elm.(tunnel.Log)
log := elm.(T.Log)
if log.LogLevel > level {
continue
}
Expand Down
28 changes: 9 additions & 19 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,28 @@ import (

C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/hub"
"github.com/Dreamacro/clash/proxy/http"
"github.com/Dreamacro/clash/proxy/socks"
"github.com/Dreamacro/clash/proxy"
"github.com/Dreamacro/clash/tunnel"

log "github.com/sirupsen/logrus"
)

func main() {
cfg, err := C.GetConfig()
if err != nil {
log.Fatalf("Read config error: %s", err.Error())
}

port, socksPort := C.DefalutHTTPPort, C.DefalutSOCKSPort
section := cfg.Section("General")
if key, err := section.GetKey("port"); err == nil {
port = key.Value()
if err := tunnel.GetInstance().UpdateConfig(); err != nil {
log.Fatalf("Parse config error: %s", err.Error())
}

if key, err := section.GetKey("socks-port"); err == nil {
socksPort = key.Value()
if err := proxy.Instance().Run(); err != nil {
log.Fatalf("Proxy listen error: %s", err.Error())
}

err = tunnel.GetInstance().UpdateConfig()
// Hub
cfg, err := C.GetConfig()
if err != nil {
log.Fatalf("Parse config error: %s", err.Error())
log.Fatalf("Read config error: %s", err.Error())
}

go http.NewHttpProxy(port)
go socks.NewSocksProxy(socksPort)

// Hub
section := cfg.Section("General")
if key, err := section.GetKey("external-controller"); err == nil {
go hub.NewHub(key.Value())
}
Expand Down
33 changes: 28 additions & 5 deletions proxy/http/server.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package http

import (
"fmt"
"context"
"net"
"net/http"
"strings"
Expand All @@ -17,9 +17,20 @@ var (
tun = tunnel.GetInstance()
)

func NewHttpProxy(port string) {
func NewHttpProxy(addr string) (*C.ProxySignal, error) {
l, err := net.Listen("tcp", addr)
if err != nil {
return nil, err
}

done := make(chan struct{})
closed := make(chan struct{})
signal := &C.ProxySignal{
Done: done,
Closed: closed,
}

server := &http.Server{
Addr: fmt.Sprintf(":%s", port),
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodConnect {
handleTunneling(w, r)
Expand All @@ -28,8 +39,20 @@ func NewHttpProxy(port string) {
}
}),
}
log.Infof("HTTP proxy :%s", port)
server.ListenAndServe()

go func() {
log.Infof("HTTP proxy listening at: %s", addr)
server.Serve(l)
}()

go func() {
<-done
server.Shutdown(context.Background())
l.Close()
closed <- struct{}{}
}()

return signal, nil
}

func handleHTTP(w http.ResponseWriter, r *http.Request) {
Expand Down
Loading

0 comments on commit 3cacfb8

Please sign in to comment.