io.connect: io is not defined but socket.io is loaded - javascript

I have built a node.js server that provides a client.html page with a list of messages from a mysql db. I can't make it work using an ajax call.
The client.html page is this:
<time></time>
<div id="container">Loading ...</div>
<script src="http://oclock.dyndns.org:8000/socket.io/socket.io.js"></script>
<!--<script src="socket.io/socket.io.js"></script>-->
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>
// create a new websocket
var socket = io.connect('http://oclock.dyndns.org:8000');
// on message received we print all the data inside the #container div
socket.on('notification', function (data) {
var msgs = '<div>';
$.each(data.flashmsgs,function(index,flashmsg){
msgs += "<b>Messaggio inviato da " + flashmsg.created_by + "</b><br>";
msgs += flashmsg.testo;
});
msgs += '</div>';
$('#container').html(msgs);
$('time').html('Last Update:' + data.time);
});
</script>
and the code for the ajax call is the following:
(function nodeLoader(){
$.ajax({
url: "client.html",
method: "get",
data: {hk: hk },
success: function(data){
$('#messaggi').html(data);
}
});
})();
The socket.io code is loaded but I get an error on io.connect: io is not defined. Same issue if i change the url from client.html to http://oclock.dyndns.org:8000 (the url of the node.js server that is listening for requests).
Any help is appreciated!
EDIT:
server.js
var hwkey;
var app = require('http').createServer(handler),
io = require('socket.io').listen(app),
url = require('url'),
fs = require('fs'),
mysql = require('mysql'),
connectionsArray = [],
connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'flipper',
database: 'oclock',
port: 3306
}),
POLLING_INTERVAL = 3000,
pollingTimer;
// If there is an error connecting to the database
connection.connect(function(err) {
// connected! (unless `err` is set)
if (err) {
console.log(err);
}
});
// creating the server ( localhost:8000 )
app.listen(8000);
function handler(req, res) {
var origin = (req.headers.origin || "*");
if (req.method.toUpperCase() === "OPTIONS"){
res.writeHead(
"204",
"No Content",
{
"access-control-allow-origin": origin,
"access-control-allow-methods": "GET, POST, PUT, DELETE, OPTIONS",
"access-control-allow-headers": "content-type, accept",
"access-control-max-age": 10, // Seconds.
"content-length": 0
}
);
return( res.end() );
}
console.log("INCOMING REQUEST: "+req.method+" "+req.url);
req.parsed_url = url.parse(req.url, true);
var getp = req.parsed_url.query;
hwkey = getp.hk;
fs.readFile(__dirname + '/client.html', function(err, data) {
if (err) {
console.log(err);
res.writeHead(500);
return res.end('Error loading client.html');
}
res.writeHead(
200,
{
"access-control-allow-origin": origin,
"content-length": data.length
}
);
res.end(data);
});
}
function pollingLoop(){
// Doing the database query
var query = connection.query('SELECT id, testo, created_by FROM flashmsgs WHERE hwk="'+hwkey+'" AND letto="0"'),
//var query = connection.query('SELECT max(id), testo, created_by FROM flashmsgs'),
flashmsgs = []; // this array will contain the result of our db query
// setting the query listeners
query
.on('error', function(err) {
// Handle error, and 'end' event will be emitted after this as well
console.log(err);
updateSockets(err);
})
.on('result', function(flashmsg) {
// it fills our array looping on each user row inside the db
flashmsgs.push(flashmsg);
})
.on('end', function() {
// loop on itself only if there are sockets still connected
if (connectionsArray.length) {
pollingTimer = setTimeout(pollingLoop, POLLING_INTERVAL);
updateSockets({
flashmsgs: flashmsgs
});
} else {
console.log('The server timer was stopped because there are no more socket connections on the app')
}
});
};
// creating a new websocket to keep the content updated without any AJAX request
io.sockets.on('connection', function(socket) {
console.log('Number of connections:' + connectionsArray.length);
// starting the loop only if at least there is one user connected
if (!connectionsArray.length) {
pollingLoop();
}
socket.on('disconnect', function() {
var socketIndex = connectionsArray.indexOf(socket);
console.log('socketID = %s got disconnected', socketIndex);
if (~socketIndex) {
connectionsArray.splice(socketIndex, 1);
}
});
console.log('A new socket is connected!');
connectionsArray.push(socket);
});
var updateSockets = function(data) {
// adding the time of the last update
data.time = new Date();
console.log('Pushing new data to the clients connected ( connections amount = %s ) - %s', connectionsArray.length , data.time);
console.log(hwkey);
// sending new data to all the sockets connected
connectionsArray.forEach(function(tmpSocket) {
tmpSocket.volatile.emit('notification', data);
});
};
console.log('Please use your browser to navigate to http://localhost:8000');

