Здравствуйте, господа.
Преамбула:
Неделю назад я купил себе дешёвый PC для организации на нём локального файл-сервера, роутера, качалки и прочих удобных сервисов, которые на десктопной машине держать надоело. Всё это дело крутится под gentoo.
Амбула:
Сегодня потратил вечер и немного подмоддил
wTorrent:
Теперь он выглядит вот так:
Из нововведений:
1. Теперь он показывает общий объём траффика, in/out.
2. Представленный в центре страницы график входящего/исходящего трафика.
Рассмотрим пункт первый. Реализация его проста:
Добавляем в планировщик rtorrent'а правила. Делается это через ctrl+x в клиенте или добавлением строки в конфиг и перезапуск.
schedule=export_traffic,0,15,«execute=/var/www/localhost/htdocs/wtorrent/schedule/passthrough,$get_up_total=,$get_down_total=,/var/www/localhost/htdocs/wtorrent/schedule/traffic.rtorrent»
это правило каждые 15 секунд в файл traffic.rtorrent через маленький скрипт passthrough
#!/bin/sh
echo $1 $2 > $3
будет писать 2 числа: исходящий и входящий объём трафика. Сделано это потому, что через xmlrpc отдаётся signed integer, которое при объёме трафика > 2Гб ожидаемо уходит в отрицательный диапазон :-) Как его научить отдавать большие числа я не нашёл — поэтому пришлось сделать такой костыль.
Теперь в rtorrent.cls.php добавим следующие три метода:
private function getTrafficInfo()
{
static $data;
if (!$data){
if (is_file('./schedule/traffic.rtorrent')) {
$data = file('./schedule/traffic.rtorrent');
$data = explode(' ', $data[0]);
} else {
$data = array(0, 0);
}
}
return $data;
}
public function getDownTotal()
{
if ($data = $this->getTrafficInfo()) {
return $this->getCorrectUnits($data[1]);
}
return $this->getCorrectUnits($this->get_info_rtorrent('get_down_total', false, false));
}
public function getUpTotal()
{
if ($data = $this->getTrafficInfo()) {
return $this->getCorrectUnits($data[0]);
}
return $this->getCorrectUnits($this->get_info_rtorrent('get_up_total', false, false));
}
которые просто извлекают из файла экспортируемые торрент-клиентом числа. Теперь в шаблоне menu.tpl.php просто покажем эти два числа:
{$str.dw_rate} {$web->getDownload()} ({$web->getDownTotal()})
{$str.up_rate} {$web->getUpload()} ({$web->getUpTotal()})
добавив их в скобки после блоков с текущей скоростью.
Задача рисования графика немногим более сложная.
Для её реализации мы добавляем ещё одно правило в планировщик:
schedule=import_traffic,0,60,«execute=/usr/bin/php,-f,/var/www/localhost/htdocs/wtorrent/schedule/bandwidth.php»
это правило каждую минуту запускает php-скрипт:
<?php
chdir(dirname(__FILE__));
$datafile = './traffic.rtorrent';
if (is_file($datafile)) {
$data = file($datafile);
list($out, $in) = explode(' ', $data[0]);
$out = (double)$out;
$in = (double)$in;
require_once '../conf/user.conf.php';
$db = new PDO(DB_STAT_DSN, DB_STAT_LOGIN, DB_STAT_PWD);
$qry = 'SELECT `in`, `out`, `time` FROM `bandwidth` ORDER BY `id` DESC LIMIT 1';
$stmt = $db->query($qry);
$delta_in = 0;
$delta_out = 0;
if ($row = $stmt->fetch()) {
if ($in >= $row['in'] && $out >= $row['out']) {
$delta_in = $in - $row['in'];
$delta_out = $out - $row['out'];
}
}
$db->query('INSERT INTO `bandwidth` (`in`, `delta_in`, `out`, `delta_out`, `period`) VALUES (' . $in . ', ' . $delta_in . ', ' . $out . ', ' . $delta_out . ", TIME_TO_SEC(TIMEDIFF(NOW(), '" . $row['time'] . "')))");
}
?>
Этот примитивный скрипт сравнивает текущие значения трафика в файле traffic.torrent и на основании этих данных записывает в базу текущие значения и разницу с предыдущими.
Вот схема БД и таблицы, в которую скрипт пишет данные:
CREATE DATABASE `rtorrent`
CHARACTER SET 'utf8'
COLLATE 'utf8_general_ci';
CREATE TABLE `bandwidth` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`in` BIGINT(20) DEFAULT NULL,
`delta_in` BIGINT(20) DEFAULT NULL,
`out` BIGINT(20) DEFAULT NULL,
`delta_out` BIGINT(20) DEFAULT NULL,
`time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`period` INTEGER(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `time` (`time`)
)ENGINE=MyISAM
AUTO_INCREMENT=1 ROW_FORMAT=FIXED CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
Осталось совсем немного :-) Скрипт, рисующий график будет использовать
jpgraph. Вот содержание самого скрипта:
<?php
include "../../lib/jpgraph/jpgraph.php";
include "../../lib/jpgraph/jpgraph_line.php";
include "../../lib/jpgraph/jpgraph_scatter.php";
include "../../lib/jpgraph/jpgraph_regstat.php";
include "../../conf/user.conf.php";
$db = new PDO(DB_STAT_DSN, DB_STAT_LOGIN, DB_STAT_PWD);
$stmt = $db->query('SELECT SUM(`delta_in`) / 1024 / SUM(`period`) AS `in`,
SUM(`delta_out`) / 1024 / SUM(`period`) AS `out`,
MAX(`time`) AS `time`
FROM `bandwidth`
WHERE `time` > DATE_SUB(NOW(), INTERVAL 12 HOUR)
GROUP BY CONCAT(DATE(`time`), HOUR(`time`), FLOOR(MINUTE(`time`) / 5))
ORDER BY `time`');
$x = $in = $out = array();
while ($row = $stmt->fetch()) {
$ts = strtotime($row['time']);
$x[] = $ts;
$in[] = $row['in'];
$out[] = $row['out'];
}
// Setup the basic graph
$graph = new Graph(800, 400);
$graph->SetMargin(30, 10, 0, 30);
$graph->title->Set('Bandwidth, KB/s');
$graph->SetAlphaBlending();
// Setup a manual x-scale (We leave the sentinels for the
// Y-axis at 0 which will then autoscale the Y-axis.)
// We could also use autoscaling for the x-axis but then it
// probably will start a little bit earlier than the first value
// to make the first value an even number as it sees the timestamp
// as an normal integer value.
$graph->SetScale("intlin", 0, max(max($out), max($in)) * 1.1, reset($x), end($x));
$graph->xgrid->Show();
$graph->yaxis->HideZeroLabel();
$graph->SetFrame(false);
function TimeCallback($aVal) {
return Date('H:i',$aVal);
}
// Setup the x-axis with a format callback to convert the timestamp
// to a user readable time
$graph->xaxis->SetLabelFormatCallback('TimeCallback');
//$graph->xaxis->SetLabelAngle(90);
// Create the line
$p1 = new LinePlot($out, $x);
$p1->SetColor("red");
$p2 = new LinePlot($in, $x);
$p2->SetColor("blue");
// Add lineplot to the graph
$graph->Add($p1);
$graph->Add($p2);
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-cache, must-revalidate");
header("Cache-Control: post-check=0,pre-check=0");
header("Cache-Control: max-age=0");
header("Pragma: no-cache");
// Output line
$graph->Stroke();
?>
Вначале мы подключаем необходимые библиотеки. Затем — простым запросом выбираем данные из базы. Причём аггрегируем их в интервалы по 5 минут, чтобы график получался более усреднённым и плавным. Затем — на основе примеров, идущих с jpgraph, «собираем» график нужного вида. Полученный код помещаем в файл wt/img/bandwidth.php.
Ну и самое последнее — отображение полученного графика на странице wtorrent.
Добавляем пункт меню. Это делается также в файле rtorrent.cls.php, добавлением элемента 'Graphic' => 'Graphic' в ассоциативный массив с меню menu_admin.
Потом — создаём класс, который будет управлять отображением страницы Graphic.cls.php:
<?php
class Graphic extends rtorrent
{
public function construct()
{
if(!$this->setClient())
{
return false;
}
}
}
?>
Ну и наконец создаём шаблон с единственной строчкой, которая и будет показывать график, graphic.tpl.php:

Всё, после этих нехитрых манипуляций у вас должно было получиться результат, сходный с тем, что я продемонстрировал выше. :-)
PS: все исходники, которые приводились выше, можно скачать
тут.