Kraken.js a Socket.IO

UPDATE [SK]: Tento blog platí pre verziu Krakana 0.7.3. Môže byť užitočný aj pre ďalšie verzie, avšak odporúčam prečítať odpoveď v tomto issue.
UPDATE[EN]: This blogpost is based on Kraken 0.7.3. If you are using version higher than that, you might still find it usefull, but I recommend to follow this asnwer.

V predchádzajúcom blogu som písal o svojej voľbe frameworku a o problémoch, ktoré ma postretli pri používaní Kraken.js. V tomto blogu by som rád dal návod, ako vyriešiť jeden z nich – prepojiť Kraken.js so Socket.IO. Tento problém som riešil zhruba týždeň voľným tempom (keďže mám skúškové). V prvom rade, čo je to Socket.IO?

Socket.IO

Socket.IO je knižnica, ktorá umožňuje komunikáciu clienta so serverom pomocou websocketov. Ak nie je možné použiť websockety, pokúsi sa celú komunikáciu presúvať na kanál, ktoré obe strany podporujú, čím zaručuje, že ak ste pripojený, správy dorazia. V dobe písania tohto blogu akurát vyšla verzia 1.0, takže celé riešenie bude už pre verziu 1.0. Na úspešnú komunikáciu potrebujete ako knižnicu Socket.IO pre klienta tak pre Node.js server. Princíp fungovania spočíva v tom, že na serveri vytvoríte websocket server, ktorý bude načúvať a posielať správy a na clientovi vytvoríte prostredie, ktoré  bude tiež načúvať a posielať správy. Avšak rád by som zdôraznil dva fakty. Websocket server rieši požiadavky sám a teda aj keď pošlete svoje správy v tvare URL (/person/get/17), váš Node.js server ich nebude analyzovať. Druhým faktom je, že Socket.IO ponúka len samotnú komunikáciu, s kým však komunikujete, musíte zistiť vy. Ako?  Aj o tomto je tento blog.

Zdroje

Zdrojov na túto tému je veľmi málo. Takže uvediem z čoho som čerpal a kam ma to až dostalo. Celý týždeň v kocke. Uvádzam to pre prípad, keby niekto používal iný framework, chcel si prečítať diskusie alebo mal pocit, že moje riešenie nie je ideálne (v tokom prípade treba určite zanechať komentár). A uvádzam tiež len to, čo považujem za kvalitné, teda nie všetko, čo som musel prečítať. Celý príbeh začína na Issue #39. Zdá sa to celkom jednoduché, takto vytvoríte server. Ako ale zistiť s kým hovoríte? Je to platný request? Je ten človek prihlásený? Tak na vyriešenie tohto problému odporúčam tento blogpost. Problém na ktorý tiež narazíte je, že kým Issue je pre Socket 0.9, tak riešenie je pre Express 2 (čiže nie pre Kraken, ktorý mimochodom beží na Express 3).

Server

V prvom rade je potrebné nainštalovať Socket.IO modul:

npm install --save socket.io

V druhom kroku upravíme index.js (nakoľko používam CoffeeScript, svoje riešenie uvádzam v CoffeeScripte). V úvode načítame knižnicu. Následne po vytvorení aplikácie previažeme Kraken so Socketmi, ako sme videli v Issue.

/index.coffee (index.js)

'use strict';

require 'coffee-script/register'

## Loading Socket.IO
## Making this global so it will be accessible from controller
global.io = new ( require 'socket.io' )

kraken = require 'kraken-js'
db = require './lib/database'
app = {}

...

if require.main == module

	kraken.create(app).listen (err, server)->

		console.error err.stack if err

		io.attach server    # Connecting to Krakenom

module.exports = app

