|  | @@ -17,6 +17,7 @@ import (
 | 
	
		
			
				|  |  |  	"v2ray.com/core/common/net"
 | 
	
		
			
				|  |  |  	"v2ray.com/core/common/protocol"
 | 
	
		
			
				|  |  |  	"v2ray.com/core/common/serial"
 | 
	
		
			
				|  |  | +	"v2ray.com/core/common/signal"
 | 
	
		
			
				|  |  |  	"v2ray.com/core/proxy/vmess"
 | 
	
		
			
				|  |  |  )
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -29,19 +30,29 @@ type sessionId struct {
 | 
	
		
			
				|  |  |  type SessionHistory struct {
 | 
	
		
			
				|  |  |  	sync.RWMutex
 | 
	
		
			
				|  |  |  	cache map[sessionId]time.Time
 | 
	
		
			
				|  |  | +	token *signal.Semaphore
 | 
	
		
			
				|  |  | +	ctx   context.Context
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  func NewSessionHistory(ctx context.Context) *SessionHistory {
 | 
	
		
			
				|  |  |  	h := &SessionHistory{
 | 
	
		
			
				|  |  |  		cache: make(map[sessionId]time.Time, 128),
 | 
	
		
			
				|  |  | +		token: signal.NewSemaphore(1),
 | 
	
		
			
				|  |  | +		ctx:   ctx,
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | -	go h.run(ctx)
 | 
	
		
			
				|  |  |  	return h
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  func (h *SessionHistory) add(session sessionId) {
 | 
	
		
			
				|  |  |  	h.Lock()
 | 
	
		
			
				|  |  |  	h.cache[session] = time.Now().Add(time.Minute * 3)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	select {
 | 
	
		
			
				|  |  | +	case <-h.token.Wait():
 | 
	
		
			
				|  |  | +		go h.run()
 | 
	
		
			
				|  |  | +	default:
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  	h.Unlock()
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -55,16 +66,22 @@ func (h *SessionHistory) has(session sessionId) bool {
 | 
	
		
			
				|  |  |  	return false
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func (h *SessionHistory) run(ctx context.Context) {
 | 
	
		
			
				|  |  | +func (h *SessionHistory) run() {
 | 
	
		
			
				|  |  | +	defer h.token.Signal()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  	for {
 | 
	
		
			
				|  |  |  		select {
 | 
	
		
			
				|  |  | -		case <-ctx.Done():
 | 
	
		
			
				|  |  | +		case <-h.ctx.Done():
 | 
	
		
			
				|  |  |  			return
 | 
	
		
			
				|  |  |  		case <-time.After(time.Second * 30):
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  		session2Remove := make([]sessionId, 0, 16)
 | 
	
		
			
				|  |  |  		now := time.Now()
 | 
	
		
			
				|  |  |  		h.Lock()
 | 
	
		
			
				|  |  | +		if len(h.cache) == 0 {
 | 
	
		
			
				|  |  | +			h.Unlock()
 | 
	
		
			
				|  |  | +			return
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  |  		for session, expire := range h.cache {
 | 
	
		
			
				|  |  |  			if expire.Before(now) {
 | 
	
		
			
				|  |  |  				session2Remove = append(session2Remove, session)
 |