#include "collection.h" constexpr std::string_view downloads("downloads"); static const std::regex remote("(^https?):\\/\\/"); Collection::Collection( const std::filesystem::path& destination, const std::string& target, const std::shared_ptr& logger, const std::shared_ptr& taskManager ): Loggable(logger), std::enable_shared_from_this(), mutex(), destination(destination), target(target), taskManager(taskManager), knownSources(), successSources(), downloadingSources(), readingSources(), buildingSources() { try { std::filesystem::create_directories(destination); } catch (const std::exception& e) { fatal(e.what()); throw e; } } void Collection::addSource(const std::string& source) { std::lock_guard lock(mutex); if (_hasSource(source)) { major("Source " + source + " is already present, skipping as duplicate"); return; } debug("Adding source " + source); if (isRemote(source)) queueDownload(source); else queueRead(source, source); } void Collection::sourceDownaloded(const std::string& source, TaskManager::Error err) { std::lock_guard lock(mutex); Downloads::const_iterator itr = downloadingSources.find(source); std::optional location = itr->second->getLocation(); downloadingSources.erase(itr); if (err.has_value() || !location.has_value()) { error("Coundn't download " + source + ": " + err.value()->what()); return; } queueRead(source, location.value()); } void Collection::sourceRead(const std::string& source, TaskManager::Error err) { std::lock_guard lock(mutex); debug("Source " + source + " has been read"); Components::iterator itr = readingSources.find(source); if (err.has_value()) { error("Coundn't read " + source + ": " + err.value()->what()); readingSources.erase(itr); return; } debug("Queuing build of " + source); std::pair res = buildingSources.emplace(source, std::move(itr->second)); readingSources.erase(itr); taskManager->queue( std::bind(&Component::build, res.first->second.get(), destination, target), std::bind(&Collection::sourceBuilt, this, source, std::placeholders::_1) ); } void Collection::sourceBuilt(const std::string& source, TaskManager::Error err) { std::lock_guard lock(mutex); debug("Source " + source + " has been built"); Components::iterator itr = buildingSources.find(source); buildingSources.erase(itr); if (err.has_value()) { error("Coundn't read " + source + ": " + err.value()->what()); return; } successSources.emplace(source); } bool Collection::isRemote(const std::string& source) { return std::regex_search(source, remote); } void Collection::queueDownload(const std::string& source) { debug("Queuing download of " + source); std::pair res = downloadingSources.emplace(std::piecewise_construct, std::forward_as_tuple(source), std::forward_as_tuple( std::make_unique(source, destination/downloads, logger) ) ); taskManager->queue( std::bind(&Download::proceed, res.first->second.get()), std::bind(&Collection::sourceDownaloded, this, source, std::placeholders::_1) ); } void Collection::queueRead(const std::string& source, const std::filesystem::path& location) { debug("Queuing read of " + source); std::pair res = readingSources.emplace(std::piecewise_construct, std::forward_as_tuple(source), std::forward_as_tuple( std::make_unique(location, shared_from_this(), logger) ) ); taskManager->queue( std::bind(&Component::read, res.first->second.get()), std::bind(&Collection::sourceRead, this, source, std::placeholders::_1) ); } bool Collection::hasSource(const std::string& source) const { std::lock_guard lock(mutex); return _hasSource(source); } bool Collection::_hasSource(const std::string& source) const { return knownSources.count(source) > 0; }