Как часто вы пользуетесь гаджетами боковой панели Windows? А хотелось бы написать свой? Не простой гаджет «Hello World», а действительно полезный, который помог бы оптимизировать затраты времени на определенный кусок работы. Тогда давайте рассмотрим случай, когда вам нужно мониторить нагрузку 10-20 серверов.
Моя профессиональная деятельность связана с разработкой VoD сервисов. Приходящие от кинокомпаний фильмы в формате MPEG2 сервис перекодирует в нужные форматы. Для кодирования используются 20 серверов. Нагрузка на сервер мониторится не по загруженности процессора, а исходя из количества задач, которые были поставлены на сервер. Данная информация хранится и постоянно обновляется в базе данных. В любом случае у вас должен быть server side скрипт и веб-сервер, который будет отдавать результат гаджету.
Следить за постоянной нагрузкой серверов и сбоями можно напрямую через запрос в базу или модуль административной зоны проекта. Оба варианта не дают оперативно и удобно реализовать сам процесс. Выход есть – написать свой Windows Sidebar Gadget, который будет трудолюбиво, самостоятельно вести мониторинг серверов и уведомлять о любых простоях и неполадках.
Сестра, скальпель
Гаджет – это обыкновенный zip-файл, который внутри себя хранит нужную информацию для развертывания. Сам гаджет – это набор HTML, CSS, JavaScript файлов, изображений и т.д.
Гаджет состоит из нескольких файлов с условными названиями:
- gadget.xml – манифест, который описывает гаджет: название, автора, версию, права, и т.д. Единственный файл, который должен иметь именно такое имя
- основное окно гаджета
- Flyout — дополнительное окно позволяющая расширить интерфейс гаджета
- Settings – окно для сохранения параметров гаджета
Для управления поведением, видом гаджета,, хранения данных используется специальный объект System.Gadget.
gadget.xml
Мы укажем в манифесте минимально нужную информацию.
<?xml version="1.0" encoding="utf-8" ?>
<gadget>
<name>DivX Server Monitor</name>
<version>2.0</version>
<author name="Евгений Жарков">
<info url="jeje.habrahabr.ru" />
</author>
<hosts>
<host name="sidebar">
<base type="HTML" apiVersion="1.0.0" src="gadget.html" />
<permissions>full</permissions>
<platform minPlatformVersion="0.3" />
</host>
</hosts>
</gadget>
Обратите внимание на строчку, в которой мы указываем гаджету, какой использовать html файл для основного окна.
<base type="HTML" apiVersion="1.0.0" src="gadget.html" />
Детальнее с описанием манифеста можно ознакомится в MSDN.
Основное окно
Разметка основного окна ничем не отличается от разметки любой другой веб-страницы. Вдобавок нам предоставляют несколько исключительно гаджетовских тегов. Для задания фона гаджета, используется тег g:background. Любое содержимое, размещенное в данном элементе будет фоновым для всего основного окна.
<g:background id="background" style="position:absolute;z-index:-1;top:0;left:0;" opacity="0"></g:background>
Я не стал делать задний фон гаджету, с помощью параметра opacity=«0» фон стал абсолютно прозрачным.
Тело страницы довольно простое верхний div служит для отображения статуса гаджета, позволяет увидеть, сколько минут осталось до обновления данных, а также поддерживает ручное обновление. Нижний div будет содержать в себе список серверов.
<div id="status"><a href="javascript:void(0)" id="statusLink">Loading...</a></div>
<div id="content">
<ul id="serverList"></ul>
</div>
Все стили, JavaScript вынесены во внешние файлы. Для удобства была подключена библиотека jQuery. Целиком разметка основного окна крохотная.
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" href="./style/gadget.css" />
<script type="text/javascript" src="./js/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="./js/gadget.js"></script>
</head>
<body onload="startMonitoring()">
<g:background id="background" style="position:absolute;z-index:-1;top:0;left:0;" opacity="0"></g:background>
<div id="status"><a href="javascript:void(0)" id="statusLink">Loading...</a></div>
<div id="content">
<ul id="serverList"></ul>
</div>
</body>
</html>
В CSS хотелось обратить внимание только на стили, которые описывают цвет ячейки сервера, в зависимости от его состояния.
ul#serverList li.busyLight
{
background: #fefe8c;
}
ul#serverList li.busy
{
background: #ffb154;
}
ul#serverList li.free
{
background: #d2e582;
}
ul#serverList li.down
{
background: #dc6161;
}
Темная сторона, Люк
Самый главный файл – JavaScript. Сразу оговорюсь, alert и confirm в гаджетах не работают. Для отладки гаджета, можно воспользоваться Visual Studio, но для этого нужно выполнить два хитрых действия. Прежде всего, включить отладчик JavaScript в Internet Explorer
Добавить в нужном месте кода гаджета строку:
debugger;
и перезапустить гаджет.
Мы объявляем две глобальных переменных, которые отвечают за время в минутах для обновления данных в гаджете, для меня оптимально 30 минут, а также счетчик отсчета оставшихся минут до обновления
var updateInterval = 30;
var updateMinutes = updateInterval;
Функция init содержит действия для инициализации гаджета, мне в данном случае было нужно установить прозрачность гаджета на 40%, чтобы он не перекрывал полностью кусочек рабочего стола.
function init() {
System.Gadget.Settings.write("PrivateSetting_GadgetOpacity", 40);
}
Функция запуска самого мониторинга, которая обновляет список серверов с их статусом, устанавливает интервал обновления данных, таймера в главном окне и так же добавляет обработчик события для ручного обновления статуса серверов.
function startMonitoring() {
init();
updateList();
setInterval(updateList, updateInterval * 1000 * 60);
setInterval(updateTimer, 1000 * 60);
statusLink.onclick = function() {
updateList();
}
}
Добавление обработчика на нажатие происходит в данном случае двумя способами:
element.onclick = function(){}
$(element).get(0).onclick = function(){}
Продвинутые способы в гаджетах не работают:
element.attachEvent('onclick', function(){})
$(element).bind('click', function(){})
Для обновления самого таймера маленькая функция updateTimer, которая каждую минуту рассчитывает сколько времени осталось до обновления.
function updateTimer() {
updateMinutes = updateMinutes == 0 ? updateInterval : updateMinutes - 1;
$('#statusLink').html('Update in ' + updateMinutes + ' m.');
}
И наконец, обновление списка серверов, для возвращенных данных я использую JSON, вид ответа примерно такой:
[{«ip»:"***.45.**.60",«lastHitTime»:«2009-09-06 00:07:24»,«runningTasks»:«1»}]
Для получения самих данных – getJSON. Вы можете использовать и AJAX, он прекрасно работает в гаджетах. Прежде всего, используя getJSON мы можем отлаживать код в браузере, не добавляя его в гаджет, AJAX нам такое сделать не позволит. В зависимости от загрузки сервера, я закрашиваю ячейку разным фоном. Одновременно выполняемых задач может быть всего две, мало, но каждая из них выполняется 1,5-2 часа. Так же дополнительная проверка, давно ли отзывался сервер.
function updateList() {
$('#statusLink').html('Loading...');
list = '';
$.getJSON('https://mysite.com/getServerStatus.php', function(json) {
$.each(json, function(i, server) {
status = '';
if (server.runningTasks == 0) {
status = "free";
} else if (server. runningTasks == 1) {
status = "busyLight";
} else if (server. runningTasks == 2) {
status = "busy";
}
hit = new Date(server.lastHitTime);
now = new Date();
if (now.getTime() - hit.getTime() >= 1000 * 60 * 60 * 3 + 1000 * 120) {
status = 'down';
}
list += '<li class="' + status + '">' + server.ip + '</li>';
});
$('#serverList').html(list);
});
$('#statusLink').html('Updated');
}
Код готов к употреблению, осталось несколько взмахов волшебно палочкой. Пакуем все файлы проекта в zip-архив.
Далее следует изменить расширения файла на .gadget
И добавить гаджет в систему, пытаясь открыть файл monitoringS.gadget
Вуаля, у нас появляется опрятный и скромный гаджет со списком серверов. Пример со 100% и 40% прозрачностью.
Я уверен, что у каждого из нас, есть похожие задачи и проблемы, так почему бы не сделать их красивее, удобнее?
Дополнительные материалы:
- Отличная статья по описанию разработке Windows гаджетов на Design For Masters
- официальный раздел MSDN