Real time message receiving from server (Database - MySQL, Frontend -Angularjs) - javascript

My code is working perfectly , But i need to refresh my page to get
new message . I want the real time message.
Angular controller's function -
$scope.getAllMessages = function() {
$scope.messages=[];
restservice.get('', "api/v1/message/getMessageList").then(function(response) {
if (response != null) {
for (var i = 0; i < response.length; i++) {
$scope.messages.push(response[i]);
}
}
});
}
My UI looks like -
<li ng-repeat="message in messages" class="{{(message.me == '1')? 'me' : 'other'}}">
<div>
{{message.userMessage}}
</div>
</li>
Please make it simple for me and give me a proper guideline/tutorial to do it. I'm bad at front end.

Another way is to use WebSockets.
Javascript has built-it WebSocket object wich you can use. And you also need to handle websockets on your server side. But for messaging websockets or long polling requests looks as more useful technologies, as for me.
WebSockets are very simple and if you want real-time, they could be useful. But you would have to implement websockets backend on your server. Here is a sample of WS usage from the JS side:
var exampleSocket = new WebSocket("ws://www.example.com/socketserver", "protocolOne");
exampleSocket.send("Here's some text that the server is urgently awaiting!");
exampleSocket.onmessage = function (event) {
console.log(event.data);
}
This is example from here: https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications

You need to call getAllMessages method on interval basis so that you get live data or real time data
Link here
https://docs.angularjs.org/api/ng/service/$interval
check with the above link for Example how to implement

To avoid getting ALL messages again i will considere do another .get maybe like this:
$interval(getLastMessagesFrom, 1000);
function getLastMessagesFrom () {
// Extract the last message_ID from $scope.messages, to do this maybe
// you will need to change your backend code to add the message ID in
// the message object. This deppends on your backend code & backend
// message response.
var last_message_id = $scope.messages[$scope.messages.length-1].id;
restservice.get('', "api/v1/message/getMessageList/" + last_message_id).then(function(response) {
if (response != null) {
// Now make sure that your server only returns messages with
// ID higher than last_message_id
for (var i = 0; i < response.length; i++) {
$scope.messages.push(response[i]);
}
}
});
}
Anyways this is still a bad practice if you have a lower time interval (1000 = 1 second) and a lot of concurrent users.
Considere use sockets to avoid repeated and unecessary calls.

use nodeJS's sockets
where you can achieve real-time experience.
e.g
once you inserted to database,you can fire JS command to emit msg realtime
io.sockets.connected[setsocketid].emit("clssifiedMessage", {msg:"Hi!!!how are yyou?" });

Related

AJAX: People interacting on a page in real time without a database?

