Skip to content

Commit

Permalink
Add: selector and proxys & rules router
Browse files Browse the repository at this point in the history
  • Loading branch information
Dreamacro committed Jul 12, 2018
1 parent 39b4551 commit 0eef9bb
Show file tree
Hide file tree
Showing 12 changed files with 390 additions and 47 deletions.
4 changes: 4 additions & 0 deletions adapters/direct.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ func (d *Direct) Name() string {
return "Direct"
}

func (d *Direct) Type() C.AdapterType {
return C.Direct
}

func (d *Direct) Generator(addr *C.Addr) (adapter C.ProxyAdapter, err error) {
c, err := net.Dial("tcp", net.JoinHostPort(addr.String(), addr.Port))
if err != nil {
Expand Down
4 changes: 4 additions & 0 deletions adapters/reject.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ func (r *Reject) Name() string {
return "Reject"
}

func (r *Reject) Type() C.AdapterType {
return C.Reject
}

func (r *Reject) Generator(addr *C.Addr) (adapter C.ProxyAdapter, err error) {
return &RejectAdapter{}, nil
}
Expand Down
65 changes: 65 additions & 0 deletions adapters/selector.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package adapters

import (
"errors"

C "github.com/Dreamacro/clash/constant"
)

type Selector struct {
name string
selected C.Proxy
proxys map[string]C.Proxy
}

func (s *Selector) Name() string {
return s.name
}

func (s *Selector) Type() C.AdapterType {
return C.Selector
}

func (s *Selector) Generator(addr *C.Addr) (adapter C.ProxyAdapter, err error) {
return s.selected.Generator(addr)
}

func (s *Selector) Now() string {
return s.selected.Name()
}

func (s *Selector) All() []string {
var all []string
for k, _ := range s.proxys {
all = append(all, k)
}
return all
}

func (s *Selector) Set(name string) error {
proxy, exist := s.proxys[name]
if !exist {
return errors.New("Proxy does not exist")
}
s.selected = proxy
return nil
}

func NewSelector(name string, proxys map[string]C.Proxy) (*Selector, error) {
if len(proxys) == 0 {
return nil, errors.New("Provide at least one proxy")
}

mapping := make(map[string]C.Proxy)
var init string
for k, v := range proxys {
mapping[k] = v
init = k
}
s := &Selector{
name: name,
proxys: mapping,
selected: proxys[init],
}
return s, nil
}
4 changes: 4 additions & 0 deletions adapters/shadowsocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ func (ss *ShadowSocks) Name() string {
return ss.name
}

func (ss *ShadowSocks) Type() C.AdapterType {
return C.Shadowsocks
}

func (ss *ShadowSocks) Generator(addr *C.Addr) (adapter C.ProxyAdapter, err error) {
c, err := net.Dial("tcp", ss.server)
if err != nil {
Expand Down
8 changes: 8 additions & 0 deletions adapters/urltest.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ func (u *URLTest) Name() string {
return u.name
}

func (u *URLTest) Type() C.AdapterType {
return C.URLTest
}

func (u *URLTest) Now() string {
return u.fast.Name()
}

func (u *URLTest) Generator(addr *C.Addr) (adapter C.ProxyAdapter, err error) {
return u.fast.Generator(addr)
}
Expand Down
30 changes: 30 additions & 0 deletions constant/adapters.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ import (
"net"
)

// Adapter Type
const (
Direct AdapterType = iota
Reject
Selector
Shadowsocks
URLTest
)

type ProxyAdapter interface {
ReadWriter() io.ReadWriter
Conn() net.Conn
Expand All @@ -19,5 +28,26 @@ type ServerAdapter interface {

type Proxy interface {
Name() string
Type() AdapterType
Generator(addr *Addr) (ProxyAdapter, error)
}

// AdapterType is enum of adapter type
type AdapterType int

func (at AdapterType) String() string {
switch at {
case Direct:
return "Direct"
case Reject:
return "Reject"
case Selector:
return "Selector"
case Shadowsocks:
return "Shadowsocks"
case URLTest:
return "URLTest"
default:
return "Unknow"
}
}
64 changes: 23 additions & 41 deletions hub/configs.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,65 +3,47 @@ package hub
import (
"net/http"

"github.com/Dreamacro/clash/tunnel"

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

type Configs struct {
Proxys []Proxy `json:"proxys"`
Rules []Rule `json:"rules"`
}

type Proxy struct {
Name string `json:"name"`
}

type Rule struct {
Name string `json:"name"`
Payload string `json:"type"`
}

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

func getConfig(w http.ResponseWriter, r *http.Request) {
rulesCfg, proxysCfg := tun.Config()

var (
rules []Rule
proxys []Proxy
)

for _, rule := range rulesCfg {
rules = append(rules, Rule{
Name: rule.RuleType().String(),
Payload: rule.Payload(),
})
}

for _, proxy := range proxysCfg {
proxys = append(proxys, Proxy{Name: proxy.Name()})
}
type General struct {
Mode string `json:mode`
}

w.WriteHeader(http.StatusOK)
render.JSON(w, r, Configs{
Rules: rules,
Proxys: proxys,
})
var modeMapping = map[string]tunnel.Mode{
"global": tunnel.Global,
"rule": tunnel.Rule,
"direct": tunnel.Direct,
}

func updateConfig(w http.ResponseWriter, r *http.Request) {
err := tun.UpdateConfig()
general := &General{}
err := render.DecodeJSON(r.Body, general)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.WriteHeader(http.StatusBadRequest)
render.JSON(w, r, Error{
Error: "Format error",
})
return
}

mode, ok := modeMapping[general.Mode]
if !ok {
w.WriteHeader(http.StatusBadRequest)
render.JSON(w, r, Error{
Error: err.Error(),
Error: "Mode error",
})
return
}
tun.SetMode(mode)
w.WriteHeader(http.StatusNoContent)
}
129 changes: 129 additions & 0 deletions hub/proxys.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package hub

import (
"fmt"
"net/http"

A "github.com/Dreamacro/clash/adapters"
C "github.com/Dreamacro/clash/constant"

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

func proxyRouter() http.Handler {
r := chi.NewRouter()
r.Get("/", getProxys)
r.Get("/{name}", getProxy)
r.Put("/{name}", updateProxy)
return r
}

type SampleProxy struct {
Type string `json:"type"`
}

type Selector struct {
Type string `json:"type"`
Now string `json:"now"`
All []string `json:"all"`
}

type URLTest struct {
Type string `json:"type"`
Now string `json:"now"`
}

func transformProxy(proxy C.Proxy) interface{} {
t := proxy.Type()
switch t {
case C.Selector:
selector := proxy.(*A.Selector)
return Selector{
Type: t.String(),
Now: selector.Now(),
All: selector.All(),
}
case C.URLTest:
return URLTest{
Type: t.String(),
Now: proxy.(*A.URLTest).Now(),
}
default:
return SampleProxy{
Type: proxy.Type().String(),
}
}
}

type GetProxysResponse struct {
Proxys map[string]interface{} `json:"proxys"`
}

func getProxys(w http.ResponseWriter, r *http.Request) {
_, rawProxys := tun.Config()
proxys := make(map[string]interface{})
for name, proxy := range rawProxys {
proxys[name] = transformProxy(proxy)
}
render.JSON(w, r, GetProxysResponse{Proxys: proxys})
}

func getProxy(w http.ResponseWriter, r *http.Request) {
name := chi.URLParam(r, "name")
_, proxys := tun.Config()
proxy, exist := proxys[name]
if !exist {
w.WriteHeader(http.StatusNotFound)
render.JSON(w, r, Error{
Error: "Proxy not found",
})
return
}
render.JSON(w, r, transformProxy(proxy))
}

type UpdateProxyRequest struct {
Name string `json:"name"`
}

func updateProxy(w http.ResponseWriter, r *http.Request) {
req := UpdateProxyRequest{}
if err := render.DecodeJSON(r.Body, &req); err != nil {
w.WriteHeader(http.StatusBadRequest)
render.JSON(w, r, Error{
Error: "Format error",
})
return
}

name := chi.URLParam(r, "name")
_, proxys := tun.Config()
proxy, exist := proxys[name]
if !exist {
w.WriteHeader(http.StatusNotFound)
render.JSON(w, r, Error{
Error: "Proxy not found",
})
return
}

selector, ok := proxy.(*A.Selector)
if !ok {
w.WriteHeader(http.StatusBadRequest)
render.JSON(w, r, Error{
Error: "Proxy can't update",
})
return
}

if err := selector.Set(req.Name); err != nil {
w.WriteHeader(http.StatusBadRequest)
render.JSON(w, r, Error{
Error: fmt.Sprintf("Selector update error: %s", err.Error()),
})
return
}

w.WriteHeader(http.StatusNoContent)
}
Loading

0 comments on commit 0eef9bb

Please sign in to comment.