Node.js + Socket.IO a posílání zpráv z jiné aplikace

ntpt

Dobrý den.

Snažím se proniknout  do node.js a socket.io a z  některých věcí nejsem trochu moudrý. Vezměme jejich příklad s jednoduchou chat aplikací.Ten je celkem srozumitelný.

Ovšem jsem v koncích, když přemýšlím, jak  to propojit s externími aplikacemi.

Když už jsme u jejich  kódu chatovací aplikace:

Kód: [Vybrat]
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);


chápu že si pomocí require vytvořím express framework objekt, v jeho rámci objekt http serveru (a ten někam bindnu), v  rámci serveru si vytvořím  objekt io, reprezentující websocket, (víceméně matrjoška)  jakmile se na něj někdo připojí vznikne socket

A v jeho rámci  reaguji na události - socket.on("událost", function(blah){udělejněco})

Kód: [Vybrat]
io.on('connection', function(socket){
  socket.on('chat message', function(msg){
    io.emit('chat message', msg);
  });
});

Řekněme že se připojí  součastzně Franta a Pepa. Chápu, že jejich spojení a jejich websockety nepromíchají neb každé patří do jiné instance objektu socket z jejich příkladu. Řekněme, že si Franta i Pepa vymění nějaké autorizační zprávy ze serverem a tedy bude jasné kdo je na kterém socketu.

Problém začíná, když potřebuji přes takto navázané spojení  poslat klientovi data z  jiného běžícího programu.Řekněme, že něco běžícího na serveru dojde k názoru, že potřebuje poslat zprávu Pepovi.

Otázklou je JAK to propojit. Zkrátka čím a jak "vstoupit" dovnitř těch vnořených objektů (a do toho správného) a říci (vyvolat událost): ted pošli TYTO data.

Hloupého kopni.... Umí mi prosím někdo vyplnit toto bílé místo ? Děkuji.
« Poslední změna: 15. 05. 2017, 08:42:32 od Petr Krčmář »


Tomas2

  • ****
  • 310
    • Zobrazit profil
    • E-mail
Re:node.js + socket.io + posílání zpráv z jiné aplikace
« Odpověď #1 kdy: 14. 05. 2017, 23:13:13 »
objekt socket si ulož do nějaké mapy (users.push({"pepa", socket})). Vytvoř si další express server na jiném portu a do něj si posílej informace z tvoji aplikace jako http požadavek, projdi mapu připojených socketů a podle tvých podmínek pošli data na klienta.

Snad pomůže i bez kód, na mobilu se mi špantě píše. Rád bych ale varoval, že podobným přístupem si do aplikace zaneseš spusty bezpečnostních chyb.

gll

Re:node.js + socket.io + posílání zpráv z jiné aplikace
« Odpověď #2 kdy: 15. 05. 2017, 06:11:56 »
objekt socket si ulož do nějaké mapy (users.push({"pepa", socket})). Vytvoř si další express server na jiném portu a do něj si posílej informace z tvoji aplikace jako http požadavek, projdi mapu připojených socketů a podle tvých podmínek pošli data na klienta.

Snad pomůže i bez kód, na mobilu se mi špantě píše. Rád bych ale varoval, že podobným přístupem si do aplikace zaneseš spusty bezpečnostních chyb.

users.push({"pepa", socket}) má dělat co? Nemělo to být users["pepa"] = socket ? Jinak máte pravdu.

ntpt

Re:node.js + socket.io + posílání zpráv z jiné aplikace
« Odpověď #3 kdy: 15. 05. 2017, 06:46:42 »
objekt socket si ulož do nějaké mapy (users.push({"pepa", socket})). Vytvoř si další express server na jiném portu a do něj si posílej informace z tvoji aplikace jako http požadavek, projdi mapu připojených socketů a podle tvých podmínek pošli data na klienta.

Snad pomůže i bez kód, na mobilu se mi špantě píše. Rád bych ale varoval, že podobným přístupem si do aplikace zaneseš spusty bezpečnostních chyb.


Ono nevadí že to users.push budu volat uvnitř té matrjožky a    ono se mi popropaguje do jiné matrjožky ?? Myslel bych si, že právě tohle nejde, že jsou to vlastně closury vložené do sebe a tedy z principu  jedna druhé do kontextu nevidí...

gll

Re:node.js + socket.io + posílání zpráv z jiné aplikace
« Odpověď #4 kdy: 15. 05. 2017, 06:52:09 »
objekt socket si ulož do nějaké mapy (users.push({"pepa", socket})). Vytvoř si další express server na jiném portu a do něj si posílej informace z tvoji aplikace jako http požadavek, projdi mapu připojených socketů a podle tvých podmínek pošli data na klienta.

Snad pomůže i bez kód, na mobilu se mi špantě píše. Rád bych ale varoval, že podobným přístupem si do aplikace zaneseš spusty bezpečnostních chyb.

