service.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. package sitecheck
  2. import (
  3. "context"
  4. "sync"
  5. "time"
  6. "github.com/uozi-tech/cosy/logger"
  7. )
  8. // Service manages site checking operations
  9. type Service struct {
  10. checker *SiteChecker
  11. ctx context.Context
  12. cancel context.CancelFunc
  13. ticker *time.Ticker
  14. mu sync.RWMutex
  15. running bool
  16. }
  17. var (
  18. globalService *Service
  19. serviceOnce sync.Once
  20. )
  21. // GetService returns the singleton service instance
  22. func GetService() *Service {
  23. serviceOnce.Do(func() {
  24. globalService = NewService(DefaultCheckOptions())
  25. })
  26. return globalService
  27. }
  28. // NewService creates a new site checking service
  29. func NewService(options CheckOptions) *Service {
  30. return NewServiceWithContext(context.Background(), options)
  31. }
  32. // NewServiceWithContext creates a new site checking service with a parent context
  33. func NewServiceWithContext(parentCtx context.Context, options CheckOptions) *Service {
  34. ctx, cancel := context.WithCancel(parentCtx)
  35. return &Service{
  36. checker: NewSiteChecker(options),
  37. ctx: ctx,
  38. cancel: cancel,
  39. }
  40. }
  41. // SetUpdateCallback sets the callback function for site updates
  42. func (s *Service) SetUpdateCallback(callback func([]*SiteInfo)) {
  43. s.checker.SetUpdateCallback(callback)
  44. }
  45. // Start begins the site checking service
  46. func (s *Service) Start() {
  47. s.mu.Lock()
  48. defer s.mu.Unlock()
  49. if s.running {
  50. return
  51. }
  52. s.running = true
  53. logger.Info("Starting site checking service")
  54. // Initial collection and check with delay to allow cache scanner to complete
  55. go func() {
  56. // Wait a bit for cache scanner to collect sites
  57. time.Sleep(2 * time.Second)
  58. s.checker.CollectSites()
  59. s.checker.CheckAllSites(s.ctx)
  60. }()
  61. // Start periodic checking (every 5 minutes)
  62. s.ticker = time.NewTicker(5 * time.Minute)
  63. go s.periodicCheck()
  64. }
  65. // Stop stops the site checking service
  66. func (s *Service) Stop() {
  67. s.mu.Lock()
  68. defer s.mu.Unlock()
  69. if !s.running {
  70. return
  71. }
  72. s.running = false
  73. logger.Info("Stopping site checking service")
  74. if s.ticker != nil {
  75. s.ticker.Stop()
  76. }
  77. s.cancel()
  78. }
  79. // Restart restarts the site checking service
  80. func (s *Service) Restart() {
  81. s.Stop()
  82. time.Sleep(100 * time.Millisecond) // Brief pause
  83. s.Start()
  84. }
  85. // periodicCheck runs periodic site checks
  86. func (s *Service) periodicCheck() {
  87. for {
  88. select {
  89. case <-s.ctx.Done():
  90. return
  91. case <-s.ticker.C:
  92. logger.Debug("Starting periodic site check")
  93. s.checker.CollectSites() // Re-collect in case sites changed
  94. s.checker.CheckAllSites(s.ctx)
  95. }
  96. }
  97. }
  98. // RefreshSites manually triggers a site collection and check
  99. func (s *Service) RefreshSites() {
  100. go func() {
  101. logger.Info("Manually refreshing sites")
  102. s.checker.CollectSites()
  103. s.checker.CheckAllSites(s.ctx)
  104. }()
  105. }
  106. // GetSites returns all checked sites with custom ordering applied
  107. func (s *Service) GetSites() []*SiteInfo {
  108. sites := s.checker.GetSitesList()
  109. // Apply custom ordering from database
  110. return s.applySiteOrdering(sites)
  111. }
  112. // GetSiteByURL returns a specific site by URL
  113. func (s *Service) GetSiteByURL(url string) *SiteInfo {
  114. sites := s.checker.GetSites()
  115. if site, exists := sites[url]; exists {
  116. return site
  117. }
  118. return nil
  119. }
  120. // IsRunning returns whether the service is currently running
  121. func (s *Service) IsRunning() bool {
  122. s.mu.RLock()
  123. defer s.mu.RUnlock()
  124. return s.running
  125. }
  126. // applySiteOrdering applies custom ordering from database to sites
  127. func (s *Service) applySiteOrdering(sites []*SiteInfo) []*SiteInfo {
  128. return applyCustomOrdering(sites)
  129. }