clash/hub/server.go

142 lines
2.7 KiB
Go
Raw Normal View History

2018-06-18 03:31:49 +00:00
package hub
import (
"encoding/json"
"net/http"
"time"
"github.com/Dreamacro/clash/config"
C "github.com/Dreamacro/clash/constant"
2018-07-15 14:23:20 +00:00
T "github.com/Dreamacro/clash/tunnel"
2018-06-18 03:31:49 +00:00
"github.com/go-chi/chi"
2018-07-19 01:31:53 +00:00
"github.com/go-chi/cors"
2018-06-18 03:31:49 +00:00
"github.com/go-chi/render"
log "github.com/sirupsen/logrus"
)
type Traffic struct {
Up int64 `json:"up"`
Down int64 `json:"down"`
}
func newHub(signal chan struct{}) {
var addr string
ch := config.Instance().Subscribe()
signal <- struct{}{}
for {
elm := <-ch
event := elm.(*config.Event)
if event.Type == "external-controller" {
addr = event.Payload.(string)
break
}
}
2018-06-18 03:31:49 +00:00
r := chi.NewRouter()
2018-07-19 01:31:53 +00:00
cors := cors.New(cors.Options{
AllowedOrigins: []string{"*"},
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowedHeaders: []string{"Content-Type"},
MaxAge: 300,
})
r.Use(cors.Handler)
r.With(jsonContentType).Get("/traffic", traffic)
r.With(jsonContentType).Get("/logs", getLogs)
2018-06-20 14:41:02 +00:00
r.Mount("/configs", configRouter())
2018-07-18 13:50:16 +00:00
r.Mount("/proxies", proxyRouter())
r.Mount("/rules", ruleRouter())
2018-06-18 03:31:49 +00:00
err := http.ListenAndServe(addr, r)
if err != nil {
log.Errorf("External controller error: %s", err.Error())
2018-06-18 03:31:49 +00:00
}
}
func jsonContentType(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
next.ServeHTTP(w, r)
}
return http.HandlerFunc(fn)
}
2018-06-18 03:31:49 +00:00
func traffic(w http.ResponseWriter, r *http.Request) {
2018-06-20 14:41:02 +00:00
w.WriteHeader(http.StatusOK)
2018-06-18 03:31:49 +00:00
tick := time.NewTicker(time.Second)
2018-07-15 14:23:20 +00:00
t := tunnel.Traffic()
2018-06-18 03:31:49 +00:00
for range tick.C {
up, down := t.Now()
if err := json.NewEncoder(w).Encode(Traffic{
Up: up,
Down: down,
}); err != nil {
break
}
w.(http.Flusher).Flush()
}
}
2018-06-22 05:15:20 +00:00
type GetLogs struct {
Level string `json:"level"`
}
type Log struct {
Type string `json:"type"`
Payload string `json:"payload"`
}
2018-06-18 03:31:49 +00:00
func getLogs(w http.ResponseWriter, r *http.Request) {
2018-06-22 05:15:20 +00:00
req := &GetLogs{}
render.DecodeJSON(r.Body, req)
if req.Level == "" {
req.Level = "info"
}
level, ok := C.LogLevelMapping[req.Level]
2018-06-22 05:15:20 +00:00
if !ok {
w.WriteHeader(http.StatusBadRequest)
render.JSON(w, r, Error{
Error: "Level error",
})
return
}
2018-07-15 14:23:20 +00:00
src := tunnel.Log()
2018-06-18 03:31:49 +00:00
sub, err := src.Subscribe()
defer src.UnSubscribe(sub)
if err != nil {
2018-06-20 14:41:02 +00:00
w.WriteHeader(http.StatusInternalServerError)
2018-06-18 03:31:49 +00:00
render.JSON(w, r, Error{
Error: err.Error(),
})
2018-06-20 14:41:02 +00:00
return
2018-06-18 03:31:49 +00:00
}
render.Status(r, http.StatusOK)
for elm := range sub {
2018-07-15 14:23:20 +00:00
log := elm.(T.Log)
2018-06-22 05:15:20 +00:00
if log.LogLevel > level {
continue
}
2018-06-18 03:31:49 +00:00
if err := json.NewEncoder(w).Encode(Log{
Type: log.Type(),
Payload: log.Payload,
}); err != nil {
break
}
w.(http.Flusher).Flush()
}
}
// Run initial hub
func Run() {
signal := make(chan struct{})
go newHub(signal)
<-signal
}