instance.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  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. "github.com/sagernet/sing-box/experimental/deprecated"
  9. "github.com/sagernet/sing-box/include"
  10. "github.com/sagernet/sing-box/option"
  11. E "github.com/sagernet/sing/common/exceptions"
  12. "github.com/sagernet/sing/common/json"
  13. "github.com/sagernet/sing/service"
  14. "github.com/sagernet/sing/service/pause"
  15. )
  16. type Instance struct {
  17. ctx context.Context
  18. cancel context.CancelFunc
  19. instance *box.Box
  20. clashServer adapter.ClashServer
  21. cacheFile adapter.CacheFile
  22. pauseManager pause.Manager
  23. urlTestHistoryStorage *urltest.HistoryStorage
  24. }
  25. func (s *StartedService) CheckConfig(configContent string) error {
  26. options, err := parseConfig(s.ctx, configContent)
  27. if err != nil {
  28. return err
  29. }
  30. ctx, cancel := context.WithCancel(s.ctx)
  31. defer cancel()
  32. instance, err := box.New(box.Options{
  33. Context: ctx,
  34. Options: options,
  35. })
  36. if err == nil {
  37. instance.Close()
  38. }
  39. return err
  40. }
  41. func (s *StartedService) FormatConfig(configContent string) (string, error) {
  42. options, err := parseConfig(s.ctx, configContent)
  43. if err != nil {
  44. return "", err
  45. }
  46. var buffer bytes.Buffer
  47. encoder := json.NewEncoder(&buffer)
  48. encoder.SetIndent("", " ")
  49. err = encoder.Encode(options)
  50. if err != nil {
  51. return "", err
  52. }
  53. return buffer.String(), nil
  54. }
  55. type OverrideOptions struct {
  56. AutoRedirect bool
  57. IncludePackage []string
  58. ExcludePackage []string
  59. }
  60. func (s *StartedService) newInstance(profileContent string, overrideOptions *OverrideOptions) (*Instance, error) {
  61. ctx := s.ctx
  62. service.MustRegister[deprecated.Manager](ctx, new(deprecatedManager))
  63. ctx, cancel := context.WithCancel(include.Context(ctx))
  64. options, err := parseConfig(ctx, profileContent)
  65. if err != nil {
  66. cancel()
  67. return nil, err
  68. }
  69. if overrideOptions != nil {
  70. for _, inbound := range options.Inbounds {
  71. if tunInboundOptions, isTUN := inbound.Options.(*option.TunInboundOptions); isTUN {
  72. tunInboundOptions.AutoRedirect = overrideOptions.AutoRedirect
  73. tunInboundOptions.IncludePackage = append(tunInboundOptions.IncludePackage, overrideOptions.IncludePackage...)
  74. tunInboundOptions.ExcludePackage = append(tunInboundOptions.ExcludePackage, overrideOptions.ExcludePackage...)
  75. break
  76. }
  77. }
  78. }
  79. urlTestHistoryStorage := urltest.NewHistoryStorage()
  80. ctx = service.ContextWithPtr(ctx, urlTestHistoryStorage)
  81. i := &Instance{
  82. ctx: ctx,
  83. cancel: cancel,
  84. urlTestHistoryStorage: urlTestHistoryStorage,
  85. }
  86. boxInstance, err := box.New(box.Options{
  87. Context: ctx,
  88. Options: options,
  89. PlatformLogWriter: s,
  90. })
  91. if err != nil {
  92. cancel()
  93. return nil, err
  94. }
  95. i.instance = boxInstance
  96. i.clashServer = service.FromContext[adapter.ClashServer](ctx)
  97. i.pauseManager = service.FromContext[pause.Manager](ctx)
  98. i.cacheFile = service.FromContext[adapter.CacheFile](ctx)
  99. return i, nil
  100. }
  101. func (i *Instance) Start() error {
  102. return i.instance.Start()
  103. }
  104. func (i *Instance) Close() error {
  105. i.cancel()
  106. i.urlTestHistoryStorage.Close()
  107. return i.instance.Close()
  108. }
  109. func (i *Instance) Box() *box.Box {
  110. return i.instance
  111. }
  112. func (i *Instance) PauseManager() pause.Manager {
  113. return i.pauseManager
  114. }
  115. func parseConfig(ctx context.Context, configContent string) (option.Options, error) {
  116. options, err := json.UnmarshalExtendedContext[option.Options](ctx, []byte(configContent))
  117. if err != nil {
  118. return option.Options{}, E.Cause(err, "decode config")
  119. }
  120. return options, nil
  121. }