instance.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. package daemon
  2. import (
  3. "bytes"
  4. "context"
  5. "github.com/sagernet/sing-box"
  6. "github.com/sagernet/sing-box/adapter"
  7. "github.com/sagernet/sing-box/common/urltest"
  8. C "github.com/sagernet/sing-box/constant"
  9. "github.com/sagernet/sing-box/experimental/deprecated"
  10. "github.com/sagernet/sing-box/include"
  11. "github.com/sagernet/sing-box/log"
  12. "github.com/sagernet/sing-box/option"
  13. "github.com/sagernet/sing/common"
  14. E "github.com/sagernet/sing/common/exceptions"
  15. "github.com/sagernet/sing/common/json"
  16. "github.com/sagernet/sing/service"
  17. "github.com/sagernet/sing/service/pause"
  18. )
  19. type Instance struct {
  20. ctx context.Context
  21. cancel context.CancelFunc
  22. instance *box.Box
  23. connectionManager adapter.ConnectionManager
  24. clashServer adapter.ClashServer
  25. cacheFile adapter.CacheFile
  26. pauseManager pause.Manager
  27. urlTestHistoryStorage *urltest.HistoryStorage
  28. }
  29. func (s *StartedService) CheckConfig(configContent string) error {
  30. options, err := parseConfig(s.ctx, configContent)
  31. if err != nil {
  32. return err
  33. }
  34. ctx, cancel := context.WithCancel(s.ctx)
  35. defer cancel()
  36. instance, err := box.New(box.Options{
  37. Context: ctx,
  38. Options: options,
  39. })
  40. if err == nil {
  41. instance.Close()
  42. }
  43. return err
  44. }
  45. func (s *StartedService) FormatConfig(configContent string) (string, error) {
  46. options, err := parseConfig(s.ctx, configContent)
  47. if err != nil {
  48. return "", err
  49. }
  50. var buffer bytes.Buffer
  51. encoder := json.NewEncoder(&buffer)
  52. encoder.SetIndent("", " ")
  53. err = encoder.Encode(options)
  54. if err != nil {
  55. return "", err
  56. }
  57. return buffer.String(), nil
  58. }
  59. type OverrideOptions struct {
  60. AutoRedirect bool
  61. IncludePackage []string
  62. ExcludePackage []string
  63. }
  64. func (s *StartedService) newInstance(profileContent string, overrideOptions *OverrideOptions) (*Instance, error) {
  65. ctx := s.ctx
  66. service.MustRegister[deprecated.Manager](ctx, new(deprecatedManager))
  67. ctx, cancel := context.WithCancel(include.Context(ctx))
  68. options, err := parseConfig(ctx, profileContent)
  69. if err != nil {
  70. cancel()
  71. return nil, err
  72. }
  73. if overrideOptions != nil {
  74. for _, inbound := range options.Inbounds {
  75. if tunInboundOptions, isTUN := inbound.Options.(*option.TunInboundOptions); isTUN {
  76. tunInboundOptions.AutoRedirect = overrideOptions.AutoRedirect
  77. tunInboundOptions.IncludePackage = append(tunInboundOptions.IncludePackage, overrideOptions.IncludePackage...)
  78. tunInboundOptions.ExcludePackage = append(tunInboundOptions.ExcludePackage, overrideOptions.ExcludePackage...)
  79. break
  80. }
  81. }
  82. }
  83. if s.oomKillerEnabled {
  84. if !common.Any(options.Services, func(it option.Service) bool {
  85. return it.Type == C.TypeOOMKiller
  86. }) {
  87. oomOptions := &option.OOMKillerServiceOptions{
  88. KillerDisabled: s.oomKillerDisabled,
  89. MemoryLimitOverride: s.oomMemoryLimit,
  90. }
  91. options.Services = append(options.Services, option.Service{
  92. Type: C.TypeOOMKiller,
  93. Options: oomOptions,
  94. })
  95. }
  96. }
  97. urlTestHistoryStorage := urltest.NewHistoryStorage()
  98. ctx = service.ContextWithPtr(ctx, urlTestHistoryStorage)
  99. i := &Instance{
  100. ctx: ctx,
  101. cancel: cancel,
  102. urlTestHistoryStorage: urlTestHistoryStorage,
  103. }
  104. boxInstance, err := box.New(box.Options{
  105. Context: ctx,
  106. Options: options,
  107. PlatformLogWriter: s,
  108. })
  109. if err != nil {
  110. cancel()
  111. return nil, err
  112. }
  113. i.instance = boxInstance
  114. i.connectionManager = service.FromContext[adapter.ConnectionManager](ctx)
  115. i.clashServer = service.FromContext[adapter.ClashServer](ctx)
  116. i.pauseManager = service.FromContext[pause.Manager](ctx)
  117. i.cacheFile = service.FromContext[adapter.CacheFile](ctx)
  118. log.SetStdLogger(boxInstance.LogFactory().Logger())
  119. return i, nil
  120. }
  121. func (i *Instance) Start() error {
  122. return i.instance.Start()
  123. }
  124. func (i *Instance) Close() error {
  125. i.cancel()
  126. i.urlTestHistoryStorage.Close()
  127. return i.instance.Close()
  128. }
  129. func (i *Instance) Box() *box.Box {
  130. return i.instance
  131. }
  132. func (i *Instance) PauseManager() pause.Manager {
  133. return i.pauseManager
  134. }
  135. func parseConfig(ctx context.Context, configContent string) (option.Options, error) {
  136. options, err := json.UnmarshalExtendedContext[option.Options](ctx, []byte(configContent))
  137. if err != nil {
  138. return option.Options{}, E.Cause(err, "decode config")
  139. }
  140. return options, nil
  141. }