Okay, I misunderstood at first. I just investigated your live app and it appears your ajax call is pulling down an entire html document.
If you're loading markup via ajax and then inserting into the existing page, you don't want a full HTML document. Just send down the body content.
Also, the socket.io script reference should ideally be on the parent page, not the page loaded via ajax.

Related

Create rest api to retrieve data from odoo erp

I am creating a rest api service to get, put, delete data from odoo erp .
Here is my code :
const Promise = require('bluebird');
Promise.promisifyAll(require('node-odoo').prototype);
const Odoo = require('odoo-xmlrpc');
const odoo = new Odoo({
url: 'zzzz',
port: 'zz',
db: 'zzzz',
username: 'zzzz',
password: 'zzz*'
});
var express = require('express'),
app = express(),
port = process.env.PORT || 3000;
this.router = express.Router();
app.listen(port);
console.log('todo list RESTful API server started on: ' + port);
this.router.get('/api/event/', (req, res) => {
return getEvent(req, res);
});
app.get('/getEvent', (request, response) => {
odoo.connect((err) => {
if(err) return console.log('Findeventlist error ' + err);
console.log('Findeventlist connected ' );
var inParams = [];
inParams.push([]);
inParams.push(['name' ])
inParams.push(0)
inParams.push(5)
var params = [];
params.push(inParams);
odoo.execute_kw('calendar.event', 'search_read', params, function (err, value) {
if (err) { return console.log(err) }
if(value){
console.log( 'Value is ' + response.status(200).json(value));
return response.status(200).json(value)
}
});
});
console.log(' odoo connected');
})
I got this error : Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
Can you help me please where i'm wrong?
response.status(200).json(value) responds to the client and ends the transaction (just like response.end() or response.sendFile() etc).
It must be called only once, but you execute it twice (once inside the console.log() then once "for real" the next line). That's why the headers are "already sent".
Remove the useless response.json() from the console.log and log only the value you want to see.

How to post data from my html page to a listener?

I'm currently designing a UI for an Automated Parking System. I currently need to test if my page sends out data from a form by sending it to a listener. I currently have this code but I'm not sure why it isn't working. Any help would be greatly appreciated.
This is my code that sends the data to a local listener.
<script>
var INPARK = {cardID: $("#ticket_num").val(), lift: 1, floor: 1};
$.ajax({
type:"POST",
url: '192.168.150.148:5007',
contentType:"application/json",
data: JSON.stringify(INPARK)
});
</script>
This is the listener code.
var HOST = '192.168.150.148'; // This should be your IP of 192.168.150.XXX
var PORT = 5007;
var http = require('http');
http.createServer(function (req, res) {
// Only listen for POST requests
if (req.method === 'POST') {
var buffer = '';
req.on('data', function (chunk) {
buffer += chunk;
});
req.on('end', function () {
var path = req.url.substring(0, req.url.indexOf('/', 1)).toUpperCase();
var json;
try {
json = JSON.parse(buffer);
} catch (err) {
//
}
if (path === '/INPARK') {
// Handle INPARK request
console.log(json);
res.write('inpark results');
} else if (path === '/OUTPARK') {
// Handle OUTPARK request
console.log(json);
res.write('outpark results');
} else {
// Do nothing - Bad request
res.write('BAD REQUEST');
}
// Close the connection
res.end();
});
}
}).listen(PORT, HOST, function () {
console.log('Listening at %s:%s', HOST, PORT);
});
Your ajax request is most likely going from port 80 or 443 to 5007, which is a cross domain request, hence it will fail,
If you want to resolve this issue, read up on CORS:
https://en.wikipedia.org/wiki/Cross-origin_resource_sharing,
and JSONP:
https://en.wikipedia.org/wiki/JSONP

jsonp GET request 404 Error

