#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; } virtual ~App() { for(auto it = modules.begin(); it != modules.end(); it++) { void* handle = (*it)->getHandle(); delete *it; if(handle) dlclose(handle); it = modules.erase(it); } } static App* Get() { return instance; } virtual void handleArgs(const int&, char*[]) = 0; virtual void run() = 0; virtual void stopModule(std::list::iterator it) { toClose.push_back(*it); } virtual void startModule(std::string lib) { toOpen.push_back(lib); } void end() { done = true; } private: 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(h, Get()); } virtual Module* load(std::string modulePath, std::list::iterator ins) { Module* m = dynamicLoad(modulePath); return load(m, ins); } virtual Module* load(Module* m, std::list::iterator ins) { 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; } } bool skip = false; for(auto it = runOrder.begin(); it != runOrder.end(); it++) { if(m->deps.find(*it) != m->deps.end()) { skip = true; m->depsInstances[*it] = modules[*it]; } if(skip) { skip = false; continue; } else { if(std::holds_alternative(m->deps[*it])) m->depsInstances[*it] = load(std::get(m->deps[*it]), ins); else m->depsInstances[*it] = load(std::get(m->deps[*it]), ins); } } return m; } virtual void unload(std::list::iterator it) { Module* m = *it; void* h = m->getHandle(); modules.erase(m->self); delete m; if(h) dlclose(h); } virtual void printHelp() = 0; }; } #endif