Основы Opera Unite для разработчиков

By Vadim Makeev

В соавторстве с Arve, Chris, Zi Bin и Lissy.

Введение

Opera Unite представляет из себя веб-сервер, работающий внутри браузера Opera, который позволяет делать удивительные вещи. Одним нажатием на кнопку вы можете поделиться картинками, документами, видео, музыкой, совместными играми и множеством других вещей с друзьями и коллегами.

Эта статья поможет вам начать путь по дороге разработки сервисов для Opera Unite — она описывает то, как сервер Opera Unite работает и что он может. Ниже я коротко расскажу вам о базовых идеях Opera Unite, покажу как запустить веб-сервер в вашем браузере и продемонстрирую пример того как написать сервис для Opera Unite в виде простого блога.

Содержание статьи по порядку:

Основные понятия

Что такое Opera Unite?

Opera Unite, если коротко, это веб-сервер, который работает внутри браузера Opera. Этот веб-сервер позволяет пользователю устанавливать сервисы и использовать их вместе с друзьями, коллегами или сразу со всеми, при желании. Всё взаимодействие происходит через центральный сервер Opera Unite, для чего Opera Unite использует прокси между сервером и его клиентами (operaunite.com), чтобы избежать дополнительной настройки файрвола.

Прокси Opera Unite

Обычно, когда пользователь запускает веб-сервер в домашней сети, в этой сети есть устройство, которое выступает в роли файрвола, который нужно дополнительно настроить. См. рисунок 1:

Традиционная конфигурация веб-сервера

Рисунок 1: традиционная конфигурация веб-сервера

В такой ситуации пользователю нужно открыть порты и настроить их переадресацию на локальный компьютер для того, чтобы люди за файрволом могли иметь доступ к серверу.

Однако когда вы используете Opera Unite, никакой настройки не требуется, что видно на рисунке 2:

Конфигурация при использовании сервера Opera Unite в браузере

Рисунок 2: конфигурация при использовании сервера Opera Unite в браузере

Веб-сервер инициализирует подключение к прокси и использует это подключение для передачи обратно информации о входящих запросах.

Сервисы Opera Unite

Сервисы Opera Unite — это такое особый вид виджетов Opera, который поддерживает механизм получения запросов и отправки ответов на них. Виджет является сервисом Opera Unite, если его config.xml содержит подобный элемент feature:

<feature name="http://xmlns.opera.com/webserver">
  <param name="type" value="service"/>
  <param name="servicepath" value="blog"/>
</feature>

Поэтому для сервиса становится доступен специальный JavaScript-объект opera.io.webserver. Более подробно об этом можно прочитать в JavaScript API документации сервера Opera Unite.

Поскольку здесь используются те же технологии, что и в виджетах Opera, то сервисы Opera Unite предлагают простой способ контролировать и настраивать их при помощи знакомых технологий: HTML, CSS и JavaScript. Но, несмотря на это, для сервисов Opera Unite доступна функциональность не представленная в виджетах или обычных веб-станицах, например — изолированная файловая система (песочница).

Если вы заинтересованы и хочет узнать больше про виджеты Opera, вы можете найти всю информацию в статьях о виджетах на сайте Dev.Opera.

Двигаемся дальше — запускаем Opera Unite и начинаем собирать простой сервис.

Запуск веб-сервера

Для большей безопасности и производительности веб-сервер не запускается по умолчанию про запуске Opera. Для запуска сервера нужно выбрать в меню Инструменты > Сервер Opera Unite > Включить Opera Unite, либо запустить один из сервисов Opera Unite. Сразу после этого появится диалог, который предложит вам ввести логин и пароль — те же, что используются на My Opera.

Обратите внимание, что для использования в Opera Unite подходят только те логины My Opera, что не содержат недопустимых для URL символов: «/», «.», «_» и пробелов.

На следующем шагу вам нужно назвать устройство. Вы можете выбрать имя из выпадающего списка или указать любое. Имя устройства будет идентифицировать ваш сервер для прокси. Сервер будет доступен по адресам вроде этих:

