manager.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. //go:build with_script
  2. package script
  3. import (
  4. "context"
  5. "github.com/sagernet/sing-box/adapter"
  6. "github.com/sagernet/sing-box/common/taskmonitor"
  7. C "github.com/sagernet/sing-box/constant"
  8. "github.com/sagernet/sing-box/log"
  9. "github.com/sagernet/sing-box/option"
  10. E "github.com/sagernet/sing/common/exceptions"
  11. F "github.com/sagernet/sing/common/format"
  12. "github.com/sagernet/sing/common/logger"
  13. "github.com/sagernet/sing/common/task"
  14. )
  15. var _ adapter.ScriptManager = (*Manager)(nil)
  16. type Manager struct {
  17. ctx context.Context
  18. logger logger.ContextLogger
  19. scripts []adapter.Script
  20. scriptByName map[string]adapter.Script
  21. surgeCache *adapter.SurgeInMemoryCache
  22. }
  23. func NewManager(ctx context.Context, logFactory log.Factory, scripts []option.Script) (*Manager, error) {
  24. manager := &Manager{
  25. ctx: ctx,
  26. logger: logFactory.NewLogger("script"),
  27. scriptByName: make(map[string]adapter.Script),
  28. }
  29. for _, scriptOptions := range scripts {
  30. script, err := NewScript(ctx, logFactory.NewLogger(F.ToString("script/", scriptOptions.Type, "[", scriptOptions.Tag, "]")), scriptOptions)
  31. if err != nil {
  32. return nil, E.Cause(err, "initialize script: ", scriptOptions.Tag)
  33. }
  34. manager.scripts = append(manager.scripts, script)
  35. manager.scriptByName[scriptOptions.Tag] = script
  36. }
  37. return manager, nil
  38. }
  39. func (m *Manager) Start(stage adapter.StartStage) error {
  40. monitor := taskmonitor.New(m.logger, C.StartTimeout)
  41. switch stage {
  42. case adapter.StartStateStart:
  43. var cacheContext *adapter.HTTPStartContext
  44. if len(m.scripts) > 0 {
  45. monitor.Start("initialize rule-set")
  46. cacheContext = adapter.NewHTTPStartContext(m.ctx)
  47. var scriptStartGroup task.Group
  48. for _, script := range m.scripts {
  49. scriptInPlace := script
  50. scriptStartGroup.Append0(func(ctx context.Context) error {
  51. err := scriptInPlace.StartContext(ctx, cacheContext)
  52. if err != nil {
  53. return E.Cause(err, "initialize script/", scriptInPlace.Type(), "[", scriptInPlace.Tag(), "]")
  54. }
  55. return nil
  56. })
  57. }
  58. scriptStartGroup.Concurrency(5)
  59. scriptStartGroup.FastFail()
  60. err := scriptStartGroup.Run(m.ctx)
  61. monitor.Finish()
  62. if err != nil {
  63. return err
  64. }
  65. }
  66. if cacheContext != nil {
  67. cacheContext.Close()
  68. }
  69. case adapter.StartStatePostStart:
  70. for _, script := range m.scripts {
  71. monitor.Start(F.ToString("post start script/", script.Type(), "[", script.Tag(), "]"))
  72. err := script.PostStart()
  73. monitor.Finish()
  74. if err != nil {
  75. return E.Cause(err, "post start script/", script.Type(), "[", script.Tag(), "]")
  76. }
  77. }
  78. }
  79. return nil
  80. }
  81. func (m *Manager) Close() error {
  82. monitor := taskmonitor.New(m.logger, C.StopTimeout)
  83. var err error
  84. for _, script := range m.scripts {
  85. monitor.Start(F.ToString("close start script/", script.Type(), "[", script.Tag(), "]"))
  86. err = E.Append(err, script.Close(), func(err error) error {
  87. return E.Cause(err, "close script/", script.Type(), "[", script.Tag(), "]")
  88. })
  89. monitor.Finish()
  90. }
  91. return err
  92. }
  93. func (m *Manager) Scripts() []adapter.Script {
  94. return m.scripts
  95. }
  96. func (m *Manager) Script(name string) (adapter.Script, bool) {
  97. script, loaded := m.scriptByName[name]
  98. return script, loaded
  99. }
  100. func (m *Manager) SurgeCache() *adapter.SurgeInMemoryCache {
  101. if m.surgeCache == nil {
  102. m.surgeCache = &adapter.SurgeInMemoryCache{
  103. Data: make(map[string]string),
  104. }
  105. }
  106. return m.surgeCache
  107. }