mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-08-06 10:12:30 +00:00
* Optimized view filtering and sorting.
git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@1213 e378c898-3ddf-0310-93e7-cc216c733640
This commit is contained in:
+34
-27
@@ -27,11 +27,11 @@ gnuplot << EOF
|
||||
# 4) throttle.global_down.rate
|
||||
# 5) throttle.global_down.total
|
||||
#
|
||||
# 9) pieces.memory.current
|
||||
# 10) pieces.memory.sync_queue
|
||||
# 11) pieces.memory.block_count
|
||||
# 12) pieces.stats.total_size
|
||||
# 13) pieces.hash.queue_size
|
||||
# 6) pieces.memory.current
|
||||
# 7) pieces.memory.sync_queue
|
||||
# 8) pieces.memory.block_count
|
||||
# 9) pieces.stats.total_size
|
||||
# 10) pieces.hash.queue_size
|
||||
#
|
||||
# schedule = log_bandwidth_stats,5,10,((execute,log_rtorrent.sh,((cat,/foo/bandwidth_stats.,((system.pid)))),((system.time_seconds)),((throttle.global_up.rate)),((throttle.global_up.total)),((throttle.global_down.rate)),((throttle.global_down.total)),((pieces.memory.current)),((pieces.memory.sync_queue)),((pieces.memory.block_count)),((pieces.stats.total_size)),((pieces.hash.queue_size))))
|
||||
#
|
||||
@@ -52,57 +52,64 @@ set terminal png size 1024,600
|
||||
set xdata time
|
||||
set timefmt "%s"
|
||||
set format x "%H:%M"
|
||||
set format y "%.0s %cb"
|
||||
set format y2 "%.0f"
|
||||
set y2tics
|
||||
set autoscale xfix
|
||||
|
||||
grab(x)=(x<min)?min=x:(x>max)?max=x:0;
|
||||
#div100(x)=(x/100)
|
||||
divrak(v)=(v>0)?-v:0;
|
||||
|
||||
set output "output_$1_sockets.png"
|
||||
plot "peer_stats.$1" using 1:7 smooth bezier with lines lw 4 title 'active',\
|
||||
"peer_stats.$1" using 1:5 smooth bezier with lines lw 4 title 'leeching',\
|
||||
"peer_stats.$1" using 1:6 smooth bezier with lines lw 4 title 'seeding',\
|
||||
"<awk '{x=1000; if (\$4 < 1000) x=\$4; print \$1,x}' peer_stats.$1" using 1:2 smooth bezier with lines lw 2 title 'open sockets' axis x1y2,\
|
||||
"peer_stats.$1" using 1:2 smooth bezier with lines lw 2 title 'upload unchoked' axis x1y2,\
|
||||
"peer_stats.$1" using 1:3 smooth bezier with lines lw 2 title 'download unchoked' axis x1y2
|
||||
|
||||
# "peer_stats.$1" using 1:4 smooth bezier with lines lw 2 title 'open sockets' axis x1y2,\
|
||||
|
||||
set format y "%.0s %cb"
|
||||
|
||||
set output "output_$1_bandwidth.png"
|
||||
plot "bandwidth_stats.$1" using 1:2 smooth bezier with lines lw 4 title 'Upload rate',\
|
||||
"bandwidth_stats.$1" using 1:4 smooth bezier with lines lw 4 title 'Download rate',\
|
||||
"bandwidth_stats.$1" using 1:6 smooth bezier with lines lw 2 title 'Upload unchoked' axis x1y2,\
|
||||
"bandwidth_stats.$1" using 1:7 smooth bezier with lines lw 2 title 'Download unchoked' axis x1y2
|
||||
"peer_stats.$1" using 1:2 smooth bezier with lines lw 2 title 'Upload unchoked' axis x1y2,\
|
||||
"peer_stats.$1" using 1:3 smooth bezier with lines lw 2 title 'Download unchoked' axis x1y2
|
||||
|
||||
set output "output_$1_memory.png"
|
||||
plot "bandwidth_stats.$1" using 1:9 smooth bezier with lines lw 4 title 'Memory usage' axis x1y1,\
|
||||
"bandwidth_stats.$1" using 1:6 smooth bezier with lines lw 2 title 'Upload unchoked' axis x1y2,\
|
||||
"bandwidth_stats.$1" using 1:7 smooth bezier with lines lw 2 title 'Download unchoked' axis x1y2
|
||||
plot "bandwidth_stats.$1" using 1:6 smooth bezier with lines lw 4 title 'Memory usage' axis x1y1,\
|
||||
"peer_stats.$1" using 1:2 smooth bezier with lines lw 2 title 'Upload unchoked' axis x1y2,\
|
||||
"peer_stats.$1" using 1:3 smooth bezier with lines lw 2 title 'Download unchoked' axis x1y2
|
||||
|
||||
#set yrange [0:3900000000.0]
|
||||
#set y2range [0:2000]
|
||||
|
||||
set output "output_$1_pieces.png"
|
||||
plot "bandwidth_stats.$1" using 1:9 smooth bezier with lines lw 4 title 'Memory usage' axis x1y1,\
|
||||
"bandwidth_stats.$1" using 1:10 smooth bezier with lines lw 4 title 'Sync queue Memory' axis x1y1,\
|
||||
plot "bandwidth_stats.$1" using 1:6 smooth bezier with lines lw 4 title 'Memory usage' axis x1y1,\
|
||||
"bandwidth_stats.$1" using 1:7 smooth bezier with lines lw 4 title 'Sync queue Memory' axis x1y1,\
|
||||
"<awk '{x=\$12*10; print \$1,x}' mincore_stats.$1" using 1:2 smooth bezier with lines lw 4 title 'Alloc /100s' axis x1y1,\
|
||||
"<awk '{x=\$13*10; print \$1,x}' mincore_stats.$1" using 1:2 smooth bezier with lines lw 4 title 'Dealloc /100s' axis x1y1,\
|
||||
"mincore_stats.$1" using 1:7 smooth bezier with lines lw 2 title 'Sync success /10s' axis x1y2,\
|
||||
"mincore_stats.$1" using 1:8 smooth bezier with lines lw 2 title 'Sync failed /10s' axis x1y2,\
|
||||
"mincore_stats.$1" using 1:7 smooth bezier with lines lw 2 title 'Sync success /10s' axis x1y2,\
|
||||
"mincore_stats.$1" using 1:8 smooth bezier with lines lw 2 title 'Sync failed /10s' axis x1y2,\
|
||||
"mincore_stats.$1" using 1:11 smooth bezier with lines lw 2 title 'Alloc failed /10s' axis x1y2,\
|
||||
"<awk '{x=\$11/10; print \$1,x}' bandwidth_stats.$1" using 1:2 smooth bezier with lines lw 2 title 'Block count /10' axis x1y2,\
|
||||
"bandwidth_stats.$1" using 1:13 smooth bezier with lines lw 2 title 'Hash queue count' axis x1y2
|
||||
# "<awk '{x=\$13/10; print \$1,x}' bandwidth_stats.$1" using 1:2 smooth bezier with lines lw 2 title 'Hash queue count /10' axis x1y2
|
||||
|
||||
"<awk '{x=\$8/10; print \$1,x}' bandwidth_stats.$1" using 1:2 smooth bezier with lines lw 2 title 'Block count /10' axis x1y2,\
|
||||
"bandwidth_stats.$1" using 1:10 smooth bezier with lines lw 2 title 'Hash queue count' axis x1y2
|
||||
|
||||
#set yrange [*:*]
|
||||
#set y2range [*:*]
|
||||
|
||||
set format y2 "%.0s %cb"
|
||||
set output "output_$1_torrents.png"
|
||||
plot "bandwidth_stats.$1" using 1:9 smooth bezier with lines lw 4 title 'Memory usage' axis x1y1,\
|
||||
"bandwidth_stats.$1" using 1:12 smooth bezier with lines lw 2 title 'Pieces total size' axis x1y2
|
||||
plot "bandwidth_stats.$1" using 1:6 smooth bezier with lines lw 4 title 'Memory usage' axis x1y1,\
|
||||
"bandwidth_stats.$1" using 1:9 smooth bezier with lines lw 2 title 'Pieces total size' axis x1y2
|
||||
|
||||
set format y "%.0f"
|
||||
|
||||
set output "output_$1_incore.png"
|
||||
plot "bandwidth_stats.$1" using 1:(0) smooth bezier with lines title '',\
|
||||
"mincore_stats.$1" using 1:2 smooth bezier with lines lw 2 title 'Incore cont.' axis x1y1,\
|
||||
"mincore_stats.$1" using 1:3 smooth bezier with lines lw 4 title 'Incore new' axis x1y2,\
|
||||
"mincore_stats.$1" using 1:4 smooth bezier with lines lw 2 title 'Not incore cont.' axis x1y1,\
|
||||
"mincore_stats.$1" using 1:5 smooth bezier with lines lw 4 title 'Not incore new' axis x1y2
|
||||
"mincore_stats.$1" using 1:2 smooth bezier with lines lw 2 title 'Incore cont. /10s' axis x1y1,\
|
||||
"mincore_stats.$1" using 1:3 smooth bezier with lines lw 4 title 'Incore new /10s' axis x1y2,\
|
||||
"mincore_stats.$1" using 1:4 smooth bezier with lines lw 2 title 'Not incore cont. /10s' axis x1y1,\
|
||||
"mincore_stats.$1" using 1:5 smooth bezier with lines lw 4 title 'Not incore new /10s' axis x1y2
|
||||
|
||||
EOF
|
||||
|
||||
+54
-16
@@ -53,7 +53,8 @@
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
|
||||
typedef void (core::ViewManager::*view_cfilter_slot)(const std::string&, const std::string&);
|
||||
typedef void (core::ViewManager::*view_cfilter_slot)(const std::string&, const torrent::Object&);
|
||||
typedef void (core::ViewManager::*view_event_slot)(const std::string&, const std::string&);
|
||||
|
||||
torrent::Object
|
||||
apply_view_filter_on(const torrent::Object::list_type& args) {
|
||||
@@ -82,6 +83,21 @@ apply_view_cfilter(view_cfilter_slot viewFilterSlot, const torrent::Object::list
|
||||
|
||||
const std::string& name = args.front().as_string();
|
||||
|
||||
if (name.empty())
|
||||
throw torrent::input_error("First argument must be a string.");
|
||||
|
||||
(control->view_manager()->*viewFilterSlot)(name, args.back());
|
||||
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_view_event(view_event_slot viewFilterSlot, const torrent::Object::list_type& args) {
|
||||
if (args.size() != 2)
|
||||
throw torrent::input_error("Too few arguments.");
|
||||
|
||||
const std::string& name = args.front().as_string();
|
||||
|
||||
if (name.empty())
|
||||
throw torrent::input_error("First argument must be a string.");
|
||||
|
||||
@@ -156,7 +172,7 @@ apply_cat(rpc::target_type target, const torrent::Object& rawArgs) {
|
||||
|
||||
// Move these boolean operators to a new file.
|
||||
|
||||
bool
|
||||
inline bool
|
||||
as_boolean(const torrent::Object& rawArgs) {
|
||||
switch (rawArgs.type()) {
|
||||
case torrent::Object::TYPE_VALUE: return rawArgs.as_value();
|
||||
@@ -169,6 +185,11 @@ as_boolean(const torrent::Object& rawArgs) {
|
||||
|
||||
torrent::Object
|
||||
apply_not(rpc::target_type target, const torrent::Object& rawArgs) {
|
||||
if (rawArgs.is_dict_key())
|
||||
return (int64_t)!as_boolean(rpc::commands.call_command(rawArgs.as_dict_key().c_str(),
|
||||
rawArgs.as_dict_obj(),
|
||||
target));
|
||||
|
||||
return (int64_t)!as_boolean(rawArgs);
|
||||
}
|
||||
|
||||
@@ -183,8 +204,14 @@ apply_and(rpc::target_type target, const torrent::Object& rawArgs) {
|
||||
return as_boolean(rawArgs);
|
||||
|
||||
for (torrent::Object::list_const_iterator itr = rawArgs.as_list().begin(), last = rawArgs.as_list().end(); itr != last; itr++)
|
||||
if (!as_boolean(rpc::parse_command_single(target, itr->as_string())))
|
||||
return (int64_t)false;
|
||||
if (itr->is_dict_key()) {
|
||||
if (!as_boolean(rpc::commands.call_command(itr->as_dict_key().c_str(), itr->as_dict_obj(), target)))
|
||||
return (int64_t)false;
|
||||
|
||||
} else {
|
||||
if (!as_boolean(rpc::parse_command_single(target, itr->as_string())))
|
||||
return (int64_t)false;
|
||||
}
|
||||
|
||||
return (int64_t)true;
|
||||
}
|
||||
@@ -195,8 +222,14 @@ apply_or(rpc::target_type target, const torrent::Object& rawArgs) {
|
||||
return as_boolean(rawArgs);
|
||||
|
||||
for (torrent::Object::list_const_iterator itr = rawArgs.as_list().begin(), last = rawArgs.as_list().end(); itr != last; itr++)
|
||||
if (as_boolean(rpc::parse_command_single(target, itr->as_string())))
|
||||
return (int64_t)true;
|
||||
if (itr->is_dict_key()) {
|
||||
if (as_boolean(rpc::commands.call_command(itr->as_dict_key().c_str(), itr->as_dict_obj(), target)))
|
||||
return (int64_t)true;
|
||||
|
||||
} else {
|
||||
if (as_boolean(rpc::parse_command_single(target, itr->as_string())))
|
||||
return (int64_t)true;
|
||||
}
|
||||
|
||||
return (int64_t)false;
|
||||
}
|
||||
@@ -215,13 +248,18 @@ apply_cmp(rpc::target_type target, const torrent::Object::list_type& args) {
|
||||
torrent::Object result1;
|
||||
torrent::Object result2;
|
||||
|
||||
if (rpc::is_target_pair(target)) {
|
||||
result1 = rpc::parse_command_single(rpc::get_target_left(target), args.front().as_string());
|
||||
result2 = rpc::parse_command_single(rpc::get_target_right(target), args.back().as_string());
|
||||
} else {
|
||||
result1 = rpc::parse_command_single(target, args.front().as_string());
|
||||
result2 = rpc::parse_command_single(target, args.back().as_string());
|
||||
}
|
||||
rpc::target_type target1 = rpc::is_target_pair(target) ? rpc::get_target_left(target) : target;
|
||||
rpc::target_type target2 = rpc::is_target_pair(target) ? rpc::get_target_right(target) : target;
|
||||
|
||||
if (args.front().is_dict_key())
|
||||
result1 = rpc::commands.call_command(args.front().as_dict_key().c_str(), args.front().as_dict_obj(), target1);
|
||||
else
|
||||
result1 = rpc::parse_command_single(target1, args.front().as_string());
|
||||
|
||||
if (args.back().is_dict_key())
|
||||
result2 = rpc::commands.call_command(args.back().as_dict_key().c_str(), args.back().as_dict_obj(), target2);
|
||||
else
|
||||
result2 = rpc::parse_command_single(target2, args.back().as_string());
|
||||
|
||||
if (result1.type() != result2.type())
|
||||
throw torrent::input_error("Type mismatch.");
|
||||
@@ -410,7 +448,7 @@ torrent::Object
|
||||
cmd_view_persistent(const torrent::Object::string_type& args) {
|
||||
core::View* view = *control->view_manager()->find_throw(args);
|
||||
|
||||
if (!view->get_filter().empty() || !view->get_event_added().empty() || !view->get_event_removed().empty())
|
||||
if (!view->get_filter().is_empty() || !view->get_event_added().empty() || !view->get_event_removed().empty())
|
||||
throw torrent::input_error("Cannot set modified views as persitent.");
|
||||
|
||||
view->set_filter("d.views.has=" + args);
|
||||
@@ -471,8 +509,8 @@ initialize_command_ui() {
|
||||
CMD2_ANY_LIST("view.sort_new", std::bind(&apply_view_cfilter, &core::ViewManager::set_sort_new, std::placeholders::_2));
|
||||
CMD2_ANY_LIST("view.sort_current", std::bind(&apply_view_cfilter, &core::ViewManager::set_sort_current, std::placeholders::_2));
|
||||
|
||||
CMD2_ANY_LIST("view.event_added", std::bind(&apply_view_cfilter, &core::ViewManager::set_event_added, std::placeholders::_2));
|
||||
CMD2_ANY_LIST("view.event_removed", std::bind(&apply_view_cfilter, &core::ViewManager::set_event_removed, std::placeholders::_2));
|
||||
CMD2_ANY_LIST("view.event_added", std::bind(&apply_view_event, &core::ViewManager::set_event_added, std::placeholders::_2));
|
||||
CMD2_ANY_LIST("view.event_removed", std::bind(&apply_view_event, &core::ViewManager::set_event_removed, std::placeholders::_2));
|
||||
|
||||
// Cleanup and add . to view.
|
||||
|
||||
|
||||
+39
-8
@@ -55,14 +55,28 @@ namespace core {
|
||||
|
||||
// Also add focus thingie here?
|
||||
struct view_downloads_compare : std::binary_function<Download*, Download*, bool> {
|
||||
view_downloads_compare(const std::string& cmd) : m_command(cmd) {}
|
||||
view_downloads_compare(const torrent::Object& cmd) : m_command(cmd) {}
|
||||
|
||||
bool operator () (Download* d1, Download* d2) const {
|
||||
try {
|
||||
if (m_command.empty())
|
||||
if (m_command.is_empty())
|
||||
return false;
|
||||
|
||||
return rpc::parse_command_single(rpc::make_target_pair(d1, d2), m_command).as_value();
|
||||
if (!m_command.is_dict_key())
|
||||
return rpc::parse_command_single(rpc::make_target_pair(d1, d2), m_command.as_string()).as_value();
|
||||
|
||||
// torrent::Object tmp_command = m_command;
|
||||
|
||||
// uint32_t flags = tmp_command.flags() & torrent::Object::mask_function;
|
||||
// tmp_command.unset_flags(torrent::Object::mask_function);
|
||||
// tmp_command.set_flags((flags >> 1) & torrent::Object::mask_function);
|
||||
|
||||
// rpc::parse_command_execute(rpc::make_target_pair(d1, d2), &tmp_command);
|
||||
// return rpc::commands.call_command(tmp_command.as_dict_key().c_str(), tmp_command.as_dict_obj(),
|
||||
// rpc::make_target_pair(d1, d2)).as_value();
|
||||
|
||||
return rpc::commands.call_command(m_command.as_dict_key().c_str(), m_command.as_dict_obj(),
|
||||
rpc::make_target_pair(d1, d2)).as_value();
|
||||
|
||||
} catch (torrent::input_error& e) {
|
||||
control->core()->push_log(e.what());
|
||||
@@ -71,18 +85,35 @@ struct view_downloads_compare : std::binary_function<Download*, Download*, bool>
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& m_command;
|
||||
const torrent::Object& m_command;
|
||||
};
|
||||
|
||||
struct view_downloads_filter : std::unary_function<Download*, bool> {
|
||||
view_downloads_filter(const std::string& cmd) : m_command(cmd) {}
|
||||
view_downloads_filter(const torrent::Object& cmd) : m_command(cmd) {}
|
||||
|
||||
bool operator () (Download* d1) const {
|
||||
if (m_command.empty())
|
||||
if (m_command.is_empty())
|
||||
return true;
|
||||
|
||||
try {
|
||||
torrent::Object result = rpc::parse_command_single(rpc::make_target(d1), m_command);
|
||||
torrent::Object result;
|
||||
|
||||
if (m_command.is_dict_key()) {
|
||||
// torrent::Object tmp_command = m_command;
|
||||
|
||||
// uint32_t flags = tmp_command.flags() & torrent::Object::mask_function;
|
||||
// tmp_command.unset_flags(torrent::Object::mask_function);
|
||||
// tmp_command.set_flags((flags >> 1) & torrent::Object::mask_function);
|
||||
|
||||
// rpc::parse_command_execute(rpc::make_target(d1), &tmp_command);
|
||||
// result = rpc::commands.call_command(tmp_command.as_dict_key().c_str(), tmp_command.as_dict_obj(),
|
||||
// rpc::make_target(d1));
|
||||
|
||||
result = rpc::commands.call_command(m_command.as_dict_key().c_str(), m_command.as_dict_obj(), rpc::make_target(d1));
|
||||
|
||||
} else {
|
||||
result = rpc::parse_command_single(rpc::make_target(d1), m_command.as_string());
|
||||
}
|
||||
|
||||
switch (result.type()) {
|
||||
// case torrent::Object::TYPE_RAW_BENCODE: return !result.as_raw_bencode().empty();
|
||||
@@ -104,7 +135,7 @@ struct view_downloads_filter : std::unary_function<Download*, bool> {
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& m_command;
|
||||
const torrent::Object& m_command;
|
||||
};
|
||||
|
||||
inline void
|
||||
|
||||
+8
-7
@@ -54,6 +54,7 @@
|
||||
#include <vector>
|
||||
#include <rak/timer.h>
|
||||
#include <sigc++/signal.h>
|
||||
#include <torrent/object.h>
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
@@ -115,15 +116,15 @@ public:
|
||||
|
||||
void sort();
|
||||
|
||||
void set_sort_new(const std::string& s) { m_sortNew = s; }
|
||||
void set_sort_current(const std::string& s) { m_sortCurrent = s; }
|
||||
void set_sort_new(const torrent::Object& s) { m_sortNew = s; }
|
||||
void set_sort_current(const torrent::Object& s) { m_sortCurrent = s; }
|
||||
|
||||
// Need to explicity trigger filtering.
|
||||
void filter();
|
||||
void filter_download(core::Download* download);
|
||||
|
||||
const std::string& get_filter() const { return m_filter; }
|
||||
void set_filter(const std::string& s) { m_filter = s; }
|
||||
const torrent::Object& get_filter() const { return m_filter; }
|
||||
void set_filter(const torrent::Object& s) { m_filter = s; }
|
||||
void set_filter_on_event(const std::string& event);
|
||||
|
||||
void clear_filter_on();
|
||||
@@ -167,10 +168,10 @@ private:
|
||||
size_type m_focus;
|
||||
|
||||
// These should be replaced by a faster non-string command type.
|
||||
std::string m_sortNew;
|
||||
std::string m_sortCurrent;
|
||||
torrent::Object m_sortNew;
|
||||
torrent::Object m_sortCurrent;
|
||||
|
||||
std::string m_filter;
|
||||
torrent::Object m_filter;
|
||||
event_list_type m_events;
|
||||
|
||||
std::string m_eventAdded;
|
||||
|
||||
@@ -102,7 +102,7 @@ ViewManager::sort(const std::string& name, uint32_t timeout) {
|
||||
}
|
||||
|
||||
void
|
||||
ViewManager::set_filter(const std::string& name, const std::string& cmd) {
|
||||
ViewManager::set_filter(const std::string& name, const torrent::Object& cmd) {
|
||||
iterator viewItr = find_throw(name);
|
||||
|
||||
(*viewItr)->set_filter(cmd);
|
||||
|
||||
@@ -88,10 +88,10 @@ public:
|
||||
void sort(const std::string& name, uint32_t timeout = 0);
|
||||
|
||||
// These could be moved to where the command is implemented.
|
||||
void set_sort_new(const std::string& name, const std::string& cmd) { (*find_throw(name))->set_sort_new(cmd); }
|
||||
void set_sort_current(const std::string& name, const std::string& cmd) { (*find_throw(name))->set_sort_current(cmd); }
|
||||
void set_sort_new(const std::string& name, const torrent::Object& cmd) { (*find_throw(name))->set_sort_new(cmd); }
|
||||
void set_sort_current(const std::string& name, const torrent::Object& cmd) { (*find_throw(name))->set_sort_current(cmd); }
|
||||
|
||||
void set_filter(const std::string& name, const std::string& cmd);
|
||||
void set_filter(const std::string& name, const torrent::Object& cmd);
|
||||
void set_filter_on(const std::string& name, const filter_args& args);
|
||||
|
||||
void set_event_added(const std::string& name, const std::string& cmd) { (*find_throw(name))->set_event_added(cmd); }
|
||||
|
||||
+20
-20
@@ -260,54 +260,54 @@ main(int argc, char** argv) {
|
||||
"view.add = default\n"
|
||||
|
||||
"view.add = name\n"
|
||||
"view.sort_new = name,less=d.name=\n"
|
||||
"view.sort_current = name,less=d.name=\n"
|
||||
"view.sort_new = name,((less,((d.name))))\n"
|
||||
"view.sort_current = name,((less,((d.name))))\n"
|
||||
|
||||
"view.add = active\n"
|
||||
"view.filter = active,false=\n"
|
||||
"view.filter = active,((false))\n"
|
||||
|
||||
"view.add = started\n"
|
||||
"view.filter = started,false=\n"
|
||||
"view.filter = started,((false))\n"
|
||||
"view.event_added = started,\"view.set_not_visible=stopped ;d.state.set=1 ;scheduler.simple.added=\"\n"
|
||||
"view.event_removed = started,\"view.set_visible=stopped ;scheduler.simple.removed=\"\n"
|
||||
|
||||
"view.add = stopped\n"
|
||||
"view.filter = stopped,false=\n"
|
||||
"view.filter = stopped,((false))\n"
|
||||
"view.event_added = stopped,\"view.set_not_visible=started ;d.state.set=0\"\n"
|
||||
"view.event_removed = stopped,view.set_visible=started\n"
|
||||
|
||||
"view.add = complete\n"
|
||||
"view.filter = complete,d.complete=\n"
|
||||
"view.filter = complete,((d.complete))\n"
|
||||
"view.filter_on = complete,event.download.hash_done,event.download.hash_failed,event.download.hash_final_failed,event.download.finished\n"
|
||||
"view.sort_new = complete,less=d.state_changed=\n"
|
||||
"view.sort_current = complete,less=d.state_changed=\n"
|
||||
// "view.sort_new = complete,((less,((d.state_changed))))\n"
|
||||
// "view.sort_current = complete,((less,((d.state_changed))))\n"
|
||||
|
||||
"view.add = incomplete\n"
|
||||
"view.filter = incomplete,not=$d.complete=\n"
|
||||
"view.filter = incomplete,((not,((d.complete))))\n"
|
||||
"view.filter_on = incomplete,event.download.hash_done,event.download.hash_failed,"
|
||||
"event.download.hash_final_failed,event.download.finished\n"
|
||||
"view.sort_new = incomplete,less=d.state_changed=\n"
|
||||
"view.sort_current = incomplete,less=d.state_changed=\n"
|
||||
"event.download.hash_final_failed,event.download.finished\n"
|
||||
// "view.sort_new = incomplete,((less,((d.state_changed))))\n"
|
||||
// "view.sort_current = incomplete,((less,((d.state_changed))))\n"
|
||||
|
||||
// The hashing view does not include stopped torrents.
|
||||
"view.add = hashing\n"
|
||||
"view.filter = hashing,d.hashing=\n"
|
||||
"view.filter = hashing,((d.hashing))\n"
|
||||
"view.filter_on = hashing,event.download.hash_queued,event.download.hash_removed,"
|
||||
"event.download.hash_done,event.download.hash_failed,event.download.hash_final_failed\n"
|
||||
"event.download.hash_done,event.download.hash_failed,event.download.hash_final_failed\n"
|
||||
// "view.sort_new = hashing,less=d.state_changed=\n"
|
||||
// "view.sort_current = hashing,less=d.state_changed=\n"
|
||||
|
||||
"view.add = seeding\n"
|
||||
"view.filter = seeding,\"and=d.state=,d.complete=\"\n"
|
||||
"view.filter = seeding,((and,((d.state)),((d.complete))))\n"
|
||||
"view.filter_on = seeding,event.download.resumed,event.download.paused,event.download.finished\n"
|
||||
"view.sort_new = seeding,less=d.state_changed=\n"
|
||||
"view.sort_current = seeding,less=d.state_changed=\n"
|
||||
// "view.sort_new = seeding,((less,((d.state_changed))))\n"
|
||||
// "view.sort_current = seeding,((less,((d.state_changed))))\n"
|
||||
|
||||
"view.add = leeching\n"
|
||||
"view.filter = leeching,\"and=d.state=,not=$d.complete=\"\n"
|
||||
"view.filter = leeching,((and,((d.state)),((not,((d.complete))))))\n"
|
||||
"view.filter_on = leeching,event.download.resumed,event.download.paused,event.download.finished\n"
|
||||
"view.sort_new = leeching,less=d.state_changed=\n"
|
||||
"view.sort_current = leeching,less=d.state_changed=\n"
|
||||
// "view.sort_new = leeching,((less,((d.state_changed))))\n"
|
||||
// "view.sort_current = leeching,((less,((d.state_changed))))\n"
|
||||
|
||||
"schedule2 = view.main,10,10,((view.sort,main,20))\n"
|
||||
"schedule2 = view.name,10,10,((view.sort,name,20))\n"
|
||||
|
||||
@@ -106,6 +106,8 @@ CommandScheduler::call_item(value_type item) {
|
||||
|
||||
// Unquote the root function object so 'parse_command_execute'
|
||||
// doesn't end up calling it.
|
||||
//
|
||||
// TODO: Only call this if mask_function is set?
|
||||
uint32_t flags = tmp_command.flags() & torrent::Object::mask_function;
|
||||
tmp_command.unset_flags(torrent::Object::mask_function);
|
||||
tmp_command.set_flags((flags >> 1) & torrent::Object::mask_function);
|
||||
|
||||
+20
-18
@@ -67,32 +67,34 @@ parse_string(const char* first, const char* last, std::string* dest, bool (*deli
|
||||
if (first == last)
|
||||
return first;
|
||||
|
||||
bool quoted = parse_is_quote(*first);
|
||||
|
||||
if (quoted)
|
||||
if (parse_is_quote(*first)) {
|
||||
first++;
|
||||
|
||||
while (first != last) {
|
||||
if (quoted) {
|
||||
while (first != last) {
|
||||
if (parse_is_quote(*first))
|
||||
return ++first;
|
||||
|
||||
} else {
|
||||
if (delim(*first))
|
||||
return first;
|
||||
}
|
||||
|
||||
if (parse_is_escape(*first) && ++first == last)
|
||||
throw torrent::input_error("Escape character at end of input.");
|
||||
if (parse_is_escape(*first) && ++first == last)
|
||||
throw torrent::input_error("Escape character at end of input.");
|
||||
|
||||
dest->push_back(*first++);
|
||||
}
|
||||
|
||||
dest->push_back(*first);
|
||||
first++;
|
||||
}
|
||||
|
||||
if (quoted)
|
||||
throw torrent::input_error("Missing closing quote.");
|
||||
|
||||
return first;
|
||||
} else {
|
||||
while (first != last) {
|
||||
if (delim(*first))
|
||||
return first;
|
||||
|
||||
if (parse_is_escape(*first) && ++first == last)
|
||||
throw torrent::input_error("Escape character at end of input.");
|
||||
|
||||
dest->push_back(*first++);
|
||||
}
|
||||
|
||||
return first;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
+19
-15
@@ -112,6 +112,21 @@ parse_command_execute(target_type target, torrent::Object* object) {
|
||||
}
|
||||
}
|
||||
|
||||
// Use a static length buffer for dest.
|
||||
inline const char*
|
||||
parse_command_name(const char* first, const char* last, char* dest_first, char* dest_last) {
|
||||
if (first == last || !std::isalpha(*first))
|
||||
throw torrent::input_error("Invalid start of command name.");
|
||||
|
||||
last = first + std::min(std::distance(first, last), std::distance(dest_first, dest_last) - 1);
|
||||
|
||||
while (first != last && (std::isalnum(*first) || *first == '_' || *first == '.'))
|
||||
*dest_first++ = *first++;
|
||||
|
||||
*dest_first = '\0';
|
||||
return first;
|
||||
}
|
||||
|
||||
// Set 'download' to NULL to call the generic functions, thus reusing
|
||||
// the code below for both cases.
|
||||
parse_command_type
|
||||
@@ -121,8 +136,9 @@ parse_command(target_type target, const char* first, const char* last) {
|
||||
if (first == last || *first == '#')
|
||||
return std::make_pair(torrent::Object(), first);
|
||||
|
||||
std::string key;
|
||||
first = parse_command_name(first, last, &key);
|
||||
char key[128];
|
||||
|
||||
first = parse_command_name(first, last, key, key + 128);
|
||||
first = std::find_if(first, last, std::not1(command_map_is_space()));
|
||||
|
||||
if (first == last || *first != '=')
|
||||
@@ -147,7 +163,7 @@ parse_command(target_type target, const char* first, const char* last) {
|
||||
// following command.
|
||||
parse_command_execute(target, &args);
|
||||
|
||||
return std::make_pair(commands.call_command(key.c_str(), args, target), first);
|
||||
return std::make_pair(commands.call_command(key, args, target), first);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
@@ -223,18 +239,6 @@ parse_command_file(const std::string& path) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use a static length buffer for dest.
|
||||
const char*
|
||||
parse_command_name(const char* first, const char* last, std::string* dest) {
|
||||
if (first == last || !std::isalpha(*first))
|
||||
throw torrent::input_error("Invalid start of name.");
|
||||
|
||||
for ( ; first != last && (std::isalnum(*first) || *first == '_' || *first == '.'); ++first)
|
||||
dest->push_back(*first);
|
||||
|
||||
return first;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user