Hotovo. Teda aspoň zdanlivo. Prichádza ťažšia časť – zistiť s kým komunikujeme. To prebieha nejako takto: Socket pošle svoje Cookies a s nimi aj session_id. Socket.IO overí, či sú platné a v prípad, že vyzerajú dobre, pozrie sa do už vytvorených sessions, či tam má session s daným ID. Session je relácia medzi užívateľom a serverom, ktorá si uchovávate informácie o užívateľovi (či je prihlásený, aké ma ID, alebo čo má v košíku). Zaniká zatvorením prehliadača, ale viete ju vypnúť (prípadne zmeniť) manuálne. PHP a Apache sa o to staralo samé na pozadí, s tým, že vždy bola dostupná premenná $_SESSION. V Krakenovi to nie je také jednoduché. Popravde získať aktuálne databázu aktuálnych sessions je aj pre mňa problém, preto som vytvoril tento Issue. Dokým dostanem nejakú rozumnú odpoveď od autorov, musíme použiť malý hack:

Update: Odpoveď som dostal, ale pre novšiu verziu Krakena, takže si myslím, že hack je stále na mieste:

/node_modules/kraken-js/lib/middleware/session.js

module.exports = function (settings) {
    var override, Store;

    override = util.tryRequire(settings && settings.module);
    if (override) {
        Store = override(express);
        settings.store = new Store(settings.config);

        global.sessionStore = settings.store; // This is our hack
    }

    return express.session(settings);
};

 Teraz keď už máme v globálnej premennej zoznam všetkých sessions, stačí znovu upraviť index.js a pridať nejaký middleware, ktorý sa o to postará:

/index.coffee (index.js)

app.configure = (nconf, next)->

    # Configure sockets

    io.use (socket, next)->

        return next("No cookie transmitted.", false) if ! socket.handshake.headers.cookie

        # Parse cookies and find our session_id

        session_id = require('express/node_modules/cookie').parse socket.handshake.headers.cookie
        session_id = require('express/node_modules/cookie-signature').unsign session_id['connect.sid'].substring(2), nconf.get("middleware").session.secret

        return next( 'Unknown cookie.', false ) if ! session_id

        # Find session_id in sessionStore

        global.sessionStore.load session_id, (err, session) ->

            next( 'Not valid session.', false ) if err or ! session

            ## Save session to socket, that way we can access user data later using socket.session
            socket.session = session

            next null, true

    next()

V poslednom rade, ešte musíme nastaviť secret. Secret je kód pomocou ktorého sa naše cookies “šifrujú”. A práve v 14 riadku sme to kontrolovali.
/config/middleware.json

{
    "middleware": {
        "session": {
            "module": "memory",
            "secret": "35cb2890c5560878c7199d88b92457776b7ecd9e" // Change this
        }
    }
}
// Source: https://github.com/lmarkus/Kraken_Example_Shopping_Cart/blob/master/config/middleware.json

Náš server je už pripravený, k dokonalosti nám ešte chýba nejaká tá samotná komunikácia:

'use strict';

module.exports = ( io )->

    io.on 'connection', ( socket )->		

        socket.emit 'hello'

        socket.on 'foo', ()->
            return 'foobar'

Klient

To najťažšie je už za nami, teraz si zlížeme smotanu vytvorím klienta. V prvom rade stiahnite socket.io pre klienta alebo použite cdn:

<script type="text/javascript" src="https://cdn.socket.io/socket.io-1.0.2.js"></script>

Teraz už len stačí vytvoriť napísať pár riadkov:

socket = io 'http://localhost:1339' # Change your port to match your server!

socket.on 'connect', ()->

    console.log 'Websockets established and running!'

socket.on 'hello', ()->

    console.log 'Hello sir!'

Hotovo

Pokiaľ ste všetko spravili správne, mali by ste po pripojení na server vidieť v konzole ‘Hello sir!’. Tento návod rieši problematiku prepojenia Socket.IO a Kraken.js, overenie platnosti cookies a načítanie session. Priestor na zlepšenie vidím ešte v tom, aby sa Sockety mapovali na Routing v Krakenovi. Čiže, aby sa dali zo socketu rovno volať controllery. Keď niekto budete mať hotové toto riešenie, určite sa oň podeľte. Tak isto všetky námety, ako zlepšiť kvalitu tohto riešenia rád uvítam v diskusií. Dúfam, že som nejednému z vás uľahčil život a možno aj vyjasnil, ako niektoré moduly fungujú.

Pridaj komentár

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>