github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/shell/autocomplete/paths_cache.go (about)

     1  package autocomplete
     2  
     3  import (
     4  	"crypto/md5"
     5  	"sync"
     6  	"time"
     7  )
     8  
     9  type pathsCacheT struct {
    10  	hash    map[string]pathsCacheItemT
    11  	gcSleep int
    12  	mutex   sync.Mutex
    13  }
    14  
    15  type pathsCacheItemT struct {
    16  	time  time.Time
    17  	paths []string
    18  }
    19  
    20  var pathsCache = NewPathsCache()
    21  
    22  func NewPathsCache() *pathsCacheT {
    23  	pc := new(pathsCacheT)
    24  	pc.hash = make(map[string]pathsCacheItemT)
    25  	pc.gcSleep = 5 // minutes
    26  	go pc.garbageCollection()
    27  	return pc
    28  }
    29  
    30  var (
    31  	t = []byte{':', 't'}
    32  	f = []byte{':', 'f'}
    33  )
    34  
    35  func (pc *pathsCacheT) CreateHash(exe string, filesToo bool, regexp bool) []byte {
    36  	h := md5.New()
    37  
    38  	_, err := h.Write([]byte(exe))
    39  	if err != nil {
    40  		return nil
    41  	}
    42  
    43  	if filesToo {
    44  		_, err = h.Write(t)
    45  	} else {
    46  		_, err = h.Write(f)
    47  	}
    48  	if err != nil {
    49  		return nil
    50  	}
    51  
    52  	if regexp {
    53  		_, err = h.Write(t)
    54  	} else {
    55  		_, err = h.Write(f)
    56  	}
    57  	if err != nil {
    58  		return nil
    59  	}
    60  
    61  	hash := h.Sum(nil)
    62  	return hash
    63  }
    64  
    65  func (pc *pathsCacheT) Get(hash []byte) []string {
    66  	s := string(hash)
    67  
    68  	pc.mutex.Lock()
    69  
    70  	cache := pc.hash[s]
    71  	if cache.time.After(time.Now()) {
    72  		s := cache.paths
    73  		pc.mutex.Unlock()
    74  		return s
    75  	}
    76  
    77  	pc.mutex.Unlock()
    78  	return nil
    79  }
    80  
    81  func (pc *pathsCacheT) Set(hash []byte, paths []string) {
    82  	pc.mutex.Lock()
    83  
    84  	pc.hash[string(hash)] = pathsCacheItemT{
    85  		time:  time.Now().Add(time.Duration(30) * time.Second),
    86  		paths: paths,
    87  	}
    88  
    89  	pc.mutex.Unlock()
    90  }
    91  
    92  func (pc *pathsCacheT) garbageCollection() {
    93  	for {
    94  		pc.mutex.Lock()
    95  		sleep := pc.gcSleep
    96  		pc.mutex.Unlock()
    97  		time.Sleep(time.Duration(sleep) * time.Minute)
    98  
    99  		pc.mutex.Lock()
   100  		for hash := range pc.hash {
   101  			if pc.hash[hash].time.Before(time.Now()) {
   102  				delete(pc.hash, hash)
   103  			}
   104  		}
   105  		pc.mutex.Unlock()
   106  	}
   107  }