func (cache *Cache) EnrichEvent(event model.ProbeEvent) bool {
	nsEntry := event.GetNamespaceCacheData()
	nsInCache := true
	if nsEntry == nil {
		nsEntry, nsInCache = cache.NamespaceCache.LookupNamespace(event.GetNetns(), event.GetTimestamp())
		event.SetNamespaceCacheData(nsEntry)
	}
	switch event.GetEventType() {
	case model.ContainerRunningEventType:
		containerEvt := event.(*model.ContainerEvent)
		nsEntry.Lock()
		nsEntry.Name = containerEvt.ContainerName
		nsEntry.ID = containerEvt.ContainerID
		nsEntry.Base = containerEvt.Image
		nsEntry.Digest = containerEvt.Digest
		nsEntry.Pod = containerEvt.Labels["io.kubernetes.pod.name"]
		nsEntry.Namespace = containerEvt.Labels["io.kubernetes.pod.namespace"]
		nsEntry.Unlock()
		return true
	case model.ContainerDestroyedEventType:
		containerEvt := event.(*model.ContainerEvent)
		exitTime := containerEvt.FinishedAt
		nsEntry.Lock()
		nsEntry.ExitTime = &exitTime
		nsEntry.Unlock()
		return true
	default:
		pEntry := event.GetProcessCacheData()
		pInCache := true
		if pEntry == nil {
			var err error
			pEntry, pInCache, err = cache.ProcessCache.LookupPid(event.GetPid(), event.GetTimestamp())
			if err != nil {
				return false
			}
			event.SetProcessCacheData(pEntry)
		}
		switch event.GetEventType() {
		case model.ExecEventType:
			pEvt := event.(*model.ExecEvent)
			ts := pEvt.Timestamp
			pEntry.Lock()
			pEntry.BinaryPath = pEvt.Path
			pEntry.ExecveTime = &ts
			pEntry.Pid = pEvt.Metadata.PID
			pEntry.TTYName = pEvt.TTYName
			if pEntry.ExitTime != nil {
				if pEntry.ExitTime.Before(ts) {
					pEntry.ExitTime = nil
				}
			}
			pEntry.Unlock()
			pInCache = true
		case model.ExitEventType:
			pEvt := event.(*model.ExecEvent)
			ts := pEvt.Timestamp
			pEntry.Lock()
			if pEntry.ExecveTime != nil {
				if pEntry.ExecveTime.Before(ts) {
					pEntry.ExitTime = &ts
				}
			}
			pEntry.Unlock()
		case model.ForkEventType:
			pEvt := event.(*model.ForkEvent)
			if pEvt.IsNewProcess() {
				childEntry, _, err := cache.ProcessCache.LookupPid(pEvt.ChildPid, pEvt.GetTimestamp())
				if err == nil {
					childEntry.Lock()
					if childEntry.ExecveTime == nil || len(childEntry.BinaryPath) == 0 {
						childEntry.BinaryPath = pEntry.BinaryPath
						childEntry.ExecveTime = pEntry.ExecveTime
						childEntry.TTYName = pEntry.TTYName
					}
					childEntry.Pid = pEvt.ChildPid
					childEntry.Ppid = pEvt.Metadata.PID
					if pEntry.BinaryPath != "" {
						childEntry.Parent = pEntry
					}
					ts := pEvt.Timestamp
					childEntry.ForkTime = &ts
					childEntry.Unlock()
				}
			}
		}
		return nsInCache && pInCache
	}
}
EnrichEvent - Enrich event with process and container data. This function will return false
if either the namespace or the process weren't in cache, or if they were in cache but aren't
linked to a container or a process yet. Whatever the initial state of the cache, when this
function returns, a new entry in cache will be created and ready to be used.
package nsp
import (
	"fmt"
	"os"
	"sync"
	"sync/atomic"
	"time"
	"unsafe"
	"github.com/Gui774ume/network-security-probe/pkg/config"
	"github.com/Gui774ume/network-security-probe/pkg/model"
)
type processArrayCache struct {
	entries               []*model.ProcessCacheEntry
	processReuseThreshold int64
}
func newPidArrayCache(size uint32) *processArrayCache {
	return &processArrayCache{
		entries: make([]*model.ProcessCacheEntry, int(size)),
	}
}
func (cache *processArrayCache) LookupPid(pid uint32, evtTs time.Time) (*model.ProcessCacheEntry, bool, error) {
	if pid == 0 || int(pid) > len(cache.entries) {
		return nil, false, fmt.Errorf("(processArrayCache) invalid pid for lookup: %d", pid)
	}
	inCache := false
	var entry *model.ProcessCacheEntry
	for {
		var old *model.ProcessCacheEntry
		entry = cache.entries[pid-1]
		if entry != nil {
			if entry.ExitTime == nil || (evtTs.Before(entry.ExitTime.Add(100 * time.Millisecond))) {
				inCache = entry.IsInCache()
				break
			}
			old = entry
		}
		entry = &model.ProcessCacheEntry{}
		if atomic.CompareAndSwapPointer(
			(*unsafe.Pointer)(unsafe.Pointer(&cache.entries[pid-1])),
			unsafe.Pointer(old),
			unsafe.Pointer(entry)) {
			break
		}
	}
	return entry, inCache, nil
}
type namespaceMapCache struct {
	sync.Mutex
	entries map[uint64]*model.NamespaceCacheEntry
}
func newNamespaceMapCache() *namespaceMapCache {
	return &namespaceMapCache{
		Mutex:   sync.Mutex{},
		entries: make(map[uint64]*model.NamespaceCacheEntry),
	}
}
func (cache *namespaceMapCache) LookupNamespace(netns uint64, evtTs time.Time) (*model.NamespaceCacheEntry, bool) {
	cache.Lock()
	entry, ok := cache.entries[netns]
	inCache := ok
	if !ok || entry.ExitTime != nil && evtTs.After(entry.ExitTime.Add(100*time.Millisecond)) {
		entry = &model.NamespaceCacheEntry{}
		cache.entries[netns] = entry
	}
	if ok {
		inCache = entry.IsInCache()
	}
	cache.Unlock()
	return entry, inCache
}
type Cache struct {
	HostNetns      uint64
	ProcessCache   *processArrayCache
	NamespaceCache *namespaceMapCache
}
func NewCache(config *config.NSPConfig, hostNetns uint64) *Cache {
	cache := &Cache{
		ProcessCache:   newPidArrayCache(config.CLI.ProcessCacheSize),
		NamespaceCache: newNamespaceMapCache(),
	}
	hostNsEntry, _ := cache.NamespaceCache.LookupNamespace(hostNetns, time.Now())
	hostNsEntry.Name = "host"
	hostNsEntry.Base = "host"
	hostNsEntry.ID = "host"
	hostNsEntry.Digest = "host"
	currentPidEntry, _, _ := cache.ProcessCache.LookupPid(uint32(os.Getpid()), time.Now())
	now := time.Now()
	currentPidEntry.ExecveTime = &now
	currentPidEntry.ForkTime = &now
	return cache
}