diff --git a/compiler/cpp/src/generate/t_js_generator.cc b/compiler/cpp/src/generate/t_js_generator.cc index 9def5da92..fa06b0517 100644 --- a/compiler/cpp/src/generate/t_js_generator.cc +++ b/compiler/cpp/src/generate/t_js_generator.cc @@ -47,6 +47,9 @@ class t_js_generator : public t_oop_generator { iter = parsed_options.find("node"); gen_node_ = (iter != parsed_options.end()); + + iter = parsed_options.find("jquery"); + gen_jquery_ = (iter != parsed_options.end()); if (gen_node_) { out_dir_base_ = "gen-nodejs"; @@ -160,7 +163,7 @@ class t_js_generator : public t_oop_generator { std::string render_includes(); std::string declare_field(t_field* tfield, bool init=false, bool obj=false); std::string function_signature(t_function* tfunction, std::string prefix="", bool include_callback=false); - std::string argument_list(t_struct* tstruct); + std::string argument_list(t_struct* tstruct, bool include_callback=false); std::string type_to_enum(t_type* ttype); std::string autogen_comment() { @@ -226,6 +229,11 @@ class t_js_generator : public t_oop_generator { */ bool gen_node_; + /** + * True if we should generate services that use jQuery ajax (async/sync). + */ + bool gen_jquery_; + /** * File streams */ @@ -341,11 +349,11 @@ void t_js_generator::generate_enum(t_enum* tenum) { vector::iterator c_iter; for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { int value = (*c_iter)->get_value(); - f_types_ << "'" << (*c_iter)->get_name() << "' : " << value; - if (c_iter != constants.end()-1) + f_types_ << "'" << (*c_iter)->get_name() << "' : " << value; + if (c_iter != constants.end()-1) { f_types_ << ","; - - f_types_ << endl; + } + f_types_ << endl; } f_types_ << "};"<& fields = arg_struct->get_members(); vector::const_iterator fld_iter; string funname = (*f_iter)->get_name(); + string arglist = argument_list(arg_struct); // Open function - f_service_ << js_namespace(tservice->get_program())<get_program())<get_name(); - } - f_service_ << ");" << endl; + f_service_ << indent() << + "this.send_" << funname << "(" << arglist << ");" << endl; if (!gen_node_ && !(*f_iter)->is_oneway()) { f_service_ << indent(); @@ -1025,12 +1028,28 @@ void t_js_generator::generate_service_client(t_service* tservice) { "this.recv_" << funname << "();" << endl; } + if (gen_jquery_) { + indent_down(); + f_service_ << indent() << "} else {" << endl; + indent_up(); + f_service_ << indent() << "var postData = this.send_" << funname << + "(" << arglist << (arglist.empty() ? "" : ", ") << "true);" << endl; + f_service_ << indent() << "return this.output.getTransport()" << endl; + indent_up(); + f_service_ << indent() << ".jqRequest(this, postData, arguments, this.recv_" << funname << ");" << endl; + indent_down(); + indent_down(); + f_service_ << indent() << "}" << endl; + } + indent_down(); f_service_ << "};" << endl << endl; + + // Send function f_service_ << js_namespace(tservice->get_program())<get_name() + " = function("; - - //Need to create js function arg inputs - const vector &fields = tfunction->get_arglist()->get_members(); - vector::const_iterator f_iter; - - for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { - - if(f_iter != fields.begin()) - str += ", "; - - str += (*f_iter)->get_name(); - } - - if (include_callback) { - if (!fields.empty()) { - str += ", "; - } - str += "callback"; - } + str += argument_list(tfunction->get_arglist(), include_callback); str += ")"; return str; @@ -1702,7 +1707,8 @@ string t_js_generator::function_signature(t_function* tfunction, /** * Renders a field list */ -string t_js_generator::argument_list(t_struct* tstruct) { +string t_js_generator::argument_list(t_struct* tstruct, + bool include_callback) { string result = ""; const vector& fields = tstruct->get_members(); @@ -1716,6 +1722,14 @@ string t_js_generator::argument_list(t_struct* tstruct) { } result += (*f_iter)->get_name(); } + + if (include_callback) { + if (!fields.empty()) { + result += ", "; + } + result += "callback"; + } + return result; } @@ -1761,6 +1775,7 @@ string t_js_generator ::type_to_enum(t_type* type) { } -THRIFT_REGISTER_GENERATOR(js, "Javascript", +THRIFT_REGISTER_GENERATOR(js, "Javascript", +" jquery: Generate jQuery compatible code.\n" " node: Generate node.js compatible code.\n") diff --git a/lib/js/test/build.xml b/lib/js/test/build.xml index c1a17e896..843ec6b52 100644 --- a/lib/js/test/build.xml +++ b/lib/js/test/build.xml @@ -66,7 +66,7 @@ You need libthrift*.jar and libthrift*test.jar located at - ${thrift.java.dir} + ${thrift.java.dir}/build Did you compile Thrift Java library and its test suite by "ant compile-test"? @@ -101,7 +101,7 @@ - + @@ -117,14 +117,14 @@ - + - + diff --git a/lib/js/test/test.html b/lib/js/test/test.html index 4615f88fc..f99da0148 100644 --- a/lib/js/test/test.html +++ b/lib/js/test/test.html @@ -27,7 +27,7 @@ - + @@ -39,9 +39,9 @@ - -

Thrift Javascript Bindings: Unit Test (ThriftTest.thrift)

diff --git a/lib/js/thrift.js b/lib/js/thrift.js index b8ca2c024..c7a46fdc2 100644 --- a/lib/js/thrift.js +++ b/lib/js/thrift.js @@ -56,7 +56,7 @@ var Thrift = { var length = 0; for (var k in obj) { if (obj.hasOwnProperty(k)) { - length++; + length++; } } @@ -75,8 +75,8 @@ var Thrift = { Thrift.TException = {}; Thrift.TException.prototype = { initialize: function(message, code) { - this.message = message; - this.code = (code === null) ? 0 : code; + this.message = message; + this.code = (code === null) ? 0 : code; } }; @@ -186,19 +186,16 @@ Thrift.Transport.prototype = { //Gets the browser specific XmlHttpRequest Object getXmlHttpRequestObject: function() { - try { return new XMLHttpRequest(); } catch (e1) { } try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch (e2) { } try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch (e3) { } throw "Your browser doesn't support the XmlHttpRequest object."; - }, - flush: function() { - + flush: function(async) { //async mode - if (this.url === undefined || this.url === '') { + if (async || this.url === undefined || this.url === '') { return this.send_buf; } @@ -225,6 +222,54 @@ Thrift.Transport.prototype = { this.rpos = 0; }, + jqRequest: function(client, postData, args, recv_method) { + if (typeof jQuery === 'undefined' || + typeof jQuery.Deferred === 'undefined') { + throw 'Thrift.js requires jQuery 1.5+ to use asynchronous requests'; + } + + // Deferreds + var deferred = jQuery.Deferred(); + var completeDfd = jQuery._Deferred(); + var dfd = deferred.promise(); + dfd.success = dfd.done; + dfd.error = dfd.fail; + dfd.complete = completeDfd.done; + + var jqXHR = jQuery.ajax({ + url: this.url, + data: postData, + type: 'POST', + cache: false, + dataType: 'text', + context: this, + success: this.jqResponse, + error: function(xhr, status, e) { + deferred.rejectWith(client, jQuery.merge([e], xhr.tArgs)); + }, + complete: function(xhr, status) { + completeDfd.resolveWith(client, [xhr, status]); + } + }); + + deferred.done(jQuery.makeArray(args).pop()); //pop callback from args + jqXHR.tArgs = args; + jqXHR.tClient = client; + jqXHR.tRecvFn = recv_method; + jqXHR.tDfd = deferred; + return dfd; + }, + + jqResponse: function(responseData, textStatus, jqXHR) { + this.setRecvBuffer(responseData); + try { + var value = jqXHR.tRecvFn.call(jqXHR.tClient); + jqXHR.tDfd.resolveWith(jqXHR, jQuery.merge([value], jqXHR.tArgs)); + } catch (ex) { + jqXHR.tDfd.rejectWith(jqXHR, jQuery.merge([ex], jqXHR.tArgs)); + } + }, + setRecvBuffer: function(buf) { this.recv_buf = buf; this.recv_buf_sz = this.recv_buf.length; @@ -531,7 +576,11 @@ Thrift.Protocol.prototype = { this.rstack = []; this.rpos = []; - this.robj = eval(this.transport.readAll()); + if (typeof jQuery !== 'undefined') { + this.robj = jQuery.parseJSON(this.transport.readAll()); + } else { + this.robj = eval(this.transport.readAll()); + } var r = {}; var version = this.robj.shift(); @@ -551,7 +600,6 @@ Thrift.Protocol.prototype = { return r; }, - readMessageEnd: function() { }, @@ -617,7 +665,6 @@ Thrift.Protocol.prototype = { r.ftype = ftype; r.fid = fid; - return r; }, @@ -632,7 +679,6 @@ Thrift.Protocol.prototype = { }, readMapBegin: function(keyType, valType, size) { - var map = this.rstack.pop(); var r = {}; @@ -652,14 +698,12 @@ Thrift.Protocol.prototype = { }, readListBegin: function(elemType, size) { - var list = this.rstack[this.rstack.length - 1]; var r = {}; r.etype = Thrift.Protocol.RType[list.shift()]; r.size = list.shift(); - this.rpos.push(this.rstack.length); this.rstack.push(list); @@ -698,7 +742,6 @@ Thrift.Protocol.prototype = { return this.readI32(); }, - readI32: function(f) { if (f === undefined) { f = this.rstack[this.rstack.length - 1]; @@ -753,5 +796,4 @@ Thrift.Protocol.prototype = { skip: function(type) { throw 'skip not supported yet'; } - };