#ifndef TASK_MANAGER_HPP #define TASK_MANAGER_HPP #include #include #include #include #include #include #include #include #include "easylogging++.h" using callable = std::function; enum TaskAction { TASK_ACTION_LOW = 0, TASK_ACTION_HIGH = 1, TASK_ACTION_NONE }; class Task { private: cron::cronexpr cronexpr; TaskAction action; callable action_fn; int pin; std::string schedule; public: Task(std::string schedule, callable action_fn); Task(Task &task); void doAction(); std::time_t next(); friend std::ostream& operator<< (std::ostream &out, const Task &task); }; class TaskManager { private: std::map tasks; std::string human_readable(std::time_t value); public: TaskManager(std::istream &stream, callable action_fn); int doWork(); friend std::ostream& operator<< (std::ostream &out, const TaskManager &tasksMgr); }; inline std::ostream& operator<< (std::ostream &out, const TaskManager &tasksMgr) { out << "Schedule table:" << std::endl; for (const auto& [key, value] : tasksMgr.tasks) { std::tm * ptm = std::localtime(&key); char buffer[32]; // Format: Mo, 15.06.2009 20:20:00 std::strftime(buffer, 32, "%a, %d.%m.%Y %H:%M:%S", ptm); out << "Next time value: " << buffer << " " << value << std::endl; } return out; } inline TaskManager::TaskManager(std::istream &stream, callable action_fn) { std::string line; while (std::getline(stream, line).good()) { Task task{line, action_fn}; tasks.emplace(std::piecewise_construct, std::forward_as_tuple(task.next()), std::forward_as_tuple(task)); } LOG(INFO) << *this; } inline int TaskManager::doWork() { auto it = tasks.begin(); if(it == tasks.end()) { LOG(WARNING) << "Table of tasks is empty!!! Nothing to do!!"; return 0; } std::time_t now = std::time(0); std::time_t stop = it->first; LOG(INFO) << "Will sleep " << human_readable(stop - now) << " till next action "; std::this_thread::sleep_for(std::chrono::seconds{stop - now}); it->second.doAction(); tasks.emplace(std::piecewise_construct, std::forward_as_tuple(it->second.next()), std::forward_as_tuple(it->second)); tasks.erase(it); LOG(INFO) << *this; return 1; } inline std::string TaskManager::human_readable(std::time_t value) { std::stringstream result; int secs = value % 60; int mins = std::floor((float)value / 60); int hours = std::floor((float)mins / 60); if(mins > 59) { mins = mins % 60; } result << std::setfill('0') << std::setw(2) << hours << ':' << std::setfill('0') << std::setw(2) << mins << ':' << std::setfill('0') << std::setw(2) << secs; return result.str(); } inline std::ostream& operator<< (std::ostream &out, const Task &task) { out << "Schedule: "<< task.schedule << " Action: "; switch (task.action) { case TASK_ACTION_HIGH: out << "HIGH"; break; case TASK_ACTION_LOW: out << "LOW"; break; default: break; } out << " Pin:" << task.pin; return out; } inline Task::Task(std::string schedule, callable action_fn): cronexpr{}, action{TASK_ACTION_NONE}, pin{0}, action_fn{action_fn}, schedule{schedule} { auto fields = cron::utils::split(schedule, ' '); fields.erase( std::remove_if(std::begin(fields), std::end(fields), [](CRONCPP_STRING_VIEW s) {return s.empty(); }), std::end(fields)); if (fields.size() != 7) throw cron::bad_cronexpr("cron expression must have 7 fields"); std::stringstream line; for (int i = 0; i < 6; ++i) { line << fields[i] << ' '; } this->schedule = line.str(); cronexpr = cron::make_cron(this->schedule); std::string command{fields[6]}; if(command.rfind("HIGH", 0) == 0) { action = TASK_ACTION_HIGH; } else if((command.rfind("LOW", 0) == 0)) { action = TASK_ACTION_LOW; } auto start = command.find('('); auto stop = command.find(')'); if(start == std::string::npos && stop == std::string::npos) { throw cron::bad_cronexpr("pin is not set in command"); } LOG(DEBUG) << "pin to parse " << command.substr(start + 1, stop - start - 1); pin = std::stoi(command.substr(start + 1, stop - start - 1)); } inline Task::Task(Task &task): cronexpr{task.cronexpr}, action{task.action}, action_fn{task.action_fn}, pin{task.pin}, schedule{task.schedule} {} inline void Task::doAction() { if(action == TASK_ACTION_NONE) return; action_fn(pin, action); } inline std::time_t Task::next() { std::time_t now = std::time(0); return cron::cron_next(cronexpr, now); } #endif //TASK_MANAGER_HPP