#include "lpxserver.hpp" #include "world.hpp" #include "drivenengine.hpp" #include "luaconsole.hpp" #include "util.hpp" #include "printbuffer.hpp" #include class ServerClient { public: int64_t actor_id_; UniqueChannel channel_; UniqueWorld sync_; }; using UniqueServerClient = std::unique_ptr; using ServerClientVector = std::vector; class LpxServer : public DrivenEngine { public: UniqueWorld master_; LuaConsole console_; ServerClientVector clients_; PrintChanneler print_channeler_; int64_t admin_id_; public: virtual void event_init(int argc, char *argv[]) { // Create the master world model. master_.reset(new World(util::WORLD_TYPE_MASTER)); // Create an actor for administrative commands. admin_id_ = master_->create_login_actor(); // Print out admin ID for debugging purposes. stdostream() << "Admin actor id = " << admin_id_ << std::endl; // Enable listening on port 8085. listen_port(8085); // Set the console prompt. get_stdio_channel()->set_prompt(console_.get_prompt()); } void do_lua_command(const util::StringVec &words) { if (words.size() != 2) { stdostream() << "lua command (lua) takes a single string" << std::endl; return; } const std::string &exp = words[1]; InvocationData dummyresult; Invocation inv(Invocation::KIND_LUA, admin_id_, admin_id_, exp, dummyresult); master_->invoke(inv); } void do_syntax_command(const util::StringVec &words) { stdostream() << "Syntax Error: "; for (int i = 1; i < int(words.size()); i++) { stdostream() << words[i] << " "; } stdostream() << std::endl; } void do_quit_command(const util::StringVec &words) { if (words.size() != 1) { stdostream() << "quit command takes no arguments" << std::endl; return; } stop_driver(); } void do_command(const util::StringVec &words) { if (words.empty()) return; else if (words[0] == "lua") do_lua_command(words); else if (words[0] == "syntax") do_syntax_command(words); else if (words[0] == "quit") do_quit_command(words); else { stdostream() << "Unknown command: " << words[0] << std::endl; } } bool handle_invocation(ServerClient *sclient) { return false; } virtual void event_update() { // Check for keyboard input on stdin. while (true) { std::string line = get_stdio_channel()->in()->readline(); if (line == "") break; console_.add(line); get_stdio_channel()->set_prompt(console_.get_prompt()); do_command(console_.get_command()); } // Anything in the administrator printbuffer should go to stdostream. if (print_channeler_.channel(master_->get_printbuffer(admin_id_), stdostream())) { master_->invoke(print_channeler_.invocation(admin_id_)); } // Check for new incoming channels, set up client structures. while (true) { UniqueChannel chan = new_incoming_channel(); if (chan == nullptr) break; ServerClient *client = new ServerClient; client->actor_id_ = master_->create_login_actor(); client->channel_ = std::move(chan); client->sync_.reset(new World(util::WORLD_TYPE_S_SYNC)); client->sync_->create_login_actor(); clients_.emplace_back(client); stdostream() << "New client: actor id=" << client->actor_id_ << std::endl; } // Traverse all existing channels, process any communication. ServerClientVector keep; for (UniqueServerClient &client : clients_) { if (client->channel_->closed()) { stdostream() << "Client closed: actor id=" << client->actor_id_ << std::endl; continue; } // Check for received invocations. while (handle_invocation(client.get())); // Transfer the client to the keep vector. keep.emplace_back(std::move(client)); } clients_ = std::move(keep); } }; UniqueDrivenEngine make_LpxServer() { return UniqueDrivenEngine(new LpxServer); }