You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: tracker.go
    path of file: ./repos/keploy/pkg/hooks/connection
    
    the code of the file until where you have to start completion: package connection

import (
	"fmt"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	structs2 "go.keploy.io/server/pkg/hooks/structs"
	"go.keploy.io/server/pkg/models"
	"go.uber.org/zap"
	// "log"
)

const (
	maxBufferSize = 16 * 1024 * 1024 // 16MB
)

// Tracker is a routine-safe container that holds a connection with unique ID, and able to create new connection.
type Tracker struct {
	connID         structs2.ConnID
	addr           structs2.SockAddrIn
	openTimestamp  uint64
	closeTimestamp uint64

	// Indicates the tracker stopped tracking due to closing the session.
	lastActivityTimestamp uint64

	// Queues to handle multiple ingress traffic on the same connection (keep-alive)

	// kernelRespSizes is a slice of the total number of Response bytes received in the kernel side
	kernelRespSizes []uint64

	// kernelReqSizes is a slice of the total number of Request bytes received in the kernel side
	kernelReqSizes []uint64

	// userRespSizes is a slice of the total number of Response bytes received in the user side
	userRespSizes []uint64

	// userReqSizes is a slice of the total number of Request bytes received in the user side
	userReqSizes []uint64
	// userRespBufs is a slice of the Response data received in the user side on this connection
	userResps [][]byte
	// userReqBufs is a slice of the Request data received in the user side on this connection
	userReqs [][]byte

	// req and resp are the buffers to store the request and response data for the current request
	// reset after 2 seconds of inactivity
	respSize uint64
	reqSize  uint64
	resp     []byte
	req      []byte

	// Additional fields to know when to capture request or response info
	// reset after 2 seconds of inactivity
	lastChunkWasResp bool
	lastChunkWasReq  bool
	recTestCounter   int32 //atomic counter
	// firstRequest is used to indicate if the current request is the first request on the connection
	// reset after 2 seconds of inactivity
	// Note: This is used to handle multiple requests on the same connection (keep-alive)
	// Its different from isNewRequest which is used to indicate if the current request chunk is the first chunk of the request
	firstRequest bool

	mutex  sync.RWMutex
	logger *zap.Logger

	reqTimestamps []time.Time
	isNewRequest  bool
}

func NewTracker(connID structs2.ConnID, logger *zap.Logger) *Tracker {
	return &Tracker{
		connID:          connID,
		req:             []byte{},
		resp:            []byte{},
		kernelRespSizes: []uint64{},
		kernelReqSizes:  []uint64{},
		userRespSizes:   []uint64{},
		userReqSizes:    []uint64{},
		userResps:       [][]byte{},
		userReqs:        [][]byte{},
		mutex:           sync.RWMutex{},
		logger:          logger,
		firstRequest:    true,
		isNewRequest:    true,
	}
}

func (conn *Tracker) ToBytes() ([]byte, []byte) {
	conn.mutex.RLock()
	defer conn.mutex.RUnlock()
	return conn.req, conn.resp
}

func (conn *Tracker) IsInactive(duration time.Duration) bool {
	conn.mutex.RLo
    
func (conn *Tracker) AddDataEvent(event structs2.SocketDataEvent) {
	conn.mutex.Lock()
	defer conn.mutex.Unlock()
	conn.UpdateTimestamps()

	conn.logger.Debug(fmt.Sprintf("Got a data event from eBPF, Direction:%v || current Event Size:%v || ConnectionID:%v\n", event.Direction, event.MsgSize, event.ConnID))

	switch event.Direction {
	case structs2.EgressTraffic:
		// Capturing the timestamp of response as the response just started to come.
		// This is to ensure that we capture the response timestamp for the first chunk of the response.
		if !conn.isNewRequest {
			conn.isNewRequest = true
		}

		// Assign the size of the message to the variable msgLengt
		msgLength := event.MsgSize
		// If the size of the message exceeds the maximum allowed size,
		// set msgLength to the maximum allowed size instead
		if event.MsgSize > structs2.EventBodyMaxSize {
			msgLength = structs2.EventBodyMaxSize
		}
		// Append the message (up to msgLength) to the connection's sent buffer
		conn.resp = append(conn.resp, event.Msg[:msgLength]...)
		conn.respSize += uint64(event.MsgSize)

		//Handling multiple request on same connection to support connection:keep-alive
		if conn.firstRequest || conn.lastChunkWasReq {
			conn.userReqSizes = append(conn.userReqSizes, conn.reqSize)
			conn.reqSize = 0

			conn.userReqs = append(conn.userReqs, conn.req)
			conn.req = []byte{}

			conn.lastChunkWasReq = false
			conn.lastChunkWasResp = true

			conn.kernelReqSizes = append(conn.kernelReqSizes, uint64(event.ValidateReadBytes))
			conn.firstRequest = false
		}

	case structs2.IngressTraffic:
		// Capturing the timestamp of request as the request just started to come.
		if conn.isNewRequest {
			conn.reqTimestamps = append(conn.reqTimestamps, ConvertUnixNanoToTime(event.EntryTimestampNano))
			conn.isNewRequest = false
		}

		// Assign the size of the message to the variable msgLength
		msgLength := event.MsgSize
		// If the size of the message exceeds the maximum allowed size,
		// set msgLength to the maximum allowed size instead
		if event.MsgSize > structs2.EventBodyMaxSize {
			msgLength = structs2.EventBodyMaxSize
		}
		// Append the message (up to msgLength) to the connection's receive buffer
		conn.req = append(conn.req, event.Msg[:msgLength]...)
		conn.reqSize += uint64(event.MsgSize)

		//Handling multiple request on same connection to support connection:keep-alive
		if conn.lastChunkWasResp {
			// conn.userRespSizes is the total numner of bytes received in the user side
			// consumer for the last response.
			conn.userRespSizes = append(conn.userRespSizes, conn.respSize)
			conn.respSize = 0

			conn.userResps = append(conn.userResps, conn.resp)
			conn.resp = []byte{}

			conn.lastChunkWasReq = true
			conn.lastChunkWasResp = false

			conn.kernelRespSizes = append(conn.kernelRespSizes, uint64(event.ValidateWrittenBytes))

			//Record a test case for the current request/
			conn.incRecordTestCount()
		}

	default:
	}
}