SignalR throwing JavaScript Error - javascript

I'm new to signalr. I've started an MVC 4.0 application, out of the box, and wired up my signalr JavaScript on the Index View. When I click either the Register or Login buttons, signalr throws a JavaScript error.
Unhandled exception at line 11, column 10700 in http://localhost:49172/Scripts/jquery.signalR- 0.5.1.min.js
0x800a138f - Microsoft JScript runtime error: Unable to set value of the property 'src': object is null or undefined
Any suggestions appreciated.
EDIT:
This is the extent of my code:
$(function () {
var blasht = $.connection.blashtHub;
blasht.addMessage = function (message) {
$('#messages').append('<li>' + message + '');
};
$("#blashtIt").click(function () {
var control = $('#blashtText');
var control2 = $('#hiddenUserId');
// Call the chat method on the server
blasht.send(control2.val(), control.val());
control.val('');
});
blasht.updateTopTen = function (message) {
//add code to update the top user's list
};
// Start the connection
$.connection.hub.start();
});
As suggested I dropped the min and here is where it is crashing, on the frame.sc = src; line.
reconnect: function (connection) {
var that = this;
window.setTimeout(function () {
var frame = connection.frame,
src = transportLogic.getUrl(connection, that.name, true) + "&frameId=" + connection.frameId;
connection.log("Upating iframe src to '" + src + "'.");
frame.src = src;
}, connection.reconnectDelay);
},
SignalR, not me, is invoking this reconnect function. Obviously, that is how it maintains a connection with the server.

