diff --git a/include/echo/Network/NetworkExecutionModel.h b/include/echo/Network/NetworkExecutionModel.h --- a/include/echo/Network/NetworkExecutionModel.h +++ b/include/echo/Network/NetworkExecutionModel.h @@ -1,82 +1,78 @@ #ifndef _ECHO_NETWORKEXECUTIONMODEL_H_ #define _ECHO_NETWORKEXECUTIONMODEL_H_ #include #include #include #include #include #include namespace Echo { class Kernel; /** * A NetworkExecutionModel is designed to update a kernel on network events. * While the NetworkExecutionModel is waiting for network events it will either behave in one of two ways: * * 1. If configured to use command processing (default), events it will be waiting for user input on std::in. * Functions can be registered with the object as named commands to allow the kernel to receive input. * The execution model needs to be set in order for a Kernel to execute. In the case of Application * the execution model can be set before Initialise() is called which then overrides the default * execution model. * - * 2. If configured to not use command processing, the model will sleep the thread until the update frequency - * time has passed then the kernel will update a Frame. This is important for allowing connections to - * auto reconnect if they are configured to do so. One side effect of this is that Connection auto reconnect - * times may be extended to up to just short of twice what is configured. It also means that reconnect times - * won't be less than the update frequency. + * 2. If configured to not use command processing, the model will wait on a condition variable until a network + * event occurs. Unfortunately when using mode Connections won't attempt to auto reconnect until a network + * event occurs. * * To set up a NetworkExecutionModel: * - Create a shared pointer pointing to an instance of a NetworkExecutionModel. * - If you're using Application set the execution model with SetExecutionModel() * - If you're using Application initialise the network interface if it has not already been done, * if you're not using Application then create a NetworkManager object and initialise it. * - Add the NetworkExecutionModel to the NetworkManager's event listener list. * * Example code: * * InitialiseNetworkManager(); * shared_ptr executionModel(new NetworkExecutionModel(*this)); * SetExecutionModel(executionModel); * GetNetworkManager()->AddNetworkEventListener(executionModel); * //Initialise application as usual. * Application::Initialise("YourApplication","resources/YourApplication.config"); */ class NetworkExecutionModel : public ExecutionModel, public NetworkEventListener { public: typedef function CommandProcessorFunction; static boost::arg<1> CommandPlaceholder; typedef function DefaultCommandProcessorFunction; static boost::arg<2> ParametersPlaceholder; NetworkExecutionModel(Kernel& kernel); ~NetworkExecutionModel(); void OnNetworkEvent(NetworkEventType eventType); bool SupportsModel(Models::ModelEnum model) override; bool ProcessEvents(f32) override; bool EnterSystemEventManager() override; bool SendUpdateRequest() override; void SetCommandProcessor(const std::string& command, CommandProcessorFunction func); void SetDefaultCommandProcessorFunction(DefaultCommandProcessorFunction func); - void SetUseCommandProcessing(bool useCommandProcessing); - void SetUpdateFrequency(Seconds updateFrequency); + void SetUseCommandProcessing(bool useCommandProcessing); private: void DefaultCommandProcessor(); bool mUseCommandProcessing; - Seconds mUpdateFrequency; Kernel& mKernel; bool mUpdateFrame; std::mutex mUpdateMutex; std::condition_variable mUpdateCondition; typedef std::map< std::string, CommandProcessorFunction > ProcessorMap; ProcessorMap mProcessors; DefaultCommandProcessorFunction mDefaultCommandProcessorFunction; }; } #endif diff --git a/src/Network/NetworkExecutionModel.cpp b/src/Network/NetworkExecutionModel.cpp --- a/src/Network/NetworkExecutionModel.cpp +++ b/src/Network/NetworkExecutionModel.cpp @@ -1,120 +1,115 @@ #include #include #include #include #include #include namespace Echo { NetworkExecutionModel::NetworkExecutionModel(Kernel& kernel) : ExecutionModel(ExecutionModel::Models::CONTROLLER), mKernel(kernel), mUseCommandProcessing(true), - mUpdateFrame(false), - mUpdateFrequency(5) + mUpdateFrame(false) { SetDefaultCommandProcessorFunction(bind(&NetworkExecutionModel::DefaultCommandProcessor,this)); } NetworkExecutionModel::~NetworkExecutionModel() { } void NetworkExecutionModel::SetUseCommandProcessing(bool useCommandProcessing) { mUseCommandProcessing = useCommandProcessing; } - void NetworkExecutionModel::SetUpdateFrequency(Seconds updateFrequency) - { - mUpdateFrequency = updateFrequency; - } - void NetworkExecutionModel::OnNetworkEvent(NetworkEventType eventType) { mUpdateFrame = true; mUpdateCondition.notify_all(); } bool NetworkExecutionModel::SupportsModel(Models::ModelEnum model) { switch (model) { case Models::CONTROLLER: return true; case Models::EXTERNAL_CONTROLLER: case Models::COOPERATE: case Models::NONE: return false; } return false; } bool NetworkExecutionModel::ProcessEvents(f32) { return false; } bool NetworkExecutionModel::EnterSystemEventManager() { if(mUseCommandProcessing) { std::string command; std::cout << "Type 'quit' to quit" << std::endl; while(command!="quit") { std::getline(std::cin,command); if(!std::cin.good()) { // The process might be launched with a detached stdin which means cin will be bad. // If that is the case we'll sleep and check back every 10 seconds (this is just arbitrary). Thread::Sleep(Seconds(10)); } size_t space = command.find_first_of(' '); std::string parameters; if(space!=std::string::npos) { parameters = command.substr(space+1); command = command.substr(0,space); } ProcessorMap::iterator it = mProcessors.find(command); if(it!=mProcessors.end()) { it->second(parameters); }else { mDefaultCommandProcessorFunction(command,parameters); } } }else { bool kernelActive = true; while(kernelActive) { std::unique_lock lock(mUpdateMutex); mUpdateCondition.wait(lock, [this](){return mUpdateFrame;}); + mUpdateFrame = false; kernelActive = mKernel.ProcessFrame(); } } return true; } bool NetworkExecutionModel::SendUpdateRequest() { return true; } void NetworkExecutionModel::SetCommandProcessor(const std::string& command, CommandProcessorFunction func) { mProcessors[command] = func; } void NetworkExecutionModel::SetDefaultCommandProcessorFunction(DefaultCommandProcessorFunction func) { mDefaultCommandProcessorFunction = func; } void NetworkExecutionModel::DefaultCommandProcessor() { } }