Inverted control flow, engine as library
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user