The is a bug in the current version of SignalR for the "Forever-Frame" implementation, which is the one that IE9 uses:
https://github.com/SignalR/SignalR/issues/446
A workaround is to force SignalR not to use Forever-Frame transport (https://github.com/SignalR/SignalR/wiki/SignalR-JS-Client).
So change
$.connection.hub.start();
to
$.connection.hub.start({ transport: ['webSockets', 'serverSentEvents', 'longPolling'] });

From the error message, and without your having shown any code, I'd have to guess that you have code that looks like this:
foo.src = someValue;
...where foo is null or undefined. Which begs the question of why is foo null or undefined, but without more context, it's impossible to say. Stepping through with the IE8+ "F12 Developer Tools" may help you pinpoint it.
(Update after code was posted)
I'm guessing that the line causing the error is frame.src = src;. Reformatting that code with consistent indentation:
reconnect: function (connection) {
var that = this;
window.setTimeout(function () {
var frame = connection.frame,
src = transportLogic.getUrl(connection, that.name, true) + "&frameId=" + connection.frameId;
connection.log("Upating iframe src to '" + src + "'.");
frame.src = src; // <=== Presumably this is the line failing
}, connection.reconnectDelay);
},
It would appear that as of the time the delayed function is called, connection.frame is null or undefined. So you'll need to find out why that is. The first thing I'd do is check whether connection.frame is null or undefined when reconnect is called, or if it's only later when the delayed function runs (e.g., has something cleared it in the meantime, and if so, why).

Related

Error while streaming through Chromecast cast_sender.js

Add chrome cast according to the tutorial.
After adding the Chromecast button, I click it, select an available device from the network, and it is connected. The status "Streaming" is visible in the browser, in fact nothing happens, except for the following error in the console:
TypeError: Cannot read property 'loadMedia' of null
Code:
cast.framework.CastContext.getInstance().setOptions({
receiverApplicationId: '111111',
autoJoinPolicy: chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED
});
var currentMediaURL =
'https://.....';
var contentType = 'mp4';
var mediaInfo = new chrome.cast.media.MediaInfo(currentMediaURL,contentType);
var request = new chrome.cast.media.LoadRequest(mediaInfo);
console.log('Below variable -mediaInfo ');
console.log(mediaInfo);
console.log('Below variable -request ');
console.log(request);
var castSession = cast.framework.CastContext.getInstance().getCurrentSession();
console.log('Below variable -castSession ');
console.log(castSession);
castSession.loadMedia(request).then(
function () {
console.log('Load succeed');
},
function (errorCode) {
console.log('Error code: ' + errorCode);
});
Code testing:
As I understand it, for some reason, the link to the stream is not sent.
There is an interesting question, why does the link to the stream go to the variable contentid although there is a variablecontentUrl?

FileReader API error while using jsmediatags

While using JSMediaTags, the onError event handler for the jsmediatags.open method receives an error object with properties:
type = "fileReader"
info = "Offset 0 hasn't been loaded yet"
See pseudo-code below.
The exact text of the error is not in the JSMediaTags file, leading me to believe that the error is being generated by the browser, but I am unable to find insight into what the specific problem is.
I'm running this on my local workstation, with a Windows 7 OS running IIS. I've tested in Chrome v 61, and Firefox v 55. Same error in both.
As you can see, I'm trying to first send the file object (as a file) into the jsmediatags.read function. This results in the error detailed above.
I've commented out the code where, instead of the file object, I try sending in 1.) the complete local path to the file, 2.) the result of createObjectURL on the file object, as well as 3.) the file object's name property. These last 3 do not result in either an onSuccess or onError event being fired.
<script type="text/javascript" src="tagreader/jsmediatags.js"></script>
<input type="file" id="fileinput" onchange="window.handleLocalFiles(this.files)">
<script>
var gobjFileTags = null;
function handleLocalFiles(argFiles){
if (argFiles && (argFiles.length > 0)){
testTagReader(argFiles[0]);
}
}
function testTagReader(objFile){
var objTagReader = null;
var strURL = "";
var strFileName = "";
var strLocalPath = "";
objTagReader = window.jsmediatags;
objTagReader.read(objFile, {
onSuccess: function(tag){
window.gobjFileTags = tag;
window.readFileTags();
},
onError: function(objError){
window.alert("objTagReader Error - type: " + objError.type + ", info: " + objError.info);
}
});
}
function readFileTags(){
window.alert("readFileTags called");
}

Worker blocking UI thread in Chrome

I'm building a web app that uses EvaporateJS to upload large files to Amazon S3 using Multipart Uploads. I noticed an issue where every time a new chunk was started the browser would freeze for ~2 seconds. I want the user to be able to continue to use my app while the upload is in progress, and this freezing makes that a bad experience.
I used Chrome's Timeline to look into what was causing this and found that it was SparkMD5's hashing. So I've moved the entire upload process into a Worker, which I thought would fix the issue.
Well the issue is now fixed in Edge and Firefox, but Chrome still has the exact same problem.
Here's a screenshot of my Timeline:
As you can see, during the freezes my main thread is doing basically nothing, with <8ms of JavaScript running during that time. All the work is occurring in my Worker thread, and even that is only running for ~600ms or so, not the 1386ms that my frame takes.
I'm really not sure what's causing the issue, are there any gotchas with Workers that I should be aware of?
Here's the code for my Worker:
var window = self; // For Worker-unaware scripts
// Shim to make Evaporate work in a Worker
var document = {
createElement: function() {
var href = undefined;
var elm = {
set href(url) {
var obj = new URL(url);
elm.protocol = obj.protocol;
elm.hostname = obj.hostname;
elm.pathname = obj.pathname;
elm.port = obj.port;
elm.search = obj.search;
elm.hash = obj.hash;
elm.host = obj.host;
href = url;
},
get href() {
return href;
},
protocol: undefined,
hostname: undefined,
pathname: undefined,
port: undefined,
search: undefined,
hash: undefined,
host: undefined
};
return elm;
}
};
importScripts("/lib/sha256/sha256.min.js");
importScripts("/lib/spark-md5/spark-md5.min.js");
importScripts("/lib/url-parse/url-parse.js");
importScripts("/lib/xmldom/xmldom.js");
importScripts("/lib/evaporate/evaporate.js");
DOMParser = self.xmldom.DOMParser;
var defaultConfig = {
computeContentMd5: true,
cryptoMd5Method: function (data) { return btoa(SparkMD5.ArrayBuffer.hash(data, true)); },
cryptoHexEncodedHash256: sha256,
awsSignatureVersion: "4",
awsRegion: undefined,
aws_url: "https://s3-ap-southeast-2.amazonaws.com",
aws_key: undefined,
customAuthMethod: function(signParams, signHeaders, stringToSign, timestamp, awsRequest) {
return new Promise(function(resolve, reject) {
var signingRequestId = currentSigningRequestId++;
postMessage(["signingRequest", signingRequestId, signParams.videoId, timestamp, awsRequest.signer.canonicalRequest()]);
queuedSigningRequests[signingRequestId] = function(signature) {
queuedSigningRequests[signingRequestId] = undefined;
if(signature) {
resolve(signature);
} else {
reject();
}
}
});
},
//logging: false,
bucket: undefined,
allowS3ExistenceOptimization: false,
maxConcurrentParts: 5
}
var currentSigningRequestId = 0;
var queuedSigningRequests = [];
var e = undefined;
var filekey = undefined;
onmessage = function(e) {
var messageType = e.data[0];
switch(messageType) {
case "init":
var globalConfig = {};
for(var k in defaultConfig) {
globalConfig[k] = defaultConfig[k];
}
for(var k in e.data[1]) {
globalConfig[k] = e.data[1][k];
}
var uploadConfig = e.data[2];
Evaporate.create(globalConfig).then(function(evaporate) {
var e = evaporate;
filekey = globalConfig.bucket + "/" + uploadConfig.name;
uploadConfig.progress = function(p, stats) {
postMessage(["progress", p, stats]);
};
uploadConfig.complete = function(xhr, awsObjectKey, stats) {
postMessage(["complete", xhr, awsObjectKey, stats]);
}
uploadConfig.info = function(msg) {
postMessage(["info", msg]);
}
uploadConfig.warn = function(msg) {
postMessage(["warn", msg]);
}
uploadConfig.error = function(msg) {
postMessage(["error", msg]);
}
e.add(uploadConfig);
});
break;
case "pause":
e.pause(filekey);
break;
case "resume":
e.resume(filekey);
break;
case "cancel":
e.cancel(filekey);
break;
case "signature":
var signingRequestId = e.data[1];
var signature = e.data[2];
queuedSigningRequests[signingRequestId](signature);
break;
}
}
Note that it relies on the calling thread to provide it with the AWS Public Key, AWS Bucket Name and AWS Region, AWS Object Key and the input File object, which are all provided in the 'init' message. When it needs something signed, it sends a 'signingRequest' message to the parent thread, which is expected to provided the signature in a 'signature' message once it's been fetched from my API's signing endpoint.
I can't give a very good example or analyze what you are doing with only the Worker code, but I strongly suspect that the issue either has to do with either the reading of the chunk on the main thread or some unexpected processing that you are doing on the chunk on the main thread. Maybe post the main thread code that calls postMessage to the Worker?
If I were debugging it right now, I'd try moving your FileReader operations into the Worker. If you don't mind the Worker blocking while it loads a chunk, you could also use FileReaderSync.
Post-comments update
Does generating the presigned URL require hashing the file content + metadata + a key? Hashing file content is going to take O(n) in the size of the chunk and it's possible, if the hash is the first operation that reads from the Blob, that the loading of the file content could be deferred until the hashing starts. Unless you are compelled to keep the signing in the main thread (you don't trust the worker with key material?) that would be another good thing to bring into the worker.
If moving the signing into the Worker is too much, you could have the worker do something to force the Blob to be read and/or pass the ArrayBuffer(or Uint8Array or what have you) of file content back to the main thread for signing; this would ensure that reading the chunk does not occur on the main thread.