Background
I am trying to design an interactive classroom type of environment. The room has different slides, a chat box and some other basic features.
My understanding
A sure way to update a page in real time for all users is for one person to persist a change via ajax to a database, then all the other users poll the server at a timed interval (one second) to check for changes... if there are their view gets updated.
My code
Each room has a unique URL... http://www.example.com/room/ajc73
Users slide through the clides using this code:
showCard();
function showCard() {
$('#card-' + (cardId)).show();
}
$('#nextCard').click(function() {
nextCard();
});
$('#previousCard').click(function() {
previousCard();
});
function nextCard() {
if ($('#card-' + (cardId + 1)).length != 0) { // if there is a next card
$('#card-' + (cardId)).hide(); // hide current card
cardId++; // increment the card id
$('#card-' + (cardId)).show(); // and show the next card
location.hash = cardId;
}
}
function previousCard() {
if (cardId != 1) { // if we are not at the first card
$('#card-' + (cardId)).hide(); // hide the current card
cardId--; // decrement the card id
$('#card-' + (cardId)).show(); // and show the previous card
location.hash = cardId;
}
}
My question
Am I required to persist data from user1 to the database in order for it to be called and displayed to user2 or is there a way to cut out the database part and push changes directly to the browser?
Go for websockets. that will be a better option. since its real-time and just a simpler logic will help you achieve the result.
If you are not sure that whether you will be able to use websockets(like if you are using shared hosting and your provider doesn't allow this or any other reason) you can go for various services like pusher(easier to understand) that will help to do your job but with some cost.
You could use sockets and just broadcast any input to every client.
Of course, the same can be done with ajax and a rest api but it'll be harder, i'll use pseudocode:
clients = {};
fn newclient() {
clients[client_id] = {
pool: [];
....
}
}
fn onNewMessage(newmessage) {
forEach(client, fn(c) {
c.pool.push(newmessage);
})
}
fn clientRequestNews() {
response = clients[client].pool;
clients[client].pool.length = 0;
return response;
}
the point here is, in server memory there would be a entry for each client, each of them has a pool, when a new message is sent to the server, it's pushed to every client's pool.
When a client ask's for news, the server will return the clients pool, after that, it'll clean the pool of that client.
With this you dont need persistence.
Use web sockets. Please see here
You need websockets, a datastructure server and a pub/serve model with events:
A hint

JS: Node.js and Socket.io - globals and architecture

Dear all,
Im working with JS for some weeks and now I need a bit of clarification. I have read a lot of sources and a lot of Q&A also in here and this is what I learned so far.
Everything below is in connection with Node.js and Socket.io
Use of globals in Node.js "can" be done, but is not best practice, terms: DONT DO IT!
With Sockets, everything is treated per socket call, meaning there is hardly a memory of previous call. Call gets in, and gets served, so no "kept" variables.
Ok I build up some chat example, multiple users - all get served with broadcast but no private messages for example.
Fairly simple and fairly ok. But now I am stuck in my mind and cant wrap my head around.
Lets say:
I need to act on the request
Like a request: "To all users whose name is BRIAN"
In my head I imagined:
1.
Custom object USER - defined globally on Node.js
function User(socket) {
this.Name;
this.socket = socket; }
2.
Than hold an ARRAY of these globally
users = [];
and on newConnection, create a new User, pass on its socket and store in the array for further action with
users.push(new User(socket));
3.
And on a Socket.io request that wants to contact all BRIANs do something like
for (var i = 0; i < users.length; i++) {
if(user[i].Name == "BRIAN") {
// Emit to user[i].socket
}}
But after trying and erroring, debugging, googling and reading apparently this is NOT how something like this should be done and somehow I cant find the right way to do it, or at least see / understand it. can you please help me, point me into a good direction or propose a best practice here? That would be awesome :-)
Note:
I dont want to store the data in a DB (that is next step) I want to work on the fly.
Thank you very much for your inputs
Oliver
first of all, please don't put users in a global variable, better put it in a module and require it elsewhere whenever needed. you can do it like this:
users.js
var users = {
_list : {}
};
users.create = function(data){
this._list[data.id] = data;
}
users.get = function(user_id){
return this._list[user_id];
};
users.getAll = function(){
return this._list;
};
module.exports = users;
and somewhere where in your implementation
var users = require('users');
For your problem where you want to send to all users with name "BRIAN",
i can see that you can do this good in 2 ways.
First.
When user is connected to socketio server, let the user join a socketio room using his/her name.
so it will look like this:
var custom_namespace = io.of('/custom_namespace');
custom_namespace.on('connection', function(client_socket){
//assuming here is where you send data from frontend to server
client_socket.on('user_data', function(data){
//assuming you have sent a valid object with a parameter "name", let the client socket join the room
if(data != undefined){
client_socket.join(data.name); //here is the trick
}
});
});
now, if you want to send to all people with name "BRIAN", you can achieve it by doing this
io.of('/custom_namespace').broadcast.to('BRIAN').emit('some_event',some_data);
Second.
By saving the data on the module users and filter it using lodash library
sample code
var _lodash = require('lodash');
var Users = require('users');
var all_users = Users.getAll();
var socket_ids = [];
var users_with_name_brian = _lodash.filter(all_users, { name : "BRIAN" });
users_with_name_brian.forEach(function(user){
socket_ids.push(user.name);
});
now instead of emitting it one by one per iteration, you can do it like this in socketio
io.of('/custom_namespace').broadcast.to(socket_ids).emit('some_event',some_data);
Here is the link for lodash documentation
I hope this helps.

