Optimize startup, HTTP/SSE streaming, and fix macOS libedit bindings
This commit is contained in:
+47
-42
@@ -1,5 +1,6 @@
|
||||
/* session.cpp — session persistence, loading, compaction. */
|
||||
#include "bantam.hpp"
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
@@ -24,6 +25,29 @@ static std::string sessions_dir() {
|
||||
return d;
|
||||
}
|
||||
|
||||
static bool load_session_file(const std::string &full, Session &s) {
|
||||
std::string buf;
|
||||
if (!read_file_str(full, buf)) return false;
|
||||
Json root_mut;
|
||||
if (!Json::parse(buf, root_mut) || !root_mut.is_object()) return false;
|
||||
const Json &root = root_mut;
|
||||
s = Session{};
|
||||
s.id = root["id"].str();
|
||||
s.created = root["created"].str();
|
||||
s.summary = root["summary"].str();
|
||||
const Json &marr = root["messages"];
|
||||
if (marr.is_array()) {
|
||||
s.messages.items.reserve(marr.aval.size());
|
||||
for (auto &mo : marr.aval) {
|
||||
Message m;
|
||||
parse_message_json(mo, m);
|
||||
s.messages.items.push_back(std::move(m));
|
||||
}
|
||||
}
|
||||
if (s.summary.empty()) s.summary = "(no summary)";
|
||||
return true;
|
||||
}
|
||||
|
||||
void save_session(const Messages &msgs, std::string_view sid,
|
||||
std::string *out_id, std::string *out_summary) {
|
||||
std::string id = (!sid.empty()) ? std::string(sid) : project_id();
|
||||
@@ -40,6 +64,7 @@ void save_session(const Messages &msgs, std::string_view sid,
|
||||
std::string sum = summary_of(msgs);
|
||||
root["summary"] = sum;
|
||||
Json arr = Json::array();
|
||||
arr.aval.reserve(msgs.items.size());
|
||||
for (auto &m : msgs.items) {
|
||||
Json mo;
|
||||
serialize_message_json(mo, m);
|
||||
@@ -63,63 +88,46 @@ std::vector<Session> sessions_load() {
|
||||
std::string nm = de->d_name;
|
||||
if (nm == "." || nm == "..") continue;
|
||||
if (nm.size() < 5 || nm.substr(nm.size() - 5) != ".json") continue;
|
||||
files.push_back(nm);
|
||||
files.push_back(std::move(nm));
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
}
|
||||
for (size_t i = 1; i < files.size(); i++) {
|
||||
for (size_t j = i; j > 0 && files[j - 1] > files[j]; j--) {
|
||||
std::swap(files[j - 1], files[j]);
|
||||
}
|
||||
}
|
||||
std::sort(files.begin(), files.end());
|
||||
ss.reserve(files.size());
|
||||
for (auto &nm : files) {
|
||||
std::string full = d + "/" + nm;
|
||||
std::string buf;
|
||||
if (!read_file_str(full, buf)) continue;
|
||||
Json root_mut;
|
||||
if (!Json::parse(buf, root_mut) || !root_mut.is_object()) continue;
|
||||
const Json &root = root_mut;
|
||||
Session s;
|
||||
s.id = root["id"].str();
|
||||
s.created = root["created"].str();
|
||||
s.summary = root["summary"].str();
|
||||
const Json &marr = root["messages"];
|
||||
if (marr.is_array()) {
|
||||
for (auto &mo : marr.aval) {
|
||||
Message m;
|
||||
parse_message_json(mo, m);
|
||||
s.messages.items.push_back(std::move(m));
|
||||
}
|
||||
if (load_session_file(full, s)) {
|
||||
ss.push_back(std::move(s));
|
||||
}
|
||||
if (s.summary.empty()) s.summary = "(no summary)";
|
||||
ss.push_back(std::move(s));
|
||||
}
|
||||
/* sort by id descending (newest first) */
|
||||
for (size_t i = 1; i < ss.size(); i++) {
|
||||
for (size_t j = i; j > 0 && ss[j - 1].id < ss[j].id; j--) {
|
||||
std::swap(ss[j - 1], ss[j]);
|
||||
}
|
||||
}
|
||||
std::sort(ss.begin(), ss.end(), [](const Session &a, const Session &b) {
|
||||
return a.id > b.id;
|
||||
});
|
||||
return ss;
|
||||
}
|
||||
|
||||
std::unique_ptr<Messages> load_session(std::string_view sid, std::string *err) {
|
||||
if (!sid.empty() && sid.find('/') == std::string_view::npos) {
|
||||
std::string exact = sessions_dir() + "/" + std::string(sid) + ".json";
|
||||
Session s;
|
||||
if (load_session_file(exact, s) && s.id == sid) {
|
||||
return std::make_unique<Messages>(std::move(s.messages));
|
||||
}
|
||||
}
|
||||
auto ss = sessions_load();
|
||||
for (auto &s : ss) {
|
||||
if (s.id == sid) {
|
||||
auto res = std::make_unique<Messages>();
|
||||
for (auto &m : s.messages.items) res->items.push_back(m);
|
||||
return res;
|
||||
return std::make_unique<Messages>(std::move(s.messages));
|
||||
}
|
||||
}
|
||||
/* prefix match */
|
||||
std::vector<Session *> pref;
|
||||
for (auto &s : ss) if (s.id.rfind(sid, 0) == 0) pref.push_back(&s);
|
||||
for (auto &s : ss) if (s.id.starts_with(sid)) pref.push_back(&s);
|
||||
if (pref.size() == 1) {
|
||||
auto res = std::make_unique<Messages>();
|
||||
for (auto &m : pref[0]->messages.items) res->items.push_back(m);
|
||||
return res;
|
||||
return std::make_unique<Messages>(std::move(pref[0]->messages));
|
||||
}
|
||||
if (pref.size() > 1) {
|
||||
std::string names;
|
||||
@@ -134,13 +142,10 @@ std::unique_ptr<Messages> load_session(std::string_view sid, std::string *err) {
|
||||
|
||||
std::unique_ptr<Session> find_project_session() {
|
||||
std::string pid = project_id();
|
||||
auto ss = sessions_load();
|
||||
for (auto &s : ss) {
|
||||
if (s.id == pid) {
|
||||
auto found = std::make_unique<Session>();
|
||||
*found = std::move(s);
|
||||
return found;
|
||||
}
|
||||
std::string path = sessions_dir() + "/" + pid + ".json";
|
||||
auto found = std::make_unique<Session>();
|
||||
if (load_session_file(path, *found) && found->id == pid) {
|
||||
return found;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user