instance.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  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.oomKiller && C.IsIos {
  84. if !common.Any(options.Services, func(it option.Service) bool {
  85. return it.Type == C.TypeOOMKiller
  86. }) {
  87. options.Services = append(options.Services, option.Service{
  88. Type: C.TypeOOMKiller,
  89. })
  90. }
  91. }
  92. urlTestHistoryStorage := urltest.NewHistoryStorage()
  93. ctx = service.ContextWithPtr(ctx, urlTestHistoryStorage)
  94. i := &Instance{
  95. ctx: ctx,
  96. cancel: cancel,
  97. urlTestHistoryStorage: urlTestHistoryStorage,
  98. }
  99. boxInstance, err := box.New(box.Options{
  100. Context: ctx,
  101. Options: options,
  102. PlatformLogWriter: s,
  103. })
  104. if err != nil {
  105. cancel()
  106. return nil, err
  107. }
  108. i.instance = boxInstance
  109. i.connectionManager = service.FromContext[adapter.ConnectionManager](ctx)
  110. i.clashServer = service.FromContext[adapter.ClashServer](ctx)
  111. i.pauseManager = service.FromContext[pause.Manager](ctx)
  112. i.cacheFile = service.FromContext[adapter.CacheFile](ctx)
  113. log.SetStdLogger(boxInstance.LogFactory().Logger())
  114. return i, nil
  115. }
  116. func (i *Instance) Start() error {
  117. return i.instance.Start()
  118. }
  119. func (i *Instance) Close() error {
  120. i.cancel()
  121. i.urlTestHistoryStorage.Close()
  122. return i.instance.Close()
  123. }
  124. func (i *Instance) Box() *box.Box {
  125. return i.instance
  126. }
  127. func (i *Instance) PauseManager() pause.Manager {
  128. return i.pauseManager
  129. }
  130. func parseConfig(ctx context.Context, configContent string) (option.Options, error) {
  131. options, err := json.UnmarshalExtendedContext[option.Options](ctx, []byte(configContent))
  132. if err != nil {
  133. return option.Options{}, E.Cause(err, "decode config")
  134. }
  135. return options, nil
  136. }