Jump to content

Cum Sa Fac Un Chat Realtime ? Cu Node.js !


gaby

Recommended Posts

Nota: Articolul a fost scris de Roland Szabo pe blogul personal.

nodejslogo.png

Sa incepem cu primirea de date de la browser. Vom face asta cu un simplu XMLHttpRequest. Sa modificam pagina SSE.html sa contina urmatoarele elemente:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
</head>
<body><input type='text' id='message'/>
<button value='Send' id='send'>Send</button>
<script>
document.getElementById('send').addEventListener('click', sendmessage);
document.getElementById('message').addEventListener('keydown', function(event) {
if (event.keyCode == 13) {
sendmessage();
}
});
function sendmessage() {
var req = new XMLHttpRequest();
req.open('POST', '/xhr');
req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
req.send(document.getElementById('message').value);
req.onreadystatechange = function (e) {
if (req.readyState == 4) {
if (req.status == 200)
;//console.log(req.responseText);
else
console.log("Error loading page\n");
}
};
}; </script>
</body>
</html>[/code] [b]Ce avem aici?[/b] Un tag input si un button. Codul Javascript contine o functie si doua event listeners care cheama acea functie: una cand facem click pe butonul Submit, iar cealalta cand apasam Enter in casuta de "[i]chat[/i]". Functia nu face altceva decat sa trimita prin POST continutul inputului la [b]/xhr[/b]. Cum arata acum fisierul [b][color="#FF0000"]chat.js[/color][/b]?
[code]var http = require('http');
var fs = require('fs');
http.createServer(function(req, res) {
if (req.method == "POST" && req.url == '/xhr') {
var data = '';
req.addListener('data', function(chunk) {
data += chunk;
});
req.addListener('end', function() {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(data);
res.end();
console.log(data);
});
} else {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(fs.readFileSync(__dirname + '/sse.html'));
res.end();
}
}).listen(8000);
Daca cererea este prin POST si la adresa /xhr, atunci ne pregatim sa primim continutul prin POST. Mai intai initializam variabila data cu un sir de caractere gol. Apoi atasam functii la doua evenimente specifice requesturilor HTTP: data si end. Eventul data se trimite atunci cand se primeste o bucata noua de date, iar cel de end se primeste la … sfarsitul trimiterii. La fiecare "data" adaugam ce s-a primit la acel event la ce am primit mai inainte, iar cand s-a terminat transmisia, atunci prelucram. in acest caz trimitem inapoi ce am primit si scriem la consola continutul mesajului primit. Daca este orice alt tip de cerere, atunci afisam pagina sse.html. Ok, acum e timpul sa combinam ce am invatat data trecuta (trimiterea de mesaje de la server la browser) cu ce am invatat azi (prelucrarea datelor primite de server).
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<ul>

</ul>
<input type='text' id='message' />
<button value='Send' id='send'>Send</button>
<script>
var source = new EventSource('/events');
source.addEventListener('message', function(e) {
var ul = document.getElementsByTagName('ul')[0];
var li = document.createElement('li');
var data = e.data.split('\n')
li.innerHTML = '<strong>'+data[0]+'</strong>:'+data[1];
ul.appendChild(li);
console.log(e);
}, false);

source.addEventListener('open', function(e) {
console.log('open');
}, false);

source.addEventListener('error', function(e) {
if (e.eventPhase == EventSource.CLOSED) {
console.log('close');
}
}, false);
document.getElementById('send').addEventListener('click',sendmessage);
document.body.addEventListener('keydown',function(event) {
if (event.keyCode == 13) {
sendmessage();
}
});
function sendmessage() {
var req = new XMLHttpRequest();
req.open('POST', '/xhr');
req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
req.send(document.getElementById('message').value);
req.onreadystatechange = function (e) {
if (req.readyState == 4) {
if (req.status == 200)
;//console.log(req.responseText);
else
console.log("Error loading page\n");
}
};
};
</script>
</body>
</html>[/code] Asta e aproape perfect combinatia celor doua fisiere de dinainte, cu exceptia faptului ca avem o lista in care o sa inseram mesajele de chat, iar cand primim un mesaj de la server, il despartim la ‘\n’. Datele de la server vor veni astfel incat pe un rand va fi numele celui care a trimis mesajul, iar pe al doilea rand va fi mesajul propriu-zis.
[code]var http = require('http');
var fs = require('fs');

//Array to contain active resources
var resources = new Array();

http.createServer(function(req, res) {
if (req.headers.accept && req.headers.accept == 'text/event-stream') {
if (req.url == '/events') {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
//Create a random ID for each guest in the chatroom
res.chatID = 'guest'+Math.floor(Math.random()*1000);
resources.push(res);
//Remove from active chat resources if connection is closed
req.addListener('close',function (event) {
console.log('A connection was closed');
var index = resources.indexOf(res);
if (index != -1) {
resources.splice(index,1);
}
});
} else{
res.writeHead(404);
res.end();
}
} else {
if(req.method == "POST" && req.url =='/xhr') {
var data = '';
req.addListener('data',function(chunk) {
data+=chunk;
});
req.addListener('end',function() {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(data);
res.end();
//send the data to all the active chat resources
for (var i=0; i<resources.length; i++) {
constructSSE(resources[i],2,[resources[i].chatID,data]);
}
});

}
else {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(fs.readFileSync(__dirname + '/sse-node.html'));
res.end();
}
}
}).listen(8000);

function constructSSE(res, id, data) {
res.write('id: ' + id + '\n');
//Adds the capability to send multiple lines of data if they are in an array
if (data.constructor != Array)
data = [data];
for (var i = 0; i<data.length; i++)
res.write("data: " + data[i] + '\n');
res.write('\n');
}

Ce facem aici? Pai in primul rand, facem ceva ce nu putem face in PHP: stocam intr-un array fiecare response ca sa stim la cine trebuie sa trimitem informatii inapoi. Cand cineva se conecteza la event source, il adaugam la acest array, iar daca se intrerupe conexiunea, il eliminam. Deasemenea, fiecarui response ii asociem un ID, ca sa putem identifica fiecare utilizator care chatuieste. Cand primim un mesaj prin XHR, il trimitem mai departe la fiecare abonat din arrayul nostru.

!!! Fisierele pot fi descarcate de aici: :link:

Numai bine :pct2: !

Te-ai inregistrat? Ne-ar placea sa te prezinti.

Cum pot sustine forumul?
Cumpara de la eMag folosind acest link.
--------------------
oG2BN9d.gifse1WdXd.gifQG6MtmI.gifRHYjDzD.gifG5p1wui.gif

Link to comment
Share on other sites

  • 3 years later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.