Uncaught InvalidStateError: Failed to execute 'send' on 'WebSocket': - javascript

I'm trying to run this code:
function smConnect() {
ws = new WebSocket('ws://127.0.0.1:1805/');
delete ws.URL;
ws.onopen = function(response) {};
ws.onmessage = function(response) {};
ws.onclose = function(response) {};
ws.onerror = function(error) {};
}
smConnect();
ws.send('message', 'hi');
But it returns me this error:
Uncaught InvalidStateError: Failed to execute 'send' on 'WebSocket': Still in CONNECTING state.
What could be the problem?

You could do it like this, it adds some logging, the sending of the info you can handle outside of your constructor, and you would also have abstracted away the SocketWrapper in its own namespace (ok, yes, it's in window now :))
You can check the dev tools (F12 in most browsers) to see whats happening in the logs/error, eg: here it throws an error, as there is no socket available :)
And you are not required to give a value for all events, just the ones you need (your case onopen + maybe onmessage?)
(inside the defined callbacks, this would point towards the socket, not the SocketWrapper, the SocketWrapper also doesn't offer the ws variable, it's kind of private, but it should do i guess)
There is a send method on the SocketWrapper, that throws an error, when you send to a closed stream, but in case it wasn't opened yet, it will queue the messages till it gets opened and then empty the queue to the websocket (so in a sence, you are not required to set the onopen callback, just adding it using the send method should be fine ;)
(function(nameSpace) {
function createMethod(method, options, stateCallback) {
var that = this;
this[method] = function() {
if (stateCallback && stateCallback.apply) {
stateCallback(method);
}
console.info(method);
if (options[method] && options[method].apply) {
options[method].apply(that, arguments);
}
};
}
function SocketWrapper(options) {
var ws,
events = ['onopen', 'onmessage', 'onclose', 'onerror'],
i, len, prop = {
opened: false,
closed: false,
error: false
},
method;
if (typeof options === 'undefined' || !options) {
throw 'ArgumentException: please add default constructor options';
}
this.queue = [];
this.onEventTrigger = function(eventName) {
var i, len;
if (eventName === 'onopen') {
prop.opened = true;
prop.closed = false;
// openend send queue
if (this.queue.length > 0) {
for (i = this.queue.length; --i >= 0;) {
this.send.apply(this, this.queue[0]);
this.queue.splice(0, 1);
}
}
}
if (eventName === 'onerror') {
prop.error = true;
}
if (eventName === 'onclosed') {
prop.opened = false;
prop.closed = true;
}
};
this.init = function() {
var cb = this.onEventTrigger.bind(this);
ws = new WebSocket(options.url);
for (i = 0; i < events.length; i++) {
method = events[i];
createMethod.apply(ws, [method, options, cb]);
}
};
this.send = function() {
if (prop.closed) {
throw 'InvalidOperation: Cannot send messages to a closed Websocket!';
}
if (!prop.opened) {
this.queue.push(arguments);
} else {
ws.send.apply(ws, arguments);
}
};
this.init();
return this;
}
window.SocketWrapper = SocketWrapper;
}(window));
var socket = new window.SocketWrapper({
url: 'ws://127.0.0.1:1805',
onopen: function() {
this.send('message', 'hi');
},
onmessage: function() {
console.log(arguments);
},
onclose: function() {
socket = null;
},
onerror: function() {
console.log('error occured, oh no!');
console.error(arguments);
}
});
socket.send('i am message send to soon, but since i check the state of the ws object, i will be queued and send when appropriate');

Related

Error "A mutation operation was attempted on a database that did not allow mutations." when trying to open a transaction inside success event of ajax

