Files
integration/luprex/core/cpp/driver-util.hpp

139 lines
4.0 KiB
C++

#ifndef DRIVER_UTIL_HPP
#define DRIVER_UTIL_HPP
#include "wrap-string.hpp"
#include "wrap-vector.hpp"
#include <string_view>
#include <fstream>
#include <ostream>
#include "drivenengine.hpp"
namespace drv {
void split_host_port(std::string_view target, std::string &host, std::string &port);
std::vector<std::string> parse_control_lst(std::string_view ctrl);
class ReplayRecorder {
private:
std::ofstream f_;
UniqueDrivenEngine e_;
bool logging_;
void flush();
public:
// Initialization consists of three steps:
//
// 1. The constructor, which creates an empty ReplayRecorder.
// 2. Open the logfile for writing, if desired, using open_logfile.
// 3. Make the engine, using create_engine.
//
// After that, you can use drv_xxx methods to send messages to the
// engine. These messages will get logged if the replay log is open.
//
ReplayRecorder() : logging_(false) {}
// Open the logfile.
//
// If you're going to open a logfile, you must do so before
// creating the engine. Returns false if the logfile couldn't be
// opened.
//
bool open_logfile(const char *fn);
// Create the DrivenEngine.
//
// Returns false if the DrivenEngine couldn't be created.
//
bool create_engine(const char *kind);
// Report to the logger that the engine is about to exit cleanly,
// without any error.
//
void clean_exit();
// These don't need to be logged.
//
const eng::vector<int> &drv_get_listen_ports() const { return e_->drv_get_listen_ports(); }
const eng::vector<int> &drv_get_new_outgoing() const { return e_->drv_get_new_outgoing(); }
const eng::string &drv_get_target(int chid) const { return e_->drv_get_target(chid); }
bool drv_outgoing_empty(int chid) const { return e_->drv_outgoing_empty(chid); }
bool drv_get_channel_released(int chid) const { return e_->drv_get_channel_released(chid); }
std::string_view drv_peek_outgoing(int chid) const { return e_->drv_peek_outgoing(chid); }
bool drv_get_rescan_lua_source() const { return e_->drv_get_rescan_lua_source(); }
bool drv_get_stop_driver() const { return e_->drv_get_stop_driver(); }
// These operations do need to be logged.
//
void drv_clear_new_outgoing();
void drv_sent_outgoing(int chid, int nbytes);
void drv_recv_incoming(int chid, std::string_view data);
void drv_notify_close(int chid, std::string_view err);
int drv_notify_accept(int port);
void drv_clear_lua_source();
void drv_add_lua_source(std::string_view fn, std::string_view data);
void drv_invoke_event_init(int argc, char *argv[]);
void drv_invoke_event_update(double clock);
};
class ReplayPlayer {
public:
enum Status {
ST_REPLAYING,
ST_CLEAN_EXIT,
ST_ERR_OPENING_LOGFILE,
ST_LOGFILE_ENDS_ABRUPTLY,
ST_LOGFILE_CORRUPT,
ST_NONDERMINISTIC,
ST_COULDNT_CREATE_ENGINE,
};
private:
std::ifstream f_;
UniqueDrivenEngine e_;
std::unique_ptr<char[]> buf_;
Status status_;
std::string logfn_;
std::string engine_;
void set_status(Status e);
void create_engine();
void clean_exit();
void drv_clear_new_outgoing();
void drv_sent_outgoing();
void drv_recv_incoming();
void drv_notify_close();
void drv_notify_accept();
void drv_clear_lua_source();
void drv_add_lua_source();
void drv_invoke_event_init();
void drv_invoke_event_update();
public:
ReplayPlayer();
// Open the logfile for reading.
//
// Returns false if the logfile can't be opened.
//
bool open_logfile(const char *fn);
// Execute a single step from the replay log.
//
// Returns a status code, which is usually ST_REPLAYING.
// If it's anything else, display the status and stop.
//
Status step();
// Print a status message.
//
// Print a message associated with the most recent status report.
//
void print_status(std::ostream &s);
};
} // namespace drv
#endif // DRIVER_UTIL_HPP