update new features service-dns
This commit is contained in:
@@ -92,7 +92,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
### Build s-ui
|
### Build s-ui
|
||||||
go build -ldflags="-w -s" -tags "with_quic,with_grpc,with_ech,with_utls,with_reality_server,with_acme,with_gvisor" -o sui main.go
|
go build -ldflags="-w -s" -tags "with_quic,with_grpc,with_utls,with_acme,with_gvisor" -o sui main.go
|
||||||
|
|
||||||
mkdir s-ui
|
mkdir s-ui
|
||||||
cp sui s-ui/
|
cp sui s-ui/
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ type ApiService struct {
|
|||||||
service.InboundService
|
service.InboundService
|
||||||
service.OutboundService
|
service.OutboundService
|
||||||
service.EndpointService
|
service.EndpointService
|
||||||
|
service.ServicesService
|
||||||
service.PanelService
|
service.PanelService
|
||||||
service.StatsService
|
service.StatsService
|
||||||
service.ServerService
|
service.ServerService
|
||||||
@@ -81,6 +82,10 @@ func (a *ApiService) getData(c *gin.Context) (interface{}, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
services, err := a.ServicesService.GetAll()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
subURI, err := a.SettingService.GetFinalSubURI(strings.Split(c.Request.Host, ":")[0])
|
subURI, err := a.SettingService.GetFinalSubURI(strings.Split(c.Request.Host, ":")[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -91,6 +96,7 @@ func (a *ApiService) getData(c *gin.Context) (interface{}, error) {
|
|||||||
data["inbounds"] = inbounds
|
data["inbounds"] = inbounds
|
||||||
data["outbounds"] = outbounds
|
data["outbounds"] = outbounds
|
||||||
data["endpoints"] = endpoints
|
data["endpoints"] = endpoints
|
||||||
|
data["services"] = services
|
||||||
data["subURI"] = subURI
|
data["subURI"] = subURI
|
||||||
data["onlines"] = onlines
|
data["onlines"] = onlines
|
||||||
} else {
|
} else {
|
||||||
@@ -124,6 +130,12 @@ func (a *ApiService) LoadPartialData(c *gin.Context, objs []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
data[obj] = endpoints
|
data[obj] = endpoints
|
||||||
|
case "services":
|
||||||
|
services, err := a.ServicesService.GetAll()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
data[obj] = services
|
||||||
case "tls":
|
case "tls":
|
||||||
tlsConfigs, err := a.TlsService.GetAll()
|
tlsConfigs, err := a.TlsService.GetAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+145
-49
@@ -12,9 +12,13 @@ import (
|
|||||||
"github.com/sagernet/sing-box/adapter/endpoint"
|
"github.com/sagernet/sing-box/adapter/endpoint"
|
||||||
"github.com/sagernet/sing-box/adapter/inbound"
|
"github.com/sagernet/sing-box/adapter/inbound"
|
||||||
"github.com/sagernet/sing-box/adapter/outbound"
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
|
boxService "github.com/sagernet/sing-box/adapter/service"
|
||||||
|
"github.com/sagernet/sing-box/common/certificate"
|
||||||
"github.com/sagernet/sing-box/common/dialer"
|
"github.com/sagernet/sing-box/common/dialer"
|
||||||
"github.com/sagernet/sing-box/common/taskmonitor"
|
"github.com/sagernet/sing-box/common/taskmonitor"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
"github.com/sagernet/sing-box/dns"
|
||||||
|
"github.com/sagernet/sing-box/dns/transport/local"
|
||||||
"github.com/sagernet/sing-box/experimental/cachefile"
|
"github.com/sagernet/sing-box/experimental/cachefile"
|
||||||
"github.com/sagernet/sing-box/experimental/libbox/platform"
|
"github.com/sagernet/sing-box/experimental/libbox/platform"
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
@@ -28,21 +32,24 @@ import (
|
|||||||
"github.com/sagernet/sing/service/pause"
|
"github.com/sagernet/sing/service/pause"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ adapter.Service = (*Box)(nil)
|
var _ adapter.SimpleLifecycle = (*Box)(nil)
|
||||||
|
|
||||||
type Box struct {
|
type Box struct {
|
||||||
createdAt time.Time
|
createdAt time.Time
|
||||||
logFactory log.Factory
|
logFactory log.Factory
|
||||||
logger log.ContextLogger
|
logger log.ContextLogger
|
||||||
network *route.NetworkManager
|
network *route.NetworkManager
|
||||||
endpoint *endpoint.Manager
|
endpoint *endpoint.Manager
|
||||||
inbound *inbound.Manager
|
inbound *inbound.Manager
|
||||||
outbound *outbound.Manager
|
outbound *outbound.Manager
|
||||||
connection *route.ConnectionManager
|
service *boxService.Manager
|
||||||
router *route.Router
|
dnsTransport *dns.TransportManager
|
||||||
services []adapter.LifecycleService
|
dnsRouter *dns.Router
|
||||||
connTracker *ConnTracker
|
connection *route.ConnectionManager
|
||||||
done chan struct{}
|
router *route.Router
|
||||||
|
internalService []adapter.LifecycleService
|
||||||
|
connTracker *ConnTracker
|
||||||
|
done chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
@@ -55,6 +62,8 @@ func Context(
|
|||||||
inboundRegistry adapter.InboundRegistry,
|
inboundRegistry adapter.InboundRegistry,
|
||||||
outboundRegistry adapter.OutboundRegistry,
|
outboundRegistry adapter.OutboundRegistry,
|
||||||
endpointRegistry adapter.EndpointRegistry,
|
endpointRegistry adapter.EndpointRegistry,
|
||||||
|
dnsTransportRegistry adapter.DNSTransportRegistry,
|
||||||
|
serviceRegistry adapter.ServiceRegistry,
|
||||||
) context.Context {
|
) context.Context {
|
||||||
if service.FromContext[option.InboundOptionsRegistry](ctx) == nil ||
|
if service.FromContext[option.InboundOptionsRegistry](ctx) == nil ||
|
||||||
service.FromContext[adapter.InboundRegistry](ctx) == nil {
|
service.FromContext[adapter.InboundRegistry](ctx) == nil {
|
||||||
@@ -71,6 +80,14 @@ func Context(
|
|||||||
ctx = service.ContextWith[option.EndpointOptionsRegistry](ctx, endpointRegistry)
|
ctx = service.ContextWith[option.EndpointOptionsRegistry](ctx, endpointRegistry)
|
||||||
ctx = service.ContextWith[adapter.EndpointRegistry](ctx, endpointRegistry)
|
ctx = service.ContextWith[adapter.EndpointRegistry](ctx, endpointRegistry)
|
||||||
}
|
}
|
||||||
|
if service.FromContext[adapter.DNSTransportRegistry](ctx) == nil {
|
||||||
|
ctx = service.ContextWith[option.DNSTransportOptionsRegistry](ctx, dnsTransportRegistry)
|
||||||
|
ctx = service.ContextWith[adapter.DNSTransportRegistry](ctx, dnsTransportRegistry)
|
||||||
|
}
|
||||||
|
if service.FromContext[adapter.ServiceRegistry](ctx) == nil {
|
||||||
|
ctx = service.ContextWith[option.ServiceOptionsRegistry](ctx, serviceRegistry)
|
||||||
|
ctx = service.ContextWith[adapter.ServiceRegistry](ctx, serviceRegistry)
|
||||||
|
}
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,6 +103,8 @@ func NewBox(options Options) (*Box, error) {
|
|||||||
endpointRegistry := service.FromContext[adapter.EndpointRegistry](ctx)
|
endpointRegistry := service.FromContext[adapter.EndpointRegistry](ctx)
|
||||||
inboundRegistry := service.FromContext[adapter.InboundRegistry](ctx)
|
inboundRegistry := service.FromContext[adapter.InboundRegistry](ctx)
|
||||||
outboundRegistry := service.FromContext[adapter.OutboundRegistry](ctx)
|
outboundRegistry := service.FromContext[adapter.OutboundRegistry](ctx)
|
||||||
|
dnsTransportRegistry := service.FromContext[adapter.DNSTransportRegistry](ctx)
|
||||||
|
serviceRegistry := service.FromContext[adapter.ServiceRegistry](ctx)
|
||||||
|
|
||||||
if endpointRegistry == nil {
|
if endpointRegistry == nil {
|
||||||
return nil, common.NewError("missing endpoint registry in context")
|
return nil, common.NewError("missing endpoint registry in context")
|
||||||
@@ -96,6 +115,12 @@ func NewBox(options Options) (*Box, error) {
|
|||||||
if outboundRegistry == nil {
|
if outboundRegistry == nil {
|
||||||
return nil, common.NewError("missing outbound registry in context")
|
return nil, common.NewError("missing outbound registry in context")
|
||||||
}
|
}
|
||||||
|
if dnsTransportRegistry == nil {
|
||||||
|
return nil, common.NewError("missing DNS transport registry in context")
|
||||||
|
}
|
||||||
|
if serviceRegistry == nil {
|
||||||
|
return nil, common.NewError("missing service registry in context")
|
||||||
|
}
|
||||||
|
|
||||||
ctx = pause.WithDefaultManager(ctx)
|
ctx = pause.WithDefaultManager(ctx)
|
||||||
experimentalOptions := sbCommon.PtrValueOrDefault(options.Experimental)
|
experimentalOptions := sbCommon.PtrValueOrDefault(options.Experimental)
|
||||||
@@ -120,13 +145,36 @@ func NewBox(options Options) (*Box, error) {
|
|||||||
}
|
}
|
||||||
factory = logFactory
|
factory = logFactory
|
||||||
|
|
||||||
|
var internalServices []adapter.LifecycleService
|
||||||
|
certificateOptions := sbCommon.PtrValueOrDefault(options.Certificate)
|
||||||
|
if C.IsAndroid || certificateOptions.Store != "" && certificateOptions.Store != C.CertificateStoreSystem ||
|
||||||
|
len(certificateOptions.Certificate) > 0 ||
|
||||||
|
len(certificateOptions.CertificatePath) > 0 ||
|
||||||
|
len(certificateOptions.CertificateDirectoryPath) > 0 {
|
||||||
|
certificateStore, err := certificate.NewStore(ctx, logFactory.NewLogger("certificate"), certificateOptions)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
service.MustRegister[adapter.CertificateStore](ctx, certificateStore)
|
||||||
|
internalServices = append(internalServices, certificateStore)
|
||||||
|
}
|
||||||
|
|
||||||
routeOptions := sbCommon.PtrValueOrDefault(options.Route)
|
routeOptions := sbCommon.PtrValueOrDefault(options.Route)
|
||||||
|
dnsOptions := sbCommon.PtrValueOrDefault(options.DNS)
|
||||||
endpointManager := endpoint.NewManager(logFactory.NewLogger("endpoint"), endpointRegistry)
|
endpointManager := endpoint.NewManager(logFactory.NewLogger("endpoint"), endpointRegistry)
|
||||||
inboundManager := inbound.NewManager(logFactory.NewLogger("inbound"), inboundRegistry, endpointManager)
|
inboundManager := inbound.NewManager(logFactory.NewLogger("inbound"), inboundRegistry, endpointManager)
|
||||||
outboundManager := outbound.NewManager(logFactory.NewLogger("outbound"), outboundRegistry, endpointManager, routeOptions.Final)
|
outboundManager := outbound.NewManager(logFactory.NewLogger("outbound"), outboundRegistry, endpointManager, routeOptions.Final)
|
||||||
|
dnsTransportManager := dns.NewTransportManager(logFactory.NewLogger("dns/transport"), dnsTransportRegistry, outboundManager, dnsOptions.Final)
|
||||||
|
serviceManager := boxService.NewManager(logFactory.NewLogger("service"), serviceRegistry)
|
||||||
|
|
||||||
service.MustRegister[adapter.EndpointManager](ctx, endpointManager)
|
service.MustRegister[adapter.EndpointManager](ctx, endpointManager)
|
||||||
service.MustRegister[adapter.InboundManager](ctx, inboundManager)
|
service.MustRegister[adapter.InboundManager](ctx, inboundManager)
|
||||||
service.MustRegister[adapter.OutboundManager](ctx, outboundManager)
|
service.MustRegister[adapter.OutboundManager](ctx, outboundManager)
|
||||||
|
service.MustRegister[adapter.DNSTransportManager](ctx, dnsTransportManager)
|
||||||
|
service.MustRegister[adapter.ServiceManager](ctx, serviceManager)
|
||||||
|
|
||||||
|
dnsRouter := dns.NewRouter(ctx, logFactory, dnsOptions)
|
||||||
|
service.MustRegister[adapter.DNSRouter](ctx, dnsRouter)
|
||||||
|
|
||||||
networkManager, err := route.NewNetworkManager(ctx, logFactory.NewLogger("network"), routeOptions)
|
networkManager, err := route.NewNetworkManager(ctx, logFactory.NewLogger("network"), routeOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -135,10 +183,34 @@ func NewBox(options Options) (*Box, error) {
|
|||||||
service.MustRegister[adapter.NetworkManager](ctx, networkManager)
|
service.MustRegister[adapter.NetworkManager](ctx, networkManager)
|
||||||
connectionManager := route.NewConnectionManager(logFactory.NewLogger("connection"))
|
connectionManager := route.NewConnectionManager(logFactory.NewLogger("connection"))
|
||||||
service.MustRegister[adapter.ConnectionManager](ctx, connectionManager)
|
service.MustRegister[adapter.ConnectionManager](ctx, connectionManager)
|
||||||
router, err := route.NewRouter(ctx, logFactory, routeOptions, sbCommon.PtrValueOrDefault(options.DNS))
|
router := route.NewRouter(ctx, logFactory, routeOptions, dnsOptions)
|
||||||
|
service.MustRegister[adapter.Router](ctx, router)
|
||||||
|
err = router.Initialize(routeOptions.Rules, routeOptions.RuleSet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, common.NewError("initialize router", err)
|
return nil, common.NewError("initialize router", err)
|
||||||
}
|
}
|
||||||
|
for i, transportOptions := range dnsOptions.Servers {
|
||||||
|
var tag string
|
||||||
|
if transportOptions.Tag != "" {
|
||||||
|
tag = transportOptions.Tag
|
||||||
|
} else {
|
||||||
|
tag = F.ToString(i)
|
||||||
|
}
|
||||||
|
err = dnsTransportManager.Create(
|
||||||
|
ctx,
|
||||||
|
logFactory.NewLogger(F.ToString("dns/", transportOptions.Type, "[", tag, "]")),
|
||||||
|
tag,
|
||||||
|
transportOptions.Type,
|
||||||
|
transportOptions.Options,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, common.NewError("initialize DNS server[", i, "]", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = dnsRouter.Initialize(dnsOptions.Rules)
|
||||||
|
if err != nil {
|
||||||
|
return nil, common.NewError("initialize dns router", err)
|
||||||
|
}
|
||||||
for i, endpointOptions := range options.Endpoints {
|
for i, endpointOptions := range options.Endpoints {
|
||||||
var tag string
|
var tag string
|
||||||
if endpointOptions.Tag != "" {
|
if endpointOptions.Tag != "" {
|
||||||
@@ -146,7 +218,8 @@ func NewBox(options Options) (*Box, error) {
|
|||||||
} else {
|
} else {
|
||||||
tag = F.ToString(i)
|
tag = F.ToString(i)
|
||||||
}
|
}
|
||||||
err = endpointManager.Create(ctx,
|
err = endpointManager.Create(
|
||||||
|
ctx,
|
||||||
router,
|
router,
|
||||||
logFactory.NewLogger(F.ToString("endpoint/", endpointOptions.Type, "[", tag, "]")),
|
logFactory.NewLogger(F.ToString("endpoint/", endpointOptions.Type, "[", tag, "]")),
|
||||||
tag,
|
tag,
|
||||||
@@ -164,7 +237,8 @@ func NewBox(options Options) (*Box, error) {
|
|||||||
} else {
|
} else {
|
||||||
tag = F.ToString(i)
|
tag = F.ToString(i)
|
||||||
}
|
}
|
||||||
err = inboundManager.Create(ctx,
|
err = inboundManager.Create(
|
||||||
|
ctx,
|
||||||
router,
|
router,
|
||||||
logFactory.NewLogger(F.ToString("inbound/", inboundOptions.Type, "[", tag, "]")),
|
logFactory.NewLogger(F.ToString("inbound/", inboundOptions.Type, "[", tag, "]")),
|
||||||
tag,
|
tag,
|
||||||
@@ -201,6 +275,24 @@ func NewBox(options Options) (*Box, error) {
|
|||||||
return nil, common.NewError("initialize outbound["+F.ToString(i)+"] "+tag, err)
|
return nil, common.NewError("initialize outbound["+F.ToString(i)+"] "+tag, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for i, serviceOptions := range options.Services {
|
||||||
|
var tag string
|
||||||
|
if serviceOptions.Tag != "" {
|
||||||
|
tag = serviceOptions.Tag
|
||||||
|
} else {
|
||||||
|
tag = F.ToString(i)
|
||||||
|
}
|
||||||
|
err = serviceManager.Create(
|
||||||
|
ctx,
|
||||||
|
logFactory.NewLogger(F.ToString("service/", serviceOptions.Type, "[", tag, "]")),
|
||||||
|
tag,
|
||||||
|
serviceOptions.Type,
|
||||||
|
serviceOptions.Options,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, common.NewError("initialize service["+F.ToString(i)+"]"+tag, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
outboundManager.Initialize(sbCommon.Must1(
|
outboundManager.Initialize(sbCommon.Must1(
|
||||||
direct.NewOutbound(
|
direct.NewOutbound(
|
||||||
ctx,
|
ctx,
|
||||||
@@ -210,6 +302,13 @@ func NewBox(options Options) (*Box, error) {
|
|||||||
option.DirectOutboundOptions{},
|
option.DirectOutboundOptions{},
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
|
dnsTransportManager.Initialize(sbCommon.Must1(
|
||||||
|
local.NewTransport(
|
||||||
|
ctx,
|
||||||
|
logFactory.NewLogger("dns/local"),
|
||||||
|
"local",
|
||||||
|
option.LocalDNSServerOptions{},
|
||||||
|
)))
|
||||||
if platformInterface != nil {
|
if platformInterface != nil {
|
||||||
err = platformInterface.Initialize(networkManager)
|
err = platformInterface.Initialize(networkManager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -219,18 +318,16 @@ func NewBox(options Options) (*Box, error) {
|
|||||||
if connTracker == nil {
|
if connTracker == nil {
|
||||||
connTracker = NewConnTracker()
|
connTracker = NewConnTracker()
|
||||||
}
|
}
|
||||||
router.SetTracker(connTracker)
|
router.AppendTracker(connTracker)
|
||||||
|
|
||||||
var services []adapter.LifecycleService
|
|
||||||
|
|
||||||
if needCacheFile {
|
if needCacheFile {
|
||||||
cacheFile := cachefile.New(ctx, sbCommon.PtrValueOrDefault(experimentalOptions.CacheFile))
|
cacheFile := cachefile.New(ctx, sbCommon.PtrValueOrDefault(experimentalOptions.CacheFile))
|
||||||
service.MustRegister[adapter.CacheFile](ctx, cacheFile)
|
service.MustRegister[adapter.CacheFile](ctx, cacheFile)
|
||||||
services = append(services, cacheFile)
|
internalServices = append(internalServices, cacheFile)
|
||||||
}
|
}
|
||||||
ntpOptions := sbCommon.PtrValueOrDefault(options.NTP)
|
ntpOptions := sbCommon.PtrValueOrDefault(options.NTP)
|
||||||
if ntpOptions.Enabled {
|
if ntpOptions.Enabled {
|
||||||
ntpDialer, err := dialer.New(ctx, ntpOptions.DialerOptions)
|
ntpDialer, err := dialer.New(ctx, ntpOptions.DialerOptions, ntpOptions.ServerIsDomain())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, common.NewError(err, "create NTP service")
|
return nil, common.NewError(err, "create NTP service")
|
||||||
}
|
}
|
||||||
@@ -243,21 +340,24 @@ func NewBox(options Options) (*Box, error) {
|
|||||||
WriteToSystem: ntpOptions.WriteToSystem,
|
WriteToSystem: ntpOptions.WriteToSystem,
|
||||||
})
|
})
|
||||||
service.MustRegister[ntp.TimeService](ctx, timeService)
|
service.MustRegister[ntp.TimeService](ctx, timeService)
|
||||||
services = append(services, adapter.NewLifecycleService(timeService, "ntp service"))
|
internalServices = append(internalServices, adapter.NewLifecycleService(timeService, "ntp service"))
|
||||||
}
|
}
|
||||||
return &Box{
|
return &Box{
|
||||||
network: networkManager,
|
network: networkManager,
|
||||||
endpoint: endpointManager,
|
endpoint: endpointManager,
|
||||||
inbound: inboundManager,
|
inbound: inboundManager,
|
||||||
outbound: outboundManager,
|
outbound: outboundManager,
|
||||||
connection: connectionManager,
|
dnsTransport: dnsTransportManager,
|
||||||
router: router,
|
service: serviceManager,
|
||||||
createdAt: createdAt,
|
dnsRouter: dnsRouter,
|
||||||
logFactory: logFactory,
|
connection: connectionManager,
|
||||||
logger: logFactory.Logger(),
|
router: router,
|
||||||
services: services,
|
createdAt: createdAt,
|
||||||
connTracker: connTracker,
|
logFactory: logFactory,
|
||||||
done: make(chan struct{}),
|
logger: logFactory.Logger(),
|
||||||
|
internalService: internalServices,
|
||||||
|
connTracker: connTracker,
|
||||||
|
done: make(chan struct{}),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,15 +405,15 @@ func (s *Box) preStart() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return common.NewError(err, "start logger")
|
return common.NewError(err, "start logger")
|
||||||
}
|
}
|
||||||
err = adapter.StartNamed(adapter.StartStateInitialize, s.services) // cache-file
|
err = adapter.StartNamed(adapter.StartStateInitialize, s.internalService) // cache-file
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = adapter.Start(adapter.StartStateInitialize, s.network, s.connection, s.router, s.outbound, s.inbound, s.endpoint)
|
err = adapter.Start(adapter.StartStateInitialize, s.network, s.dnsTransport, s.dnsRouter, s.connection, s.router, s.outbound, s.inbound, s.endpoint, s.service)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = adapter.Start(adapter.StartStateStart, s.outbound, s.network, s.connection, s.router)
|
err = adapter.Start(adapter.StartStateStart, s.outbound, s.dnsTransport, s.dnsRouter, s.network, s.connection, s.router)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -325,31 +425,27 @@ func (s *Box) start() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = adapter.StartNamed(adapter.StartStateStart, s.services)
|
err = adapter.StartNamed(adapter.StartStateStart, s.internalService)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = s.inbound.Start(adapter.StartStateStart)
|
err = adapter.Start(adapter.StartStateStart, s.inbound, s.endpoint, s.service)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = adapter.Start(adapter.StartStateStart, s.endpoint)
|
err = adapter.Start(adapter.StartStatePostStart, s.outbound, s.network, s.dnsTransport, s.dnsRouter, s.connection, s.router, s.inbound, s.endpoint, s.service)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = adapter.Start(adapter.StartStatePostStart, s.outbound, s.network, s.connection, s.router, s.inbound, s.endpoint)
|
err = adapter.StartNamed(adapter.StartStatePostStart, s.internalService)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = adapter.StartNamed(adapter.StartStatePostStart, s.services)
|
err = adapter.Start(adapter.StartStateStarted, s.network, s.dnsTransport, s.dnsRouter, s.connection, s.router, s.outbound, s.inbound, s.endpoint, s.service)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = adapter.Start(adapter.StartStateStarted, s.network, s.connection, s.router, s.outbound, s.inbound, s.endpoint)
|
err = adapter.StartNamed(adapter.StartStateStarted, s.internalService)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = adapter.StartNamed(adapter.StartStateStarted, s.services)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -364,9 +460,9 @@ func (s *Box) Close() error {
|
|||||||
close(s.done)
|
close(s.done)
|
||||||
}
|
}
|
||||||
err := sbCommon.Close(
|
err := sbCommon.Close(
|
||||||
s.endpoint, s.inbound, s.outbound, s.router, s.connection, s.network,
|
s.endpoint, s.inbound, s.outbound, s.router, s.connection, s.dnsRouter, s.dnsTransport, s.network,
|
||||||
)
|
)
|
||||||
for _, lifecycleService := range s.services {
|
for _, lifecycleService := range s.internalService {
|
||||||
err1 := lifecycleService.Close()
|
err1 := lifecycleService.Close()
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
s.logger.Debug(lifecycleService.Name(), " close error: ", err1)
|
s.logger.Debug(lifecycleService.Name(), " close error: ", err1)
|
||||||
|
|||||||
@@ -112,3 +112,36 @@ func (c *Core) RemoveEndpoint(tag string) error {
|
|||||||
logger.Info("remove endpoint: ", tag)
|
logger.Info("remove endpoint: ", tag)
|
||||||
return endpoint_manager.Remove(tag)
|
return endpoint_manager.Remove(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Core) AddService(config []byte) error {
|
||||||
|
if !c.isRunning {
|
||||||
|
return common.NewError("sing-box is not running")
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
var srv_config option.Service
|
||||||
|
|
||||||
|
err = srv_config.UnmarshalJSONContext(c.GetCtx(), config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = service_manager.Create(
|
||||||
|
c.GetCtx(),
|
||||||
|
factory.NewLogger("service/"+srv_config.Type+"["+srv_config.Tag+"]"),
|
||||||
|
srv_config.Tag,
|
||||||
|
srv_config.Type,
|
||||||
|
srv_config.Options)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Core) RemoveService(tag string) error {
|
||||||
|
if !c.isRunning {
|
||||||
|
return common.NewError("sing-box is not running")
|
||||||
|
}
|
||||||
|
logger.Info("remove service: ", tag)
|
||||||
|
return service_manager.Remove(tag)
|
||||||
|
}
|
||||||
|
|||||||
+3
-1
@@ -19,6 +19,7 @@ var (
|
|||||||
globalCtx context.Context
|
globalCtx context.Context
|
||||||
inbound_manager adapter.InboundManager
|
inbound_manager adapter.InboundManager
|
||||||
outbound_manager adapter.OutboundManager
|
outbound_manager adapter.OutboundManager
|
||||||
|
service_manager adapter.ServiceManager
|
||||||
endpoint_manager adapter.EndpointManager
|
endpoint_manager adapter.EndpointManager
|
||||||
router adapter.Router
|
router adapter.Router
|
||||||
connTracker *ConnTracker
|
connTracker *ConnTracker
|
||||||
@@ -32,7 +33,7 @@ type Core struct {
|
|||||||
|
|
||||||
func NewCore() *Core {
|
func NewCore() *Core {
|
||||||
globalCtx = context.Background()
|
globalCtx = context.Background()
|
||||||
globalCtx = sb.Context(globalCtx, inboundRegistry(), outboundRegistry(), EndpointRegistry())
|
globalCtx = sb.Context(globalCtx, InboundRegistry(), OutboundRegistry(), EndpointRegistry(), DNSTransportRegistry(), ServiceRegistry())
|
||||||
return &Core{
|
return &Core{
|
||||||
isRunning: false,
|
isRunning: false,
|
||||||
instance: nil,
|
instance: nil,
|
||||||
@@ -70,6 +71,7 @@ func (c *Core) Start(sbConfig []byte) error {
|
|||||||
globalCtx = service.ContextWith(globalCtx, c)
|
globalCtx = service.ContextWith(globalCtx, c)
|
||||||
inbound_manager = service.FromContext[adapter.InboundManager](globalCtx)
|
inbound_manager = service.FromContext[adapter.InboundManager](globalCtx)
|
||||||
outbound_manager = service.FromContext[adapter.OutboundManager](globalCtx)
|
outbound_manager = service.FromContext[adapter.OutboundManager](globalCtx)
|
||||||
|
service_manager = service.FromContext[adapter.ServiceManager](globalCtx)
|
||||||
endpoint_manager = service.FromContext[adapter.EndpointManager](globalCtx)
|
endpoint_manager = service.FromContext[adapter.EndpointManager](globalCtx)
|
||||||
router = service.FromContext[adapter.Router](globalCtx)
|
router = service.FromContext[adapter.Router](globalCtx)
|
||||||
|
|
||||||
|
|||||||
+70
-4
@@ -4,9 +4,18 @@ import (
|
|||||||
"github.com/sagernet/sing-box/adapter/endpoint"
|
"github.com/sagernet/sing-box/adapter/endpoint"
|
||||||
"github.com/sagernet/sing-box/adapter/inbound"
|
"github.com/sagernet/sing-box/adapter/inbound"
|
||||||
"github.com/sagernet/sing-box/adapter/outbound"
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
|
"github.com/sagernet/sing-box/adapter/service"
|
||||||
|
"github.com/sagernet/sing-box/dns"
|
||||||
|
"github.com/sagernet/sing-box/dns/transport"
|
||||||
|
"github.com/sagernet/sing-box/dns/transport/dhcp"
|
||||||
|
"github.com/sagernet/sing-box/dns/transport/fakeip"
|
||||||
|
"github.com/sagernet/sing-box/dns/transport/hosts"
|
||||||
|
"github.com/sagernet/sing-box/dns/transport/local"
|
||||||
|
"github.com/sagernet/sing-box/dns/transport/quic"
|
||||||
|
"github.com/sagernet/sing-box/protocol/anytls"
|
||||||
"github.com/sagernet/sing-box/protocol/block"
|
"github.com/sagernet/sing-box/protocol/block"
|
||||||
"github.com/sagernet/sing-box/protocol/direct"
|
"github.com/sagernet/sing-box/protocol/direct"
|
||||||
"github.com/sagernet/sing-box/protocol/dns"
|
protocolDNS "github.com/sagernet/sing-box/protocol/dns"
|
||||||
"github.com/sagernet/sing-box/protocol/group"
|
"github.com/sagernet/sing-box/protocol/group"
|
||||||
"github.com/sagernet/sing-box/protocol/http"
|
"github.com/sagernet/sing-box/protocol/http"
|
||||||
"github.com/sagernet/sing-box/protocol/hysteria"
|
"github.com/sagernet/sing-box/protocol/hysteria"
|
||||||
@@ -19,6 +28,7 @@ import (
|
|||||||
"github.com/sagernet/sing-box/protocol/shadowtls"
|
"github.com/sagernet/sing-box/protocol/shadowtls"
|
||||||
"github.com/sagernet/sing-box/protocol/socks"
|
"github.com/sagernet/sing-box/protocol/socks"
|
||||||
"github.com/sagernet/sing-box/protocol/ssh"
|
"github.com/sagernet/sing-box/protocol/ssh"
|
||||||
|
"github.com/sagernet/sing-box/protocol/tailscale"
|
||||||
"github.com/sagernet/sing-box/protocol/tor"
|
"github.com/sagernet/sing-box/protocol/tor"
|
||||||
"github.com/sagernet/sing-box/protocol/trojan"
|
"github.com/sagernet/sing-box/protocol/trojan"
|
||||||
"github.com/sagernet/sing-box/protocol/tuic"
|
"github.com/sagernet/sing-box/protocol/tuic"
|
||||||
@@ -26,11 +36,14 @@ import (
|
|||||||
"github.com/sagernet/sing-box/protocol/vless"
|
"github.com/sagernet/sing-box/protocol/vless"
|
||||||
"github.com/sagernet/sing-box/protocol/vmess"
|
"github.com/sagernet/sing-box/protocol/vmess"
|
||||||
"github.com/sagernet/sing-box/protocol/wireguard"
|
"github.com/sagernet/sing-box/protocol/wireguard"
|
||||||
|
"github.com/sagernet/sing-box/service/derp"
|
||||||
|
"github.com/sagernet/sing-box/service/resolved"
|
||||||
|
"github.com/sagernet/sing-box/service/ssmapi"
|
||||||
_ "github.com/sagernet/sing-box/transport/v2rayquic"
|
_ "github.com/sagernet/sing-box/transport/v2rayquic"
|
||||||
_ "github.com/sagernet/sing-dns/quic"
|
_ "github.com/sagernet/sing-dns/quic"
|
||||||
)
|
)
|
||||||
|
|
||||||
func inboundRegistry() *inbound.Registry {
|
func InboundRegistry() *inbound.Registry {
|
||||||
registry := inbound.NewRegistry()
|
registry := inbound.NewRegistry()
|
||||||
|
|
||||||
tun.RegisterInbound(registry)
|
tun.RegisterInbound(registry)
|
||||||
@@ -48,6 +61,7 @@ func inboundRegistry() *inbound.Registry {
|
|||||||
naive.RegisterInbound(registry)
|
naive.RegisterInbound(registry)
|
||||||
shadowtls.RegisterInbound(registry)
|
shadowtls.RegisterInbound(registry)
|
||||||
vless.RegisterInbound(registry)
|
vless.RegisterInbound(registry)
|
||||||
|
anytls.RegisterInbound(registry)
|
||||||
|
|
||||||
hysteria.RegisterInbound(registry)
|
hysteria.RegisterInbound(registry)
|
||||||
tuic.RegisterInbound(registry)
|
tuic.RegisterInbound(registry)
|
||||||
@@ -56,13 +70,13 @@ func inboundRegistry() *inbound.Registry {
|
|||||||
return registry
|
return registry
|
||||||
}
|
}
|
||||||
|
|
||||||
func outboundRegistry() *outbound.Registry {
|
func OutboundRegistry() *outbound.Registry {
|
||||||
registry := outbound.NewRegistry()
|
registry := outbound.NewRegistry()
|
||||||
|
|
||||||
direct.RegisterOutbound(registry)
|
direct.RegisterOutbound(registry)
|
||||||
|
|
||||||
block.RegisterOutbound(registry)
|
block.RegisterOutbound(registry)
|
||||||
dns.RegisterOutbound(registry)
|
protocolDNS.RegisterOutbound(registry)
|
||||||
|
|
||||||
group.RegisterSelector(registry)
|
group.RegisterSelector(registry)
|
||||||
group.RegisterURLTest(registry)
|
group.RegisterURLTest(registry)
|
||||||
@@ -76,6 +90,7 @@ func outboundRegistry() *outbound.Registry {
|
|||||||
ssh.RegisterOutbound(registry)
|
ssh.RegisterOutbound(registry)
|
||||||
shadowtls.RegisterOutbound(registry)
|
shadowtls.RegisterOutbound(registry)
|
||||||
vless.RegisterOutbound(registry)
|
vless.RegisterOutbound(registry)
|
||||||
|
anytls.RegisterOutbound(registry)
|
||||||
|
|
||||||
hysteria.RegisterOutbound(registry)
|
hysteria.RegisterOutbound(registry)
|
||||||
tuic.RegisterOutbound(registry)
|
tuic.RegisterOutbound(registry)
|
||||||
@@ -89,6 +104,57 @@ func EndpointRegistry() *endpoint.Registry {
|
|||||||
registry := endpoint.NewRegistry()
|
registry := endpoint.NewRegistry()
|
||||||
|
|
||||||
wireguard.RegisterEndpoint(registry)
|
wireguard.RegisterEndpoint(registry)
|
||||||
|
registerTailscaleEndpoint(registry)
|
||||||
|
|
||||||
|
return registry
|
||||||
|
}
|
||||||
|
|
||||||
|
func DNSTransportRegistry() *dns.TransportRegistry {
|
||||||
|
registry := dns.NewTransportRegistry()
|
||||||
|
|
||||||
|
transport.RegisterTCP(registry)
|
||||||
|
transport.RegisterUDP(registry)
|
||||||
|
transport.RegisterTLS(registry)
|
||||||
|
transport.RegisterHTTPS(registry)
|
||||||
|
hosts.RegisterTransport(registry)
|
||||||
|
local.RegisterTransport(registry)
|
||||||
|
fakeip.RegisterTransport(registry)
|
||||||
|
|
||||||
|
registerQUICTransports(registry)
|
||||||
|
registerDHCPTransport(registry)
|
||||||
|
registerTailscaleTransport(registry)
|
||||||
|
|
||||||
|
return registry
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerTailscaleEndpoint(registry *endpoint.Registry) {
|
||||||
|
tailscale.RegisterEndpoint(registry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerTailscaleTransport(registry *dns.TransportRegistry) {
|
||||||
|
tailscale.RegistryTransport(registry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerDERPService(registry *service.Registry) {
|
||||||
|
derp.Register(registry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerQUICTransports(registry *dns.TransportRegistry) {
|
||||||
|
quic.RegisterTransport(registry)
|
||||||
|
quic.RegisterHTTP3Transport(registry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerDHCPTransport(registry *dns.TransportRegistry) {
|
||||||
|
dhcp.RegisterTransport(registry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ServiceRegistry() *service.Registry {
|
||||||
|
registry := service.NewRegistry()
|
||||||
|
|
||||||
|
resolved.RegisterService(registry)
|
||||||
|
ssmapi.RegisterService(registry)
|
||||||
|
|
||||||
|
registerDERPService(registry)
|
||||||
|
|
||||||
return registry
|
return registry
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ func InitDB(dbPath string) error {
|
|||||||
&model.Tls{},
|
&model.Tls{},
|
||||||
&model.Inbound{},
|
&model.Inbound{},
|
||||||
&model.Outbound{},
|
&model.Outbound{},
|
||||||
|
&model.Service{},
|
||||||
&model.Endpoint{},
|
&model.Endpoint{},
|
||||||
&model.User{},
|
&model.User{},
|
||||||
&model.Tokens{},
|
&model.Tokens{},
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
Id uint `json:"id" form:"id" gorm:"primaryKey;autoIncrement"`
|
||||||
|
Type string `json:"type" form:"type"`
|
||||||
|
Tag string `json:"tag" form:"tag" gorm:"unique"`
|
||||||
|
|
||||||
|
// Foreign key to tls table
|
||||||
|
TlsId uint `json:"tls_id" form:"tls_id"`
|
||||||
|
Tls *Tls `json:"tls" form:"tls" gorm:"foreignKey:TlsId;references:Id"`
|
||||||
|
|
||||||
|
Options json.RawMessage `json:"-" form:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Service) UnmarshalJSON(data []byte) error {
|
||||||
|
var err error
|
||||||
|
var raw map[string]interface{}
|
||||||
|
if err = json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract fixed fields and store the rest in Options
|
||||||
|
if val, exists := raw["id"].(float64); exists {
|
||||||
|
i.Id = uint(val)
|
||||||
|
}
|
||||||
|
delete(raw, "id")
|
||||||
|
i.Type, _ = raw["type"].(string)
|
||||||
|
delete(raw, "type")
|
||||||
|
i.Tag, _ = raw["tag"].(string)
|
||||||
|
delete(raw, "tag")
|
||||||
|
|
||||||
|
// TlsId
|
||||||
|
if val, exists := raw["tls_id"].(float64); exists {
|
||||||
|
i.TlsId = uint(val)
|
||||||
|
}
|
||||||
|
delete(raw, "tls_id")
|
||||||
|
delete(raw, "tls")
|
||||||
|
|
||||||
|
// Remaining fields
|
||||||
|
i.Options, err = json.MarshalIndent(raw, "", " ")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON customizes marshalling
|
||||||
|
func (i Service) MarshalJSON() ([]byte, error) {
|
||||||
|
// Combine fixed fields and dynamic fields into one map
|
||||||
|
combined := make(map[string]interface{})
|
||||||
|
combined["type"] = i.Type
|
||||||
|
combined["tag"] = i.Tag
|
||||||
|
if i.Tls != nil {
|
||||||
|
combined["tls"] = i.Tls.Server
|
||||||
|
}
|
||||||
|
|
||||||
|
if i.Options != nil {
|
||||||
|
var restFields map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(i.Options, &restFields); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range restFields {
|
||||||
|
combined[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(combined)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i Service) MarshalFull() (*map[string]interface{}, error) {
|
||||||
|
combined := make(map[string]interface{})
|
||||||
|
combined["id"] = i.Id
|
||||||
|
combined["type"] = i.Type
|
||||||
|
combined["tag"] = i.Tag
|
||||||
|
combined["tls_id"] = i.TlsId
|
||||||
|
|
||||||
|
if i.Options != nil {
|
||||||
|
var restFields map[string]interface{}
|
||||||
|
if err := json.Unmarshal(i.Options, &restFields); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range restFields {
|
||||||
|
combined[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &combined, nil
|
||||||
|
}
|
||||||
+16
-1
@@ -22,6 +22,7 @@ type ConfigService struct {
|
|||||||
SettingService
|
SettingService
|
||||||
InboundService
|
InboundService
|
||||||
OutboundService
|
OutboundService
|
||||||
|
ServicesService
|
||||||
EndpointService
|
EndpointService
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,6 +32,7 @@ type SingBoxConfig struct {
|
|||||||
Ntp json.RawMessage `json:"ntp"`
|
Ntp json.RawMessage `json:"ntp"`
|
||||||
Inbounds []json.RawMessage `json:"inbounds"`
|
Inbounds []json.RawMessage `json:"inbounds"`
|
||||||
Outbounds []json.RawMessage `json:"outbounds"`
|
Outbounds []json.RawMessage `json:"outbounds"`
|
||||||
|
Services []json.RawMessage `json:"services"`
|
||||||
Endpoints []json.RawMessage `json:"endpoints"`
|
Endpoints []json.RawMessage `json:"endpoints"`
|
||||||
Route json.RawMessage `json:"route"`
|
Route json.RawMessage `json:"route"`
|
||||||
Experimental json.RawMessage `json:"experimental"`
|
Experimental json.RawMessage `json:"experimental"`
|
||||||
@@ -63,6 +65,10 @@ func (s *ConfigService) GetConfig(data string) (*SingBoxConfig, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
singboxConfig.Services, err = s.ServicesService.GetAllConfig(database.GetDB())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
singboxConfig.Endpoints, err = s.EndpointService.GetAllConfig(database.GetDB())
|
singboxConfig.Endpoints, err = s.EndpointService.GetAllConfig(database.GetDB())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -119,6 +125,7 @@ func (s *ConfigService) StopCore() error {
|
|||||||
func (s *ConfigService) Save(obj string, act string, data json.RawMessage, initUsers string, loginUser string, hostname string) ([]string, error) {
|
func (s *ConfigService) Save(obj string, act string, data json.RawMessage, initUsers string, loginUser string, hostname string) ([]string, error) {
|
||||||
var err error
|
var err error
|
||||||
var inboundIds []uint
|
var inboundIds []uint
|
||||||
|
var serviceIds []uint
|
||||||
var inboundId uint
|
var inboundId uint
|
||||||
var objs []string = []string{obj}
|
var objs []string = []string{obj}
|
||||||
|
|
||||||
@@ -133,6 +140,12 @@ func (s *ConfigService) Save(obj string, act string, data json.RawMessage, initU
|
|||||||
logger.Error("unable to restart inbounds: ", err1)
|
logger.Error("unable to restart inbounds: ", err1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(serviceIds) > 0 && corePtr.IsRunning() {
|
||||||
|
err1 := s.ServicesService.RestartServices(db, serviceIds)
|
||||||
|
if err1 != nil {
|
||||||
|
logger.Error("unable to restart services: ", err1)
|
||||||
|
}
|
||||||
|
}
|
||||||
// Try to start core if it is not running
|
// Try to start core if it is not running
|
||||||
if !corePtr.IsRunning() {
|
if !corePtr.IsRunning() {
|
||||||
s.StartCore("")
|
s.StartCore("")
|
||||||
@@ -147,11 +160,13 @@ func (s *ConfigService) Save(obj string, act string, data json.RawMessage, initU
|
|||||||
inboundIds, err = s.ClientService.Save(tx, act, data, hostname)
|
inboundIds, err = s.ClientService.Save(tx, act, data, hostname)
|
||||||
objs = append(objs, "inbounds")
|
objs = append(objs, "inbounds")
|
||||||
case "tls":
|
case "tls":
|
||||||
inboundIds, err = s.TlsService.Save(tx, act, data)
|
serviceIds, inboundIds, err = s.TlsService.Save(tx, act, data)
|
||||||
case "inbounds":
|
case "inbounds":
|
||||||
inboundId, err = s.InboundService.Save(tx, act, data, initUsers, hostname)
|
inboundId, err = s.InboundService.Save(tx, act, data, initUsers, hostname)
|
||||||
case "outbounds":
|
case "outbounds":
|
||||||
err = s.OutboundService.Save(tx, act, data)
|
err = s.OutboundService.Save(tx, act, data)
|
||||||
|
case "services":
|
||||||
|
err = s.ServicesService.Save(tx, act, data)
|
||||||
case "endpoints":
|
case "endpoints":
|
||||||
err = s.EndpointService.Save(tx, act, data)
|
err = s.EndpointService.Save(tx, act, data)
|
||||||
case "config":
|
case "config":
|
||||||
|
|||||||
@@ -0,0 +1,149 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
"s-ui/database"
|
||||||
|
"s-ui/database/model"
|
||||||
|
"s-ui/util/common"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServicesService struct{}
|
||||||
|
|
||||||
|
func (s *ServicesService) GetAll() (*[]map[string]interface{}, error) {
|
||||||
|
db := database.GetDB()
|
||||||
|
services := []model.Service{}
|
||||||
|
err := db.Model(model.Service{}).Scan(&services).Error
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var data []map[string]interface{}
|
||||||
|
for _, srv := range services {
|
||||||
|
srvData := map[string]interface{}{
|
||||||
|
"id": srv.Id,
|
||||||
|
"type": srv.Type,
|
||||||
|
"tag": srv.Tag,
|
||||||
|
"tls_id": srv.TlsId,
|
||||||
|
}
|
||||||
|
if srv.Options != nil {
|
||||||
|
var restFields map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(srv.Options, &restFields); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for k, v := range restFields {
|
||||||
|
srvData[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data = append(data, srvData)
|
||||||
|
}
|
||||||
|
return &data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServicesService) GetAllConfig(db *gorm.DB) ([]json.RawMessage, error) {
|
||||||
|
var servicesJson []json.RawMessage
|
||||||
|
var services []*model.Service
|
||||||
|
err := db.Model(model.Service{}).Preload("Tls").Find(&services).Error
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, srv := range services {
|
||||||
|
srvJson, err := srv.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
servicesJson = append(servicesJson, srvJson)
|
||||||
|
}
|
||||||
|
return servicesJson, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServicesService) Save(tx *gorm.DB, act string, data json.RawMessage) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
switch act {
|
||||||
|
case "new", "edit":
|
||||||
|
var srv model.Service
|
||||||
|
err = srv.UnmarshalJSON(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if srv.TlsId > 0 {
|
||||||
|
err = tx.Model(model.Tls{}).Where("id = ?", srv.TlsId).Find(&srv.Tls).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if corePtr.IsRunning() {
|
||||||
|
configData, err := srv.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if act == "edit" {
|
||||||
|
var oldTag string
|
||||||
|
err = tx.Model(model.Service{}).Select("tag").Where("id = ?", srv.Id).Find(&oldTag).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = corePtr.RemoveService(oldTag)
|
||||||
|
if err != nil && err != os.ErrInvalid {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = corePtr.AddService(configData)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tx.Save(&srv).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case "del":
|
||||||
|
var tag string
|
||||||
|
err = json.Unmarshal(data, &tag)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if corePtr.IsRunning() {
|
||||||
|
err = corePtr.RemoveService(tag)
|
||||||
|
if err != nil && err != os.ErrInvalid {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = tx.Where("tag = ?", tag).Delete(model.Service{}).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return common.NewErrorf("unknown action: %s", act)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServicesService) RestartServices(tx *gorm.DB, ids []uint) error {
|
||||||
|
var services []*model.Service
|
||||||
|
err := tx.Model(model.Service{}).Preload("Tls").Where("id in ?", ids).Find(&services).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, srv := range services {
|
||||||
|
err = corePtr.RemoveService(srv.Tag)
|
||||||
|
if err != nil && err != os.ErrInvalid {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
srvConfig, err := srv.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = corePtr.AddService(srvConfig)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
+18
-11
@@ -24,45 +24,52 @@ func (s *TlsService) GetAll() ([]model.Tls, error) {
|
|||||||
return tlsConfig, nil
|
return tlsConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TlsService) Save(tx *gorm.DB, action string, data json.RawMessage) ([]uint, error) {
|
func (s *TlsService) Save(tx *gorm.DB, action string, data json.RawMessage) ([]uint, []uint, error) {
|
||||||
var err error
|
var err error
|
||||||
var inboundIds []uint
|
var inboundIds []uint
|
||||||
|
var serviceIds []uint
|
||||||
|
|
||||||
switch action {
|
switch action {
|
||||||
case "new", "edit":
|
case "new", "edit":
|
||||||
var tls model.Tls
|
var tls model.Tls
|
||||||
err = json.Unmarshal(data, &tls)
|
err = json.Unmarshal(data, &tls)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
err = tx.Save(&tls).Error
|
err = tx.Save(&tls).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
err = tx.Model(model.Inbound{}).Select("id").Where("tls_id = ?", tls.Id).Scan(&inboundIds).Error
|
err = tx.Model(model.Inbound{}).Select("id").Where("tls_id = ?", tls.Id).Scan(&inboundIds).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
return inboundIds, nil
|
err = tx.Model(model.Service{}).Where("tls_id = ?", tls.Id).Scan(&serviceIds).Error
|
||||||
|
return serviceIds, inboundIds, nil
|
||||||
case "del":
|
case "del":
|
||||||
var id uint
|
var id uint
|
||||||
err = json.Unmarshal(data, &id)
|
err = json.Unmarshal(data, &id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
var inboundCount int64
|
var inboundCount int64
|
||||||
err = tx.Model(model.Inbound{}).Where("tls_id = ?", id).Count(&inboundCount).Error
|
err = tx.Model(model.Inbound{}).Where("tls_id = ?", id).Count(&inboundCount).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if inboundCount > 0 {
|
var serviceCount int64
|
||||||
return nil, common.NewError("tls in use")
|
err = tx.Model(model.Service{}).Where("tls_id = ?", id).Count(&serviceCount).Error
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if inboundCount > 0 || serviceCount > 0 {
|
||||||
|
return nil, nil, common.NewError("tls in use")
|
||||||
}
|
}
|
||||||
err = tx.Where("id = ?", id).Delete(model.Tls{}).Error
|
err = tx.Where("id = ?", id).Delete(model.Tls{}).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user