#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: bool done = false; inline static App* instance = nullptr; protected: std::list modules; 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 std::list::iterator load(std::string modulePath, std::list blacklist = {}) { Module* m = dynamicLoad(modulePath); return load(m, blacklist); } virtual std::list::iterator load(Module* m, std::list blacklist = {}) { if(!m) { return modules.end(); } void* h = m->getHandle(); for(auto it = blacklist.begin(); it != blacklist.end(); it++) { if(*it == m->getName()) { std::cout << "Module \"" << *it << "\" is already loaded!\n"; delete m; if(h) dlclose(h); return modules.end(); } } blacklist.push_back(m->getName()); bool skip = false; for(auto it = m->deps.begin(); it != m->deps.end(); it++) { for(std::string s : blacklist) { if(it->first == s) skip = true; } if(skip) { skip = false; continue; } else { if(std::holds_alternative(it->second)) m->depsInstances[it->first] = load(std::get(it->second), blacklist); else m->depsInstances[it->first] = load(std::get(it->second), blacklist); } } modules.push_back(m); m->setSelf(--modules.end()); modules.end()++; return m->self; } 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; std::list getBlacklist() { std::list l; for(Module* m : modules) l.push_back(m->getName()); return l; } }; } #endif