Real-time database view on HTML page with Socket.io - mysql

I have a raspberry Pi that is constantly pushing data to a MySQL database via PHP. I am trying to create a website where I can see the contents of this database realtime.
I've been following this tutorial : http://markshust.com/2013/11/07/creating-nodejs-server-client-socket-io-mysql which shows an example on using socket.io for this purpose. This is working fine from 2 clients, when I add a new note it updates on both browsers. The problem is when I manually add a record to the database from mysql CLI, it does not update. I'm guessing this is because there is no emit happening. How can I implement this?
Server.js:
var mysql = require('mysql')
// Let’s make node/socketio listen on port 3000
var io = require('socket.io').listen(3000)
// Define our db creds
var db = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'root',
database: 'node'
})
// Log any errors connected to the db
db.connect(function(err){
if (err) console.log(err)
})
// Define/initialize our global vars
var notes = []
var isInitNotes = false
var socketCount = 0
console.log("connected");
io.sockets.on('connection', function(socket){
// Socket has connected, increase socket count
socketCount++
// Let all sockets know how many are connected
io.sockets.emit('users connected', socketCount)
socket.on('disconnect', function() {
// Decrease the socket count on a disconnect, emit
socketCount--
io.sockets.emit('users connected', socketCount)
})
socket.on('new note', function(data){
// New note added, push to all sockets and insert into db
notes.push(data)
io.sockets.emit('new note', data)
// Use node's db injection format to filter incoming data
db.query('INSERT INTO notes (note) VALUES (?)', data.note)
})
// Check to see if initial query/notes are set
if (! isInitNotes) {
// Initial app start, run db query
db.query('SELECT * FROM notes')
.on('result', function(data){
// Push results onto the notes array
notes.push(data)
})
.on('end', function(){
// Only emit notes after query has been completed
socket.emit('initial notes', notes)
})
isInitNotes = true
} else {
// Initial notes already exist, send out
socket.emit('initial notes', notes)
}
})
Index.html:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="http://localhost:3000/socket.io/socket.io.js"></script>
<script>
$(document).ready(function(){
// Connect to our node/websockets server
var socket = io.connect('http://localhost:3000');
// Initial set of notes, loop through and add to list
socket.on('initial notes', function(data){
var html = ''
for (var i = 0; i < data.length; i++){
// We store html as a var then add to DOM after for efficiency
html += '<li>' + data[i].note + '</li>'
}
$('#notes').html(html)
})
// New note emitted, add it to our list of current notes
socket.on('new note', function(data){
$('#notes').append('<li>' + data.note + '</li>')
})
// New socket connected, display new count on page
socket.on('users connected', function(data){
$('#usersConnected').html('Users connected: ' + data)
})
// Add a new (random) note, emit to server to let others know
$('#newNote').click(function(){
var newNote = 'This is a random ' + (Math.floor(Math.random() * 100) + 1) + ' note'
socket.emit('new note', {note: newNote})
})
})
</script>
<ul id="notes"></ul>
<div id="usersConnected"></div>
<div id="newNote">Create a new note</div>

This is similar to a previous question, where it appears there was no simple way to do this with MySQL.
If you are in an early enough stage of development that you are not tied to MySQL, then I will point out that you can solve this problem with postgresql:
Be pushed to from PHP via PDO library (see docs).
Runs on the Raspberry Pi.
Can detect updates pushed from anywhere on the command-line via pg_notify on a trigger (see docs).
Updates can be subscribed to with NodeJS via the pg package.
On a technical level this will work, but databases in general are not efficient as messaging systems (watch out for the Database-as-IPC anti-pattern). The PHP client could also emit its own notification when things happen, via a message queue, UDP socket, or something else.

Related

Node.js - can it be used for Desktop app development - MySQL, DataTable & File Open

