// handleSingleMessage processes a single refresh credentials message.
func (refreshHandler *refreshCredentialsHandler) handleSingleMessage(message *ecsacs.IAMRoleCredentialsMessage) error {
	// Validate fields in the message
	err := validateIAMRoleCredentialsMessage(message)
	if err != nil {
		seelog.Errorf("Error validating credentials message: %v", err)
		return err
	}
	taskArn := aws.StringValue(message.TaskArn)
	messageId := aws.StringValue(message.MessageId)
	task, ok := refreshHandler.taskEngine.GetTaskByArn(taskArn)
	if !ok {
		seelog.Errorf("Task not found in the engine for the arn in credentials message, arn: %s, messageId: %s", taskArn, messageId)
		return fmt.Errorf("Task not found in the engine for the arn in credentials message, arn: %s", taskArn)
	}
	taskCredentials := credentials.TaskIAMRoleCredentials{
		ARN:                taskArn,
		IAMRoleCredentials: credentials.IAMRoleCredentialsFromACS(message.RoleCredentials),
	}
	err = refreshHandler.credentialsManager.SetTaskCredentials(taskCredentials)
	if err != nil {
		seelog.Errorf("Error updating credentials, err: %v messageId: %s", err, messageId)
		return fmt.Errorf("Error updating credentials %v", err)
	}
	task.SetCredentialsId(aws.StringValue(message.RoleCredentials.CredentialsId))

	go func() {
		response := &ecsacs.IAMRoleCredentialsAckRequest{
			Expiration:    message.RoleCredentials.Expiration,
			MessageId:     message.MessageId,
			CredentialsId: message.RoleCredentials.CredentialsId,
		}
		refreshHandler.ackRequest <- response
	}()
	return nil
}
// addPayloadTasks does validation on each task and, for all valid ones, adds
// it to the task engine. It returns a bool indicating if it could add every
// task to the taskEngine and a slice of credential ack requests
func (payloadHandler *payloadRequestHandler) addPayloadTasks(payload *ecsacs.PayloadMessage) ([]*ecsacs.IAMRoleCredentialsAckRequest, bool) {
	// verify thatwe were able to work with all tasks in this payload so we know whether to ack the whole thing or not
	allTasksOK := true

	validTasks := make([]*api.Task, 0, len(payload.Tasks))
	for _, task := range payload.Tasks {
		if task == nil {
			seelog.Criticalf("Recieved nil task for messageId: %s", *payload.MessageId)
			allTasksOK = false
			continue
		}
		apiTask, err := api.TaskFromACS(task, payload)
		if err != nil {
			payloadHandler.handleUnrecognizedTask(task, err, payload)
			allTasksOK = false
			continue
		}
		if task.RoleCredentials != nil {
			// The payload from ACS for the task has credentials for the
			// task. Add those to the credentials manager and set the
			// credentials id for the task as well
			taskCredentials := credentials.TaskIAMRoleCredentials{
				ARN:                aws.StringValue(task.Arn),
				IAMRoleCredentials: credentials.IAMRoleCredentialsFromACS(task.RoleCredentials),
			}
			err = payloadHandler.credentialsManager.SetTaskCredentials(taskCredentials)
			if err != nil {
				payloadHandler.handleUnrecognizedTask(task, err, payload)
				allTasksOK = false
				continue
			}
			apiTask.SetCredentialsId(taskCredentials.IAMRoleCredentials.CredentialsId)
		}
		validTasks = append(validTasks, apiTask)
	}
	// Add 'stop' transitions first to allow seqnum ordering to work out
	// Because a 'start' sequence number should only be proceeded if all 'stop's
	// of the same sequence number have completed, the 'start' events need to be
	// added after the 'stop' events are there to block them.
	stoppedTasksCredentialsAcks, stoppedTasksAddedOK := payloadHandler.addTasks(payload, validTasks, isTaskStatusNotStopped)
	newTasksCredentialsAcks, newTasksAddedOK := payloadHandler.addTasks(payload, validTasks, isTaskStatusStopped)
	if !stoppedTasksAddedOK || !newTasksAddedOK {
		allTasksOK = false
	}

	// Construct a slice with credentials acks from all tasks
	var credentialsAcks []*ecsacs.IAMRoleCredentialsAckRequest
	credentialsAcks = append(stoppedTasksCredentialsAcks, newTasksCredentialsAcks...)
	return credentialsAcks, allTasksOK
}