Implement Server Side Events with Grails

I want to implement Server side events with grails. What i want is that only when there is a change in the DataBase my DataTable should refresh. I want to user HTML5 Server Side events for this. My first question is that while using SSE i observed that the client keeps making a request to the server and if data is available it pulls it. Its similar to an Ajax call being sent every 3-4 seconds which can be changed but what i really want is that only and only when the Data in the DataBase changes should there be a refresh in the DataTable. Also i want to send JSON data to the client but am unable to send it in the right format. Below is my controller code.
def test(){
def action
something.each(){
action = "<a href=\"javascript:fetchDetails('"+it.id+"','comments'"+")\" class='btn btn-primary'><span class='glyphicon glyphicon-upload'></span></a>"
dataArr << [
it.Number,
it.product,
it.description,
OrgChart.findByid(it.Owner)?.displayName,
OrgChart.findByid(it.Coordinator)?.displayName,
startDate,
endDate,
it.status.status,
action
]
}
println dataArr
response.setContentType("text/event-stream;charset=UTF-8")
response << "data: ${dataArr}\n\n"
render "Hi"
}
}
Below is the gsp or the client side code
console.log("Starting eventSource");
var eventSource = new EventSource("/ops/test");
console.log("Started eventSource");
eventSource.onmessage = function(event) {
var data = JSON.stringify(event.data)
console.log("Message received: " + JSON.parse(data));
changeRequestsTable.clear().rows.add(JSON.parse(event.data)).draw()
};
eventSource.onopen = function(event) { console.log("Open " + event); };
eventSource.onerror = function(event) { console.log("Error " + event); };
console.log("eventState: " + eventSource.readyState);
// Stop trying after 10 seconds of errors
setTimeout(function() {eventSource.close();}, 10000);
I know i am a long way from implementing what i intend to but any help would be really appreciated
Going to answer this since it is getting to be a long conversation. As it stands the solution is too broad to give a proper answer since the angle as to how you do things could vary in such a dramatic range from using events that get triggered upon record save that then go off to either make client socket connections through application through to direct socket client connection at point of save that triggers something to be sent to clients. These methods are probably all more complex and more entangled and in short can be done all in a much easier way.
As the users go their interface get the users to make a ws connection to a backend listener. It can be the same location as in no room/separation (additional complexity needed).
As they join room declare a static concurrent map in the top of your websocket listener that collections each session and userId. I wouldn't do it the chat way since this is injected through a service that keeps it as a collection instead like this and changing RunnableFuture to be Websocket sessions like seen in the service link example.
Once you have this you can simply call a broadcast something like this that gets hold of your static concurrent map and for each session either broadcasts the entire new list in json and user processes html update with it or sends a trigger to say update page and they go off doing ajax call to update list.
See the following guide for a tutorial on how to implement Server Sent Events with Grails 3:
http://guides.grails.org/server-sent-events/guide/index.html

Javascript: Schedule HTTP requests for later

I'm developing an app using Phonegap (AngularJS + HTML5) and I want some of the functionality to be available even when the user is offline.
What I was thinking of doing is when I need to do an HTTP request, check if the device is online. If it is, then make the request. Otherwise, store the request in an array of other requests, and when you go back online start processing all these requests one-by-one.
So, I have created a service called HttpRequestScheduler which looks something like the following:
.service('HttpRequestSchedule', ['$http', function ($http) {
var requests = [];
// schedule function tries to send the request
// if it doesn't succeed, it adds it to the requests queue
function schedule(httpRequest) {
$http(
httpRequest
).success(function () {
}).error(function () {
requests.push(httpRequest);
});
}
// this method is called every time the device goes back online
function processRequests() {
while (requests.length !== 0) {
var currentRequest = requests.splice(0, 1)[0];
$http(
currentRequest
).success(function () {
}).error(function () {
requests.push(currentRequest);
});
}
}
return {
schedule: schedule,
processRequests: processRequests
};
}])
I guess this is a requirement for many apps out there. So my question is, is this the proper/usual way of doing such a thing? Or is there a better way?
To check if your device is online or not you should use cordova-plugin-network-information. Also when you're using Angular inside a Cordova-like application, ngCordova will help you a lot !
To answer your question, this a classic problem and the best is to find your own logic mixing an $interval watching regularly the connection via network-information plugin when it's down. When the network connection goes back, you have to execute the list of tasks that you stored in your LocalStorage.