Since last 3days, I am after this, not sure I understood its purpose properly - Node.js/Electron.
Few years back I had built a simple VB.net application - It connects to Mysql (contains a table of filename with path), shows the filenamesPath as rows in grid, upon double click, it opens the file.
Can I do such a thing in Node.js or Electron?.
1) I am able to make a js file with a button which can open a local file, in Node.js desktop app window (not browser). [https://www.codediesel.com/nodejs/how-to-open-various-desktop-applications-from-nodejs/ ].
2) Also I am able to view mySql table as html table in browser with localhost:port as well as the rows in console-log window [https://www.sitepoint.com/using-node-mysql-javascript-client/]
Is it possible to club both of these 2, Or Should I try something else. [As the rows are more than 100K, would need also Ajax]
EDITED:
test.html
<html>
<head>
<script>window.$ = window.jQuery = require('./js/jquery.js');</script>
<meta http-equiv="Content-Security-Policy" content="script-src 'unsafe-inline';">
</head>
<body>
<h1>Electron MySQL Example</h1>
<div id="resultDiv"></div>
<div>
<input type="button" id="action-btn" value="Retrieve 10 first rows in the database" />
<table id="table" border="1">
<tbody>
</tbody>
</table>
</div>
<script>
var mysql = require('mysql');
var connection = mysql.createConnection({
host : '10.251.198.2',
user : 'root',
password : '',
database : 'test'
});
connection.connect();
var sql = 'SELECT `id`,`name` FROM `employees`';
connection.query(sql, function (error, results, fields) {
if (error) console.log(error.code);
else {
console.log(results);
$('#resultDiv').text(results[0].name); //emp_name is column name in your database
}
});
connection.end();
</script>
<!---New --->
<script>
var mysql = require('mysql');
function el(selector) {
return document.getElementById(selector);
}
el('action-btn').addEventListener('click', function(){
// Get the mysql service
getFirstTenRows(function(rows){
var html = '';
rows.forEach(function(row){
html += '<tr>';
html += '<td>';
html += row.id;
html += '</td>';
html += '<td>';
html += row.name;
html += '</td>';
html += '</tr>';
console.log(row);
});
document.querySelector('#table > tbody').innerHTML = html;
});
},false);
function getFirstTenRows(callback){
var mysql = require('mysql');
// Add the credentials to access your database
var connection = mysql.createConnection({
host : '10.251.198.2',
user : 'root',
password : '',
database : 'test'
});
// connect to mysql
connection.connect(function(err) {
// in case of error
if(err){
console.log(err.code);
console.log(err.fatal);
}
});
// Perform a query
$query = 'SELECT `id`,`name` FROM `employees` LIMIT 10';
connection.query($query, function(err, rows, fields) {
if(err){
console.log("An error ocurred performing the query.");
console.log(err);
return;
}
callback(rows);
console.log("Query succesfully executed");
});
// Close the connection
connection.end(function(){
// The connection has been closed
});
}
</script>
</body>
</html>
Index.js
const electron = require('electron');
const app = electron.app;
const path = require('path');
const url = require('url');
const BrowserWindow = electron.BrowserWindow;
var mainWindow;
app.on('ready',function(){
mainWindow = new BrowserWindow({
width: 1024,
height: 768,
webPreferences: {
nodeIntegration: true
},
//backgroundColor: '#2e2c29'
});
//mainWindow.loadURL('https://github.com');
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'test.html'),
protocol: 'file:',
slashes: true
}));
});
You can use Electron to create Desktop app and connect to Mysql database. Here are couple of useful links.
https://ourcodeworld.com/articles/read/259/how-to-connect-to-a-mysql-database-in-electron-framework
https://github.com/techiediaries/electron-mysql-demo
Node JS is primarily used to create REST API, serve web pages from the server. You may create API in Node JS using Express/Restify which interacts with DB and the Electron app can consume this service. It depends on your requirement whether or not you want to have API layer.
Sure, you can build desktop Apps nowadays in Node, in fact there is multible options that you can choose from:
Electron
Meteor
NWJS
App JS
Proton Native
All of these frameworks/technology allow you to write you App in Javascript and run it on Desktop platforms.

When database is changed value is not updating in socket.io

I have write code of socket.io and nodejs to fetch value from database and send the value to the client without refresh with setInterval. It is working fine but I don't want to use setInterval function. Because sometimes my database change in hours, sometimes in minuts and sometimes in miliseconds. So I don't want to use setInterval function. I only want that when database value change it automatically update. thats it. I am kinda stuck in it.
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
var mysql = require('mysql');
users = [];
connections = [];
disconnection = [];
var connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'test'
});
connection.connect(function(error){
if(!!error) {
console.log('Error in connection');
} else {
console.log('Database Connected');
}
});
server.listen(process.env.PORT || 3000);
console.log('Server Running...');
app.get('/', function(req, res) {
res.sendFile(__dirname + '/index.html');
});
io.sockets.on('connection', function(socket) {
connections.push(socket);
console.log('Connected: %s socket connected',
connections.length);
setInterval(function() {
connection.query('select value from piechart',
function(error, rows, fields) {
if(rows.length>0) {
io.sockets.emit('new message', {msg: rows});
//io.sockets.emit('new message', {msg:
'Change.'});
//console.log('Value is fetched from database');
//console.log(rows);
} else {
alert('what will happend');
}
//connection.release();
});
}, 3000);
});
You should take the interval out of the socket scope and make it global.
Then make an interval loop that fetches the value and emits it globally if the value changed from last time it was fetched, to all connected socket clients.
You state that you would like to avoid an interval, but at the end you are going to be needing one.
You can check out mysql-events
A Node JS NPM package that watches a MySQL database and runs callbacks
on matched events.
Another way around it, would be to find all the events that update the value and make them inform your NodeJS process.
But this might be hard if it has components that are out of your control (example : unable of adding code to other process that updates DB)

