| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 | package strmatcherimport (	"regexp"	"sync"	"time"	"v2ray.com/core/common/task")type Matcher interface {	Match(string) bool}type Type byteconst (	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	}	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}
 |