[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/Soralsei/client-sdk-cpp/main/src/token_source_json.cpp [Back]  [Original]

/*
 * Copyright 2026 LiveKit
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the License governing permissions and limitations.
 */

#include 
#include 
#include 

#include "token_source_internal.h"

namespace livekit {
namespace {

using nlohmann::json;

// Read a string field, accepting either the snake_case or camelCase spelling.
// Returns the value only when it is a non-empty JSON string.
std::optional readStringField(const json& obj, const char* snake_key, const char* camel_key) {
  for (const char* key : {snake_key, camel_key}) {
    const auto it = obj.find(key);
    if (it != obj.end() && it->is_string()) {
      std::string value = it->get();
      if (!value.empty()) {
        return value;
      }
    }
  }
  return std::nullopt;
}

} // namespace

std::string buildTokenSourceRequestJson(const TokenRequestOptions& options) {
  json body = json::object();

  const auto set_optional = [&body](const char* key, const std::optional& value) {
    if (value.has_value() && !value->empty()) {
      body[key] = *value;
    }
  };

  set_optional("room_name", options.room_name);
  set_optional("participant_name", options.participant_name);
  set_optional("participant_identity", options.participant_identity);
  set_optional("participant_metadata", options.participant_metadata);

  if (!options.participant_attributes.empty()) {
    json attributes = json::object();
    for (const auto& [key, value] : options.participant_attributes) {
      if (!key.empty()) {
        attributes[key] = value;
      }
    }
    body["participant_attributes"] = std::move(attributes);
  }

  if (options.agent_name.has_value() || options.agent_metadata.has_value() || options.agent_deployment.has_value()) {
    json agent = json::object();
    if (options.agent_name.has_value() && !options.agent_name->empty()) {
      agent["agent_name"] = *options.agent_name;
    }
    if (options.agent_metadata.has_value() && !options.agent_metadata->empty()) {
      agent["metadata"] = *options.agent_metadata;
    }
    if (options.agent_deployment.has_value() && !options.agent_deployment->empty()) {
      agent["deployment"] = *options.agent_deployment;
    }
    body["room_config"] = json{{"agents", json::array({std::move(agent)})}};
  }

  return body.dump();
}

Result parseTokenSourceResponseJson(const std::string& json_text) {
  // Parse without exceptions: malformed input yields a discarded value, which we
  // treat the same as a response missing the required fields.
  const json parsed = json::parse(json_text, nullptr, /*allow_exceptions=*/false);

  TokenSourceResponse details;

  if (parsed.is_object()) {
    if (const auto server_url = readStringField(parsed, "server_url", "serverUrl")) {
      details.server_url = *server_url;
    }
    if (const auto participant_token = readStringField(parsed, "participant_token", "participantToken")) {
      details.participant_token = *participant_token;
    }
    details.participant_name = readStringField(parsed, "participant_name", "participantName");
    details.room_name = readStringField(parsed, "room_name", "roomName");
  }

  if (details.server_url.empty()) {
    return Result::failure(
        TokenSourceError{"token server response missing server_url"});
  }
  if (details.participant_token.empty()) {
    return Result::failure(
        TokenSourceError{"token server response missing participant_token"});
  }

  return Result::success(std::move(details));
}

} // namespace livekit

Web Proxy Viewer  |  New URL  |  Original Page