socket connection always failing - angularjs

I'm writing an application that connects to a sails server.
This application is written with cordova, angularJS and Ionic.
When I launch my application in my browser (with ionic serve) the socket fails to connect to the server. Here is the message I get:
GET http://localhost:8100/socket.io/?__sails_io_sdk_version=0.11.0&__sails_io_s…sails_io_sdk_language=javascript&EIO=3&transport=polling&t=1443472067762-4 404 (Not Found)
The server is running locally on port 1337. I tried to change the above URL to:
http://localhost:1337/socket.io/?__sails_io_sdk_version=0.11.0&__sails_io_s…sails_io_sdk_language=javascript&EIO=3&transport=polling&t=1443472067762-4
and it's working.
In my code I set the URL after sails.io.js has been included:
io.sails.url = 'http://localhost:1337';
io.sails.useCORSRouteToGetCookie = false;
Why is it asking to localhost:8100 and not localhost:1337?
When I launch this application in my mobile device (setting the url to http://192.168.1.10:1337) it's working correctly.
Version of sails.io.js is 0.11.6, and version of sails is 0.11.0

localhost:8100 wont work in your mobile development environment. I faced same issue and changing localhost to your workstation's ip solved the problem

I finally found the solution (but I'm sorry I can't recall where I found it :()
The problem was that the io.sails.url = 'http://localhost:1337'; was executed after the first JS cycle, and thus the sails socket was already loaded. (that's (from what I understood) because in some browsers if the code is in another script tag it is executed in another cycle)
To make it work I had to add this code before I include the sails socket script:
var apiHost = 'localhost';
(function (){
var io;
Object.defineProperty(window, 'io', {
get: function (){
return io;
},
set: function (value){
var sails;
io = value;
Object.defineProperty(io, 'sails', {
get: function (){
return sails;
},
set: function (value){
sails = value;
sails.url = 'http://'+apiHost+':1337';
sails.useCORSRouteToGetCookie = false;
}
});
}
});
})();

Related

Log client side error At Server Side Using Angular JS

i'm newbie in angular js, have created a project in angular js and want to maintain log on server for all the issues occuring at the client side.
Gone through various blogs and found few suggestions for applying stack js but couldn't understand the implementation for same.
Please suggest if it is possible to log all the errors in project from one single point of client side, at the server through factory or service method using angular js.
This is possibly by overriding angulars built in $exceptionHandler. Below is the snippet of code from my own app that logs any failures to the backend, but also prints them into the console, in case the backend logging fails. As my javascript is minified, I use StackTrace to turn this back into an un-minified stack trace, and send that to my backend.
function exceptionLoggingService($injector) {
function error(exception, cause) {
// preserve the default behaviour which will log the error
// to the console, and allow the application to continue running.
var $log = $injector.get('$log');
var $window = $injector.get('$window');
$log.error.apply($log, arguments);
var errorMessage = exception.toString();
StackTrace.fromError(exception).then(function (arrayStack) {
var exceptionData = angular.toJson({
errorUrl: $window.location.href,
errorMessage: errorMessage,
stackTrace: arrayStack,
cause: ( cause || "" )
});
// now post this exceptionData to your backend
}).catch(function (backendLoggingError) {
$log.warn("Error logging failure.");
$log.log(backendLoggingError);
});
}
return(error);
}
angular.module('dashboard-ui').factory('$exceptionHandler', ['$injector', exceptionLoggingService])

Off-line Chrome Packaged App: how to manage Prod and Dev modes

To switch between dev/stage/prod on the server, I set an ENV variable. This is pretty standard.
With an Off-line Chrome App, how do I switch between dev/stage/prod? Especially around REST API URL's?
During development my app is installed in chrome as an "unpacked" app.
SOLUTION:
I combined these answers. Here's what I did:
On install, if unpacked extension, I set a value in localStorage.
On app run, I set a variable to the localstorage value, or to production if undefined.
FWIW, here's the code:
background.js:
chrome.runtime.onInstalled.addListener(function () {
console.log('onInstalled');
// Note: this event is fired every time the "Reload" link is clicked in
// 'Chrome Apps & Extensions Developer Tool'. So only set if not set.
// If unpacked extension,
if(!chrome.runtime.getManifest().update_url) {
// Load existing value
chrome.storage.local.get('APIBaseURL', function(data) {
// Has value already been set?
if (!data.hasOwnProperty('APIBaseURL')) {
// set API server to localhost
chrome.storage.local.set({'APIBaseURL': DEV_APIBASEURL }, function() {
// Ok, notify the console.
console.log('Installed in dev mode: APIBaseURL = '+DEV_APIBASEURL);
} );
}
});
}
});
App.js (this is Angular, but you should see the pattern. Promises are ES6)
var PROD_APIBASEURL = 'https://production.com';
angular.module('wmw', ['wmw.routes'])
// Listen for online/offline events and set status in $rootScope
.run(['$rootScope', function($rootScope){
// Determine which server to run on
$rootScope.isDev = chrome.runtime.getManifest().hasOwnProperty('update_url');
// Async init code is in a Promise
$rootScope.promiseAppReady = new Promise(function(resolve, reject) {
// Get the Base URL
chrome.storage.local.get('APIBaseURL', function(data) {
// Apply it to our scope. If not set, use PROD.
$rootScope.$apply(function() {
if (data.hasOwnProperty('APIBaseURL')) {
$rootScope.APIBaseURL = data.APIBaseURL;
} else {
$rootScope.APIBaseURL = PROD_APIBASEURL;
}
resolve($rootScope.APIBaseURL);
});
});
});
}]);
$rootScope.promiseAppReady let's me know when the code is done and the app is ready.
$rootScope.$apply() bubbles changes up to other scopes. If you're not using Angular, you can remove this.
I also included this code with some debug tools:
var debugTools = {
setAPIBaseURL: function (url) {
chrome.storage.local.set({'APIBaseURL': url});
},
showAPIBaseURL: function() {
chrome.storage.local.get('APIBaseURL', function(data) {console.log(data)});
}
}
so it was easy to change in the console.
In the console chrome.runtime.getManifest().update_url will have a value if installed from the store. Undefined if not.
See How to distinguish between dev and production in a Firefox extension I'm building?
And Check if Chrome extension installed in unpacked mode
From your description, I don't think you want the Chrome App to only talk to the remote server when it's installed from the Chrome Web Store and only talk to the local server when it's installed unpacked. I would think that you'd want the option of talking to either server no matter how it's installed.
So, I'd program the app to choose its server based on a key in Local Storage. You can then easily set that key from the Developer Tools panel (the Resources) tab. If the key is undefined, it uses the remote server.

SignalR: How to add client call after the hub is started?

First off, I just started trying to add SignalR 2 to my existing Angular SPA project.
I have a main controller which starts the hub right away that is feeding some messages to the client. Inside, I have several sub pages and each could subscribe to a different hub for services. The problems is that the client doesn't receive message because it is hooked up after the hub is already started in the main controller.
As a test, if I comment out the hub start in the main controller, the one in the sub controller works fine.
From what I read, it is by design that you have to hook up all client calls before starting the hub. I don't understand...if it is a service, I should be able to subscribe or unsubscribe anytime after the hub is started. Why not? How to workaround?
Because no response in the 12 hours (which is quite unusual in so), I had to dig around myself. I think, I was misled by the answers from SO on related questions that you have to subscribe all client call before starting the connection, as mentioned e.g. here. I found in Hubs API Guide, one section says
Define method on client (without the generated proxy, or when adding
after calling the start method)
So, it is possible to add client method after connection is started. The trick is to use so-called "without the generated proxy". That limitation is for "with generated proxy".
The following is my working example taken from SignalR get started tutorial.
This is the main controller using "with generated proxy":
$.connection.statusHub.client.updateStatus = function (status) {
$scope.status = status;
$scope.$apply();
}
$.connection.hub.start();
This is in a subcontroller using "without generated proxy":
var connection = $.hubConnection();
var proxy = connection.createHubProxy('stockTickerHub');
proxy.on('updateStockPrice', function (stock) {
var st = $scope.stocks.firstOfKey(stock.symbol, 'symbol');
st.lastPrice = stock.lastPrice;
$scope.$apply();
});
var hub = $.connection.stockTickerHub;
connection.start().done(function () {
hub.server.getAllStocks().done(function (stocks) {
$scope.stocks = stocks;
});
});
Note that it doesn't work if I use "with generated proxy" in the subcontroller like this:
var hub = $.connection.stockTickerHub;
hub.client.updateStockPrice = function (stock) {
var st = $scope.stocks.firstOfKey(stock.symbol, 'symbol');
st.lastPrice = stock.lastPrice;
$scope.$apply();
};
$.connection.hub.start().done(function () {
hub.server.getAllStocks().done(function (stocks) {
$scope.stocks = stocks;
});
});
To prove the limitation of "with generated proxy" mode, this code works if I comment out the one in the main controller.
By the way, I was so confused by the term with or without generated proxy in the Guide, and in both cases, it is still called xxxProxy. Can't they find a better name? Or somebody has an explanation?

Mean.io framework with socket.io

How to use socket.io in Mean.io stack?
First of all, Mean.io changes their folder structure very regularly.. So my question is where is the best place to configure socket.io ? or is it better to use express.io ?
Second I am still not quite sure where to look for to find code that tells mean.io to listen for port, I have found a port is defined in config folder in all.js file, but real problem is as soon as I define server.listen(port) app doesn't load. and if I don't app loads but socket.io doesn't work.
Also I have another question about /socket.io/socket-io.js file? I have copied that in index folder, but my app can't find it or says 404 error. I know it's not an actual file sitting on any such location as far as I have understood, also people suggested to put that line as 127.0.0.1/socket.io/socket-io.js but none made the js file available for the app to be able to run socket.io.
What is the proper way of defining socket.io in mean.io framework?
I also faced the same issue and took me about a week to finally get it right. I'll try to explain what I did:
app.js
In this file, I just invoke the code that creates and sets up a socket.io object for me, which is then passed to the routes module.
'use strict';
/*
* Defining the Package
*/
var Module = require('meanio').Module;
var MeanSocket = new Module('chat');
/*
* All MEAN packages require registration
* Dependency injection is used to define required modules
*/
MeanSocket.register(function(app, http) {
var io = require('./server/config/socketio')(http);
//We enable routing. By default the Package Object is passed to the routes
MeanSocket.routes(io);
return MeanSocket;
});
server/config/socketio.js
This file simply configures the socket.io object. Please note that I had to upgrade meanio module to version 0.5.26 for this work, as http object (express server) is not available in older meanio versions. Moreover, in case you want to use ssl, you can inject https instead of http.
'use strict';
var config = require('meanio').loadConfig(),
cookie = require('cookie'),
cookieParser = require('cookie-parser'),
socketio = require('socket.io');
module.exports = function(http) {
var io = socketio.listen(http);
io.use(function(socket, next) {
var data = socket.request;
if (!data.headers.cookie) {
return next(new Error('No cookie transmitted.'));
}
var parsedCookie = cookie.parse(data.headers.cookie);
var sessionID = parsedCookie[config.sessionName];
var parsedSessionID = cookieParser.signedCookie(parsedCookie[config.sessionName], config.sessionSecret);
if (sessionID === parsedSessionID) {
return next(new Error('Cookie is invalid.'));
}
next();
});
return io;
};
routes/chat.js
Finally, use the routes file to define the socket events, etc.
'use strict';
// The Package is passed automatically as first parameter
module.exports = function(MeanSocket, io) {
io.on('connection', function(socket) {
console.log('Client Connected');
socket.on('authenticate', function(data, callback) {
});
});
};
Hope this helps!
The simplest way would be to install the socket package...
mean install socket

XSockets do not connect from Firefox

I need to use web sockets for some interactions with the user. I have pretty much copypasted solution from here - http://xsockets.net/blog/angular-js-xsocketsnet and got an issue with Firefox (27.0.1).
When I try to make this call (TwoWayBinding is my XSockets controller, I'm using .NET MVC on host side):
var connect = function (url) {
var deferred = $q.defer();
socket = new XSockets.WebSocket(url);
socket.on(XSockets.Events.open, function (conn) {
$rootScope.$apply(function () {
deferred.resolve(conn);
});
});
return deferred.promise;
};
connect("ws://localhost:49200/TwoWayBinding").then(function (ctx) {
isConnected = true;
queued.forEach(function (msg, i) {
publish(msg.t, msg.d);
});
queued = [];
});
I always get an error from Firebug:
Firefox can't establish a connection to the server at ws://localhost:49200/TwoWayBinding.
this.webSocket = new window.WebSocket(url, subprotocol || "XSocketsNET");
The same code works well in Chrome, it gets connected and I'm getting messages sent from host. Mentioned methods are wrapped into angular service, but this all works, I do not think this should be a problem.
One thing I was able to figure out from Fiddler was this:
Chrome:
Result Protocol Host URL Body Caching Content-Type Process Comments Custom
3 200 HTTP Tunnel to localhost:49200 0 chrome:3976
Result Protocol Host URL Body Caching Content-Type Process Comments Custom
6 101 HTTP localhost:49200 /TwoWayBinding?XSocketsClientStorageGuid=5cf5c99aafd141d1b247ed70107659e0 0 chrome:3976
Firefox:
Result Protocol Host URL Body Caching Content-Type Process Comments Custom
1740 200 HTTP Tunnel to localhost:49200 0 firefox:1420
Result Protocol Host URL Body Caching Content-Type Process Comments Custom
1741 - HTTP localhost:49200 /TwoWayBinding -1 firefox:1420
Simply said - there is some additional parameter XSocketsClientStorageGuid in the response for Chrome which does not occur in the respose to FF. I'm not sure if that has any impact or if I'm completely wrong but will appreciate any advice if somebody experiences same issue.
Update:
It looks like the critical line is this one
socket = new XSockets.WebSocket(url);
as the socket is not created properly in Firefox. But I still not have the cause of this.
What version are you running on , did you make a new installation of XSockets.NET using the Nuget Package or did you use the git example mentioned in the quesion above?
I just did a test on FF 26.0 and 27.0.1 , and it did go well using this pice of example;
http://xsockets.github.io/XSockets.JavaScript.API/test/index.html
I will have a look at the old Angular example asap and makre sure it is fixed of there is a problem!
Kind regards
Magnus

Resources