service.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. package analytics
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/0xJacky/Nginx-UI/internal/nginx_log/searcher"
  6. "github.com/0xJacky/Nginx-UI/internal/nginx_log/utlis"
  7. )
  8. // Service defines the interface for analytics operations
  9. type Service interface {
  10. GetDashboardAnalytics(ctx context.Context, req *DashboardQueryRequest) (*DashboardAnalytics, error)
  11. GetLogEntriesStats(ctx context.Context, req *searcher.SearchRequest) (*EntriesStats, error)
  12. GetGeoDistribution(ctx context.Context, req *GeoQueryRequest) (*GeoDistribution, error)
  13. GetGeoDistributionByCountry(ctx context.Context, req *GeoQueryRequest, countryCode string) (*GeoDistribution, error)
  14. GetTopCountries(ctx context.Context, req *GeoQueryRequest) ([]CountryStats, error)
  15. GetTopCities(ctx context.Context, req *GeoQueryRequest) ([]CityStats, error)
  16. GetGeoStatsForIP(ctx context.Context, req *GeoQueryRequest, ip string) (*CityStats, error)
  17. GetTopPaths(ctx context.Context, req *TopListRequest) ([]KeyValue, error)
  18. GetTopIPs(ctx context.Context, req *TopListRequest) ([]KeyValue, error)
  19. GetTopUserAgents(ctx context.Context, req *TopListRequest) ([]KeyValue, error)
  20. ValidateLogPath(logPath string) error
  21. ValidateTimeRange(startTime, endTime int64) error
  22. }
  23. // service implements the Service interface
  24. type service struct {
  25. searcher searcher.Searcher
  26. }
  27. // NewService creates a new analytics service
  28. func NewService(s searcher.Searcher) Service {
  29. return &service{
  30. searcher: s,
  31. }
  32. }
  33. // ValidateLogPath validates the log path against whitelist
  34. func (s *service) ValidateLogPath(logPath string) error {
  35. if logPath == "" {
  36. return nil // Empty path is acceptable for global search
  37. }
  38. if !utlis.IsValidLogPath(logPath) {
  39. return fmt.Errorf("log path is not under whitelist")
  40. }
  41. return nil
  42. }
  43. // ValidateTimeRange validates the time range parameters
  44. func (s *service) ValidateTimeRange(startTime, endTime int64) error {
  45. if startTime < 0 || endTime < 0 {
  46. return fmt.Errorf("time values cannot be negative")
  47. }
  48. if startTime > 0 && endTime > 0 && startTime >= endTime {
  49. return fmt.Errorf("start time must be before end time")
  50. }
  51. return nil
  52. }
  53. // buildBaseSearchRequest builds a base search request with common parameters
  54. func (s *service) buildBaseSearchRequest(startTime, endTime int64, logPath string) *searcher.SearchRequest {
  55. req := &searcher.SearchRequest{
  56. Limit: DefaultLimit,
  57. Offset: 0,
  58. UseCache: true,
  59. }
  60. if startTime > 0 {
  61. req.StartTime = &startTime
  62. }
  63. if endTime > 0 {
  64. req.EndTime = &endTime
  65. }
  66. if logPath != "" {
  67. req.LogPaths = []string{logPath}
  68. }
  69. return req
  70. }
  71. // validateAndNormalizeSearchRequest validates and normalizes a search request
  72. func (s *service) validateAndNormalizeSearchRequest(req *searcher.SearchRequest) error {
  73. if req == nil {
  74. return fmt.Errorf("request cannot be nil")
  75. }
  76. if req.Limit <= 0 {
  77. req.Limit = DefaultLimit
  78. }
  79. if req.Limit > MaxLimit {
  80. req.Limit = MaxLimit
  81. }
  82. if req.Offset < 0 {
  83. req.Offset = 0
  84. }
  85. return nil
  86. }