I'm using Nodejs, Socket.io, and Angular to build a web app taking advantage of the Instagram Real-Time API. I'm running into an issue when I fire off GET requests to the Instagram API.
I get this error every time I send a GET request:
"Failed to load resource: the server responded with a status of 404 (NOT FOUND)"
The error details reveal:
https://api.instagram.com/v1/geographies/[object%20Object]/media/recent?client_id=MY_CLIENT_ID
Obviously that [object%20Object] is where the error lies. As my code below shows, that should be the 'geo_id' which I'm passing in as an argument. Geo_id is actually the 'object_id' of the Instagram real-time subscription.
Below is my code. Any idea where I'm going wrong?
Socket.io server side code:
io.sockets.on('connection', function(socket) {
// log user connections
console.log("user connected");
// receive the Instagram handshake for real-time subscriptions
app.get('/callback', function(req, res){
var handshake = Instagram.subscriptions.handshake(req, res);
});
// for each new post Instagram sends us the data
app.post('/callback', function(req, res) {
var data = req.body;
// grab the object_id (as geo_id) of the subscription and send as an argument to the client side
data.forEach(function(data) {
var geo_id = data.object_id;
sendUpdate(geo_id);
});
res.end();
});
// send the url with the geo_id to the client side
// to do the ajax call
function sendUpdate(geo_id) {
io.sockets.emit('newImage', { geo_id: geo_id });
}
// log user disconnections
socket.on('disconnect', function () {
console.log('user disconnected');
});
});
relevant angular controller code:
socket.on('newImage', function(geo_id) {
// pass geo_id into Instagram API call
Instagram.get(geo_id).success(function(response) {
instagramSuccess(response.geo_id, response);
});
// Instagram API callback
var instagramSuccess = function(scope,res) {
if (res.meta.code !== 200) {
scope.error = res.meta.error_type + ' | ' + res.meta.error_message;
return;
}
if (res.data.length > 0) {
$scope.items = res.data;
} else {
scope.error = "This location has returned no results";
}
};
});
Instagram angular factory code:
angular.module('InstaFactory', []).factory('Instagram', function($http) {
var base = "https://api.instagram.com/v1";
var client_id = 'MY_CLIENT_ID';
return {
'get': function(geo_id) {
var request = '/geographies/' + geo_id + '/media/recent?client_id=' + client_id;
var url = base + request;
var config = {
'params': {
'callback': 'JSON_CALLBACK'
}
};
return $http.jsonp(url, config);
}
};
});

Long polling with Node.js and ajax

