func (h *Handler) UpdateSession(product, productPassword, clientKey string,
	units uint64, stopSession bool) error {
	logger := h.logger.Add("method", "UpdateSession", "product", product,
		"clientKey", clientKey, "units", units,
		"stopSession", stopSession)

	if stopSession {
		logger.Info("session stop request")
	} else {
		logger.Info("session update request")
	}

	prod, err := h.checkProductPassword(logger, product, productPassword)
	if err != nil {
		return err
	}

	ch, err := h.findClientChannel(logger, prod, clientKey, true)
	if err != nil {
		return err
	}

	// Make the server adapter to kill the session for non-active channel.
	if prod.IsServer && ch.ServiceStatus != data.ServiceActive {
		logger.Warn("non-active channel")
		return ErrNonActiveChannel
	}

	clientStop := !prod.IsServer && stopSession

	if clientStop {
		if ch.ServiceStatus == data.ServiceTerminated {
			logger.Warn("already terminated channel")
			return nil
		}

		status := data.ServiceSuspended
		if ch.ServiceStatus == data.ServiceTerminating {
			status = data.ServiceTerminated
		}

		err := job.AddWithData(h.queue, nil,
			data.JobClientCompleteServiceTransition,
			data.JobChannel, ch.ID, data.JobSessionServer,
			status)
		if err != nil && err != job.ErrDuplicatedJob {
			logger.Error(err.Error())
			return err
		}
	}

	sess, err := h.findCurrentSession(logger, ch.ID)
	if err != nil {
		// Client adapter can signal failure immediately, when no
		// session is yet created.
		if err == ErrSessionNotFound && clientStop {
			return nil
		}
		return err
	}
	logger = logger.Add("session", sess)

	if units != 0 {
		// TODO: Use unit size instead of this hardcode.
		units /= 1024 * 1024

		switch prod.UsageRepType {
		case data.ProductUsageIncremental:
			sess.UnitsUsed += units
		case data.ProductUsageTotal:
			sess.UnitsUsed = units
		default:
			logger.Fatal("unsupported product usage")
		}
	}

	sess.LastUsageTime = time.Now()
	if stopSession {
		sess.Stopped = pointer.ToTime(sess.LastUsageTime)
	}

	logger.Info("updating session")

	if err := h.db.Save(sess); err != nil {
		logger.Error(err.Error())
		return ErrInternal
	}

	return nil
}
func (h *Handler) UpdateSession(product, productPassword, clientKey string,
	units uint64, stopSession bool) error {
	logger := h.logger.Add("method", "UpdateSession", "product", product,
		"clientKey", clientKey, "units", units,
		"stopSession", stopSession)

	if stopSession {
		logger.Info("session stop request")
	} else {
		logger.Info("session update request")
	}

	prod, err := h.checkProductPassword(logger, product, productPassword)
	if err != nil {
		return err
	}

	ch, err := h.findClientChannel(logger, prod, clientKey, true)
	if err != nil {
		return err
	}

	// Make the server adapter to kill the session for non-active channel.
	if prod.IsServer && ch.ServiceStatus != data.ServiceActive {
		logger.Warn("non-active channel")
		return ErrNonActiveChannel
	}

	clientStop := !prod.IsServer && stopSession

	if clientStop {
		if ch.ServiceStatus == data.ServiceTerminated {
			logger.Warn("already terminated channel")
			return nil
		}

		status := data.ServiceSuspended
		if ch.ServiceStatus == data.ServiceTerminating {
			status = data.ServiceTerminated
		}

		err := job.AddWithData(h.queue, nil,
			data.JobClientCompleteServiceTransition,
			data.JobChannel, ch.ID, data.JobSessionServer,
			status)
		if err != nil && err != job.ErrDuplicatedJob {
			logger.Error(err.Error())
			return err
		}
	}

	sess, err := h.findCurrentSession(logger, ch.ID)
	if err != nil {
		// Client adapter can signal failure immediately, when no
		// session is yet created.
		if err == ErrSessionNotFound && clientStop {
			return nil
		}
		return err
	}
	logger = logger.Add("session", sess)

	if units != 0 {
		// TODO: Use unit size instead of this hardcode.
		units /= 1024 * 1024

		switch prod.UsageRepType {
		case data.ProductUsageIncremental:
			sess.UnitsUsed += units
		case data.ProductUsageTotal:
			sess.UnitsUsed = units
		default:
			logger.Fatal("unsupported product usage")
		}
	}

	sess.LastUsageTime = time.Now()
	if stopSession {
		sess.Stopped = pointer.ToTime(sess.LastUsageTime)
	}

	logger.Info("updating session")

	if err := h.db.Save(sess); err != nil {
		logger.Error(err.Error())
		return ErrInternal
	}

	return nil
}
// UpdateSession updates and optionally stops the current client session.