http://devicename.username.proxyaddress/servicename

Таким образом, для того, чтобы увидеть сервис test на сервере your_device на operaunite.com вам нужно открыть этот URL:

http://your_device.your_username.operaunite.com/test

Создание сервиса Opera Unite: простой блог

А теперь короткий рассказ об изготовлении простого сервиса для ведения блога, который позволит пользователю публиковать записи. Однажды сохранённые, записи немедленно становятся доступны всему миру при помощи сервера.

Сервис состоит из двух частей: первая — это те страницы, которые позволяют владельцу сервиса настраивать и управлять им, вторая — это набор страниц видимых всем пользователям, которые и отдаёт сервер.

Те, кому не терпится попробовать, могут загрузить код блога для Opera Unite. Он упакован в файл с расширением .us — такое расширение по умолчанию имеют все сервисы Opera Unite. Вы можете разархивировать пакет, чтобы взглянуть на исходный код или просто перетянуть пакет в браузер Opera, чтобы увидеть пример блога для Unite.

Файлы и папки сервиса

Наш сервис будет содержать файлы и папки, изображённые на рисунке 3:

Структура папки сервиса

Рисунок 3: структура папки сервиса

  • config.xml: файл настроек сервиса
  • index.html: логическое начало сервиса, куда подключаются скрипты
  • script/script.js: непосредственный код сервиса

Из указанных файлов строго необходимы только config.xml и index.html.

Также вы можете включить в состав пакета папку public_html — волшебную папку для сервисов Opera Unite. Обычно файлы и папки внутри вашего сервиса недоступны пользователям, запрашивающим ваш сервис, поэтому, если вы захотите отдать пользователю какой нибудь файлик стилей, статические картинки или что-нибудь вроде этого, то положите файлы именно в эту папку. Эти файлы будут привязаны к относительному корню вашего сервиса и, к примеру, файл cats.png внутри папки public_html сервиса helloOperaUnite будет доступен по адресу:

http://your_device.your_username.operaunite.com/helloOperaUnite/cats.png.

Настройки сервиса: config.xml

Этот сервис будет собран точно так же, как виджет Opera, поэтому нам будет нужно задать настройки в файле config.xml. Этот файл по сути является обычным файлом настройки для виджетов Opera, за исключением некоторых дополнительных особенностей. Для того, чтобы обозначить ваш сервис как сервис Opera Unite, вам потребуется включить элемент feature в элемент widget вашего файла config.xml.

Обратите внимание, что виджеты Opera упакованы в обычные zip-файлы и переименованы в файлы с расширением .wgt, тогда как сервисы Opera Unite упакованы и переименованы в файлы с расширением .us для указания на сервис Opera Unite.

<widget>
  <widgetname>My blogging service</widgetname>
  <description>Blogging service example from the Opera Unite Services primer.</description>
  <author>
    <name>Hans S. Toemmerholt</name>
    <organisation>Opera Software ASA</organisation>
  </author>
  <feature name="http://xmlns.opera.com/webserver">
    <param name="type" value="service"/>
    <param name="servicepath" value="blog"/>
  </feature>
</widget>

Элемент widgetname также является названием вашего сервиса. Это название будет показано пользователю во время установки и использования сервиса.

Вы также можете добавить в config.xml элемент servicepath. Содержимое этого элемента должно быть валидным URI и будет являться именем сервиса, что присутствует в URI. Если этот элемент отсутствует, Opera попытается использовать в качестве URI сервиса содержимое элемента widgetname. Но если это имя не окажется валидным URI, инсталляция прервётся с ошибкой.

После того, как сервис упакован и запущен, упомянутый выше config.xml сделает его доступным по адресу:

http://your_device.your_username.operaunite.com/blog/

Соединяем всё вместе: index.html

У нашего сервиса нет интерфейса, кроме тех страниц, что он создаёт. Файл index.html — это начальная точка сервиса и, по сути, весь его интерфейс. В нашем пример мы используем минимальный файл HTML 5 со ссылкой на используемый файл скриптов:

<!DOCTYPE html>
<script src="script/script.js"></script>

