4#include <condition_variable>
8#include "absl/strings/str_cat.h"
9#include "absl/strings/str_format.h"
10#include "absl/time/clock.h"
11#include "absl/time/time.h"
14#include "nlohmann/json.hpp"
15#if !defined(_WIN32) && !defined(YAZE_IOS)
16#define CPPHTTPLIB_OPENSSL_SUPPORT
36class Z3edNetworkClient::Impl {
38 Impl() : connected_(false), in_session_(false) {}
42 absl::Status
Connect(
const std::string& host,
int port) {
43 std::lock_guard<std::mutex> lock(mutex_);
46 return absl::AlreadyExistsError(
"Already connected");
54 client_ = std::make_unique<httplib::Client>(host, port);
55 client_->set_connection_timeout(5, 0);
56 client_->set_read_timeout(30, 0);
59 auto res = client_->Get(
"/health");
60 if (!res || res->status != 200) {
61 return absl::UnavailableError(
"Server not responding");
65 return absl::OkStatus();
67 }
catch (
const std::exception& e) {
68 return absl::UnavailableError(
69 absl::StrCat(
"Connection failed: ", e.what()));
74 std::lock_guard<std::mutex> lock(mutex_);
80 absl::Status
JoinSession(
const std::string& session_code,
81 const std::string& username) {
82 std::lock_guard<std::mutex> lock(mutex_);
85 return absl::FailedPreconditionError(
"Not connected");
89 nlohmann::json message = {
90 {
"type",
"join_session"},
92 {{
"session_code", session_code}, {
"username", username}}}};
94 auto res = client_->Post(
"/message", message.dump(),
"application/json");
96 if (!res || res->status != 200) {
97 return absl::InternalError(
"Failed to join session");
101 session_code_ = session_code;
102 username_ = username;
104 return absl::OkStatus();
106 }
catch (
const std::exception& e) {
107 return absl::InternalError(absl::StrCat(
"Join failed: ", e.what()));
112 const std::string& proposal_json,
113 const std::string& username) {
114 std::lock_guard<std::mutex> lock(mutex_);
116 if (!connected_ || !in_session_) {
117 return absl::FailedPreconditionError(
"Not in a session");
121 nlohmann::json proposal_data = nlohmann::json::parse(proposal_json);
124 nlohmann::json message = {
125 {
"type",
"proposal_share"},
127 {{
"sender", username}, {
"proposal_data", proposal_data}}}};
129 auto res = client_->Post(
"/message", message.dump(),
"application/json");
131 if (!res || res->status != 200) {
132 return absl::InternalError(
"Failed to submit proposal");
136 if (!res->body.empty()) {
138 auto response_json = nlohmann::json::parse(res->body);
139 if (response_json.contains(
"proposal_id")) {
140 last_proposal_id_ = response_json[
"proposal_id"];
147 return absl::OkStatus();
149 }
catch (
const std::exception& e) {
150 return absl::InternalError(
151 absl::StrCat(
"Proposal submission failed: ", e.what()));
156 const std::string& proposal_id) {
157 std::lock_guard<std::mutex> lock(mutex_);
160 return absl::FailedPreconditionError(
"Not connected");
165 auto res = client_->Get(
166 absl::StrFormat(
"/proposal/%s/status", proposal_id).c_str());
168 if (!res || res->status != 200) {
169 return absl::NotFoundError(
"Proposal not found");
172 auto response = nlohmann::json::parse(res->body);
173 return response[
"status"].get<std::string>();
175 }
catch (
const std::exception& e) {
176 return absl::InternalError(
177 absl::StrCat(
"Status check failed: ", e.what()));
182 int timeout_seconds) {
183 auto deadline = absl::Now() + absl::Seconds(timeout_seconds);
185 while (absl::Now() < deadline) {
188 if (!status_result.ok()) {
189 return status_result.status();
192 std::string status = *status_result;
194 if (status ==
"approved" || status ==
"applied") {
196 }
else if (status ==
"rejected") {
201 absl::SleepFor(absl::Seconds(1));
204 return absl::DeadlineExceededError(
"Approval timeout");
207 absl::Status
SendMessage(
const std::string& message,
208 const std::string& sender) {
209 std::lock_guard<std::mutex> lock(mutex_);
211 if (!connected_ || !in_session_) {
212 return absl::FailedPreconditionError(
"Not in a session");
216 nlohmann::json msg = {
217 {
"type",
"chat_message"},
218 {
"payload", {{
"message", message}, {
"sender", sender}}}};
220 auto res = client_->Post(
"/message", msg.dump(),
"application/json");
222 if (!res || res->status != 200) {
223 return absl::InternalError(
"Failed to send message");
226 return absl::OkStatus();
228 }
catch (
const std::exception& e) {
229 return absl::InternalError(absl::StrCat(
"Send failed: ", e.what()));
233 absl::StatusOr<std::string>
QueryAI(
const std::string& query,
234 const std::string& username) {
235 std::lock_guard<std::mutex> lock(mutex_);
237 if (!connected_ || !in_session_) {
238 return absl::FailedPreconditionError(
"Not in a session");
242 nlohmann::json message = {
243 {
"type",
"ai_query"},
244 {
"payload", {{
"query", query}, {
"username", username}}}};
246 auto res = client_->Post(
"/message", message.dump(),
"application/json");
248 if (!res || res->status != 200) {
249 return absl::InternalError(
"AI query failed");
254 return std::string(
"AI agent endpoint not configured");
256 }
catch (
const std::exception& e) {
257 return absl::InternalError(absl::StrCat(
"AI query failed: ", e.what()));
262 std::lock_guard<std::mutex> lock(mutex_);
267 std::lock_guard<std::mutex> lock(mutex_);
268 return last_proposal_id_;
272 mutable std::mutex mutex_;
273 std::unique_ptr<httplib::Client> client_;
280 std::string session_code_;
281 std::string username_;
282 std::string last_proposal_id_;
290 absl::Status
Connect(
const std::string&,
int) {
291 return absl::UnimplementedError(
"Network support requires JSON library");
294 absl::Status
JoinSession(
const std::string&,
const std::string&) {
295 return absl::UnimplementedError(
"Network support requires JSON library");
298 const std::string&) {
299 return absl::UnimplementedError(
"Network support requires JSON library");
302 return absl::UnimplementedError(
"Network support requires JSON library");
305 return absl::UnimplementedError(
"Network support requires JSON library");
307 absl::Status
SendMessage(
const std::string&,
const std::string&) {
308 return absl::UnimplementedError(
"Network support requires JSON library");
310 absl::StatusOr<std::string>
QueryAI(
const std::string&,
const std::string&) {
311 return absl::UnimplementedError(
"Network support requires JSON library");
328 return impl_->Connect(host, port);
332 const std::string& username) {
333 return impl_->JoinSession(session_code, username);
337 const std::string& proposal_json,
338 const std::string& username) {
339 return impl_->SubmitProposal(description, proposal_json, username);
343 const std::string& proposal_id) {
344 return impl_->GetProposalStatus(proposal_id);
348 const std::string& proposal_id,
int timeout_seconds) {
349 return impl_->WaitForApproval(proposal_id, timeout_seconds);
353 const std::string& sender) {
354 return impl_->SendMessage(message, sender);
358 const std::string& query,
const std::string& username) {
359 return impl_->QueryAI(query, username);
367 return impl_->IsConnected();
absl::Status SendMessage(const std::string &, const std::string &)
absl::Status Connect(const std::string &, int)
absl::StatusOr< bool > WaitForApproval(const std::string &, int)
absl::Status JoinSession(const std::string &, const std::string &)
absl::StatusOr< std::string > GetProposalStatus(const std::string &)
absl::Status SubmitProposal(const std::string &, const std::string &, const std::string &)
absl::StatusOr< std::string > QueryAI(const std::string &, const std::string &)
std::string GetLastProposalId() const
absl::StatusOr< bool > WaitForApproval(const std::string &proposal_id, int timeout_seconds=60)
absl::Status SendMessage(const std::string &message, const std::string &sender)
std::unique_ptr< Impl > impl_
absl::Status JoinSession(const std::string &session_code, const std::string &username)
absl::StatusOr< std::string > QueryAI(const std::string &query, const std::string &username)
absl::Status Connect(const std::string &host, int port=8765)
absl::StatusOr< std::string > GetProposalStatus(const std::string &proposal_id)
absl::Status SubmitProposal(const std::string &description, const std::string &proposal_json, const std::string &username)