Refactor for DLL
This commit is contained in:
@@ -2,12 +2,9 @@
|
||||
//
|
||||
// DrivenEngine
|
||||
//
|
||||
// This module embodies the idea of an "event-driven game engine." We want the
|
||||
// engine to be event-driven because an event-driven engine is a deterministic
|
||||
// state machine. That, in turn, makes it possible to do replay logging.
|
||||
//
|
||||
// The DrivenEngine module provides two APIs: the 'engine-side' API, and the
|
||||
// 'driver-side' API.
|
||||
// This module embodies the idea of an "event-driven game engine." The
|
||||
// DrivenEngine module provides two APIs: the engine-side API, and the
|
||||
// driver-side API.
|
||||
//
|
||||
// The engine-side API looks like a typical collection of I/O primitives. It
|
||||
// includes methods to open sockets, read and write sockets, read lua source,
|
||||
@@ -41,53 +38,6 @@
|
||||
// machine, free of all OS-specific code.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Here are the rules for what the driver must do:
|
||||
//
|
||||
// * Before doing anything else, the driver must select one of the three
|
||||
// logmodes.
|
||||
//
|
||||
// * If 'logmode_replay' is selected, then the driver must proceed to invoke
|
||||
// 'drv_step_logfile' over and over until it returns false. In replay mode,
|
||||
// the driver should not do anything else.
|
||||
//
|
||||
// * If 'logmode_write' or 'logmode_none' is selected, the driver must proceed
|
||||
// to drive the application. Follow the remainder of these steps.
|
||||
//
|
||||
// * Open a hardwired list of ports for listening.
|
||||
//
|
||||
// * 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'.
|
||||
//
|
||||
// - Get a list of recently-closed channels using drv_get_closed_channels.
|
||||
// Close any socket associated with these channels and free all resources.
|
||||
//
|
||||
// - Get a list of recently-opened channels using drv_get_opened_channels.
|
||||
// Open new outgoing connections for these channels.
|
||||
//
|
||||
// - Do an OS 'poll'. The poll should include the sockets for all channels
|
||||
// in the channel list, all listening ports, and stdio.
|
||||
//
|
||||
// - If the poll indicates that a listening port has acceptable
|
||||
// connections, accept and call drv_notify_accept. Associate the
|
||||
// accepted socket with the channel.
|
||||
//
|
||||
// - If the poll indicates that a connection can accept outgoing data, use
|
||||
// drv_peek_outgoing to fetch some data to write, and write it. Use
|
||||
// drv_sent_outgoing_bytes to indicate that the data was sent.
|
||||
//
|
||||
// - If the poll indicates that a connection has incoming data, read the
|
||||
// data then push it into the channel using drv_recv_incoming.
|
||||
//
|
||||
// - If the poll indicates that STDIO can be read/written, use
|
||||
// drv_peek_outgoing, drv_sent_outgoing, and drv_recv_incoming in the
|
||||
// same manner as you would for a socket.
|
||||
//
|
||||
// - Use 'drv_invoke_event_update' to invoke the engine's update callback.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef DRIVENENGINE_HPP
|
||||
#define DRIVENENGINE_HPP
|
||||
@@ -101,10 +51,12 @@
|
||||
|
||||
#include "util.hpp"
|
||||
#include "streambuffer.hpp"
|
||||
#include "enginewrapper.hpp"
|
||||
|
||||
class DrivenEngine;
|
||||
using UniqueDrivenEngine = std::unique_ptr<DrivenEngine>;
|
||||
using DrivenEngineMaker = UniqueDrivenEngine (*)();
|
||||
using DrivenEngineInitializer = void (*)();
|
||||
|
||||
class Channel : public eng::opnew {
|
||||
public:
|
||||
@@ -209,10 +161,14 @@ public:
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
// The init callback. You may override this in a subclass.
|
||||
// This will be called once at program initialization.
|
||||
//
|
||||
virtual void event_init(int argc, char *argv[]) {}
|
||||
|
||||
// The update callback. You may override this in a subclass.
|
||||
// This will be called whenever anything changes.
|
||||
//
|
||||
virtual void event_init(int argc, char *argv[]) {}
|
||||
virtual void event_update() {}
|
||||
|
||||
// Specify the set of listening ports.
|
||||
@@ -288,111 +244,6 @@ public:
|
||||
//
|
||||
void stop_driver();
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The following methods are the 'driver' side of the pipe.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
// The maximum channel ID plus one.
|
||||
//
|
||||
static const int MAX_CHAN = 256;
|
||||
|
||||
// Get a list of all the listening ports. The driver is expected
|
||||
// to fetch this set shortly after the event_init callback is invoked.
|
||||
//
|
||||
const eng::vector<int> &drv_get_listen_ports() const;
|
||||
|
||||
// Get a list of all recently-opened channels that were created using
|
||||
// drv_new_outgoing_channel. The driver should initiate outgoing
|
||||
// connections for these channels.
|
||||
//
|
||||
const eng::vector<int> &drv_get_new_outgoing() const;
|
||||
|
||||
// Clear the list of recently-opened channels that were created using
|
||||
// drv_new_outgoing_channel.
|
||||
//
|
||||
void drv_clear_new_outgoing();
|
||||
|
||||
// Get the target of a channel. A target is a string like
|
||||
// "cert:whatever.com:80" or "nocert:whatever.com:80".
|
||||
// The first word indicate whether or not a valid SSL certificate
|
||||
// is required. The second word is the hostname. The third word is
|
||||
// the port number.
|
||||
//
|
||||
std::string_view drv_get_target(int chid) const;
|
||||
|
||||
// Return true if the outgoing buffer is empty.
|
||||
//
|
||||
bool drv_outgoing_empty(int chid) const;
|
||||
|
||||
// Return true if the user has released all references to this channel.
|
||||
// In this case, the driver should initiate shutdown of the channel,
|
||||
// and the driver should eventually call drv_notify_close.
|
||||
//
|
||||
bool drv_get_channel_released(int chid) const;
|
||||
|
||||
// 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
|
||||
// is used for all channels, including sockets and stdio.
|
||||
//
|
||||
std::string_view drv_peek_outgoing(int chid) const;
|
||||
|
||||
// Notifies the channel that some bytes were transmitted. This causes those
|
||||
// bytes to be removed from the outgoing buffer. This function is used for
|
||||
// all channels, including sockets and stdio.
|
||||
//
|
||||
void drv_sent_outgoing(int chid, int nbytes);
|
||||
|
||||
// Notifies the channel that some bytes were received. This causes those
|
||||
// bytes to be appended to the incoming buffer. This function is used for
|
||||
// all channels, including sockets and stdio.
|
||||
//
|
||||
void drv_recv_incoming(int chid, std::string_view data);
|
||||
|
||||
// Notify the channel that the connection was closed. This includes all
|
||||
// sorts of closes, including friendly termination, all the way to network
|
||||
// failure. Closing the channel doesn't delete it. The engine is
|
||||
// responsible for noticing that the channel closed and the engine must
|
||||
// delete it. Closing a channel prevents it from showing up in
|
||||
// 'drv_list_channels'.
|
||||
//
|
||||
void drv_notify_close(int chid, std::string_view err);
|
||||
|
||||
// Notify the DrivenEngine that somebody connected to an incoming port.
|
||||
// This will cause the DrivenEngine to allocate a new channel and put the
|
||||
// new channel into the incoming channels queue. Returns the new channel
|
||||
// ID. The new incoming channel appears in the 'drv_list_channels' list,
|
||||
// even before the engine pops the channel from the incoming channels queue.
|
||||
//
|
||||
int drv_notify_accept(int port);
|
||||
|
||||
|
||||
// Clear the lua source code.
|
||||
//
|
||||
void drv_clear_lua_source();
|
||||
|
||||
// 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_add_lua_source(std::string_view fn, std::string_view data);
|
||||
|
||||
// Invoke the init or update event.
|
||||
//
|
||||
void drv_invoke_event_init(int argc, char *argv[]);
|
||||
void drv_invoke_event_update(double clock);
|
||||
|
||||
// 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.
|
||||
// When the driver sees this flag, it should rescan the source and call
|
||||
// drv_set_source.
|
||||
//
|
||||
bool drv_get_rescan_lua_source() const;
|
||||
|
||||
// If true, the engine is done. Stop the driver.
|
||||
//
|
||||
bool drv_get_stop_driver() const;
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Creation and Destruction.
|
||||
@@ -413,15 +264,38 @@ public:
|
||||
//
|
||||
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.
|
||||
// The following accessors are for use by PlayWrapper and ReplayWrapper.
|
||||
//
|
||||
static void set(DrivenEngine *de);
|
||||
static DrivenEngine *get();
|
||||
// The PlayWrapper and ReplayWrapper use C stubs to access
|
||||
// the engine. The C stubs, in turn, call these C++ methods.
|
||||
//
|
||||
// The stubs for the getters are trivial, one-line stubs.
|
||||
//
|
||||
// The stubs for the mutators add logging.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
void drv_get_listen_ports(uint32_t *nports, const uint32_t **ports) const;
|
||||
void drv_get_new_outgoing(uint32_t *nchids, const uint32_t **chids) const;
|
||||
const char *drv_get_target(uint32_t chid) const;
|
||||
bool drv_get_channel_released(uint32_t chid) const;
|
||||
void drv_get_outgoing(uint32_t chid, uint32_t *len, const char **data) const;
|
||||
bool drv_get_outgoing_empty(uint32_t chid) const;
|
||||
double drv_get_clock() const;
|
||||
bool drv_get_rescan_lua_source() const;
|
||||
bool drv_get_stop_driver() const;
|
||||
|
||||
void drv_initialize(uint32_t srcpklen, const char *srcpk, int argc, char **argv);
|
||||
void drv_clear_new_outgoing();
|
||||
void drv_sent_outgoing(uint32_t chid, uint32_t nbytes);
|
||||
void drv_recv_incoming(uint32_t chid, uint32_t nbytes, const char *bytes);
|
||||
void drv_notify_close(uint32_t chid, uint32_t len, const char *data);
|
||||
uint32_t drv_notify_accept(uint32_t port);
|
||||
void drv_invoke_event_update(double clock);
|
||||
void drv_set_lua_source(uint32_t srcpklen, const char *srcpk);
|
||||
|
||||
private:
|
||||
// Find a currently-unused channel ID. Channel IDs
|
||||
// are small integers that are reused.
|
||||
@@ -431,19 +305,23 @@ private:
|
||||
Channel *get_chid(int chid) const;
|
||||
|
||||
private:
|
||||
SharedChannel channels_[MAX_CHAN];
|
||||
SharedChannel channels_[DRV_MAX_CHAN];
|
||||
int next_unused_chid_;
|
||||
SharedChannel stdio_channel_;
|
||||
eng::vector<SharedChannel> accepted_channels_;
|
||||
eng::vector<int> new_outgoing_;
|
||||
eng::vector<uint32_t> new_outgoing_;
|
||||
util::LuaSourcePtr lua_source_;
|
||||
eng::vector<int> listen_ports_;
|
||||
eng::vector<uint32_t> listen_ports_;
|
||||
bool rescan_lua_source_;
|
||||
double clock_;
|
||||
bool stop_driver_;
|
||||
friend class Channel;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
struct DrivenEngineReg {
|
||||
const char *name;
|
||||
DrivenEngineMaker maker;
|
||||
@@ -458,5 +336,10 @@ struct DrivenEngineReg {
|
||||
} \
|
||||
DrivenEngineReg dengreg_##cname(name, dengmake_##cname);
|
||||
|
||||
struct DrivenEngineInitializerReg {
|
||||
static DrivenEngineInitializer func;
|
||||
DrivenEngineInitializerReg(DrivenEngineInitializer f);
|
||||
};
|
||||
|
||||
|
||||
#endif // DRIVENENGINE_HPP
|
||||
|
||||
Reference in New Issue
Block a user