diff --git a/design.txt b/design.txt index 99226df..10db17b 100644 --- a/design.txt +++ b/design.txt @@ -49,9 +49,10 @@ files. They cannot export any internally defined functions directly, but they can provide convenience wrappers for event-based interfaces. Startup sequence and what the module should do: -- constructor : Initialize everything you can here -- init() : Subscribe to events -- "core:start" event : Start doing whatever the module wants to actively do +- constructor : Don't access other modules. Throw on fatal errors. +- init() : Subscribe to events; access other external things. +- "core:start" : Start doing whatever the module wants to actively do. +- "core:continue" : Continue doing stuff after a reload. Network protocol ---------------- diff --git a/src/interface/server.h b/src/interface/server.h index b4018cf..45f6679 100644 --- a/src/interface/server.h +++ b/src/interface/server.h @@ -17,12 +17,20 @@ namespace interface SocketEvent(int fd): fd(fd){} }; + struct ModuleModifiedEvent: public interface::Event::Private { + ss_ name; + ss_ path; + ModuleModifiedEvent(const ss_ &name, const ss_ &path): + name(name), path(path){} + }; + struct Server { virtual ~Server(){} virtual void load_module(const ss_ &module_name, const ss_ &path) = 0; virtual void unload_module(const ss_ &module_name) = 0; + virtual void reload_module(const ss_ &module_name, const ss_ &path) = 0; virtual ss_ get_modules_path() = 0; virtual ss_ get_builtin_modules_path() = 0; virtual bool has_module(const ss_ &module_name) = 0; diff --git a/src/server/state.cpp b/src/server/state.cpp index e8dfc20..822487e 100644 --- a/src/server/state.cpp +++ b/src/server/state.cpp @@ -88,9 +88,11 @@ struct CState: public State, public interface::Server interface::createFileWatch({init_cpp_path}, [this, module_name, path]() { - log_i(MODULE, "Module modified: %s; reloading", cs(module_name)); - unload_module_u(module_name); - load_module(module_name, path); + log_i(MODULE, "Module modified: %s: %s", + cs(module_name), cs(path)); + emit_event(Event("core:module_modified", + new interface::ModuleModifiedEvent(module_name, path))); + handle_events(); })); } @@ -130,7 +132,7 @@ struct CState: public State, public interface::Server m_modules_path = path; ss_ first_module_path = path+"/__loader"; load_module("__loader", first_module_path); - // Allow loader load other modules + // Allow loader to load other modules emit_event(Event("core:load_modules")); handle_events(); // Now that everyone is listening, we can fire the start event @@ -148,6 +150,26 @@ struct CState: public State, public interface::Server m_unloads_requested.insert(module_name); } + void reload_module(const ss_ &module_name, const ss_ &path) + { + log_i(MODULE, "reload_module(%s)", cs(module_name)); + unload_module_u(module_name); + load_module(module_name, path); + // Send core::continue directly to module + { + interface::MutexScope ms(m_modules_mutex); + auto it = m_modules.find(module_name); + if(it == m_modules.end()){ + log_w(MODULE, "reload_module: Module not found: %s", + cs(module_name)); + return; + } + ModuleContainer *mc = &it->second; + interface::MutexScope mc_ms(mc->mutex); + mc->module->event(Event::t("core:continue"), nullptr); + } + } + // Direct version; internal and unsafe void unload_module_u(const ss_ &module_name) { diff --git a/test/testmodules/__loader/server/init.cpp b/test/testmodules/__loader/server/init.cpp index e8869c7..2511d44 100644 --- a/test/testmodules/__loader/server/init.cpp +++ b/test/testmodules/__loader/server/init.cpp @@ -28,13 +28,14 @@ struct Module: public interface::Module { log_v(MODULE, "__loader init"); m_server->sub_event(this, Event::t("core:load_modules")); + m_server->sub_event(this, Event::t("core:module_modified")); } void event(const Event::Type &type, const Event::Private *p) { - if(type == Event::t("core:load_modules")){ - on_load_modules(); - } + EVENT_VOIDN("core:load_modules", on_load_modules) + EVENT_TYPEN("core:module_modified", on_module_modified, + interface::ModuleModifiedEvent) } void on_load_modules() @@ -55,6 +56,12 @@ struct Module: public interface::Module m_server->load_module(n.name, m_server->get_modules_path()+"/"+n.name); }*/ } + + void on_module_modified(const interface::ModuleModifiedEvent &event) + { + log_v(MODULE, "__loader::on_module_modified()"); + m_server->reload_module(event.name, event.path); + } }; extern "C" {