Ono nevadí že to users.push budu volat uvnitř té matrjožky a    ono se mi popropaguje do jiné matrjožky ?? Myslel bych si, že právě tohle nejde, že jsou to vlastně closury vložené do sebe a tedy z principu  jedna druhé do kontextu nevidí...

users je globální proměnná. Na začátku napiš var users = {}


gll

Re:node.js + socket.io + posílání zpráv z jiné aplikace
« Odpověď #5 kdy: 15. 05. 2017, 07:15:42 »
zprávu uživateli pošleš takto

Kód: [Vybrat]
users[username].send(data, callback)

je to zjednodušené, asi budeš ověřovat jestli spojení existuje.

ntpt

Re:node.js + socket.io + posílání zpráv z jiné aplikace
« Odpověď #6 kdy: 15. 05. 2017, 08:04:01 »
jestli tedy dobře chápu:  vložit  objekt socket  do pole - globální proměnné,  a použít jej v  jiné matrjožce třeba  připojené na zmq nebo redis. Principiálně

var users;

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

io.on('connection', function(socket){

  socket.on('username', function(username){
  users[username]=socket; // ano já vím nebezpečné

};
  socket.on('chat message', function(msg){
    io.emit('chat message', msg);
  });
});

var zmq = require('zeromq')
  , sock = zmq.socket('pull');
 
sock.connect('tcp://127.0.0.1:3000');
console.log('Worker connected to port 3000');
 
sock.on('message', function(msg){

jakmile dostanu ze zmq zprávu   
PODLE OBSAHU ZPRAVY VYBER, kterému spojení poslat,
třeba pomocí JSON.parse(msg) atd získat ze zprávy username a data  a ty pak poslat
 
users[username].send(data, callback);

;
});



takhle nějak ?

gll

Re:node.js + socket.io + posílání zpráv z jiné aplikace
« Odpověď #7 kdy: 15. 05. 2017, 08:25:02 »
jestli tedy dobře chápu:  vložit  objekt socket  do pole - globální proměnné,  a použít jej v  jiné matrjožce třeba  připojené na zmq nebo redis. Principiálně

var users;

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

io.on('connection', function(socket){

  socket.on('username', function(username){
  users[username]=socket; // ano já vím nebezpečné

};
  socket.on('chat message', function(msg){
    io.emit('chat message', msg);
  });
});

var zmq = require('zeromq')
  , sock = zmq.socket('pull');
 
sock.connect('tcp://127.0.0.1:3000');
console.log('Worker connected to port 3000');
 
sock.on('message', function(msg){

jakmile dostanu ze zmq zprávu   
PODLE OBSAHU ZPRAVY VYBER, kterému spojení poslat,
třeba pomocí JSON.parse(msg) atd získat ze zprávy username a data  a ty pak poslat
 
users[username].send(data, callback);

;
});



takhle nějak ?

v principu je to správně.

nevím co znamená matrjožka kromě dřevěné hračky. V kontextu nodejs jsem to nikdy neslyšel.

users by měl být objekt, tedy var users = {}.

Bezpečnější by asi bylo použít sessionid namísto username. Případně ověřovat, že zpráva přišla z originu, na kterou se může dostat jen danný uživatel.

Zeromq je asi dobrý nápad. Dá se použít i http na nějakém portu neviditelném zvenku.

Tomas2

  • ****
  • 310
    • Zobrazit profil
    • E-mail
Re:Node.js + Socket.IO a posílání zpráv z jiné aplikace
« Odpověď #8 kdy: 15. 05. 2017, 09:55:49 »
ano, nadřazené proměnné se propagují do těch vnitřních. Nejedná se o globální proměnné, btw.

Použití pole místo objektu byl ode mě jen krok napřed (users je poté nutné inicializovat jako var user = []). Mohu mít uživatele s více okny prohlížeče, chci mu to tedy poslat asi do všech nebo v době vytvoření připojení nemám k dispozici ještě jméno uživatele, tak musím ukládat sessionId a to je pak mnohem efektivnější procházet a hledat v poli než v objektu.

Je tady poté i další aspekt, pokud uživatelské jméno je vstupem z venku a já ho dávám jako klíč do objektu, mohu si s tím zadělat na problém, kdy správně zvolená jména mi odrovnají aplikaci kvůli složitosti jejich hledání v hashmapě.

Další drobnost je třeba performance, pokud budu do pole ukládat pořád stejný objekt, JIT v JS s ním bude pracovat velice efektivně. Mazání nebo přidávání položek do pole je i při velkém množství takových operací stabilní. Dělat tohle s objektem, mohu si zadělat na dost nepříjemné bugy nebo memory leaky.

ntpt

Re:Node.js + Socket.IO a posílání zpráv z jiné aplikace
« Odpověď #9 kdy: 15. 05. 2017, 09:58:36 »
matrjožka jako přirovnání, že jsou jednotlivé  objekty do sebe zanořeny jeden v druhém jako ty panenky jedna do druhé   expres(http(io(connection(socket(on({}))))))  je jedna matrjožka. zmq( sock (on({})) ) je dhuhá..

Zkrátka jako ilustraci zapouidření instancí objektů do sebe.

Jinak samozřejmě tohle byl příklad, kde bezpečnost nebyla řešená neb šlo o princip.  Samozřejmě v reálu je nutno použít patřičné mechanizmy jak se daný klient autorizuje  atd....

gll

Re:Node.js + Socket.IO a posílání zpráv z jiné aplikace
« Odpověď #10 kdy: 15. 05. 2017, 10:19:44 »
ano, nadřazené proměnné se propagují do těch vnitřních. Nejedná se o globální proměnné, btw.

Použití pole místo objektu byl ode mě jen krok napřed (users je poté nutné inicializovat jako var user = []). Mohu mít uživatele s více okny prohlížeče, chci mu to tedy poslat asi do všech nebo v době vytvoření připojení nemám k dispozici ještě jméno uživatele, tak musím ukládat sessionId a to je pak mnohem efektivnější procházet a hledat v poli než v objektu.

Je tady poté i další aspekt, pokud uživatelské jméno je vstupem z venku a já ho dávám jako klíč do objektu, mohu si s tím zadělat na problém, kdy správně zvolená jména mi odrovnají aplikaci kvůli složitosti jejich hledání v hashmapě.

Další drobnost je třeba performance, pokud budu do pole ukládat pořád stejný objekt, JIT v JS s ním bude pracovat velice efektivně. Mazání nebo přidávání položek do pole je i při velkém množství takových operací stabilní. Dělat tohle s objektem, mohu si zadělat na dost nepříjemné bugy nebo memory leaky.

Vyhledávání v hashmapě je rychlejší než v poli. Pokud potřebujete řešit víc spojení pro jednoho usera, musíte to dělat pomocí hashmapy polí.

Kód: [Vybrat]
var users = {};
.....
if(users[userid]){
users[userid].push(connection);
}else{
users[userid] = [connection];
}

ntpt

Re:Node.js + Socket.IO a posílání zpráv z jiné aplikace
« Odpověď #11 kdy: 15. 05. 2017, 10:20:57 »
ano, nadřazené proměnné se propagují do těch vnitřních. Nejedná se o globální proměnné, btw.

Jaký je mezi tím a globální proměnnou rozdíl ?

Použití pole místo objektu byl ode mě jen krok napřed (users je poté nutné inicializovat jako var user = []). Mohu mít uživatele s více okny prohlížeče, chci mu to tedy poslat asi do všech nebo v době vytvoření připojení nemám k dispozici ještě jméno uživatele, tak musím ukládat sessionId a to je pak mnohem efektivnější procházet a hledat v poli než v objektu.



Je tady poté i další aspekt, pokud uživatelské jméno je vstupem z venku a já ho dávám jako klíč do objektu, mohu si s tím zadělat na problém, kdy správně zvolená jména mi odrovnají aplikaci kvůli složitosti jejich hledání v hashmapě.

samozřejmě tohle je rychlopříklad mechanizmu, v reálu by spoléhal že uživatel je skutečně ten jehož username mi pošle prohlížeč , bez žádné autentizace, vytvoření sessiony či nějakého ekvivalentu etc , asi jen šílenec.

Další drobnost je třeba performance, pokud budu do pole ukládat pořád stejný objekt, JIT v JS s ním bude pracovat velice efektivně. Mazání nebo přidávání položek do pole je i při velkém množství takových operací stabilní. Dělat tohle s objektem, mohu si zadělat na dost nepříjemné bugy nebo memory leaky.

díky za užitečný tip..





gll

Re:Node.js + Socket.IO a posílání zpráv z jiné aplikace
« Odpověď #12 kdy: 15. 05. 2017, 10:22:56 »
Kód: [Vybrat]
users.push({"pepa", socket})

je syntakticky špatně, proto jsem se ptal, co to má dělat. Asi jste chtěl napsat {"pepa":socket}.

gll

Re:Node.js + Socket.IO a posílání zpráv z jiné aplikace
« Odpověď #13 kdy: 15. 05. 2017, 10:25:45 »
ano, nadřazené proměnné se propagují do těch vnitřních. Nejedná se o globální proměnné, btw.

Jaký je mezi tím a globální proměnnou rozdíl ?

je to atribut objektu global, ale to je IMHO to stejné co globální proměnná.

gll

Re:Node.js + Socket.IO a posílání zpráv z jiné aplikace
« Odpověď #14 kdy: 15. 05. 2017, 10:32:04 »
Je tady poté i další aspekt, pokud uživatelské jméno je vstupem z venku a já ho dávám jako klíč do objektu, mohu si s tím zadělat na problém, kdy správně zvolená jména mi odrovnají aplikaci kvůli složitosti jejich hledání v hashmapě.

to je blbost. Složitost vyhledávání v hashmapě nemůže být horší než vyhledávání v poli, i kdyby útočník měl možnost vytvořit jména všech uživatelů.