#ifndef APP_H #define APP_H #include "pch.hpp" #include "utils/Module/Module.h" namespace Archimedes { class App { public: App() { if(instance != nullptr) { std::cout << "App already exists\nThere can only be one!\n"; std::abort(); } instance = this; roInsert = runOrder.begin(); } virtual ~App() { for(std::string s : runOrder) { void* handle = modules[s]->getHandle(); delete modules[s]; if(handle) dlclose(handle); modules[s] = nullptr; } runOrder.clear(); } static App* Get() { return instance; } virtual void handleArgs(const int&, char*[]) = 0; virtual void run() = 0; virtual void stopModule(std::string lib) { toClose.push_back(lib); } virtual void startModule(std::variant m) { toOpen.push_back(m); } void end() { done = true; } private: std::list::iterator roInsert; inline static App* instance = nullptr; protected: bool done = false; std::unordered_map modules; std::list runOrder; std::list toClose; std::list> toOpen; virtual Module* dynamicLoad(std::string lib) { void* h = dlopen(lib.c_str(), RTLD_NOW); if(!h) { std::cout << "could not open lib at: \"" << lib.c_str() << "\"\nError: " << dlerror() << std::endl; return nullptr; } Module::create_t* create = (Module::create_t*) dlsym(h, "create"); char* err = dlerror(); if(err) { std::cout << "error finding create function in file: " << lib << std::endl; std::cout << "dlerror(): " << err << std::endl; return nullptr; } return create(Get(), h); } virtual Module* load(std::string modulePath) { Module* m = dynamicLoad(modulePath); return load(m); } virtual Module* load(Module* m) { if(!m) { return nullptr; } void* h = m->getHandle(); for(auto it = runOrder.begin(); it != runOrder.end(); it++) { if(*it == m->getName()) { std::cout << "Module \"" << *it << "\" is already loaded!\n"; delete m; if(h) { dlclose(h); } return nullptr; } } modules[m->getName()] = m; for(auto it = runOrder.begin(); it != runOrder.end(); it++) { if(m->deps.find(*it) != m->deps.end()) { m->moduleInstances[*it] = modules[*it]; //modules should be located after their dependencies if(std::distance(roInsert, it) <= 0) { roInsert = ++it--; } } } //insert temporarily to avoid circular dependencies runOrder.insert(roInsert, m->getName()); bool skip = false; for(auto it : m->deps) { for(auto s : runOrder) { if(s == it.first) { skip = true; m->moduleInstances[s] = modules[s]; } } if(skip) continue; if(std::holds_alternative(it.second)) m->moduleInstances[it.first] = load(std::get(it.second)); else m->moduleInstances[it.first] = load(std::get(it.second)); } //reinsert once final order has been reached runOrder.remove(m->getName()); runOrder.insert(roInsert, m->getName()); return m; } virtual void unload(std::string name) { if(modules.find(name) == modules.end()) return; //unload modules that depend on the one we are unloading for(std::string s : runOrder) { if(modules[s]->deps.find(name) != modules[s]->deps.end()) { unload(s); } } Module* m = modules[name]; void* h = m->getHandle(); modules[name] = nullptr; if(h) { delete m; dlclose(h); } runOrder.remove(name); } virtual void printHelp() = 0; }; } #endif