I just started my research on indexeddb for storing the data on the client-side. I was able to perform basic CRUD operations so I started to code the actual implementation case where user should retrieve the data from server in the form of json and then store it in the indexedDB objectStore. Now this is where I am facing problem, I know both ajax and transactions in IndexedDB are async ,so I'm calling transactions in the success event, it throws me error saying "InvalidStateError : A mutation operation was attempted on a database that did not allow mutations." on the line where I call transaction to open.
Here is the javascript code and the json file
// Javascript IndexedDB start
var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction;
var IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
// open db
var dbase;
var gotWidgetTemplates = false;
var widgetTemplets;
function init() {
var databaseName = "ADTClientDB";
var databaseVersion = 1;
var open = indexedDB.open(databaseName, databaseVersion);
open.onupgradeneeded = function (e) {
var db = e.target.result;
if (!db.objectStoreNames.contains("WidgetTemplate")) {
var widgetTemplateObj = db.createObjectStore("WidgetTemplate", {
keyPath: 'name' });
widgetTemplateObj.createIndex("image", "image", { unique: false });
widgetTemplateObj.createIndex("html", "html", { unique: false });
widgetTemplateObj.createIndex("css", "css", { unique: false });
widgetTemplateObj.createIndex("rules", "rules", { multiEntry: true });
}
}
open.onsuccess = function (e1) {
dbase = e1.target.result;
getTemplates(dbase);
dbase.close();
}
open.onerror = function () {
alert("Error opening the database");
}
function getTemplates(dbase) {
$.ajax({
url: "../Sample Json files/widgetTemplates.json",
type: "GET",
success:
function (data) {
var obj = JSON.parse(JSON.stringify(data));
widgetTemplets = obj.widgets_info;
gotWidgetTemplates = true;
if (gotWidgetTemplates && widgetTemplets !== null) {
// I tried putting the transaction and store here,it was giving me same error..
for (var temp in widgetTemplets) {
// error on the next line
var trans = dbase.transaction(["WidgetTemplate"], "readwrite");
var store = trans.objectStore("WidgetTemplate");
store.add(widgetTemplets[temp]);
}
}
},
error: function (error) {
console.log(arguments);
}
});
}
I tried putting setTimeout() like this
function addTemps(dbase) {
if (gotWidgetTemplates && widgetTemplets !== null) {
var trans = dbase.transaction(["WidgetTemplate"], "readwrite");
var store = trans.objectStore("WidgetTemplate");
for (var temp in widgetTemplets) {
store.add(widgetTemplets[temp]);
}
}
else {
setTimeout(addTemps, 7000);
}
}
Still it gives me either same error on the line of creating transaction or "tooManyRecursions" error.
I tried putting promise into this like
$.get("../Sample Json files/widgetTemplates.json").then(
function (data0) {
console.log(data0);
var obj = JSON.parse(JSON.stringify(data0));
widgetTemplets = obj.widgets_info;
var trans1 = dbase.transaction(["WidgetTemplate"], "readwrite");
var store1 = trans1.objectStore("WidgetTemplate");
for (var temp in widgetTemplets) {
store1.add(widgetTemplets[temp]);
}
console.log(obj);
}, function (xhr, state, error) {
debugger;
console.log(arguments);
});
It gives me same error on the transaction line.
Here is the json
{
"widgets_info": [
{
"name": "TextInput",
"image": "TEXTINPUT.PNG",
"html": "<label for=\"uname\">LABEL</label> <input type=\"text\" id = \"uname\" name=\"uname\">",
"css": "{width : 30%; height:10%;}",
"rules": {
"on the event of": [
"NONE",
"Single left mouse click"
],
"do these": [
"NONE",
"Trigger behavior"
]
}
}
]
}
I could see a transaction is possible inside ajax success link (Ajax IndexedDB Delete Current Sucesfull Upload)
I want to know why I cannot achieve this.I tried what all I can do, I browsed all the stuff I can but I cannot find the solution. A solution/reason for this would be greatly appreciated.Thanks!!

Node.js - Can't send headers after they are sent

The closest issue I've found to mine is here. I believe I'm getting this error from how my .end() calls are set up. Here's the code we're working with:
app.get('/anihome',function(req,res){
var context = {};
function renderPage(context) {
res.render('anihome',context);
}
function addRequestToPage(text) {
context.data = text.toString('utf8');
context.info = JSON.parse(text);
return context;
}
function addAnimeToPage(text) {
context.anime = JSON.parse(text);
return context;
}
function addAnimeRequest(context) {
var options2 = {
host: 'anilist.co',
path: '/api/anime/20631?access_token=' + context.info.access_token,
method: 'GET'
};
https.request(options2, function(restRes) {
restRes.on('data',function(jsonResult) {
//context.anime = JSON.parse(jsonResult);
//console.log(JSON.parse(jsonResult));
console.log(context);
renderPage(context);
});
}).end();
}
function addHeaderRequest(context) {
var options = {
host: 'anilist.co',
path: '/api/auth/access_token?grant_type=client_credentials&client_id='
+ clientID + '&client_secret=' + secretKey,
method: 'POST'
};
https.request(options, function(restRes) {
restRes.on('data', function(jsonResult) {
context = addRequestToPage(jsonResult);
addAnimeRequest(context);
});
}).end();
}
addHeaderRequest(context);
});
I've tried setting up one of the .end()s with a callback, .end(addAnimeRequest(context));, which leaves me with a socket hang up error, so presumably something in my addAnimeRequest function is taking too long?
Is there a better way to make multiple requests to the same website with different options? I'm pretty new to Node.js.
The data event can be emitted more than once. You would need to add a listener for the end event and then pass in all of your data. Example:
https.request(options2, function(restRes) {
var buf = ''
restRes.on('data',function(jsonResult) {
//context.anime = JSON.parse(jsonResult);
//console.log(JSON.parse(jsonResult));
buf += jsonResult
});
restRes.on('end', function() {
// TODO JSON.parse can throw
var context = JSON.parse(buf)
renderPage(context)
})
}).end();

why callback variable is undefined in this function?

I have a function which handle an Ajax call in my status.js:
window.APPLICATION = window.APPLICATION || {};
window.APPLICATION = {
getStatus: function(callingScope) {
var _this = this;
var getStatus = $.ajax({
type: "POST",
url: "/php/status.php",
data: {
"action": "mystatus"
}
});
getStatus.done(function(Response) {
if (Response.data != undefined) {
_this.cache.statusdata = {
userstatus: Response.data
};
} else if (Response.error != undefined) {
console.log('status data request error...');
}
callingScope.ajaxLoaded++;
}),
getStatus.fail(function(jqXHR, textStatus) {
console.log("user save form fail - an error occurred: (" + textStatus + ").");
});
},
}
in my user.js, I call it:
window.APPLICATION.USER.ajaxLoaded = 0;
window.APPLICATION.getStatus(window.APPLICATION.USER);
I need this ajaxLoaded variable counter as I have other Ajax calls. Need it to determine whether all calls finished.
However, I got following errors in console:
how to solve it?
window.APPLICATION.USER.ajaxLoaded = 0;
this line is giving error.
It's because, USER is undefined.
You need to declare USER as an object first before defining properties.
so
window.APPLICATION.USER = {};
then
window.APPLICATION.USER.ajaxLoaded = 0; // this will work
Inside the callback you are trying to access window.APPLICATION.USER object which was undefined so callingScope is giving error that it's undefined

Trying to get HTTP POST request in Firefox extension

I'm building an extension to get the POST request in Firefox. I read through the documentation for intercepting page loads and HTTP observers, but still couldn't manage to get the specific POST data on a page load (ex: data1=50&sdata2=0&data3=50).
I looked into TamperData's code, and found that they used stream.available() and stream.read(1). However, I couldn't get these commands to work with my code.
Currently my code looks like this:
var ObserverTest = {
observe: function(subject, topic, data) {
if (topic == 'http-on-modify-request') {
var httpChannel = subject.QueryInterface(Components.interfaces.nsIHttpChannel);
}
if (topic == "http-on-examine-response") {
var newListener = new TracingListener();
subject.QueryInterface(Ci.nsITraceableChannel);
newListener.originalListener = subject.setNewListener(newListener);
}
},
register: function() {
var observerService = Components.classes["#mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
observerService.addObserver(ObserverTest, "http-on-modify-request", false);
observerService.addObserver(ObserverTest, "http-on-examine-response", false);
},
unregister: function() {
var observerService = Components.classes["#mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
observerService.removeObserver(ObserverTest, "http-on-modify-request");
observerService.removeObserver(ObserverTest,"http-on-examine-response");
}
}
window.addEventListener("load", ObserverTest.register, false);
window.addEventListener("unload", ObserverTest.unregister, false);
//Helper function for XPCOM instanciation (from Firebug)
function CCIN(cName, ifaceName) {
return Cc[cName].createInstance(Ci[ifaceName]);
}
// Copy response listener implementation.
function TracingListener() {
this.originalListener = null;
this.receivedData = []; // array for incoming data.
}
TracingListener.prototype = {
onDataAvailable: function(request, context, inputStream, offset, count) {
var binaryInputStream = CCIN("#mozilla.org/binaryinputstream;1", "nsIBinaryInputStream");
var storageStream = CCIN("#mozilla.org/storagestream;1", "nsIStorageStream");
var binaryOutputStream = CCIN("#mozilla.org/binaryoutputstream;1", "nsIBinaryOutputStream");
var stream = Components.classes["#mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
stream.init(binaryInputStream);
binaryInputStream.setInputStream(inputStream);
storageStream.init(8192, count, null);
binaryOutputStream.setOutputStream(storageStream.getOutputStream(0));
// Copy received data as they come.
var data = binaryInputStream.readBytes(count);
this.receivedData.push(data);
binaryOutputStream.writeBytes(data, count);
this.originalListener.onDataAvailable(request, context, storageStream.newInputStream(0), offset, count);
},
onStartRequest: function(request, context) {
this.originalListener.onStartRequest(request, context);
},
onStopRequest: function(request, context, statusCode)
{
// Get entire response
var responseSource = this.receivedData.join();
this.originalListener.onStopRequest(request, context, statusCode);
},
QueryInterface: function (aIID) {
if (aIID.equals(Ci.nsIStreamListener) || aIID.equals(Ci.nsISupports)) {
return this;
}
throw Components.results.NS_NOINTERFACE;
}
}
First of all, the "http-on-examine-response" and TracingListener isn't required at all. This stuff would have merit if you wanted to do something with the response, but you're after data in the request, so topic == 'http-on-modify-request' it is.
The following function (untested, but copied from one of my extensions and cleaned up a bit) demonstrates how to get post data. The function is assumed to be called from http-on-modify-request.
const ScriptableInputStream = Components.Constructor(
"#mozilla.org/scriptableinputstream;1",
"nsIScriptableInputStream",
"init");
function observeRequest(channel, topic, data) {
let post = null;
if (!(channel instanceof Ci.nsIHttpChannel) ||
!(channel instanceof Ci.nsIUploadChannel)) {
return post;
}
if (channel.requestMethod !== 'POST') {
return post;
}
try {
let us = channel.uploadStream;
if (!us) {
return post;
}
if (us instanceof Ci.nsIMultiplexInputStream) {
// Seeking in a nsIMultiplexInputStream effectively breaks the stream.
return post;
}
if (!(us instanceof Ci.nsISeekableStream)) {
// Cannot seek within the stream :(
return post;
}
let oldpos = us.tell();
us.seek(0, 0);
try {
let is = new ScriptableInputStream(us);
// we'll read max 64k
let available = Math.min(is.available(), 1 << 16);
if (available) {
post = is.read(available);
}
}
finally {
// Always restore the stream position!
us.seek(0, oldpos);
}
}
catch (ex) {
Cu.reportError(ex);
}
return post;
}
Depending on your use case, you might want to check if the us instanceof e.g. nsIMIMEInputStream or nsIStringInputStream for special handling or fast-paths...
You'd call it from your observer like:
observe: function(subject, topic, data) {
if (topic == 'http-on-modify-request') {
observeRequest(subject, topic, data);
}
},

What design pattern should I apply when checking multiple ajax request completion?

I have 3 ajax call in one function and checkAjaxCompletion which checks each ajax completion flag.
What the code below does is send multiple separate ajax calls and interval method checks completion flags to determine whether to proceed or keep interval. (I know clearInterval is not shown but the point is I want to use something other than interval)
Current code is:
function manyAjax() {
setInterval( function() { checkAjaxCompletion(); } , 200);
ajax1();
ajax2();
ajax3();
}
function ajax1() {
//send ajax request to server and if success set flag to 1. Default is 0. Error is 2.
}
function ajax2() {
//send ajax request to server and if success set flag to 1. Default is 0. Error is 2.
}
function ajax3() {
//send ajax request to server and if success set flag to 1. Default is 0. Error is 2.
}
function checkAjaxCompletion() {
if(ajax1_flag == 1 && ajax2_flag == 1 && ajax3_flag == 1) {
//everything went success, do some process
}
else if(ajax1_flag == 2 || ajax2_flag == 2 || ajax3_flag == 2) {
//some ajax failed, do some process
}
else {
//all ajax have not been completed so keep interval i.e. do nothing here
}
}
But I'm hesitating to depend on using interval function because calling it so often seem such waste of memory. There must be better way to do. I'm thinking if observer pattern can be applied here but would like to hear opinions.
It is observer-notifier, if you want to call it that - but each of your ajax calls will more than likely have a callback in javascript when they complete. Why not call checkAjaxCompletion() at the end of each of them, and do nothing if you're still waiting on others?
Dustin Diaz does a great job with this example.
function Observer() {
this.fns = [];
}
Observer.prototype = {
subscribe : function(fn) {
this.fns.push(fn);
},
unsubscribe : function(fn) {
this.fns = this.fns.filter(
function(el) {
if ( el !== fn ) {
return el;
}
}
);
},
fire : function(o, thisObj) {
var scope = thisObj || window;
this.fns.forEach(
function(el) {
el.call(scope, o);
}
);
}
};
The publisher:
var o = new Observer;
o.fire('here is my data');
The subscriber:
var fn = function() {
// my callback stuff
};
o.subscribe(fn);
To unsubscribe:
var fn = function() {
// my callback stuff
};
o.subscribe(fn);
// ajax callback
this.ajaxCallback = function(){
$.ajax({
type: "POST",
url: ajax.url,
data: {key: value},
async : !isAll,// false使用同步方式执行AJAX,true使用异步方式执行ajax
dataType: "json",
success: function(data){
if(data.status == 'successful'){
selfVal.parent().find('.msg').addClass('ok').html(msg.ok);
}else if(data.status == 'failed'){
checkRet = false;
selfVal.parent().find('.msg').removeClass('ok').html(msg.error);
}else{
checkRet = false;
}
return this;
}
});
}
return this;
Maybe you want to check your inputvalue callback ajax in your form;
You can view my website Demo, hope help you.
http://6yang.net/myjavascriptlib/regForm
Okay my idea was to make your own object that can handle sending an array of requests, keep a history of each request and do what i'm gonna call 'postProccessing' on each response, here is a probably very dodgy bit of code to hopefully demonstrate what I am thinking.
var Ajax = function() {
var request, callback, lst;
if (window.XMLHttpRequest) {
request = new XMLHttpRequest();
} else if (window.ActiveXObject) {
request = new ActiveXObject("Microsoft.XMLHTTP");
}
request.onreadystatechange = handleResponse;
this.history = [{}];
this.send = function(args) {
for (var i = 0; i < args.length; i++) {
if (args.url) {
request.open(args.type || 'GET', args.url);
}
request.send(args.data || null);
callback = args.callback;
lst++;
}
}
function handleResponse() {
var response = {
url: '',
success: true,
data: 'blah'
};
history.push(response);
if (postProccess()) {
callback();
}
}
function postProcess() {
if (this.history[lst].success) {
return true;
} else {
return false;
}
}
}

Categories