I'm trying to create a webtracker to track what pages my users are seeing and how much time they are spending at each page, at the end they will make a registration and i will associate their navigation with the created user.
I want to use node because i can see when the user connect to the url and disconnect to calculate the time, i have tried that with pure javascript but i can see when the user leaves the page only on Chrome.
I have already managed to create some of what i need using the socket.io lib but i can't find a way to use it without creating an html page. What i need is to create something like google analytics where i will only incorporate the script. Is it possible?
I have managed to figure it out so i will post it to help others with the same problem:
Server
let socket = require('socket.io');
let http = require('http');
let serveStatic = require('serve-static');
let finalhandler = require('finalhandler');
var port = process.env.PORT || 1337;
let serve = serveStatic(__dirname, { 'index': ['client.js'] });
let server = http.createServer(function (req, res) {
serve(req, res, finalhandler(req, res));
});
let io = socket(server);
server.listen(port);
io.on('connection', client => {
console.log('new user connected!', client.id);
client.on('hello', data => {
console.log('data: ', data);
});
client.on('disconnect', () => {
console.log('user disconnected', client.id);
});
});
Client
(function (plugin) {
plugin.socket = null;
function loadDependencies() {
head.js(
{ socket: 'https://cdn.socket.io/socket.io-1.4.5.js' }
);
head.ready('socket', function() {
plugin.socket = io('http://localhost:1337');
setSocketHandlers();
});
}
function setSocketHandlers() {
plugin.socket.on('my-event', function(data){
console.log('called my event');
});
}
plugin.init = () => {
loadDependencies();
}
}(this.WebTracker = this.WebTracker || {}));
WebTracker.init();
Related
I have a simple authentication app to instagram. After I authenticate to instagram and receive user profile I would like to send the username from server side to reactjs client side. I tried using socket IO but I can't make it work.
Client side
componentDidMount() {
const { socket, provider } = this.props
console.log('component did mount')
socket.on(provider, user => { //provider is a string e.g 'instagram'
//receives data and update state.
this.setState({user})
})
}
startAuth() { //onclick function that opens up new window for auth
const {provider} = this.props
const width = 600, height = 600
const left = (window.innerWidth / 2) - (width / 2)
const top = (window.innerHeight / 2) - (height / 2)
const url = `https://localhost:5000/${provider}`
return window.open(url, '',
`toolbar=no, location=no, directories=no, status=no, menubar=no,
scrollbars=no, resizable=no, copyhistory=no, width=${width},
height=${height}, top=${top}, left=${left}`
)
}
Server side
//After successful authentication redirect here with username and provider as
//query string. Here I want to emit to my component and update component's state
app.get('/success', (req, res) => {
var provider = req.query.provider
var username = req.query.username
io.emit(provider, username); //this doesn't work
res.send('Auth to ' + provider + ' successful by ' + username)
})
What should I do in order for the emitted event in server side to get caught by the on inside componentDidMount()? I got no error messages whatsoever. I'm not even sure if the emitted event at /success got fired or not.
Socket connection works fine, I did the following code below and it works fine.
io.on('connection', (client) => {
client.on('subscribeToTimer', (interval) => {
console.log('client is subscribing to timer with interval', interval);
setInterval(() => {
client.emit('timer', new Date());
}, interval);
})
})
I faced a similar problem on a project I was working upon & the way I solved the problem was
Create file io.js
// singleton instance of socket.io that is stored here after the
// constructor function is called
let ioInstance;
module.exports = function(server) {
const io = require("socket.io")(server);
io.on("connection", socket => {
console.log("made socket connection", socket.id);
// Handle socket event
socket.on("eventTrigger", function(data) {
// console.log(data);
io.sockets.emit("chat", data);
});
});
// save in higher scope so it can be obtained later
ioInstance = io;
return io;
};
// this getIO method is designed for subsequent
// sharing of the io instance with other modules once the module has been initialized
// other modules can do: let io = require("./io.js").getIO();
module.exports.getIO = () => {
if (!ioInstance) {
throw new Error(
"Must call module constructor function before you can get the IO instance"
);
}
return ioInstance;
};
In file bin/www add below code
var app = require("../app");
var debug = require("debug")("express-sequelize");
var http = require("http");
var models = require("../models");
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || "3000");
app.set("port", port);
/**
* Create HTTP server.
*/
var server = http.createServer(app);
//initialize io
require("../io")(server);
server.listen(port, function() {
debug("Express server listening on port " + server.address().port);
});
server.on("error", onError);
server.on("listening", onListening);
now in route file for an api call if I wanted to send socket data
#file app.js
app.get('/success', (req, res) => {
const io = require("./io").getIO();
....
io.sockets.emit("eventTrigger",data);
res.send('Auth to ' + provider + ' successful by ' + username)
})
Hope this approach helps in fixing the issue that you are facing.
I am using Adonis 4.1.0 and Adonis-websocket is only been available for v3. Can anyone tell me workaround for using socket.io with Adonis 4.1.0?
apparently they have been working on this not long ago, it was based on socket.io but because of some issues like memory leaks and others, they decided to use websockets directly instead, check these discussions :
https://github.com/adonisjs/discussion/issues/51
https://forum.adonisjs.com/t/integrating-socket-io-with-adonis-4/519
have you tried using socket.io without relying on Adonis ? ,
something like :
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
io.on('connection', function(socket){
console.log('a user connected');
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
But you should be able to do this with Adonis by now according to : https://github.com/adonisjs/adonis-websocket-protocol
Example :
const filereader = require('simple-filereader')
const msgpack = require('msgpack-lite')
const packets = require('#adonisjs/websocket-packets')
const client = new WebSocket('ws://localhost:3000/adonis-ws')
client.onopen = function () {
// TCP connection created
}
client.onerror = function () {
// TCP connection error
}
client.onmessage = function (message) {
filereader(message, function (error, payload) {
const packet = msgpack.decode(payload)
handlePacket(packet)
})
}
function handlePacket (packet) {
if (packets.isOpenPacket(packet)) {
console.log('Server ack connection. Make channel subscriptions now')
}
if (packets.isJoinAck(packet)) {
console.log('subscription created for %s', packet.d.topic)
}
}
check this for broadcast examples using WS : https://github.com/websockets/ws#broadcast-example
Create start/socket.js file and paste following code inside it.
const Server = use('Server')
const io = use('socket.io')(Server.getInstance())
io.on('connection', function (socket) {
console.log(socket.id)
})
From Virk Himself in this forum:https://forum.adonisjs.com/t/integrating-socket-io-with-adonis-4/519
create a standalone socket io configuration file in start/socket.js
const io = require('socket.io')();
io.listen(3000);
io.on('connection', function (socket) {
console.log(socket.id)
})
to start your socket io server you can configure your server.js as below
new Ignitor(require('#adonisjs/fold'))
.appRoot(__dirname)
.preLoad('start/socket') //path of socket.js
.fireHttpServer()
.catch(console.error)
now when you start your server then it will start along with socket io
I'm currently trying to have an angular2 frontend communicating with a node.js backend with socket.io.
The point is, I get the client connected to the server, but after that, no socket call can be successfully passed between them.
Here is a simple piece a code for the server :
var app = require('express')();
var http = require('http');
var server = http.createServer(app);
var io = require('socket.io').listen(server);
io.on('connection', function() {
io.emit('update');
console.log('Connected');
});
io.on('updated', function() {
io.emit('update');
console.log('Updated');
});
server.listen(5000, function() {
console.log('Listening on 5000');
});
... and for the component :
import { Component } from '#angular/core';
import * as io from 'socket.io-client';
#Component({
selector: 'main-app',
template: `
<div>
<button (click)="foo()"
style='padding:20px; background:red; color:white'>
click me
</button>
</div>
`
})
export class AppComponent {
title = 'bar';
socket = null;
constructor() {
let self = this;
self.socket = io.connect('http://mysuperwebsite:5000', {
transports : ["websocket"]
});
self.socket.on('update', function(data) {
console.log(data);
});
}
foo() {
let self = this;
self.socket.emit('updated', {});
}
}
I can't get what is wrong, I guess you will ;)
Thanks for your help !
EDIT : Finally, the problem seemed to come from the lack of second parameter in io.emit(). Now it works, thanks you very much :)
Instead of debugging your code, I'll post you an example that works and you can go from there:
Socket.IO Server
Socket.IO server example using Express.js:
var path = require('path');
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', (req, res) => {
console.error('express connection');
res.sendFile(path.join(__dirname, 'si.html'));
});
io.on('connection', s => {
console.error('socket.io connection');
for (var t = 0; t < 3; t++)
setTimeout(() => s.emit('message', 'message from server'), 1000*t);
});
http.listen(3002, () => console.error('listening on http://localhost:3002/'));
console.error('socket.io example');
Source: https://github.com/rsp/node-websocket-vs-socket.io/blob/master/si.js
Socket.IO Client
Socket.IO client example using vanilla JavaScript:
var l = document.getElementById('l');
var log = function (m) {
var i = document.createElement('li');
i.innerText = new Date().toISOString()+' '+m;
l.appendChild(i);
}
log('opening socket.io connection');
var s = io();
s.on('connect_error', function (m) { log("error"); });
s.on('connect', function (m) { log("socket.io connection open"); });
s.on('message', function (m) { log(m); });
Source: https://github.com/rsp/node-websocket-vs-socket.io/blob/master/si.html
That example can be installed from npm or downloaded from GitHub. It's as simple as it gets and it's known to work so you can have a working backend part to test your frontend with.
It was written for this answer - you can find mush more info there.
Your server setup seems to be incorrect.
Try this:
io.on('connection', function(socket) {
socket.emit('update');
console.log('Connected');
socket.on('updated', function() {
socket.emit('update');
console.log('Updated');
});
});
Tried different methods, but the data is sent to a maximum of one or two clients. How to send data to all the clients connected to the server ? What am I doing wrong?
Server.js:
var PORT = 3000;
var options = {
// 'log level': 0
};
var express = require('express');
var app = express();
var http = require('http');
var server = http.createServer(app);
var io = require('socket.io').listen(server, options);
server.listen(PORT);
app.get('/', function (req, res) {
res.sendfile(__dirname + '/attantions/templates/.default/template.php');
});
io.sockets.on('connection', function (client) {
client.on('attantion', function (data) {
try {
// Tried so
io.sockets.volatile.emit('attantion', data);
// And tried so
io.sockets.emit('attantion', data);
client.emit('attantion', data);
client.broadcast.emit('attantion', data );
} catch (e) {
console.log(e);
client.disconnect();
}
});
});
Client.js:
socket.emit("attantion", data);
socket.on('attantion', function (data) {
pushData(data);
});
See this post for different options for socket.io messages
Send response to all clients except sender (Socket.io)
io.sockets.on('connection', function (client) {
client.on('attantion', function (data) {
//client.emit('attantion', data ); // This will send it to only the client
//client.broadcast.emit('attantion', data); // This will send it to everyone but this client
io.emit('attantion', data); // This will send it to all attached sockets.
});
});
Edit
I wonder if this post can help you?
Socket.io - Cannot load file
I was curious how sending the php file to the client through node.js works? are you using another framework?
Could you show more of what your client code looks like? loading the lib and the instantiation of the socket.
I've found this script for reading a file an "broadcast" its content to every connection.
var serverServiceConfig={port: 8081};
var express = require("express");
var app = express();
var fs = require('fs');
var socket = require('socket.io');
function readTick(ws){
fs.readFile('tick.json', 'utf8', function (err,data) {
if (!err) {
try {
ws.emit('ticks', data);
} catch (e) {
// handle error
console.log('can not read file');
}
}
});
setTimeout(function () {
readTick(ws);
}, 200);
}
console.log('server is running ...');
app.configure(function(){
app.use(express.static(__dirname + '/'));
});
var server = app.listen(serverServiceConfig.port);
var io = socket.listen(server);
io.sockets.on('connection', function (socket) {
readTick(socket);
socket.on('disconnect', function (socket) {
});
});
The server starts without an error, so far so good. But if i try to connect to the server via ip:port i get the following message:
Cannot GET /
I tested this script on my local machine and it worked (a couple of weeks ago)
From what i "know" or i think is that a route is missing, or?
Any help is more than welcome.
Thank you in advance
Instead of using that function, you should put it in app.get('/', function(){//whatever you want to do//})