Пишем скрипт: script.js

Обратите внимание на то, как мы подключили скрипт в предыдущем примере кода. Веб-сервер слушает запросы от пользователей, которые в данный момент ходят по страницам сервиса, и создаёт ответы, которые отправляются обратно. Ответом обычно является сгенерированная страница, содержащая информацию.

Функциональность Opera Unite доступна разработчикам через набор JavaScript API, включающий объекты представляющие веб-сервер, соединения, входящие запросы и исходящие ответы.

Шаг за шагом рассмотрим скрипт:

Обработчики запросов

Веб-сервер принимает запросы от клиентов и посылает им ответы обратно. Сервер Opera Unite основан на событийной модели и вызывает событие в DOM каждый раз, когда браузер к серверу, запрашивая файлы имеющие отношение к сервису Opera Unite. Чтобы иметь возможность обрабатывать эти события, нужно повесить на них обработчики. Это делается при помощи window.onload:

var webserver;
var entries = [];

window.onload = function () {

    webserver = opera.io.webserver

    if (webserver)
    {
        //Handle requests for various URLs
        webserver.addEventListener('_index', showEntryList, false);
        webserver.addEventListener('entry', showEntry, false);
        webserver.addEventListener('form', showForm, false);
        webserver.addEventListener('save', saveEntry, false);
    }
}

Что же здесь происходит?

Первым делом мы проверяем, что наш сервис действительно является веб-сервисом, проверяя существование объекта webserver. Если он существует, то мы добавляем четыре обработчика событий: _index, entry, form и save.

Когда обработчики установлены, сервер будет вызывать одну из указанных функций каждый раз, когда пользователь посетит один из следующих URL’ов:

  • http://your_device.your_username.operaunite.com/blog/
  • http://your_device.your_username.operaunite.com/blog/entry
  • http://your_device.your_username.operaunite.com/blog/form

Запрос _index особенный потому, что является запросом к корню сервиса. Как мы увидим дальше, пользователь не сможет получить доступ к «save» напрямую, а только через форму.

Показываем список записей

Код функции showEntryList для запроса _index довольно простой. После получения запроса, функция в ответ создаёт HTML-документ со списком сохранённых записей.

function showEntryList(e)
{
    var response = e.connection.response;
    response.write( '<!DOCTYPE html>'
        + '<html><head><title>Entries</title></head>'
        + '<body><ul>'
    );

    for ( var i = 0, entry; entry = entries[i]; i++ )
    {
        response.write('<li>'+entry.date+': <a href="entry?id='+i+'">'+entry.title+'</a></li>');
    }

    response.write('</ul>'
      + '<p><a href="form">Add en entry</a>.</p>'
      + '</body></html>'
    );
    response.close();
}

Шаг за шагом, функция делает следующее:

Первым делом создаётся переменная, содержащая объект response. Этот объект содержит все необходимые методы для отправки данных клиенту:

var response = e.connection.response;

Дальше идёт метод write, который записывает данные в документ для браузера, который запросил страницу. Для начала создадим простую HTML-обёртку:

response.write( '<!DOCTYPE html>'
    + '<html><head><title>Entries</title></head>'
    + '<body><ul>'
);

Существующие в блоге записи мы оформим списком ссылок:

for ( var i = 0, entry; entry = entries[i]; i++ )
{
    response.write('<li>'+entry.date+': <a href="entry?id='+i+'">'+entry.title+'</a></li>');
}

И, наконец, закрываем подключение:

response.close();

Показываем запись

Дальше нам нужно вывести что-нибудь, когда пользователь кликнул по ссылке на запись:

function showEntry(e)
{
    var index = e.connection.request.queryItems['id'][0];
    var entry = entries[index];
    //ToDo Should have error handling here
    var response = e.connection.response;
    response.write('<!DOCTYPE html>'
        + '<html><head><title>'+entry.title+'</title></head>'
        + '<body><h1>'+entry.title+'</h1>'
        + '<p>'+entry.date+'</p>'
        + '<div>'+entry.text+'</div>'
        + '</body></html>'
    );
    response.close();
}

