refactor: Modular inbound/outbound manager
This commit is contained in:
@@ -23,7 +23,7 @@ func groupRouter(server *Server) http.Handler {
|
||||
r := chi.NewRouter()
|
||||
r.Get("/", getGroups(server))
|
||||
r.Route("/{name}", func(r chi.Router) {
|
||||
r.Use(parseProxyName, findProxyByName(server.router))
|
||||
r.Use(parseProxyName, findProxyByName(server))
|
||||
r.Get("/", getGroup(server))
|
||||
r.Get("/delay", getGroupDelay(server))
|
||||
})
|
||||
@@ -32,7 +32,7 @@ func groupRouter(server *Server) http.Handler {
|
||||
|
||||
func getGroups(server *Server) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
groups := common.Map(common.Filter(server.router.Outbounds(), func(it adapter.Outbound) bool {
|
||||
groups := common.Map(common.Filter(server.outboundManager.Outbounds(), func(it adapter.Outbound) bool {
|
||||
_, isGroup := it.(adapter.OutboundGroup)
|
||||
return isGroup
|
||||
}), func(it adapter.Outbound) *badjson.JSONObject {
|
||||
@@ -86,7 +86,7 @@ func getGroupDelay(server *Server) func(w http.ResponseWriter, r *http.Request)
|
||||
result, err = urlTestGroup.URLTest(ctx)
|
||||
} else {
|
||||
outbounds := common.FilterNotNil(common.Map(outboundGroup.All(), func(it string) adapter.Outbound {
|
||||
itOutbound, _ := server.router.Outbound(it)
|
||||
itOutbound, _ := server.outboundManager.Outbound(it)
|
||||
return itOutbound
|
||||
}))
|
||||
b, _ := batch.New(ctx, batch.WithConcurrencyNum[any](10))
|
||||
@@ -100,7 +100,7 @@ func getGroupDelay(server *Server) func(w http.ResponseWriter, r *http.Request)
|
||||
continue
|
||||
}
|
||||
checked[realTag] = true
|
||||
p, loaded := server.router.Outbound(realTag)
|
||||
p, loaded := server.outboundManager.Outbound(realTag)
|
||||
if !loaded {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -23,10 +23,10 @@ import (
|
||||
|
||||
func proxyRouter(server *Server, router adapter.Router) http.Handler {
|
||||
r := chi.NewRouter()
|
||||
r.Get("/", getProxies(server, router))
|
||||
r.Get("/", getProxies(server))
|
||||
|
||||
r.Route("/{name}", func(r chi.Router) {
|
||||
r.Use(parseProxyName, findProxyByName(router))
|
||||
r.Use(parseProxyName, findProxyByName(server))
|
||||
r.Get("/", getProxy(server))
|
||||
r.Get("/delay", getProxyDelay(server))
|
||||
r.Put("/", updateProxy)
|
||||
@@ -42,11 +42,11 @@ func parseProxyName(next http.Handler) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
func findProxyByName(router adapter.Router) func(next http.Handler) http.Handler {
|
||||
func findProxyByName(server *Server) func(next http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
name := r.Context().Value(CtxKeyProxyName).(string)
|
||||
proxy, exist := router.Outbound(name)
|
||||
proxy, exist := server.outboundManager.Outbound(name)
|
||||
if !exist {
|
||||
render.Status(r, http.StatusNotFound)
|
||||
render.JSON(w, r, ErrNotFound)
|
||||
@@ -83,10 +83,10 @@ func proxyInfo(server *Server, detour adapter.Outbound) *badjson.JSONObject {
|
||||
return &info
|
||||
}
|
||||
|
||||
func getProxies(server *Server, router adapter.Router) func(w http.ResponseWriter, r *http.Request) {
|
||||
func getProxies(server *Server) 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 {
|
||||
outbounds := common.Filter(server.outboundManager.Outbounds(), func(detour adapter.Outbound) bool {
|
||||
return detour.Tag() != ""
|
||||
})
|
||||
|
||||
@@ -100,12 +100,7 @@ func getProxies(server *Server, router adapter.Router) func(w http.ResponseWrite
|
||||
allProxies = append(allProxies, detour.Tag())
|
||||
}
|
||||
|
||||
var defaultTag string
|
||||
if defaultOutbound, err := router.DefaultOutbound(N.NetworkTCP); err == nil {
|
||||
defaultTag = defaultOutbound.Tag()
|
||||
} else {
|
||||
defaultTag = allProxies[0]
|
||||
}
|
||||
defaultTag := server.outboundManager.Default().Tag()
|
||||
|
||||
sort.SliceStable(allProxies, func(i, j int) bool {
|
||||
return allProxies[i] == defaultTag
|
||||
|
||||
@@ -40,15 +40,16 @@ func init() {
|
||||
var _ adapter.ClashServer = (*Server)(nil)
|
||||
|
||||
type Server struct {
|
||||
ctx context.Context
|
||||
router adapter.Router
|
||||
logger log.Logger
|
||||
httpServer *http.Server
|
||||
trafficManager *trafficontrol.Manager
|
||||
urlTestHistory *urltest.HistoryStorage
|
||||
mode string
|
||||
modeList []string
|
||||
modeUpdateHook chan<- struct{}
|
||||
ctx context.Context
|
||||
router adapter.Router
|
||||
outboundManager adapter.OutboundManager
|
||||
logger log.Logger
|
||||
httpServer *http.Server
|
||||
trafficManager *trafficontrol.Manager
|
||||
urlTestHistory *urltest.HistoryStorage
|
||||
mode string
|
||||
modeList []string
|
||||
modeUpdateHook chan<- struct{}
|
||||
|
||||
externalController bool
|
||||
externalUI string
|
||||
@@ -56,13 +57,14 @@ type Server struct {
|
||||
externalUIDownloadDetour string
|
||||
}
|
||||
|
||||
func NewServer(ctx context.Context, router adapter.Router, logFactory log.ObservableFactory, options option.ClashAPIOptions) (adapter.ClashServer, error) {
|
||||
func NewServer(ctx context.Context, logFactory log.ObservableFactory, options option.ClashAPIOptions) (adapter.ClashServer, error) {
|
||||
trafficManager := trafficontrol.NewManager()
|
||||
chiRouter := chi.NewRouter()
|
||||
server := &Server{
|
||||
ctx: ctx,
|
||||
router: router,
|
||||
logger: logFactory.NewLogger("clash-api"),
|
||||
s := &Server{
|
||||
ctx: ctx,
|
||||
router: service.FromContext[adapter.Router](ctx),
|
||||
outboundManager: service.FromContext[adapter.OutboundManager](ctx),
|
||||
logger: logFactory.NewLogger("clash-api"),
|
||||
httpServer: &http.Server{
|
||||
Addr: options.ExternalController,
|
||||
Handler: chiRouter,
|
||||
@@ -73,18 +75,18 @@ func NewServer(ctx context.Context, router adapter.Router, logFactory log.Observ
|
||||
externalUIDownloadURL: options.ExternalUIDownloadURL,
|
||||
externalUIDownloadDetour: options.ExternalUIDownloadDetour,
|
||||
}
|
||||
server.urlTestHistory = service.PtrFromContext[urltest.HistoryStorage](ctx)
|
||||
if server.urlTestHistory == nil {
|
||||
server.urlTestHistory = urltest.NewHistoryStorage()
|
||||
s.urlTestHistory = service.PtrFromContext[urltest.HistoryStorage](ctx)
|
||||
if s.urlTestHistory == nil {
|
||||
s.urlTestHistory = urltest.NewHistoryStorage()
|
||||
}
|
||||
defaultMode := "Rule"
|
||||
if options.DefaultMode != "" {
|
||||
defaultMode = options.DefaultMode
|
||||
}
|
||||
if !common.Contains(server.modeList, defaultMode) {
|
||||
server.modeList = append([]string{defaultMode}, server.modeList...)
|
||||
if !common.Contains(s.modeList, defaultMode) {
|
||||
s.modeList = append([]string{defaultMode}, s.modeList...)
|
||||
}
|
||||
server.mode = defaultMode
|
||||
s.mode = defaultMode
|
||||
//goland:noinspection GoDeprecation
|
||||
//nolint:staticcheck
|
||||
if options.StoreMode || options.StoreSelected || options.StoreFakeIP || options.CacheFile != "" || options.CacheID != "" {
|
||||
@@ -108,30 +110,30 @@ func NewServer(ctx context.Context, router adapter.Router, logFactory log.Observ
|
||||
r.Get("/logs", getLogs(logFactory))
|
||||
r.Get("/traffic", traffic(trafficManager))
|
||||
r.Get("/version", version)
|
||||
r.Mount("/configs", configRouter(server, logFactory))
|
||||
r.Mount("/proxies", proxyRouter(server, router))
|
||||
r.Mount("/rules", ruleRouter(router))
|
||||
r.Mount("/connections", connectionRouter(router, trafficManager))
|
||||
r.Mount("/configs", configRouter(s, logFactory))
|
||||
r.Mount("/proxies", proxyRouter(s, s.router))
|
||||
r.Mount("/rules", ruleRouter(s.router))
|
||||
r.Mount("/connections", connectionRouter(s.router, trafficManager))
|
||||
r.Mount("/providers/proxies", proxyProviderRouter())
|
||||
r.Mount("/providers/rules", ruleProviderRouter())
|
||||
r.Mount("/script", scriptRouter())
|
||||
r.Mount("/profile", profileRouter())
|
||||
r.Mount("/cache", cacheRouter(ctx))
|
||||
r.Mount("/dns", dnsRouter(router))
|
||||
r.Mount("/dns", dnsRouter(s.router))
|
||||
|
||||
server.setupMetaAPI(r)
|
||||
s.setupMetaAPI(r)
|
||||
})
|
||||
if options.ExternalUI != "" {
|
||||
server.externalUI = filemanager.BasePath(ctx, os.ExpandEnv(options.ExternalUI))
|
||||
s.externalUI = filemanager.BasePath(ctx, os.ExpandEnv(options.ExternalUI))
|
||||
chiRouter.Group(func(r chi.Router) {
|
||||
fs := http.StripPrefix("/ui", http.FileServer(http.Dir(server.externalUI)))
|
||||
fs := http.StripPrefix("/ui", http.FileServer(http.Dir(s.externalUI)))
|
||||
r.Get("/ui", http.RedirectHandler("/ui/", http.StatusTemporaryRedirect).ServeHTTP)
|
||||
r.Get("/ui/*", func(w http.ResponseWriter, r *http.Request) {
|
||||
fs.ServeHTTP(w, r)
|
||||
})
|
||||
})
|
||||
}
|
||||
return server, nil
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *Server) PreStart() error {
|
||||
@@ -235,12 +237,12 @@ func (s *Server) TrafficManager() *trafficontrol.Manager {
|
||||
}
|
||||
|
||||
func (s *Server) RoutedConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, matchedRule adapter.Rule) (net.Conn, adapter.Tracker) {
|
||||
tracker := trafficontrol.NewTCPTracker(conn, s.trafficManager, metadata, s.router, matchedRule)
|
||||
tracker := trafficontrol.NewTCPTracker(conn, s.trafficManager, metadata, s.outboundManager, matchedRule)
|
||||
return tracker, tracker
|
||||
}
|
||||
|
||||
func (s *Server) RoutedPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext, matchedRule adapter.Rule) (N.PacketConn, adapter.Tracker) {
|
||||
tracker := trafficontrol.NewUDPTracker(conn, s.trafficManager, metadata, s.router, matchedRule)
|
||||
tracker := trafficontrol.NewUDPTracker(conn, s.trafficManager, metadata, s.outboundManager, matchedRule)
|
||||
return tracker, tracker
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/service/filemanager"
|
||||
)
|
||||
|
||||
@@ -45,16 +44,13 @@ func (s *Server) downloadExternalUI() error {
|
||||
s.logger.Info("downloading external ui")
|
||||
var detour adapter.Outbound
|
||||
if s.externalUIDownloadDetour != "" {
|
||||
outbound, loaded := s.router.Outbound(s.externalUIDownloadDetour)
|
||||
outbound, loaded := s.outboundManager.Outbound(s.externalUIDownloadDetour)
|
||||
if !loaded {
|
||||
return E.New("detour outbound not found: ", s.externalUIDownloadDetour)
|
||||
}
|
||||
detour = outbound
|
||||
} else {
|
||||
outbound, err := s.router.DefaultOutbound(N.NetworkTCP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
outbound := s.outboundManager.Default()
|
||||
detour = outbound
|
||||
}
|
||||
httpClient := &http.Client{
|
||||
|
||||
@@ -124,7 +124,7 @@ func (tt *TCPConn) WriterReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func NewTCPTracker(conn net.Conn, manager *Manager, metadata adapter.InboundContext, router adapter.Router, rule adapter.Rule) *TCPConn {
|
||||
func NewTCPTracker(conn net.Conn, manager *Manager, metadata adapter.InboundContext, outboundManager adapter.OutboundManager, rule adapter.Rule) *TCPConn {
|
||||
id, _ := uuid.NewV4()
|
||||
var (
|
||||
chain []string
|
||||
@@ -138,11 +138,11 @@ func NewTCPTracker(conn net.Conn, manager *Manager, metadata adapter.InboundCont
|
||||
}
|
||||
if routeAction, isRouteAction := action.(*R.RuleActionRoute); isRouteAction {
|
||||
next = routeAction.Outbound
|
||||
} else if defaultOutbound, err := router.DefaultOutbound(N.NetworkTCP); err == nil {
|
||||
next = defaultOutbound.Tag()
|
||||
} else {
|
||||
next = outboundManager.Default().Tag()
|
||||
}
|
||||
for {
|
||||
detour, loaded := router.Outbound(next)
|
||||
detour, loaded := outboundManager.Outbound(next)
|
||||
if !loaded {
|
||||
break
|
||||
}
|
||||
@@ -213,7 +213,7 @@ func (ut *UDPConn) WriterReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func NewUDPTracker(conn N.PacketConn, manager *Manager, metadata adapter.InboundContext, router adapter.Router, rule adapter.Rule) *UDPConn {
|
||||
func NewUDPTracker(conn N.PacketConn, manager *Manager, metadata adapter.InboundContext, outboundManager adapter.OutboundManager, rule adapter.Rule) *UDPConn {
|
||||
id, _ := uuid.NewV4()
|
||||
var (
|
||||
chain []string
|
||||
@@ -227,11 +227,11 @@ func NewUDPTracker(conn N.PacketConn, manager *Manager, metadata adapter.Inbound
|
||||
}
|
||||
if routeAction, isRouteAction := action.(*R.RuleActionRoute); isRouteAction {
|
||||
next = routeAction.Outbound
|
||||
} else if defaultOutbound, err := router.DefaultOutbound(N.NetworkUDP); err == nil {
|
||||
next = defaultOutbound.Tag()
|
||||
} else {
|
||||
next = outboundManager.Default().Tag()
|
||||
}
|
||||
for {
|
||||
detour, loaded := router.Outbound(next)
|
||||
detour, loaded := outboundManager.Outbound(next)
|
||||
if !loaded {
|
||||
break
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user