| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- package strmatcher
- import (
- "regexp"
- "sync"
- "time"
- "v2ray.com/core/common/task"
- )
- type Matcher interface {
- Match(string) bool
- }
- type Type byte
- const (
- Full Type = iota
- Substr
- Domain
- Regex
- )
- func (t Type) New(pattern string) (Matcher, error) {
- switch t {
- case Full:
- return fullMatcher(pattern), nil
- case Substr:
- return substrMatcher(pattern), nil
- case Domain:
- return domainMatcher(pattern), nil
- case Regex:
- r, err := regexp.Compile(pattern)
- if err != nil {
- return nil, err
- }
- return ®exMatcher{
- pattern: r,
- }, nil
- default:
- panic("Unknown type")
- }
- }
- type IndexMatcher interface {
- Match(pattern string) uint32
- }
- type matcherEntry struct {
- m Matcher
- id uint32
- }
- type MatcherGroup struct {
- count uint32
- fullMatchers map[string]uint32
- domainMatcher DomainMatcherGroup
- otherMatchers []matcherEntry
- }
- func NewMatcherGroup() *MatcherGroup {
- return &MatcherGroup{
- count: 1,
- fullMatchers: make(map[string]uint32),
- }
- }
- func (g *MatcherGroup) Add(m Matcher) uint32 {
- c := g.count
- g.count++
- switch tm := m.(type) {
- case fullMatcher:
- g.fullMatchers[string(tm)] = c
- case domainMatcher:
- g.domainMatcher.Add(string(tm), c)
- default:
- g.otherMatchers = append(g.otherMatchers, matcherEntry{
- m: m,
- id: c,
- })
- }
- return c
- }
- func (g *MatcherGroup) Match(pattern string) uint32 {
- if c, f := g.fullMatchers[pattern]; f {
- return c
- }
- if c := g.domainMatcher.Match(pattern); c > 0 {
- return c
- }
- for _, e := range g.otherMatchers {
- if e.m.Match(pattern) {
- return e.id
- }
- }
- return 0
- }
- func (g *MatcherGroup) Size() uint32 {
- return g.count
- }
- type cacheEntry struct {
- timestamp time.Time
- result uint32
- }
- type CachedMatcherGroup struct {
- sync.Mutex
- group *MatcherGroup
- cache map[string]cacheEntry
- cleanup *task.Periodic
- }
- func NewCachedMatcherGroup(g *MatcherGroup) *CachedMatcherGroup {
- r := &CachedMatcherGroup{
- group: g,
- cache: make(map[string]cacheEntry),
- }
- r.cleanup = &task.Periodic{
- Interval: time.Second * 30,
- Execute: func() error {
- r.Lock()
- defer r.Unlock()
- expire := time.Now().Add(-1 * time.Second * 60)
- for p, e := range r.cache {
- if e.timestamp.Before(expire) {
- delete(r.cache, p)
- }
- }
- return nil
- },
- }
- return r
- }
- func (g *CachedMatcherGroup) Match(pattern string) uint32 {
- g.Lock()
- defer g.Unlock()
- r, f := g.cache[pattern]
- if f {
- r.timestamp = time.Now()
- g.cache[pattern] = r
- return r.result
- }
- mr := g.group.Match(pattern)
- g.cache[pattern] = cacheEntry{
- result: mr,
- timestamp: time.Now(),
- }
- return mr
- }
|