132 lines
3.8 KiB
C++
132 lines
3.8 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);
|
|
|
|
// 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 Error {
|
|
ERR_NONE,
|
|
ERR_OPEN_LOGFILE,
|
|
ERR_LOGFILE_EOF,
|
|
ERR_LOGFILE_CORRUPT,
|
|
ERR_NONDERMINISTIC,
|
|
ERR_CREATE_ENGINE,
|
|
};
|
|
private:
|
|
std::ifstream f_;
|
|
UniqueDrivenEngine e_;
|
|
std::unique_ptr<char[]> buf_;
|
|
Error error_;
|
|
std::string logfn_;
|
|
std::string engine_;
|
|
|
|
void set_error(Error e);
|
|
|
|
void create_engine();
|
|
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 an error code, which is usually ERR_NONE.
|
|
// If it's anything else, display an error and stop.
|
|
//
|
|
Error step();
|
|
|
|
// Print an error message.
|
|
//
|
|
// Print a message associated with the most recent error.
|
|
//
|
|
void print_error(std::ostream &s);
|
|
};
|
|
|
|
} // namespace drv
|
|
|
|
#endif // DRIVER_UTIL_HPP
|