Browse Source

Fix integration with clash-dashboard

世界 3 years ago
parent
commit
3838d3070d

+ 5 - 5
experimental/clashapi/connections.go

@@ -7,14 +7,14 @@ import (
 	"strconv"
 	"time"
 
-	"github.com/sagernet/sing-box/experimental/clashapi/trafficontroll"
+	"github.com/sagernet/sing-box/experimental/clashapi/trafficontrol"
 
 	"github.com/go-chi/chi/v5"
 	"github.com/go-chi/render"
 	"github.com/gorilla/websocket"
 )
 
-func connectionRouter(trafficManager *trafficontroll.Manager) http.Handler {
+func connectionRouter(trafficManager *trafficontrol.Manager) http.Handler {
 	r := chi.NewRouter()
 	r.Get("/", getConnections(trafficManager))
 	r.Delete("/", closeAllConnections(trafficManager))
@@ -22,7 +22,7 @@ func connectionRouter(trafficManager *trafficontroll.Manager) http.Handler {
 	return r
 }
 
-func getConnections(trafficManager *trafficontroll.Manager) func(w http.ResponseWriter, r *http.Request) {
+func getConnections(trafficManager *trafficontrol.Manager) func(w http.ResponseWriter, r *http.Request) {
 	return func(w http.ResponseWriter, r *http.Request) {
 		if !websocket.IsWebSocketUpgrade(r) {
 			snapshot := trafficManager.Snapshot()
@@ -72,7 +72,7 @@ func getConnections(trafficManager *trafficontroll.Manager) func(w http.Response
 	}
 }
 
-func closeConnection(trafficManager *trafficontroll.Manager) func(w http.ResponseWriter, r *http.Request) {
+func closeConnection(trafficManager *trafficontrol.Manager) func(w http.ResponseWriter, r *http.Request) {
 	return func(w http.ResponseWriter, r *http.Request) {
 		id := chi.URLParam(r, "id")
 		snapshot := trafficManager.Snapshot()
@@ -86,7 +86,7 @@ func closeConnection(trafficManager *trafficontroll.Manager) func(w http.Respons
 	}
 }
 
-func closeAllConnections(trafficManager *trafficontroll.Manager) func(w http.ResponseWriter, r *http.Request) {
+func closeAllConnections(trafficManager *trafficontrol.Manager) func(w http.ResponseWriter, r *http.Request) {
 	return func(w http.ResponseWriter, r *http.Request) {
 		snapshot := trafficManager.Snapshot()
 		for _, c := range snapshot.Connections {

+ 6 - 33
experimental/clashapi/provider.go

@@ -4,15 +4,13 @@ import (
 	"context"
 	"net/http"
 
-	"github.com/sagernet/sing-box/adapter"
-
 	"github.com/go-chi/chi/v5"
 	"github.com/go-chi/render"
 )
 
-func proxyProviderRouter(server *Server, router adapter.Router) http.Handler {
+func proxyProviderRouter() http.Handler {
 	r := chi.NewRouter()
-	r.Get("/", getProviders(server, router))
+	r.Get("/", getProviders)
 
 	r.Route("/{name}", func(r chi.Router) {
 		r.Use(parseProviderName, findProviderByName)
@@ -23,35 +21,10 @@ func proxyProviderRouter(server *Server, router adapter.Router) http.Handler {
 	return r
 }
 
-func getProviders(server *Server, router adapter.Router) func(w http.ResponseWriter, r *http.Request) {
-	return func(w http.ResponseWriter, r *http.Request) {
-		var proxies []any
-		proxies = append(proxies, render.M{
-			"history": []*DelayHistory{},
-			"name":    "DIRECT",
-			"type":    "Direct",
-			"udp":     true,
-		})
-		proxies = append(proxies, render.M{
-			"history": []*DelayHistory{},
-			"name":    "REJECT",
-			"type":    "Reject",
-			"udp":     true,
-		})
-		for _, detour := range router.Outbounds() {
-			proxies = append(proxies, proxyInfo(server, detour))
-		}
-		render.JSON(w, r, render.M{
-			"providers": render.M{
-				"default": render.M{
-					"name":        "default",
-					"type":        "Proxy",
-					"proxies":     proxies,
-					"vehicleType": "Compatible",
-				},
-			},
-		})
-	}
+func getProviders(w http.ResponseWriter, r *http.Request) {
+	render.JSON(w, r, render.M{
+		"providers": render.M{},
+	})
 }
 
 func getProvider(w http.ResponseWriter, r *http.Request) {

+ 36 - 23
experimental/clashapi/proxies.go

@@ -19,6 +19,7 @@ import (
 
 	"github.com/go-chi/chi/v5"
 	"github.com/go-chi/render"
+	"sort"
 )
 
 func proxyRouter(server *Server, router adapter.Router) http.Handler {
@@ -85,17 +86,20 @@ func proxyInfo(server *Server, detour adapter.Outbound) *badjson.JSONObject {
 	info.Put("name", detour.Tag())
 	info.Put("udp", common.Contains(detour.Network(), C.NetworkUDP))
 
-	delayHistory, loaded := server.delayHistory[detour.Tag()]
-	if loaded {
-		info.Put("history", []*DelayHistory{delayHistory, delayHistory})
-	} else {
-		info.Put("history", []*DelayHistory{{Time: time.Now()}, {Time: time.Now()}})
-	}
-
+	var delayHistory *DelayHistory
+	var loaded bool
 	if isSelector {
 		selector := detour.(*outbound.Selector)
 		info.Put("now", selector.Now())
 		info.Put("all", selector.All())
+		delayHistory, loaded = server.delayHistory[selector.Now()]
+	} else {
+		delayHistory, loaded = server.delayHistory[detour.Tag()]
+	}
+	if loaded {
+		info.Put("history", []*DelayHistory{delayHistory})
+	} else {
+		info.Put("history", []*DelayHistory{})
 	}
 	return &info
 }
@@ -103,30 +107,39 @@ func proxyInfo(server *Server, detour adapter.Outbound) *badjson.JSONObject {
 func getProxies(server *Server, router adapter.Router) func(w http.ResponseWriter, r *http.Request) {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var proxyMap badjson.JSONObject
+		outbounds := common.Filter(router.Outbounds(), func(detour adapter.Outbound) bool {
+			return detour.Tag() != ""
+		})
 
-		// fix clash dashboard
-		proxyMap.Put("DIRECT", map[string]any{
-			"type":    "Direct",
-			"name":    "DIRECT",
-			"udp":     true,
-			"history": []*DelayHistory{},
+		allProxies := make([]string, 0, len(outbounds))
+
+		for _, detour := range outbounds {
+			switch detour.Type() {
+			case C.TypeDirect, C.TypeBlock:
+				continue
+			}
+			allProxies = append(allProxies, detour.Tag())
+		}
+
+		defaultTag := router.DefaultOutbound(C.NetworkTCP).Tag()
+		if defaultTag == "" {
+			defaultTag = allProxies[0]
+		}
+
+		sort.Slice(allProxies, func(i, j int) bool {
+			return allProxies[i] == defaultTag
 		})
+
+		// fix clash dashboard
 		proxyMap.Put("GLOBAL", map[string]any{
-			"type":    "Selector",
+			"type":    "Fallback",
 			"name":    "GLOBAL",
 			"udp":     true,
 			"history": []*DelayHistory{},
-			"all":     []string{},
-			"now":     "",
-		})
-		proxyMap.Put("REJECT", map[string]any{
-			"type":    "Reject",
-			"name":    "REJECT",
-			"udp":     true,
-			"history": []*DelayHistory{},
+			"all":     allProxies,
+			"now":     defaultTag,
 		})
 
-		outbounds := router.Outbounds()
 		for i, detour := range outbounds {
 			var tag string
 			if detour.Tag() == "" {

+ 9 - 9
experimental/clashapi/server.go

@@ -11,7 +11,7 @@ import (
 
 	"github.com/sagernet/sing-box/adapter"
 	C "github.com/sagernet/sing-box/constant"
-	"github.com/sagernet/sing-box/experimental/clashapi/trafficontroll"
+	"github.com/sagernet/sing-box/experimental/clashapi/trafficontrol"
 	"github.com/sagernet/sing-box/log"
 	"github.com/sagernet/sing-box/option"
 	E "github.com/sagernet/sing/common/exceptions"
@@ -30,7 +30,7 @@ var _ adapter.ClashServer = (*Server)(nil)
 type Server struct {
 	logger         log.Logger
 	httpServer     *http.Server
-	trafficManager *trafficontroll.Manager
+	trafficManager *trafficontrol.Manager
 	delayHistory   map[string]*DelayHistory
 }
 
@@ -40,7 +40,7 @@ type DelayHistory struct {
 }
 
 func NewServer(router adapter.Router, logFactory log.ObservableFactory, options option.ClashAPIOptions) *Server {
-	trafficManager := trafficontroll.NewManager()
+	trafficManager := trafficontrol.NewManager()
 	chiRouter := chi.NewRouter()
 	server := &Server{
 		logFactory.NewLogger("clash-api"),
@@ -68,7 +68,7 @@ func NewServer(router adapter.Router, logFactory log.ObservableFactory, options
 		r.Mount("/proxies", proxyRouter(server, router))
 		r.Mount("/rules", ruleRouter(router))
 		r.Mount("/connections", connectionRouter(trafficManager))
-		r.Mount("/providers/proxies", proxyProviderRouter(server, router))
+		r.Mount("/providers/proxies", proxyProviderRouter())
 		r.Mount("/providers/rules", ruleProviderRouter())
 		r.Mount("/script", scriptRouter())
 		r.Mount("/profile", profileRouter())
@@ -106,14 +106,14 @@ func (s *Server) Close() error {
 }
 
 func (s *Server) RoutedConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, matchedRule adapter.Rule) net.Conn {
-	return trafficontroll.NewTCPTracker(conn, s.trafficManager, castMetadata(metadata), matchedRule)
+	return trafficontrol.NewTCPTracker(conn, s.trafficManager, castMetadata(metadata), matchedRule)
 }
 
 func (s *Server) RoutedPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext, matchedRule adapter.Rule) N.PacketConn {
-	return trafficontroll.NewUDPTracker(conn, s.trafficManager, castMetadata(metadata), matchedRule)
+	return trafficontrol.NewUDPTracker(conn, s.trafficManager, castMetadata(metadata), matchedRule)
 }
 
-func castMetadata(metadata adapter.InboundContext) trafficontroll.Metadata {
+func castMetadata(metadata adapter.InboundContext) trafficontrol.Metadata {
 	var inbound string
 	if metadata.Inbound != "" {
 		inbound = metadata.InboundType + "/" + metadata.Inbound
@@ -126,7 +126,7 @@ func castMetadata(metadata adapter.InboundContext) trafficontroll.Metadata {
 	} else {
 		domain = metadata.Destination.Fqdn
 	}
-	return trafficontroll.Metadata{
+	return trafficontrol.Metadata{
 		NetWork: metadata.Network,
 		Type:    inbound,
 		SrcIP:   metadata.Source.Addr,
@@ -189,7 +189,7 @@ type Traffic struct {
 	Down int64 `json:"down"`
 }
 
-func traffic(trafficManager *trafficontroll.Manager) func(w http.ResponseWriter, r *http.Request) {
+func traffic(trafficManager *trafficontrol.Manager) func(w http.ResponseWriter, r *http.Request) {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var wsConn *websocket.Conn
 		if websocket.IsWebSocketUpgrade(r) {

+ 1 - 1
experimental/clashapi/trafficontroll/manager.go → experimental/clashapi/trafficontrol/manager.go

@@ -1,4 +1,4 @@
-package trafficontroll
+package trafficontrol
 
 import (
 	"time"

+ 1 - 1
experimental/clashapi/trafficontroll/tracker.go → experimental/clashapi/trafficontrol/tracker.go

@@ -1,4 +1,4 @@
-package trafficontroll
+package trafficontrol
 
 import (
 	"net"