mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-10-20 00:04:24 +00:00
Merge tag 'v1.14.0'
This commit is contained in:
@@ -9,21 +9,21 @@ import (
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/cors"
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/trafficcontrol"
|
||||
"github.com/sagernet/sing-box/common/urltest"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/experimental"
|
||||
"github.com/sagernet/sing-box/experimental/clashapi/trafficontrol"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/json"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/common/observable"
|
||||
"github.com/sagernet/sing/service"
|
||||
"github.com/sagernet/sing/service/filemanager"
|
||||
@@ -42,6 +42,7 @@ var _ adapter.ClashServer = (*Server)(nil)
|
||||
|
||||
type Server struct {
|
||||
ctx context.Context
|
||||
network adapter.NetworkManager
|
||||
router adapter.Router
|
||||
dnsRouter adapter.DNSRouter
|
||||
outbound adapter.OutboundManager
|
||||
@@ -49,13 +50,14 @@ type Server struct {
|
||||
provider adapter.ProviderManager
|
||||
logger log.Logger
|
||||
httpServer *http.Server
|
||||
trafficManager *trafficontrol.Manager
|
||||
urlTestHistory adapter.URLTestHistoryStorage
|
||||
trafficManager *trafficcontrol.Manager
|
||||
urlTestHistory *urltest.HistoryStorage
|
||||
logDebug bool
|
||||
|
||||
mode string
|
||||
modeList []string
|
||||
modeUpdateHook *observable.Subscriber[struct{}]
|
||||
mode string
|
||||
modeList []string
|
||||
modeUpdateAccess sync.Mutex
|
||||
modeUpdateHooks []*observable.Subscriber[struct{}]
|
||||
|
||||
externalController bool
|
||||
externalUI string
|
||||
@@ -64,10 +66,18 @@ type Server struct {
|
||||
}
|
||||
|
||||
func NewServer(ctx context.Context, logFactory log.ObservableFactory, options option.ClashAPIOptions) (adapter.ClashServer, error) {
|
||||
trafficManager := trafficontrol.NewManager()
|
||||
trafficManager := service.PtrFromContext[trafficcontrol.Manager](ctx)
|
||||
if trafficManager == nil {
|
||||
return nil, E.New("missing traffic manager")
|
||||
}
|
||||
urlTestHistory := service.PtrFromContext[urltest.HistoryStorage](ctx)
|
||||
if urlTestHistory == nil {
|
||||
return nil, E.New("missing URL test history storage")
|
||||
}
|
||||
chiRouter := chi.NewRouter()
|
||||
s := &Server{
|
||||
ctx: ctx,
|
||||
network: service.FromContext[adapter.NetworkManager](ctx),
|
||||
router: service.FromContext[adapter.Router](ctx),
|
||||
dnsRouter: service.FromContext[adapter.DNSRouter](ctx),
|
||||
outbound: service.FromContext[adapter.OutboundManager](ctx),
|
||||
@@ -79,16 +89,13 @@ func NewServer(ctx context.Context, logFactory log.ObservableFactory, options op
|
||||
Handler: chiRouter,
|
||||
},
|
||||
trafficManager: trafficManager,
|
||||
urlTestHistory: urlTestHistory,
|
||||
logDebug: logFactory.Level() >= log.LevelDebug,
|
||||
modeList: options.ModeList,
|
||||
externalController: options.ExternalController != "",
|
||||
externalUIDownloadURL: options.ExternalUIDownloadURL,
|
||||
externalUIDownloadDetour: options.ExternalUIDownloadDetour,
|
||||
}
|
||||
s.urlTestHistory = service.FromContext[adapter.URLTestHistoryStorage](ctx)
|
||||
if s.urlTestHistory == nil {
|
||||
s.urlTestHistory = urltest.NewHistoryStorage()
|
||||
}
|
||||
defaultMode := "Rule"
|
||||
if options.DefaultMode != "" {
|
||||
defaultMode = options.DefaultMode
|
||||
@@ -123,7 +130,7 @@ func NewServer(ctx context.Context, logFactory log.ObservableFactory, options op
|
||||
r.Mount("/configs", configRouter(s, logFactory))
|
||||
r.Mount("/proxies", proxyRouter(s, s.router))
|
||||
r.Mount("/rules", ruleRouter(s.router))
|
||||
r.Mount("/connections", connectionRouter(s.ctx, s.router, trafficManager))
|
||||
r.Mount("/connections", connectionRouter(s.ctx, s.network, trafficManager))
|
||||
r.Mount("/providers/proxies", proxyProviderRouter(s))
|
||||
r.Mount("/providers/rules", ruleProviderRouter())
|
||||
r.Mount("/script", scriptRouter())
|
||||
@@ -135,6 +142,10 @@ func NewServer(ctx context.Context, logFactory log.ObservableFactory, options op
|
||||
})
|
||||
if options.ExternalUI != "" {
|
||||
s.externalUI = filemanager.BasePath(ctx, os.ExpandEnv(options.ExternalUI))
|
||||
_, err := filemanager.ReadDir(ctx, s.externalUI)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return nil, E.Cause(err, "read external UI directory")
|
||||
}
|
||||
chiRouter.Group(func(r chi.Router) {
|
||||
r.Get("/ui", http.RedirectHandler("/ui/", http.StatusMovedPermanently).ServeHTTP)
|
||||
r.Handle("/ui/*", http.StripPrefix("/ui/", http.FileServer(Dir(s.externalUI))))
|
||||
@@ -193,8 +204,6 @@ func (s *Server) Start(stage adapter.StartStage) error {
|
||||
func (s *Server) Close() error {
|
||||
return common.Close(
|
||||
common.PtrOrNil(s.httpServer),
|
||||
s.trafficManager,
|
||||
s.urlTestHistory,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -206,8 +215,10 @@ func (s *Server) ModeList() []string {
|
||||
return s.modeList
|
||||
}
|
||||
|
||||
func (s *Server) SetModeUpdateHook(hook *observable.Subscriber[struct{}]) {
|
||||
s.modeUpdateHook = hook
|
||||
func (s *Server) AddModeUpdateHook(hook *observable.Subscriber[struct{}]) {
|
||||
s.modeUpdateAccess.Lock()
|
||||
defer s.modeUpdateAccess.Unlock()
|
||||
s.modeUpdateHooks = append(s.modeUpdateHooks, hook)
|
||||
}
|
||||
|
||||
func (s *Server) SetMode(newMode string) {
|
||||
@@ -223,9 +234,11 @@ func (s *Server) SetMode(newMode string) {
|
||||
return
|
||||
}
|
||||
s.mode = newMode
|
||||
if s.modeUpdateHook != nil {
|
||||
s.modeUpdateHook.Emit(struct{}{})
|
||||
s.modeUpdateAccess.Lock()
|
||||
for _, hook := range s.modeUpdateHooks {
|
||||
hook.Emit(struct{}{})
|
||||
}
|
||||
s.modeUpdateAccess.Unlock()
|
||||
s.dnsRouter.ClearCache()
|
||||
cacheFile := service.FromContext[adapter.CacheFile](s.ctx)
|
||||
if cacheFile != nil {
|
||||
@@ -237,22 +250,6 @@ func (s *Server) SetMode(newMode string) {
|
||||
s.logger.Notice("updated mode: ", newMode)
|
||||
}
|
||||
|
||||
func (s *Server) HistoryStorage() adapter.URLTestHistoryStorage {
|
||||
return s.urlTestHistory
|
||||
}
|
||||
|
||||
func (s *Server) TrafficManager() *trafficontrol.Manager {
|
||||
return s.trafficManager
|
||||
}
|
||||
|
||||
func (s *Server) RoutedConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, matchedRule adapter.Rule, matchOutbound adapter.Outbound) net.Conn {
|
||||
return trafficontrol.NewTCPTracker(conn, s.trafficManager, metadata, s.outbound, matchedRule, matchOutbound)
|
||||
}
|
||||
|
||||
func (s *Server) RoutedPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext, matchedRule adapter.Rule, matchOutbound adapter.Outbound) N.PacketConn {
|
||||
return trafficontrol.NewUDPTracker(conn, s.trafficManager, metadata, s.outbound, matchedRule, matchOutbound)
|
||||
}
|
||||
|
||||
func authentication(serverSecret string) func(next http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -305,7 +302,7 @@ type Traffic struct {
|
||||
Down int64 `json:"down"`
|
||||
}
|
||||
|
||||
func traffic(ctx context.Context, trafficManager *trafficontrol.Manager) func(w http.ResponseWriter, r *http.Request) {
|
||||
func traffic(ctx context.Context, trafficManager *trafficcontrol.Manager) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var conn net.Conn
|
||||
if r.Header.Get("Upgrade") == "websocket" {
|
||||
|
||||
Reference in New Issue
Block a user