strmatcher.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. package strmatcher
  2. import (
  3. "regexp"
  4. "sync"
  5. "time"
  6. "v2ray.com/core/common/task"
  7. )
  8. type Matcher interface {
  9. Match(string) bool
  10. }
  11. type Type byte
  12. const (
  13. Full Type = iota
  14. Substr
  15. Domain
  16. Regex
  17. )
  18. func (t Type) New(pattern string) (Matcher, error) {
  19. switch t {
  20. case Full:
  21. return fullMatcher(pattern), nil
  22. case Substr:
  23. return substrMatcher(pattern), nil
  24. case Domain:
  25. return domainMatcher(pattern), nil
  26. case Regex:
  27. r, err := regexp.Compile(pattern)
  28. if err != nil {
  29. return nil, err
  30. }
  31. return &regexMatcher{
  32. pattern: r,
  33. }, nil
  34. default:
  35. panic("Unknown type")
  36. }
  37. }
  38. type IndexMatcher interface {
  39. Match(pattern string) uint32
  40. }
  41. type matcherEntry struct {
  42. m Matcher
  43. id uint32
  44. }
  45. type MatcherGroup struct {
  46. count uint32
  47. fullMatcher FullMatcherGroup
  48. domainMatcher DomainMatcherGroup
  49. otherMatchers []matcherEntry
  50. }
  51. func NewMatcherGroup() *MatcherGroup {
  52. return &MatcherGroup{}
  53. }
  54. func (g *MatcherGroup) Add(m Matcher) uint32 {
  55. g.count++
  56. c := g.count
  57. switch tm := m.(type) {
  58. case fullMatcher:
  59. g.fullMatcher.addMatcher(tm, c)
  60. case domainMatcher:
  61. g.domainMatcher.addMatcher(tm, c)
  62. default:
  63. g.otherMatchers = append(g.otherMatchers, matcherEntry{
  64. m: m,
  65. id: c,
  66. })
  67. }
  68. return c
  69. }
  70. func (g *MatcherGroup) Match(pattern string) uint32 {
  71. if c := g.fullMatcher.Match(pattern); c > 0 {
  72. return c
  73. }
  74. if c := g.domainMatcher.Match(pattern); c > 0 {
  75. return c
  76. }
  77. for _, e := range g.otherMatchers {
  78. if e.m.Match(pattern) {
  79. return e.id
  80. }
  81. }
  82. return 0
  83. }
  84. func (g *MatcherGroup) Size() uint32 {
  85. return g.count
  86. }
  87. type cacheEntry struct {
  88. timestamp time.Time
  89. result uint32
  90. }
  91. type CachedMatcherGroup struct {
  92. sync.RWMutex
  93. group *MatcherGroup
  94. cache map[string]cacheEntry
  95. cleanup *task.Periodic
  96. }
  97. func NewCachedMatcherGroup(g *MatcherGroup) *CachedMatcherGroup {
  98. r := &CachedMatcherGroup{
  99. group: g,
  100. cache: make(map[string]cacheEntry),
  101. }
  102. r.cleanup = &task.Periodic{
  103. Interval: time.Second * 30,
  104. Execute: func() error {
  105. r.Lock()
  106. defer r.Unlock()
  107. expire := time.Now().Add(-1 * time.Second * 120)
  108. for p, e := range r.cache {
  109. if e.timestamp.Before(expire) {
  110. delete(r.cache, p)
  111. }
  112. }
  113. return nil
  114. },
  115. }
  116. return r
  117. }
  118. func (g *CachedMatcherGroup) Match(pattern string) uint32 {
  119. g.RLock()
  120. r, f := g.cache[pattern]
  121. g.RUnlock()
  122. if f {
  123. return r.result
  124. }
  125. mr := g.group.Match(pattern)
  126. g.Lock()
  127. g.cache[pattern] = cacheEntry{
  128. result: mr,
  129. timestamp: time.Now(),
  130. }
  131. g.Unlock()
  132. return mr
  133. }