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: authenticator.go
    path of file: ./repos/magma/feg/gateway/services/aaa/servicers
    
    the code of the file until where you have to start completion: /*
Copyright 2020 The Magma Authors.

This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree.

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WAR
    
func (srv *eapAuth) Handle(ctx context.Context, in *protos.Eap) (*protos.Eap, error) {
	resp, err := client.Handle(in)
	if resp == nil {
		errMsg := fmt.Sprintf("Auth Handle error: %v, <nil> response", err)
		if srv.config.GetEventLoggingEnabled() {
			events.LogAuthenticationFailedEvent(in.GetCtx(), errMsg)
		}
		return resp, Errorf(codes.Internal, errMsg)
	}
	method := eap.Packet(resp.GetPayload()).Type()
	if method == uint8(protos.EapType_Reserved) {
		method = eap.Packet(in.GetPayload()).Type()
	}

	metrics.Auth.WithLabelValues(
		protos.EapCode(eap.Packet(resp.GetPayload()).Code()).String(),
		protos.EapType(method).String(),
		in.GetCtx().GetApn(),
		resp.Ctx.GetImsi()).Inc()

	if err != nil && len(resp.GetPayload()) > 0 {
		// log error, but do not return it to Radius. EAP will carry its own error
		errMsg := fmt.Sprintf("EAP Handle Error for Identity '%s', APN '%s': %v", resp.GetCtx().GetIdentity(), resp.GetCtx().GetApn(), err)
		if srv.config.GetEventLoggingEnabled() {
			events.LogAuthenticationFailedEvent(resp.GetCtx(), errMsg)
		}
		glog.Error(errMsg)
		return resp, nil
	}
	if srv.sessions != nil && eap.Packet(resp.Payload).IsSuccess() {
		if srv.config.GetEventLoggingEnabled() {
			events.LogAuthenticationSuccessEvent(resp.GetCtx())
		}

		imsi := resp.Ctx.GetImsi()
		if srv.config.GetAccountingEnabled() && srv.config.GetCreateSessionOnAuth() {
			if srv.accounting == nil {
				resp.Payload[eap.EapMsgCode] = eap.FailureCode
				glog.Errorf("Cannot Create Session on Auth: accounting service is missing")
				return resp, nil
			}
			csResp, err := srv.accounting.CreateSession(ctx, resp.Ctx)
			if err != nil {
				resp.Payload[eap.EapMsgCode] = eap.FailureCode
				glog.Errorf("Failed to create session: %v", err)
				return resp, nil
			}
			resp.Ctx.AcctSessionId = csResp.GetSessionId()
		}
		if srv.accounting != nil {
			_, err := srv.accounting.baseAccountingStart(resp.Ctx)
			if err != nil {
				resp.Payload[eap.EapMsgCode] = eap.FailureCode
				glog.Errorf("Accounting session start error: %v", err)
				return resp, nil
			}
		}
		// Add Session & overwrite an existing session with the same ID if present,
		// otherwise a UE can get stuck on buggy/non-unique AP or Radius session generation
		resp.Ctx.CreatedTimeMs = uint64(time.Now().UnixNano() / NanoInMilli)
		_, err := srv.sessions.AddSession(resp.Ctx, srv.sessionTout, srv.accounting.timeoutSessionNotifier, true)
		if err != nil {
			glog.Errorf("Error adding a new session for SID: %s: %v", resp.Ctx.GetSessionId(), err)
			return resp, nil // log error, but don't pass to caller, the auth only users will still be able to connect
		}
		updateRequest := &orcprotos.UpdateRecordRequest{
			Id:       imsi,
			Location: gatewayHardwareId,
			Fields:   map[string]string{MacAddrKey: resp.Ctx.GetMacAddr()},
		}
		// execute in a new goroutine in case calls to directoryd take long time
		go directoryd.UpdateRecord(updateRequest)
	}
	return resp, nil
}