Začátek je jednoduchý, ostatně jako u všech ostatních rozšíření pro Nette framework. Ještě ale než budeme instalovat rozšíření, je potřeba se rozhodnout který typ web socketů budeme chtít implementovat.
- iPub:WebSocketsMessage! - jednoduché řešení
- ipub:WebSocketsWAMP! - implementace WAMP (Websocket Application Messaging Protocol) ktetrý přináší pokročilejší způsoby komunikace
Toto rychlé how-to se bude podrobněji zabývat druhou možností a tedy iPub:WebSocketsWAMP!
Instalace pomocí composeru je velice jednoduchá, vystačíme si s příkazem:
$ composer require ipub/websockets-wamp
Nainstalované rozšíření je zapotřebí registrovat v aplikaci např. pomocí config.neon
.
extensions:
webSockets: IPub\WebSockets\DI\WebSocketsExtension
webSocketsWAMP: IPub\WebSocketsWAMP\DI\WebSocketsWAMPExtension
Jak je vidět, registrují se zde dvě rozšíření. První slouží jako jádro, má v sobě všechny základní služby jako např. samotný server či router. Druhé rozšíření doplňuje jádro o WAMP protokol ve verzi 1.
Samotná definice serveru má několik volitelných parametrů
webSockets:
server:
httpHost: localhost
port: 8888
address: 0.0.0.0
- httpHost definuje adresu socketového serveru, v úplném formátu. Tuto adresu je pak možné předat do šablony a pak JS klientovi.
- address definuje IP adresu na které bude server naslouchat na příchozí spojení. 0.0.0.0 definuje neomezné spojení, tj. libovolný klient se může připojit
- port je port na kterém má server naslouchat
Základní stavební kameny jsou routy a jejich controllery. Jejich definice je identická jako v klasické Nette aplikaci.
Routy můžeme definovat pomocí neonu:
webSockets:
routes:
'/demo-chat/<room>' : 'DemoChat:'
'/notification' : 'Notification:'
Takže stejně jako v Nette, zde definujeme tvar CURIE a jméno controlleru která jej bude obsluhovat.
Když už máme nadefinované routy, je potřeba k nim vytvořit i odpovídající controllery. Každý controller musí vycházet z abstraktního BaseControlleru IPub\WebSockets\Application\Controller\Controller
namespace App\Controllers;
use IPub\WebSockets\Application\Controller\Controller;
class DemoChatController extends Controller
{
// ...
}
Jak je vidět, controller jsme umístili do našeho aplikačního namespace App\Controllers
a aby tento controller byl dohledatelný pomocí továrničky na controllery, je potřeba rozšíření naučit naše mapování. To lze stejně jako v Nette pomocí konfigurace:
webSockets:
mapping:
*: App\Controllers\*Controller
Základní konfiguraci máme za sebou a nyní můžeme spustit websocketový server. Aby bylo ovládání serveru co nejjednodušší, rozšíření implementuje konzolové rozšíření Kdyby/Console. Aby konzole fungovala správně, je potřeba provést její registraci a nastavení:
extensions:
console: Kdyby\Console\DI\ConsoleExtension
console:
url: https://www.yourpage.tld
A nyní je možné pomocí příkazu spustit samotný server z rootu webové aplikace:
$ php web/index.php ipub:websockets:start
Pokud jsme postupovali správně, uvidíme v konzoli informační hlášky:
+------------------+
| WebSocket server |
+------------------+
! [NOTE] Starting IPub\WebSockets
! [NOTE] Launching WebSockets WS Server on: localhost:8888
Základní serverou část máme za sebou. Nyní můžeme nakonfigurovat klientskou část naší aplikace. Aby jsme si usnadnili klientskou část, je možné využít připravené JS knihovny, které stačí přilinkovat do html stránky:
<script src="/components/ipub-websockets-wamp/public/js/autobahn.js"></script>
<script src="/components/ipub-websockets-wamp/public/js/ipub.websockets.wamp.js"></script>
- autobahn.js je knihovna která implementuje všechny základní metody WAMP v1 protokolu
- ipub.websockets.wamp.js obaluje knihovnu autobahn.js a umožňuje snadnou reigstraci událostí pro spojení a komunikaci se serverem
<h1>Websocketová komunikace</h1>
<form>
<input name="message" />
<button name="send" class="button-send">Odeslat</button>
</form>
<script language="javascript" type="text/javascript">
var socketsConnection;
var socketSession;
$(function () {
socketsConnection = IPub.WebSockets.WAMP.initialize('wss://www.yourdomain.tld/');
socketsConnection.on('socket/connect',
function(session) {
// Callback po úspěšném spojení se serverem
socketSession = session;
socketSession.subscribe('/demo-chat/general', function (topic, event) {
// Callback který se zavolá, jakmile obdržíme zprávu v tomto topicu
alert('Prijal jsem zprávu ze serveru!');
});
},
function (code, reason, detail) {
// Callback při neúspěšném spojení se serverem
// např. když server odmítne naše spojení
}
);
socketsConnection.on('socket/disconnect', function(error) {
// Callback který se zavola při ukončení spojení se serverem
// např. při reloadu stránky nebo když spojení ukončí samotný server
});
$('.button-send').click(function() {
var data = {
'message': $('input[name="message"]').val();
};
socketSession.publish('/demo-chat/general', data);
});
});
</script>
Nyní máme velice základní konfiugraci klientské části, která je nyní schopna komunikovat s websocketovým serverem.
Pokud chceme předávat přijaté zprávy ostatním klientům, je zapotřebí doplnit patřičný controller:
namespace App\Controllers;
use IPub\WebSockets\Application\Controller\Controller;
use IPub\WebSocketsWAMP\Entities\Clients\IClient;
use IPub\WebSocketsWAMP\Entities\Topics\ITopic;
use Nette\Utils\Json;
class DemoChatController extends Controller
{
/**
* Akce která se zavolá když JS klient zavolá publish metodu.
*
* @param \stdClass $event - Zde jsou všechny příchozí data odeslané z JS klienta
* @param IClient $client - Klient který akci vyvolal
* @param ITopic $topic - Topic kterého se akce týká
*/
public function actionPublish(\stdClass $event, IClient $client, ITopic $topic)
{
$outgoing = new \stdClass();
$outgoing->time = (new \DateTime())->format('Y-m-d H:i:s');
$outgoing->from = $client->getId();
$outgoing->content = $event->message;
// Odešleme všem, i tomu kdo zprávu poslal
$topic->broadcast(Json::encode($message));
// Pošleme všem, vyjma toho kdo zprávu poslal
$topic->broadcast(Json::encode($message), [$client->getId()]);
}
}
Jen pár oprav v js:
zde nemá být středník ;)
zde, pokud nahoře jsme si nastavili port 8888 tak bychom si ho měli uvést i zde ;)