I have a web socket service that I need it to fetch multiple requests.
I init the web socket with a url and need to send about 200 json requests.
So my question is,
What is the best way to do it?
Do I need open a web socket separatelly for each request?
CODE:
var ws = new WebSocket("wss://api.example.com/api/");
ws.onopen = function() {
ws.send(
JSON.stringify({
"method": "getItem",
"params": {
"color": "WHITE"
}
})
);
};
ws.onmessage = function(evt) {
var received_msg = evt.data;
console.log(received_msg);
};
So in this example I need more 200 times this JSON request:
JSON.stringify({
"method": "getItem",
"params": {
"color": "WHITE"
}
})
I would consider adding a message queue (this could be a simple Array) and sending the messages in the queue whenever you can.
i.e.:
ws.queue = []
ws.onmessage = function(evt) {
var received_msg = evt.data;
console.log(received_msg);
while(evt.target.queue.length) {
evt.target.send(evt.target.queue.pop());
}
};
ws.onopen = function(evt) {
while(evt.target.queue.length) {
evt.target.send(evt.target.queue.pop());
}
}
ws.queue.push( JSON.stringify({
"method": "getItem",
"params": {
"color": "WHITE"
}
}) );
This is quick and dirty example, but I'm sure a similar approach could work.
Related
I'm struggling with trying to figure out what I'm doing wrong, mostly down to not having a good understanding of AngularJS due to being new. The main goal is that I'm trying to list out all the values in the additionalText list out on the front-end, but it seems to be causing issue with this error:
Error: [$http:badreq] Http request configuration url must be a string or a $sce trusted object. Received: []
Context:
I have table in my application that relies on the API, this variable contains a list and outputs the following:
{
"name": "TEST",
"description": "TEST",
"additionalText": [
{
"name": "TEST",
"description": "TEST",
"lockId": 0
}
{
"name": "TEST",
"description": "TEST",
"lockId": 0
}
],
"lockId": 0
}
The API is working as expected, I can carry out all the necessary REST calls successfully. So I'm not struggling with that, the front-end is where I am having some difficulty.
HTML:
<td data-title="'additionalTexts'" sortable="'additionalTexts'">
<span ng-repeat="additionalText in additionalTextList[entity.name]">
<i>{{additionalText.name}}</i><br>
</span>
</td>
AngularJS:
$scope.refreshTextTable= function() {
SpringDataRestService.query(
{
collection: "APIURL"
},
function (response) {
var additionalTextRoles = response;
$scope.textTableOptions = new NgTableParams({}, {
dataset: additionalTextRoles,
counts: [],
});
// Also populate a list of all linked roles
for (var i = 0; i < additionalTextRoles.length; i++) {
var additionalTextRole = additionalTextRoles[i];
// This approach allows you to inject data into the callback
$http.get(additionalTextRole.additionalText).then((function (additionalTextRole) {
return function(response) {
$scope.additionalTextList[additionalTextRole.name] = response.additionalText;
};
})(additionalTextRole));
}
},
function (response) {
// TODO: Error Handling
}
);
};
Any help would be greatly appreciated, I'm really struggling with this one.
Can you try this below code:
$scope.refreshTextTable = function() {
SpringDataRestService.query({
collection: "APIURL"
},
function(response) {
var additionalTextRoles = response;
$scope.textTableOptions = new NgTableParams({}, {
dataset: additionalTextRoles,
counts: [],
});
// Also populate a list of all linked roles
for (var i = 0; i < additionalTextRoles.length; i++) {
var additionalTextRole = additionalTextRoles[i];
// This approach allows you to inject data into the callback
$http.get(additionalTextRole.additionalText).then((function(additionalTextRole) {
return function(response) {
$scope.additionalTextList = response.additionalText;
};
})(additionalTextRole));
}
},
function(response) {
// TODO: Error Handling
}
);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.3/angular.min.js"></script>
<td data-title="'additionalTexts'" sortable="'additionalTexts'">
<span ng-repeat="additionalText in additionalTextList">
<i>{{additionalText.name}}</i><br>
</span>
</td>
The error message says the url must be a string.
For debugging purposes, console.log the URL:
for (var i = 0; i < additionalTextRoles.length; i++) {
var additionalTextRole = additionalTextRoles[i];
// This approach allows you to inject data into the callback
var url = additionalTextRole.additionalText;
console.log(i, url);
$http.get(url).then((function (additionalTextRole) {
return function(response) {
$scope.additionalTextList[additionalTextRole.name] = response.additionalText;
};
})(additionalTextRole));
}
Also note that the response object returned by the $http service does not have a property named additionalText. So it is likely that the intention is response.data.additionalText. To avoid the IIFE, use the forEach method:
additionalTextRoles.forEach( role => {
var url = role.additionalText;
console.log(url);
$http.get(url).then((function(response) {
$scope.additionalTextList[role.name] = response.data.additionalText;
});
});
I'm trying to implement a very simple video chat based on the WebRTC API.
Unfortunately my Code is just working from Chrome-to-Chrome and from Firefox-to-Firefox so far.
If I try it from Chrome-to-Firefox or from Firefox-to-Chrome I get the following error output:
Failed to set local offer sdp: Session error code: ERROR_CONTENT. Session error description: Failed to set local video description recv parameters..(anonymous function) # helloWebRtc.js:126***
Did I possibly missed something or do I need some flags in the Chrome or Firefox browser?
Do you have any idea? I would be grateful for any help I can get to solve this issue.
Thank you all in advance!
My helloWebRtc.js looks like this:
var localVideo = document.querySelector("#localVideo");
var remoteVideo = document.querySelector("#remoteVideo");
var SIGNAL_ROOM = "signal_room";
var CHAT_ROOM = "chat_room";
var serverConfig = {
"iceServers": [
{
"urls": "stun:stun.l.google.com:19302"
}
]
};
var optionalConfig = {
optional: [
{
RtpDataChannels: true
},
{
DtlsSrtpKeyAgreement: true
}
]
};
var rtcPeerConn,
localStream;
io = io.connect();
io.emit("ready", {"chat_room": CHAT_ROOM, "signal_room": SIGNAL_ROOM});
io.emit("signal", {
"room": SIGNAL_ROOM,
"type": "user_here",
"message": "new user joined the room"
});
io.on("rtcSignaling", function(data) {
if(!rtcPeerConn) {
startSignaling();
}
if(data.type !== "user_here" && data.message) {
var message = JSON.parse(data.message);
if(message.description) {
var remoteDesc = new RTCSessionDescription(message.description);
rtcPeerConn.setRemoteDescription(remoteDesc, function() {
// if we receive an offer we need to answer
if(rtcPeerConn.remoteDescription.type === "offer") {
rtcPeerConn.createAnswer(sendLocalDescription, function(error) {
console.error("error on creating answer", error);
});
}
}, function(error) {
console.error("error on set remote description", error);
});
} else if(message.candidate) {
var iceCandidate = new RTCIceCandidate(message.candidate);
rtcPeerConn.addIceCandidate(iceCandidate);
}
}
});
function startSignaling() {
rtcPeerConn = new RTCPeerConnection(serverConfig, optionalConfig);
//send any ice candidate to the other peer
rtcPeerConn.onicecandidate = function(event) {
if(event.candidate) {
io.emit("signal", {
"room": SIGNAL_ROOM,
"type": "candidate",
"message": JSON.stringify({
"candidate": event.candidate
})
});
}
};
rtcPeerConn.onnegotiationneeded = function() {
rtcPeerConn.createOffer(sendLocalDescription, function(error) {
console.error("error on creating offer", error);
});
};
// add the other peer's stream
rtcPeerConn.onaddstream = function(event) {
console.info("on add stream called");
remoteVideo.srcObject = event.stream;
};
// add local stream
navigator.mediaDevices.getUserMedia({
audio: true,
video: true
})
.then(function(stream) {
localVideo.srcObject = stream;
localStream = stream;
rtcPeerConn.addStream(localStream);
})
.catch(function(e) {
alert('getUserMedia() error: ' + e.name);
});
}
function sendLocalDescription(description) {
rtcPeerConn.setLocalDescription(
description,
function() {
io.emit("signal", {
"room": SIGNAL_ROOM,
"type": "description",
"message": JSON.stringify({
"description": rtcPeerConn.localDescription
})
});
},
function(error) {
console.error("error to set local desc", error);
}
);
}
My NodeJS server (using express.io) looks like the following:
var express = require('express.io');
var app = express();
var PORT = 8686;
app.http().io();
console.log('server started # localhost:8686');
// declaring folders to access i.e.g html files
app.use(express.static(__dirname + '/views'));
app.use('/scripts', express.static(__dirname + '/scripts'));
// root url i.e. "localhost:8686/"
app.get('/', function(req, res) {
res.sendFile('index.html');
});
/**
* Socket.IO Routes for signaling pruposes
*/
app.io.route('ready', function(req) {
req.io.join(req.data.chat_room);
req.io.join(req.data.signal_room);
app.io.room(req.data.chat_room).broadcast('announce', {
message: 'New client in the ' + req.data.chat_room + ' room.'
});
});
app.io.route('send', function(req) {
app.io.room(req.data.room).broadcast('message', {
message: req.data.message,
author: req.data.author
});
});
app.io.route('signal', function(req) {
// Note: req means just broadcasting without letting the sender also receive their own message
if(req.data.type === "description" || req.data.type === "candidate")
req.io.room(req.data.room).broadcast('rtcSignaling', {
type: req.data.type,
message: req.data.message
});
else
req.io.room(req.data.room).broadcast('rtcSignaling', {
type: req.data.type
});
});
app.listen(PORT);
You can compare the offer SDP generated by the chrome and firefox, there might be some difference which is not interoperable to other.
Edit to the old answer below: there are several bugs in interoperability between Chrome and Firefox. Someone from the webrtc team gave me the suggestion to keep the offerer to the same party. So if A creates an offer when setting up a stream to B, then B asks A to create a new offer, instead of creating one self, when setting up a stream to A.
See also here:
https://bugs.chromium.org/p/webrtc/issues/detail?id=5499#c15
I did note that if Firefox initiates a session, Chrome will kick the stream coming from Firefox out of the video element but you can create a new object URL on the stream and set it as the source.
Hope that helps.
Old message:
I am experiencing the same thing, so if you have an answer, I'm curious.
I do believe that there is a mismatch (bug) between FireFox and Chrome in setting up DTLS roles, see also:
https://bugs.chromium.org/p/webrtc/issues/detail?id=2782#c26
just check if you are setting DtlsSrtpKeyAgreement parameter to true while you create the peerconnection.
pc = new RTCPeerConnection(pc_config,{optional: [{RtpDataChannels: true},{
DtlsSrtpKeyAgreement: true}]});
We are using the Google Places API to add places and those should reflect in the Map loaded with the API key from the same console project. However, the added places do not reflect on the map, even after a long period of time.
https://developers.google.com/places/webservice/add-place
if somebody has used these APIs, please suggest some insight as to why this is happening. I had enabled the APis from the console project.
Thanks
Code is as follows:
function addPlaceToGoogle(data, callback) {
var request = require('request');
var requestUrl = 'https://maps.googleapis.com/maps/api/place/add/json?key=' + config.get("google_key");
var type = "store";
if (data.type) {
type = data.type;
}
var newData =
{
"location": {
"lat": data.latitude,
"lng": data.longitude
},
"accuracy": 50,
"name": data.address,
"address": data.address,
"types": [type]
};
var request = require('request');
var options = {
uri: requestUrl,
method: 'POST',
json: newData
};
request(options, function(error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body) // Print the shortened url.
if (body.status == 'OK') {
data.placeId = body.place_id;
} else {
data.placeId = "";
}
data.type = type;
callback(null, data);
}
});
}
need to know if i can call a specific part of the following script
chrome.identity.getAuthToken({
interactive: true
}, function(token) {
if (chrome.runtime.lastError) {
alert(chrome.runtime.lastError.message);
return;
}
var x = new XMLHttpRequest();
x.open('GET', 'https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token=' + token);
x.onload = function() {
alert(x.response);
};
x.send();
});
I currently use document.write(x.response) which writes out the users information but would like to call only the id
{ "id": "XXX",
"email": "XXX",
"verified_email": true,
"name": "XXX", }
what I would like to do is turn the id into a variable.
var user_id = x.response['id']... Or something like that.
the original code can be found
chrome.identity User Authentication in a Chrome Extension
Try :
var user_id = JSON.parse(x.response).id;
I am a complete n00b to Backbone.js, and have only been working with it for a few days. I am attempting to fetch JSON data to populate the model, and in this scenario I have two models that I need to generate. Here is the sample JSON I have been working with:
JSON
{
"status": "200",
"total": "2",
"items":
[{
"id": "1",
"name": "Here is another name",
"label": "Label for test",
"description": "A description for more information.",
"dataAdded": "123456789",
"lastModified": "987654321"
},
{
"id": "2",
"name": "Name of item",
"label": "Test Label",
"description": "This is just a long description.",
"dataAdded": "147258369",
"lastModified": "963852741"
}]
}
Backbone JS
// MODEL
var Service = Backbone.Model.extend({
defaults: {
id: '',
name: '',
label: '',
description: '',
dateAdded: '',
dateModified: ''
}
});
var service = new Service();
// COLLECTION
var ServiceList = Backbone.Collection.extend({
model: Service,
url: "./api/service.php",
parse: function(response) {
return response.items;
}
});
//
var serviceList = new ServiceList();
var jqXHR = serviceList.fetch({
success: function() {
console.log("Working!");
console.log(serviceList.length);
},
error: function() {
console.log("Failed to fetch!");
}
});
// VIEW for each Model
var ServiceView = Backbone.View.extend({
el: $('.widget-content'),
tagName: 'div',
template: _.template($('#service-template').html()),
initialize: function() {
this.collection.bind("reset", this.render, this);
},
render: function() {
console.log(this.collection);
this.$el.html('');
var self = this;
this.collection.each(function(model) {
self.$el.append(self.template(model.toJSON()));
});
return this;
}
});
//
var serviceView = new ServiceView({
collection: serviceList
});
console.log(serviceView.render().el);
html
<div class="widget-content">
<!-- Template -->
<script type="text/template" id="service-template">
<div><%= name %></div>
</script>
</div>
When I console log the serviceList.length I get the value 2, so I believe the JSON object is fetched successfully. I also get the "Working!" response for success too. However, in the view I am showing an empty object, which gives me an empty model.
I am still trying to understand the best way to do this too. Maybe I should be using collections for the "items" and then mapping over the collection for each model data? What am I doing wrong? Any advice or help is greatly appreciated.
I can see two problems. First, you want to remove serviceList.reset(list). Your collection should be populated automatically by the call to fetch. (In any case the return value of fetch is not the data result from the server, it is the "jqXHR" object).
var serviceList = new ServiceList();
var jqXHR = serviceList.fetch({
success: function(collection, response) {
console.log("Working!");
// this is the asynchronous callback, where "serviceList" should have data
console.log(serviceList.length);
console.log("Collection populated: " + JSON.stringify(collection.toJSON()));
},
error: function() {
console.log("Failed to fetch!");
}
});
// here, "serviceList" will not be populated yet
Second, you probably want to pass the serviceList instance into the view as its "collection". As it is, you're passing an empty model instance into the view.
var serviceView = new ServiceView({
collection: serviceList
});
And for the view, render using the collection:
var ServiceView = Backbone.View.extend({
// ...
initialize: function() {
// render when the collection is reset
this.collection.bind("reset", this.render, this);
},
render: function() {
console.log("Collection rendering: " + JSON.stringify(this.collection.toJSON()));
// start by clearing the view
this.$el.html('');
// loop through the collection and render each model
var self = this;
this.collection.each(function(model) {
self.$el.append(self.template(model.toJSON()));
});
return this;
}
});
Here's a Fiddle demo.
The call serviceList.fetch is made asynchronously, so when you try console.log(serviceList.length); the server has not yet send it's response that's why you get the the value 1, try this :
var list = serviceList.fetch({
success: function() {
console.log(serviceList.length);
console.log("Working!");
},
error: function() {
console.log("Failed to fetch!");
}
});