func (c *cache) Lookup(hash hashPrefix) (map[ThreatDescriptor]bool, cacheResult) {
	if !hash.IsFull() {
		panic("hash is not full")
	}
	c.Lock()
	defer c.Unlock()
	now := c.now()
	threats := make(map[ThreatDescriptor]bool)
	threatTTLs := c.pttls[hash]
	for td, pttl := range threatTTLs {
		if pttl.After(now) {
			threats[td] = true
		} else {
			return nil, cacheMiss
		}
	}
	if len(threats) > 0 {
		return threats, positiveCacheHit
	}
	for i := minHashPrefixLength; i <= maxHashPrefixLength; i++ {
		if nttl, ok := c.nttls[hash[:i]]; ok {
			if nttl.After(now) {
				return nil, negativeCacheHit
			}
		}
	}
	return nil, cacheMiss
}
Lookup looks up a full hash and returns a set of ThreatDescriptors and the
validity of the result.
package safebrowsing
import (
	"sync"
	"time"
	pb "github.com/google/safebrowsing/internal/safebrowsing_proto"
)
type cacheResult int
const (
	positiveCacheHit cacheResult = iota
	negativeCacheHit
	cacheMiss
)
type cache struct {
	sync.RWMutex
	pttls map[hashPrefix]map[ThreatDescriptor]time.Time
	nttls map[hashPrefix]time.Time
	now func() time.Time
}
func (c *cache) Update(req *pb.FindFullHashesRequest, resp *pb.FindFullHashesResponse) {
	c.Lock()
	defer c.Unlock()
	now := c.now()
	if c.pttls == nil {
		c.pttls = make(map[hashPrefix]map[ThreatDescriptor]time.Time)
		c.nttls = make(map[hashPrefix]time.Time)
	}
	for _, tm := range resp.GetMatches() {
		fullHash := hashPrefix(tm.GetThreat().Hash)
		if !fullHash.IsFull() {
			continue
		}
		if c.pttls[fullHash] == nil {
			c.pttls[fullHash] = make(map[ThreatDescriptor]time.Time)
		}
		var dur time.Duration
		if tmCacheDur := tm.GetCacheDuration(); tmCacheDur != nil {
			dur = time.Duration(tm.GetCacheDuration().Seconds) * time.Second
		} else {
			dur = 0
		}
		td := ThreatDescriptor{
			ThreatType:      ThreatType(tm.ThreatType),
			PlatformType:    PlatformType(tm.PlatformType),
			ThreatEntryType: ThreatEntryType(tm.ThreatEntryType),
		}
		c.pttls[fullHash][td] = now.Add(dur)
	}
	if resp.GetNegativeCacheDuration() != nil {
		dur := time.Duration(resp.GetNegativeCacheDuration().Seconds) * time.Second
		nttl := now.Add(dur)
		for _, te := range req.GetThreatInfo().GetThreatEntries() {
			partialHash := hashPrefix(te.Hash)
			c.nttls[partialHash] = nttl
		}
	}
}