If Websocket connection can't be established do something else

I'm currently running into a problem you guys might be able to help me with..
I'm using websockets to connect to a custom server. Now i want to integrate a second Server IP if the first one isn't available.
How is it possible to detect, that the connection couldn't be made because the server isn't reachable? When I enter a wrong ws://url in my script, Chrome for example gives me the following error:
WebSocket connection to 'wss://1234/' failed: Error in connection establishment: net::ERR_NAME_NOT_RESOLVED
in Firefox it's something complete different. Do you guys of any method to catch this error with Javascript?
Basically when the ws:// url can't be reached, i want to change a variable with a different Server-IP and try it with this one again...
Thanks for your help!
It seems there's no way to catch the problem on instantiation, even though the magical JavaScript black box somehow seems to know the problem occurs on the new WebSocket.
To detect this error, use the following:
ws = new WebSocket(server);
ws.onerror = function (evt) {
if (ws.readyState == 3) {
//Connection closed.
}
}
thanks #orbitbot,
I'm using a framework called jwebsocket (jwebsocket.org). My Code is basically this:
serverstate = "0";
console.log(serverstate);
function logon() {
if(serverstate == "0") {
lURL = "wss://testurl-one:9797";
} else if (serverstate == "1") {
lURL = "wss://testurl-two:9797";
}
var gUsername = "user";
var lPassword = "pass";
console.log( "Connecting to " + lURL + " and console.logging in as '" + gUsername + "'..." );
var lRes = lWSC.logon( lURL, gUsername, lPassword, {
// OnOpen callback
OnOpen: function( aEvent ) {
console.log( "jWebSocket connection established." );
},
// OnMessage callback
OnMessage: function( aEvent, aToken ) {
var lDate = "";
if( aToken.date_val ) {
lDate = jws.tools.ISO2Date( aToken.date_val );
}
console.log( "jWebSocket '" + aToken.type + "' token received, full message: '" + aEvent.data + "' " + lDate + "" );
console.log(aToken);
}
},
// OnClose callback
OnClose: function( aEvent ) {
console.log( "Disconnected from Server" );
console.log("Using next server..");
serverstate = "1";
console.log(serverstate);
console.log("Trying to connect to next server");
logon();
},
// OnClose callback
OnError: function( aEvent ) {
console.log ("Some error appeared");
}
});
console.log( lWSC.resultToString( lRes ) );
}
Of course this would work so far. My Problem is that im using websockets to open a connection, get some information, and after that close the connection again.
since this code will always be fired if the server connection is closed (which in many cases i want to..) i can't use it like that...
any other ideas on this problem ?
I got it.. for everyone else who's interested:
When connection is made you receive a message from there server. So if the server is not available.. there'll be no message. So i just added a variable to the "OnMessage" Part.. and in the disconnect i check if a message was received. If not the server isn't there.. if yes, everything works fine..
Assuming your code is something like this,
var host = 'ws://a.real.websocket.url';
var socket = new WebSocket(host);
... you just need to surround the call to new WebSocket with a try/catch block, something like this
try {
var socket = new WebSocket(host);
} catch (e) {
// inspect e to understand why there was an error
// and connect to another url if necessary
}
That being said, it might be easier to work with a websockets library such as Socket.IO or SockJS (https://github.com/sockjs/sockjs-client), which then would change your reconnection code logic to whatever the libraries provide.

How to postMessage through port when websocket receives the word.?

I am trying to use the websocket's onMessage function so that when it receives the word "go", it will postMessage through the port for the current tab. The current tab id is valid, but I keep getting the error Uncaught TypeError: Cannot read property 'postMessage' of undefined.
ws.onmessage = function (evt) {
if(evt.data == "connect"){
rpwd = "helloworld";
ports[curTabID].postMessage({text: rpwd});
}
};
The problem was with my mistaking ports and tab.id to be the same thing. The postMessage must be called on a port. I had to add in an onConnect listener to get the port for whatever tab was opened.
var ports = {};
function onConnect(port) {
ports[port.sender.tab.id] = port;
}
chrome.extension.onConnect.addListener(onConnect);
After that, I needed to know what my current tab id was so that I can look it up in the ports array, which is populated by the onConnect.
var curTabID = 0;
chrome.tabs.onSelectionChanged.addListener(function(tabId) {
curTabID = tabId;
});
From that, I was able to get the port info necessary to send the postMessage.
ws.onmessage = function (evt) {
if(evt.data == "connect"){
rpwd = "helloworld";
ports[curTabID].postMessage({text: rpwd});
}
};
I struggled pretty hard with this code, so I hope I can save somebody time.

Categories