88 lines
2.8 KiB
C++
88 lines
2.8 KiB
C++
#include "tui_control.h"
|
|
#include "../llm/proc.h"
|
|
#include "../llm/py.h"
|
|
#include "text.h"
|
|
#include <cerrno>
|
|
#include <cstring>
|
|
#include <poll.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
#include <unistd.h>
|
|
namespace detz::agent {
|
|
|
|
std::string grr_control_path() {
|
|
std::string home = llm::env_get("TAI_HOME");
|
|
if (home.empty()) { home = expanduser("~") + "/.tai"; }
|
|
std::string sock = llm::env_get("TAI_TUI_SOCK");
|
|
return !sock.empty() ? sock : home + "/tui.sock";
|
|
}
|
|
|
|
json::Value grr_control_call(const json::Value& payload, const std::string& path_in, double timeout) {
|
|
std::string path = path_in.empty() ? grr_control_path() : path_in;
|
|
auto failure = [&](const std::string& what) {
|
|
json::Value o = json::Value::object();
|
|
o.set("state", "error");
|
|
o.set("error", "no running grr TUI answers on " + path + " (" + what + ")");
|
|
return o;
|
|
};
|
|
int fd = ::socket(AF_UNIX, SOCK_STREAM, 0);
|
|
if (fd < 0) { return failure(std::string("[Errno ") + std::to_string(errno) + "] " + std::strerror(errno)); }
|
|
struct sockaddr_un addr{};
|
|
addr.sun_family = AF_UNIX;
|
|
if (path.size() >= sizeof addr.sun_path) {
|
|
::close(fd);
|
|
return failure("AF_UNIX path too long");
|
|
}
|
|
std::memcpy(addr.sun_path, path.c_str(), path.size() + 1);
|
|
if (::connect(fd, reinterpret_cast<sockaddr*>(&addr), sizeof addr) != 0) {
|
|
int err = errno;
|
|
::close(fd);
|
|
return failure("[Errno " + std::to_string(err) + "] " + std::strerror(err));
|
|
}
|
|
std::string line = payload.dumps() + "\n";
|
|
size_t off = 0;
|
|
while (off < line.size()) {
|
|
ssize_t w = ::send(fd, line.data() + off, line.size() - off, MSG_NOSIGNAL);
|
|
if (w < 0) {
|
|
if (errno == EINTR) { continue; }
|
|
int err = errno;
|
|
::close(fd);
|
|
return failure("[Errno " + std::to_string(err) + "] " + std::strerror(err));
|
|
}
|
|
off += static_cast<size_t>(w);
|
|
}
|
|
std::string data;
|
|
while (data.empty() || data.back() != '\n') {
|
|
struct pollfd pfd{fd, POLLIN, 0};
|
|
int pr = ::poll(&pfd, 1, static_cast<int>(timeout * 1000));
|
|
if (pr == 0) { ::close(fd); return failure("timed out"); }
|
|
if (pr < 0) {
|
|
if (errno == EINTR) { continue; }
|
|
int err = errno;
|
|
::close(fd);
|
|
return failure("[Errno " + std::to_string(err) + "] " + std::strerror(err));
|
|
}
|
|
char buf[65536];
|
|
ssize_t c = ::recv(fd, buf, sizeof buf, 0);
|
|
if (c < 0) {
|
|
if (errno == EINTR) { continue; }
|
|
int err = errno;
|
|
::close(fd);
|
|
return failure("[Errno " + std::to_string(err) + "] " + std::strerror(err));
|
|
}
|
|
if (c == 0) { break; }
|
|
data.append(buf, static_cast<size_t>(c));
|
|
}
|
|
::close(fd);
|
|
try {
|
|
return json::Value::loads(py::utf8_replace(data));
|
|
} catch (const json::ParseError&) {
|
|
json::Value o = json::Value::object();
|
|
o.set("state", "error");
|
|
o.set("error", "unreadable reply");
|
|
return o;
|
|
}
|
|
}
|
|
|
|
} // namespace detz::agent
|