mirror of https://github.com/grpc/grpc-web.git
Migrate to ES6 classes
This commit is contained in:
parent
8c96b8cee3
commit
670326124a
|
|
@ -7,53 +7,60 @@ goog.module.declareLegacyNamespace();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The collection of runtime options for a new RPC call.
|
* The collection of runtime options for a new RPC call.
|
||||||
* @param {!Object<string, !Object>=} options
|
* @unrestricted
|
||||||
* @constructor
|
|
||||||
*/
|
*/
|
||||||
const CallOptions = function(options) {
|
class CallOptions {
|
||||||
|
/**
|
||||||
|
* @param {!Object<string, !Object>=} options
|
||||||
|
*/
|
||||||
|
constructor(options) {
|
||||||
/**
|
/**
|
||||||
* @const {!Object<string, !Object>}
|
* @const {!Object<string, !Object>}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
this.properties_ = options || {};
|
this.properties_ = options || {};
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a new CallOption or override an existing one.
|
* Add a new CallOption or override an existing one.
|
||||||
*
|
*
|
||||||
* @param {string} name name of the CallOption that should be added/overridden.
|
* @param {string} name name of the CallOption that should be
|
||||||
|
* added/overridden.
|
||||||
* @param {VALUE} value value of the CallOption
|
* @param {VALUE} value value of the CallOption
|
||||||
* @template VALUE
|
* @template VALUE
|
||||||
*/
|
*/
|
||||||
CallOptions.prototype.setOption = function(name, value) {
|
setOption(name, value) {
|
||||||
this.properties_[name] = value;
|
this.properties_[name] = value;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of one CallOption.
|
* Get the value of one CallOption.
|
||||||
*
|
*
|
||||||
* @param {string} name name of the CallOption.
|
* @param {string} name name of the CallOption.
|
||||||
* @return {!Object} value of the CallOption. If name doesn't exist, will return
|
* @return {!Object} value of the CallOption. If name doesn't exist, will
|
||||||
* 'undefined'.
|
* return 'undefined'.
|
||||||
*/
|
*/
|
||||||
CallOptions.prototype.get = function(name) {
|
get(name) {
|
||||||
return this.properties_[name];
|
return this.properties_[name];
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a CallOption.
|
* Remove a CallOption.
|
||||||
*
|
*
|
||||||
* @param {string} name name of the CallOption that shoud be removed.
|
* @param {string} name name of the CallOption that shoud be removed.
|
||||||
*/
|
*/
|
||||||
CallOptions.prototype.removeOption = function(name) {
|
removeOption(name) {
|
||||||
delete this.properties_[name];
|
delete this.properties_[name];
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {!Array<string>}
|
* @return {!Array<string>}
|
||||||
*/
|
*/
|
||||||
CallOptions.prototype.getKeys = function() {
|
getKeys() {
|
||||||
return Object.keys(this.properties_);
|
return Object.keys(this.properties_);
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
exports = CallOptions;
|
exports = CallOptions;
|
||||||
|
|
|
||||||
|
|
@ -47,17 +47,19 @@ const {StreamInterceptor, UnaryInterceptor} = goog.require('grpc.web.Interceptor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for gRPC web client using the application/grpc-web wire format
|
* Base class for gRPC web client using the application/grpc-web wire format
|
||||||
* @param {?Object=} opt_options
|
|
||||||
* @constructor
|
|
||||||
* @implements {AbstractClientBase}
|
* @implements {AbstractClientBase}
|
||||||
|
* @unrestricted
|
||||||
*/
|
*/
|
||||||
const GrpcWebClientBase = function(opt_options) {
|
class GrpcWebClientBase {
|
||||||
|
/**
|
||||||
|
* @param {?Object=} opt_options
|
||||||
|
*/
|
||||||
|
constructor(opt_options) {
|
||||||
/**
|
/**
|
||||||
* @const
|
* @const
|
||||||
* @private {string}
|
* @private {string}
|
||||||
*/
|
*/
|
||||||
this.format_ =
|
this.format_ = goog.getObjectByName('format', opt_options) || 'text';
|
||||||
goog.getObjectByName('format', opt_options) || "text";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @const
|
* @const
|
||||||
|
|
@ -87,15 +89,13 @@ const GrpcWebClientBase = function(opt_options) {
|
||||||
*/
|
*/
|
||||||
this.unaryInterceptors_ =
|
this.unaryInterceptors_ =
|
||||||
goog.getObjectByName('unaryInterceptors', opt_options) || [];
|
goog.getObjectByName('unaryInterceptors', opt_options) || [];
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @override
|
* @override
|
||||||
* @export
|
* @export
|
||||||
*/
|
*/
|
||||||
GrpcWebClientBase.prototype.rpcCall = function(
|
rpcCall(method, requestMessage, metadata, methodDescriptor, callback) {
|
||||||
method, requestMessage, metadata, methodDescriptor, callback) {
|
|
||||||
methodDescriptor = AbstractClientBase.ensureMethodDescriptor(
|
methodDescriptor = AbstractClientBase.ensureMethodDescriptor(
|
||||||
method, requestMessage, MethodType.UNARY, methodDescriptor);
|
method, requestMessage, MethodType.UNARY, methodDescriptor);
|
||||||
var hostname = AbstractClientBase.getHostname(method, methodDescriptor);
|
var hostname = AbstractClientBase.getHostname(method, methodDescriptor);
|
||||||
|
|
@ -106,15 +106,13 @@ GrpcWebClientBase.prototype.rpcCall = function(
|
||||||
this, methodDescriptor.createRequest(requestMessage, metadata)));
|
this, methodDescriptor.createRequest(requestMessage, metadata)));
|
||||||
GrpcWebClientBase.setCallback_(stream, callback, false);
|
GrpcWebClientBase.setCallback_(stream, callback, false);
|
||||||
return stream;
|
return stream;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @override
|
* @override
|
||||||
* @export
|
* @export
|
||||||
*/
|
*/
|
||||||
GrpcWebClientBase.prototype.thenableCall = function(
|
thenableCall(method, requestMessage, metadata, methodDescriptor) {
|
||||||
method, requestMessage, metadata, methodDescriptor) {
|
|
||||||
methodDescriptor = AbstractClientBase.ensureMethodDescriptor(
|
methodDescriptor = AbstractClientBase.ensureMethodDescriptor(
|
||||||
method, requestMessage, MethodType.UNARY, methodDescriptor);
|
method, requestMessage, MethodType.UNARY, methodDescriptor);
|
||||||
var hostname = AbstractClientBase.getHostname(method, methodDescriptor);
|
var hostname = AbstractClientBase.getHostname(method, methodDescriptor);
|
||||||
|
|
@ -143,7 +141,7 @@ GrpcWebClientBase.prototype.thenableCall = function(
|
||||||
var unaryResponse = /** @type {!Promise<?>} */ (invoker.call(
|
var unaryResponse = /** @type {!Promise<?>} */ (invoker.call(
|
||||||
this, methodDescriptor.createRequest(requestMessage, metadata)));
|
this, methodDescriptor.createRequest(requestMessage, metadata)));
|
||||||
return unaryResponse.then((response) => response.getResponseMessage());
|
return unaryResponse.then((response) => response.getResponseMessage());
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @export
|
* @export
|
||||||
|
|
@ -156,19 +154,16 @@ GrpcWebClientBase.prototype.thenableCall = function(
|
||||||
* @return {!Promise<RESPONSE>}
|
* @return {!Promise<RESPONSE>}
|
||||||
* @template REQUEST, RESPONSE
|
* @template REQUEST, RESPONSE
|
||||||
*/
|
*/
|
||||||
GrpcWebClientBase.prototype.unaryCall = function(
|
unaryCall(method, requestMessage, metadata, methodDescriptor) {
|
||||||
method, requestMessage, metadata, methodDescriptor) {
|
|
||||||
return /** @type {!Promise<RESPONSE>}*/ (
|
return /** @type {!Promise<RESPONSE>}*/ (
|
||||||
this.thenableCall(method, requestMessage, metadata, methodDescriptor));
|
this.thenableCall(method, requestMessage, metadata, methodDescriptor));
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @override
|
* @override
|
||||||
* @export
|
* @export
|
||||||
*/
|
*/
|
||||||
GrpcWebClientBase.prototype.serverStreaming = function(
|
serverStreaming(method, requestMessage, metadata, methodDescriptor) {
|
||||||
method, requestMessage, metadata, methodDescriptor) {
|
|
||||||
methodDescriptor = AbstractClientBase.ensureMethodDescriptor(
|
methodDescriptor = AbstractClientBase.ensureMethodDescriptor(
|
||||||
method, requestMessage, MethodType.SERVER_STREAMING, methodDescriptor);
|
method, requestMessage, MethodType.SERVER_STREAMING, methodDescriptor);
|
||||||
var hostname = AbstractClientBase.getHostname(method, methodDescriptor);
|
var hostname = AbstractClientBase.getHostname(method, methodDescriptor);
|
||||||
|
|
@ -177,8 +172,7 @@ GrpcWebClientBase.prototype.serverStreaming = function(
|
||||||
this.streamInterceptors_);
|
this.streamInterceptors_);
|
||||||
return /** @type {!ClientReadableStream<?>} */ (invoker.call(
|
return /** @type {!ClientReadableStream<?>} */ (invoker.call(
|
||||||
this, methodDescriptor.createRequest(requestMessage, metadata)));
|
this, methodDescriptor.createRequest(requestMessage, metadata)));
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
|
|
@ -187,7 +181,7 @@ GrpcWebClientBase.prototype.serverStreaming = function(
|
||||||
* @param {string} hostname
|
* @param {string} hostname
|
||||||
* @return {!ClientReadableStream<RESPONSE>}
|
* @return {!ClientReadableStream<RESPONSE>}
|
||||||
*/
|
*/
|
||||||
GrpcWebClientBase.prototype.startStream_ = function(request, hostname) {
|
startStream_(request, hostname) {
|
||||||
var methodDescriptor = request.getMethodDescriptor();
|
var methodDescriptor = request.getMethodDescriptor();
|
||||||
var path = hostname + methodDescriptor.name;
|
var path = hostname + methodDescriptor.name;
|
||||||
|
|
||||||
|
|
@ -218,8 +212,7 @@ GrpcWebClientBase.prototype.startStream_ = function(request, hostname) {
|
||||||
}
|
}
|
||||||
xhr.send(path, 'POST', payload);
|
xhr.send(path, 'POST', payload);
|
||||||
return stream;
|
return stream;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
|
|
@ -230,7 +223,7 @@ GrpcWebClientBase.prototype.startStream_ = function(request, hostname) {
|
||||||
* function(?Error,?RESPONSE)} callback
|
* function(?Error,?RESPONSE)} callback
|
||||||
* @param {boolean} useUnaryResponse
|
* @param {boolean} useUnaryResponse
|
||||||
*/
|
*/
|
||||||
GrpcWebClientBase.setCallback_ = function(stream, callback, useUnaryResponse) {
|
static setCallback_(stream, callback, useUnaryResponse) {
|
||||||
var responseReceived = null;
|
var responseReceived = null;
|
||||||
var errorEmitted = false;
|
var errorEmitted = false;
|
||||||
|
|
||||||
|
|
@ -274,7 +267,7 @@ GrpcWebClientBase.setCallback_ = function(stream, callback, useUnaryResponse) {
|
||||||
callback(null, null); // trigger unaryResponse
|
callback(null, null); // trigger unaryResponse
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new XhrIo object
|
* Create a new XhrIo object
|
||||||
|
|
@ -282,9 +275,9 @@ GrpcWebClientBase.setCallback_ = function(stream, callback, useUnaryResponse) {
|
||||||
* @private
|
* @private
|
||||||
* @return {!XhrIo} The created XhrIo object
|
* @return {!XhrIo} The created XhrIo object
|
||||||
*/
|
*/
|
||||||
GrpcWebClientBase.prototype.newXhr_ = function() {
|
newXhr_() {
|
||||||
return new XhrIo();
|
return new XhrIo();
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encode the grpc-web request
|
* Encode the grpc-web request
|
||||||
|
|
@ -293,7 +286,7 @@ GrpcWebClientBase.prototype.newXhr_ = function() {
|
||||||
* @param {!Uint8Array} serialized The serialized proto payload
|
* @param {!Uint8Array} serialized The serialized proto payload
|
||||||
* @return {!Uint8Array} The application/grpc-web padded request
|
* @return {!Uint8Array} The application/grpc-web padded request
|
||||||
*/
|
*/
|
||||||
GrpcWebClientBase.prototype.encodeRequest_ = function(serialized) {
|
encodeRequest_(serialized) {
|
||||||
var len = serialized.length;
|
var len = serialized.length;
|
||||||
var bytesArray = [0, 0, 0, 0];
|
var bytesArray = [0, 0, 0, 0];
|
||||||
var payload = new Uint8Array(5 + len);
|
var payload = new Uint8Array(5 + len);
|
||||||
|
|
@ -304,14 +297,14 @@ GrpcWebClientBase.prototype.encodeRequest_ = function(serialized) {
|
||||||
payload.set(new Uint8Array(bytesArray), 1);
|
payload.set(new Uint8Array(bytesArray), 1);
|
||||||
payload.set(serialized, 5);
|
payload.set(serialized, 5);
|
||||||
return payload;
|
return payload;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {!XhrIo} xhr The xhr object
|
* @param {!XhrIo} xhr The xhr object
|
||||||
*/
|
*/
|
||||||
GrpcWebClientBase.prototype.processHeaders_ = function(xhr) {
|
processHeaders_(xhr) {
|
||||||
if (this.format_ == "text") {
|
if (this.format_ == 'text') {
|
||||||
xhr.headers.set('Content-Type', 'application/grpc-web-text');
|
xhr.headers.set('Content-Type', 'application/grpc-web-text');
|
||||||
xhr.headers.set('Accept', 'application/grpc-web-text');
|
xhr.headers.set('Accept', 'application/grpc-web-text');
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -332,7 +325,7 @@ GrpcWebClientBase.prototype.processHeaders_ = function(xhr) {
|
||||||
xhr.headers.set('grpc-timeout', timeout + 'm');
|
xhr.headers.set('grpc-timeout', timeout + 'm');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
|
|
@ -341,10 +334,10 @@ GrpcWebClientBase.prototype.processHeaders_ = function(xhr) {
|
||||||
* @param {!Object<string,string>} headerObject The xhr headers
|
* @param {!Object<string,string>} headerObject The xhr headers
|
||||||
* @return {string} The URI object or a string path with headers
|
* @return {string} The URI object or a string path with headers
|
||||||
*/
|
*/
|
||||||
GrpcWebClientBase.setCorsOverride_ = function(method, headerObject) {
|
static setCorsOverride_(method, headerObject) {
|
||||||
return /** @type {string} */ (HttpCors.setHttpHeadersWithOverwriteParam(
|
return /** @type {string} */ (HttpCors.setHttpHeadersWithOverwriteParam(
|
||||||
method, HttpCors.HTTP_HEADERS_PARAM_NAME, headerObject));
|
method, HttpCors.HTTP_HEADERS_PARAM_NAME, headerObject));
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
|
|
@ -357,12 +350,16 @@ GrpcWebClientBase.setCorsOverride_ = function(method, headerObject) {
|
||||||
* @return {function(!Request<REQUEST,RESPONSE>):
|
* @return {function(!Request<REQUEST,RESPONSE>):
|
||||||
* (!Promise<RESPONSE>|!ClientReadableStream<RESPONSE>)}
|
* (!Promise<RESPONSE>|!ClientReadableStream<RESPONSE>)}
|
||||||
*/
|
*/
|
||||||
GrpcWebClientBase.runInterceptors_ = function(invoker, interceptors) {
|
static runInterceptors_(invoker, interceptors) {
|
||||||
let curInvoker = invoker;
|
let curInvoker = invoker;
|
||||||
interceptors.forEach((interceptor) => {
|
interceptors.forEach((interceptor) => {
|
||||||
const lastInvoker = curInvoker;
|
const lastInvoker = curInvoker;
|
||||||
curInvoker = (request) => interceptor.intercept(request, lastInvoker);
|
curInvoker = (request) => interceptor.intercept(request, lastInvoker);
|
||||||
});
|
});
|
||||||
return curInvoker;
|
return curInvoker;
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
exports = GrpcWebClientBase;
|
exports = GrpcWebClientBase;
|
||||||
|
|
|
||||||
|
|
@ -29,16 +29,16 @@ const {StreamInterceptor} = goog.require('grpc.web.Interceptor');
|
||||||
goog.require('goog.testing.jsunit');
|
goog.require('goog.testing.jsunit');
|
||||||
|
|
||||||
var REQUEST_BYTES = [1, 2, 3];
|
var REQUEST_BYTES = [1, 2, 3];
|
||||||
var FAKE_METHOD = "fake-method";
|
var FAKE_METHOD = 'fake-method';
|
||||||
var PROTO_FIELD_VALUE = "meow";
|
var PROTO_FIELD_VALUE = 'meow';
|
||||||
var EXPECTED_HEADERS;
|
var EXPECTED_HEADERS;
|
||||||
var EXPECTED_HEADER_VALUES;
|
var EXPECTED_HEADER_VALUES;
|
||||||
var EXPECTED_UNARY_HEADERS = ['Content-Type', 'Accept',
|
var EXPECTED_UNARY_HEADERS =
|
||||||
'X-User-Agent', 'X-Grpc-Web'];
|
['Content-Type', 'Accept', 'X-User-Agent', 'X-Grpc-Web'];
|
||||||
var EXPECTED_UNARY_HEADER_VALUES = ['application/grpc-web-text',
|
var EXPECTED_UNARY_HEADER_VALUES = [
|
||||||
'application/grpc-web-text',
|
'application/grpc-web-text', 'application/grpc-web-text',
|
||||||
'grpc-web-javascript/0.1',
|
'grpc-web-javascript/0.1', '1'
|
||||||
'1'];
|
];
|
||||||
var dataCallback;
|
var dataCallback;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -62,22 +62,23 @@ testSuite({
|
||||||
client.newXhr_ = function() {
|
client.newXhr_ = function() {
|
||||||
return new MockXhr({
|
return new MockXhr({
|
||||||
// This parses to [ { DATA: [4,5,6] }, { TRAILER: "a: b" } ]
|
// This parses to [ { DATA: [4,5,6] }, { TRAILER: "a: b" } ]
|
||||||
response: googCrypt.encodeByteArray(new Uint8Array([
|
response: googCrypt.encodeByteArray(new Uint8Array(
|
||||||
0, 0, 0, 0, 3, 4, 5, 6, 128, 0, 0, 0, 4, 97, 58, 32, 98
|
[0, 0, 0, 0, 3, 4, 5, 6, 128, 0, 0, 0, 4, 97, 58, 32, 98])),
|
||||||
])),
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
expectUnaryHeaders();
|
expectUnaryHeaders();
|
||||||
client.rpcCall(FAKE_METHOD, {}, {}, {
|
client.rpcCall(
|
||||||
|
FAKE_METHOD, {}, {}, {
|
||||||
requestSerializeFn: function(request) {
|
requestSerializeFn: function(request) {
|
||||||
return REQUEST_BYTES;
|
return REQUEST_BYTES;
|
||||||
},
|
},
|
||||||
responseDeserializeFn: function(bytes) {
|
responseDeserializeFn: function(bytes) {
|
||||||
assertElementsEquals([4, 5, 6], [].slice.call(bytes));
|
assertElementsEquals([4, 5, 6], [].slice.call(bytes));
|
||||||
return {"field1": PROTO_FIELD_VALUE};
|
return {'field1': PROTO_FIELD_VALUE};
|
||||||
}
|
}
|
||||||
}, function(error, response) {
|
},
|
||||||
|
function(error, response) {
|
||||||
assertNull(error);
|
assertNull(error);
|
||||||
assertEquals(PROTO_FIELD_VALUE, response['field1']);
|
assertEquals(PROTO_FIELD_VALUE, response['field1']);
|
||||||
});
|
});
|
||||||
|
|
@ -119,20 +120,23 @@ testSuite({
|
||||||
return new MockXhr({
|
return new MockXhr({
|
||||||
// This decodes to "grpc-status: 3"
|
// This decodes to "grpc-status: 3"
|
||||||
response: googCrypt.encodeByteArray(new Uint8Array([
|
response: googCrypt.encodeByteArray(new Uint8Array([
|
||||||
128, 0, 0, 0, 14, 103, 114, 112, 99, 45, 115, 116, 97, 116, 117, 115, 58, 32, 51
|
128, 0, 0, 0, 14, 103, 114, 112, 99, 45, 115, 116, 97, 116, 117, 115,
|
||||||
|
58, 32, 51
|
||||||
])),
|
])),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
expectUnaryHeaders();
|
expectUnaryHeaders();
|
||||||
client.rpcCall(FAKE_METHOD, {}, {}, {
|
client.rpcCall(
|
||||||
|
FAKE_METHOD, {}, {}, {
|
||||||
requestSerializeFn: function(request) {
|
requestSerializeFn: function(request) {
|
||||||
return REQUEST_BYTES;
|
return REQUEST_BYTES;
|
||||||
},
|
},
|
||||||
responseDeserializeFn: function(bytes) {
|
responseDeserializeFn: function(bytes) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}, function(error, response) {
|
},
|
||||||
|
function(error, response) {
|
||||||
assertNull(response);
|
assertNull(response);
|
||||||
assertEquals(3, error.code);
|
assertEquals(3, error.code);
|
||||||
});
|
});
|
||||||
|
|
@ -144,28 +148,29 @@ testSuite({
|
||||||
client.newXhr_ = function() {
|
client.newXhr_ = function() {
|
||||||
return new MockXhr({
|
return new MockXhr({
|
||||||
// This parses to [ { DATA: [4,5,6] }, { TRAILER: "a: b" } ]
|
// This parses to [ { DATA: [4,5,6] }, { TRAILER: "a: b" } ]
|
||||||
response: googCrypt.encodeByteArray(new Uint8Array([
|
response: googCrypt.encodeByteArray(new Uint8Array(
|
||||||
0, 0, 0, 0, 3, 4, 5, 6, 128, 0, 0, 0, 4, 97, 58, 32, 98
|
[0, 0, 0, 0, 3, 4, 5, 6, 128, 0, 0, 0, 4, 97, 58, 32, 98])),
|
||||||
])),
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
expectUnaryHeaders();
|
expectUnaryHeaders();
|
||||||
var call = client.rpcCall(FAKE_METHOD, {}, {}, {
|
var call = client.rpcCall(
|
||||||
|
FAKE_METHOD, {}, {}, {
|
||||||
requestSerializeFn: function(request) {
|
requestSerializeFn: function(request) {
|
||||||
return REQUEST_BYTES;
|
return REQUEST_BYTES;
|
||||||
},
|
},
|
||||||
responseDeserializeFn: function(bytes) {
|
responseDeserializeFn: function(bytes) {
|
||||||
assertElementsEquals([4, 5, 6], [].slice.call(bytes));
|
assertElementsEquals([4, 5, 6], [].slice.call(bytes));
|
||||||
return {"field1": PROTO_FIELD_VALUE};
|
return {'field1': PROTO_FIELD_VALUE};
|
||||||
}
|
}
|
||||||
}, function(error, response) {
|
},
|
||||||
|
function(error, response) {
|
||||||
assertNull(error);
|
assertNull(error);
|
||||||
assertEquals(PROTO_FIELD_VALUE, response['field1']);
|
assertEquals(PROTO_FIELD_VALUE, response['field1']);
|
||||||
});
|
});
|
||||||
call.on('metadata', (metadata) => {
|
call.on('metadata', (metadata) => {
|
||||||
assertEquals(metadata['sample-initial-metadata-1'],
|
assertEquals(
|
||||||
'sample-initial-metadata-val');
|
metadata['sample-initial-metadata-1'], 'sample-initial-metadata-val');
|
||||||
});
|
});
|
||||||
dataCallback();
|
dataCallback();
|
||||||
}
|
}
|
||||||
|
|
@ -180,104 +185,102 @@ function expectUnaryHeaders() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** @unrestricted */
|
||||||
|
class MockXhr {
|
||||||
/**
|
/**
|
||||||
* @constructor
|
|
||||||
* @param {?Object} mockValues
|
* @param {?Object} mockValues
|
||||||
* Mock XhrIO object to test the outgoing values
|
* Mock XhrIO object to test the outgoing values
|
||||||
*/
|
*/
|
||||||
function MockXhr(mockValues) {
|
constructor(mockValues) {
|
||||||
this.mockValues = mockValues;
|
this.mockValues = mockValues;
|
||||||
this.headers = new Map();
|
this.headers = new Map();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} url
|
* @param {string} url
|
||||||
* @param {string=} opt_method
|
* @param {string=} opt_method
|
||||||
* @param {string=} opt_content
|
* @param {string=} opt_content
|
||||||
* @param {string=} opt_headers
|
* @param {string=} opt_headers
|
||||||
*/
|
*/
|
||||||
MockXhr.prototype.send = function(url, opt_method, opt_content, opt_headers) {
|
send(url, opt_method, opt_content, opt_headers) {
|
||||||
assertEquals(FAKE_METHOD, url);
|
assertEquals(FAKE_METHOD, url);
|
||||||
assertEquals("POST", opt_method);
|
assertEquals('POST', opt_method);
|
||||||
assertElementsEquals(googCrypt.encodeByteArray(new Uint8Array([0, 0, 0, 0, 3, 1, 2, 3])), opt_content);
|
assertElementsEquals(
|
||||||
|
googCrypt.encodeByteArray(new Uint8Array([0, 0, 0, 0, 3, 1, 2, 3])),
|
||||||
|
opt_content);
|
||||||
assertElementsEquals(EXPECTED_HEADERS, this.headers.getKeys());
|
assertElementsEquals(EXPECTED_HEADERS, this.headers.getKeys());
|
||||||
assertElementsEquals(EXPECTED_HEADER_VALUES, this.headers.getValues());
|
assertElementsEquals(EXPECTED_HEADER_VALUES, this.headers.getValues());
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {boolean} withCredentials
|
* @param {boolean} withCredentials
|
||||||
*/
|
*/
|
||||||
MockXhr.prototype.setWithCredentials = function(withCredentials) {
|
setWithCredentials(withCredentials) {
|
||||||
return;
|
return;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {string} response
|
* @return {string} response
|
||||||
*/
|
*/
|
||||||
MockXhr.prototype.getResponseText = function() {
|
getResponseText() {
|
||||||
return this.mockValues.response;
|
return this.mockValues.response;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} key header key
|
* @param {string} key header key
|
||||||
* @return {string} content-type
|
* @return {string} content-type
|
||||||
*/
|
*/
|
||||||
MockXhr.prototype.getStreamingResponseHeader = function(key) {
|
getStreamingResponseHeader(key) {
|
||||||
return 'application/grpc-web-text';
|
return 'application/grpc-web-text';
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {string} response
|
* @return {string} response
|
||||||
*/
|
*/
|
||||||
MockXhr.prototype.getResponseHeaders = function() {
|
getResponseHeaders() {
|
||||||
return {'sample-initial-metadata-1': 'sample-initial-metadata-val'};
|
return {'sample-initial-metadata-1': 'sample-initial-metadata-val'};
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {number} xhr state
|
* @return {number} xhr state
|
||||||
*/
|
*/
|
||||||
MockXhr.prototype.getReadyState = function() {
|
getReadyState() {
|
||||||
return 0;
|
return 0;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {number} lastErrorCode
|
* @return {number} lastErrorCode
|
||||||
*/
|
*/
|
||||||
MockXhr.prototype.getLastErrorCode = function() {
|
getLastErrorCode() {
|
||||||
return 0;
|
return 0;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {string} lastError
|
* @return {string} lastError
|
||||||
*/
|
*/
|
||||||
MockXhr.prototype.getLastError = function() {
|
getLastError() {
|
||||||
return 'server not responding';
|
return 'server not responding';
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} responseType
|
* @param {string} responseType
|
||||||
*/
|
*/
|
||||||
MockXhr.prototype.setResponseType = function(responseType) {
|
setResponseType(responseType) {
|
||||||
return;
|
return;
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @constructor
|
|
||||||
* @implements {StreamInterceptor}
|
* @implements {StreamInterceptor}
|
||||||
|
* @unrestricted
|
||||||
*/
|
*/
|
||||||
const StreamResponseInterceptor = function() {};
|
class StreamResponseInterceptor {
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
StreamResponseInterceptor.prototype.intercept = function(request, invoker) {
|
intercept(request, invoker) {
|
||||||
/**
|
/**
|
||||||
* @implements {ClientReadableStream}
|
* @implements {ClientReadableStream}
|
||||||
* @constructor
|
* @constructor
|
||||||
|
|
@ -309,4 +312,5 @@ StreamResponseInterceptor.prototype.intercept = function(request, invoker) {
|
||||||
};
|
};
|
||||||
|
|
||||||
return new InterceptedStream(invoker(request));
|
return new InterceptedStream(invoker(request));
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,28 +45,27 @@ const {Status} = goog.require('grpc.web.Status');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const GRPC_STATUS = "grpc-status";
|
const GRPC_STATUS = 'grpc-status';
|
||||||
const GRPC_STATUS_MESSAGE = "grpc-message";
|
const GRPC_STATUS_MESSAGE = 'grpc-message';
|
||||||
|
|
||||||
/** @type {!Array<string>} */
|
/** @type {!Array<string>} */
|
||||||
const EXCLUDED_RESPONSE_HEADERS = [
|
const EXCLUDED_RESPONSE_HEADERS =
|
||||||
'content-type',
|
['content-type', GRPC_STATUS, GRPC_STATUS_MESSAGE];
|
||||||
GRPC_STATUS,
|
|
||||||
GRPC_STATUS_MESSAGE
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A stream that the client can read from. Used for calls that are streaming
|
* A stream that the client can read from. Used for calls that are streaming
|
||||||
* from the server side.
|
* from the server side.
|
||||||
*
|
|
||||||
* @template RESPONSE
|
* @template RESPONSE
|
||||||
* @constructor
|
|
||||||
* @implements {ClientReadableStream}
|
* @implements {ClientReadableStream}
|
||||||
* @final
|
* @final
|
||||||
|
* @unrestricted
|
||||||
|
*/
|
||||||
|
class GrpcWebClientReadableStream {
|
||||||
|
/**
|
||||||
* @param {!GenericTransportInterface} genericTransportInterface The
|
* @param {!GenericTransportInterface} genericTransportInterface The
|
||||||
* GenericTransportInterface
|
* GenericTransportInterface
|
||||||
*/
|
*/
|
||||||
const GrpcWebClientReadableStream = function(genericTransportInterface) {
|
constructor(genericTransportInterface) {
|
||||||
/**
|
/**
|
||||||
* @const
|
* @const
|
||||||
* @private
|
* @private
|
||||||
|
|
@ -135,8 +134,7 @@ const GrpcWebClientReadableStream = function(genericTransportInterface) {
|
||||||
this.parser_ = new GrpcWebStreamParser();
|
this.parser_ = new GrpcWebStreamParser();
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
events.listen(this.xhr_, EventType.READY_STATE_CHANGE,
|
events.listen(this.xhr_, EventType.READY_STATE_CHANGE, function(e) {
|
||||||
function(e) {
|
|
||||||
var contentType = self.xhr_.getStreamingResponseHeader('Content-Type');
|
var contentType = self.xhr_.getStreamingResponseHeader('Content-Type');
|
||||||
if (!contentType) return;
|
if (!contentType) return;
|
||||||
contentType = contentType.toLowerCase();
|
contentType = contentType.toLowerCase();
|
||||||
|
|
@ -172,8 +170,8 @@ const GrpcWebClientReadableStream = function(genericTransportInterface) {
|
||||||
var trailerString = '';
|
var trailerString = '';
|
||||||
for (var pos = 0; pos < messages[i][FrameType.TRAILER].length;
|
for (var pos = 0; pos < messages[i][FrameType.TRAILER].length;
|
||||||
pos++) {
|
pos++) {
|
||||||
trailerString += String.fromCharCode(
|
trailerString +=
|
||||||
messages[i][FrameType.TRAILER][pos]);
|
String.fromCharCode(messages[i][FrameType.TRAILER][pos]);
|
||||||
}
|
}
|
||||||
var trailers = self.parseHttp1Headers_(trailerString);
|
var trailers = self.parseHttp1Headers_(trailerString);
|
||||||
var grpcStatusCode = StatusCode.OK;
|
var grpcStatusCode = StatusCode.OK;
|
||||||
|
|
@ -265,15 +263,13 @@ const GrpcWebClientReadableStream = function(genericTransportInterface) {
|
||||||
self.sendEndCallbacks_();
|
self.sendEndCallbacks_();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @override
|
* @override
|
||||||
* @export
|
* @export
|
||||||
*/
|
*/
|
||||||
GrpcWebClientReadableStream.prototype.on = function(
|
on(eventType, callback) {
|
||||||
eventType, callback) {
|
|
||||||
// TODO(stanleycheung): change eventType to @enum type
|
// TODO(stanleycheung): change eventType to @enum type
|
||||||
if (eventType == 'data') {
|
if (eventType == 'data') {
|
||||||
this.onDataCallbacks_.push(callback);
|
this.onDataCallbacks_.push(callback);
|
||||||
|
|
@ -287,29 +283,25 @@ GrpcWebClientReadableStream.prototype.on = function(
|
||||||
this.onErrorCallbacks_.push(callback);
|
this.onErrorCallbacks_.push(callback);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {!Array<function(?)>} callbacks the internal list of callbacks
|
* @param {!Array<function(?)>} callbacks the internal list of callbacks
|
||||||
* @param {function(?)} callback the callback to remove
|
* @param {function(?)} callback the callback to remove
|
||||||
*/
|
*/
|
||||||
GrpcWebClientReadableStream.prototype.removeListenerFromCallbacks_ = function(
|
removeListenerFromCallbacks_(callbacks, callback) {
|
||||||
callbacks, callback) {
|
|
||||||
const index = callbacks.indexOf(callback);
|
const index = callbacks.indexOf(callback);
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
callbacks.splice(index, 1);
|
callbacks.splice(index, 1);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @export
|
* @export
|
||||||
* @override
|
* @override
|
||||||
*/
|
*/
|
||||||
GrpcWebClientReadableStream.prototype.removeListener = function(
|
removeListener(eventType, callback) {
|
||||||
eventType, callback) {
|
|
||||||
if (eventType == 'data') {
|
if (eventType == 'data') {
|
||||||
this.removeListenerFromCallbacks_(this.onDataCallbacks_, callback);
|
this.removeListenerFromCallbacks_(this.onDataCallbacks_, callback);
|
||||||
} else if (eventType == 'status') {
|
} else if (eventType == 'status') {
|
||||||
|
|
@ -322,8 +314,7 @@ GrpcWebClientReadableStream.prototype.removeListener = function(
|
||||||
this.removeListenerFromCallbacks_(this.onErrorCallbacks_, callback);
|
this.removeListenerFromCallbacks_(this.onErrorCallbacks_, callback);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a callbackl to parse the response
|
* Register a callbackl to parse the response
|
||||||
|
|
@ -331,21 +322,18 @@ GrpcWebClientReadableStream.prototype.removeListener = function(
|
||||||
* @param {function(?):!RESPONSE} responseDeserializeFn The deserialize
|
* @param {function(?):!RESPONSE} responseDeserializeFn The deserialize
|
||||||
* function for the proto
|
* function for the proto
|
||||||
*/
|
*/
|
||||||
GrpcWebClientReadableStream.prototype.setResponseDeserializeFn =
|
setResponseDeserializeFn(responseDeserializeFn) {
|
||||||
function(responseDeserializeFn) {
|
|
||||||
this.responseDeserializeFn_ = responseDeserializeFn;
|
this.responseDeserializeFn_ = responseDeserializeFn;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @override
|
* @override
|
||||||
* @export
|
* @export
|
||||||
*/
|
*/
|
||||||
GrpcWebClientReadableStream.prototype.cancel = function() {
|
cancel() {
|
||||||
this.aborted_ = true;
|
this.aborted_ = true;
|
||||||
this.xhr_.abort();
|
this.xhr_.abort();
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse HTTP headers
|
* Parse HTTP headers
|
||||||
|
|
@ -354,72 +342,67 @@ GrpcWebClientReadableStream.prototype.cancel = function() {
|
||||||
* @param {string} str The raw http header string
|
* @param {string} str The raw http header string
|
||||||
* @return {!Object} The header:value pairs
|
* @return {!Object} The header:value pairs
|
||||||
*/
|
*/
|
||||||
GrpcWebClientReadableStream.prototype.parseHttp1Headers_ =
|
parseHttp1Headers_(str) {
|
||||||
function(str) {
|
var chunks = str.trim().split('\r\n');
|
||||||
var chunks = str.trim().split("\r\n");
|
|
||||||
var headers = {};
|
var headers = {};
|
||||||
for (var i = 0; i < chunks.length; i++) {
|
for (var i = 0; i < chunks.length; i++) {
|
||||||
var pos = chunks[i].indexOf(":");
|
var pos = chunks[i].indexOf(':');
|
||||||
headers[chunks[i].substring(0, pos).trim()] =
|
headers[chunks[i].substring(0, pos).trim()] =
|
||||||
chunks[i].substring(pos + 1).trim();
|
chunks[i].substring(pos + 1).trim();
|
||||||
}
|
}
|
||||||
return headers;
|
return headers;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {!RESPONSE} data The data to send back
|
* @param {!RESPONSE} data The data to send back
|
||||||
*/
|
*/
|
||||||
GrpcWebClientReadableStream.prototype.sendDataCallbacks_ = function(data) {
|
sendDataCallbacks_(data) {
|
||||||
for (var i = 0; i < this.onDataCallbacks_.length; i++) {
|
for (var i = 0; i < this.onDataCallbacks_.length; i++) {
|
||||||
this.onDataCallbacks_[i](data);
|
this.onDataCallbacks_[i](data);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {!Status} status The status to send back
|
* @param {!Status} status The status to send back
|
||||||
*/
|
*/
|
||||||
GrpcWebClientReadableStream.prototype.sendStatusCallbacks_ = function(status) {
|
sendStatusCallbacks_(status) {
|
||||||
for (var i = 0; i < this.onStatusCallbacks_.length; i++) {
|
for (var i = 0; i < this.onStatusCallbacks_.length; i++) {
|
||||||
this.onStatusCallbacks_[i](status);
|
this.onStatusCallbacks_[i](status);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {!Metadata} metadata The metadata to send back
|
* @param {!Metadata} metadata The metadata to send back
|
||||||
*/
|
*/
|
||||||
GrpcWebClientReadableStream.prototype.sendMetadataCallbacks_ =
|
sendMetadataCallbacks_(metadata) {
|
||||||
function(metadata) {
|
|
||||||
for (var i = 0; i < this.onMetadataCallbacks_.length; i++) {
|
for (var i = 0; i < this.onMetadataCallbacks_.length; i++) {
|
||||||
this.onMetadataCallbacks_[i](metadata);
|
this.onMetadataCallbacks_[i](metadata);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {?} error The error to send back
|
* @param {?} error The error to send back
|
||||||
*/
|
*/
|
||||||
GrpcWebClientReadableStream.prototype.sendErrorCallbacks_ = function(error) {
|
sendErrorCallbacks_(error) {
|
||||||
for (var i = 0; i < this.onErrorCallbacks_.length; i++) {
|
for (var i = 0; i < this.onErrorCallbacks_.length; i++) {
|
||||||
this.onErrorCallbacks_[i](error);
|
this.onErrorCallbacks_[i](error);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
GrpcWebClientReadableStream.prototype.sendEndCallbacks_ = function() {
|
sendEndCallbacks_() {
|
||||||
for (var i = 0; i < this.onEndCallbacks_.length; i++) {
|
for (var i = 0; i < this.onEndCallbacks_.length; i++) {
|
||||||
this.onEndCallbacks_[i]();
|
this.onEndCallbacks_[i]();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
exports = GrpcWebClientReadableStream;
|
exports = GrpcWebClientReadableStream;
|
||||||
|
|
|
||||||
|
|
@ -49,13 +49,11 @@ const asserts = goog.require('goog.asserts');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default grpc-web stream parser.
|
* The default grpc-web stream parser.
|
||||||
*
|
|
||||||
* @constructor
|
|
||||||
* @struct
|
|
||||||
* @implements {StreamParser}
|
* @implements {StreamParser}
|
||||||
* @final
|
* @final
|
||||||
*/
|
*/
|
||||||
const GrpcWebStreamParser = function() {
|
class GrpcWebStreamParser {
|
||||||
|
constructor() {
|
||||||
/**
|
/**
|
||||||
* The current error message, if any.
|
* The current error message, if any.
|
||||||
* @private {?string}
|
* @private {?string}
|
||||||
|
|
@ -99,8 +97,8 @@ const GrpcWebStreamParser = function() {
|
||||||
this.countLengthBytes_ = 0;
|
this.countLengthBytes_ = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Raw bytes of the current message. Uses Uint8Array by default. Falls back to
|
* Raw bytes of the current message. Uses Uint8Array by default. Falls back
|
||||||
* native array when Uint8Array is unsupported.
|
* to native array when Uint8Array is unsupported.
|
||||||
* @private {?Uint8Array|?Array<number>}
|
* @private {?Uint8Array|?Array<number>}
|
||||||
*/
|
*/
|
||||||
this.messageBuffer_ = null;
|
this.messageBuffer_ = null;
|
||||||
|
|
@ -110,83 +108,38 @@ const GrpcWebStreamParser = function() {
|
||||||
* @private {number}
|
* @private {number}
|
||||||
*/
|
*/
|
||||||
this.countMessageBytes_ = 0;
|
this.countMessageBytes_ = 0;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
const Parser = GrpcWebStreamParser;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The parser state.
|
|
||||||
* @private @enum {number}
|
|
||||||
*/
|
|
||||||
Parser.State_ = {
|
|
||||||
INIT: 0, // expecting the next frame byte
|
|
||||||
LENGTH: 1, // expecting 4 bytes of length
|
|
||||||
MESSAGE: 2, // expecting more message bytes
|
|
||||||
INVALID: 3
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Possible frame byte
|
|
||||||
* @enum {number}
|
|
||||||
*/
|
|
||||||
GrpcWebStreamParser.FrameType = {
|
|
||||||
DATA: 0x00, // expecting a data frame
|
|
||||||
TRAILER: 0x80, // expecting a trailer frame
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
var FrameType = GrpcWebStreamParser.FrameType;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @override
|
* @override
|
||||||
*/
|
*/
|
||||||
GrpcWebStreamParser.prototype.isInputValid = function() {
|
isInputValid() {
|
||||||
return this.state_ != Parser.State_.INVALID;
|
return this.state_ != Parser.State_.INVALID;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @override
|
* @override
|
||||||
*/
|
*/
|
||||||
GrpcWebStreamParser.prototype.getErrorMessage = function() {
|
getErrorMessage() {
|
||||||
return this.errorMessage_;
|
return this.errorMessage_;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {!Uint8Array|!Array<number>} inputBytes The current input buffer
|
|
||||||
* @param {number} pos The position in the current input that triggers the error
|
|
||||||
* @param {string} errorMsg Additional error message
|
|
||||||
* @throws {!Error} Throws an error indicating where the stream is broken
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
Parser.prototype.error_ = function(inputBytes, pos, errorMsg) {
|
|
||||||
this.state_ = Parser.State_.INVALID;
|
|
||||||
this.errorMessage_ = 'The stream is broken @' + this.streamPos_ + '/' + pos +
|
|
||||||
'. ' +
|
|
||||||
'Error: ' + errorMsg + '. ' +
|
|
||||||
'With input:\n' + inputBytes;
|
|
||||||
throw new Error(this.errorMessage_);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the new input.
|
* Parse the new input.
|
||||||
*
|
*
|
||||||
* Note that there is no Parser state to indicate the end of a stream.
|
* Note that there is no Parser state to indicate the end of a stream.
|
||||||
*
|
*
|
||||||
* @param {string|!ArrayBuffer|!Uint8Array|!Array<number>} input The input data
|
* @param {string|!ArrayBuffer|!Uint8Array|!Array<number>} input The input
|
||||||
|
* data
|
||||||
* @throws {!Error} Throws an error message if the input is invalid.
|
* @throws {!Error} Throws an error message if the input is invalid.
|
||||||
* @return {?Array<string|!Object>} any parsed objects (atomic messages)
|
* @return {?Array<string|!Object>} any parsed objects (atomic messages)
|
||||||
* in an array, or null if more data needs be read to parse any new object.
|
* in an array, or null if more data needs be read to parse any new object.
|
||||||
* @override
|
* @override
|
||||||
*/
|
*/
|
||||||
GrpcWebStreamParser.prototype.parse = function(input) {
|
parse(input) {
|
||||||
asserts.assert(input instanceof Array || input instanceof ArrayBuffer || input instanceof Uint8Array);
|
asserts.assert(
|
||||||
|
input instanceof Array || input instanceof ArrayBuffer ||
|
||||||
|
input instanceof Uint8Array);
|
||||||
|
|
||||||
var parser = this;
|
var parser = this;
|
||||||
var inputBytes;
|
var inputBytes;
|
||||||
|
|
@ -216,7 +169,9 @@ GrpcWebStreamParser.prototype.parse = function(input) {
|
||||||
processMessageByte(inputBytes[pos]);
|
processMessageByte(inputBytes[pos]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: { throw new Error('unexpected parser state: ' + parser.state_); }
|
default: {
|
||||||
|
throw new Error('unexpected parser state: ' + parser.state_);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parser.streamPos_++;
|
parser.streamPos_++;
|
||||||
|
|
@ -285,6 +240,53 @@ GrpcWebStreamParser.prototype.parse = function(input) {
|
||||||
parser.result_.push(message);
|
parser.result_.push(message);
|
||||||
parser.state_ = Parser.State_.INIT;
|
parser.state_ = Parser.State_.INIT;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Parser = GrpcWebStreamParser;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parser state.
|
||||||
|
* @private @enum {number}
|
||||||
|
*/
|
||||||
|
Parser.State_ = {
|
||||||
|
INIT: 0, // expecting the next frame byte
|
||||||
|
LENGTH: 1, // expecting 4 bytes of length
|
||||||
|
MESSAGE: 2, // expecting more message bytes
|
||||||
|
INVALID: 3
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Possible frame byte
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
GrpcWebStreamParser.FrameType = {
|
||||||
|
DATA: 0x00, // expecting a data frame
|
||||||
|
TRAILER: 0x80, // expecting a trailer frame
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var FrameType = GrpcWebStreamParser.FrameType;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!Uint8Array|!Array<number>} inputBytes The current input buffer
|
||||||
|
* @param {number} pos The position in the current input that triggers the error
|
||||||
|
* @param {string} errorMsg Additional error message
|
||||||
|
* @throws {!Error} Throws an error indicating where the stream is broken
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
Parser.prototype.error_ = function(inputBytes, pos, errorMsg) {
|
||||||
|
this.state_ = Parser.State_.INVALID;
|
||||||
|
this.errorMessage_ = 'The stream is broken @' + this.streamPos_ + '/' + pos +
|
||||||
|
'. ' +
|
||||||
|
'Error: ' + errorMsg + '. ' +
|
||||||
|
'With input:\n' + inputBytes;
|
||||||
|
throw new Error(this.errorMessage_);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,9 @@ const MethodType = goog.require('grpc.web.MethodType');
|
||||||
const Request = goog.require('grpc.web.Request');
|
const Request = goog.require('grpc.web.Request');
|
||||||
const RequestInternal = goog.require('grpc.web.RequestInternal');
|
const RequestInternal = goog.require('grpc.web.RequestInternal');
|
||||||
|
|
||||||
|
/** @template REQUEST, RESPONSE */
|
||||||
|
class MethodDescriptor {
|
||||||
/**
|
/**
|
||||||
* @constructor
|
|
||||||
* @struct
|
|
||||||
* @template REQUEST, RESPONSE
|
|
||||||
* @param {string} name
|
* @param {string} name
|
||||||
* @param {!MethodType} methodType
|
* @param {!MethodType} methodType
|
||||||
* @param {function(new: REQUEST, ...)} requestType
|
* @param {function(new: REQUEST, ...)} requestType
|
||||||
|
|
@ -24,7 +23,7 @@ const RequestInternal = goog.require('grpc.web.RequestInternal');
|
||||||
* @param {function(REQUEST): ?} requestSerializeFn
|
* @param {function(REQUEST): ?} requestSerializeFn
|
||||||
* @param {function(?): RESPONSE} responseDeserializeFn
|
* @param {function(?): RESPONSE} responseDeserializeFn
|
||||||
*/
|
*/
|
||||||
const MethodDescriptor = function(
|
constructor(
|
||||||
name, methodType, requestType, responseType, requestSerializeFn,
|
name, methodType, requestType, responseType, requestSerializeFn,
|
||||||
responseDeserializeFn) {
|
responseDeserializeFn) {
|
||||||
/** @const */
|
/** @const */
|
||||||
|
|
@ -39,7 +38,7 @@ const MethodDescriptor = function(
|
||||||
this.requestSerializeFn = requestSerializeFn;
|
this.requestSerializeFn = requestSerializeFn;
|
||||||
/** @const */
|
/** @const */
|
||||||
this.responseDeserializeFn = responseDeserializeFn;
|
this.responseDeserializeFn = responseDeserializeFn;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @template REQUEST, RESPONSE
|
* @template REQUEST, RESPONSE
|
||||||
|
|
@ -48,9 +47,12 @@ const MethodDescriptor = function(
|
||||||
* @param {!CallOptions=} callOptions
|
* @param {!CallOptions=} callOptions
|
||||||
* @return {!Request<REQUEST, RESPONSE>}
|
* @return {!Request<REQUEST, RESPONSE>}
|
||||||
*/
|
*/
|
||||||
MethodDescriptor.prototype.createRequest = function(
|
createRequest(
|
||||||
requestMessage, metadata = {}, callOptions = new CallOptions()) {
|
requestMessage, metadata = {}, callOptions = new CallOptions()) {
|
||||||
return new RequestInternal(requestMessage, this, metadata, callOptions);
|
return new RequestInternal(requestMessage, this, metadata, callOptions);
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
exports = MethodDescriptor;
|
exports = MethodDescriptor;
|
||||||
|
|
|
||||||
|
|
@ -44,15 +44,17 @@ const {Status} = goog.require('grpc.web.Status');
|
||||||
/**
|
/**
|
||||||
* A stream that the client can read from. Used for calls that are streaming
|
* A stream that the client can read from. Used for calls that are streaming
|
||||||
* from the server side.
|
* from the server side.
|
||||||
*
|
|
||||||
* @template RESPONSE
|
* @template RESPONSE
|
||||||
* @constructor
|
|
||||||
* @implements {ClientReadableStream}
|
* @implements {ClientReadableStream}
|
||||||
* @final
|
* @final
|
||||||
|
* @unrestricted
|
||||||
|
*/
|
||||||
|
class StreamBodyClientReadableStream {
|
||||||
|
/**
|
||||||
* @param {!GenericTransportInterface} genericTransportInterface The
|
* @param {!GenericTransportInterface} genericTransportInterface The
|
||||||
* GenericTransportInterface
|
* GenericTransportInterface
|
||||||
*/
|
*/
|
||||||
const StreamBodyClientReadableStream = function(genericTransportInterface) {
|
constructor(genericTransportInterface) {
|
||||||
/**
|
/**
|
||||||
* @const
|
* @const
|
||||||
* @private
|
* @private
|
||||||
|
|
@ -109,13 +111,12 @@ const StreamBodyClientReadableStream = function(genericTransportInterface) {
|
||||||
this.rpcStatusParseFn_ = null;
|
this.rpcStatusParseFn_ = null;
|
||||||
|
|
||||||
this.setStreamCallback_();
|
this.setStreamCallback_();
|
||||||
|
}
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
StreamBodyClientReadableStream.prototype.setStreamCallback_ = function() {
|
setStreamCallback_() {
|
||||||
// Add the callback to the underlying stream
|
// Add the callback to the underlying stream
|
||||||
var self = this;
|
var self = this;
|
||||||
this.xhrNodeReadableStream_.on('data', function(data) {
|
this.xhrNodeReadableStream_.on('data', function(data) {
|
||||||
|
|
@ -167,14 +168,13 @@ StreamBodyClientReadableStream.prototype.setStreamCallback_ = function() {
|
||||||
message: ErrorCode.getDebugMessage(lastErrorCode)
|
message: ErrorCode.getDebugMessage(lastErrorCode)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @override
|
* @override
|
||||||
* @export
|
* @export
|
||||||
*/
|
*/
|
||||||
StreamBodyClientReadableStream.prototype.on = function(
|
on(eventType, callback) {
|
||||||
eventType, callback) {
|
|
||||||
// TODO(stanleycheung): change eventType to @enum type
|
// TODO(stanleycheung): change eventType to @enum type
|
||||||
if (eventType == 'data') {
|
if (eventType == 'data') {
|
||||||
this.onDataCallbacks_.push(callback);
|
this.onDataCallbacks_.push(callback);
|
||||||
|
|
@ -186,29 +186,25 @@ StreamBodyClientReadableStream.prototype.on = function(
|
||||||
this.onErrorCallbacks_.push(callback);
|
this.onErrorCallbacks_.push(callback);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {!Array<function(?)>} callbacks the internal list of callbacks
|
* @param {!Array<function(?)>} callbacks the internal list of callbacks
|
||||||
* @param {function(?)} callback the callback to remove
|
* @param {function(?)} callback the callback to remove
|
||||||
*/
|
*/
|
||||||
StreamBodyClientReadableStream.prototype.removeListenerFromCallbacks_ = function(
|
removeListenerFromCallbacks_(callbacks, callback) {
|
||||||
callbacks, callback) {
|
|
||||||
const index = callbacks.indexOf(callback);
|
const index = callbacks.indexOf(callback);
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
callbacks.splice(index, 1);
|
callbacks.splice(index, 1);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @export
|
* @export
|
||||||
* @override
|
* @override
|
||||||
*/
|
*/
|
||||||
StreamBodyClientReadableStream.prototype.removeListener = function(
|
removeListener(eventType, callback) {
|
||||||
eventType, callback) {
|
|
||||||
if (eventType == 'data') {
|
if (eventType == 'data') {
|
||||||
this.removeListenerFromCallbacks_(this.onDataCallbacks_, callback);
|
this.removeListenerFromCallbacks_(this.onDataCallbacks_, callback);
|
||||||
} else if (eventType == 'status') {
|
} else if (eventType == 'status') {
|
||||||
|
|
@ -219,8 +215,7 @@ StreamBodyClientReadableStream.prototype.removeListener = function(
|
||||||
this.removeListenerFromCallbacks_(this.onErrorCallbacks_, callback);
|
this.removeListenerFromCallbacks_(this.onErrorCallbacks_, callback);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a callbackl to parse the response
|
* Register a callbackl to parse the response
|
||||||
|
|
@ -228,10 +223,9 @@ StreamBodyClientReadableStream.prototype.removeListener = function(
|
||||||
* @param {function(?): RESPONSE} responseDeserializeFn The deserialize
|
* @param {function(?): RESPONSE} responseDeserializeFn The deserialize
|
||||||
* function for the proto
|
* function for the proto
|
||||||
*/
|
*/
|
||||||
StreamBodyClientReadableStream.prototype.setResponseDeserializeFn =
|
setResponseDeserializeFn(responseDeserializeFn) {
|
||||||
function(responseDeserializeFn) {
|
|
||||||
this.responseDeserializeFn_ = responseDeserializeFn;
|
this.responseDeserializeFn_ = responseDeserializeFn;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a function to parse RPC status response
|
* Register a function to parse RPC status response
|
||||||
|
|
@ -239,61 +233,58 @@ StreamBodyClientReadableStream.prototype.setResponseDeserializeFn =
|
||||||
* @param {function(?):!Status} rpcStatusParseFn A function to parse
|
* @param {function(?):!Status} rpcStatusParseFn A function to parse
|
||||||
* the RPC status response
|
* the RPC status response
|
||||||
*/
|
*/
|
||||||
StreamBodyClientReadableStream.prototype.setRpcStatusParseFn = function(rpcStatusParseFn) {
|
setRpcStatusParseFn(rpcStatusParseFn) {
|
||||||
this.rpcStatusParseFn_ = rpcStatusParseFn;
|
this.rpcStatusParseFn_ = rpcStatusParseFn;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @override
|
* @override
|
||||||
* @export
|
* @export
|
||||||
*/
|
*/
|
||||||
StreamBodyClientReadableStream.prototype.cancel = function() {
|
cancel() {
|
||||||
this.xhr_.abort();
|
this.xhr_.abort();
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {!RESPONSE} data The data to send back
|
* @param {!RESPONSE} data The data to send back
|
||||||
*/
|
*/
|
||||||
StreamBodyClientReadableStream.prototype.sendDataCallbacks_ = function(data) {
|
sendDataCallbacks_(data) {
|
||||||
for (var i = 0; i < this.onDataCallbacks_.length; i++) {
|
for (var i = 0; i < this.onDataCallbacks_.length; i++) {
|
||||||
this.onDataCallbacks_[i](data);
|
this.onDataCallbacks_[i](data);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {!Status} status The status to send back
|
* @param {!Status} status The status to send back
|
||||||
*/
|
*/
|
||||||
StreamBodyClientReadableStream.prototype.sendStatusCallbacks_ = function(status) {
|
sendStatusCallbacks_(status) {
|
||||||
for (var i = 0; i < this.onStatusCallbacks_.length; i++) {
|
for (var i = 0; i < this.onStatusCallbacks_.length; i++) {
|
||||||
this.onStatusCallbacks_[i](status);
|
this.onStatusCallbacks_[i](status);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {?} error The error to send back
|
* @param {?} error The error to send back
|
||||||
*/
|
*/
|
||||||
StreamBodyClientReadableStream.prototype.sendErrorCallbacks_ = function(error) {
|
sendErrorCallbacks_(error) {
|
||||||
for (var i = 0; i < this.onErrorCallbacks_.length; i++) {
|
for (var i = 0; i < this.onErrorCallbacks_.length; i++) {
|
||||||
this.onErrorCallbacks_[i](error);
|
this.onErrorCallbacks_[i](error);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
StreamBodyClientReadableStream.prototype.sendEndCallbacks_ = function() {
|
sendEndCallbacks_() {
|
||||||
for (var i = 0; i < this.onEndCallbacks_.length; i++) {
|
for (var i = 0; i < this.onEndCallbacks_.length; i++) {
|
||||||
this.onEndCallbacks_[i]();
|
this.onEndCallbacks_[i]();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
exports = StreamBodyClientReadableStream;
|
exports = StreamBodyClientReadableStream;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue