This commit is contained in:
parent
10e26e8a6c
commit
ede75f5565
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"cmake.sourceDirectory": "/home/j/code/dropshell-build/ipdemo"
|
||||||
|
}
|
16
CLAUDE.md
16
CLAUDE.md
@ -115,3 +115,19 @@ Applications can use:
|
|||||||
- SQLite3 at `/usr/local/sqlite3/`
|
- SQLite3 at `/usr/local/sqlite3/`
|
||||||
|
|
||||||
All database libraries are statically linked into the final binary.
|
All database libraries are statically linked into the final binary.
|
||||||
|
|
||||||
|
### HTTP Client Utilities
|
||||||
|
|
||||||
|
The ipdemo includes a blocking HTTP client utility (`src/http_utils.hpp`) that wraps Drogon's asynchronous HttpClient:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include "http_utils.hpp"
|
||||||
|
|
||||||
|
// Make a blocking HTTP GET request
|
||||||
|
auto response = http_get("example.com", "/api/endpoint", true, 10.0); // HTTPS with 10s timeout
|
||||||
|
if (response.success && response.status_code == 200) {
|
||||||
|
std::cout << response.body << std::endl;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This utility handles the threading complexity and provides a simple synchronous interface for HTTP requests.
|
@ -112,15 +112,9 @@ set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH}
|
|||||||
set(JSONCPP_INCLUDE_DIRS /usr/local/jsoncpp/include)
|
set(JSONCPP_INCLUDE_DIRS /usr/local/jsoncpp/include)
|
||||||
set(JSONCPP_LIBRARIES /usr/local/jsoncpp/lib/libjsoncpp.a)
|
set(JSONCPP_LIBRARIES /usr/local/jsoncpp/lib/libjsoncpp.a)
|
||||||
|
|
||||||
##########
|
|
||||||
# If you include the drogon source code locally in your project, use this method to add drogon
|
|
||||||
# add_subdirectory(external/drogon)
|
|
||||||
# target_link_libraries(${PROJECT_NAME} PRIVATE drogon)
|
|
||||||
##########
|
|
||||||
find_package(Drogon CONFIG REQUIRED)
|
find_package(Drogon CONFIG REQUIRED)
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE Drogon::Drogon)
|
target_link_libraries(${PROJECT_NAME} PRIVATE Drogon::Drogon)
|
||||||
|
|
||||||
|
|
||||||
# Additional PostgreSQL libraries needed for static linking
|
# Additional PostgreSQL libraries needed for static linking
|
||||||
set(POSTGRESQL_EXTRA_LIBS
|
set(POSTGRESQL_EXTRA_LIBS
|
||||||
/usr/local/pgsql/lib/libpgcommon.a
|
/usr/local/pgsql/lib/libpgcommon.a
|
||||||
|
48
ipdemo/src/http_utils.cpp
Normal file
48
ipdemo/src/http_utils.cpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include "http_utils.hpp"
|
||||||
|
|
||||||
|
HttpResponse http_get(const std::string& url, const std::string& path, bool use_https, double timeout_seconds) {
|
||||||
|
HttpResponse result{0, "", false};
|
||||||
|
bool done = false;
|
||||||
|
std::mutex mtx;
|
||||||
|
std::condition_variable cv;
|
||||||
|
|
||||||
|
std::thread worker([&]() {
|
||||||
|
trantor::EventLoop loop;
|
||||||
|
|
||||||
|
auto client = drogon::HttpClient::newHttpClient(
|
||||||
|
(use_https ? "https://" : "http://") + url,
|
||||||
|
&loop
|
||||||
|
);
|
||||||
|
|
||||||
|
auto req = drogon::HttpRequest::newHttpRequest();
|
||||||
|
req->setMethod(drogon::Get);
|
||||||
|
req->setPath(path);
|
||||||
|
|
||||||
|
client->sendRequest(req, [&](drogon::ReqResult res, const drogon::HttpResponsePtr &resp) {
|
||||||
|
std::lock_guard<std::mutex> lock(mtx);
|
||||||
|
if (res == drogon::ReqResult::Ok && resp) {
|
||||||
|
result.status_code = resp->statusCode();
|
||||||
|
result.body = resp->body();
|
||||||
|
result.success = true;
|
||||||
|
} else {
|
||||||
|
result.status_code = 0;
|
||||||
|
result.body = "";
|
||||||
|
result.success = false;
|
||||||
|
}
|
||||||
|
done = true;
|
||||||
|
cv.notify_one();
|
||||||
|
loop.quit();
|
||||||
|
}, timeout_seconds);
|
||||||
|
|
||||||
|
loop.loop();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wait for completion
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mtx);
|
||||||
|
cv.wait(lock, [&] { return done; });
|
||||||
|
}
|
||||||
|
|
||||||
|
worker.join();
|
||||||
|
return result;
|
||||||
|
}
|
17
ipdemo/src/http_utils.hpp
Normal file
17
ipdemo/src/http_utils.hpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <drogon/HttpClient.h>
|
||||||
|
#include <trantor/net/EventLoop.h>
|
||||||
|
|
||||||
|
struct HttpResponse {
|
||||||
|
int status_code;
|
||||||
|
std::string body;
|
||||||
|
bool success;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Utility function for blocking HTTP GET requests
|
||||||
|
HttpResponse http_get(const std::string& url, const std::string& path, bool use_https = false, double timeout_seconds = 10.0);
|
@ -1,12 +1,9 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
|
||||||
#include <thread>
|
|
||||||
#include <chrono>
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#include <drogon/drogon.h>
|
|
||||||
#include "version.hpp"
|
#include "version.hpp"
|
||||||
#include "assert.hpp"
|
#include "assert.hpp"
|
||||||
|
#include "http_utils.hpp"
|
||||||
|
|
||||||
void crashy() {
|
void crashy() {
|
||||||
ASSERT(false, "SUCCESS!");
|
ASSERT(false, "SUCCESS!");
|
||||||
@ -17,42 +14,14 @@ int main() {
|
|||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
std::cout << "Retrieving IP address..." << std::endl;
|
std::cout << "Retrieving IP address..." << std::endl;
|
||||||
|
|
||||||
// Initialize drogon app but don't run it
|
// Use the utility function for HTTP GET
|
||||||
drogon::app().setLogLevel(trantor::Logger::kError);
|
auto response = http_get("ipinfo.io", "/ip", false, 10.0);
|
||||||
|
|
||||||
std::string ip_body;
|
ASSERT(response.success && response.status_code == 200, "Failed to get IP");
|
||||||
int status = 0;
|
|
||||||
bool done = false;
|
|
||||||
|
|
||||||
// Run in a separate thread to avoid event loop conflicts
|
|
||||||
std::thread worker([&]() {
|
|
||||||
trantor::EventLoop loop;
|
|
||||||
auto client = drogon::HttpClient::newHttpClient("http://ipinfo.io", &loop);
|
|
||||||
auto req = drogon::HttpRequest::newHttpRequest();
|
|
||||||
req->setMethod(drogon::Get);
|
|
||||||
req->setPath("/ip");
|
|
||||||
|
|
||||||
client->sendRequest(req, [&](drogon::ReqResult result, const drogon::HttpResponsePtr &resp) {
|
|
||||||
if (result == drogon::ReqResult::Ok && resp) {
|
|
||||||
ip_body = resp->body();
|
|
||||||
status = resp->statusCode();
|
|
||||||
} else {
|
|
||||||
status = 0;
|
|
||||||
}
|
|
||||||
done = true;
|
|
||||||
loop.quit();
|
|
||||||
});
|
|
||||||
|
|
||||||
loop.loop();
|
|
||||||
});
|
|
||||||
|
|
||||||
worker.join();
|
|
||||||
|
|
||||||
ASSERT(status == 200, "Failed to get IP");
|
|
||||||
|
|
||||||
nlohmann::json j;
|
nlohmann::json j;
|
||||||
j["ip"] = ip_body;
|
j["ip"] = response.body;
|
||||||
j["status"] = status;
|
j["status"] = response.status_code;
|
||||||
|
|
||||||
std::cout << j.dump(4) << std::endl;
|
std::cout << j.dump(4) << std::endl;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user