Inverted control flow, engine as library

This commit is contained in:
2021-10-04 17:45:18 -04:00
parent e0fdb2d42f
commit bc22dc89af
15 changed files with 387 additions and 136 deletions

View File

@@ -73,6 +73,9 @@
//
// * Repeat the following steps over and over:
//
// - If the engine asked that the lua source be refreshed, read the source
// from disk and call 'drv_set_lua_source'.
//
// - List all existing channels using drv_list_channels.
//
// - If there are any new channels in the channel list, use
@@ -101,8 +104,7 @@
// drv_peek_outgoing, drv_sent_outgoing, and drv_recv_incoming in the
// same manner as you would for a socket.
//
// - Use 'drv_invoke_engine_update' to invoke the engine's update
// callback.
// - Use 'drv_invoke_engine_update' to invoke the engine's update callback.
//
//////////////////////////////////////////////////////////////
@@ -111,25 +113,19 @@
#include <memory>
#include <string>
#include <vector>
#include <map>
#include "streambuffer.hpp"
#include "util.hpp"
class DrivenEngine;
class Channel {
private:
int chid_;
std::unique_ptr<StreamBuffer> sb_in_;
std::unique_ptr<StreamBuffer> sb_out_;
int port_;
bool remote_closed_;
std::string target_;
public:
// Get the buffers associated with this channel.
//
StreamBuffer *out();
StreamBuffer *in();
const StreamBuffer *out() const;
const StreamBuffer *in() const;
StreamBuffer *out() { return sb_out_.get(); }
StreamBuffer *in() { return sb_in_.get(); }
// If this is a socket connection, the receiver's port number.
//
@@ -140,30 +136,32 @@ public:
// True if the remote closed the connection, or a failure occurred.
//
bool remote_closed() const { return remote_closed_; }
bool closed() const { return closed_; }
// If communications were closed by the remote, there may
// be an error message.
// You may delete any channel except for stdio. This closes
// the channel.
//
std::string errmsg() const { return errmsg_; }
~Channel();
private:
// Constructor is deliberately private. Use
// DrivenEngine::new_outgoing_channel to create outgoing socket channels.
//
Channel(DrivenEngine *de, int chid, int port, const std::string &target);
private:
DrivenEngine *driven_;
int chid_;
std::unique_ptr<StreamBuffer> sb_in_;
std::unique_ptr<StreamBuffer> sb_out_;
int port_;
bool closed_;
std::string target_;
friend class DrivenEngine;
};
class DrivenEngine {
public:
// Constructor.
//
// Most initialization is achieved by 'drv_xxx' functions, so
// this constructor takes no arguments.
//
DrivenEngine();
// Destructor.
//
// It is necessary to delete all channels before deleting the
// DrivenEngine. The destructor will verify that this has been done.
//
~DrivenEngine();
//////////////////////////////////////////////////////////////
//
// The following methods are the 'engine' side of the pipe.
@@ -174,7 +172,7 @@ public:
// This will be called to initialize the logic engine, shortly after the lua
// source is loaded.
//
virtual void init() { }
virtual void init() {}
// The update function. You should override this in a subclass. This will
// be called to give the engine a chance to respond to new data.
@@ -195,7 +193,7 @@ public:
// actually opening the connection and relaying data into the channel using
// drv_get_target, drv_peek_outgoing, drv_sent_outgoing, drv_recv_incoming.
//
std::unique_ptr<Channel> new_outgoing_channel(const std::string &target)
std::unique_ptr<Channel> new_outgoing_channel(const std::string &target);
// Create a new channel from any pending incoming connection. If there is no
// incoming connection, returns nullptr.
@@ -234,7 +232,7 @@ public:
// periodically poll to see if the engine has called rescan_lua_source,
// using drv_get_rescan
//
std::unique_ptr<util::StringMap> get_lua_source();
std::unique_ptr<util::LuaSource> get_lua_source();
// Rescan the lua source directory. The lua source directory is read once,
// automatically, at engine creation time. If you want to read it again,
@@ -245,6 +243,11 @@ public:
//
void rescan_lua_source();
// Stop the driver. The engine should call this when it's done
// and there's nothing left to do.
//
void stop_driver();
//////////////////////////////////////////////////////////////
//
// The following methods are the 'driver' side of the pipe.
@@ -293,7 +296,7 @@ public:
// is supposed to be talking to. Non-socket channels and incoming channels
// have empty targets.
//
std::string drv_get_target(int chid);
const std::string &drv_get_target(int chid);
// Get a pointer to the bytes in the outgoing buffer. The pointer returned
// here is naturally only valid until the buffer is changed. This function
@@ -338,7 +341,7 @@ public:
// Set the lua source code. The driver is expected to read the lua source
// code and store it (using this function) once before invoking
//
void drv_set_lua_source(const util::StringMap &source);
void drv_set_lua_source(const util::LuaSource &source);
// Check the 'rescan_lua_source' flag. If this flag is set, it means
// that the engine wants the driver to rescan the lua source code.
@@ -347,19 +350,59 @@ public:
//
bool drv_get_rescan_lua_source();
// If true, the engine is done. Stop the driver.
//
bool drv_get_stop_driver();
// In replay mode, perform a single step of the logfile. Returns true
// if the logfile was not empty.
//
bool drv_step_logfile();
//////////////////////////////////////////////////////////////
//
// Creation and Destruction.
//
//////////////////////////////////////////////////////////////
// Constructor.
//
// Most initialization is achieved by 'drv_xxx' functions, so
// this constructor takes no arguments.
//
DrivenEngine();
// Destructor.
//
// It is necessary to delete all channels before deleting the
// DrivenEngine. The destructor will verify that this has been done.
//
virtual ~DrivenEngine();
// Set/Get Global Pointer.
//
// Normally, there is a single global "DrivenEngine" instance.
// We provide a global pointer to store this instance. This is
// a raw pointer, you must manually delete the DrivenEngine.
//
static void set(DrivenEngine *de);
static DrivenEngine *get();
private:
Channel *stdio_channel_;
// Get a channel by channel ID.
Channel *get_chid(int chid);
private:
std::unique_ptr<Channel> stdio_channel_;
int next_channel_id_;
std::map<int, Channel *> channels_;
Channel *recent_channel_;
std::vector<Channel*> accepted_channels_;
std::vector<std::unique_ptr<Channel>> accepted_channels_;
bool rescan_lua_source_;
std::unique_ptr<util::StringMap> lua_source_;
std::unique_ptr<util::LuaSource> lua_source_;
double clock_;
bool stop_driver_;
friend class Channel;
};
#endif // DRIVENENGINE_HPP