manager.go 3.3 KB

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