Для отправки данных с сервера на клиент, не важно будь это веб, мобайл или десктоп существует достаточное количество техник. Но проблема в том что они все разные и если нужно реализовать оповещение об одном и том же событии для клиентов на всех основных платформах, то придется дублировать этот самый код оповещения. Вот поэтому я хочу поделится с сообществом своей практикой по работе с одним продуктом под названием 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
Для запуска нам понадобится консольная апликуха
В папке /Lightstreamer/adapters/ создаём новую папку и копируем в неё /Lightstreamer/DOCS-SDKs/sdk_adapter_remoting_infrastructure/lib/ls-proxy-adapters.jar. Там же создаём новый файл /lib/adapters.xml с контентом
Имя может бить любое — оно будет указываться при написании клиента и все. Как видите порты указываются такие же как при запуске адаптера.
Для примера приведу простейший JavaScript клиент
И в итоге получили автоматически обновляемые данные на клиенте:
Что бы клиент мог получать уникальные данные, которые относятся именно к нему, например сообщения в чате, то вместо просто 'greetings' (второй параметр) нужно передать айдишку пользователя и на стороне адаптера по этой айдишке выгребать его сообщения.
Так же можно передавать не только один параметр, а несколько, разделённых запятой, двоеточьем и тд. и соответственно на стороне адаптера всё это парсить.
В процессе разработки столкнулся с неудобством дебага на сервере, на котором никакой студии нет и выяснил что можно вместо localhost в DataAdapterLauncher классе передать адрес машины где стоит сервер и таким образом возможно не имея локального сервака дебажить.
Судя по www.lightstreamer.com/doc адаптер можно написать на:
А список платформ для клиентов побольше:
P.S.
Сорсы адаптера для примера на github'e.
Скажу сразу — это не реклама и я не имею никакого отношения к разработчикам и не получу никакого вознаграждения за свою работу (кроме морального, за то что поделился своим опытом).
Итак, 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>
Результат
И в итоге получили автоматически обновляемые данные на клиенте:
Что бы клиент мог получать уникальные данные, которые относятся именно к нему, например сообщения в чате, то вместо просто '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.