Дуплексный асинхронный обмен данными для веба, мобайла и десктопа в одной реализации

от автора

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

Скажу сразу — это не реклама и я не имею никакого отношения к разработчикам и не получу никакого вознаграждения за свою работу (кроме морального, за то что поделился своим опытом).

Итак, LightStreamer это сервер работающий на Java и как следствие может быть запущен как на Windows так и Linux машинах + если разработка ведется на амазоне, то можно использовать готовый Amazon Machine Image с LightStreamer на борту download.lightstreamer.com.
Установочный пакет (фактически заархивированная папка) уже содержит демо лицензию, ограничения которой сводятся лишь к 20 одновременно подключенных клиентов, что, согласитесь, для разработки вполне достаточно, но если нет — можно заказать evaluation без ограничений на 60 дней. Вот список доступных лицензий.

Инструкции по установке изложены в /Lightstreamer/GETTING_STARTED.TXT который находится внутри архива. Все предельно просто (опишу для Windows):
— распаковываем, желательно в корень диска потому что архив содержит достаточно длинные пути к файлам;
— указываем TCP порты на котором будет висеть сервер в /Lightstreamer/conf/lightstreamer_conf.xml, по умолчанию 8080 и 8888;
— в /Lightstreamer/bin/windows/LS.bat в переменной JAVA_HOME указываем где установлен JDK (если не установлен — установите);
— и запускаем сервер /Lightstreamer/bin/windows/Start_LS_as_Application.bat.
Для теста открываем http://localhost:8080 (порт указываем тот же что был указан в /Lightstreamer/conf/lightstreamer_conf.xml) и должны увидеть страницу приветствия с ссылками на преинсталированые демки.
Так же есть возможность вместо HTTP использовать HTTPS и кластеризацию с лоадбалансером

Что ж, сервер установлен, но толку мало — нужно научить его обрабатывать наши запросы и давать ответы. Для этого существует механизм адаптеров (что то на подобии плагинов). То есть, нам нужно написать адаптер, который будет обрабатывать запросы с наших клиентов и дать знать самому серверу что такой адаптер существует что бы он направлял запросы на него.

Написание адаптера

В папке /Lightstreamer/DOCS-SDKs/ находятся SDK. Для написания адаптера на .NET нужно реализовать интерфейс Lightstreamer.Interfaces.Data.IDataProvider из /Lightstreamer/DOCS-SDKs/sdk_adapter_dotnet/lib/DotNetAdapter_N2.dll

using System; using System.Collections; using System.Threading; using Lightstreamer.Interfaces.Data; public class HelloWorldAdapter : IDataProvider {     private IItemEventListener _listener;     private volatile bool go;     public void Init(IDictionary parameters, string configFile) { }     public bool IsSnapshotAvailable(string itemName) { return false; }     public void SetListener(IItemEventListener eventListener) { _listener = eventListener; }     public void Subscribe(string itemName)     {         if (itemName.Equals("greetings")) { new Thread(new ThreadStart(Run)).Start(); }     }     public void Unsubscribe(string itemName) { if (itemName.Equals("greetings")) { go = false; } }     public void Run()     {         go = true;         int c = 0;         Random rand = new Random();         while (go)         {             IDictionary eventData = new Hashtable();             eventData["message"] = c % 2 == 0 ? "Hello" : "World";             eventData["timestamp"] = DateTime.Now.ToString("s");             _listener.Update("greetings", eventData, false);             c++;             Thread.Sleep(1000 + rand.Next(2000));         }     } } 

Запуск адаптера

Для запуска нам понадобится консольная апликуха

