Step 230: Enhance session recorder
This commit is contained in:
@@ -12,19 +12,44 @@ using json = nlohmann::json;
|
||||
|
||||
class WorkflowRecorder {
|
||||
public:
|
||||
struct RecordingConfig {
|
||||
bool recordAllSessions = false;
|
||||
bool recordControlMethods = false;
|
||||
bool recordEditorEvents = true;
|
||||
bool autoRecording = false;
|
||||
};
|
||||
|
||||
struct WorkflowCall {
|
||||
json request;
|
||||
json response;
|
||||
std::string timestamp;
|
||||
std::string sessionId;
|
||||
std::string method;
|
||||
};
|
||||
|
||||
struct WorkflowEvent {
|
||||
std::string type;
|
||||
json payload;
|
||||
std::string timestamp;
|
||||
};
|
||||
|
||||
void startRecording(const std::string& name, const std::string& sessionId) {
|
||||
startRecording(name, sessionId, RecordingConfig{}, json::object());
|
||||
}
|
||||
|
||||
void startRecording(const std::string& name,
|
||||
const std::string& sessionId,
|
||||
const RecordingConfig& config,
|
||||
const json& metadata) {
|
||||
name_ = name.empty() ? "workflow" : name;
|
||||
sessionId_ = sessionId;
|
||||
calls_.clear();
|
||||
events_.clear();
|
||||
recording_ = true;
|
||||
createdAt_ = currentTimestamp();
|
||||
stoppedAt_.clear();
|
||||
config_ = config;
|
||||
metadata_ = metadata;
|
||||
}
|
||||
|
||||
json stopRecording() {
|
||||
@@ -37,36 +62,60 @@ public:
|
||||
bool isReplaying() const { return replaying_; }
|
||||
|
||||
void setReplaying(bool replaying) { replaying_ = replaying; }
|
||||
bool isAutoRecording() const { return config_.autoRecording; }
|
||||
|
||||
void record(const std::string& sessionId,
|
||||
const json& request,
|
||||
const json& response) {
|
||||
if (!recording_ || replaying_) return;
|
||||
if (!sessionId_.empty() && sessionId != sessionId_) return;
|
||||
if (!config_.recordAllSessions && !sessionId_.empty() && sessionId != sessionId_) return;
|
||||
std::string method = request.value("method", "");
|
||||
if (isControlMethod(method)) return;
|
||||
if (!config_.recordControlMethods && isControlMethod(method)) return;
|
||||
WorkflowCall call;
|
||||
call.request = request;
|
||||
call.response = response;
|
||||
call.timestamp = currentTimestamp();
|
||||
call.sessionId = sessionId;
|
||||
call.method = method;
|
||||
calls_.push_back(std::move(call));
|
||||
}
|
||||
|
||||
void recordEvent(const std::string& type, const json& payload) {
|
||||
if (!recording_ || replaying_ || !config_.recordEditorEvents) return;
|
||||
WorkflowEvent ev;
|
||||
ev.type = type;
|
||||
ev.payload = payload;
|
||||
ev.timestamp = currentTimestamp();
|
||||
events_.push_back(std::move(ev));
|
||||
}
|
||||
|
||||
json exportWorkflow() const {
|
||||
json out;
|
||||
out["name"] = name_;
|
||||
out["sessionId"] = sessionId_;
|
||||
out["createdAt"] = createdAt_;
|
||||
out["stoppedAt"] = stoppedAt_;
|
||||
out["metadata"] = metadata_;
|
||||
json arr = json::array();
|
||||
for (const auto& c : calls_) {
|
||||
arr.push_back({
|
||||
{"timestamp", c.timestamp},
|
||||
{"sessionId", c.sessionId},
|
||||
{"method", c.method},
|
||||
{"request", c.request},
|
||||
{"response", c.response}
|
||||
});
|
||||
}
|
||||
out["calls"] = arr;
|
||||
json events = json::array();
|
||||
for (const auto& e : events_) {
|
||||
events.push_back({
|
||||
{"timestamp", e.timestamp},
|
||||
{"type", e.type},
|
||||
{"payload", e.payload}
|
||||
});
|
||||
}
|
||||
out["events"] = events;
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -76,14 +125,27 @@ public:
|
||||
sessionId_ = workflow.value("sessionId", "");
|
||||
createdAt_ = workflow.value("createdAt", "");
|
||||
stoppedAt_ = workflow.value("stoppedAt", "");
|
||||
metadata_ = workflow.value("metadata", json::object());
|
||||
calls_.clear();
|
||||
for (const auto& c : workflow["calls"]) {
|
||||
WorkflowCall call;
|
||||
call.timestamp = c.value("timestamp", "");
|
||||
call.sessionId = c.value("sessionId", "");
|
||||
call.method = c.value("method", "");
|
||||
call.request = c.value("request", json::object());
|
||||
call.response = c.value("response", json::object());
|
||||
calls_.push_back(std::move(call));
|
||||
}
|
||||
events_.clear();
|
||||
if (workflow.contains("events") && workflow["events"].is_array()) {
|
||||
for (const auto& e : workflow["events"]) {
|
||||
WorkflowEvent ev;
|
||||
ev.timestamp = e.value("timestamp", "");
|
||||
ev.type = e.value("type", "");
|
||||
ev.payload = e.value("payload", json::object());
|
||||
events_.push_back(std::move(ev));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -105,12 +167,17 @@ public:
|
||||
createdAt_.clear();
|
||||
stoppedAt_.clear();
|
||||
calls_.clear();
|
||||
events_.clear();
|
||||
metadata_.clear();
|
||||
recording_ = false;
|
||||
config_ = RecordingConfig{};
|
||||
}
|
||||
|
||||
private:
|
||||
static std::string currentTimestamp() {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
now.time_since_epoch()) % 1000;
|
||||
std::time_t tt = std::chrono::system_clock::to_time_t(now);
|
||||
std::tm tm{};
|
||||
#ifdef _WIN32
|
||||
@@ -119,7 +186,8 @@ private:
|
||||
localtime_r(&tt, &tm);
|
||||
#endif
|
||||
std::ostringstream oss;
|
||||
oss << std::put_time(&tm, "%H:%M:%S");
|
||||
oss << std::put_time(&tm, "%Y-%m-%dT%H:%M:%S")
|
||||
<< '.' << std::setw(3) << std::setfill('0') << ms.count();
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
@@ -134,7 +202,10 @@ private:
|
||||
std::string sessionId_;
|
||||
std::string createdAt_;
|
||||
std::string stoppedAt_;
|
||||
json metadata_;
|
||||
std::vector<WorkflowCall> calls_;
|
||||
std::vector<WorkflowEvent> events_;
|
||||
bool recording_ = false;
|
||||
bool replaying_ = false;
|
||||
RecordingConfig config_;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user