I have following server code.
var http = require('http');
var mysql = require('mysql');
var querystring = require('request');
var util = require('util');
var url = require('url');
var singer_name;
var currentmodif, lastmodif;
var requests=[];
var response;
var connection = mysql.createConnection({
host : 'localhost',
user : 'someone',
password : 'xxxxxxx',
database : 'rest', //mysql database to work with (optional)
});
connection.connect(); //connect to mysql
connection.query('SELECT * FROM musics WHERE id=1', function(err, rows, fields) {
if (err) throw err;
singer_name=rows[0].singer_name;
currentmodif=rows[0].time_added;
});
http.createServer(function (req, res) {
console.log('request received');
requests.push({
response: res,
timestamp: new Date().getTime()
});
if(req.method=='GET'){
var url_parts = url.parse(req.url,true);
lastmodif = url_parts.query.timestamp;
}
//check_update(req, res);
}).listen(9000);
setInterval(function() {
var expiration = new Date().getTime() - 30000;
for (var i = requests.length - 1; i >= 0; i--) {
//console.log("Request timestamp: "+requests[i].timestamp+" Expiration : "+expiration);
response = requests[i].response;
if (requests[i].timestamp < expiration) {
console.log("The condition is met");
response.writeHead(200, {
'Content-Type' : 'text/plain',
'Access-Control-Allow-Origin' : '*'
});
// return response
response.write('_testcb(\'ok\')', 'utf8');
response.end();
//break;
}
}
connection.query('SELECT * FROM musics WHERE id=1', function(err, rows, fields) {
if (err) throw err;
currentmodif=rows[0].time_added;
//console.log("currentmodif: "+currentmodif+" lastmodif: "+lastmodif);
if (currentmodif > lastmodif){
singer_name=rows[0].singer_name;
var _arrays = {'singer_name': singer_name, 'time': currentmodif}
var data = "_testcb"+"("+JSON.stringify(_arrays)+")";
response.writeHead(200, {
'Content-Type' : 'text/plain',
'Access-Control-Allow-Origin' : '*'
});
if (response.end(data))
console.log("Response successfully sent");
//return false;
}
});
}, 2000);
and Client code:
<html>
<head>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<title>Node.js Ajax test</title>
</head>
<body>
</body>
<script>
var timestamp = "1380020402";
function callNode() {
var time = "1380020402";
$.ajax({
url: 'http://xx.xxx.xx.xxx:9000/',
dataType: "jsonp",
data: {"timestamp":timestamp},
type: 'POST',
jsonpCallback: "_testcb",
cache: false,
timeout: 35000,
success: function(response, code, xhr) {
if ('ok' == response) {
callNode();
return false;
}
console.log(response);
timestamp = response.time;
// make new call
callNode();
},
error: function(jqXHR, textStatus, errorThrown) {
console.log('error ' + textStatus + " " + errorThrown);
}
});
}
$(function () {
callNode();
});
</script>
</html>
I am trying to do a long polling. So until a data in database is updated, the response to ajax request should be paused but the above code is not working. I am making the ajax request from different domain and therefore using jsonp.
Exact problem is that currently when the data is changed in database the response doesn't get sent. It works every now and then but it is not consistently reliable.
Another problem is that the code block for time out is not working. If the request is 30 seconds old then a blank response should be sent in order to avoid the timeout from ajax.
If someone can help then I would appreciate.
Cheers.
I have figured this out. Amended code that work is as below:
Client side:
<html>
<head>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<title>Node.js Ajax test</title>
</head>
<body>
</body>
<script>
var timestamp;
function callNode() {
$.ajax({
url: 'http://xx.xxx.xx.xxx:9000/',
dataType: "jsonp",
data: {"timestamp":timestamp},
//type: 'POST', //don't need this with jsonp
jsonpCallback: "_testcb",
cache: false,
timeout: 35000,
success: function(response, code, xhr) {
if ('ok' == response) {
console.log(response);
callNode();
return false;
}
console.log(response);
timestamp = response.time;
// make new call
callNode();
},
error: function(jqXHR, textStatus, errorThrown) {
console.log('error ' + textStatus + " " + errorThrown);
}
});
}
$(function () {
setTimeout(callNode, 1); //call function with setTimeout in order to avoid ugly constant browser loading
});
</script>
</html>
Server Side (server.js):
var http = require('http');
var mysql = require('mysql');
var util = require('util');
var url = require('url');
var singer_name, currentmodif, lastmodif, request, response, time_of_request;
//var requests=[];
var connection = mysql.createConnection({
host : 'localhost',
user : 'someone',
password : 'xxxxxx',
database : 'rest', //mysql database to work with (optional)
});
connection.connect(); //connect to mysql
connection.query('SELECT * FROM musics WHERE id=1', function(err, rows, fields) {
if (err) throw err;
singer_name=rows[0].singer_name;
currentmodif=rows[0].time_added;
});
http.createServer(function (req, res) {
request = req;
response = res;
time_of_request = new Date().getTime();
console.log('request received');
if(req.method=='GET'){
var url_parts = url.parse(req.url,true);
lastmodif = url_parts.query.timestamp;
}
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
//checkupdate();
}).listen(9000);
var response;
function checkupdate() {
var expiration = new Date().getTime() - 30000;
//for (var i = requests.length - 1; i >= 0; i--) {
//console.log("Request timestamp: "+time_of_request+" Expiration : "+expiration);
if (time_of_request < expiration) {
console.log("The condition is met");
// return response
response.write('_testcb(\'ok\')', 'utf8');
response.end();
}
//}
connection.query('SELECT * FROM musics WHERE id=1', function(err, rows, fields) {
if (err) throw err;
currentmodif=rows[0].time_added;
if (lastmodif == undefined)
lastmodif = 0;
console.log("currentmodif: "+currentmodif+" lastmodif: "+lastmodif);
if (currentmodif > lastmodif){
singer_name=rows[0].singer_name;
var _arrays = {'singer_name': singer_name, 'time': currentmodif}
var data = "_testcb"+"("+JSON.stringify(_arrays)+")";
//response.writeHead(200, { 'content-type':'application/json',
//'Access-Control-Allow-Origin' : '*'});
//response.write(data);
response.end(data);
console.log("Response successfully sent");
//return false;
}
});
};
setInterval(checkupdate, 2000);
The problem was with the server side. The response object was not available (it was undefined) when server wanted to reply and therefore the response was not being sent. I may have overlooked the error in the node.js's console.
This is almost a complete example of long polling with node.js with MYSQL database. This script will wait for fresh data to become available before replying to the ajax request. If fresh data (in MYSQL) is not available within 30 seconds of the request then a fake reply is made so that the request does not time out. There is a condition in ajax's success callback that re-initiates this ajax request when this demo response is received, therefore making this an infinite loop.
I have successfully tested code above and it seems to work fine. I ran the script and then updated the data in my database (mainly the time_added field) and this triggered a reply to my waiting ajax call with new data from node.js's server.
I hope this code helps someone out there.
Checkout tutorial here for further explanation: http://www.sahilsaid.com/blog/long-polling-node-js-mysql-database-ajax/