Шаг за шагом, функция делает следующее:

Первым делом мы создаём переменную, содержащую объект request, который содержит информацию о входящем запросе:

var request = e.connection.request;

Аргументы CGI GET содержатся в свойстве queryItems запроса. Мы получаем id записи, которую хотим вывести. Обратите внимание, что один и тот же CGI-аргумент может иметь несколько значений.

var index = request.queryItems['id'][0];

Дальше мы получаем соответствующую запись в блоге:

var entry = entries[index];

Метод write записывает данные в документ браузера, который запросил страницу. Заголовок, дата и текст записи заворачиваются в подходящую разметку:

response.write('<!DOCTYPE html>'
    + '<html><head><title>'+entry.title+'</title></head>'
    + '<body><h1>'+entry.title+'</h1>'
    + '<p>'+entry.date+'</p>'
    + '<div>'+entry.text+'</div>'
    + '</body></html>'
);

Показываем форму для добавления записи

После нажатия на ссылку «Добавить запись» вы увидите знакомую форму:

function showForm(e)
{
    var response = e.connection.response;
    response.write('<!DOCTYPE html>'
        + '<html><head><title>Add entry</title></head>'
        + '<body><h1>Add entry</h1>'
        + '<form method="post" action="save">'
        + '<p><label for="namefield">Title</label> <input id="nameField" type="text" name="title"></p>'
        + '<p><label for="textArea">Text</label> <textarea id="textArea" name="text"></textarea></p>'
        + '<p><input type="submit" name="Add entry"></p>'
        + '</form>'
        + '</body></html>'
    );
    response.close();
}

Эта форма может быть гораздо сложнее, например: поддерживать обработку ошибок, вывод уже введённых данных и так далее. Также стоит придумать механизм аутентификации для потенциально деструктивных операций с данными, но не будем увлекаться — всё-таки у нас простой пример.

Сохранение записи

Наконец, после отправки формы, новая запись должна быть сохранена. В данном примере записи хранятся в простом массиве, который будет утерян после перезапуска сервиса, однако расширить пример и добавить механизм сохранения записей будет довольно просто

function saveEntry(e)
{
    var request = e.connection.request
    var response = e.connection.response;

    //Get POST data
    var title = request.bodyItems['title'][0];
    var text = request.bodyItems['text'][0];

    entries.push({
        'title' : title, 
        'text'  : text,
        'date'  : new Date()
    });


    //Redirect back to the index of the service
    response.setStatusCode(302);
    response.setResponseHeader( 'Location', webserver.currentServicePath );
    response.close();
}

Вместо request.queryItems мы используем свойство bodyItems, чтобы получить доступ к данным, отправленным при помощи POST — в нашем случае это заголовок и содержимое новой записи.

var title = request.bodyItems['title'][0];
var text = request.bodyItems['text'][0];

Отправка формы сохраняет запись в массив:

entries.push({
 	     'title' : title,
 	     'text'  : text,
 	     'date'  : new Date()
 	 });

И, наконец, когда новая запись сохранена, мы возвращаемся обратно к списку записей:

response.setStatusCode(302);
response.setResponseHeader( 'Location', webserver.currentServicePath );
response.close();

Таким образом мы создаём стандартный HTTP-редирект обратно к корню нашего сервиса, который хранится в свойстве webserver.currentServicePath. Этот редирект вызовет запрос _index и мы снова получим список всех записей.

Как уже упоминалось, к этому стоит добавить обработку ошибок и статусные сообщения.

Использование вашего сервиса Opera Unite

Для того, чтобы запустить ваш собственный сервис Opera Unite, вам сначала нужно его установить. Перетяните config.xml или полную zip-версию вашего сервиса в окно браузера или откройте через файловый диалог. Если вы до сих пор не запускали сервисы Opera Unite, то перед вам появится окно настройки Opera Unite, которое уже упоминалось в начале статьи.

Если вы кликнете дважды по сервису My blogging service в панели сервисов Unite вы должны увидеть страницу как на рисунке 4:

Главная страница блог-сервиса

