| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 | 
							- package strmatcher
 
- import (
 
- 	"regexp"
 
- 	"sync"
 
- 	"time"
 
- 	"v2ray.com/core/common"
 
- 	"v2ray.com/core/common/task"
 
- )
 
- // Matcher is the interface to determine a string matches a pattern.
 
- type Matcher interface {
 
- 	// Match returns true if the given string matches a predefined pattern.
 
- 	Match(string) bool
 
- }
 
- // Type is the type of the matcher.
 
- type Type byte
 
- const (
 
- 	// Full is the type of matcher that the input string must exactly equal to the pattern.
 
- 	Full Type = iota
 
- 	// Substr is the type of matcher that the input string must contain the pattern as a sub-string.
 
- 	Substr
 
- 	// Domain is the type of matcher that the input string must be a sub-domain or itself of the pattern.
 
- 	Domain
 
- 	// Regex is the type of matcher that the input string must matches the regular-expression pattern.
 
- 	Regex
 
- )
 
- // New creates a new Matcher based on the given pattern.
 
- 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")
 
- 	}
 
- }
 
- // IndexMatcher is the interface for matching with a group of matchers.
 
- type IndexMatcher interface {
 
- 	// Match returns the the index of a matcher that matches the input. It returns 0 if no such matcher exists.
 
- 	Match(input string) uint32
 
- }
 
- type matcherEntry struct {
 
- 	m  Matcher
 
- 	id uint32
 
- }
 
- // MatcherGroup is an implementation of IndexMatcher.
 
- // Empty initialization works.
 
- type MatcherGroup struct {
 
- 	count         uint32
 
- 	fullMatcher   FullMatcherGroup
 
- 	domainMatcher DomainMatcherGroup
 
- 	otherMatchers []matcherEntry
 
- }
 
- // Add adds a new Matcher into the MatcherGroup, and returns its index. The index will never be 0.
 
- func (g *MatcherGroup) Add(m Matcher) uint32 {
 
- 	g.count++
 
- 	c := g.count
 
- 	switch tm := m.(type) {
 
- 	case fullMatcher:
 
- 		g.fullMatcher.addMatcher(tm, c)
 
- 	case domainMatcher:
 
- 		g.domainMatcher.addMatcher(tm, c)
 
- 	default:
 
- 		g.otherMatchers = append(g.otherMatchers, matcherEntry{
 
- 			m:  m,
 
- 			id: c,
 
- 		})
 
- 	}
 
- 	return c
 
- }
 
- // Match implements IndexMatcher.Match.
 
- func (g *MatcherGroup) Match(pattern string) uint32 {
 
- 	if c := g.fullMatcher.Match(pattern); c > 0 {
 
- 		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
 
- }
 
- // Size returns the number of matchers in the MatcherGroup.
 
- func (g *MatcherGroup) Size() uint32 {
 
- 	return g.count
 
- }
 
- type cacheEntry struct {
 
- 	timestamp time.Time
 
- 	result    uint32
 
- }
 
- // CachedMatcherGroup is a IndexMatcher with cachable results.
 
- type CachedMatcherGroup struct {
 
- 	sync.RWMutex
 
- 	group   *MatcherGroup
 
- 	cache   map[string]cacheEntry
 
- 	cleanup *task.Periodic
 
- }
 
- // NewCachedMatcherGroup creats a new CachedMatcherGroup.
 
- 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 * 120)
 
- 			for p, e := range r.cache {
 
- 				if e.timestamp.Before(expire) {
 
- 					delete(r.cache, p)
 
- 				}
 
- 			}
 
- 			return nil
 
- 		},
 
- 	}
 
- 	common.Must(r.cleanup.Start())
 
- 	return r
 
- }
 
- // Match implements IndexMatcher.Match.
 
- func (g *CachedMatcherGroup) Match(pattern string) uint32 {
 
- 	g.RLock()
 
- 	r, f := g.cache[pattern]
 
- 	g.RUnlock()
 
- 	if f {
 
- 		return r.result
 
- 	}
 
- 	mr := g.group.Match(pattern)
 
- 	g.Lock()
 
- 	g.cache[pattern] = cacheEntry{
 
- 		result:    mr,
 
- 		timestamp: time.Now(),
 
- 	}
 
- 	g.Unlock()
 
- 	return mr
 
- }
 
 
  |