using System; using System.Net.Sockets; using Lightstreamer.DotNet.Server; public class DataAdapterLauncher {     public static void Main(string[] args)     {         string host = "localhost";         int reqrepPort = 6661;         int notifPort = 6662;         try         {             DataProviderServer server = new DataProviderServer();             server.Adapter = new HelloWorldAdapter();             TcpClient reqrepSocket = new TcpClient(host, reqrepPort);             server.RequestStream = reqrepSocket.GetStream();             server.ReplyStream = reqrepSocket.GetStream();             TcpClient notifSocket = new TcpClient(host, notifPort);             server.NotifyStream = notifSocket.GetStream();             server.Start();             System.Console.WriteLine("Remote Adapter connected to Lightstreamer Server.");             System.Console.WriteLine("Ready to publish data...");         }         catch (Exception e)         {             System.Console.WriteLine("Could not connect to Lightstreamer Server.");             System.Console.WriteLine("Make sure Lightstreamer Server is started before this Adapter.");             System.Console.WriteLine(e);         }     } } 

Заливка адаптера на сервер

В папке /Lightstreamer/adapters/ создаём новую папку и копируем в неё /Lightstreamer/DOCS-SDKs/sdk_adapter_remoting_infrastructure/lib/ls-proxy-adapters.jar. Там же создаём новый файл /lib/adapters.xml с контентом

<?xml version="1.0"?> <adapters_conf id="HelloWorld">    <metadata_provider>       <adapter_class>com.lightstreamer.adapters.metadata.LiteralBasedProvider</adapter_class>    </metadata_provider>    <data_provider>       <adapter_class>com.lightstreamer.adapters.remote.data.RobustNetworkedDataProvider</adapter_class>       <classloader>log-enabled</classloader>       <param name="request_reply_port">       6661</param>       <param name="notify_port">       6662</param>    </data_provider> </adapters_conf> 

Имя может бить любое — оно будет указываться при написании клиента и все. Как видите порты указываются такие же как при запуске адаптера.

Написание клиента

Для примера приведу простейший JavaScript клиент

<html>    <head>       <script src="http://cdnjs.cloudflare.com/ajax/libs/require.js/1.0.7/require.min.js"></script>       <script src="https://code.jquery.com/jquery-2.1.0.min.js"></script>       <script src="C:/Lightstreamer/DOCS-SDKs/sdk_client_javascript/lib/lightstreamer.js"></script>       <script>          require(["LightstreamerClient","Subscription","StaticGrid"],function(LightstreamerClient,Subscription,StaticGrid) {            var lsClient = new LightstreamerClient("http://localhost:8080", "HelloWorld");            lsClient.connect();            var lsSubscription = new Subscription("MERGE",['greetings'],['greetings', 'message', 'timestamp']);            lsSubscription.addListener({              onItemUpdate: function(updateObject) {                $("#message").text('Message=' + updateObject.getValue("message"));                $("#timestamp").text('TimeStamp=' + updateObject.getValue("timestamp"));              }            });            lsClient.subscribe(lsSubscription);          });       </script>    </head>    <body>       <span id="message"></span><br/>       <span id="timestamp">       </span>    </body> </html> 

Результат

И в итоге получили автоматически обновляемые данные на клиенте:
image
Что бы клиент мог получать уникальные данные, которые относятся именно к нему, например сообщения в чате, то вместо просто ‘greetings’ (второй параметр) нужно передать айдишку пользователя и на стороне адаптера по этой айдишке выгребать его сообщения.

new Subscription("MERGE",['userID123'],['greetings', 'message', 'timestamp']) 

Так же можно передавать не только один параметр, а несколько, разделённых запятой, двоеточьем и тд. и соответственно на стороне адаптера всё это парсить.
В процессе разработки столкнулся с неудобством дебага на сервере, на котором никакой студии нет и выяснил что можно вместо localhost в DataAdapterLauncher классе передать адрес машины где стоит сервер и таким образом возможно не имея локального сервака дебажить.

Напоследок

Судя по www.lightstreamer.com/doc адаптер можно написать на:

  • Java
  • .NET
  • Node js

А список платформ для клиентов побольше:

  • avaScript
  • Android
  • iOS
  • Windows Phone
  • WinRT
  • BlackBerry
  • Java ME
  • Flash
  • Flex
  • Silverlight
  • .NET
  • Java SE
  • OS X

P.S.
Сорсы адаптера для примера на github‘e.

ссылка на оригинал статьи http://habrahabr.ru/post/220343/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *