strmatcher.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  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. fullMatchers map[string]uint32
  48. domainMatcher DomainMatcherGroup
  49. otherMatchers []matcherEntry
  50. }
  51. func NewMatcherGroup() *MatcherGroup {
  52. return &MatcherGroup{
  53. count: 1,
  54. fullMatchers: make(map[string]uint32),
  55. }
  56. }
  57. func (g *MatcherGroup) Add(m Matcher) uint32 {
  58. c := g.count
  59. g.count++
  60. switch tm := m.(type) {
  61. case fullMatcher:
  62. g.fullMatchers[string(tm)] = c
  63. case domainMatcher:
  64. g.domainMatcher.Add(string(tm), c)
  65. default:
  66. g.otherMatchers = append(g.otherMatchers, matcherEntry{
  67. m: m,
  68. id: c,
  69. })
  70. }
  71. return c
  72. }
  73. func (g *MatcherGroup) Match(pattern string) uint32 {
  74. if c, f := g.fullMatchers[pattern]; f {
  75. return c
  76. }
  77. if c := g.domainMatcher.Match(pattern); c > 0 {
  78. return c
  79. }
  80. for _, e := range g.otherMatchers {
  81. if e.m.Match(pattern) {
  82. return e.id
  83. }
  84. }
  85. return 0
  86. }
  87. func (g *MatcherGroup) Size() uint32 {
  88. return g.count
  89. }
  90. type cacheEntry struct {
  91. timestamp time.Time
  92. result uint32
  93. }
  94. type CachedMatcherGroup struct {
  95. sync.Mutex
  96. group *MatcherGroup
  97. cache map[string]cacheEntry
  98. cleanup *task.Periodic
  99. }
  100. func NewCachedMatcherGroup(g *MatcherGroup) *CachedMatcherGroup {
  101. r := &CachedMatcherGroup{
  102. group: g,
  103. cache: make(map[string]cacheEntry),
  104. }
  105. r.cleanup = &task.Periodic{
  106. Interval: time.Second * 30,
  107. Execute: func() error {
  108. r.Lock()
  109. defer r.Unlock()
  110. expire := time.Now().Add(-1 * time.Second * 60)
  111. for p, e := range r.cache {
  112. if e.timestamp.Before(expire) {
  113. delete(r.cache, p)
  114. }
  115. }
  116. return nil
  117. },
  118. }
  119. return r
  120. }
  121. func (g *CachedMatcherGroup) Match(pattern string) uint32 {
  122. g.Lock()
  123. defer g.Unlock()
  124. r, f := g.cache[pattern]
  125. if f {
  126. r.timestamp = time.Now()
  127. g.cache[pattern] = r
  128. return r.result
  129. }
  130. mr := g.group.Match(pattern)
  131. g.cache[pattern] = cacheEntry{
  132. result: mr,
  133. timestamp: time.Now(),
  134. }
  135. return mr
  136. }