mirror of https://github.com/grpc/grpc-web.git
Internal code sync (#1140)
This commit is contained in:
parent
627e33718d
commit
f1fe57473f
6
Makefile
6
Makefile
|
@ -3,11 +3,11 @@ ROOT_DIR := $(shell pwd)
|
|||
all: clean
|
||||
|
||||
plugin:
|
||||
cd "$(ROOT_DIR)"/javascript/net/grpc/web && make
|
||||
cd "$(ROOT_DIR)"/javascript/net/grpc/web/generator && make
|
||||
|
||||
install-plugin:
|
||||
cd "$(ROOT_DIR)"/javascript/net/grpc/web && make install
|
||||
cd "$(ROOT_DIR)"/javascript/net/grpc/web/generator && make install
|
||||
|
||||
clean:
|
||||
cd "$(ROOT_DIR)"/javascript/net/grpc/web && make clean
|
||||
cd "$(ROOT_DIR)"/javascript/net/grpc/web/generator && make clean
|
||||
cd "$(ROOT_DIR)"
|
||||
|
|
|
@ -63,64 +63,18 @@ enum ImportStyle {
|
|||
const char GRPC_PROMISE[] = "grpc.web.promise.GrpcWebPromise";
|
||||
|
||||
const char* kKeyword[] = {
|
||||
"abstract",
|
||||
"boolean",
|
||||
"break",
|
||||
"byte",
|
||||
"case",
|
||||
"catch",
|
||||
"char",
|
||||
"class",
|
||||
"const",
|
||||
"continue",
|
||||
"debugger",
|
||||
"default",
|
||||
"delete",
|
||||
"do",
|
||||
"double",
|
||||
"else",
|
||||
"enum",
|
||||
"export",
|
||||
"extends",
|
||||
"false",
|
||||
"final",
|
||||
"finally",
|
||||
"float",
|
||||
"for",
|
||||
"function",
|
||||
"goto",
|
||||
"if",
|
||||
"implements",
|
||||
"import",
|
||||
"in",
|
||||
"instanceof",
|
||||
"int",
|
||||
"interface",
|
||||
"long",
|
||||
"native",
|
||||
"new",
|
||||
"null",
|
||||
"package",
|
||||
"private",
|
||||
"protected",
|
||||
"public",
|
||||
"return",
|
||||
"short",
|
||||
"static",
|
||||
"super",
|
||||
"switch",
|
||||
"synchronized",
|
||||
"this",
|
||||
"throw",
|
||||
"throws",
|
||||
"transient",
|
||||
"try",
|
||||
"typeof",
|
||||
"var",
|
||||
"void",
|
||||
"volatile",
|
||||
"while",
|
||||
"with",
|
||||
"abstract", "boolean", "break", "byte", "case",
|
||||
"catch", "char", "class", "const", "continue",
|
||||
"debugger", "default", "delete", "do", "double",
|
||||
"else", "enum", "export", "extends", "false",
|
||||
"final", "finally", "float", "for", "function",
|
||||
"goto", "if", "implements", "import", "in",
|
||||
"instanceof", "int", "interface", "long", "native",
|
||||
"new", "null", "package", "private", "protected",
|
||||
"public", "return", "short", "static", "super",
|
||||
"switch", "synchronized", "this", "throw", "throws",
|
||||
"transient", "try", "typeof", "var", "void",
|
||||
"volatile", "while", "with",
|
||||
};
|
||||
|
||||
bool IsReserved(const string& ident) {
|
||||
|
@ -204,10 +158,9 @@ string Uppercase(string s) {
|
|||
// The following 5 functions were copied from
|
||||
// google/protobuf/src/google/protobuf/stubs/strutil.h
|
||||
|
||||
inline bool HasPrefixString(const string& str,
|
||||
const string& prefix) {
|
||||
inline bool HasPrefixString(const string& str, const string& prefix) {
|
||||
return str.size() >= prefix.size() &&
|
||||
str.compare(0, prefix.size(), prefix) == 0;
|
||||
str.compare(0, prefix.size(), prefix) == 0;
|
||||
}
|
||||
|
||||
inline string StripPrefixString(const string& str, const string& prefix) {
|
||||
|
@ -218,10 +171,9 @@ inline string StripPrefixString(const string& str, const string& prefix) {
|
|||
}
|
||||
}
|
||||
|
||||
inline bool HasSuffixString(const string& str,
|
||||
const string& suffix) {
|
||||
inline bool HasSuffixString(const string& str, const string& suffix) {
|
||||
return str.size() >= suffix.size() &&
|
||||
str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
|
||||
str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
|
||||
}
|
||||
|
||||
inline string StripSuffixString(const string& str, const string& suffix) {
|
||||
|
@ -232,17 +184,15 @@ inline string StripSuffixString(const string& str, const string& suffix) {
|
|||
}
|
||||
}
|
||||
|
||||
void ReplaceCharacters(string *s, const char *remove, char replacewith) {
|
||||
const char *str_start = s->c_str();
|
||||
const char *str = str_start;
|
||||
for (str = strpbrk(str, remove);
|
||||
str != nullptr;
|
||||
void ReplaceCharacters(string* s, const char* remove, char replacewith) {
|
||||
const char* str_start = s->c_str();
|
||||
const char* str = str_start;
|
||||
for (str = strpbrk(str, remove); str != nullptr;
|
||||
str = strpbrk(str + 1, remove)) {
|
||||
(*s)[str - str_start] = replacewith;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The following function was copied from
|
||||
// google/protobuf/src/google/protobuf/compiler/cpp/cpp_helpers.cc
|
||||
|
||||
|
@ -313,7 +263,7 @@ string ModuleAlias(const string& filename) {
|
|||
return basename + "_pb";
|
||||
}
|
||||
|
||||
string JSMessageType(const Descriptor *desc, const FileDescriptor *file) {
|
||||
string JSMessageType(const Descriptor* desc, const FileDescriptor* file) {
|
||||
string class_name;
|
||||
class_name = StripPrefixString(desc->full_name(), desc->file()->package());
|
||||
if (!class_name.empty() && class_name[0] == '.') {
|
||||
|
@ -327,11 +277,11 @@ string JSMessageType(const Descriptor *desc, const FileDescriptor *file) {
|
|||
return ModuleAlias(desc->file()->name()) + "." + class_name;
|
||||
}
|
||||
|
||||
string JSMessageType(const Descriptor *desc) {
|
||||
string JSMessageType(const Descriptor* desc) {
|
||||
return JSMessageType(desc, nullptr);
|
||||
}
|
||||
|
||||
string JSElementType(const FieldDescriptor *desc, const FileDescriptor *file) {
|
||||
string JSElementType(const FieldDescriptor* desc, const FileDescriptor* file) {
|
||||
switch (desc->type()) {
|
||||
case FieldDescriptor::TYPE_DOUBLE:
|
||||
case FieldDescriptor::TYPE_FLOAT:
|
||||
|
@ -367,15 +317,13 @@ string JSElementType(const FieldDescriptor *desc, const FileDescriptor *file) {
|
|||
// [for protobuf .d.ts files only] Do not add the module prefix for
|
||||
// local messages.
|
||||
string enum_name =
|
||||
StripPrefixString(
|
||||
desc->enum_type()->full_name(),
|
||||
desc->enum_type()->file()->package());
|
||||
StripPrefixString(desc->enum_type()->full_name(),
|
||||
desc->enum_type()->file()->package());
|
||||
return StripPrefixString(enum_name, ".");
|
||||
}
|
||||
return ModuleAlias(desc->enum_type()->file()->name())
|
||||
+ StripPrefixString(
|
||||
desc->enum_type()->full_name(),
|
||||
desc->enum_type()->file()->package());
|
||||
return ModuleAlias(desc->enum_type()->file()->name()) +
|
||||
StripPrefixString(desc->enum_type()->full_name(),
|
||||
desc->enum_type()->file()->package());
|
||||
|
||||
case FieldDescriptor::TYPE_MESSAGE:
|
||||
return JSMessageType(desc->message_type(), file);
|
||||
|
@ -385,22 +333,21 @@ string JSElementType(const FieldDescriptor *desc, const FileDescriptor *file) {
|
|||
}
|
||||
}
|
||||
|
||||
string JSFieldType(const FieldDescriptor *desc, const FileDescriptor *file) {
|
||||
string JSFieldType(const FieldDescriptor* desc, const FileDescriptor* file) {
|
||||
string js_field_type = JSElementType(desc, file);
|
||||
if (desc->is_map()) {
|
||||
string key_type = JSFieldType(desc->message_type()->field(0), file);
|
||||
string value_type = JSFieldType(desc->message_type()->field(1), file);
|
||||
return "jspb.Map<" + key_type + ", " + value_type + ">";
|
||||
}
|
||||
if (desc->is_repeated())
|
||||
{
|
||||
if (desc->is_repeated()) {
|
||||
return "Array<" + js_field_type + ">";
|
||||
}
|
||||
return js_field_type;
|
||||
}
|
||||
|
||||
string AsObjectFieldType(
|
||||
const FieldDescriptor *desc, const FileDescriptor *file) {
|
||||
string AsObjectFieldType(const FieldDescriptor* desc,
|
||||
const FileDescriptor* file) {
|
||||
if (desc->type() != FieldDescriptor::TYPE_MESSAGE) {
|
||||
return JSFieldType(desc, file);
|
||||
}
|
||||
|
@ -417,11 +364,11 @@ string AsObjectFieldType(
|
|||
return field_type;
|
||||
}
|
||||
|
||||
string JSElementName(const FieldDescriptor *desc) {
|
||||
string JSElementName(const FieldDescriptor* desc) {
|
||||
return ToUpperCamel(ParseLowerUnderscore(desc->name()));
|
||||
}
|
||||
|
||||
string JSFieldName(const FieldDescriptor *desc) {
|
||||
string JSFieldName(const FieldDescriptor* desc) {
|
||||
string js_field_name = JSElementName(desc);
|
||||
if (desc->is_map()) {
|
||||
js_field_name += "Map";
|
||||
|
@ -432,20 +379,17 @@ string JSFieldName(const FieldDescriptor *desc) {
|
|||
}
|
||||
|
||||
// Like ToUpperCamel except the first letter is not converted.
|
||||
string ToCamelCase(const std::vector<string>& words)
|
||||
{
|
||||
string ToCamelCase(const std::vector<string>& words) {
|
||||
if (words.empty()) {
|
||||
return "";
|
||||
return "";
|
||||
}
|
||||
string result = words[0];
|
||||
return result + ToUpperCamel(std::vector<string>(
|
||||
words.begin()+1,
|
||||
words.begin()+words.size()));
|
||||
words.begin() + 1, words.begin() + words.size()));
|
||||
}
|
||||
|
||||
// Like JSFieldName, but with first letter not uppercased
|
||||
string CamelCaseJSFieldName(const FieldDescriptor *desc)
|
||||
{
|
||||
string CamelCaseJSFieldName(const FieldDescriptor* desc) {
|
||||
string js_field_name = ToCamelCase(ParseLowerUnderscore(desc->name()));
|
||||
if (desc->is_map()) {
|
||||
js_field_name += "Map";
|
||||
|
@ -463,8 +407,8 @@ string GetNestedMessageName(const Descriptor* descriptor) {
|
|||
if (descriptor == nullptr) {
|
||||
return "";
|
||||
}
|
||||
string result = StripPrefixString(descriptor->full_name(),
|
||||
descriptor->file()->package());
|
||||
string result =
|
||||
StripPrefixString(descriptor->full_name(), descriptor->file()->package());
|
||||
// Add a leading dot if one is not already present.
|
||||
if (!result.empty() && result[0] != '.') {
|
||||
result = "." + result;
|
||||
|
@ -534,7 +478,7 @@ std::map<string, const Descriptor*> GetAllMessages(const FileDescriptor* file) {
|
|||
for (int s = 0; s < file->service_count(); ++s) {
|
||||
const ServiceDescriptor* service = file->service(s);
|
||||
for (int m = 0; m < service->method_count(); ++m) {
|
||||
const MethodDescriptor *method = service->method(m);
|
||||
const MethodDescriptor* method = service->method(m);
|
||||
messages[method->input_type()->full_name()] = method->input_type();
|
||||
messages[method->output_type()->full_name()] = method->output_type();
|
||||
}
|
||||
|
@ -544,12 +488,10 @@ std::map<string, const Descriptor*> GetAllMessages(const FileDescriptor* file) {
|
|||
}
|
||||
|
||||
void PrintClosureDependencies(Printer* printer, const FileDescriptor* file) {
|
||||
for (const auto &entry : GetAllMessages(file)) {
|
||||
printer->Print(
|
||||
"goog.require('proto.$full_name$');\n",
|
||||
"full_name", entry.second->full_name());
|
||||
for (const auto& entry : GetAllMessages(file)) {
|
||||
printer->Print("goog.require('proto.$full_name$');\n", "full_name",
|
||||
entry.second->full_name());
|
||||
}
|
||||
printer->Print("\n\n\n");
|
||||
}
|
||||
|
||||
void PrintCommonJsMessagesDeps(Printer* printer, const FileDescriptor* file) {
|
||||
|
@ -560,9 +502,7 @@ void PrintCommonJsMessagesDeps(Printer* printer, const FileDescriptor* file) {
|
|||
vars["alias"] = ModuleAlias(name);
|
||||
vars["dep_filename"] = GetRootPath(file->name(), name) + StripProto(name);
|
||||
// we need to give each cross-file import an alias
|
||||
printer->Print(
|
||||
vars,
|
||||
"\nvar $alias$ = require('$dep_filename$_pb.js')\n");
|
||||
printer->Print(vars, "\nvar $alias$ = require('$dep_filename$_pb.js')\n");
|
||||
}
|
||||
|
||||
const string& package = file->package();
|
||||
|
@ -587,13 +527,10 @@ void PrintCommonJsMessagesDeps(Printer* printer, const FileDescriptor* file) {
|
|||
vars["filename"] = GetBasename(StripProto(file->name()));
|
||||
|
||||
if (!package.empty()) {
|
||||
printer->Print(
|
||||
vars,
|
||||
"proto.$package_name$ = require('./$filename$_pb.js');\n\n");
|
||||
printer->Print(vars,
|
||||
"proto.$package_name$ = require('./$filename$_pb.js');\n\n");
|
||||
} else {
|
||||
printer->Print(
|
||||
vars,
|
||||
"const proto = require('./$filename$_pb.js');\n\n");
|
||||
printer->Print(vars, "const proto = require('./$filename$_pb.js');\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -603,7 +540,7 @@ void PrintES6Imports(Printer* printer, const FileDescriptor* file) {
|
|||
printer->Print("import * as grpcWeb from 'grpc-web';\n\n");
|
||||
|
||||
std::set<string> imports;
|
||||
for (const auto &entry : GetAllMessages(file)) {
|
||||
for (const auto& entry : GetAllMessages(file)) {
|
||||
const string& name = entry.second->file()->name();
|
||||
string dep_filename = GetRootPath(file->name(), name) + StripProto(name);
|
||||
if (imports.find(dep_filename) != imports.end()) {
|
||||
|
@ -611,10 +548,8 @@ void PrintES6Imports(Printer* printer, const FileDescriptor* file) {
|
|||
}
|
||||
imports.insert(dep_filename);
|
||||
// We need to give each cross-file import an alias.
|
||||
printer->Print(
|
||||
"import * as $alias$ from '$dep_filename$_pb';\n",
|
||||
"alias", ModuleAlias(name),
|
||||
"dep_filename", dep_filename);
|
||||
printer->Print("import * as $alias$ from '$dep_filename$_pb';\n", "alias",
|
||||
ModuleAlias(name), "dep_filename", dep_filename);
|
||||
}
|
||||
printer->Print("\n\n");
|
||||
}
|
||||
|
@ -687,13 +622,12 @@ void PrintTypescriptFile(Printer* printer, const FileDescriptor* file,
|
|||
"metadata?: grpcWeb.Metadata) {\n");
|
||||
printer->Print(vars, "return this.client_.serverStreaming(\n");
|
||||
printer->Indent();
|
||||
printer->Print(
|
||||
vars,
|
||||
"this.hostname_ +\n"
|
||||
" '/$package_dot$$service_name$/$method_name$',\n"
|
||||
"request,\n"
|
||||
"metadata || {},\n"
|
||||
"this.methodInfo$method_name$);\n");
|
||||
printer->Print(vars,
|
||||
"this.hostname_ +\n"
|
||||
" '/$package_dot$$service_name$/$method_name$',\n"
|
||||
"request,\n"
|
||||
"metadata || {},\n"
|
||||
"this.methodInfo$method_name$);\n");
|
||||
printer->Outdent();
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
|
@ -727,14 +661,13 @@ void PrintTypescriptFile(Printer* printer, const FileDescriptor* file,
|
|||
printer->Indent();
|
||||
printer->Print(vars, "return this.client_.rpcCall(\n");
|
||||
printer->Indent();
|
||||
printer->Print(
|
||||
vars,
|
||||
"this.hostname_ +\n"
|
||||
" '/$package_dot$$service_name$/$method_name$',\n"
|
||||
"request,\n"
|
||||
"metadata || {},\n"
|
||||
"this.methodInfo$method_name$,\n"
|
||||
"callback);\n");
|
||||
printer->Print(vars,
|
||||
"this.hostname_ +\n"
|
||||
" '/$package_dot$$service_name$/$method_name$',\n"
|
||||
"request,\n"
|
||||
"metadata || {},\n"
|
||||
"this.methodInfo$method_name$,\n"
|
||||
"callback);\n");
|
||||
printer->Outdent();
|
||||
printer->Outdent();
|
||||
printer->Print(vars,
|
||||
|
@ -757,7 +690,7 @@ void PrintTypescriptFile(Printer* printer, const FileDescriptor* file,
|
|||
}
|
||||
|
||||
void PrintGrpcWebDtsClientClass(Printer* printer, const FileDescriptor* file,
|
||||
const string &client_type) {
|
||||
const string& client_type) {
|
||||
std::map<string, string> vars;
|
||||
vars["client_type"] = client_type;
|
||||
vars["promise"] = "Promise";
|
||||
|
@ -824,15 +757,13 @@ void PrintGrpcWebDtsFile(Printer* printer, const FileDescriptor* file) {
|
|||
PrintGrpcWebDtsClientClass(printer, file, "PromiseClient");
|
||||
}
|
||||
|
||||
void PrintProtoDtsEnum(Printer *printer, const EnumDescriptor *desc)
|
||||
{
|
||||
void PrintProtoDtsEnum(Printer* printer, const EnumDescriptor* desc) {
|
||||
std::map<string, string> vars;
|
||||
vars["enum_name"] = desc->name();
|
||||
|
||||
printer->Print(vars, "export enum $enum_name$ { \n");
|
||||
printer->Indent();
|
||||
for (int i = 0; i < desc->value_count(); i++)
|
||||
{
|
||||
for (int i = 0; i < desc->value_count(); i++) {
|
||||
vars["value_name"] = Uppercase(desc->value(i)->name());
|
||||
vars["value_number"] = std::to_string(desc->value(i)->number());
|
||||
printer->Print(vars, "$value_name$ = $value_number$,\n");
|
||||
|
@ -841,8 +772,7 @@ void PrintProtoDtsEnum(Printer *printer, const EnumDescriptor *desc)
|
|||
printer->Print("}\n");
|
||||
}
|
||||
|
||||
void PrintProtoDtsOneofCase(Printer *printer, const OneofDescriptor *desc)
|
||||
{
|
||||
void PrintProtoDtsOneofCase(Printer* printer, const OneofDescriptor* desc) {
|
||||
std::map<string, string> vars;
|
||||
vars["oneof_name"] = ToUpperCamel(ParseLowerUnderscore(desc->name()));
|
||||
vars["oneof_name_upper"] = Uppercase(desc->name());
|
||||
|
@ -851,7 +781,7 @@ void PrintProtoDtsOneofCase(Printer *printer, const OneofDescriptor *desc)
|
|||
printer->Indent();
|
||||
printer->Print(vars, "$oneof_name_upper$_NOT_SET = 0,\n");
|
||||
for (int i = 0; i < desc->field_count(); i++) {
|
||||
const FieldDescriptor *field = desc->field(i);
|
||||
const FieldDescriptor* field = desc->field(i);
|
||||
vars["field_name"] = Uppercase(field->name());
|
||||
vars["field_number"] = std::to_string(field->number());
|
||||
printer->Print(vars, "$field_name$ = $field_number$,\n");
|
||||
|
@ -860,8 +790,8 @@ void PrintProtoDtsOneofCase(Printer *printer, const OneofDescriptor *desc)
|
|||
printer->Print("}\n");
|
||||
}
|
||||
|
||||
void PrintProtoDtsMessage(Printer *printer, const Descriptor *desc,
|
||||
const FileDescriptor *file) {
|
||||
void PrintProtoDtsMessage(Printer* printer, const Descriptor* desc,
|
||||
const FileDescriptor* file) {
|
||||
const string& class_name = desc->name();
|
||||
std::map<string, string> vars;
|
||||
vars["class_name"] = class_name;
|
||||
|
@ -874,8 +804,7 @@ void PrintProtoDtsMessage(Printer *printer, const Descriptor *desc,
|
|||
vars["js_field_type"] = JSFieldType(field, file);
|
||||
if (field->type() != FieldDescriptor::TYPE_MESSAGE ||
|
||||
field->is_repeated()) {
|
||||
printer->Print(vars,
|
||||
"get$js_field_name$(): $js_field_type$;\n");
|
||||
printer->Print(vars, "get$js_field_name$(): $js_field_type$;\n");
|
||||
} else {
|
||||
printer->Print(vars,
|
||||
"get$js_field_name$(): $js_field_type$ | undefined;\n");
|
||||
|
@ -895,8 +824,8 @@ void PrintProtoDtsMessage(Printer *printer, const Descriptor *desc,
|
|||
"set$js_field_name$(value?: $js_field_type$): "
|
||||
"$class_name$;\n");
|
||||
}
|
||||
if (field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_repeated()
|
||||
&& !field->is_map()) {
|
||||
if (field->type() == FieldDescriptor::TYPE_MESSAGE &&
|
||||
!field->is_repeated() && !field->is_map()) {
|
||||
printer->Print(vars, "has$js_field_name$(): boolean;\n");
|
||||
}
|
||||
if (field->type() == FieldDescriptor::TYPE_MESSAGE ||
|
||||
|
@ -924,8 +853,7 @@ void PrintProtoDtsMessage(Printer *printer, const Descriptor *desc,
|
|||
const OneofDescriptor* oneof = desc->oneof_decl(i);
|
||||
vars["js_oneof_name"] = ToUpperCamel(ParseLowerUnderscore(oneof->name()));
|
||||
printer->Print(
|
||||
vars,
|
||||
"get$js_oneof_name$Case(): $class_name$.$js_oneof_name$Case;\n");
|
||||
vars, "get$js_oneof_name$Case(): $class_name$.$js_oneof_name$Case;\n");
|
||||
printer->Print("\n");
|
||||
}
|
||||
|
||||
|
@ -988,17 +916,15 @@ void PrintProtoDtsMessage(Printer *printer, const Descriptor *desc,
|
|||
printer->Print("}\n\n");
|
||||
}
|
||||
|
||||
void PrintProtoDtsFile(Printer *printer, const FileDescriptor *file)
|
||||
{
|
||||
void PrintProtoDtsFile(Printer* printer, const FileDescriptor* file) {
|
||||
printer->Print("import * as jspb from 'google-protobuf'\n\n");
|
||||
|
||||
for (int i = 0; i < file->dependency_count(); i++) {
|
||||
const string& name = file->dependency(i)->name();
|
||||
// We need to give each cross-file import an alias.
|
||||
printer->Print(
|
||||
"import * as $alias$ from '$dep_filename$_pb';\n",
|
||||
"alias", ModuleAlias(name),
|
||||
"dep_filename", GetRootPath(file->name(), name) + StripProto(name));
|
||||
printer->Print("import * as $alias$ from '$dep_filename$_pb';\n", "alias",
|
||||
ModuleAlias(name), "dep_filename",
|
||||
GetRootPath(file->name(), name) + StripProto(name));
|
||||
}
|
||||
printer->Print("\n\n");
|
||||
|
||||
|
@ -1080,8 +1006,9 @@ void PrintMethodDescriptorFile(Printer* printer,
|
|||
" * @param {!proto.$in$} request\n");
|
||||
printer->Print(
|
||||
(" * @return {" + GetSerializeMethodReturnType(vars) + "}\n").c_str());
|
||||
printer->Print(" */\n"
|
||||
"function(request) {\n");
|
||||
printer->Print(
|
||||
" */\n"
|
||||
"function(request) {\n");
|
||||
printer->Print(
|
||||
(" return request." + GetSerializeMethodName(vars) + "();\n").c_str());
|
||||
printer->Print("},\n");
|
||||
|
@ -1102,7 +1029,7 @@ void PrintServiceConstructor(Printer* printer, std::map<string, string> vars,
|
|||
"/**\n"
|
||||
" * @param {string} hostname\n"
|
||||
" * @param {?Object} credentials\n"
|
||||
" * @param {?Object} options\n"
|
||||
" * @param {?grpc.web.ClientOptions} options\n"
|
||||
" * @constructor\n"
|
||||
" * @struct\n"
|
||||
" * @final\n"
|
||||
|
@ -1111,7 +1038,7 @@ void PrintServiceConstructor(Printer* printer, std::map<string, string> vars,
|
|||
" function(hostname, credentials, options) {\n"
|
||||
" if (!options) options = {};\n");
|
||||
if (vars["mode"] == GetModeVar(Mode::GRPCWEB)) {
|
||||
printer->Print(vars, " options['format'] = '$format$';\n\n");
|
||||
printer->Print(vars, " options.format = '$format$';\n\n");
|
||||
}
|
||||
if (vars["mode"] == GetModeVar(Mode::OP)) {
|
||||
printer->Print(
|
||||
|
@ -1213,7 +1140,7 @@ void PrintPromiseUnaryCall(Printer* printer, std::map<string, string> vars) {
|
|||
"/**\n"
|
||||
" * @param {!proto.$in$} request The\n"
|
||||
" * request proto\n"
|
||||
" * @param {?Object<string, string>} metadata User defined\n"
|
||||
" * @param {?Object<string, string>=} metadata User defined\n"
|
||||
" * call metadata\n"
|
||||
" * @return {!$promise$<!proto.$out$>}\n"
|
||||
" * Promise that resolves to the response\n"
|
||||
|
@ -1243,17 +1170,16 @@ void PrintPromiseUnaryCall(Printer* printer, std::map<string, string> vars) {
|
|||
}
|
||||
|
||||
void PrintServerStreamingCall(Printer* printer, std::map<string, string> vars) {
|
||||
printer->Print(
|
||||
vars,
|
||||
"/**\n"
|
||||
" * @param {!proto.$in$} request The request proto\n"
|
||||
" * @param {?Object<string, string>} metadata User defined\n"
|
||||
" * call metadata\n"
|
||||
" * @return {!grpc.web.ClientReadableStream<!proto.$out$>}\n"
|
||||
" * The XHR Node Readable Stream\n"
|
||||
" */\n"
|
||||
"proto.$package_dot$$service_name$$client_type$.prototype."
|
||||
"$js_method_name$ =\n");
|
||||
printer->Print(vars,
|
||||
"/**\n"
|
||||
" * @param {!proto.$in$} request The request proto\n"
|
||||
" * @param {?Object<string, string>=} metadata User defined\n"
|
||||
" * call metadata\n"
|
||||
" * @return {!grpc.web.ClientReadableStream<!proto.$out$>}\n"
|
||||
" * The XHR Node Readable Stream\n"
|
||||
" */\n"
|
||||
"proto.$package_dot$$service_name$$client_type$.prototype."
|
||||
"$js_method_name$ =\n");
|
||||
printer->Indent();
|
||||
printer->Print(
|
||||
" function(request, metadata) {\n"
|
||||
|
@ -1359,6 +1285,11 @@ void PrintMultipleFilesMode(const FileDescriptor* file, string file_name,
|
|||
PrintClosureDependencies(&printer1, file);
|
||||
PrintClosureDependencies(&printer2, file);
|
||||
|
||||
printer1.Print(vars, "\ngoog.requireType('grpc.web.ClientOptions');\n");
|
||||
printer2.Print(vars, "\ngoog.requireType('grpc.web.ClientOptions');\n");
|
||||
|
||||
printer1.Print("\n\n\n");
|
||||
printer2.Print("\n\n\n");
|
||||
printer1.Print("goog.scope(function() {\n\n");
|
||||
printer2.Print("goog.scope(function() {\n\n");
|
||||
|
||||
|
@ -1403,20 +1334,20 @@ void PrintMultipleFilesMode(const FileDescriptor* file, string file_name,
|
|||
printer2.Print("}); // goog.scope\n\n");
|
||||
}
|
||||
|
||||
void PrintClosureES6Imports(
|
||||
Printer* printer, const FileDescriptor* file, string package_dot) {
|
||||
void PrintClosureES6Imports(Printer* printer, const FileDescriptor* file,
|
||||
string package_dot) {
|
||||
for (int i = 0; i < file->service_count(); ++i) {
|
||||
const ServiceDescriptor* service = file->service(i);
|
||||
|
||||
string service_namespace = "proto." + package_dot + service->name();
|
||||
printer->Print(
|
||||
"import $service_name$Client_import from 'goog:$namespace$';\n",
|
||||
"service_name", service->name(),
|
||||
"namespace", service_namespace + "Client");
|
||||
"service_name", service->name(), "namespace",
|
||||
service_namespace + "Client");
|
||||
printer->Print(
|
||||
"import $service_name$PromiseClient_import from 'goog:$namespace$';\n",
|
||||
"service_name", service->name(),
|
||||
"namespace", service_namespace + "PromiseClient");
|
||||
"service_name", service->name(), "namespace",
|
||||
service_namespace + "PromiseClient");
|
||||
}
|
||||
|
||||
printer->Print("\n\n\n");
|
||||
|
@ -1441,9 +1372,8 @@ void PrintGrpcWebClosureES6File(Printer* printer, const FileDescriptor* file) {
|
|||
const ServiceDescriptor* service = file->service(i);
|
||||
|
||||
string service_namespace = "proto." + package_dot + service->name();
|
||||
printer->Print(
|
||||
"export const $name$Client = $name$Client_import;\n",
|
||||
"name", service->name());
|
||||
printer->Print("export const $name$Client = $name$Client_import;\n", "name",
|
||||
service->name());
|
||||
printer->Print(
|
||||
"export const $name$PromiseClient = $name$PromiseClient_import;\n",
|
||||
"name", service->name());
|
||||
|
@ -1664,7 +1594,8 @@ class GrpcCodeGenerator : public CodeGenerator {
|
|||
printer.Print(vars, "goog.require('grpc.web.RpcError');\n");
|
||||
|
||||
PrintClosureDependencies(&printer, file);
|
||||
|
||||
printer.Print(vars, "\ngoog.requireType('grpc.web.ClientOptions');\n");
|
||||
printer.Print("\n\n\n");
|
||||
printer.Print("goog.scope(function() {\n\n");
|
||||
break;
|
||||
case ImportStyle::COMMONJS:
|
|
@ -1,41 +0,0 @@
|
|||
/**
|
||||
* @fileoverview base interface for grpc web GenericClient.
|
||||
*/
|
||||
|
||||
goog.module('grpc.web.GenericClient');
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
const MethodDescriptor = goog.require('grpc.web.MethodDescriptor');
|
||||
const Request = goog.require('grpc.web.Request');
|
||||
const UnaryResponse = goog.require('grpc.web.UnaryResponse');
|
||||
|
||||
/**
|
||||
* @interface
|
||||
*/
|
||||
const GenericClient = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* @param {!Request<REQUEST, RESPONSE>} request The wrapped gRPC-Web request
|
||||
* @return {!Promise<!UnaryResponse<RESPONSE>>} A promise that resolves to the
|
||||
* response message and metadata
|
||||
* @template REQUEST, RESPONSE
|
||||
* @abstract
|
||||
*/
|
||||
GenericClient.prototype.unaryCall = function(request) {};
|
||||
|
||||
/**
|
||||
* Simplified version of GenericClient.prototype.unaryCall. Users are expected
|
||||
* to use this method if they don't have the need to customize metadata and
|
||||
* callOptions .
|
||||
* @param {!REQUEST} requestMessage The request message
|
||||
* @param {!MethodDescriptor<REQUEST, RESPONSE>} methodDescriptor Information of
|
||||
* this RPC method
|
||||
* @return {!Promise<RESPONSE>} A promise that resolves to the
|
||||
* response message
|
||||
* @template REQUEST, RESPONSE
|
||||
* @abstract
|
||||
*/
|
||||
GenericClient.prototype.call = function(requestMessage, methodDescriptor) {};
|
||||
|
||||
exports = GenericClient;
|
|
@ -42,6 +42,7 @@ const XhrIo = goog.require('goog.net.XhrIo');
|
|||
const googCrypt = goog.require('goog.crypt.base64');
|
||||
const {Status} = goog.require('grpc.web.Status');
|
||||
const {StreamInterceptor, UnaryInterceptor} = goog.require('grpc.web.Interceptor');
|
||||
const {toObject} = goog.require('goog.collections.maps');
|
||||
|
||||
|
||||
|
||||
|
@ -193,10 +194,13 @@ class GrpcWebClientBase {
|
|||
stream.setResponseDeserializeFn(
|
||||
methodDescriptor.getResponseDeserializeFn());
|
||||
|
||||
xhr.headers.addAll(request.getMetadata());
|
||||
const metadata = request.getMetadata();
|
||||
for(const key in metadata) {
|
||||
xhr.headers.set(key, metadata[key]);
|
||||
}
|
||||
this.processHeaders_(xhr);
|
||||
if (this.suppressCorsPreflight_) {
|
||||
const headerObject = xhr.headers.toObject();
|
||||
const headerObject = toObject(xhr.headers);
|
||||
xhr.headers.clear();
|
||||
path = GrpcWebClientBase.setCorsOverride_(path, headerObject);
|
||||
}
|
||||
|
@ -310,11 +314,11 @@ class GrpcWebClientBase {
|
|||
}
|
||||
xhr.headers.set('X-User-Agent', 'grpc-web-javascript/0.1');
|
||||
xhr.headers.set('X-Grpc-Web', '1');
|
||||
if (xhr.headers.containsKey('deadline')) {
|
||||
const deadline = xhr.headers.get('deadline'); // in ms
|
||||
if (xhr.headers.has('deadline')) {
|
||||
const deadline = Number(xhr.headers.get('deadline')); // in ms
|
||||
const currentTime = (new Date()).getTime();
|
||||
let timeout = Math.round(deadline - currentTime);
|
||||
xhr.headers.remove('deadline');
|
||||
xhr.headers.delete('deadline');
|
||||
if (timeout === Infinity) {
|
||||
// grpc-timeout header defaults to infinity if not set.
|
||||
timeout = 0;
|
||||
|
|
|
@ -24,12 +24,17 @@ const MethodDescriptor = goog.require('grpc.web.MethodDescriptor');
|
|||
const ReadyState = goog.require('goog.net.XmlHttp.ReadyState');
|
||||
const Request = goog.requireType('grpc.web.Request');
|
||||
const RpcError = goog.require('grpc.web.RpcError');
|
||||
const StatusCode = goog.require('grpc.web.StatusCode');
|
||||
const XhrIo = goog.require('goog.testing.net.XhrIo');
|
||||
const googCrypt = goog.require('goog.crypt.base64');
|
||||
const testSuite = goog.require('goog.testing.testSuite');
|
||||
const {StreamInterceptor} = goog.require('grpc.web.Interceptor');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
// This parses to [ { DATA: [4, 5, 6] }, { TRAILER: "a: b" } ]
|
||||
const DEFAULT_RPC_RESPONSE =
|
||||
new Uint8Array([0, 0, 0, 0, 3, 4, 5, 6, 128, 0, 0, 0, 4, 97, 58, 32, 98]);
|
||||
const DEFAULT_RPC_RESPONSE_DATA = [4, 5, 6];
|
||||
const DEFAULT_UNARY_HEADERS =
|
||||
['Content-Type', 'Accept', 'X-User-Agent', 'X-Grpc-Web'];
|
||||
const DEFAULT_UNARY_HEADER_VALUES = [
|
||||
|
@ -47,7 +52,7 @@ testSuite({
|
|||
const xhr = new XhrIo();
|
||||
const client = new GrpcWebClientBase(/* options= */ {}, xhr);
|
||||
const methodDescriptor = createMethodDescriptor((bytes) => {
|
||||
assertElementsEquals([4, 5, 6], [].slice.call(bytes));
|
||||
assertElementsEquals(DEFAULT_RPC_RESPONSE_DATA, [].slice.call(bytes));
|
||||
return new MockReply('value');
|
||||
});
|
||||
|
||||
|
@ -58,10 +63,8 @@ testSuite({
|
|||
assertNull(error);
|
||||
resolve(response);
|
||||
});
|
||||
// This parses to [ { DATA: [4,5,6] }, { TRAILER: "a: b" } ]
|
||||
xhr.simulatePartialResponse(
|
||||
googCrypt.encodeByteArray(new Uint8Array(
|
||||
[0, 0, 0, 0, 3, 4, 5, 6, 128, 0, 0, 0, 4, 97, 58, 32, 98])),
|
||||
googCrypt.encodeByteArray(new Uint8Array(DEFAULT_RPC_RESPONSE)),
|
||||
DEFAULT_RESPONSE_HEADERS);
|
||||
xhr.simulateReadyStateChange(ReadyState.COMPLETE);
|
||||
});
|
||||
|
@ -86,10 +89,8 @@ testSuite({
|
|||
assertNull(error);
|
||||
resolve();
|
||||
});
|
||||
// This parses to [ { DATA: [4,5,6] }, { TRAILER: "a: b" } ]
|
||||
xhr.simulatePartialResponse(
|
||||
googCrypt.encodeByteArray(new Uint8Array(
|
||||
[0, 0, 0, 0, 3, 4, 5, 6, 128, 0, 0, 0, 4, 97, 58, 32, 98])),
|
||||
googCrypt.encodeByteArray(new Uint8Array(DEFAULT_RPC_RESPONSE)),
|
||||
DEFAULT_RESPONSE_HEADERS);
|
||||
xhr.simulateReadyStateChange(ReadyState.COMPLETE);
|
||||
});
|
||||
|
@ -122,11 +123,34 @@ testSuite({
|
|||
assertEquals(3, error.code);
|
||||
},
|
||||
|
||||
async testRpcDeserializationError() {
|
||||
const xhr = new XhrIo();
|
||||
const client = new GrpcWebClientBase(/* options= */ {}, xhr);
|
||||
|
||||
const responseDeserializeFn = () => {
|
||||
throw new Error('Decoding error :)');
|
||||
};
|
||||
const methodDescriptor = createMethodDescriptor(responseDeserializeFn);
|
||||
const error = await new Promise((resolve, reject) => {
|
||||
client.rpcCall(
|
||||
'urlurl', new MockRequest(), /* metadata= */ {}, methodDescriptor,
|
||||
(error, response) => {
|
||||
assertNull(response);
|
||||
resolve(error);
|
||||
});
|
||||
xhr.simulatePartialResponse(
|
||||
googCrypt.encodeByteArray(new Uint8Array(DEFAULT_RPC_RESPONSE)),
|
||||
DEFAULT_RESPONSE_HEADERS);
|
||||
});
|
||||
assertTrue(error instanceof RpcError);
|
||||
assertEquals(StatusCode.INTERNAL, error.code);
|
||||
},
|
||||
|
||||
async testRpcResponseHeader() {
|
||||
const xhr = new XhrIo();
|
||||
const client = new GrpcWebClientBase(/* options= */ {}, xhr);
|
||||
const methodDescriptor = createMethodDescriptor((bytes) => {
|
||||
assertElementsEquals([4, 5, 6], [].slice.call(bytes));
|
||||
assertElementsEquals(DEFAULT_RPC_RESPONSE_DATA, [].slice.call(bytes));
|
||||
return new MockReply('value');
|
||||
});
|
||||
|
||||
|
@ -139,11 +163,8 @@ testSuite({
|
|||
call.on('metadata', (metadata) => {
|
||||
resolve(metadata);
|
||||
});
|
||||
// This parses to [ { DATA: [4,5,6] }, { TRAILER: "a: b" } ]
|
||||
xhr.simulatePartialResponse(
|
||||
googCrypt.encodeByteArray(new Uint8Array(
|
||||
[0, 0, 0, 0, 3, 4, 5, 6, 128, 0, 0, 0, 4, 97, 58, 32, 98])),
|
||||
{
|
||||
googCrypt.encodeByteArray(new Uint8Array(DEFAULT_RPC_RESPONSE)), {
|
||||
'Content-Type': 'application/grpc-web-text',
|
||||
'initial-metadata-key': 'initial-metadata-value',
|
||||
});
|
||||
|
@ -156,7 +177,7 @@ testSuite({
|
|||
const xhr = new XhrIo();
|
||||
const interceptor = new StreamResponseInterceptor();
|
||||
const methodDescriptor = createMethodDescriptor((bytes) => {
|
||||
assertElementsEquals([4, 5, 6], [].slice.call(bytes));
|
||||
assertElementsEquals(DEFAULT_RPC_RESPONSE_DATA, [].slice.call(bytes));
|
||||
return new MockReply('value');
|
||||
});
|
||||
const client =
|
||||
|
@ -169,10 +190,8 @@ testSuite({
|
|||
assertNull(error);
|
||||
resolve(response);
|
||||
});
|
||||
// This parses to [ { DATA: [4,5,6] }, { TRAILER: "a: b" } ]
|
||||
xhr.simulatePartialResponse(
|
||||
googCrypt.encodeByteArray(new Uint8Array(
|
||||
[0, 0, 0, 0, 3, 4, 5, 6, 128, 0, 0, 0, 4, 97, 58, 32, 98])),
|
||||
googCrypt.encodeByteArray(new Uint8Array(DEFAULT_RPC_RESPONSE)),
|
||||
DEFAULT_RESPONSE_HEADERS);
|
||||
xhr.simulateReadyStateChange(ReadyState.COMPLETE);
|
||||
});
|
||||
|
|
|
@ -152,16 +152,16 @@ class GrpcWebClientReadableStream {
|
|||
var byteSource = new Uint8Array(
|
||||
/** @type {!ArrayBuffer} */ (self.xhr_.getResponse()));
|
||||
} else {
|
||||
self.handleError_(new RpcError(
|
||||
StatusCode.UNKNOWN, 'Unknown Content-type received.'));
|
||||
self.handleError_(
|
||||
new RpcError(StatusCode.UNKNOWN, 'Unknown Content-type received.'));
|
||||
return;
|
||||
}
|
||||
var messages = null;
|
||||
try {
|
||||
messages = self.parser_.parse(byteSource);
|
||||
} catch (err) {
|
||||
self.handleError_(new RpcError(
|
||||
StatusCode.UNKNOWN, 'Error in parsing response body'));
|
||||
self.handleError_(
|
||||
new RpcError(StatusCode.UNKNOWN, 'Error in parsing response body'));
|
||||
}
|
||||
if (messages) {
|
||||
var FrameType = GrpcWebStreamParser.FrameType;
|
||||
|
@ -169,15 +169,16 @@ class GrpcWebClientReadableStream {
|
|||
if (FrameType.DATA in messages[i]) {
|
||||
var data = messages[i][FrameType.DATA];
|
||||
if (data) {
|
||||
let response;
|
||||
try {
|
||||
var response = self.responseDeserializeFn_(data);
|
||||
if (response) {
|
||||
self.sendDataCallbacks_(response);
|
||||
}
|
||||
response = self.responseDeserializeFn_(data);
|
||||
} catch (err) {
|
||||
self.handleError_(new RpcError(
|
||||
StatusCode.UNKNOWN,
|
||||
'Error in response deserializer function.'));
|
||||
StatusCode.INTERNAL,
|
||||
`Error when deserializing response data: ${response}`));
|
||||
}
|
||||
if (response) {
|
||||
self.sendDataCallbacks_(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -193,15 +194,16 @@ class GrpcWebClientReadableStream {
|
|||
var grpcStatusCode = StatusCode.OK;
|
||||
var grpcStatusMessage = '';
|
||||
if (GRPC_STATUS in trailers) {
|
||||
grpcStatusCode = trailers[GRPC_STATUS];
|
||||
grpcStatusCode =
|
||||
/** @type {!StatusCode} */ (Number(trailers[GRPC_STATUS]));
|
||||
delete trailers[GRPC_STATUS];
|
||||
}
|
||||
if (GRPC_STATUS_MESSAGE in trailers) {
|
||||
grpcStatusMessage = trailers[GRPC_STATUS_MESSAGE];
|
||||
delete trailers[GRPC_STATUS_MESSAGE];
|
||||
}
|
||||
self.handleError_(new RpcError(
|
||||
Number(grpcStatusCode), grpcStatusMessage, trailers));
|
||||
self.handleError_(
|
||||
new RpcError(grpcStatusCode, grpcStatusMessage, trailers));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -210,7 +212,7 @@ class GrpcWebClientReadableStream {
|
|||
|
||||
events.listen(this.xhr_, EventType.COMPLETE, function(e) {
|
||||
var lastErrorCode = self.xhr_.getLastErrorCode();
|
||||
var grpcStatusCode;
|
||||
var grpcStatusCode = StatusCode.UNKNOWN;
|
||||
var grpcStatusMessage = '';
|
||||
var initialMetadata = /** @type {!Metadata} */ ({});
|
||||
|
||||
|
@ -249,14 +251,14 @@ class GrpcWebClientReadableStream {
|
|||
|
||||
// Check whethere there are grpc specific response headers
|
||||
if (GRPC_STATUS in responseHeaders) {
|
||||
grpcStatusCode = self.xhr_.getResponseHeader(GRPC_STATUS);
|
||||
grpcStatusCode = /** @type {!StatusCode} */ (
|
||||
Number(self.xhr_.getResponseHeader(GRPC_STATUS)));
|
||||
if (GRPC_STATUS_MESSAGE in responseHeaders) {
|
||||
grpcStatusMessage = self.xhr_.getResponseHeader(GRPC_STATUS_MESSAGE);
|
||||
}
|
||||
if (Number(grpcStatusCode) != StatusCode.OK) {
|
||||
if (grpcStatusCode != StatusCode.OK) {
|
||||
self.handleError_(new RpcError(
|
||||
Number(grpcStatusCode), grpcStatusMessage || '',
|
||||
responseHeaders));
|
||||
grpcStatusCode, grpcStatusMessage || '', responseHeaders));
|
||||
errorEmitted = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,16 +26,21 @@
|
|||
goog.module('grpc.web.RpcError');
|
||||
|
||||
const Metadata = goog.require('grpc.web.Metadata');
|
||||
const StatusCode = goog.require('grpc.web.StatusCode');
|
||||
|
||||
/**
|
||||
* gRPC-Web Error object, contains the {@link StatusCode}, a string message
|
||||
* and {@link Metadata} contained in the error response.
|
||||
*/
|
||||
class RpcError extends Error {
|
||||
/**
|
||||
* @param {number} code
|
||||
* @param {!StatusCode} code
|
||||
* @param {string} message
|
||||
* @param {!Metadata=} metadata
|
||||
*/
|
||||
constructor(code, message, metadata = {}) {
|
||||
super(message);
|
||||
/** @type {number} */
|
||||
/** @type {!StatusCode} */
|
||||
this.code = code;
|
||||
/** @type {!Metadata} */
|
||||
this.metadata = metadata;
|
||||
|
|
|
@ -23,11 +23,9 @@
|
|||
* @author stanleycheung@google.com (Stanley Cheung)
|
||||
*/
|
||||
goog.module('grpc.web.Status');
|
||||
|
||||
goog.module.declareLegacyNamespace();
|
||||
|
||||
|
||||
|
||||
/** @record */
|
||||
function Status() {}
|
||||
|
||||
|
|
|
@ -26,7 +26,8 @@ goog.module('grpc.web.StatusCode');
|
|||
|
||||
/**
|
||||
* gRPC Status Codes
|
||||
* See: https://github.com/grpc/grpc/blob/master/include/grpc%2B%2B/impl/codegen/status_code_enum.h
|
||||
* See:
|
||||
* https://github.com/grpc/grpc/blob/master/include/grpcpp/impl/codegen/status_code_enum.h
|
||||
* @enum {number}
|
||||
*/
|
||||
const StatusCode = {
|
||||
|
@ -140,11 +141,11 @@ const StatusCode = {
|
|||
|
||||
/**
|
||||
* Convert HTTP Status code to gRPC Status code
|
||||
* @param {number} http_status HTTP Status Code
|
||||
* @return {number} gRPC Status Code
|
||||
* @param {number} httpStatus HTTP Status Code
|
||||
* @return {!StatusCode} gRPC Status Code
|
||||
*/
|
||||
StatusCode.fromHttpStatus = function(http_status) {
|
||||
switch (http_status) {
|
||||
StatusCode.fromHttpStatus = function(httpStatus) {
|
||||
switch (httpStatus) {
|
||||
case 200:
|
||||
return StatusCode.OK;
|
||||
case 400:
|
||||
|
@ -178,4 +179,44 @@ StatusCode.fromHttpStatus = function(http_status) {
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* Convert a {@link StatusCode} to an HTTP Status code
|
||||
* @param {!StatusCode} statusCode GRPC Status Code
|
||||
* @return {number} HTTP Status code
|
||||
*/
|
||||
StatusCode.getHttpStatus = function(statusCode) {
|
||||
switch (statusCode) {
|
||||
case StatusCode.OK:
|
||||
return 200;
|
||||
case StatusCode.INVALID_ARGUMENT:
|
||||
return 400;
|
||||
case StatusCode.UNAUTHENTICATED:
|
||||
return 401;
|
||||
case StatusCode.PERMISSION_DENIED:
|
||||
return 403;
|
||||
case StatusCode.NOT_FOUND:
|
||||
return 404;
|
||||
case StatusCode.ABORTED:
|
||||
return 409;
|
||||
case StatusCode.FAILED_PRECONDITION:
|
||||
return 412;
|
||||
case StatusCode.RESOURCE_EXHAUSTED:
|
||||
return 429;
|
||||
case StatusCode.CANCELLED:
|
||||
return 499;
|
||||
case StatusCode.UNKNOWN:
|
||||
return 500;
|
||||
case StatusCode.UNIMPLEMENTED:
|
||||
return 501;
|
||||
case StatusCode.UNAVAILABLE:
|
||||
return 503;
|
||||
case StatusCode.DEADLINE_EXCEEDED:
|
||||
return 504;
|
||||
/* everything else is unknown */
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
exports = StatusCode;
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
goog.module('grpc.web.StatusCodeTest');
|
||||
goog.setTestOnly('grpc.web.StatusCodeTest');
|
||||
|
||||
const StatusCode = goog.require('grpc.web.StatusCode');
|
||||
const testSuite = goog.require('goog.testing.testSuite');
|
||||
|
||||
|
||||
/** @type {!Map<number, !StatusCode>} */
|
||||
const statusMap = new Map([
|
||||
[200, StatusCode.OK],
|
||||
[400, StatusCode.INVALID_ARGUMENT],
|
||||
[401, StatusCode.UNAUTHENTICATED],
|
||||
[403, StatusCode.PERMISSION_DENIED],
|
||||
[404, StatusCode.NOT_FOUND],
|
||||
[409, StatusCode.ABORTED],
|
||||
[412, StatusCode.FAILED_PRECONDITION],
|
||||
[429, StatusCode.RESOURCE_EXHAUSTED],
|
||||
[500, StatusCode.UNKNOWN],
|
||||
[501, StatusCode.UNIMPLEMENTED],
|
||||
[503, StatusCode.UNAVAILABLE],
|
||||
[504, StatusCode.DEADLINE_EXCEEDED],
|
||||
]);
|
||||
|
||||
testSuite({
|
||||
testFromHttpStatus() {
|
||||
statusMap.forEach((statusCode, httpStatus) => {
|
||||
assertEquals(StatusCode.fromHttpStatus(httpStatus), statusCode);
|
||||
});
|
||||
},
|
||||
|
||||
testGetHttpStatus() {
|
||||
statusMap.forEach((statusCode, httpStatus) => {
|
||||
assertEquals(StatusCode.getHttpStatus(statusCode), httpStatus);
|
||||
});
|
||||
},
|
||||
|
||||
testUnknown() {
|
||||
assertEquals(StatusCode.getHttpStatus(StatusCode.UNKNOWN), 500);
|
||||
assertEquals(StatusCode.fromHttpStatus(511), StatusCode.UNKNOWN);
|
||||
}
|
||||
});
|
|
@ -73,11 +73,10 @@ WORKDIR /github/grpc-web
|
|||
# Copy only files necessary to build the protoc-gen-grpc-web first as an optimization because they
|
||||
# are rarely updated compared with the javascript files.
|
||||
COPY ./WORKSPACE ./WORKSPACE
|
||||
COPY ./javascript/net/grpc/web/grpc_generator.cc javascript/net/grpc/web/grpc_generator.cc
|
||||
COPY ./javascript/net/grpc/web/BUILD.bazel javascript/net/grpc/web/BUILD.bazel
|
||||
COPY ./javascript/net/grpc/web/generator javascript/net/grpc/web/generator
|
||||
|
||||
RUN bazel build javascript/net/grpc/web:protoc-gen-grpc-web && \
|
||||
cp $(bazel info bazel-genfiles)/javascript/net/grpc/web/protoc-gen-grpc-web \
|
||||
RUN bazel build javascript/net/grpc/web/generator:protoc-gen-grpc-web && \
|
||||
cp $(bazel info bazel-genfiles)/javascript/net/grpc/web/generator/protoc-gen-grpc-web \
|
||||
/usr/local/bin/protoc-gen-grpc-web
|
||||
|
||||
COPY ./javascript ./javascript
|
||||
|
|
|
@ -32,5 +32,5 @@ WORKDIR /github/grpc-web
|
|||
RUN cd ./third_party/protobuf && \
|
||||
./autogen.sh && ./configure && make && make install && ldconfig
|
||||
|
||||
RUN cd ./javascript/net/grpc/web && \
|
||||
RUN cd ./javascript/net/grpc/web/generator && \
|
||||
make protoc-gen-grpc-web
|
||||
|
|
|
@ -6,6 +6,6 @@
|
|||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"google-closure-compiler": "~20200224.0.0",
|
||||
"google-closure-library": "~20201102.0.1"
|
||||
"google-closure-library": "~20210808.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -376,8 +376,8 @@ describe('grpc-web generated code (commonjs+grpcwebtext)', function() {
|
|||
if (response) {
|
||||
assert.fail('should not receive response');
|
||||
}
|
||||
assert.equal(2, err.code);
|
||||
assert.equal(true, err.message.toLowerCase().includes('deserialize'));
|
||||
assert.equal(13 /* StatusCode.INTERNAL */, err.code);
|
||||
assert.equal(true, err.message.toLowerCase().includes('deserializing'));
|
||||
assert.equal(true, err.message.toLowerCase().includes('error'));
|
||||
done();
|
||||
});
|
||||
|
|
|
@ -16,7 +16,7 @@ in Docker Desktop for Mac (e.g. to 4 - 6GB) if you see the following errors:
|
|||
|
||||
|
||||
```
|
||||
$ bazel test --cache_test_results=no //javascript/net/grpc/web/... //net/grpc/gateway/examples/...
|
||||
$ bazel build //javascript/net/grpc/web/generator/... //net/grpc/gateway/examples/echo/...
|
||||
|
||||
...
|
||||
|
||||
|
|
|
@ -21,5 +21,5 @@ set -ex
|
|||
cd /github/grpc-web && \
|
||||
bazel clean && \
|
||||
bazel build \
|
||||
//javascript/net/grpc/web/... \
|
||||
//net/grpc/gateway/examples/...
|
||||
//javascript/net/grpc/web/generator/... \
|
||||
//net/grpc/gateway/examples/echo/...
|
||||
|
|
Loading…
Reference in New Issue