Skip to content

Commit

Permalink
Add the apikey, and use the RAII pattern for curl
Browse files Browse the repository at this point in the history
  • Loading branch information
opsnlops committed Jun 2, 2024
1 parent fcb794a commit b14b093
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 19 deletions.
4 changes: 1 addition & 3 deletions lib/CreatureVoicesLib/src/CreatureVoices.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,12 @@ namespace creatures::voice {
debug("Fetching available voices");

auto curlHandle = createCurlHandle(url);
auto res = performRequest(curlHandle, HttpMethod::GET, "");
auto res = performRequest(curlHandle, apiKey, HttpMethod::GET, "");
if(!res.isSuccess()) {
auto error = res.getError();
std::string errorMessage = fmt::format("Failed to fetch available voices: {}", error->getMessage());
curl_easy_cleanup(curlHandle.get());
return VoiceResult<std::vector<Voice>>{VoiceError(error->getCode(), error->getMessage())};
}
curl_easy_cleanup(curlHandle.get());

auto httpResponse = res.getValue().value();
trace("httpResponse was: {}", httpResponse);
Expand Down
25 changes: 11 additions & 14 deletions lib/CreatureVoicesLib/src/CurlBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namespace creatures::voice {
}

VoiceResult<std::string> CurlBase::performRequest(CurlHandle& curlHandle,
const std::string& apiKey,
HttpMethod method,
const std::string& data) {

Expand All @@ -43,6 +44,11 @@ namespace creatures::voice {
return VoiceResult<std::string>{VoiceError(VoiceError::InternalError, errorMessage)};
}

// Set headers
std::string apiKeyHeader = fmt::format("xi-api-key: {}", apiKey);
curlHandle.addHeader(apiKeyHeader);
curlHandle.addHeader("Content-Type: application/json");

curl_easy_setopt(curlHandle.get(), CURLOPT_WRITEDATA, &response);
trace("CURL handle set up for writing");

Expand All @@ -64,7 +70,6 @@ namespace creatures::voice {
default:
errorMessage = fmt::format("Unknown HTTP method: {}", httpMethodToString(method));
error(errorMessage);
curl_easy_cleanup(curlHandle.get());
return VoiceResult<std::string>{VoiceError(VoiceError::InternalError, errorMessage)};
}

Expand All @@ -73,7 +78,6 @@ namespace creatures::voice {
if (res != CURLE_OK) {
errorMessage = fmt::format("CURL request failed: {}", curl_easy_strerror(res));
error(errorMessage);
curl_easy_cleanup(curlHandle.get());
return VoiceResult<std::string>{VoiceError(VoiceError::InternalError, errorMessage)};
}

Expand All @@ -89,39 +93,32 @@ namespace creatures::voice {
break;
case 301:
case 302:
errorMessage = fmt::format("HTTP error: {} - redirect", http_code);
errorMessage = fmt::format("11labs API error: {} - redirect", http_code);
warn(errorMessage);
curl_easy_cleanup(curlHandle.get());
return VoiceResult<std::string>{VoiceError(VoiceError::InvalidData, errorMessage)};
case 400:
errorMessage = fmt::format("HTTP error: {} - bad request", http_code);
errorMessage = fmt::format("11labs API error: {} - bad request", http_code);
warn(errorMessage);
curl_easy_cleanup(curlHandle.get());
return VoiceResult<std::string>{VoiceError(VoiceError::InvalidData, errorMessage)};
case 401:
case 403:
errorMessage = fmt::format("HTTP error: {} - unauthorized", http_code);
errorMessage = fmt::format("11labs API error: {} - unauthorized (make sure the server has a good apiKey!)", http_code);
warn(errorMessage);
curl_easy_cleanup(curlHandle.get());
return VoiceResult<std::string>{VoiceError(VoiceError::InvalidApiKey, errorMessage)};
case 404:
errorMessage = fmt::format("HTTP error: {} - not found", http_code);
errorMessage = fmt::format("11labs API error: {} - not found", http_code);
warn(errorMessage);
curl_easy_cleanup(curlHandle.get());
return VoiceResult<std::string>{VoiceError(VoiceError::NotFound, errorMessage)};

// Map everything else to an error
default:
errorMessage = fmt::format("HTTP error: {}", http_code);
errorMessage = fmt::format("11labs API error: {} ({})", http_code, response);
error(errorMessage);
curl_easy_cleanup(curlHandle.get());
return VoiceResult<std::string>{VoiceError(VoiceError::InternalError, errorMessage)};
}


// Looks good! We have good data
curl_easy_cleanup(curlHandle.get());

debug("request successful!");
return VoiceResult<std::string>{response};
}
Expand Down
3 changes: 2 additions & 1 deletion lib/CreatureVoicesLib/src/CurlBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ namespace creatures :: voice {

protected:
CurlHandle createCurlHandle(const std::string& url);
VoiceResult<std::string> performRequest(CurlHandle& curlHandle, HttpMethod method, const std::string& data);
VoiceResult<std::string> performRequest(CurlHandle& curlHandle, const std::string& apiKey,
HttpMethod method, const std::string& data);
static size_t WriteCallback(char* ptr, size_t size, size_t nmemb, std::string* data);
};

Expand Down
31 changes: 31 additions & 0 deletions lib/CreatureVoicesLib/src/CurlHandle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,44 @@ namespace creatures :: voice {
if (curl) {
curl_easy_cleanup(curl);
}
if (headers) {
curl_slist_free_all(headers);
}
spdlog::trace("CurlHandle destroyed");
}


CurlHandle::CurlHandle(CurlHandle&& other) noexcept : curl(other.curl), headers(other.headers) {
other.curl = nullptr;
other.headers = nullptr;
}

CurlHandle& CurlHandle::operator=(CurlHandle&& other) noexcept {
if (this != &other) {
if (curl) {
curl_easy_cleanup(curl);
}
if (headers) {
curl_slist_free_all(headers);
}
spdlog::trace("CurlHandle destroyed via move assignment");
curl = other.curl;
headers = other.headers;
other.curl = nullptr;
other.headers = nullptr;
}
return *this;
}

CURL* CurlHandle::get() const {
return curl;
}

void CurlHandle::addHeader(const std::string& header) {
headers = curl_slist_append(headers, header.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
}

size_t CurlHandle::WriteCallback(char* ptr, size_t size, size_t nmemb, std::string* data) {
data->append(ptr, size * nmemb);
return size * nmemb;
Expand Down
9 changes: 8 additions & 1 deletion lib/CreatureVoicesLib/src/CurlHandle.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,23 @@ namespace creatures :: voice {
public:
CurlHandle(const std::string& url);
~CurlHandle();
//CurlHandle(CurlHandle&& other) noexcept;

// Allow move semantics
CurlHandle(CurlHandle&& other) noexcept;

// Delete copy constructor and copy assignment to avoid double cleanup
CurlHandle(const CurlHandle&) = delete;
CurlHandle& operator=(const CurlHandle&) = delete;

CurlHandle& operator=(CurlHandle&& other) noexcept;

CURL* get() const;

void addHeader(const std::string& header);

private:
CURL* curl = nullptr;
struct curl_slist* headers = nullptr;
static size_t WriteCallback(char* ptr, size_t size, size_t nmemb, std::string* data);

};
Expand Down

0 comments on commit b14b093

Please sign in to comment.