Skip to content

Instantly share code, notes, and snippets.

@akadlec
Last active January 11, 2018 13:52
Show Gist options
  • Save akadlec/94bf04023101ac5c8f56f84a9332f0d8 to your computer and use it in GitHub Desktop.
Save akadlec/94bf04023101ac5c8f56f84a9332f0d8 to your computer and use it in GitHub Desktop.
iPub:WebSockets!

iPub:WebSockets! - websockety snadno a rychle

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!

Server a základní příprava

Instalace

Instalace pomocí composeru je velice jednoduchá, vystačíme si s příkazem:

$ composer require ipub/websockets-wamp

Konfigurace

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.

Konfigurace serveru

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

Routy a controllery

Základní stavební kameny jsou routy a jejich controllery. Jejich definice je identická jako v klasické Nette aplikaci.

Definice rout

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.

Definice controllerů

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

Spuštění serveru

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

Klientská část

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.

Komunikace server - klient

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()]);
	}
}
@JanGalek
Copy link

Jen pár oprav v js:

'message': $('input[name="message"]').val();

zde nemá být středník ;)

socketsConnection = IPub.WebSockets.WAMP.initialize('wss://www.yourdomain.tld/');

zde, pokud nahoře jsme si nastavili port 8888 tak bychom si ho měli uvést i zde ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment