I'm making a module named rooms.js for my game in socket.io and canvas, and I've a function to sync with the client the users data as an object, but setInterval is not working on my function Rooms.Listener(), the client only get the data 4 times with setInterval at 1ms, but only one time with 10ms.
Code:
Listener: function() {
setInterval(function() {
// send data to client every 1ms
Rooms.ListUsers();
}, 1);
},
ListUsers: function() {
for(var roomID in Rooms.Obj) {
var room = Rooms.Obj[roomID];
// send users data to client
room.users.forEach(function(uid) {
var socketID = users.getSocketIDbyId(uid);
var data = Rooms.getUsersInRoomData(roomID);
fiveSocket.emitClient(socketID, headers.roomUsers, data);
});
}
},
getUsersInRoomData: function(roomID) {
var room = Rooms.Obj[roomID];
var obj = {};
room.users.forEach(function(uid) {
var user = users.Obj[uid];
obj[uid] = {
username: user.username,
position: user.position,
figure: user.figure
};
});
return obj;
},
Where's the problem? Thanks
Double check your methods separately. The code itself should work, problem may be inside your inner methods.
var Rooms = {
Listener: function() {
setInterval(function() {
Rooms.ListUsers();
}, 1000); // change to 1ms if necessary
},
ListUsers : function() {
document.body.innerHTML += Date.now() + "<br />";
}
};
Rooms.Listener();
Related
I have this code and I need my table to show the first 10 patients and, after 10 seconds, show the next 10 without touching any button (automatically).
I'm looking for something similar to this: https://embed.plnkr.co/ioh85m5OtPmcvPHyl3Bg/
But with an OData model (as specified on my view and controller).
This is my view:
<Table id="tablaPacientes" items="{/EspCoSet}">
<columns>
<!-- ... -->
</columns>
<ColumnListItem>
<ObjectIdentifier title="{Bett}" />
<!-- ... -->
</ColumnListItem>
</Table>
This is my controller:
onInit: function () {
var oModel = this.getOwnerComponent().getModel("zctv");
this.getView().setModel(oModel);
},
onBeforeRendering: function () { // method to get the local IP because I need it for the OData
var ipAddress;
var RTCPeerConnection = window.webkitRTCPeerConnection || window.mozRTCPeerConnection;
var self = this;
function grepSDP (sdp) {
var ip = /(192\.168\.(0|\d{0,3})\.(0|\d{0,3}))/i;
sdp.split('\r\n').forEach(function (line) {
if (line.match(ip)) {
ipAddress = line.match(ip)[0];
self.setIp(ipAddress);
}
});
}
if (RTCPeerConnection) {
(function () {
var rtc = new RTCPeerConnection({
iceServers: []
});
rtc.createDataChannel('', {
reliable: false
});
rtc.onicecandidate = function (evt) {
if (evt.candidate) {
grepSDP(evt.candidate.candidate);
}
};
rtc.createOffer(function (offerDesc) {
rtc.setLocalDescription(offerDesc);
}, function (e) {
console.log("Failed to get Ip address");
});
})();
}
},
setIp: function (ip) {
this.getView().byId("planta").bindElement({
path: "/CenTVSet('" + ip + "')"
});
var oModel = this.getView().getModel();
var that = this;
oModel.read("/CenTVSet('" + ip + "')", {
success: function (oData, oRes) {
var einri = oData.Einri;
var orgpf = oData.Orgpf;
var oTable = that.getView().byId("tablaPacientes");
var oBinding = oTable.getBinding("items");
var aFilters = [];
var filterO = new Filter("Orgna", sap.ui.model.FilterOperator.EQ, orgpf);
aFilters.push(filterO);
var filterE = new Filter("Einri", sap.ui.model.FilterOperator.EQ, einri);
aFilters.push(filterE);
oBinding.filter(aFilters);
}
});
}
I searched some functions like IntervalTrigger but I really don't know how can I use it for this example.
Here are some small samples:
OData V4: https://embed.plnkr.co/4zIAH7q2E0lngbyX
OData V2: https://embed.plnkr.co/rNa0TktXiQqSCGJV
startList: function(listBase, $skip, $top, restInfo) {
let startIndex = $skip;
let length = $top;
let totalSize;
(function repeat(that) {
const bindingInfo = Object.assign({ startIndex, length }, restInfo);
listBase.bindItems(bindingInfo);
listBase.data("repeater", event => {
totalSize = event.getParameter("total"); // $count value
startIndex += $top;
startIndex = startIndex < totalSize ? startIndex : 0;
setTimeout(() => repeat(that), 2000);
}).attachEventOnce("updateFinished", listBase.data("repeater"), that);
})(this);
},
stopList: function(listBase) {
listBase.detachEvent("updateFinished", listBase.data("repeater"), this);
},
The samples make use of startIndex and length in the list binding info which translates to $skip and $top system queries of the entity request URL. I.e. appending those system queries to the request URL (e.g. https://<host>/<service>/<EntitySet>?$skip=3&$top=3), should return the correct set of entities like this.
Additional options for the list binding info can be found in the UI5 documentation as I explained here.
JavaScript part
The interval is implemented with an IIFE (Immediately Invoked Function Expression) in combination with setTimeout instead of setInterval.
setInterval has the following disadvantages:
The callback is not immediately invoked. You'd have to wait 10 seconds first to trigger the 1st callback.
Does not wait for the data response to arrive. This may cause skipping a batch or showing it for a too short period of time because the delay simply continues regardless of the server response.
setTimeout instead offers a better control when the next batch should be requested.
You could bind you items using bindItems, pass skip,top parameters and wrap the whole thing in a setInterval
var iSkip = 0;
var iTop = 10;
setInterval(function() {
table.bindItems("/EspCoSet", {
urlParameters: {
"$skip": iSkip.toString() // Get first 10 entries
"$top": iTop.toString()
},
success: fuction (oData) {
iSkip = iTop; // Update iSkip and iTop to get the next set
iTop+= 10;
}
...
}, 10000); // Each 10 seconds
)
Almost the same thing, just use oModel.read to read the entities into you viewModel.allEntities, bind your table to the viewModel.shownEntities and use a setInterval to get the next 10 from allEntities to update shownEntities.
I have a server sent event in PHP that displays inventory information client side and updates in real time. That part works great. The challenge is that I want to trigger a reload when the inventory = 0. Note: I'm using jQuery Mobile 1.4.5
Here's my code:
var source = new EventSource('listener.php');
source.onmessage = function(msg) {
document.getElementById('inv').innerHTML = msg.data;
};
source.addEventListener('msg', onMessageHandler,false);
function onMessageHandler(msg) {
var inventory = msg.data;
};
// Trying to Fire Something like this //
//if (inventory = 0) {
//setTimeout(function() {
//location.reload(true)
//},5000);
Thanks for any suggestions : )
Watch the scoping:
var source = new EventSource('listener.php');
source.onmessage = function(msg) {
document.getElementById('inv').innerHTML = msg.data;
};
source.addEventListener('msg', onMessageHandler,false);
function onMessageHandler(msg) {
var inventory = msg.data;
if (inventory === 0) {
setTimeout(function() {
location.reload(true);
}, 5000);
}
};
Thank you for the suggestions. Both helped tremendously. This is what worked for me in the event any others ever have a similar challenge:
var source = new EventSource('listener.php');
source.onmessage = function(msg) {
document.getElementById('inv').innerHTML = msg.data;
console.log(msg.data);
var x = msg.data;
if (x == 0) {
setTimeout(function() {
window.location.reload(true);
// Or any of the 1000's of other ways to reload
}, 1000);
}
};
source.addEventListener('msg', onMessageHandler,false);
function onMessageHandler(msg) {
var inventory = msg.data;
};
In my node.js app, reading data from MSSQL using tedious, I'm calling the below every 1 second:
Fetch the data from the server (fetchStock function) and save it in temporary array
Send the data saved in the temporary array to the client using the Server-Sent Events (SSE) API.
It looks the 1 second is not enough to recall the fetchStock function before the previous call is completely executed, so I get execution errors from time to time.
I increased it to 5 seconds, but still get the same issue every once in a while.
How can I use Promise().then to be sure the fetchStock function is not re-called before the previouse call be completely executed?
var Request = require('tedious').Request;
var Connection = require('tedious').Connection;
var config = {
userName: 'sa',
password: 'pswd',
server: 'xx.xxx.xx.xxx',
options: {
database: 'DB',
rowCollectionOnRequestCompletion: 'true',
rowCollectionOnDone: 'true'
},
};
var sql = new Connection(config);
var addElem = (obj, elem)=> [].push.call(obj, elem);
var result = {}, tmpCol = {}, tmpRow = {};
module.exports = {
displayStock: function (es) {
var dloop = setInterval(function() {
if(result.error !== null)
if (es) es.send(JSON.stringify(result), {event: 'rmSoH', id: (new Date()).toLocaleTimeString()});
if(result.error === null)
if (es) es.send('connection is closed');
}, 1000);
},
fetchStock: function () {
request = new Request("SELECT ItemCode, WhsCode, OnHand FROM OITW where OnHand > 0 and (WhsCode ='RM' or WhsCode ='FG');", function(err, rowCount, rows) {
if (err) {
result = {'error': err};
console.log((new Date()).toLocaleTimeString()+' err : '+err);
}
if(rows)
rows.forEach(function(row){
row.forEach(function(column){
var colName = column.metadata.colName;
var value = column.value;
addElem(tmpCol, {colName: value})
});
addElem(tmpRow,{'item': tmpCol[0].colName, 'Whs': tmpCol[1].colName, 'Qty': tmpCol[2].colName});
tmpCol = {};
});
result = tmpRow;
tmpRow={}
});
sql.execSql(request);
}
}
I think what you need is a simple variable to check if there's already running request not Promise.
var latch = false;
// It will be called only if the previous call is completed
var doFetchStock = () => sql.execSql(new Request("SQL", (err, rowCount, rows) => {
// Your logic dealing with result
// Initializes the latch
latch = false;
});
module.exports = {
fetchStock: function () {
// Check if the previous request is completed or not
if (!latch) {
// Sets the latch
latch = true;
// Fetches stock
doFetchStock();
}
}
};
Actually I've used this kind of pattern a lot to allow some behavior only once.
https://github.com/cettia/cettia-javascript-client/blob/1.0.0-Beta1/cettia.js#L397-L413
https://github.com/cettia/cettia-javascript-client/blob/1.0.0-Beta1/cettia.js#L775-L797
Since javascript is mono-threaded a simple code like this should be enough on client-side
function () {
if(currentPromise != null){ // define in a closure outside
currentPromise = [..] // call to server which return a promise
currentPromise.then(function(){
currentPromise = null;
});
}
}
I have been adapting the IBM angularjs tutorial here into a Yeoman angular-fullstack tutorial and it has been relatively easy except I have one Issue. When I vote on a Poll the data does not refresh and show the results on my version.
I have tried Debugging through it as best I can and I cannot see any difference between my version and the IBM version that would cause this issue. I have also looked here on SO and on google but I'm actually completely lost.
my entire code base is located here on github and I have embeded what I think is the relevant code below, Any help would be greatly appreciated
This is the client side controller
.controller('PollViewCtrl', function ($scope, $routeParams, Poll, socket){
$scope.poll = Poll.get({pollId: $routeParams.id});
socket.on('myvote', function(data) {
console.dir(data);
if(data._id === $routeParams.pollId) {
$scope.poll = data;
}
});
socket.on('vote', function(data) {
console.dir(data);
if(data._id === $routeParams.pollId) {
$scope.poll.choices = data.choices;
$scope.poll.totalVotes = data.totalVotes;
}
});
$scope.vote = function() {
var pollId = $scope.poll._id,
choiceId = $scope.poll.userVote;
if(choiceId) {
var voteObj = { poll_id: pollId, choice: choiceId };
socket.emit('send:vote', voteObj);
} else {
alert('You must select an option to vote for');
}
};
})
and this is the relavent server side code
//app.js
var io = require('socket.io').listen(app.listen(config.port));
var poll = require('./lib/controllers/polls');
io.sockets.on('connection', poll.vote);
//poll.js
exports.vote = function(socket) {
socket.on('send:vote', function(data) {
var ip = socket.handshake.headers['x-forwarded-for'] || socket.handshake.address.address;
Poll.findById(data.poll_id, function(err, poll) {
var choice = poll.choices.id(data.choice);
choice.votes.push({ ip: ip });
poll.save(function(err, doc) {
var theDoc = {
question: doc.question, _id: doc._id, choices: doc.choices,
userVoted: false, totalVotes: 0
};
for(var i = 0, ln = doc.choices.length; i < ln; i++) {
var choice = doc.choices[i];
for(var j = 0, jLn = choice.votes.length; j < jLn; j++) {
var vote = choice.votes[j];
theDoc.totalVotes++;
theDoc.ip = ip;
if(vote.ip === ip) {
theDoc.userVoted = true;
theDoc.userChoice = { _id: choice._id, text: choice.text };
}
}
}
socket.emit('myvote', theDoc);
socket.broadcast.emit('vote', theDoc);
});
});
});
};
Update
Here is the factory for socket
.factory('socket', function($rootScope) {
var socket = io.connect();
return {
on: function (eventName, callback) {
socket.on(eventName, function () {
var args = arguments;
$rootScope.$apply(function () {
callback.apply(socket, args);
});
});
},
emit: function (eventName, data, callback) {
socket.emit(eventName, data, function () {
var args = arguments;
$rootScope.$apply(function () {
if (callback) {
callback.apply(socket, args);
}
});
})
}
};
});;
You have to make an apply when you're receiving the sockent on AngularJS because socket.io is not "in the AngularJS world".
You have a rerally great tutorial here to do what you want :
http://www.html5rocks.com/en/tutorials/frameworks/angular-websockets/?redirect_from_locale=fr
If you have any questions just ask it !
Hope it helps
This was simply a mix up of variable name, while IBM was using pollId in their route for getting a poll I was using id but had managed to use pollId in my controller, once I changed this all behaved as expected.
I have view page where am trying to display all organizations,which is
obtained by a server call..In order to feel the application responsive
, in between the server response I want to load all local store
items.. But server call is always executing first.. The code I
mentioned bellow..
initialize: function()
{
var me = this,
st = Ext.create("Ext.data.Store", {
fields : [ {......................}]});
me.callParent(arguments);
me.setStore(st);
me.on({
show : me.onShow,
scope: me
});
},
onShow:function()
{
var me = this;
Ext.create('Ext.util.DelayedTask',
//call back function ,purpose : delayed exicution
function () {
me.DelShow(function(){
_syncMgr.getOrgGroup(-1,0,5); // servercall
});
}).delay(500);
},
DelShow: function(callback)
{
orgStore = Ext.getStore('Organizations'),
orgStore.load(function(records)
{
var i=0,len = records.length,
for(;i<len;i++)
{
organization = records[i];
regId = organization.get('rg_id');
resStr = organization.Resources();
resStr.load({callback:function(resorces)
{
var i = 0,rlen =resorces.length,
obj = {},
obj.rg_id = str.boundTo.get('rg_id');
}
orgViStr.add([obj]);
});
}
});
me.lodorg(callback);
},
lodorg:function(callback)
{
callback();
console.log("I don't know why this call back works first....");
console.log("plz help me to work last....");
}
Call You callback method after You load data from local store .
What you want to do is add the content from your local store to the list that is currently set in the view then refresh the list.
var localStore = something.getStore(),
entries = [];
localStore.each(function(entry){
entries.push(entry.copy);
});
//me is the list that is set in the view
me.add(entries);
me.deselectAll();
me.refresh();
Hope that helps :)