From c89ae513eff63004819addecde49b20b7c5890f2 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Wed, 25 Jan 2006 21:23:46 +0000 Subject: [PATCH] * Allow clock time for command scheduler interval and start time using the format "hh:mm:ss". git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@627 e378c898-3ddf-0310-93e7-cc216c733640 --- rak/timer.h | 2 + src/command_scheduler.cc | 73 +++++++++++++++++++++++++++++++++-- src/command_scheduler.h | 6 +++ src/command_scheduler_item.cc | 29 +++++++++++++- src/command_scheduler_item.h | 7 +++- src/option_handler_rules.cc | 13 +++++-- 6 files changed, 118 insertions(+), 12 deletions(-) diff --git a/rak/timer.h b/rak/timer.h index 36a65fe3..91ff75e8 100644 --- a/rak/timer.h +++ b/rak/timer.h @@ -67,6 +67,8 @@ class timer { timer operator - (const timer& t) const { return timer(m_time - t.m_time); } timer operator + (const timer& t) const { return timer(m_time + t.m_time); } + timer operator * (int64_t t) const { return timer(m_time * t); } + timer operator / (int64_t t) const { return timer(m_time / t); } timer operator -= (int64_t t) { m_time -= t; return *this; } timer operator -= (const timer& t) { m_time -= t.m_time; return *this; } diff --git a/src/command_scheduler.cc b/src/command_scheduler.cc index 75627275..6f1d766a 100644 --- a/src/command_scheduler.cc +++ b/src/command_scheduler.cc @@ -37,6 +37,7 @@ #include "config.h" #include +#include #include #include @@ -98,9 +99,73 @@ CommandScheduler::call_item(value_type item) { m_slotErrorMessage("Scheduled command failed: " + item->key() + ": " + e.what()); } - uint32_t interval = item->interval(); + // Still schedule if we caught a torrrent::input_error? + rak::timer next = item->next_time_scheduled(); - // Enable if we caught a torrrent::input_error? - if (interval != 0) - item->enable(interval); + if (next == rak::timer()) { + // Remove from scheduler? + return; + } + + if (next <= cachedTime) + throw torrent::internal_error("CommandScheduler::call_item(...) tried to schedule a zero interval item."); + + item->enable(next); +} + +uint32_t +CommandScheduler::parse_absolute(const char* str) { + Time result = parse_time(str); + + switch (result.first) { + case 1: + return result.second; + + case 2: + return (result.second - cachedTime.seconds() % 3600) % 3600; + + case 0: + default: + throw torrent::input_error("Could not parse interval."); + } +} + +uint32_t +CommandScheduler::parse_interval(const char* str) { + Time result = parse_time(str); + + if (result.first == 0) + throw torrent::input_error("Could not parse interval."); + + return result.second; +} + +CommandScheduler::Time +CommandScheduler::parse_time(const char* str) { + Time result(0, 0); + + while (true) { + char* pos; + result.first++; + result.second += strtol(str, &pos, 10); + + if (pos == str || result.second < 0) + return Time(0, 0); + + while (std::isspace(*pos)) + ++pos; + + if (*pos == '\0') + return result; + + if (*pos != ':' || result.first > 3) + return Time(0, 0); + + if (result.first < 3) + result.second *= 60; + else + result.second *= 24; + + str = pos + 1; + } } diff --git a/src/command_scheduler.h b/src/command_scheduler.h index 7e6f2c45..e9ecaf93 100644 --- a/src/command_scheduler.h +++ b/src/command_scheduler.h @@ -46,6 +46,7 @@ class CommandSchedulerItem; class CommandScheduler : public std::vector { public: typedef rak::function1 SlotString; + typedef std::pair Time; typedef std::vector base_type; using base_type::value_type; @@ -67,6 +68,11 @@ public: iterator insert(const std::string& key); void erase(iterator itr); + static uint32_t parse_absolute(const char* str); + static uint32_t parse_interval(const char* str); + + static Time parse_time(const char* str); + private: void call_item(value_type item); diff --git a/src/command_scheduler_item.cc b/src/command_scheduler_item.cc index cc26c0ec..bf33314e 100644 --- a/src/command_scheduler_item.cc +++ b/src/command_scheduler_item.cc @@ -36,6 +36,8 @@ #include "config.h" +#include + #include "command_scheduler_item.h" CommandSchedulerItem::~CommandSchedulerItem() { @@ -43,17 +45,40 @@ CommandSchedulerItem::~CommandSchedulerItem() { } void -CommandSchedulerItem::enable(uint32_t first) { +CommandSchedulerItem::enable(rak::timer t) { + if (t == rak::timer()) + throw torrent::internal_error("CommandSchedulerItem::enable() t == rak::timer()."); + if (is_queued()) disable(); // If 'first' is zero then we execute the task // immediately. ''interval()'' will not return zero so we never end // up in an infinit loop. - priority_queue_insert(&taskScheduler, &m_task, (cachedTime + ((int64_t)first * 1000000)).round_seconds()); + m_timeScheduled = t; + priority_queue_insert(&taskScheduler, &m_task, t); } void CommandSchedulerItem::disable() { + m_timeScheduled = rak::timer(); priority_queue_erase(&taskScheduler, &m_task); } + +rak::timer +CommandSchedulerItem::next_time_scheduled() const { + if (m_interval == 0) + return rak::timer(); + + if (m_timeScheduled == rak::timer()) + throw torrent::internal_error("CommandSchedulerItem::next_time_scheduled() m_timeScheduled == rak::timer()."); + + rak::timer next = m_timeScheduled; + + // This should be done in a non-looping manner. + do { + next += rak::timer(m_interval) * 1000000; + } while (next <= cachedTime.round_seconds()); + + return next; +} diff --git a/src/command_scheduler_item.h b/src/command_scheduler_item.h index 3cfeb808..439ee186 100644 --- a/src/command_scheduler_item.h +++ b/src/command_scheduler_item.h @@ -48,8 +48,7 @@ public: bool is_queued() const { return m_task.is_queued(); } - //void enable() { enable(interval()); } - void enable(uint32_t first); + void enable(rak::timer t); void disable(); const std::string& key() const { return m_key; } @@ -61,6 +60,9 @@ public: uint32_t interval() const { return m_interval; } void set_interval(uint32_t v) { m_interval = v; } + rak::timer time_scheduled() const { return m_timeScheduled; } + rak::timer next_time_scheduled() const; + void set_slot(Slot::base_type* s) { m_task.set_slot(s); } private: @@ -71,6 +73,7 @@ private: std::string m_command; uint32_t m_interval; + rak::timer m_timeScheduled; rak::priority_item m_task; diff --git a/src/option_handler_rules.cc b/src/option_handler_rules.cc index b90048bd..99270f54 100644 --- a/src/option_handler_rules.cc +++ b/src/option_handler_rules.cc @@ -197,20 +197,23 @@ apply_encoding_list(Control* m, const std::string& arg) { void apply_schedule(Control* m, const std::string& arg) { - int first; - int interval; char key[21]; + char bufAbsolute[21]; + char bufInterval[21]; char command[2048]; - if (std::sscanf(arg.c_str(), "%20[^,],%i,%i,%2047[^\n]", key, &first, &interval, command) != 4) + if (std::sscanf(arg.c_str(), "%20[^,],%20[^,],%20[^,],%2047[^\n]", key, bufAbsolute, bufInterval, command) != 4) throw torrent::input_error("Invalid arguments to command."); + uint32_t absolute = CommandScheduler::parse_absolute(bufAbsolute); + uint32_t interval = CommandScheduler::parse_interval(bufInterval); + CommandSchedulerItem* item = *m->command_scheduler()->insert(rak::trim(std::string(key))); item->set_command(rak::trim(std::string(command))); item->set_interval(interval); - item->enable(first); + item->enable((cachedTime + rak::timer(absolute) * 1000000).round_seconds()); } void @@ -245,6 +248,8 @@ initialize_option_handler(Control* c) { variables->insert("max_open_files", new utils::VariableSlotValue(NULL, rak::ptr_fn(&torrent::set_max_open_files), "%i")); variables->insert("max_open_sockets", new utils::VariableSlotValue(NULL, rak::ptr_fn(&torrent::set_max_open_sockets), "%i")); + variables->insert("print", new utils::VariableSlotString<>(NULL, rak::mem_fn(control->core(), &core::Manager::push_log))); + // Old. variables->insert("port_range", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_port_range, c)));