Рисунок 4: главная страница блог-сервиса

Клик по ссылке «Добавить запись» покажет вам форму, которая позволит вам добавить новую запись в блог, как на рисунке 5:

Форма для публикации записи

Рисунок 5: форма для публикации записи

Если ввести в эту форму какой-то текст и нажать кнопку отправки, вы вернётесь на главную страницу блога, где уже будет видна ваша новая запись. Кликните по её заголовку, чтобы посмотреть запись. Добавьте несколько других записей, поиграйте со страницами и вы увидите что-нибудь вроде рисунка 6:

Несколько записей в блоге Полный вид одной записи в блоге

Рисунок 6: наш блог удачно заселён

Просмотр вашего сервиса Opera Unite

Если вы следовали всем рекомендациям и успешно запустили сервисы в вашем браузере Opera, то все они должны работать. Любой желающий может зайти на один из сервисов по ссылке:

http://devicename.username.proxyaddress/servicename

В нашем случае, если устройство называется your_device и на нём запущен блог-сервис, то его URL будет выглядеть так:

http://your_device.username.operaunite.com/blog

Как вы могли заметить, запуская пример, вы также можете зайти в корень устройства и увидеть все установленные на нём сервисы, например:

http://your_device.username.operaunite.com/

Эта страница будет содержать информацию о всех установленных на данном устройстве сервисах а также, если эти данные будут найдены в config.xml, более подробную информацию о сервисе и его авторе.

Загрузка вашего сервиса Opera Unite на unite.opera.com

Итак, вы собрали классный сервис Opera Unite и хотите, чтобы им могли пользоваться не только посетители вашего сервера Opera Unite — вы также хотите сделать его доступным для загрузки и установки на другие сервера Opera Unite, ведь так? Хорошо. И что же для этого нужно сделать? Ответ прост: сервис нужно загрузить на unite.opera.com — этот сайт предназначен для распространения сервисов. Данная часть статьи расскажет вам о том, как это сделать.

Перед публикацией

В идеале, перед публикацией вам стоит протестировать сервис на наличие ошибок. Если это возможно, то протестируйте его на разных платформах, устройствах версиях браузера Opera. Также не забывайте, что пользователи ваших сервисов могут использовать любой браузер, а не только Opera, поэтому протестируйте сервис в различных браузерах (Firefox, Safari, и т.п.) и на других компьютерах.

Если вы столкнулись с проблемами в работе вашего сервиса, но уверены, что с его кодом всё в порядке, то проверьте файл config.xml на наличие ошибок. Он необходим для правильной работы сервиса. Если вы откроете его в других браузерах, то сможете проверить его на корректность синтаксиса. Также стоит проверить, содержит ли config.xml достаточное количество информации, ведь он будет использоваться для получения всей информации о сервисе для репозитария unite.opera.com, а также для пользователей на страницах уже установленных сервисов.

Также стоит подумать о переводе сервиса на другие языки.

И, наконец, сделайте скриншот работающего сервиса, как описано ниже.

Публикация сервиса

Для публикации вашего сервиса вам нужно посетить страницу загрузки. Выберите файл своего сервиса (.zip) в диалоге выбора и загрузите его. Внимательно прочтите и, при необходимости, уточните информацию из config.xml. При желании, вы можете добавить более подробное описание.

Дальше выберите скриншот сервиса в файловом диалоге для того, чтобы другие пользователи смогли понять что из себя представляет ваш сервис, прежде чем они попробуют его установить.

Помимо этого, вам нужно будет выбрать устройства для использования на которых ваш сервис был создан. Убедитесь, что сервис был протестирован на указанных устройствах и выберите подходящую группу. Последним шагом будет выбор поддерживаемых вашим сервисом языков. Убедитесь, что вы предусмотрели перевод для всех выбранных языков.

Как я могу предложить воспользоваться моим сервисом?

После того, как вы потратили кучу времени на изготовление сервиса, вполне естественно, что вам захочется показать его другим людям. Чтобы увеличить число просмотров, вам нужно рассказать потенциальным пользователям каких возможностей стоит ожидать от вашего сервиса.

