#ifndef DRIVER_UTIL_HPP #define DRIVER_UTIL_HPP #include "wrap-string.hpp" #include "wrap-vector.hpp" #include #include #include #include "drivenengine.hpp" namespace drv { void split_host_port(std::string_view target, std::string &host, std::string &port); std::vector 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 &drv_get_listen_ports() const { return e_->drv_get_listen_ports(); } const eng::vector &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 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