multiple websockets connections on the same client - server cannot handle - html

Let me clarify, this is kind of complicated.
I'm implementing a form to insert data in the database.
I have two websockets connections in the same client side, connecting on the same nodejs server.
One connection is triggered after the user inserts a name on the "name" textfield of the form. Sends the data to the server, server checks the database if the name already exists and responces back "This already exists. Mayde you are inserting something that is already there".
The other connection is triggered if all the fields of the form are not blank and sends the data to server to insert them in the database.
I thought it was a good idea to distinguish on server-side ,the different connections using arrays. If the first element of the array is "name" call the checkName function, or if it is "insert" , call the insertInDB function.
I created two small testing files. They do not work. Connections are open and the client sends the data. I get no errors inte server nor the client side. But server never responces. I dont get the expected numbers, back in the client side. I dont think this is the right anyway. This is complecated, I hope the code helps you.
Is it possible, what I am trying to do? Any hints or alternatives?
Thanks
the code....
server-side
function WebSocketTest1(){
var a=1;
var b=2;
var c = [a,b];
var so = new WebSocket("ws://localhost:1337");
so.onerror=function (evt)
{message.textContent = evt;}
so.onopen = function(){
message.textContent = "opened";
so.send(c);
message.textContent = "sended";
}
so.onmessage = function (evt) {
var received_msg = evt.data;
document.getElementById("message").innerHTML=received_msg;
}
}
function WebSocketTest2(){
var d=3;
var e=4;
var f = [d,e];
var sa = new WebSocket("ws://localhost:1337");
sa.onerror=function (evt)
{message2.textContent = evt;}
sa.onopen = function(){
message2.textContent = "opened";
sa.send(f);
message2.textContent = "sended";
}
sa.onmessage = function (evt) {
var received_msg = evt.data;
document.getElementById("message2").innerHTML=received_msg;
}
}
</script>
</head>
<input type="button" value="one" onClick="WebSocketTest1()"><br/>
<input type="button" value="two" onClick="WebSocketTest2()"><br/>
<body>
<div id="message"></div>
mesage2</br>
<div id="message2"></div>
</body>
</html>
on the server side I am listing the sessions, to communicate only with a specific session, code found here
and the server side (snippets)
var connections = {};
var connectionIDCounter = 0;
var connection = request.accept(null, request.origin);
// Store a reference to the connection using an incrementing ID
connection.id = connectionIDCounter ++;
connections[connection.id] = connection;
console.log((new Date()) + ' Connection accepted.');
connection.on('message', function(message) {
var ja=message;
if(ja[0]==1)
{ja[1]=7;}
else if(ja[0]==3)
{ja[1]=8;}
});
connection.on('close', function(reasonCode, description) {
console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
delete connections[connection.id];
});
});
// Send a message to a connection by its connectionID
function sendToConnectionId(connectionID, data) {
var connection = connections[connectionID];
if (connection && connection.connected) {
connection.send(ja[1]);
}

I wonder why you need 2 connections.
Open one connection and send the payload as JSON.
e.g.
var ws = new WebSocket("ws://localhost:1336");
ws.send(JSON.stringify({ command: "checkname", params: "xxxx"; });
ws.send(JSON.stringify({ command: "submit", params: { ... });
At the server side, you just have to parse the payload and determine which command is executed.

I am just wondering why you need websocket. It seems that you need to validate user presence in the application. If user is not present then you need to insert in the database else throw error.
you can go through jquery post and jquery form validation
http://api.jquery.com/jQuery.post/

Related

How can I keep my connection alive for multiple queries using JDBC and Google-App-Script?

I saw this post but it didn't really helped me solving my problem.
I use a HTML dialog box opened with an add-on on google spreadsheets and I'm using JBDC.
I load from multiple queries some datas from my MYSQL database, I also have a search bar to search for datas in the DB and in the future I would like my HTML to automatically show various database values depending on option choosen in my HTMLpage. Basically that's a lot of queries for only one App so I guess there should be one connection object to use.
I've tried multiple things that I can show you in pseudo-code.
open a new connection every time
so here would be my GS file
function firstFunc()
{
var conn = Jdbc.getConnection(dbUrl, user, userPwd);
//do my thing
return (datas);
}
function secondFunc()
{
var conn = Jdbc.getConnection(dbUrl, user, userPwd);
//do my thing
return (datas);
}
function thirdFunc()
{
var conn = Jdbc.getConnection(dbUrl, user, userPwd);
//do my thing
return (datas);
}
and then my HTML
<script>
var onSuccessFirst = function (data){
//update my HTML with data
}
var onSuccessSecond = function (data){
//update my HTML with data
}
var onSuccessThird = function (data){
//update my HTML with data
}
google.script.run.withSuccessHandler(onSuccessFirst).firstFunc();
google.script.run.withSuccessHandler(onSuccessSecond).secondFunc();
google.script.run.withSuccessHandler(onSuccessThird).thirdFunc();
</script>
But as I'm using a free database provider for developping the third connection returns me an error telling me to verify password or username because it failed to connect to database.
try passing the connection from the server to the client then back to the server:
GS file
function getConnection()
{
return (Jdbc.getConnection(dbUrl, user, userPwd););
}
function firstFunc(conn)
{
conn...
//do my thing
return (datas);
}
function secondFunc(conn)
{
conn...
//do my thing
return (datas);
}
function thirdFunc(conn)
{
conn...
//do my thing
return (datas);
}
and then my HTML
<script>
var onSuccessFirst = function (data){
//update my HTML with data
}
var onSuccessSecond = function (data){
//update my HTML with data
}
var onSuccessThird = function (data){
//update my HTML with data
}
var onSuccessConnection = function(conn)
{
google.script.run.withSuccessHandler(onSuccessFirst).firstFunc(conn);
google.script.run.withSuccessHandler(onSuccessSecond).secondFunc(conn);
google.script.run.withSuccessHandler(onSuccessThird).thirdFunc(conn);
}
google.script.run.withSuccessHandler(onSuccessConnection).getConnection();
</script>
But here conn is null.
I also have a lot of queries sent when my input (search bar) is onchange and I use first method it works except it doesn't allow quick typing as it increases connection requests on each character typed.
What can I do?
Maybe Try chaining with your first approach:
<script>
var onSuccessThird = function (data){
//update my HTML with data
}
var onSuccessSecond = function (data){
//update my HTML with data
google.script.run.withSuccessHandler(onSuccessThird).thirdFunc();
}
var onSuccessFirst = function (data){
//update my HTML with data
google.script.run.withSuccessHandler(onSuccessSecond).secondFunc();
}
google.script.run.withSuccessHandler(onSuccessFirst).firstFunc();
</script>
Notes:
google.script.run is a async function. All three runs will be called one by one without waiting for the the previous run to finish, which means almost 3 Jdbc connections will be opened more or less at the same time in the first approach.
A single script.run call will close the connection. So in your second approach, the conn will be null when the first run is over or before that.
JDBC connections close automatically when a script finishes executing. (Keep in mind that a single google.script.run call counts as a complete execution, even if the HTML service page that made the call remains open.)
References:
Closing connections
If you are able to use connection pooling,
else you can keep the connection alive for one complete set of transactions by checking null and opening / closing the connection only once for a full set of request response.

When opening multiple clients, old client does not get updated using nodejs web socket

My goal is when I open a new browser(client), the message sent from the server in the previous client gets updated as well.
Currently,
The clients send messages to the server, the server stores them in localStorage as an array and should send it back to all the clients. All clients should get the same array of messages. It works like ajax call.
As of right now, when I open the first browser, the message is sent to the server and received in the client successfully, and then I open the second one(it works) but the message is not updated in the first browser. PS this acts like a forum, when somebody posts a messages to server, all users should be able to see it.
Here's my code for server:
<html>
<head>
<!-- This is the websocket SERVER -->
<script src="http://localhost:5000/socket.io/socket.io.js"></script>
</head>
<body>
<div id="msg"></div>
<script>
// connect to WEBSOCKET server
var socket = io.connect('http://localhost:5000',{'forceNew':true} );
// Fire an event (that the server will handle
socket.emit('myEvent', 'Hello Message from the client');
// Attach event handler for event fired by server
socket.on('server', function(data) {
var elem = document.getElementById('msg');
console.log(data);
elem.innerHTML += "<br>" + data; // append data that we got back
});
</script>
</body>
</html>
Here's for client:
//---------------------------------------------------------------
// The purpose is to introduce you to websockets
// This is a SERVER that is SEPARATE from the http server.
//
// Your webpage (in this case the index.html in this directory)
// will be SERVED by the http server. THEN, it will connect to the
// websocket server. Then - they will talk to each other!
//
// Note that in regular http - the server cannot initiate a conversation
// Here, the websocket server sends a message to the client browser.
//
// This example has THREE parts
// 1) The http server code (which is same as what we did earlier)
// 2) This code - this is the web socket server
// It prints what it got from client. It also sends a message to the
// client after every 1 second.
// 3) The html or client code. Note how it connects to the websocket
// and how it sends and receives messages
//
// To RUN THIS EXAMPLE
// First, run node httpServer.js on one terminal
// Next, run node 1_ws.js on another terminal
// Next, type localhost:4000/index.html on some browser
//
//---------------------------------------------------------------
var items=[];
var io = require('socket.io').listen(5000);
if (typeof localStorage === "undefined" || localStorage === null) {
var LocalStorage = require('node-localstorage').LocalStorage;
localStorage = new LocalStorage('./scratch');
}
io.sockets.on('connection', function(socket) {
socket.on('myEvent', function(content) {
//i need to store the content
items.push(content);
localStorage.setItem("list",JSON.stringify(items));
socket.emit('server', JSON.parse(localStorage.getItem("list")));
});
});
I'm running on the local server:( you can ignore the local server if you want, the above code can function on their own)
//---------------------------------------------------------------
// The purpose is to serve a file!
//---------------------------------------------------------------
var util = require('util');
var path = require('path');
var http = require('http');
var fs = require('fs');
var server = http.createServer();
// attach handler
server.on('request', function (req,res) {
var file = path.normalize('.' + req.url);
fs.exists(file, function(exists) {
if (exists) {
var rs = fs.createReadStream(file);
rs.on('error', function() {
res.writeHead(500); // error status
res.end('Internal Server Error');
});
res.writeHead(200); // ok status
// PIPE the read stream with the RESPONSE stream
rs.pipe(res);
}
else {
res.writeHead(404); // error status
res.end('NOT FOUND');
}
});
}); // end server on handler
server.listen(4000);
console.log("start");
You are sending response to only client who sent message to sever only,
To send to all clients which are connected you must use this,
io.emit('server', JSON.parse(localStorage.getItem("list")));
Visit this answer for all
Responses

How to send Data to the client with out client requesting the ws server in nodejs

I need to convert a csv file to json format and send it to a client requesting to ws server in nodejs ,
the file will be updated so many times so i need to send updated data to client
i am able to send data once it is loaded completely(like when app is started it sends all data in file to client) but when i update data in the file the updated data is being printed out on console but it is not being sent to client is their any thing wrong in my code
my node.js code:
var ts = require('tail-stream');
var Converter = require("csvtojson").Converter;
var converter = new Converter({constructResult:false}); //for big csv data
var WebSocketServer = require('websocket').server;
var http = require('http');
var server = http.createServer(function(request, response) {
// process HTTP request. Since we're writing just WebSockets server
// we don't have to implement anything.
response.write('hello');
console.log('in http server \n');
});
server.listen(1337, function() { });
// create the server
wsServer = new WebSocketServer({
httpServer: server
});
// WebSocket server
wsServer.on('request', function(request) {
var connection = request.accept(null, request.origin);
console.log('wsserver');
connection.send('ws server');
converter.on("record_parsed", function (jsonObj) {
console.log(jsonObj); //here is your result json object
connection.send(jsonObj);
});
var tstream = ts.createReadStream('log.csv', {
beginAt: 0,
onMove: 'follow',
detectTruncate: false,
onTruncate: 'end',
endOnError: false
});
tstream.pipe(converter);
});
Right now you are creating a new read stream and adding a listener to the converter on every new connection, that will cause trouble once you have more than one client (same event emitted multiple times, etc..). Instead of that you should keep just one reader and notify all open connections when there's a new record.
Also notice that the library you are using only accepts UTF-8 strings or binary type messages, row objects sent the way you're sending them now will be received as a "[object Object]" string after toString() is called on them. You should probably send just send the row string or use JSON.stringify / JSON.parse.
Try this:
var http = require("http");
var tailStream = require("tail-stream");
var Converter = require("csvtojson").Converter;
var WebSocketServer = require("websocket").server;
var server = http.createServer();
var wsServer = new WebSocketServer({ httpServer: server });
var converter = new Converter({constructResult:false});
var logStream = tailStream.createReadStream("log.csv", { detectTruncate : false });
var connections = [];
server.listen(1337);
logStream.pipe(converter);
//----------------------------------------------------
converter.on("record_parsed", function (jsonObj) {
connections.forEach(function(connection){
connection.send(JSON.stringify(jsonObj));
});
});
//----------------------------------------------------
wsServer.on("request", function(request) {
var connection = request.accept(null, request.origin);
connection.on("close", function() {
connections.splice(connections.indexOf(connection), 1);
});
connections.push(connection);
});
The code above works, tested like this on the client side:
var socket = new WebSocket('ws://localhost:1337/');
socket.onmessage = function (event) {
console.log(JSON.parse(event.data));
}
Note: this doesn't send the whole content of the file at the beginning, just the updates, but you can easily achieve this storing the records and sending them on new connections.

IndexedDB can make database unreachable (getting blocked), how unblock?

UPDATE
I discovered the issue is that it's blocked. Despite the database always being created and upgraded by the same extension, it does not get closed. So now I'm getting the "onblocked" function called.
How do I "unblock" currently blocked databases? And how do I prevent this in the future? This is an app, so no tabs are using it. And since I can't open those databases to even delete them (this also gets blocked), how do I close them?
(For anyone wondering, to avoid this issue from the start, you HAVE to do the folllowing:)
mydb.onversionchange = function(event) {
mydb.close();
};
Original Post
IndexedDB dies and becomes unopenable if I (accidentally) try to open and upgrade with the wrong version. As far as I can tell, there's no way to ask indexedDB for the latest version of a DB. So if I try to run the following code twice, it destroys the database and it becomes unopenable:
And it never throws an error or calls onerror. It just sits silently
var db = null;
//Note, no version passed in, so the second time I do this, it seems to cause an error
var req = indexedDB.open( "test" );
req.onsuccess = function(event) { console.log( "suc: " + event.target.result.version ); db = event.target.result; };
req.onerror = function(event) { console.log( "err: " + event ); };
req.onupgradeneeded = function(event) { console.log( "upg: " + event.target.result.version ); };
//We're doing in interval since waiting for callback
var intv = setInterval(
function()
{
if ( db === null ) return;
clearInterval( intv );
var req2 = indexedDB.open( "test", db.version + 1 );
req2.onsuccess = function(event) { console.log( "suc: " + event.target.result.version ); };
req2.onerror = function(event) { console.log( "err: " + event ); };
req2.onupgradeneeded = function(event) { console.log( "upg: " + event.target.result.version ); };
},
50
);
All of that code is in my chrome.runtime.onInstalled.addListener. So when I update my app, it calls it again. If I call indexedDB.open( "test" ) without passing in the new version and then again run the setInterval function, it causes everything to become unusable and I'm never able to open "test" again. This would be solved if I could query indexedDB for the version of a database prior to attempting to open it. Does that exist?
Maybe this helps?
function getVersion(callback) {
var r = indexedDB.open('asdf');
r.onblocked = r.onerror = console.error;
r.onsuccess = function(event) {
event.target.result.close();
callback(event.target.result.version);
};
}
getVersion(function(version) {
console.log('The version is: %s', version);
});
Ok, based on the convo, this little util function might set you on the path:
var DATABASE_NAME_CONSTANT = 'whatever';
// Basic indexedDB connection helper
// #param callback the action to perform with the open connection
// #param version the version of the database to open or upgrade to
// #param upgradeNeeded the callback if the db should be upgraded
function connect(callback, version, upgradeNeeded) {
var r = indexedDB.open(DATABASE_NAME_CONSTANT, version);
if(upgradeNeeded) r.onupgradeneeded = updateNeeded;
r.onblocked = r.onerror = console.error;
r.onsuccess = function(event) {
console.log('Connected to %s version %s',
DATABASE_NAME_CONSTANT, version);
callback(event.target.result);
};
}
// Now let us say you needed to connect
// and need to have the version be upgraded
// and need to send in custom upgrades based on some ajax call
function fetch() {
var xhr = new XMLHttpRequest();
// ... setup the request and what not
xhr.onload = function(event) {
// if response is 200 etc
// store the json in some variable
var responseJSON = ...;
console.log('Fetched the json file successfully');
// Let's suppose you send in version and updgradeNeeded
// as properties of your fetched JSON object
var targetVersion = responseJSON.idb.targetVersion;
var upgradeNeeded = responseJSON.idb.upgradeNeeded;
// Now connect and do whatever
connect(function(db) {
// Do stuff with the locally scoped db variable
// For example, grab a prop from the fetched object
db.objectStore('asdf').put(responseJSON.recordToInsert);
// If you feel the need, but should not, close the db
db.close();
console.log('Finished doing idb stuff');
}, targetVersion, upgradeNeeded);
}
}
I think it is best to provide the version number always. If you don't how are you going to manage upgrades on the db structure? If you don't its a good chance you will get in a situation where same db versions on a client will have an other database structure, and I don't think that is the thing you want. So I would suggest to keep the version number in a variable.
Also when working with indexeddb you will have to provide an upgrade plan from al previous versions to the current. Meaning version 4 has a certain structure, but you will have to be able to get that same structure from scratch as from version 1,2 and 3

How to uniquely identify a socket with Node.js

TLDR; How to identify sockets in event based programming model.
I am just starting up with node.js , in the past i have done most of my coding
part in C++ and PHP sockets() so node.js is something extremely new to me.
In c++ to identify a socket we could have done something like writing a main socket say server to listen for new connections and changes, and then handling those connections accordingly.
If you are looking for actual sockets and not socket.io, they do exist.
But as stated, Node.js and Javascript use an event-based programming model, so you create a (TCP) socket, listen on an IP:port (similar to bind), then accept connection events which pass a Javascript object representing the connection.
From this you can get the FD or another identifier, but this object is also a long-lived object that you can store an identifier on if you wish (this is what socket.io does).
var server = net.createServer();
server.on('connection', function(conn) {
conn.id = Math.floor(Math.random() * 1000);
conn.on('data', function(data) {
conn.write('ID: '+conn.id);
});
});
server.listen(3000);
Timothy's approach is good, the only thing to mention - Math.random() may cause id's duplication. So the chance it will generate the same random number is really tiny, but it could happen. So I'd recommend you to use dylang's module - shortid:
var shortid = require('shortid');
var server = net.createServer();
server.on('connection', function(conn) {
conn.id = shortid.generate();
conn.on('data', function(data) {
conn.write('ID: '+conn.id);
});
});
server.listen(3000);
So in that case you can be sure that no id duplications will occur.
in typescript:
import { v4 as uuidv4 } from 'uuid';
import net from 'net';
class Socket extends net.Socket {
id?: string;
}
const server = net.createServer();
server.on('connection', (conn) => {
conn.id = uuidv4();
conn.on('data', (data) => {
console.log(conn.id);
});
});
server.listen(3000);
you need to add id first;
In c++ to identify a socket we could have done something like writing
a main socket say server to listen for new connections and then
handling those connections accordingly.but so far i havent found
anything like that in node.js . (the berkeley socket model) Does it
even exist in node.js .. if not i am going back to my C++ :$
You should go back, because JavaScript is a prototype-based, object-oriented scripting language that is dynamic, weakly typed and has first-class functions. They are both completely different languages and you will have to have a different mindset to write clean JavaScript code.
https://github.com/LearnBoost/Socket.IO/wiki/Migrating-0.6-to-0.7
Session ID
If you made use of the sessionId property of socket in v0.6, this is now simply .id.
// v0.6.x
var sid = socket.sessionId;
// v0.7.x
var sid = socket.id;
if you found this question by looking for socket.io unique ids that you can use to differentiate between sockets on the client-side (just like i did), then here is a very simple answer:
var id = 0; //initial id value
io.sockets.on('connection', function(socket) {
var my_id = id; //my_id = value for this exact socket connection
id++; //increment global id for further connnections
socket.broadcast.emit("user_connected", "user with id " + my_id + "connected");
}
on every new connection the id is incremented on the serverside. this guarantees a unique id.
I use this method for finding out where a broadcast came from on the clientside and saving data from concurrent sockets.
for example:
server-side
var my_coords = {x : 2, y : -5};
socket.broadcast.emit("user_position", {id: my_id, coord: my_coords});
client-side
user = {};
socketio.on("user_position", function(data) {
if(typeof user[data.id] === "undefined")
user[data.id] = {};
user[data.id]["x"] = data.coord.x;
user[data.id]["y"] = data.coord.y;
});
How to identify a client based on its socket id. Useful for private messaging and other stuff.
Using socket.io v1.4.5
client side:
var socketclientid = "john"; //should be the unique login id
var iosocket = io.connect("http://localhost:5000", {query: "name=john"});
var socketmsg = JSON.stringify({
type: "private messaging",
to: "doe",
message: "whats up!"
});
iosocket.send(socketmsg);
server side:
io.on('connection', function(socket){
var sessionid = socket.id;
var name = socket.handshake.query['name'];
//store both data in json object and put in array or something
socket.on('message', function(msg){
var thesessionid = socket.id;
var name = ???? //do lookup in the user array using the sessionid
console.log("Message receive from: " + name);
var msgobject = JSON.parse(msg);
var msgtype = msgobject.type;
var msgto = msgobject.to;
var themessage = msgobject.message;
//do something with the msg
//john want to send private msg to doe
var doesocketid = ???? //use socket id lookup for msgto in the array
//doe must be online
//send to doe only
if (msgtype == "private messaging")
socket.to(doesocketid).emit('message', 'themessage');
});
mmmm, i don't really get what you're looking for but socket-programming with node.js (and socket.io) is really straight forward. take a look at some examples on the socket.io homepage:
// note, io.listen() will create a http server for you
var io = require('socket.io').listen(80);
io.sockets.on('connection', function (socket) {
io.sockets.emit('this', { will: 'be received by everyone connected'});
socket.on('private message', function (from, msg) {
console.log('I received a private message by ', from, ' saying ', msg);
});
socket.on('disconnect', function () {
sockets.emit('user disconnected');
});
});
on connecting to the server, every socket get an unique id with which you can identify it later on.
hope this helps!?
cheers