Socket.io not responding, Node.js

I'm moving my code to a server. This code works and renders database information perfectly on my own server I set up on localhost, however an error from index.html stating "io is not defined" displays when I run the code from my server. For whatever reason socket.io is not being recognized. Also, nothing is shown if I type in localhost:3000 in my browser. Any help would be greatly appreciated.
I have two files, server.js and index.html.
server.js:
var mysql = require('mysql')
var io = require('socket.io').listen(3000)
var db = mysql.createConnection({
host: '127.0.0.1', // Important to connect to localhost after connecting via ssh in screen
user: 'username',
password: '12345',
database: '12345',
port: 3306
})
// Log any errors connected to the db
db.connect(function(err){
if (err) console.log(err)
})
// Define/initialize our global vars
var notes = []
var isInitNotes = false
var socketCount = 0
//Socket.io code below
io.sockets.on('connection', function(socket){
// Socket has connected, increase socket count
socketCount++
// Let all sockets know how many are connected
io.sockets.emit('users connected', socketCount)
socket.on('disconnect', function() {
// Decrease the socket count on a disconnect, emit
socketCount--
io.sockets.emit('users connected', socketCount)
})
socket.on('new note', function(data){
// New note added, push to all sockets and insert into db
notes.push(data)
io.sockets.emit('new note', data)
// Use node's db injection format to filter incoming data
db.query('INSERT INTO notes (note) VALUES (?)', data.note)
})
console.log("10");
// Check to see if initial query/notes are set
if (! isInitNotes) {
// Initial app start, run db query
db.query('SELECT * FROM `Users`')
.on('result', function(data){
// Push results onto the notes array
//console.log(notes);
notes.push(data)
})
.on('end', function(){
// Only emit notes after query has been completed
socket.emit('initial notes', notes)
})
isInitNotes = true
} else {
// Initial notes already exist, send out
socket.emit('initial notes', notes)
}
})
index.html: (thinking the problem is in either the way I'm linking my socket.io.js file, or in the line of code where I declare the variable "socket")
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<!-- Script below works with my server I set up on local host
<script src="http://localhost:3000/socket.io/socket.io.js"></script>-->
<!-- script below properly links to the socket.io.js file in my directory, and throws no errors-->
<script type= "node_modules/socket.io/node_modules/socket.io-client/socket.io.js"></script>
<script>
$(document).ready(function(){
var socket = io.connect('http://localhost:3000'); //LINE OF CODE IN QUESTION
//Code below not really relevant to problem, but still part of my project.
socket.on('initial notes', function(data){
var html = ''
for (var i = 0; i < data.length; i++){
// We store html as a var then add to DOM after for efficiency
html += '<li>' + data[i].Name + '</li>'
}
$('#notes').html(html)
})
// New note emitted, add it to our list of current notes
socket.on('new note', function(data){
$('#notes').append('<li>' + data.Name + '</li>')
})
// New socket connected, display new count on page
socket.on('users connected', function(data){
$('#usersConnected').html('Users connected: ' + data)
})
// Add a new (random) note, emit to server to let others know
$('#newNote').click(function(){
var newNote = 'This is a random ' + (Math.floor(Math.random() * 100) + 1) + ' note'
socket.emit('new note', {note: newNote})
})
})
</script>
<ul id="notes"></ul>
<div id="usersConnected"></div>
<div id="newNote">Create a new note:</div
SOLVED!
Figured it out. I used "script src="my servers ip address:3000/socket.io/socket.io.js" and then change the variable socket to var socket = io.connect('Servers ip address:3000'); So the answer was to take out localhost all together.
I believe there could be a problem loading Socket.io from your server if it works locally (perhaps a permissions issue?), try loading it from Socket.io CDN to test.
<script src="http://cdnjs.cloudflare.com/ajax/libs/socket.io/0.9.16/socket.io.min.js"></script>

multiple websockets connections on the same client - server cannot handle

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/

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