script_surge_cron.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. package script
  2. import (
  3. "context"
  4. "time"
  5. "github.com/sagernet/sing-box/adapter"
  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. "github.com/sagernet/sing/common/logger"
  11. "github.com/adhocore/gronx"
  12. )
  13. var _ adapter.GenericScript = (*SurgeCronScript)(nil)
  14. type SurgeCronScript struct {
  15. GenericScript
  16. ctx context.Context
  17. expression string
  18. timer *time.Timer
  19. }
  20. func NewSurgeCronScript(ctx context.Context, logger logger.ContextLogger, options option.Script) (*SurgeCronScript, error) {
  21. source, err := NewSource(ctx, logger, options)
  22. if err != nil {
  23. return nil, err
  24. }
  25. if !gronx.IsValid(options.CronOptions.Expression) {
  26. return nil, E.New("invalid cron expression: ", options.CronOptions.Expression)
  27. }
  28. return &SurgeCronScript{
  29. GenericScript: GenericScript{
  30. logger: logger,
  31. tag: options.Tag,
  32. timeout: time.Duration(options.Timeout),
  33. arguments: options.Arguments,
  34. source: source,
  35. },
  36. ctx: ctx,
  37. expression: options.CronOptions.Expression,
  38. }, nil
  39. }
  40. func (s *SurgeCronScript) Type() string {
  41. return C.ScriptTypeSurgeCron
  42. }
  43. func (s *SurgeCronScript) Tag() string {
  44. return s.tag
  45. }
  46. func (s *SurgeCronScript) StartContext(ctx context.Context, startContext *adapter.HTTPStartContext) error {
  47. return s.source.StartContext(ctx, startContext)
  48. }
  49. func (s *SurgeCronScript) PostStart() error {
  50. err := s.source.PostStart()
  51. if err != nil {
  52. return err
  53. }
  54. go s.loop()
  55. return nil
  56. }
  57. func (s *SurgeCronScript) loop() {
  58. s.logger.Debug("starting event")
  59. err := s.Run(s.ctx)
  60. if err != nil {
  61. s.logger.Error(E.Cause(err, "running event"))
  62. }
  63. nextTick, err := gronx.NextTick(s.expression, false)
  64. if err != nil {
  65. s.logger.Error(E.Cause(err, "determine next tick"))
  66. return
  67. }
  68. s.timer = time.NewTimer(nextTick.Sub(time.Now()))
  69. s.logger.Debug("next event at: ", nextTick.Format(log.DefaultTimeFormat))
  70. for {
  71. select {
  72. case <-s.ctx.Done():
  73. return
  74. case <-s.timer.C:
  75. s.logger.Debug("starting event")
  76. err = s.Run(s.ctx)
  77. if err != nil {
  78. s.logger.Error(E.Cause(err, "running event"))
  79. }
  80. nextTick, err = gronx.NextTick(s.expression, false)
  81. if err != nil {
  82. s.logger.Error(E.Cause(err, "determine next tick"))
  83. return
  84. }
  85. s.timer.Reset(nextTick.Sub(time.Now()))
  86. s.logger.Debug("next event at: ", nextTick)
  87. }
  88. }
  89. }
  90. func (s *SurgeCronScript) Close() error {
  91. return s.source.Close()
  92. }
  93. func (s *SurgeCronScript) Run(ctx context.Context) error {
  94. program := s.source.Program()
  95. if program == nil {
  96. return E.New("invalid script")
  97. }
  98. ctx, cancel := context.WithCancelCause(ctx)
  99. defer cancel(nil)
  100. vm := NewRuntime(ctx, s.logger, cancel)
  101. err := SetSurgeModules(vm, ctx, s.logger, cancel, s.Tag(), s.Type(), s.arguments)
  102. if err != nil {
  103. return err
  104. }
  105. return ExecuteSurgeGeneral(vm, program, ctx, s.timeout)
  106. }