Существует два эффективных способа сделать это: написать удачное описание и сделать полезные скриншоты — ниже подробнее про оба способа.

Как написать удачное описание сервиса?

Всего существует два поля, которые вы можете использовать для общения с пользователем:

  • Короткое описание сервиса, которое берётся из файла config.xml и отображается во всех списках, где появляется сервис
  • Длинное описание, которое отображается на странице сервиса

Используйте короткое описание, чтобы привлечь взгляд пользователя, расскажите ему что ваш сервис может и какую пользу можно из него извлечь. Это может быть даже короткий подзаголовок, но он должен быть информативным. Вам стоит избегать фраз вроде «Скачай меня» или «Это супер-крутой сервис».

Примеры удачных коротких описаний:

  • «Будьте в курсе погоды в А, Б, В»
  • «Расслабьтесь под классическую игру АБВ»
  • «Получите быстрый доступ к спецификации АБВ»
  • «Измеряйте элементы на ваших страницах при помощи растягивающейся линейки»
  • «Читайте новости с Хабрахабра»

Используйте длинное описание для того, чтобы объяснить пользователям какие возможности предоставляет ваш сервис, как они реализованы. Также полезно будет рассказать про изменения в различных версиях сервиса, правила игры и так далее.

Имейте в виду, что ваше описание будут читать люди с различным опытом, из различных стран, культур и возрастных групп, с различных платформ, устройств и версий браузера. Не все из них смогут понять то, что очевидно для вас. Вы можете даже прямо указать потенциально возможные сложности, которые потребуют обратиться за помощью к друзьям или родственникам.

Как сделать удачный скриншот сервиса?

Для того, чтобы скриншоты были полезны, следуйте следующим рекомендациям:

  • Покажите на них базовые возможности сервиса
  • Покажите самые важные страницы сервиса, а не страницу авторизации или настроек, если они у вас есть
  • Покажите ваш сервис в действии. Если это игра, покажите её в процессе. Если сервис требует для работы данные — покажите его с данными
  • Откадрируйте скриншот так, чтобы показать самые важные части вашего сервиса

Обратите внимание, что идеальные размеры для скриншота составляют 445 × 230 пикселов — именно эти размеры используются на сайте Opera Unite. Если ваши скриншоты будут разных размеров, то они будут приведены к единым размерам, что может привести к нежелательным результатам.

Одобрение сервисов Opera Unite

Все сервисы Opera Unite должны быть одобрены специальными сотрудниками Opera Software. Мы проверим их на ошибки, чтобы убедиться в том, что все пользователи смогут их запустить, однако мы не несём ответственности за содержимое этих сервисов и не даём гарантий касательно их функциональности. Подробнее об этом в читайте в правилах.

Каким правилам нужно соответствовать для одобрения сервиса?

Некторые требования, которые мы предъявляем к сервисам:

  • Сервис должен иметь внятное название и описание.
  • Сервис не должен иметь очевидных ошибок, поэтому протестируйте его перед загрузкой.
  • Сервис не должен содержать намеренно опасного кода.
  • Сервис не должен содержать информации, на которую вы не имеете авторского права.
  • Сервис не должен содержать или ссылаться на информацию «для взрослых» или провокационную информацию.
  • Сервис должен соответствовать визуальному стилю сервисов Opera Unite. Любые случаи явного расхождения должны быть описаны в подаче заявки.
  • Сервис должен отдавать HTML-страницы совместимые со стандартами, которые доступны для всех современных браузеров и устройств.

Дальнейшее чтение

Теперь вы разбираетесь в основах создания и загрузки сервисов Opera Unite, и вам, возможно, будет интересно узнать больше:

Author of pepelsbey.net blog, advocating web standards, semantic coding and microformats. Permanent member of Russian IT conference movement as organizer and speaker. Web Evangelist, founder of "Web Standards" Russian development community.


This article is licensed under a Creative Commons Attribution, Non Commercial - Share Alike 2.5 license.

Comments

The forum archive of this article is still available on My Opera.

No new comments accepted.