Strange issue with socket.on method

I am facing a strange issue with calling socket.on methods from the Javascript client. Consider below code:
for(var i=0;i<2;i++) {
var socket = io.connect('http://localhost:5000/');
socket.emit('getLoad');
socket.on('cpuUsage',function(data) {
document.write(data);
});
}
Here basically I am calling a cpuUsage event which is emitted by socket server, but for each iteration I am getting the same value. This is the output:
0.03549148310035006
0.03549148310035006
0.03549148310035006
0.03549148310035006
Edit: Server side code, basically I am using node-usage library to calculate CPU usage:
socket.on('getLoad', function (data) {
usage.lookup(pid, function(err, result) {
cpuUsage = result.cpu;
memUsage = result.memory;
console.log("Cpu Usage1: " + cpuUsage);
console.log("Cpu Usage2: " + memUsage);
/*socket.emit('cpuUsage',result.cpu);
socket.emit('memUsage',result.memory);*/
socket.emit('cpuUsage',cpuUsage);
socket.emit('memUsage',memUsage);
});
});
Where as in the server side, I am getting different values for each emit and socket.on. I am very much feeling strange why this is happening. I tried setting data = null after each socket.on call, but still it prints the same value. I don't know what phrase to search, so I posted. Can anyone please guide me?
Please note: I am basically Java developer and have a less experience in Javascript side.
You are making the assumption that when you use .emit(), a subsequent .on() will wait for a reply, but that's not how socket.io works.
Your code basically does this:
it emits two getLoad messages directly after each other (which is probably why the returning value is the same);
it installs two handlers for a returning cpuUsage message being sent by the server;
This also means that each time you run your loop, you're installing more and more handlers for the same message.
Now I'm not sure what exactly it is you want. If you want to periodically request the CPU load, use setInterval or setTimeout. If you want to send a message to the server and want to 'wait' for a response, you may want to use acknowledgement functions (not very well documented, but see this blog post).
But you should assume that for each type of message, you should only call socket.on('MESSAGETYPE', ) once during the runtime of your code.
EDIT: here's an example client-side setup for a periodic poll of the data:
var socket = io.connect(...);
socket.on('connect', function() {
// Handle the server response:
socket.on('cpuUsage', function(data) {
document.write(data);
});
// Start an interval to query the server for the load every 30 seconds:
setInterval(function() {
socket.emit('getLoad');
}, 30 * 1000); // milliseconds
});
Use this line instead:
var socket = io.connect('iptoserver', {'force new connection': true});
Replace iptoserver with the actual ip to the server of course, in this case localhost.
Edit.
That is, if you want to create multiple clients.
Else you have to place your initiation of the socket variable before the for loop.
I suspected the call returns average CPU usage at the time of startup, which seems to be the case here. Checking the node-usage documentation page (average-cpu-usage-vs-current-cpu-usage) I found:
By default CPU Percentage provided is an average from the starting
time of the process. It does not correctly reflect the current CPU
usage. (this is also a problem with linux ps utility)
But If you call usage.lookup() continuously for a given pid, you can
turn on keepHistory flag and you'll get the CPU usage since last time
you track the usage. This reflects the current CPU usage.
Also given the example how to use it.
var pid = process.pid;
var options = { keepHistory: true }
usage.lookup(pid, options, function(err, result) {
});

Categories

Resources