How to push changes in a database to the client using socket.io?

I am working on an app which, among other things, pushes data to the client when an updation occurs on the database. The trouble is that the websocket on node.js listens to the databse on a different port then the node. The guy before me wrote a piece of code and then dumped it on me. The node looks somewhat like this:
var handler=http.createServer(function(req, res){
session(req, res, function(req, res, body) {
if (!req.session || !req.session.data || !req.session.data.uid || req.session.data.uid == '' || !req.session.data.role || req.session.data.role =='') {
var uri = url.parse(req.url).pathname;
if(req.method == 'GET' && uri =="/attendance-node/getMonthFromReport") {
var uri = url.parse(req.url).pathname;
var url_parts = url.parse(req.url,true);
processgetMonthFromReport(req, res, uri, url_parts.query);
return;
}
res.writeHead(401, {"Content-Type": "text/plain"});
res.write("401 Unauthorized");
res.end();
return;
}
if(req.method == 'POST') {
var uri = url.parse(req.url).pathname;
var qs = require('querystring');
var POSTVAR = qs.parse(body, '&', '=', {"maxKeys" : 0});
//var POSTVAR=JSON.parse(body);
handleRequest(req, res, uri, POSTVAR);
}
if (req.method=='GET') {
var uri = url.parse(req.url).pathname;
var url_parts = url.parse(req.url,true);
handleRequest(req, res, uri, url_parts.query);
}
});
}).listen(3014,"127.0.0.1");
var io = require('socket.io').listen(8077,"127.0.0.1");
sys.puts("websocket Server running on port 8077");
io.configure(function () {
io.set('transports', ['websocket', 'flashsocket', 'xhr-polling','jsonp-polling']);
io.set('log level', 0);
});
io.sockets.on('connection', function (socket) {
io.sockets.emit('init',"i am working via websocket");
});
As you can see the node is listening on 3014 and the socket on 8077. Now how am I suppossed to provide an handler for the message received on the socket and forward it to the node's client?
Note: I am fairly new to web development. So basically I was thrown in the water and now I am learning to swim.
P.S. Also, what would the client side of the socket look like?
P.P.S. The database sending update notification to the socket is already taken care of. It comes as a POST request.
Thanx in advance!!
It sounds like you want to have socket.io also on the client side (browser?) as well.
I'd say the best solution would be to have socket.io run on the same port as your web server. However, if it this not possible and you must keep the web socket that the database uses separate from the web server you could run two instances of socket.io.
One would be attached to the web server, and the other would be for the database.
var app = require('http').createServer(handler)
, IO = require('socket.io')
, web_io = IO.listen(app)
, data_io = IO.listen(8080)
, fs = require('fs')
app.listen(80);
function handler (req, res) {
fs.readFile(__dirname + '/index.html',
function (err, data) {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
});
}
web_io.sockets.on('connection', function (socket) {
socket.on('some_event', function (data) {
console.log(data);
});
});
data_io.sockets.on('connection', function (socket) {
socket.on('database_update', function (data) {
// Will be sent to everyone socket listening on port 80 (browser sockets mostlikely)
web_io.sockets.emit('database_update', data);
});
socket.on('disconnect', function () {
io.sockets.emit('user disconnected');
});
});

Categories