diff --git a/bazel/grpc_build_system.bzl b/bazel/grpc_build_system.bzl index 23f90d0dc806a05ea11005fae9619ad7237232b9..f386b87b583c13879b84c167feff947efbcaa755 100644 --- a/bazel/grpc_build_system.bzl +++ b/bazel/grpc_build_system.bzl @@ -24,6 +24,7 @@ # load("//bazel:cc_grpc_library.bzl", "cc_grpc_library") +load("@build_bazel_rules_apple//apple:resources.bzl", "apple_resource_bundle") load("@upb//bazel:upb_proto_library.bzl", "upb_proto_library") load("@build_bazel_rules_apple//apple:ios.bzl", "ios_unit_test") @@ -238,13 +239,19 @@ def grpc_cc_binary(name, srcs = [], deps = [], external_deps = [], args = [], da ) def grpc_generate_one_off_targets(): + apple_resource_bundle( + # The choice of name is signicant here, since it determines the bundle name. + name = "gRPCCertificates", + resources = ["etc/roots.pem"], + ) + # In open-source, grpc_objc* libraries depend directly on //:grpc native.alias( name = "grpc_objc", actual = "//:grpc", ) -def grpc_generate_objc_one_off_targets(): +def grpc_objc_use_cronet_config(): pass def grpc_sh_test(name, srcs, args = [], data = []): @@ -289,7 +296,7 @@ def grpc_package(name, visibility = "private", features = []): def grpc_objc_library( name, - srcs = [], + srcs, hdrs = [], textual_hdrs = [], data = [], diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec index 4c5ebb36562c64cdc04f99192fa5d965b098078d..57dac5a10e52d240a81563f87bdff2dd6818a5e1 100644 --- a/gRPC-ProtoRPC.podspec +++ b/gRPC-ProtoRPC.podspec @@ -42,40 +42,22 @@ Pod::Spec.new do |s| s.module_name = name s.header_dir = name - s.default_subspec = 'Main', 'Legacy', 'Legacy-Header' + src_dir = 'src/objective-c/ProtoRPC' - s.subspec 'Legacy-Header' do |ss| - ss.header_mappings_dir = "src/objective-c/ProtoRPC" - ss.public_header_files = "src/objective-c/ProtoRPC/ProtoRPCLegacy.h" - ss.source_files = "src/objective-c/ProtoRPC/ProtoRPCLegacy.h" - end + s.default_subspec = 'Main' s.subspec 'Main' do |ss| - ss.header_mappings_dir = "src/objective-c/ProtoRPC" - ss.dependency "#{s.name}/Legacy-Header", version - ss.dependency 'gRPC/Interface', version - ss.dependency 'Protobuf', '~> 3.0' - - ss.source_files = "src/objective-c/ProtoRPC/ProtoMethod.{h,m}", - "src/objective-c/ProtoRPC/ProtoRPC.{h,m}", - "src/objective-c/ProtoRPC/ProtoService.{h,m}" - end - - s.subspec 'Legacy' do |ss| - ss.header_mappings_dir = "src/objective-c/ProtoRPC" - ss.dependency "#{s.name}/Main", version - ss.dependency "#{s.name}/Legacy-Header", version - ss.dependency 'gRPC/GRPCCore', version + ss.header_mappings_dir = "#{src_dir}" + ss.dependency 'gRPC', version ss.dependency 'gRPC-RxLibrary', version ss.dependency 'Protobuf', '~> 3.0' - ss.source_files = "src/objective-c/ProtoRPC/ProtoRPCLegacy.m", - "src/objective-c/ProtoRPC/ProtoServiceLegacy.m" + ss.source_files = "#{src_dir}/*.{h,m}" end # CFStream is now default. Leaving this subspec only for compatibility purpose. s.subspec 'CFStream' do |ss| - ss.dependency "#{s.name}/Legacy", version + ss.dependency "#{s.name}/Main", version end s.pod_target_xcconfig = { diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec index 2e412cf67d69112f12f9a945f71facbda4381b11..9666c3c1b98a139263d9a8e2795c2a9caaf1f99d 100644 --- a/gRPC-RxLibrary.podspec +++ b/gRPC-RxLibrary.podspec @@ -42,23 +42,6 @@ Pod::Spec.new do |s| s.module_name = name s.header_dir = name - s.default_subspec = 'Interface', 'Implementation' - - src_dir = 'src/objective-c/RxLibrary' - s.subspec 'Interface' do |ss| - ss.header_mappings_dir = "#{src_dir}" - ss.source_files = "#{src_dir}/*.h" - ss.public_header_files = "#{src_dir}/*.h" - end - - s.subspec 'Implementation' do |ss| - ss.header_mappings_dir = "#{src_dir}" - ss.source_files = "#{src_dir}/*.m", "#{src_dir}/**/*.{h,m}" - ss.private_header_files = "#{src_dir}/**/*.h" - - ss.dependency "#{s.name}/Interface" - end - src_dir = 'src/objective-c/RxLibrary' s.source_files = "#{src_dir}/*.{h,m}", "#{src_dir}/**/*.{h,m}" s.private_header_files = "#{src_dir}/private/*.h" diff --git a/gRPC.podspec b/gRPC.podspec index e18adcd276e8d3fca1c9b8a4a9ddeff045a1673e..09baf1e3b4b21b5f3428afca4b4f35f96446112a 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -41,7 +41,13 @@ Pod::Spec.new do |s| s.module_name = name s.header_dir = name - s.default_subspec = 'Interface', 'GRPCCore', 'Interface-Legacy' + src_dir = 'src/objective-c/GRPCClient' + + s.dependency 'gRPC-RxLibrary', version + s.default_subspec = 'Main' + + # Certificates, to be able to establish TLS connections: + s.resource_bundles = { 'gRPCCertificates' => ['etc/roots.pem'] } s.pod_target_xcconfig = { # This is needed by all pods that depend on gRPC-RxLibrary: @@ -49,103 +55,29 @@ Pod::Spec.new do |s| 'CLANG_WARN_STRICT_PROTOTYPES' => 'NO', } - s.subspec 'Interface-Legacy' do |ss| - ss.header_mappings_dir = 'src/objective-c/GRPCClient' - - ss.public_header_files = "GRPCClient/GRPCCall+ChannelArg.h", - "GRPCClient/GRPCCall+ChannelCredentials.h", - "GRPCClient/GRPCCall+Cronet.h", - "GRPCClient/GRPCCall+OAuth2.h", - "GRPCClient/GRPCCall+Tests.h", - "src/objective-c/GRPCClient/GRPCCallLegacy.h", - "src/objective-c/GRPCClient/GRPCTypes.h" - - ss.source_files = "GRPCClient/GRPCCall+ChannelArg.h", - "GRPCClient/GRPCCall+ChannelCredentials.h", - "GRPCClient/GRPCCall+Cronet.h", - "GRPCClient/GRPCCall+OAuth2.h", - "GRPCClient/GRPCCall+Tests.h", - "src/objective-c/GRPCClient/GRPCCallLegacy.h", - "src/objective-c/GRPCClient/GRPCTypes.h" - ss.dependency "gRPC-RxLibrary/Interface", version - end + s.subspec 'Main' do |ss| + ss.header_mappings_dir = "#{src_dir}" - s.subspec 'Interface' do |ss| - ss.header_mappings_dir = 'src/objective-c/GRPCClient' - - ss.public_header_files = 'src/objective-c/GRPCClient/GRPCCall.h', - 'src/objective-c/GRPCClient/GRPCCall+Interceptor.h', - 'src/objective-c/GRPCClient/GRPCCallOptions.h', - 'src/objective-c/GRPCClient/GRPCInterceptor.h', - 'src/objective-c/GRPCClient/GRPCTransport.h', - 'src/objective-c/GRPCClient/GRPCDispatchable.h', - 'src/objective-c/GRPCClient/version.h' - - ss.source_files = 'src/objective-c/GRPCClient/GRPCCall.h', - 'src/objective-c/GRPCClient/GRPCCall.m', - 'src/objective-c/GRPCClient/GRPCCall+Interceptor.h', - 'src/objective-c/GRPCClient/GRPCCall+Interceptor.m', - 'src/objective-c/GRPCClient/GRPCCallOptions.h', - 'src/objective-c/GRPCClient/GRPCCallOptions.m', - 'src/objective-c/GRPCClient/GRPCDispatchable.h', - 'src/objective-c/GRPCClient/GRPCInterceptor.h', - 'src/objective-c/GRPCClient/GRPCInterceptor.m', - 'src/objective-c/GRPCClient/GRPCTransport.h', - 'src/objective-c/GRPCClient/GRPCTransport.m', - 'src/objective-c/GRPCClient/internal/*.h', - 'src/objective-c/GRPCClient/private/GRPCTransport+Private.h', - 'src/objective-c/GRPCClient/private/GRPCTransport+Private.m', - 'src/objective-c/GRPCClient/version.h' - - ss.dependency "#{s.name}/Interface-Legacy", version - end + ss.source_files = "#{src_dir}/*.{h,m}", "#{src_dir}/**/*.{h,m}" + ss.exclude_files = "#{src_dir}/GRPCCall+GID.{h,m}" + ss.private_header_files = "#{src_dir}/private/*.h", "#{src_dir}/internal/*.h" - s.subspec 'GRPCCore' do |ss| - ss.header_mappings_dir = 'src/objective-c/GRPCClient' - - ss.public_header_files = 'src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h', - 'src/objective-c/GRPCClient/GRPCCall+Cronet.h', - 'src/objective-c/GRPCClient/GRPCCall+OAuth2.h', - 'src/objective-c/GRPCClient/GRPCCall+Tests.h', - 'src/objective-c/GRPCClient/GRPCCall+ChannelArg.h', - 'src/objective-c/GRPCClient/internal_testing/*.h' - ss.private_header_files = 'src/objective-c/GRPCClient/private/GRPCCore/*.h' - ss.source_files = 'src/objective-c/GRPCClient/internal_testing/*.{h,m}', - 'src/objective-c/GRPCClient/private/GRPCCore/*.{h,m}', - 'src/objective-c/GRPCClient/GRPCCall+ChannelArg.h', - 'src/objective-c/GRPCClient/GRPCCall+ChannelArg.m', - 'src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h', - 'src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.m', - 'src/objective-c/GRPCClient/GRPCCall+Cronet.h', - 'src/objective-c/GRPCClient/GRPCCall+Cronet.m', - 'src/objective-c/GRPCClient/GRPCCall+OAuth2.h', - 'src/objective-c/GRPCClient/GRPCCall+OAuth2.m', - 'src/objective-c/GRPCClient/GRPCCall+Tests.h', - 'src/objective-c/GRPCClient/GRPCCall+Tests.m', - 'src/objective-c/GRPCClient/GRPCCallLegacy.m' - - # Certificates, to be able to establish TLS connections: - ss.resource_bundles = { 'gRPCCertificates' => ['etc/roots.pem'] } - - ss.dependency "#{s.name}/Interface-Legacy", version - ss.dependency "#{s.name}/Interface", version ss.dependency 'gRPC-Core', version - ss.dependency 'gRPC-RxLibrary', version - end - - s.subspec 'GRPCCoreCronet' do |ss| - ss.header_mappings_dir = 'src/objective-c/GRPCClient' - - ss.source_files = 'src/objective-c/GRPCClient/GRPCCall+Cronet.h', - 'src/objective-c/GRPCClient/GRPCCall+Cronet.m', - 'src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/*.{h,m}' - ss.dependency "#{s.name}/GRPCCore", version - ss.dependency 'gRPC-Core/Cronet-Implementation', version - ss.dependency 'CronetFramework' end # CFStream is now default. Leaving this subspec only for compatibility purpose. s.subspec 'CFStream' do |ss| - ss.dependency "#{s.name}/GRPCCore", version + ss.dependency "#{s.name}/Main", version + end + + s.subspec 'GID' do |ss| + ss.ios.deployment_target = '7.0' + + ss.header_mappings_dir = "#{src_dir}" + + ss.source_files = "#{src_dir}/GRPCCall+GID.{h,m}" + + ss.dependency "#{s.name}/Main", version + ss.dependency 'Google/SignIn' end end diff --git a/src/compiler/objective_c_generator.cc b/src/compiler/objective_c_generator.cc index ed262308aba9123974c1b20df0408136ecb65e3a..24845ecdb06622773a41cc92be2d9b60cd250f9b 100644 --- a/src/compiler/objective_c_generator.cc +++ b/src/compiler/objective_c_generator.cc @@ -238,21 +238,19 @@ void PrintV2Implementation(Printer* printer, const MethodDescriptor* method, } void PrintMethodImplementations(Printer* printer, - const MethodDescriptor* method, - const Parameters& generator_params) { + const MethodDescriptor* method) { map< ::grpc::string, ::grpc::string> vars = GetMethodVars(method); PrintProtoRpcDeclarationAsPragma(printer, method, vars); - if (!generator_params.no_v1_compatibility) { - // TODO(jcanizales): Print documentation from the method. - PrintSimpleSignature(printer, method, vars); - PrintSimpleImplementation(printer, method, vars); + // TODO(jcanizales): Print documentation from the method. + printer->Print("// Deprecated methods.\n"); + PrintSimpleSignature(printer, method, vars); + PrintSimpleImplementation(printer, method, vars); - printer->Print("// Returns a not-yet-started RPC object.\n"); - PrintAdvancedSignature(printer, method, vars); - PrintAdvancedImplementation(printer, method, vars); - } + printer->Print("// Returns a not-yet-started RPC object.\n"); + PrintAdvancedSignature(printer, method, vars); + PrintAdvancedImplementation(printer, method, vars); PrintV2Signature(printer, method, vars); PrintV2Implementation(printer, method, vars); @@ -278,12 +276,9 @@ void PrintMethodImplementations(Printer* printer, return output; } -::grpc::string GetProtocol(const ServiceDescriptor* service, - const Parameters& generator_params) { +::grpc::string GetProtocol(const ServiceDescriptor* service) { ::grpc::string output; - if (generator_params.no_v1_compatibility) return output; - // Scope the output stream so it closes and finalizes output to the string. grpc::protobuf::io::StringOutputStream output_stream(&output); Printer printer(&output_stream, '$'); @@ -326,8 +321,7 @@ void PrintMethodImplementations(Printer* printer, return output; } -::grpc::string GetInterface(const ServiceDescriptor* service, - const Parameters& generator_params) { +::grpc::string GetInterface(const ServiceDescriptor* service) { ::grpc::string output; // Scope the output stream so it closes and finalizes output to the string. @@ -344,11 +338,7 @@ void PrintMethodImplementations(Printer* printer, " */\n"); printer.Print(vars, "@interface $service_class$ :" - " GRPCProtoService<$service_class$2"); - if (!generator_params.no_v1_compatibility) { - printer.Print(vars, ", $service_class$"); - } - printer.Print(">\n"); + " GRPCProtoService<$service_class$, $service_class$2>\n"); printer.Print( "- (instancetype)initWithHost:(NSString *)host " "callOptions:(GRPCCallOptions " @@ -357,20 +347,17 @@ void PrintMethodImplementations(Printer* printer, printer.Print( "+ (instancetype)serviceWithHost:(NSString *)host " "callOptions:(GRPCCallOptions *_Nullable)callOptions;\n"); - if (!generator_params.no_v1_compatibility) { - printer.Print( - "// The following methods belong to a set of old APIs that have been " - "deprecated.\n"); - printer.Print("- (instancetype)initWithHost:(NSString *)host;\n"); - printer.Print("+ (instancetype)serviceWithHost:(NSString *)host;\n"); - } + printer.Print( + "// The following methods belong to a set of old APIs that have been " + "deprecated.\n"); + printer.Print("- (instancetype)initWithHost:(NSString *)host;\n"); + printer.Print("+ (instancetype)serviceWithHost:(NSString *)host;\n"); printer.Print("@end\n"); return output; } -::grpc::string GetSource(const ServiceDescriptor* service, - const Parameters& generator_params) { +::grpc::string GetSource(const ServiceDescriptor* service) { ::grpc::string output; { // Scope the output stream so it closes and finalizes output to the string. @@ -394,28 +381,22 @@ void PrintMethodImplementations(Printer* printer, " packageName:@\"$package$\"\n" " serviceName:@\"$service_name$\"\n" " callOptions:callOptions];\n" - "}\n\n"); - if (!generator_params.no_v1_compatibility) { - printer.Print(vars, - "- (instancetype)initWithHost:(NSString *)host {\n" - " return [super initWithHost:host\n" - " packageName:@\"$package$\"\n" - " serviceName:@\"$service_name$\"];\n" - "}\n\n"); - } - printer.Print("#pragma clang diagnostic pop\n\n"); - - if (!generator_params.no_v1_compatibility) { - printer.Print( - "// Override superclass initializer to disallow different" - " package and service names.\n" - "- (instancetype)initWithHost:(NSString *)host\n" - " packageName:(NSString *)packageName\n" - " serviceName:(NSString *)serviceName {\n" - " return [self initWithHost:host];\n" - "}\n\n"); - } + "}\n\n" + "- (instancetype)initWithHost:(NSString *)host {\n" + " return [super initWithHost:host\n" + " packageName:@\"$package$\"\n" + " serviceName:@\"$service_name$\"];\n" + "}\n\n" + "#pragma clang diagnostic pop\n\n"); + printer.Print( + "// Override superclass initializer to disallow different" + " package and service names.\n" + "- (instancetype)initWithHost:(NSString *)host\n" + " packageName:(NSString *)packageName\n" + " serviceName:(NSString *)serviceName {\n" + " return [self initWithHost:host];\n" + "}\n\n" "- (instancetype)initWithHost:(NSString *)host\n" " packageName:(NSString *)packageName\n" " serviceName:(NSString *)serviceName\n" @@ -423,14 +404,11 @@ void PrintMethodImplementations(Printer* printer, " return [self initWithHost:host callOptions:callOptions];\n" "}\n\n"); - printer.Print("#pragma mark - Class Methods\n\n"); - if (!generator_params.no_v1_compatibility) { - printer.Print( - "+ (instancetype)serviceWithHost:(NSString *)host {\n" - " return [[self alloc] initWithHost:host];\n" - "}\n\n"); - } printer.Print( + "#pragma mark - Class Methods\n\n" + "+ (instancetype)serviceWithHost:(NSString *)host {\n" + " return [[self alloc] initWithHost:host];\n" + "}\n\n" "+ (instancetype)serviceWithHost:(NSString *)host " "callOptions:(GRPCCallOptions *_Nullable)callOptions {\n" " return [[self alloc] initWithHost:host callOptions:callOptions];\n" @@ -439,8 +417,7 @@ void PrintMethodImplementations(Printer* printer, printer.Print("#pragma mark - Method Implementations\n\n"); for (int i = 0; i < service->method_count(); i++) { - PrintMethodImplementations(&printer, service->method(i), - generator_params); + PrintMethodImplementations(&printer, service->method(i)); } printer.Print("@end\n"); diff --git a/src/compiler/objective_c_generator.h b/src/compiler/objective_c_generator.h index 518962fceee26ab928ed1dc6385ab8b2435662af..c171e5bf772daa67752f093e2b890adc1b2b0952 100644 --- a/src/compiler/objective_c_generator.h +++ b/src/compiler/objective_c_generator.h @@ -23,11 +23,6 @@ namespace grpc_objective_c_generator { -struct Parameters { - // Do not generate V1 interface and implementation - bool no_v1_compatibility; -}; - using ::grpc::protobuf::FileDescriptor; using ::grpc::protobuf::FileDescriptor; using ::grpc::protobuf::ServiceDescriptor; @@ -39,8 +34,7 @@ string GetAllMessageClasses(const FileDescriptor* file); // Returns the content to be included defining the @protocol segment at the // insertion point of the generated implementation file. This interface is // legacy and for backwards compatibility. -string GetProtocol(const ServiceDescriptor* service, - const Parameters& generator_params); +string GetProtocol(const ServiceDescriptor* service); // Returns the content to be included defining the @protocol segment at the // insertion point of the generated implementation file. @@ -48,13 +42,11 @@ string GetV2Protocol(const ServiceDescriptor* service); // Returns the content to be included defining the @interface segment at the // insertion point of the generated implementation file. -string GetInterface(const ServiceDescriptor* service, - const Parameters& generator_params); +string GetInterface(const ServiceDescriptor* service); // Returns the content to be included in the "global_scope" insertion point of // the generated implementation file. -string GetSource(const ServiceDescriptor* service, - const Parameters& generator_params); +string GetSource(const ServiceDescriptor* service); } // namespace grpc_objective_c_generator diff --git a/src/compiler/objective_c_plugin.cc b/src/compiler/objective_c_plugin.cc index a08064a08bd60b44be64978e23434b0a965531b9..f398033f6db4c8ea44d1d04214f84f91980faecc 100644 --- a/src/compiler/objective_c_plugin.cc +++ b/src/compiler/objective_c_plugin.cc @@ -111,22 +111,6 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { ::grpc::string file_name = google::protobuf::compiler::objectivec::FilePath(file); - grpc_objective_c_generator::Parameters generator_params; - generator_params.no_v1_compatibility = false; - - if (!parameter.empty()) { - std::vector<grpc::string> parameters_list = - grpc_generator::tokenize(parameter, ","); - for (auto parameter_string = parameters_list.begin(); - parameter_string != parameters_list.end(); parameter_string++) { - std::vector<grpc::string> param = - grpc_generator::tokenize(*parameter_string, "="); - if (param[0] == "no_v1_compatibility") { - generator_params.no_v1_compatibility = true; - } - } - } - { // Generate .pbrpc.h @@ -137,25 +121,18 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { imports = FrameworkImport(file_name + ".pbobjc.h", framework); } - ::grpc::string system_imports = - SystemImport("ProtoRPC/ProtoService.h") + - (generator_params.no_v1_compatibility - ? SystemImport("ProtoRPC/ProtoRPC.h") - : SystemImport("ProtoRPC/ProtoRPCLegacy.h")); - if (!generator_params.no_v1_compatibility) { - system_imports += SystemImport("RxLibrary/GRXWriteable.h") + - SystemImport("RxLibrary/GRXWriter.h"); - } + ::grpc::string system_imports = SystemImport("ProtoRPC/ProtoService.h") + + SystemImport("ProtoRPC/ProtoRPC.h") + + SystemImport("RxLibrary/GRXWriteable.h") + + SystemImport("RxLibrary/GRXWriter.h"); ::grpc::string forward_declarations = + "@class GRPCProtoCall;\n" "@class GRPCUnaryProtoCall;\n" "@class GRPCStreamingProtoCall;\n" "@class GRPCCallOptions;\n" - "@protocol GRPCProtoResponseHandler;\n"; - if (!generator_params.no_v1_compatibility) { - forward_declarations += "@class GRPCProtoCall;\n"; - } - forward_declarations += "\n"; + "@protocol GRPCProtoResponseHandler;\n" + "\n"; ::grpc::string class_declarations = grpc_objective_c_generator::GetAllMessageClasses(file); @@ -175,15 +152,13 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { ::grpc::string protocols; for (int i = 0; i < file->service_count(); i++) { const grpc::protobuf::ServiceDescriptor* service = file->service(i); - protocols += - grpc_objective_c_generator::GetProtocol(service, generator_params); + protocols += grpc_objective_c_generator::GetProtocol(service); } ::grpc::string interfaces; for (int i = 0; i < file->service_count(); i++) { const grpc::protobuf::ServiceDescriptor* service = file->service(i); - interfaces += - grpc_objective_c_generator::GetInterface(service, generator_params); + interfaces += grpc_objective_c_generator::GetInterface(service); } Write(context, file_name + ".pbrpc.h", @@ -203,16 +178,14 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { ::grpc::string imports; if (framework.empty()) { imports = LocalImport(file_name + ".pbrpc.h") + - LocalImport(file_name + ".pbobjc.h"); + LocalImport(file_name + ".pbobjc.h") + + SystemImport("ProtoRPC/ProtoRPC.h") + + SystemImport("RxLibrary/GRXWriter+Immediate.h"); } else { imports = FrameworkImport(file_name + ".pbrpc.h", framework) + - FrameworkImport(file_name + ".pbobjc.h", framework); - } - imports += (generator_params.no_v1_compatibility - ? SystemImport("ProtoRPC/ProtoRPC.h") - : SystemImport("ProtoRPC/ProtoRPCLegacy.h")); - if (!generator_params.no_v1_compatibility) { - imports += SystemImport("RxLibrary/GRXWriter+Immediate.h"); + FrameworkImport(file_name + ".pbobjc.h", framework) + + SystemImport("ProtoRPC/ProtoRPC.h") + + SystemImport("RxLibrary/GRXWriter+Immediate.h"); } ::grpc::string class_imports; @@ -223,8 +196,7 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { ::grpc::string definitions; for (int i = 0; i < file->service_count(); i++) { const grpc::protobuf::ServiceDescriptor* service = file->service(i); - definitions += - grpc_objective_c_generator::GetSource(service, generator_params); + definitions += grpc_objective_c_generator::GetSource(service); } Write(context, file_name + ".pbrpc.m", diff --git a/src/objective-c/BUILD b/src/objective-c/BUILD index 5f53486d17eeb1040ceaec6a0844ed7975d6ebb8..3a71086f0f60f9efa2189733f77aeb7d386a1fe6 100644 --- a/src/objective-c/BUILD +++ b/src/objective-c/BUILD @@ -18,30 +18,24 @@ licenses(["notice"]) # Apache v2 package(default_visibility = ["//visibility:public"]) -load("//bazel:grpc_build_system.bzl", "grpc_objc_library", "grpc_generate_objc_one_off_targets") +load("//bazel:grpc_build_system.bzl", "grpc_objc_library", "grpc_objc_use_cronet_config") exports_files(["LICENSE"]) -grpc_generate_objc_one_off_targets() - -grpc_objc_library( - name = "rx_library_headers", - hdrs = glob([ - "RxLibrary/*.h", - ]), - includes = ["."], -) +grpc_objc_use_cronet_config() grpc_objc_library( name = "rx_library", srcs = glob([ "RxLibrary/*.m", + "RxLibrary/transformations/*.m", + ]), + hdrs = glob([ + "RxLibrary/*.h", + "RxLibrary/transformations/*.h", ]), includes = ["."], - deps = [ - ":rx_library_headers", - ":rx_library_private", - ], + deps = [":rx_library_private"], ) grpc_objc_library( @@ -56,196 +50,84 @@ grpc_objc_library( ) grpc_objc_library( - name = "grpc_objc_interface_legacy", - hdrs = [ - "GRPCClient/GRPCCall+ChannelArg.h", - "GRPCClient/GRPCCall+ChannelCredentials.h", - "GRPCClient/GRPCCall+Cronet.h", - "GRPCClient/GRPCCall+OAuth2.h", - "GRPCClient/GRPCCall+Tests.h", - "GRPCClient/GRPCCallLegacy.h", - "GRPCClient/GRPCTypes.h", - ], - deps = [ - "rx_library_headers", - ], -) - -grpc_objc_library( - name = "grpc_objc_interface", - hdrs = [ - "GRPCClient/GRPCCall.h", - "GRPCClient/GRPCCall+Interceptor.h", - "GRPCClient/GRPCCallOptions.h", - "GRPCClient/GRPCInterceptor.h", - "GRPCClient/GRPCTransport.h", - "GRPCClient/GRPCDispatchable.h", - "GRPCClient/internal/GRPCCallOptions+Internal.h", - "GRPCClient/version.h", - ], - srcs = [ - "GRPCClient/GRPCCall.m", - "GRPCClient/GRPCCall+Interceptor.m", - "GRPCClient/GRPCCallOptions.m", - "GRPCClient/GRPCInterceptor.m", - "GRPCClient/GRPCTransport.m", - "GRPCClient/private/GRPCTransport+Private.m", - ], - includes = ["."], - textual_hdrs = [ - "GRPCClient/private/GRPCTransport+Private.h", - ], - deps = [ - ":grpc_objc_interface_legacy", - ], -) - -grpc_objc_library( - name = "grpc_objc_client_core", - hdrs = [ - "GRPCClient/GRPCCall+ChannelCredentials.h", - "GRPCClient/GRPCCall+Cronet.h", - "GRPCClient/GRPCCall+OAuth2.h", - "GRPCClient/GRPCCall+Tests.h", - "GRPCClient/GRPCCall+ChannelArg.h", - ], - textual_hdrs = glob(["GRPCClient/private/GRPCCore/*.h"]), - srcs = [ - "GRPCClient/GRPCCall+ChannelArg.m", - "GRPCClient/GRPCCall+ChannelCredentials.m", - "GRPCClient/GRPCCall+Cronet.m", - "GRPCClient/GRPCCall+OAuth2.m", - "GRPCClient/GRPCCall+Tests.m", - "GRPCClient/GRPCCallLegacy.m", - ] + glob(["GRPCClient/private/GRPCCore/*.m"]), - data = [":gRPCCertificates"], + name = "grpc_objc_client", + srcs = glob( + [ + "GRPCClient/*.m", + "GRPCClient/private/*.m", + ], + exclude = ["GRPCClient/GRPCCall+GID.m"], + ), + hdrs = glob( + [ + "GRPCClient/*.h", + "GRPCClient/internal/*.h", + ], + exclude = ["GRPCClient/GRPCCall+GID.h"], + ), + data = ["//:gRPCCertificates"], includes = ["."], + textual_hdrs = glob([ + "GRPCClient/private/*.h", + ]), deps = [ - ":grpc_objc_interface", - ":grpc_objc_interface_legacy", ":rx_library", "//:grpc_objc", ], ) -alias( - name = "grpc_objc_client", - actual = "grpc_objc_client_core", -) - -grpc_objc_library( - name = "proto_objc_rpc_legacy_header", - hdrs = [ - "ProtoRPC/ProtoRPCLegacy.h", - ], - includes = ["."], -) - -grpc_objc_library( - name = "proto_objc_rpc_v2", - srcs = [ - "ProtoRPC/ProtoMethod.m", - "ProtoRPC/ProtoRPC.m", - "ProtoRPC/ProtoService.m", - ], - hdrs = [ - "ProtoRPC/ProtoMethod.h", - "ProtoRPC/ProtoRPC.h", - "ProtoRPC/ProtoService.h", - ], - includes = ["."], - defines = ["GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=0"], - deps = [ - ":grpc_objc_interface", - ":proto_objc_rpc_legacy_header", - "@com_google_protobuf//:protobuf_objc", - ], -) - grpc_objc_library( name = "proto_objc_rpc", - srcs = [ - "ProtoRPC/ProtoRPCLegacy.m", - "ProtoRPC/ProtoServiceLegacy.m", - ], - hdrs = [ - "ProtoRPC/ProtoMethod.h", - "ProtoRPC/ProtoRPCLegacy.h", - "ProtoRPC/ProtoService.h", - ], + srcs = glob( + ["ProtoRPC/*.m"], + ), + hdrs = glob( + ["ProtoRPC/*.h"], + ), + # Different from Cocoapods, do not import as if @com_google_protobuf//:protobuf_objc is a framework, + # use the real paths of @com_google_protobuf//:protobuf_objc instead + defines = ["GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=0"], deps = [ + ":grpc_objc_client", ":rx_library", - ":proto_objc_rpc_v2", - ":proto_objc_rpc_legacy_header", - ":grpc_objc_client_core", "@com_google_protobuf//:protobuf_objc", ], ) -load("@build_bazel_rules_apple//apple:resources.bzl", "apple_resource_bundle") - -apple_resource_bundle( - # The choice of name is signicant here, since it determines the bundle name. - name = "gRPCCertificates", - resources = ["//:etc/roots.pem"], -) - -# Internal target combining grpc_objc_client_core and proto_objc_rpc for testing grpc_objc_library( - name = "grpc_objc_client_core_internal_testing", - hdrs = [ - "GRPCClient/GRPCCall+ChannelCredentials.h", - "GRPCClient/GRPCCall+Cronet.h", - "GRPCClient/GRPCCall+OAuth2.h", - "GRPCClient/GRPCCall+Tests.h", - "GRPCClient/GRPCCall+ChannelArg.h", - "GRPCClient/internal_testing/GRPCCall+InternalTests.h", - ], - textual_hdrs = glob(["GRPCClient/private/GRPCCore/*.h"]), - srcs = [ - "GRPCClient/GRPCCall+ChannelArg.m", - "GRPCClient/GRPCCall+ChannelCredentials.m", - "GRPCClient/GRPCCall+Cronet.m", - "GRPCClient/GRPCCall+OAuth2.m", - "GRPCClient/GRPCCall+Tests.m", - "GRPCClient/GRPCCallLegacy.m", - "GRPCClient/internal_testing/GRPCCall+InternalTests.m", - ] + glob(["GRPCClient/private/GRPCCore/*.m"]), - data = [":gRPCCertificates"], + name = "grpc_objc_client_internal_testing", + srcs = glob( + [ + "GRPCClient/*.m", + "GRPCClient/private/*.m", + "GRPCClient/internal_testing/*.m", + "ProtoRPC/*.m", + ], + exclude = ["GRPCClient/GRPCCall+GID.m"], + ), + hdrs = glob( + [ + "GRPCClient/*.h", + "GRPCClient/internal/*.h", + "GRPCClient/internal_testing/*.h", + "ProtoRPC/*.h", + ], + exclude = ["GRPCClient/GRPCCall+GID.h"], + ), includes = ["."], + data = ["//:gRPCCertificates"], defines = [ "GRPC_TEST_OBJC=1", + "GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=0", ], + textual_hdrs = glob( + [ + "GRPCClient/private/*.h", + ], + ), deps = [ - ":grpc_objc_interface", - ":grpc_objc_interface_legacy", ":rx_library", "//:grpc_objc", - ], -) - -grpc_objc_library( - name = "proto_objc_rpc_internal_testing", - srcs = [ - "ProtoRPC/ProtoRPCLegacy.m", - "ProtoRPC/ProtoServiceLegacy.m", - ], - hdrs = [ - "ProtoRPC/ProtoMethod.h", - "ProtoRPC/ProtoRPC.h", - "ProtoRPC/ProtoRPCLegacy.h", - "ProtoRPC/ProtoService.h", - ], - deps = [ - ":rx_library", - ":proto_objc_rpc_v2", - ":proto_objc_rpc_legacy_header", - ":grpc_objc_client_core_internal_testing", "@com_google_protobuf//:protobuf_objc", ], ) - -alias( - name = "grpc_objc_client_internal_testing", - actual = "proto_objc_rpc_internal_testing", -) diff --git a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.h b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.h index ff5a153a0f65ecd3dd4eb20f4a0be2bfce620da8..2ddd53a5c6695257d9504be01fd880ebedf51482 100644 --- a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.h +++ b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.h @@ -15,7 +15,7 @@ * limitations under the License. * */ -#import "GRPCCallLegacy.h" +#import "GRPCCall.h" #include <AvailabilityMacros.h> diff --git a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m index aae1b740c71b6c3d6fcb510e36f587e88b9a3863..ae60d6208e11c42492b00c599c6c6b323fa7059a 100644 --- a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m +++ b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m @@ -18,8 +18,8 @@ #import "GRPCCall+ChannelArg.h" -#import "private/GRPCCore/GRPCChannelPool.h" -#import "private/GRPCCore/GRPCHost.h" +#import "private/GRPCChannelPool.h" +#import "private/GRPCHost.h" #import <grpc/impl/codegen/compression_types.h> diff --git a/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h b/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h index c3d194bff9451f870e2f1ee94e353c9a88ccdc00..7d6f79b7655ed4bf1296fd6cf37cc883eacf7254 100644 --- a/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h +++ b/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h @@ -16,7 +16,7 @@ * */ -#import "GRPCCallLegacy.h" +#import "GRPCCall.h" // Deprecated interface. Please use GRPCCallOptions instead. @interface GRPCCall (ChannelCredentials) diff --git a/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.m b/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.m index aa97ca82bf8de2e1cc497084071cb0c26dc49746..2689ec2effb22e5184a2bb221dcc2034ba0ca7d1 100644 --- a/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.m +++ b/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.m @@ -18,7 +18,7 @@ #import "GRPCCall+ChannelCredentials.h" -#import "private/GRPCCore/GRPCHost.h" +#import "private/GRPCHost.h" @implementation GRPCCall (ChannelCredentials) diff --git a/src/objective-c/GRPCClient/GRPCCall+Cronet.h b/src/objective-c/GRPCClient/GRPCCall+Cronet.h index d107ada367258759c0c5f05823dd667aca75a3a4..3059c6f18600e5bae74752283de1008e4d01d921 100644 --- a/src/objective-c/GRPCClient/GRPCCall+Cronet.h +++ b/src/objective-c/GRPCClient/GRPCCall+Cronet.h @@ -15,16 +15,12 @@ * limitations under the License. * */ +#ifdef GRPC_COMPILE_WITH_CRONET +#import <Cronet/Cronet.h> -#import "GRPCCallLegacy.h" -#import "GRPCTypes.h" +#import "GRPCCall.h" -typedef struct stream_engine stream_engine; - -// Transport id for Cronet transport -extern const GRPCTransportId gGRPCCoreCronetId; - -// Deprecated class. Please use the gGRPCCoreCronetId with GRPCCallOptions.transport instead. +// Deprecated interface. Please use GRPCCallOptions instead. @interface GRPCCall (Cronet) + (void)useCronetWithEngine:(stream_engine*)engine; @@ -32,3 +28,4 @@ extern const GRPCTransportId gGRPCCoreCronetId; + (BOOL)isUsingCronet; @end +#endif diff --git a/src/objective-c/GRPCClient/GRPCCall+Cronet.m b/src/objective-c/GRPCClient/GRPCCall+Cronet.m index a732208e1f645f1738e4576030345374f00511cd..ba8d2c23db8d86a9c3700996a6d00d97603edcd0 100644 --- a/src/objective-c/GRPCClient/GRPCCall+Cronet.m +++ b/src/objective-c/GRPCClient/GRPCCall+Cronet.m @@ -18,8 +18,7 @@ #import "GRPCCall+Cronet.h" -const GRPCTransportId gGRPCCoreCronetId = "io.grpc.transport.core.cronet"; - +#ifdef GRPC_COMPILE_WITH_CRONET static BOOL useCronet = NO; static stream_engine *globalCronetEngine; @@ -39,3 +38,4 @@ static stream_engine *globalCronetEngine; } @end +#endif diff --git a/src/objective-c/GRPCClient/GRPCCall+GID.h b/src/objective-c/GRPCClient/GRPCCall+GID.h index 80e34ea98da86cf7df0853a4b31844a509f3ceb7..8293e92ebe9ec848a69c4b1b4f2e5af24f10e20f 100644 --- a/src/objective-c/GRPCClient/GRPCCall+GID.h +++ b/src/objective-c/GRPCClient/GRPCCall+GID.h @@ -17,7 +17,7 @@ */ #import "GRPCCall+OAuth2.h" -#import "GRPCCallLegacy.h" +#import "GRPCCall.h" #import <Google/SignIn.h> diff --git a/src/objective-c/GRPCClient/GRPCCall+OAuth2.h b/src/objective-c/GRPCClient/GRPCCall+OAuth2.h index cf60c794f270fe8e1fae0cbcd27853bcd72c6126..60cdc50bfda10ba28ed1b18066e83db41b729991 100644 --- a/src/objective-c/GRPCClient/GRPCCall+OAuth2.h +++ b/src/objective-c/GRPCClient/GRPCCall+OAuth2.h @@ -16,9 +16,9 @@ * */ -#import "GRPCCallLegacy.h" +#import "GRPCCall.h" -@protocol GRPCAuthorizationProtocol; +#import "GRPCCallOptions.h" // Deprecated interface. Please use GRPCCallOptions instead. @interface GRPCCall (OAuth2) diff --git a/src/objective-c/GRPCClient/GRPCCall+Tests.h b/src/objective-c/GRPCClient/GRPCCall+Tests.h index af81eec6b8279e7612d392bd691d4f5f0423e48c..edaa5ed582c6a897fbcfe20a91c0ab847ef95fc0 100644 --- a/src/objective-c/GRPCClient/GRPCCall+Tests.h +++ b/src/objective-c/GRPCClient/GRPCCall+Tests.h @@ -16,7 +16,7 @@ * */ -#import "GRPCCallLegacy.h" +#import "GRPCCall.h" // Deprecated interface. Please use GRPCCallOptions instead. @interface GRPCCall (Tests) diff --git a/src/objective-c/GRPCClient/GRPCCall+Tests.m b/src/objective-c/GRPCClient/GRPCCall+Tests.m index 3a1dff388681f6ff6cae4820694f26a49d11d24d..20f5cba4178073e770397653748dd5bcc2151a36 100644 --- a/src/objective-c/GRPCClient/GRPCCall+Tests.m +++ b/src/objective-c/GRPCClient/GRPCCall+Tests.m @@ -18,7 +18,7 @@ #import "GRPCCall+Tests.h" -#import "private/GRPCCore/GRPCHost.h" +#import "private/GRPCHost.h" #import "GRPCCallOptions.h" diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index 1c7a10048cf0d863d8629f5083e8354a701cb281..d02ec60172768f4e5cea7a8ce17c7df3aac47289 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -33,19 +33,134 @@ */ #import <Foundation/Foundation.h> +#import <RxLibrary/GRXWriter.h> -#import "GRPCCallOptions.h" -#import "GRPCDispatchable.h" -#import "GRPCTypes.h" +#include <AvailabilityMacros.h> -// The legacy header is included for backwards compatibility. Some V1 API users are still using -// GRPCCall by importing GRPCCall.h header so we need this import. -#import "GRPCCallLegacy.h" +#include "GRPCCallOptions.h" NS_ASSUME_NONNULL_BEGIN +#pragma mark gRPC errors + +/** Domain of NSError objects produced by gRPC. */ +extern NSString *const kGRPCErrorDomain; + +/** + * gRPC error codes. + * Note that a few of these are never produced by the gRPC libraries, but are of general utility for + * server applications to produce. + */ +typedef NS_ENUM(NSUInteger, GRPCErrorCode) { + /** The operation was cancelled (typically by the caller). */ + GRPCErrorCodeCancelled = 1, + + /** + * Unknown error. Errors raised by APIs that do not return enough error information may be + * converted to this error. + */ + GRPCErrorCodeUnknown = 2, + + /** + * The client specified an invalid argument. Note that this differs from FAILED_PRECONDITION. + * INVALID_ARGUMENT indicates arguments that are problematic regardless of the state of the + * server (e.g., a malformed file name). + */ + GRPCErrorCodeInvalidArgument = 3, + + /** + * Deadline expired before operation could complete. For operations that change the state of the + * server, this error may be returned even if the operation has completed successfully. For + * example, a successful response from the server could have been delayed long enough for the + * deadline to expire. + */ + GRPCErrorCodeDeadlineExceeded = 4, + + /** Some requested entity (e.g., file or directory) was not found. */ + GRPCErrorCodeNotFound = 5, + + /** Some entity that we attempted to create (e.g., file or directory) already exists. */ + GRPCErrorCodeAlreadyExists = 6, + + /** + * The caller does not have permission to execute the specified operation. PERMISSION_DENIED isn't + * used for rejections caused by exhausting some resource (RESOURCE_EXHAUSTED is used instead for + * those errors). PERMISSION_DENIED doesn't indicate a failure to identify the caller + * (UNAUTHENTICATED is used instead for those errors). + */ + GRPCErrorCodePermissionDenied = 7, + + /** + * The request does not have valid authentication credentials for the operation (e.g. the caller's + * identity can't be verified). + */ + GRPCErrorCodeUnauthenticated = 16, + + /** Some resource has been exhausted, perhaps a per-user quota. */ + GRPCErrorCodeResourceExhausted = 8, + + /** + * The RPC was rejected because the server is not in a state required for the procedure's + * execution. For example, a directory to be deleted may be non-empty, etc. + * The client should not retry until the server state has been explicitly fixed (e.g. by + * performing another RPC). The details depend on the service being called, and should be found in + * the NSError's userInfo. + */ + GRPCErrorCodeFailedPrecondition = 9, + + /** + * The RPC was aborted, typically due to a concurrency issue like sequencer check failures, + * transaction aborts, etc. The client should retry at a higher-level (e.g., restarting a read- + * modify-write sequence). + */ + GRPCErrorCodeAborted = 10, + + /** + * The RPC was attempted past the valid range. E.g., enumerating past the end of a list. + * Unlike INVALID_ARGUMENT, this error indicates a problem that may be fixed if the system state + * changes. For example, an RPC to get elements of a list will generate INVALID_ARGUMENT if asked + * to return the element at a negative index, but it will generate OUT_OF_RANGE if asked to return + * the element at an index past the current size of the list. + */ + GRPCErrorCodeOutOfRange = 11, + + /** The procedure is not implemented or not supported/enabled in this server. */ + GRPCErrorCodeUnimplemented = 12, + + /** + * Internal error. Means some invariant expected by the server application or the gRPC library has + * been broken. + */ + GRPCErrorCodeInternal = 13, + + /** + * The server is currently unavailable. This is most likely a transient condition and may be + * corrected by retrying with a backoff. Note that it is not always safe to retry + * non-idempotent operations. + */ + GRPCErrorCodeUnavailable = 14, + + /** Unrecoverable data loss or corruption. */ + GRPCErrorCodeDataLoss = 15, +}; + +/** + * Keys used in |NSError|'s |userInfo| dictionary to store the response headers and trailers sent by + * the server. + */ +extern NSString *const kGRPCHeadersKey; +extern NSString *const kGRPCTrailersKey; + /** An object can implement this protocol to receive responses from server from a call. */ -@protocol GRPCResponseHandler<NSObject, GRPCDispatchable> +@protocol GRPCResponseHandler<NSObject> + +@required + +/** + * All the responses must be issued to a user-provided dispatch queue. This property specifies the + * dispatch queue to be used for issuing the notifications. + */ +@property(atomic, readonly) dispatch_queue_t dispatchQueue; @optional @@ -187,3 +302,114 @@ NS_ASSUME_NONNULL_BEGIN @end NS_ASSUME_NONNULL_END + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnullability-completeness" + +/** + * This interface is deprecated. Please use \a GRPCcall2. + * + * Represents a single gRPC remote call. + */ +@interface GRPCCall : GRXWriter + +- (instancetype)init NS_UNAVAILABLE; + +/** + * The container of the request headers of an RPC conforms to this protocol, which is a subset of + * NSMutableDictionary's interface. It will become a NSMutableDictionary later on. + * The keys of this container are the header names, which per the HTTP standard are case- + * insensitive. They are stored in lowercase (which is how HTTP/2 mandates them on the wire), and + * can only consist of ASCII characters. + * A header value is a NSString object (with only ASCII characters), unless the header name has the + * suffix "-bin", in which case the value has to be a NSData object. + */ +/** + * These HTTP headers will be passed to the server as part of this call. Each HTTP header is a + * name-value pair with string names and either string or binary values. + * + * The passed dictionary has to use NSString keys, corresponding to the header names. The value + * associated to each can be a NSString object or a NSData object. E.g.: + * + * call.requestHeaders = @{@"authorization": @"Bearer ..."}; + * + * call.requestHeaders[@"my-header-bin"] = someData; + * + * After the call is started, trying to modify this property is an error. + * + * The property is initialized to an empty NSMutableDictionary. + */ +@property(atomic, readonly) NSMutableDictionary *requestHeaders; + +/** + * This dictionary is populated with the HTTP headers received from the server. This happens before + * any response message is received from the server. It has the same structure as the request + * headers dictionary: Keys are NSString header names; names ending with the suffix "-bin" have a + * NSData value; the others have a NSString value. + * + * The value of this property is nil until all response headers are received, and will change before + * any of -writeValue: or -writesFinishedWithError: are sent to the writeable. + */ +@property(atomic, readonly) NSDictionary *responseHeaders; + +/** + * Same as responseHeaders, but populated with the HTTP trailers received from the server before the + * call finishes. + * + * The value of this property is nil until all response trailers are received, and will change + * before -writesFinishedWithError: is sent to the writeable. + */ +@property(atomic, readonly) NSDictionary *responseTrailers; + +/** + * The request writer has to write NSData objects into the provided Writeable. The server will + * receive each of those separately and in order as distinct messages. + * A gRPC call might not complete until the request writer finishes. On the other hand, the request + * finishing doesn't necessarily make the call to finish, as the server might continue sending + * messages to the response side of the call indefinitely (depending on the semantics of the + * specific remote method called). + * To finish a call right away, invoke cancel. + * host parameter should not contain the scheme (http:// or https://), only the name or IP addr + * and the port number, for example @"localhost:5050". + */ +- (instancetype)initWithHost:(NSString *)host + path:(NSString *)path + requestsWriter:(GRXWriter *)requestWriter; + +/** + * Finishes the request side of this call, notifies the server that the RPC should be cancelled, and + * finishes the response side of the call with an error of code CANCELED. + */ +- (void)cancel; + +/** + * The following methods are deprecated. + */ ++ (void)setCallSafety:(GRPCCallSafety)callSafety host:(NSString *)host path:(NSString *)path; +@property(atomic, copy, readwrite) NSString *serverName; +@property NSTimeInterval timeout; +- (void)setResponseDispatchQueue:(dispatch_queue_t)queue; + +@end + +#pragma mark Backwards compatibiity + +/** This protocol is kept for backwards compatibility with existing code. */ +DEPRECATED_MSG_ATTRIBUTE("Use NSDictionary or NSMutableDictionary instead.") +@protocol GRPCRequestHeaders<NSObject> +@property(nonatomic, readonly) NSUInteger count; + +- (id)objectForKeyedSubscript:(id)key; +- (void)setObject:(id)obj forKeyedSubscript:(id)key; + +- (void)removeAllObjects; +- (void)removeObjectForKey:(id)key; +@end + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" +/** This is only needed for backwards-compatibility. */ +@interface NSMutableDictionary (GRPCRequestHeaders)<GRPCRequestHeaders> +@end +#pragma clang diagnostic pop +#pragma clang diagnostic pop diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 73ee530ef2c4373a535c3d6adc894119424ea834..cd293cc8e59c0bacb6b66336ed132d56a15d4f0f 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -17,86 +17,56 @@ */ #import "GRPCCall.h" - #import "GRPCCall+Interceptor.h" +#import "GRPCCall+OAuth2.h" #import "GRPCCallOptions.h" #import "GRPCInterceptor.h" -#import "private/GRPCTransport+Private.h" +#import <RxLibrary/GRXBufferedPipe.h> +#import <RxLibrary/GRXConcurrentWriteable.h> +#import <RxLibrary/GRXImmediateSingleWriter.h> +#import <RxLibrary/GRXWriter+Immediate.h> +#include <grpc/grpc.h> +#include <grpc/support/time.h> + +#import "private/GRPCCall+V2API.h" +#import "private/GRPCCallInternal.h" +#import "private/GRPCChannelPool.h" +#import "private/GRPCCompletionQueue.h" +#import "private/GRPCHost.h" +#import "private/GRPCRequestHeaders.h" +#import "private/GRPCWrappedCall.h" +#import "private/NSData+GRPC.h" +#import "private/NSDictionary+GRPC.h" +#import "private/NSError+GRPC.h" + +// At most 6 ops can be in an op batch for a client: SEND_INITIAL_METADATA, +// SEND_MESSAGE, SEND_CLOSE_FROM_CLIENT, RECV_INITIAL_METADATA, RECV_MESSAGE, +// and RECV_STATUS_ON_CLIENT. +NSInteger kMaxClientBatch = 6; NSString *const kGRPCHeadersKey = @"io.grpc.HeadersKey"; NSString *const kGRPCTrailersKey = @"io.grpc.TrailersKey"; +static NSMutableDictionary *callFlags; -NSString *const kGRPCErrorDomain = @"io.grpc"; - -/** - * The response dispatcher creates its own serial dispatch queue and target the queue to the - * dispatch queue of a user provided response handler. It removes the requirement of having to use - * serial dispatch queue in the user provided response handler. - */ -@interface GRPCResponseDispatcher : NSObject<GRPCResponseHandler> - -- (nullable instancetype)initWithResponseHandler:(id<GRPCResponseHandler>)responseHandler; - -@end +static NSString *const kAuthorizationHeader = @"authorization"; +static NSString *const kBearerPrefix = @"Bearer "; -@implementation GRPCResponseDispatcher { - id<GRPCResponseHandler> _responseHandler; - dispatch_queue_t _dispatchQueue; -} +const char *kCFStreamVarName = "grpc_cfstream"; -- (instancetype)initWithResponseHandler:(id<GRPCResponseHandler>)responseHandler { - if ((self = [super init])) { - _responseHandler = responseHandler; -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 - if (@available(iOS 8.0, macOS 10.10, *)) { - _dispatchQueue = dispatch_queue_create( - NULL, - dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0)); - } else { -#else - { -#endif - _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); - } - dispatch_set_target_queue(_dispatchQueue, _responseHandler.dispatchQueue); - } +@interface GRPCCall ()<GRXWriteable> +// Make them read-write. +@property(atomic, strong) NSDictionary *responseHeaders; +@property(atomic, strong) NSDictionary *responseTrailers; - return self; -} - -- (dispatch_queue_t)dispatchQueue { - return _dispatchQueue; -} - -- (void)didReceiveInitialMetadata:(nullable NSDictionary *)initialMetadata { - if ([_responseHandler respondsToSelector:@selector(didReceiveInitialMetadata:)]) { - [_responseHandler didReceiveInitialMetadata:initialMetadata]; - } -} - -- (void)didReceiveData:(id)data { - // For backwards compatibility with didReceiveRawMessage, if the user provided a response handler - // that handles didReceiveRawMesssage, we issue to that method instead - if ([_responseHandler respondsToSelector:@selector(didReceiveRawMessage:)]) { - [_responseHandler didReceiveRawMessage:data]; - } else if ([_responseHandler respondsToSelector:@selector(didReceiveData:)]) { - [_responseHandler didReceiveData:data]; - } -} - -- (void)didCloseWithTrailingMetadata:(nullable NSDictionary *)trailingMetadata - error:(nullable NSError *)error { - if ([_responseHandler respondsToSelector:@selector(didCloseWithTrailingMetadata:error:)]) { - [_responseHandler didCloseWithTrailingMetadata:trailingMetadata error:error]; - } -} +- (void)receiveNextMessages:(NSUInteger)numberOfMessages; -- (void)didWriteData { - if ([_responseHandler respondsToSelector:@selector(didWriteData)]) { - [_responseHandler didWriteData]; - } -} +- (instancetype)initWithHost:(NSString *)host + path:(NSString *)path + callSafety:(GRPCCallSafety)safety + requestsWriter:(GRXWriter *)requestsWriter + callOptions:(GRPCCallOptions *)callOptions + writeDone:(void (^)(void))writeDone; @end @@ -170,39 +140,54 @@ NSString *const kGRPCErrorDomain = @"io.grpc"; } _responseHandler = responseHandler; - GRPCResponseDispatcher *dispatcher = - [[GRPCResponseDispatcher alloc] initWithResponseHandler:_responseHandler]; - NSMutableArray<id<GRPCInterceptorFactory>> *interceptorFactories; - if (_actualCallOptions.interceptorFactories != nil) { - interceptorFactories = - [NSMutableArray arrayWithArray:_actualCallOptions.interceptorFactories]; - } else { - interceptorFactories = [NSMutableArray array]; - } + // Initialize the interceptor chain + + // First initialize the internal call + GRPCCall2Internal *internalCall = [[GRPCCall2Internal alloc] init]; + id<GRPCInterceptorInterface> nextInterceptor = internalCall; + GRPCInterceptorManager *nextManager = nil; + + // Then initialize the global interceptor, if applicable id<GRPCInterceptorFactory> globalInterceptorFactory = [GRPCCall2 globalInterceptorFactory]; - if (globalInterceptorFactory != nil) { - [interceptorFactories addObject:globalInterceptorFactory]; + if (globalInterceptorFactory) { + GRPCInterceptorManager *manager = + [[GRPCInterceptorManager alloc] initWithNextInterceptor:nextInterceptor]; + GRPCInterceptor *interceptor = + [globalInterceptorFactory createInterceptorWithManager:manager]; + if (interceptor != nil) { + [internalCall setResponseHandler:interceptor]; + nextInterceptor = interceptor; + nextManager = manager; + } } - // continuously create interceptor until one is successfully created - while (_firstInterceptor == nil) { - if (interceptorFactories.count == 0) { - _firstInterceptor = [[GRPCTransportManager alloc] initWithTransportId:_callOptions.transport - previousInterceptor:dispatcher]; - break; + + // Finally initialize the interceptors in the chain + NSArray *interceptorFactories = _actualCallOptions.interceptorFactories; + for (int i = (int)interceptorFactories.count - 1; i >= 0; i--) { + GRPCInterceptorManager *manager = + [[GRPCInterceptorManager alloc] initWithNextInterceptor:nextInterceptor]; + GRPCInterceptor *interceptor = [interceptorFactories[i] createInterceptorWithManager:manager]; + NSAssert(interceptor != nil, @"Failed to create interceptor from factory: %@", + interceptorFactories[i]); + if (interceptor == nil) { + NSLog(@"Failed to create interceptor from factory: %@", interceptorFactories[i]); + continue; + } + if (nextManager == nil) { + [internalCall setResponseHandler:interceptor]; } else { - _firstInterceptor = - [[GRPCInterceptorManager alloc] initWithFactories:interceptorFactories - previousInterceptor:dispatcher - transportId:_callOptions.transport]; - if (_firstInterceptor == nil) { - [interceptorFactories removeObjectAtIndex:0]; - } + [nextManager setPreviousInterceptor:interceptor]; } + nextInterceptor = interceptor; + nextManager = manager; } - NSAssert(_firstInterceptor != nil, @"Failed to create interceptor or transport."); - if (_firstInterceptor == nil) { - NSLog(@"Failed to create interceptor or transport."); + if (nextManager == nil) { + [internalCall setResponseHandler:_responseHandler]; + } else { + [nextManager setPreviousInterceptor:_responseHandler]; } + + _firstInterceptor = nextInterceptor; } return self; @@ -215,42 +200,696 @@ NSString *const kGRPCErrorDomain = @"io.grpc"; } - (void)start { - id<GRPCInterceptorInterface> copiedFirstInterceptor = _firstInterceptor; - GRPCRequestOptions *requestOptions = _requestOptions; - GRPCCallOptions *callOptions = _actualCallOptions; - dispatch_async(copiedFirstInterceptor.dispatchQueue, ^{ - [copiedFirstInterceptor startWithRequestOptions:requestOptions callOptions:callOptions]; - }); + id<GRPCInterceptorInterface> copiedFirstInterceptor; + @synchronized(self) { + copiedFirstInterceptor = _firstInterceptor; + } + GRPCRequestOptions *requestOptions = [_requestOptions copy]; + GRPCCallOptions *callOptions = [_actualCallOptions copy]; + if ([copiedFirstInterceptor respondsToSelector:@selector(startWithRequestOptions:callOptions:)]) { + dispatch_async(copiedFirstInterceptor.requestDispatchQueue, ^{ + [copiedFirstInterceptor startWithRequestOptions:requestOptions callOptions:callOptions]; + }); + } } - (void)cancel { - id<GRPCInterceptorInterface> copiedFirstInterceptor = _firstInterceptor; - if (copiedFirstInterceptor != nil) { - dispatch_async(copiedFirstInterceptor.dispatchQueue, ^{ + id<GRPCInterceptorInterface> copiedFirstInterceptor; + @synchronized(self) { + copiedFirstInterceptor = _firstInterceptor; + } + if ([copiedFirstInterceptor respondsToSelector:@selector(cancel)]) { + dispatch_async(copiedFirstInterceptor.requestDispatchQueue, ^{ [copiedFirstInterceptor cancel]; }); } } - (void)writeData:(id)data { - id<GRPCInterceptorInterface> copiedFirstInterceptor = _firstInterceptor; - dispatch_async(copiedFirstInterceptor.dispatchQueue, ^{ - [copiedFirstInterceptor writeData:data]; - }); + id<GRPCInterceptorInterface> copiedFirstInterceptor; + @synchronized(self) { + copiedFirstInterceptor = _firstInterceptor; + } + if ([copiedFirstInterceptor respondsToSelector:@selector(writeData:)]) { + dispatch_async(copiedFirstInterceptor.requestDispatchQueue, ^{ + [copiedFirstInterceptor writeData:data]; + }); + } } - (void)finish { - id<GRPCInterceptorInterface> copiedFirstInterceptor = _firstInterceptor; - dispatch_async(copiedFirstInterceptor.dispatchQueue, ^{ - [copiedFirstInterceptor finish]; + id<GRPCInterceptorInterface> copiedFirstInterceptor; + @synchronized(self) { + copiedFirstInterceptor = _firstInterceptor; + } + if ([copiedFirstInterceptor respondsToSelector:@selector(finish)]) { + dispatch_async(copiedFirstInterceptor.requestDispatchQueue, ^{ + [copiedFirstInterceptor finish]; + }); + } +} + +- (void)receiveNextMessages:(NSUInteger)numberOfMessages { + id<GRPCInterceptorInterface> copiedFirstInterceptor; + @synchronized(self) { + copiedFirstInterceptor = _firstInterceptor; + } + if ([copiedFirstInterceptor respondsToSelector:@selector(receiveNextMessages:)]) { + dispatch_async(copiedFirstInterceptor.requestDispatchQueue, ^{ + [copiedFirstInterceptor receiveNextMessages:numberOfMessages]; + }); + } +} + +@end + +// The following methods of a C gRPC call object aren't reentrant, and thus +// calls to them must be serialized: +// - start_batch +// - destroy +// +// start_batch with a SEND_MESSAGE argument can only be called after the +// OP_COMPLETE event for any previous write is received. This is achieved by +// pausing the requests writer immediately every time it writes a value, and +// resuming it again when OP_COMPLETE is received. +// +// Similarly, start_batch with a RECV_MESSAGE argument can only be called after +// the OP_COMPLETE event for any previous read is received.This is easier to +// enforce, as we're writing the received messages into the writeable: +// start_batch is enqueued once upon receiving the OP_COMPLETE event for the +// RECV_METADATA batch, and then once after receiving each OP_COMPLETE event for +// each RECV_MESSAGE batch. +@implementation GRPCCall { + dispatch_queue_t _callQueue; + + NSString *_host; + NSString *_path; + GRPCCallSafety _callSafety; + GRPCCallOptions *_callOptions; + GRPCWrappedCall *_wrappedCall; + + // The C gRPC library has less guarantees on the ordering of events than we + // do. Particularly, in the face of errors, there's no ordering guarantee at + // all. This wrapper over our actual writeable ensures thread-safety and + // correct ordering. + GRXConcurrentWriteable *_responseWriteable; + + // The network thread wants the requestWriter to resume (when the server is ready for more input), + // or to stop (on errors), concurrently with user threads that want to start it, pause it or stop + // it. Because a writer isn't thread-safe, we'll synchronize those operations on it. + // We don't use a dispatch queue for that purpose, because the writer can call writeValue: or + // writesFinishedWithError: on this GRPCCall as part of those operations. We want to be able to + // pause the writer immediately on writeValue:, so we need our locking to be recursive. + GRXWriter *_requestWriter; + + // To create a retain cycle when a call is started, up until it finishes. See + // |startWithWriteable:| and |finishWithError:|. This saves users from having to retain a + // reference to the call object if all they're interested in is the handler being executed when + // the response arrives. + GRPCCall *_retainSelf; + + GRPCRequestHeaders *_requestHeaders; + + // In the case that the call is a unary call (i.e. the writer to GRPCCall is of type + // GRXImmediateSingleWriter), GRPCCall will delay sending ops (not send them to C core + // immediately) and buffer them into a batch _unaryOpBatch. The batch is sent to C core when + // the SendClose op is added. + BOOL _unaryCall; + NSMutableArray *_unaryOpBatch; + + // The dispatch queue to be used for enqueuing responses to user. Defaulted to the main dispatch + // queue + dispatch_queue_t _responseQueue; + + // The OAuth2 token fetched from a token provider. + NSString *_fetchedOauth2AccessToken; + + // The callback to be called when a write message op is done. + void (^_writeDone)(void); + + // Indicate a read request to core is pending. + BOOL _pendingCoreRead; + + // Indicate pending read message request from user. + NSUInteger _pendingReceiveNextMessages; +} + +@synthesize state = _state; + ++ (void)initialize { + // Guarantees the code in {} block is invoked only once. See ref at: + // https://developer.apple.com/documentation/objectivec/nsobject/1418639-initialize?language=objc + if (self == [GRPCCall self]) { + grpc_init(); + callFlags = [NSMutableDictionary dictionary]; + } +} + ++ (void)setCallSafety:(GRPCCallSafety)callSafety host:(NSString *)host path:(NSString *)path { + if (host.length == 0 || path.length == 0) { + return; + } + NSString *hostAndPath = [NSString stringWithFormat:@"%@/%@", host, path]; + @synchronized(callFlags) { + switch (callSafety) { + case GRPCCallSafetyDefault: + callFlags[hostAndPath] = @0; + break; + case GRPCCallSafetyIdempotentRequest: + callFlags[hostAndPath] = @GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST; + break; + case GRPCCallSafetyCacheableRequest: + callFlags[hostAndPath] = @GRPC_INITIAL_METADATA_CACHEABLE_REQUEST; + break; + default: + break; + } + } +} + ++ (uint32_t)callFlagsForHost:(NSString *)host path:(NSString *)path { + NSString *hostAndPath = [NSString stringWithFormat:@"%@/%@", host, path]; + @synchronized(callFlags) { + return [callFlags[hostAndPath] intValue]; + } +} + +// Designated initializer +- (instancetype)initWithHost:(NSString *)host + path:(NSString *)path + requestsWriter:(GRXWriter *)requestWriter { + return [self initWithHost:host + path:path + callSafety:GRPCCallSafetyDefault + requestsWriter:requestWriter + callOptions:nil]; +} + +- (instancetype)initWithHost:(NSString *)host + path:(NSString *)path + callSafety:(GRPCCallSafety)safety + requestsWriter:(GRXWriter *)requestsWriter + callOptions:(GRPCCallOptions *)callOptions { + return [self initWithHost:host + path:path + callSafety:safety + requestsWriter:requestsWriter + callOptions:callOptions + writeDone:nil]; +} + +- (instancetype)initWithHost:(NSString *)host + path:(NSString *)path + callSafety:(GRPCCallSafety)safety + requestsWriter:(GRXWriter *)requestsWriter + callOptions:(GRPCCallOptions *)callOptions + writeDone:(void (^)(void))writeDone { + // Purposely using pointer rather than length (host.length == 0) for backwards compatibility. + NSAssert(host != nil && path != nil, @"Neither host nor path can be nil."); + NSAssert(safety <= GRPCCallSafetyCacheableRequest, @"Invalid call safety value."); + NSAssert(requestsWriter.state == GRXWriterStateNotStarted, + @"The requests writer can't be already started."); + if (!host || !path) { + return nil; + } + if (safety > GRPCCallSafetyCacheableRequest) { + return nil; + } + if (requestsWriter.state != GRXWriterStateNotStarted) { + return nil; + } + + if ((self = [super init])) { + _host = [host copy]; + _path = [path copy]; + _callSafety = safety; + _callOptions = [callOptions copy]; + + // Serial queue to invoke the non-reentrant methods of the grpc_call object. + _callQueue = dispatch_queue_create("io.grpc.call", DISPATCH_QUEUE_SERIAL); + + _requestWriter = requestsWriter; + _requestHeaders = [[GRPCRequestHeaders alloc] initWithCall:self]; + _writeDone = writeDone; + + if ([requestsWriter isKindOfClass:[GRXImmediateSingleWriter class]]) { + _unaryCall = YES; + _unaryOpBatch = [NSMutableArray arrayWithCapacity:kMaxClientBatch]; + } + + _responseQueue = dispatch_get_main_queue(); + + // do not start a read until initial metadata is received + _pendingReceiveNextMessages = 0; + _pendingCoreRead = YES; + } + return self; +} + +- (void)setResponseDispatchQueue:(dispatch_queue_t)queue { + @synchronized(self) { + if (_state != GRXWriterStateNotStarted) { + return; + } + _responseQueue = queue; + } +} + +#pragma mark Finish + +// This function should support being called within a @synchronized(self) block in another function +// Should not manipulate _requestWriter for deadlock prevention. +- (void)finishWithError:(NSError *)errorOrNil { + @synchronized(self) { + if (_state == GRXWriterStateFinished) { + return; + } + _state = GRXWriterStateFinished; + + if (errorOrNil) { + [_responseWriteable cancelWithError:errorOrNil]; + } else { + [_responseWriteable enqueueSuccessfulCompletion]; + } + + // If the call isn't retained anywhere else, it can be deallocated now. + _retainSelf = nil; + } +} + +- (void)cancel { + @synchronized(self) { + if (_state == GRXWriterStateFinished) { + return; + } + [self finishWithError:[NSError + errorWithDomain:kGRPCErrorDomain + code:GRPCErrorCodeCancelled + userInfo:@{NSLocalizedDescriptionKey : @"Canceled by app"}]]; + [_wrappedCall cancel]; + } + _requestWriter.state = GRXWriterStateFinished; +} + +- (void)dealloc { + __block GRPCWrappedCall *wrappedCall = _wrappedCall; + dispatch_async(_callQueue, ^{ + wrappedCall = nil; + }); +} + +#pragma mark Read messages + +// Only called from the call queue. +// The handler will be called from the network queue. +- (void)startReadWithHandler:(void (^)(grpc_byte_buffer *))handler { + // TODO(jcanizales): Add error handlers for async failures + [_wrappedCall startBatchWithOperations:@[ [[GRPCOpRecvMessage alloc] initWithHandler:handler] ]]; +} + +// Called initially from the network queue once response headers are received, +// then "recursively" from the responseWriteable queue after each response from the +// server has been written. +// If the call is currently paused, this is a noop. Restarting the call will invoke this +// method. +// TODO(jcanizales): Rename to readResponseIfNotPaused. +- (void)maybeStartNextRead { + @synchronized(self) { + if (_state != GRXWriterStateStarted) { + return; + } + if (_callOptions.flowControlEnabled && (_pendingCoreRead || _pendingReceiveNextMessages == 0)) { + return; + } + _pendingCoreRead = YES; + _pendingReceiveNextMessages--; + } + + dispatch_async(_callQueue, ^{ + __weak GRPCCall *weakSelf = self; + [self startReadWithHandler:^(grpc_byte_buffer *message) { + if (message == NULL) { + // No more messages from the server + return; + } + __strong GRPCCall *strongSelf = weakSelf; + if (strongSelf == nil) { + grpc_byte_buffer_destroy(message); + return; + } + NSData *data = [NSData grpc_dataWithByteBuffer:message]; + grpc_byte_buffer_destroy(message); + if (!data) { + // The app doesn't have enough memory to hold the server response. We + // don't want to throw, because the app shouldn't crash for a behavior + // that's on the hands of any server to have. Instead we finish and ask + // the server to cancel. + @synchronized(strongSelf) { + strongSelf->_pendingCoreRead = NO; + [strongSelf + finishWithError:[NSError errorWithDomain:kGRPCErrorDomain + code:GRPCErrorCodeResourceExhausted + userInfo:@{ + NSLocalizedDescriptionKey : + @"Client does not have enough memory to " + @"hold the server response." + }]]; + [strongSelf->_wrappedCall cancel]; + } + strongSelf->_requestWriter.state = GRXWriterStateFinished; + } else { + @synchronized(strongSelf) { + [strongSelf->_responseWriteable enqueueValue:data + completionHandler:^{ + __strong GRPCCall *strongSelf = weakSelf; + if (strongSelf) { + @synchronized(strongSelf) { + strongSelf->_pendingCoreRead = NO; + [strongSelf maybeStartNextRead]; + } + } + }]; + } + } + }]; + }); +} + +#pragma mark Send headers + +- (void)sendHeaders { + // TODO (mxyan): Remove after deprecated methods are removed + uint32_t callSafetyFlags = 0; + switch (_callSafety) { + case GRPCCallSafetyDefault: + callSafetyFlags = 0; + break; + case GRPCCallSafetyIdempotentRequest: + callSafetyFlags = GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST; + break; + case GRPCCallSafetyCacheableRequest: + callSafetyFlags = GRPC_INITIAL_METADATA_CACHEABLE_REQUEST; + break; + } + + NSMutableDictionary *headers = [_requestHeaders mutableCopy]; + NSString *fetchedOauth2AccessToken; + @synchronized(self) { + fetchedOauth2AccessToken = _fetchedOauth2AccessToken; + } + if (fetchedOauth2AccessToken != nil) { + headers[@"authorization"] = [kBearerPrefix stringByAppendingString:fetchedOauth2AccessToken]; + } else if (_callOptions.oauth2AccessToken != nil) { + headers[@"authorization"] = + [kBearerPrefix stringByAppendingString:_callOptions.oauth2AccessToken]; + } + + // TODO(jcanizales): Add error handlers for async failures + GRPCOpSendMetadata *op = [[GRPCOpSendMetadata alloc] + initWithMetadata:headers + flags:callSafetyFlags + handler:nil]; // No clean-up needed after SEND_INITIAL_METADATA + dispatch_async(_callQueue, ^{ + if (!self->_unaryCall) { + [self->_wrappedCall startBatchWithOperations:@[ op ]]; + } else { + [self->_unaryOpBatch addObject:op]; + } }); } - (void)receiveNextMessages:(NSUInteger)numberOfMessages { - id<GRPCInterceptorInterface> copiedFirstInterceptor = _firstInterceptor; - dispatch_async(copiedFirstInterceptor.dispatchQueue, ^{ - [copiedFirstInterceptor receiveNextMessages:numberOfMessages]; + if (numberOfMessages == 0) { + return; + } + @synchronized(self) { + _pendingReceiveNextMessages += numberOfMessages; + + if (_state != GRXWriterStateStarted || !_callOptions.flowControlEnabled) { + return; + } + [self maybeStartNextRead]; + } +} + +#pragma mark GRXWriteable implementation + +// Only called from the call queue. The error handler will be called from the +// network queue if the write didn't succeed. +// If the call is a unary call, parameter \a errorHandler will be ignored and +// the error handler of GRPCOpSendClose will be executed in case of error. +- (void)writeMessage:(NSData *)message withErrorHandler:(void (^)(void))errorHandler { + __weak GRPCCall *weakSelf = self; + void (^resumingHandler)(void) = ^{ + // Resume the request writer. + GRPCCall *strongSelf = weakSelf; + if (strongSelf) { + strongSelf->_requestWriter.state = GRXWriterStateStarted; + if (strongSelf->_writeDone) { + strongSelf->_writeDone(); + } + } + }; + GRPCOpSendMessage *op = + [[GRPCOpSendMessage alloc] initWithMessage:message handler:resumingHandler]; + if (!_unaryCall) { + [_wrappedCall startBatchWithOperations:@[ op ] errorHandler:errorHandler]; + } else { + // Ignored errorHandler since it is the same as the one for GRPCOpSendClose. + // TODO (mxyan): unify the error handlers of all Ops into a single closure. + [_unaryOpBatch addObject:op]; + } +} + +- (void)writeValue:(id)value { + NSAssert([value isKindOfClass:[NSData class]], @"value must be of type NSData"); + + @synchronized(self) { + if (_state == GRXWriterStateFinished) { + return; + } + } + + // Pause the input and only resume it when the C layer notifies us that writes + // can proceed. + _requestWriter.state = GRXWriterStatePaused; + + dispatch_async(_callQueue, ^{ + // Write error is not processed here. It is handled by op batch of GRPC_OP_RECV_STATUS_ON_CLIENT + [self writeMessage:value withErrorHandler:nil]; + }); +} + +// Only called from the call queue. The error handler will be called from the +// network queue if the requests stream couldn't be closed successfully. +- (void)finishRequestWithErrorHandler:(void (^)(void))errorHandler { + if (!_unaryCall) { + [_wrappedCall startBatchWithOperations:@[ [[GRPCOpSendClose alloc] init] ] + errorHandler:errorHandler]; + } else { + [_unaryOpBatch addObject:[[GRPCOpSendClose alloc] init]]; + [_wrappedCall startBatchWithOperations:_unaryOpBatch errorHandler:errorHandler]; + } +} + +- (void)writesFinishedWithError:(NSError *)errorOrNil { + if (errorOrNil) { + [self cancel]; + } else { + dispatch_async(_callQueue, ^{ + // EOS error is not processed here. It is handled by op batch of GRPC_OP_RECV_STATUS_ON_CLIENT + [self finishRequestWithErrorHandler:nil]; + }); + } +} + +#pragma mark Invoke + +// Both handlers will eventually be called, from the network queue. Writes can start immediately +// after this. +// The first one (headersHandler), when the response headers are received. +// The second one (completionHandler), whenever the RPC finishes for any reason. +- (void)invokeCallWithHeadersHandler:(void (^)(NSDictionary *))headersHandler + completionHandler:(void (^)(NSError *, NSDictionary *))completionHandler { + dispatch_async(_callQueue, ^{ + // TODO(jcanizales): Add error handlers for async failures + [self->_wrappedCall + startBatchWithOperations:@[ [[GRPCOpRecvMetadata alloc] initWithHandler:headersHandler] ]]; + [self->_wrappedCall + startBatchWithOperations:@[ [[GRPCOpRecvStatus alloc] initWithHandler:completionHandler] ]]; }); } +- (void)invokeCall { + __weak GRPCCall *weakSelf = self; + [self invokeCallWithHeadersHandler:^(NSDictionary *headers) { + // Response headers received. + __strong GRPCCall *strongSelf = weakSelf; + if (strongSelf) { + @synchronized(strongSelf) { + // it is ok to set nil because headers are only received once + strongSelf.responseHeaders = nil; + // copy the header so that the GRPCOpRecvMetadata object may be dealloc'ed + NSDictionary *copiedHeaders = + [[NSDictionary alloc] initWithDictionary:headers copyItems:YES]; + strongSelf.responseHeaders = copiedHeaders; + strongSelf->_pendingCoreRead = NO; + [strongSelf maybeStartNextRead]; + } + } + } + completionHandler:^(NSError *error, NSDictionary *trailers) { + __strong GRPCCall *strongSelf = weakSelf; + if (strongSelf) { + strongSelf.responseTrailers = trailers; + + if (error) { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + if (error.userInfo) { + [userInfo addEntriesFromDictionary:error.userInfo]; + } + userInfo[kGRPCTrailersKey] = strongSelf.responseTrailers; + // Since gRPC core does not guarantee the headers block being called before this block, + // responseHeaders might be nil. + userInfo[kGRPCHeadersKey] = strongSelf.responseHeaders; + error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo]; + } + [strongSelf finishWithError:error]; + strongSelf->_requestWriter.state = GRXWriterStateFinished; + } + }]; +} + +#pragma mark GRXWriter implementation + +// Lock acquired inside startWithWriteable: +- (void)startCallWithWriteable:(id<GRXWriteable>)writeable { + @synchronized(self) { + if (_state == GRXWriterStateFinished) { + return; + } + + _responseWriteable = + [[GRXConcurrentWriteable alloc] initWithWriteable:writeable dispatchQueue:_responseQueue]; + + GRPCPooledChannel *channel = + [[GRPCChannelPool sharedInstance] channelWithHost:_host callOptions:_callOptions]; + _wrappedCall = [channel wrappedCallWithPath:_path + completionQueue:[GRPCCompletionQueue completionQueue] + callOptions:_callOptions]; + + if (_wrappedCall == nil) { + [self finishWithError:[NSError errorWithDomain:kGRPCErrorDomain + code:GRPCErrorCodeUnavailable + userInfo:@{ + NSLocalizedDescriptionKey : + @"Failed to create call or channel." + }]]; + return; + } + + [self sendHeaders]; + [self invokeCall]; + } + + // Now that the RPC has been initiated, request writes can start. + [_requestWriter startWithWriteable:self]; +} + +- (void)startWithWriteable:(id<GRXWriteable>)writeable { + id<GRPCAuthorizationProtocol> tokenProvider = nil; + @synchronized(self) { + _state = GRXWriterStateStarted; + + // Create a retain cycle so that this instance lives until the RPC finishes (or is cancelled). + // This makes RPCs in which the call isn't externally retained possible (as long as it is + // started before being autoreleased). Care is taken not to retain self strongly in any of the + // blocks used in this implementation, so that the life of the instance is determined by this + // retain cycle. + _retainSelf = self; + + if (_callOptions == nil) { + GRPCMutableCallOptions *callOptions = [[GRPCHost callOptionsForHost:_host] mutableCopy]; + if (_serverName.length != 0) { + callOptions.serverAuthority = _serverName; + } + if (_timeout > 0) { + callOptions.timeout = _timeout; + } + uint32_t callFlags = [GRPCCall callFlagsForHost:_host path:_path]; + if (callFlags != 0) { + if (callFlags == GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) { + _callSafety = GRPCCallSafetyIdempotentRequest; + } else if (callFlags == GRPC_INITIAL_METADATA_CACHEABLE_REQUEST) { + _callSafety = GRPCCallSafetyCacheableRequest; + } + } + + id<GRPCAuthorizationProtocol> tokenProvider = self.tokenProvider; + if (tokenProvider != nil) { + callOptions.authTokenProvider = tokenProvider; + } + _callOptions = callOptions; + } + + NSAssert(_callOptions.authTokenProvider == nil || _callOptions.oauth2AccessToken == nil, + @"authTokenProvider and oauth2AccessToken cannot be set at the same time"); + + tokenProvider = _callOptions.authTokenProvider; + } + + if (tokenProvider != nil) { + __weak typeof(self) weakSelf = self; + [tokenProvider getTokenWithHandler:^(NSString *token) { + __strong typeof(self) strongSelf = weakSelf; + if (strongSelf) { + BOOL startCall = NO; + @synchronized(strongSelf) { + if (strongSelf->_state != GRXWriterStateFinished) { + startCall = YES; + if (token) { + strongSelf->_fetchedOauth2AccessToken = [token copy]; + } + } + } + if (startCall) { + [strongSelf startCallWithWriteable:writeable]; + } + } + }]; + } else { + [self startCallWithWriteable:writeable]; + } +} + +- (void)setState:(GRXWriterState)newState { + @synchronized(self) { + // Manual transitions are only allowed from the started or paused states. + if (_state == GRXWriterStateNotStarted || _state == GRXWriterStateFinished) { + return; + } + + switch (newState) { + case GRXWriterStateFinished: + _state = newState; + // Per GRXWriter's contract, setting the state to Finished manually + // means one doesn't wish the writeable to be messaged anymore. + [_responseWriteable cancelSilently]; + _responseWriteable = nil; + return; + case GRXWriterStatePaused: + _state = newState; + return; + case GRXWriterStateStarted: + if (_state == GRXWriterStatePaused) { + _state = newState; + [self maybeStartNextRead]; + } + return; + case GRXWriterStateNotStarted: + return; + } + } +} + @end diff --git a/src/objective-c/GRPCClient/GRPCCallLegacy.h b/src/objective-c/GRPCClient/GRPCCallLegacy.h deleted file mode 100644 index 51dd7da3440169de57664bd616e07a5c430a8706..0000000000000000000000000000000000000000 --- a/src/objective-c/GRPCClient/GRPCCallLegacy.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * This is the legacy interface of this gRPC library. This API is deprecated and users should use - * the API in GRPCCall.h. This API exists solely for the purpose of backwards compatibility. - */ - -#import <RxLibrary/GRXWriter.h> -#import "GRPCTypes.h" - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wnullability-completeness" - -/** - * This interface is deprecated. Please use \a GRPCCall2. - * - * Represents a single gRPC remote call. - */ -@interface GRPCCall : GRXWriter - -- (instancetype)init NS_UNAVAILABLE; - -/** - * The container of the request headers of an RPC conforms to this protocol, which is a subset of - * NSMutableDictionary's interface. It will become a NSMutableDictionary later on. - * The keys of this container are the header names, which per the HTTP standard are case- - * insensitive. They are stored in lowercase (which is how HTTP/2 mandates them on the wire), and - * can only consist of ASCII characters. - * A header value is a NSString object (with only ASCII characters), unless the header name has the - * suffix "-bin", in which case the value has to be a NSData object. - */ -/** - * These HTTP headers will be passed to the server as part of this call. Each HTTP header is a - * name-value pair with string names and either string or binary values. - * - * The passed dictionary has to use NSString keys, corresponding to the header names. The value - * associated to each can be a NSString object or a NSData object. E.g.: - * - * call.requestHeaders = @{@"authorization": @"Bearer ..."}; - * - * call.requestHeaders[@"my-header-bin"] = someData; - * - * After the call is started, trying to modify this property is an error. - * - * The property is initialized to an empty NSMutableDictionary. - */ -@property(atomic, readonly) NSMutableDictionary *requestHeaders; - -/** - * This dictionary is populated with the HTTP headers received from the server. This happens before - * any response message is received from the server. It has the same structure as the request - * headers dictionary: Keys are NSString header names; names ending with the suffix "-bin" have a - * NSData value; the others have a NSString value. - * - * The value of this property is nil until all response headers are received, and will change before - * any of -writeValue: or -writesFinishedWithError: are sent to the writeable. - */ -@property(atomic, readonly) NSDictionary *responseHeaders; - -/** - * Same as responseHeaders, but populated with the HTTP trailers received from the server before the - * call finishes. - * - * The value of this property is nil until all response trailers are received, and will change - * before -writesFinishedWithError: is sent to the writeable. - */ -@property(atomic, readonly) NSDictionary *responseTrailers; - -/** - * The request writer has to write NSData objects into the provided Writeable. The server will - * receive each of those separately and in order as distinct messages. - * A gRPC call might not complete until the request writer finishes. On the other hand, the request - * finishing doesn't necessarily make the call to finish, as the server might continue sending - * messages to the response side of the call indefinitely (depending on the semantics of the - * specific remote method called). - * To finish a call right away, invoke cancel. - * host parameter should not contain the scheme (http:// or https://), only the name or IP addr - * and the port number, for example @"localhost:5050". - */ -- (instancetype)initWithHost:(NSString *)host - path:(NSString *)path - requestsWriter:(GRXWriter *)requestWriter; - -/** - * Finishes the request side of this call, notifies the server that the RPC should be cancelled, and - * finishes the response side of the call with an error of code CANCELED. - */ -- (void)cancel; - -/** - * The following methods are deprecated. - */ -+ (void)setCallSafety:(GRPCCallSafety)callSafety host:(NSString *)host path:(NSString *)path; -@property(atomic, copy, readwrite) NSString *serverName; -@property NSTimeInterval timeout; -- (void)setResponseDispatchQueue:(dispatch_queue_t)queue; - -@end - -#pragma mark Backwards compatibiity - -/** This protocol is kept for backwards compatibility with existing code. */ -DEPRECATED_MSG_ATTRIBUTE("Use NSDictionary or NSMutableDictionary instead.") -@protocol GRPCRequestHeaders<NSObject> -@property(nonatomic, readonly) NSUInteger count; - -- (id)objectForKeyedSubscript:(id)key; -- (void)setObject:(id)obj forKeyedSubscript:(id)key; - -- (void)removeAllObjects; -- (void)removeObjectForKey:(id)key; -@end - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated" -/** This is only needed for backwards-compatibility. */ -@interface NSMutableDictionary (GRPCRequestHeaders)<GRPCRequestHeaders> -@end -#pragma clang diagnostic pop -#pragma clang diagnostic pop diff --git a/src/objective-c/GRPCClient/GRPCCallLegacy.m b/src/objective-c/GRPCClient/GRPCCallLegacy.m deleted file mode 100644 index d06048c3a89b3c08bd40fe33965a3eb62ede1e06..0000000000000000000000000000000000000000 --- a/src/objective-c/GRPCClient/GRPCCallLegacy.m +++ /dev/null @@ -1,677 +0,0 @@ -/* - * - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#import "GRPCCallLegacy.h" - -#import "GRPCCall+OAuth2.h" -#import "GRPCCallOptions.h" -#import "GRPCTypes.h" - -#import "private/GRPCCore/GRPCChannelPool.h" -#import "private/GRPCCore/GRPCCompletionQueue.h" -#import "private/GRPCCore/GRPCHost.h" -#import "private/GRPCCore/GRPCWrappedCall.h" -#import "private/GRPCCore/NSData+GRPC.h" - -#import <RxLibrary/GRXBufferedPipe.h> -#import <RxLibrary/GRXConcurrentWriteable.h> -#import <RxLibrary/GRXImmediateSingleWriter.h> -#import <RxLibrary/GRXWriter+Immediate.h> - -#include <grpc/grpc.h> - -const char *kCFStreamVarName = "grpc_cfstream"; -static NSMutableDictionary *callFlags; - -// At most 6 ops can be in an op batch for a client: SEND_INITIAL_METADATA, -// SEND_MESSAGE, SEND_CLOSE_FROM_CLIENT, RECV_INITIAL_METADATA, RECV_MESSAGE, -// and RECV_STATUS_ON_CLIENT. -NSInteger kMaxClientBatch = 6; - -static NSString *const kAuthorizationHeader = @"authorization"; -static NSString *const kBearerPrefix = @"Bearer "; - -@interface GRPCCall ()<GRXWriteable> -// Make them read-write. -@property(atomic, strong) NSDictionary *responseHeaders; -@property(atomic, strong) NSDictionary *responseTrailers; - -- (void)receiveNextMessages:(NSUInteger)numberOfMessages; - -@end - -// The following methods of a C gRPC call object aren't reentrant, and thus -// calls to them must be serialized: -// - start_batch -// - destroy -// -// start_batch with a SEND_MESSAGE argument can only be called after the -// OP_COMPLETE event for any previous write is received. This is achieved by -// pausing the requests writer immediately every time it writes a value, and -// resuming it again when OP_COMPLETE is received. -// -// Similarly, start_batch with a RECV_MESSAGE argument can only be called after -// the OP_COMPLETE event for any previous read is received.This is easier to -// enforce, as we're writing the received messages into the writeable: -// start_batch is enqueued once upon receiving the OP_COMPLETE event for the -// RECV_METADATA batch, and then once after receiving each OP_COMPLETE event for -// each RECV_MESSAGE batch. -@implementation GRPCCall { - dispatch_queue_t _callQueue; - - NSString *_host; - NSString *_path; - GRPCCallSafety _callSafety; - GRPCCallOptions *_callOptions; - GRPCWrappedCall *_wrappedCall; - - // The C gRPC library has less guarantees on the ordering of events than we - // do. Particularly, in the face of errors, there's no ordering guarantee at - // all. This wrapper over our actual writeable ensures thread-safety and - // correct ordering. - GRXConcurrentWriteable *_responseWriteable; - - // The network thread wants the requestWriter to resume (when the server is ready for more input), - // or to stop (on errors), concurrently with user threads that want to start it, pause it or stop - // it. Because a writer isn't thread-safe, we'll synchronize those operations on it. - // We don't use a dispatch queue for that purpose, because the writer can call writeValue: or - // writesFinishedWithError: on this GRPCCall as part of those operations. We want to be able to - // pause the writer immediately on writeValue:, so we need our locking to be recursive. - GRXWriter *_requestWriter; - - // To create a retain cycle when a call is started, up until it finishes. See - // |startWithWriteable:| and |finishWithError:|. This saves users from having to retain a - // reference to the call object if all they're interested in is the handler being executed when - // the response arrives. - GRPCCall *_retainSelf; - - GRPCRequestHeaders *_requestHeaders; - - // In the case that the call is a unary call (i.e. the writer to GRPCCall is of type - // GRXImmediateSingleWriter), GRPCCall will delay sending ops (not send them to C core - // immediately) and buffer them into a batch _unaryOpBatch. The batch is sent to C core when - // the SendClose op is added. - BOOL _unaryCall; - NSMutableArray *_unaryOpBatch; - - // The dispatch queue to be used for enqueuing responses to user. Defaulted to the main dispatch - // queue - dispatch_queue_t _responseQueue; - - // The OAuth2 token fetched from a token provider. - NSString *_fetchedOauth2AccessToken; - - // The callback to be called when a write message op is done. - void (^_writeDone)(void); - - // Indicate a read request to core is pending. - BOOL _pendingCoreRead; - - // Indicate pending read message request from user. - NSUInteger _pendingReceiveNextMessages; -} - -@synthesize state = _state; - -+ (void)initialize { - // Guarantees the code in {} block is invoked only once. See ref at: - // https://developer.apple.com/documentation/objectivec/nsobject/1418639-initialize?language=objc - if (self == [GRPCCall self]) { - grpc_init(); - callFlags = [NSMutableDictionary dictionary]; - } -} - -+ (void)setCallSafety:(GRPCCallSafety)callSafety host:(NSString *)host path:(NSString *)path { - if (host.length == 0 || path.length == 0) { - return; - } - NSString *hostAndPath = [NSString stringWithFormat:@"%@/%@", host, path]; - @synchronized(callFlags) { - switch (callSafety) { - case GRPCCallSafetyDefault: - callFlags[hostAndPath] = @0; - break; - case GRPCCallSafetyIdempotentRequest: - callFlags[hostAndPath] = @GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST; - break; - case GRPCCallSafetyCacheableRequest: - callFlags[hostAndPath] = @GRPC_INITIAL_METADATA_CACHEABLE_REQUEST; - break; - default: - break; - } - } -} - -+ (uint32_t)callFlagsForHost:(NSString *)host path:(NSString *)path { - NSString *hostAndPath = [NSString stringWithFormat:@"%@/%@", host, path]; - @synchronized(callFlags) { - return [callFlags[hostAndPath] intValue]; - } -} - -- (instancetype)initWithHost:(NSString *)host - path:(NSString *)path - requestsWriter:(GRXWriter *)requestWriter { - return [self initWithHost:host - path:path - callSafety:GRPCCallSafetyDefault - requestsWriter:requestWriter - callOptions:nil - writeDone:nil]; -} - -- (instancetype)initWithHost:(NSString *)host - path:(NSString *)path - callSafety:(GRPCCallSafety)safety - requestsWriter:(GRXWriter *)requestsWriter - callOptions:(GRPCCallOptions *)callOptions - writeDone:(void (^)(void))writeDone { - // Purposely using pointer rather than length (host.length == 0) for backwards compatibility. - NSAssert(host != nil && path != nil, @"Neither host nor path can be nil."); - NSAssert(safety <= GRPCCallSafetyCacheableRequest, @"Invalid call safety value."); - NSAssert(requestsWriter.state == GRXWriterStateNotStarted, - @"The requests writer can't be already started."); - if (!host || !path) { - return nil; - } - if (safety > GRPCCallSafetyCacheableRequest) { - return nil; - } - if (requestsWriter.state != GRXWriterStateNotStarted) { - return nil; - } - - if ((self = [super init])) { - _host = [host copy]; - _path = [path copy]; - _callSafety = safety; - _callOptions = [callOptions copy]; - - // Serial queue to invoke the non-reentrant methods of the grpc_call object. - _callQueue = dispatch_queue_create("io.grpc.call", DISPATCH_QUEUE_SERIAL); - - _requestWriter = requestsWriter; - _requestHeaders = [[GRPCRequestHeaders alloc] initWithCall:self]; - _writeDone = writeDone; - - if ([requestsWriter isKindOfClass:[GRXImmediateSingleWriter class]]) { - _unaryCall = YES; - _unaryOpBatch = [NSMutableArray arrayWithCapacity:kMaxClientBatch]; - } - - _responseQueue = dispatch_get_main_queue(); - - // do not start a read until initial metadata is received - _pendingReceiveNextMessages = 0; - _pendingCoreRead = YES; - } - return self; -} - -- (void)setResponseDispatchQueue:(dispatch_queue_t)queue { - @synchronized(self) { - if (_state != GRXWriterStateNotStarted) { - return; - } - _responseQueue = queue; - } -} - -#pragma mark Finish - -// This function should support being called within a @synchronized(self) block in another function -// Should not manipulate _requestWriter for deadlock prevention. -- (void)finishWithError:(NSError *)errorOrNil { - @synchronized(self) { - if (_state == GRXWriterStateFinished) { - return; - } - _state = GRXWriterStateFinished; - - if (errorOrNil) { - [_responseWriteable cancelWithError:errorOrNil]; - } else { - [_responseWriteable enqueueSuccessfulCompletion]; - } - - // If the call isn't retained anywhere else, it can be deallocated now. - _retainSelf = nil; - } -} - -- (void)cancel { - @synchronized(self) { - if (_state == GRXWriterStateFinished) { - return; - } - [self finishWithError:[NSError - errorWithDomain:kGRPCErrorDomain - code:GRPCErrorCodeCancelled - userInfo:@{NSLocalizedDescriptionKey : @"Canceled by app"}]]; - [_wrappedCall cancel]; - } - _requestWriter.state = GRXWriterStateFinished; -} - -- (void)dealloc { - __block GRPCWrappedCall *wrappedCall = _wrappedCall; - dispatch_async(_callQueue, ^{ - wrappedCall = nil; - }); -} - -#pragma mark Read messages - -// Only called from the call queue. -// The handler will be called from the network queue. -- (void)startReadWithHandler:(void (^)(grpc_byte_buffer *))handler { - // TODO(jcanizales): Add error handlers for async failures - [_wrappedCall startBatchWithOperations:@[ [[GRPCOpRecvMessage alloc] initWithHandler:handler] ]]; -} - -// Called initially from the network queue once response headers are received, -// then "recursively" from the responseWriteable queue after each response from the -// server has been written. -// If the call is currently paused, this is a noop. Restarting the call will invoke this -// method. -// TODO(jcanizales): Rename to readResponseIfNotPaused. -- (void)maybeStartNextRead { - @synchronized(self) { - if (_state != GRXWriterStateStarted) { - return; - } - if (_callOptions.flowControlEnabled && (_pendingCoreRead || _pendingReceiveNextMessages == 0)) { - return; - } - _pendingCoreRead = YES; - _pendingReceiveNextMessages--; - } - - dispatch_async(_callQueue, ^{ - __weak GRPCCall *weakSelf = self; - [self startReadWithHandler:^(grpc_byte_buffer *message) { - if (message == NULL) { - // No more messages from the server - return; - } - __strong GRPCCall *strongSelf = weakSelf; - if (strongSelf == nil) { - grpc_byte_buffer_destroy(message); - return; - } - NSData *data = [NSData grpc_dataWithByteBuffer:message]; - grpc_byte_buffer_destroy(message); - if (!data) { - // The app doesn't have enough memory to hold the server response. We - // don't want to throw, because the app shouldn't crash for a behavior - // that's on the hands of any server to have. Instead we finish and ask - // the server to cancel. - @synchronized(strongSelf) { - strongSelf->_pendingCoreRead = NO; - [strongSelf - finishWithError:[NSError errorWithDomain:kGRPCErrorDomain - code:GRPCErrorCodeResourceExhausted - userInfo:@{ - NSLocalizedDescriptionKey : - @"Client does not have enough memory to " - @"hold the server response." - }]]; - [strongSelf->_wrappedCall cancel]; - } - strongSelf->_requestWriter.state = GRXWriterStateFinished; - } else { - @synchronized(strongSelf) { - [strongSelf->_responseWriteable enqueueValue:data - completionHandler:^{ - __strong GRPCCall *strongSelf = weakSelf; - if (strongSelf) { - @synchronized(strongSelf) { - strongSelf->_pendingCoreRead = NO; - [strongSelf maybeStartNextRead]; - } - } - }]; - } - } - }]; - }); -} - -#pragma mark Send headers - -- (void)sendHeaders { - // TODO (mxyan): Remove after deprecated methods are removed - uint32_t callSafetyFlags = 0; - switch (_callSafety) { - case GRPCCallSafetyDefault: - callSafetyFlags = 0; - break; - case GRPCCallSafetyIdempotentRequest: - callSafetyFlags = GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST; - break; - case GRPCCallSafetyCacheableRequest: - callSafetyFlags = GRPC_INITIAL_METADATA_CACHEABLE_REQUEST; - break; - } - - NSMutableDictionary *headers = [_requestHeaders mutableCopy]; - NSString *fetchedOauth2AccessToken; - @synchronized(self) { - fetchedOauth2AccessToken = _fetchedOauth2AccessToken; - } - if (fetchedOauth2AccessToken != nil) { - headers[@"authorization"] = [kBearerPrefix stringByAppendingString:fetchedOauth2AccessToken]; - } else if (_callOptions.oauth2AccessToken != nil) { - headers[@"authorization"] = - [kBearerPrefix stringByAppendingString:_callOptions.oauth2AccessToken]; - } - - // TODO(jcanizales): Add error handlers for async failures - GRPCOpSendMetadata *op = [[GRPCOpSendMetadata alloc] - initWithMetadata:headers - flags:callSafetyFlags - handler:nil]; // No clean-up needed after SEND_INITIAL_METADATA - dispatch_async(_callQueue, ^{ - if (!self->_unaryCall) { - [self->_wrappedCall startBatchWithOperations:@[ op ]]; - } else { - [self->_unaryOpBatch addObject:op]; - } - }); -} - -- (void)receiveNextMessages:(NSUInteger)numberOfMessages { - if (numberOfMessages == 0) { - return; - } - @synchronized(self) { - _pendingReceiveNextMessages += numberOfMessages; - - if (_state != GRXWriterStateStarted || !_callOptions.flowControlEnabled) { - return; - } - [self maybeStartNextRead]; - } -} - -#pragma mark GRXWriteable implementation - -// Only called from the call queue. The error handler will be called from the -// network queue if the write didn't succeed. -// If the call is a unary call, parameter \a errorHandler will be ignored and -// the error handler of GRPCOpSendClose will be executed in case of error. -- (void)writeMessage:(NSData *)message withErrorHandler:(void (^)(void))errorHandler { - __weak GRPCCall *weakSelf = self; - void (^resumingHandler)(void) = ^{ - // Resume the request writer. - GRPCCall *strongSelf = weakSelf; - if (strongSelf) { - strongSelf->_requestWriter.state = GRXWriterStateStarted; - if (strongSelf->_writeDone) { - strongSelf->_writeDone(); - } - } - }; - GRPCOpSendMessage *op = - [[GRPCOpSendMessage alloc] initWithMessage:message handler:resumingHandler]; - if (!_unaryCall) { - [_wrappedCall startBatchWithOperations:@[ op ] errorHandler:errorHandler]; - } else { - // Ignored errorHandler since it is the same as the one for GRPCOpSendClose. - // TODO (mxyan): unify the error handlers of all Ops into a single closure. - [_unaryOpBatch addObject:op]; - } -} - -- (void)writeValue:(id)value { - NSAssert([value isKindOfClass:[NSData class]], @"value must be of type NSData"); - - @synchronized(self) { - if (_state == GRXWriterStateFinished) { - return; - } - } - - // Pause the input and only resume it when the C layer notifies us that writes - // can proceed. - _requestWriter.state = GRXWriterStatePaused; - - dispatch_async(_callQueue, ^{ - // Write error is not processed here. It is handled by op batch of GRPC_OP_RECV_STATUS_ON_CLIENT - [self writeMessage:value withErrorHandler:nil]; - }); -} - -// Only called from the call queue. The error handler will be called from the -// network queue if the requests stream couldn't be closed successfully. -- (void)finishRequestWithErrorHandler:(void (^)(void))errorHandler { - if (!_unaryCall) { - [_wrappedCall startBatchWithOperations:@[ [[GRPCOpSendClose alloc] init] ] - errorHandler:errorHandler]; - } else { - [_unaryOpBatch addObject:[[GRPCOpSendClose alloc] init]]; - [_wrappedCall startBatchWithOperations:_unaryOpBatch errorHandler:errorHandler]; - } -} - -- (void)writesFinishedWithError:(NSError *)errorOrNil { - if (errorOrNil) { - [self cancel]; - } else { - dispatch_async(_callQueue, ^{ - // EOS error is not processed here. It is handled by op batch of GRPC_OP_RECV_STATUS_ON_CLIENT - [self finishRequestWithErrorHandler:nil]; - }); - } -} - -#pragma mark Invoke - -// Both handlers will eventually be called, from the network queue. Writes can start immediately -// after this. -// The first one (headersHandler), when the response headers are received. -// The second one (completionHandler), whenever the RPC finishes for any reason. -- (void)invokeCallWithHeadersHandler:(void (^)(NSDictionary *))headersHandler - completionHandler:(void (^)(NSError *, NSDictionary *))completionHandler { - dispatch_async(_callQueue, ^{ - // TODO(jcanizales): Add error handlers for async failures - [self->_wrappedCall - startBatchWithOperations:@[ [[GRPCOpRecvMetadata alloc] initWithHandler:headersHandler] ]]; - [self->_wrappedCall - startBatchWithOperations:@[ [[GRPCOpRecvStatus alloc] initWithHandler:completionHandler] ]]; - }); -} - -- (void)invokeCall { - __weak GRPCCall *weakSelf = self; - [self invokeCallWithHeadersHandler:^(NSDictionary *headers) { - // Response headers received. - __strong GRPCCall *strongSelf = weakSelf; - if (strongSelf) { - @synchronized(strongSelf) { - // it is ok to set nil because headers are only received once - strongSelf.responseHeaders = nil; - // copy the header so that the GRPCOpRecvMetadata object may be dealloc'ed - NSDictionary *copiedHeaders = - [[NSDictionary alloc] initWithDictionary:headers copyItems:YES]; - strongSelf.responseHeaders = copiedHeaders; - strongSelf->_pendingCoreRead = NO; - [strongSelf maybeStartNextRead]; - } - } - } - completionHandler:^(NSError *error, NSDictionary *trailers) { - __strong GRPCCall *strongSelf = weakSelf; - if (strongSelf) { - strongSelf.responseTrailers = trailers; - - if (error) { - NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; - if (error.userInfo) { - [userInfo addEntriesFromDictionary:error.userInfo]; - } - userInfo[kGRPCTrailersKey] = strongSelf.responseTrailers; - // Since gRPC core does not guarantee the headers block being called before this block, - // responseHeaders might be nil. - userInfo[kGRPCHeadersKey] = strongSelf.responseHeaders; - error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo]; - } - [strongSelf finishWithError:error]; - strongSelf->_requestWriter.state = GRXWriterStateFinished; - } - }]; -} - -#pragma mark GRXWriter implementation - -// Lock acquired inside startWithWriteable: -- (void)startCallWithWriteable:(id<GRXWriteable>)writeable { - @synchronized(self) { - if (_state == GRXWriterStateFinished) { - return; - } - - _responseWriteable = - [[GRXConcurrentWriteable alloc] initWithWriteable:writeable dispatchQueue:_responseQueue]; - - GRPCPooledChannel *channel = - [[GRPCChannelPool sharedInstance] channelWithHost:_host callOptions:_callOptions]; - _wrappedCall = [channel wrappedCallWithPath:_path - completionQueue:[GRPCCompletionQueue completionQueue] - callOptions:_callOptions]; - - if (_wrappedCall == nil) { - [self finishWithError:[NSError errorWithDomain:kGRPCErrorDomain - code:GRPCErrorCodeUnavailable - userInfo:@{ - NSLocalizedDescriptionKey : - @"Failed to create call or channel." - }]]; - return; - } - - [self sendHeaders]; - [self invokeCall]; - } - - // Now that the RPC has been initiated, request writes can start. - [_requestWriter startWithWriteable:self]; -} - -- (void)startWithWriteable:(id<GRXWriteable>)writeable { - id<GRPCAuthorizationProtocol> tokenProvider = nil; - @synchronized(self) { - _state = GRXWriterStateStarted; - - // Create a retain cycle so that this instance lives until the RPC finishes (or is cancelled). - // This makes RPCs in which the call isn't externally retained possible (as long as it is - // started before being autoreleased). Care is taken not to retain self strongly in any of the - // blocks used in this implementation, so that the life of the instance is determined by this - // retain cycle. - _retainSelf = self; - - // If _callOptions is nil, people must be using the deprecated v1 interface. In this case, - // generate the call options from the corresponding GRPCHost configs and apply other options - // that are not covered by GRPCHost. - if (_callOptions == nil) { - GRPCMutableCallOptions *callOptions = [[GRPCHost callOptionsForHost:_host] mutableCopy]; - if (_serverName.length != 0) { - callOptions.serverAuthority = _serverName; - } - if (_timeout > 0) { - callOptions.timeout = _timeout; - } - uint32_t callFlags = [GRPCCall callFlagsForHost:_host path:_path]; - if (callFlags != 0) { - if (callFlags == GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) { - _callSafety = GRPCCallSafetyIdempotentRequest; - } else if (callFlags == GRPC_INITIAL_METADATA_CACHEABLE_REQUEST) { - _callSafety = GRPCCallSafetyCacheableRequest; - } - } - - id<GRPCAuthorizationProtocol> tokenProvider = self.tokenProvider; - if (tokenProvider != nil) { - callOptions.authTokenProvider = tokenProvider; - } - _callOptions = callOptions; - } - - NSAssert(_callOptions.authTokenProvider == nil || _callOptions.oauth2AccessToken == nil, - @"authTokenProvider and oauth2AccessToken cannot be set at the same time"); - - tokenProvider = _callOptions.authTokenProvider; - } - - if (tokenProvider != nil) { - __weak typeof(self) weakSelf = self; - [tokenProvider getTokenWithHandler:^(NSString *token) { - __strong typeof(self) strongSelf = weakSelf; - if (strongSelf) { - BOOL startCall = NO; - @synchronized(strongSelf) { - if (strongSelf->_state != GRXWriterStateFinished) { - startCall = YES; - if (token) { - strongSelf->_fetchedOauth2AccessToken = [token copy]; - } - } - } - if (startCall) { - [strongSelf startCallWithWriteable:writeable]; - } - } - }]; - } else { - [self startCallWithWriteable:writeable]; - } -} - -- (void)setState:(GRXWriterState)newState { - @synchronized(self) { - // Manual transitions are only allowed from the started or paused states. - if (_state == GRXWriterStateNotStarted || _state == GRXWriterStateFinished) { - return; - } - - switch (newState) { - case GRXWriterStateFinished: - _state = newState; - // Per GRXWriter's contract, setting the state to Finished manually - // means one doesn't wish the writeable to be messaged anymore. - [_responseWriteable cancelSilently]; - _responseWriteable = nil; - return; - case GRXWriterStatePaused: - _state = newState; - return; - case GRXWriterStateStarted: - if (_state == GRXWriterStatePaused) { - _state = newState; - [self maybeStartNextRead]; - } - return; - case GRXWriterStateNotStarted: - return; - } - } -} - -@end diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.h b/src/objective-c/GRPCClient/GRPCCallOptions.h index e4261b5b5f9dec7adbc9b80a3352bc5cddb37129..98511e3f5cb3d00277a494e8bb67906e92d76ff9 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.h +++ b/src/objective-c/GRPCClient/GRPCCallOptions.h @@ -18,11 +18,57 @@ #import <Foundation/Foundation.h> -#import "GRPCTypes.h" - NS_ASSUME_NONNULL_BEGIN -@protocol GRPCInterceptorFactory; +/** + * Safety remark of a gRPC method as defined in RFC 2616 Section 9.1 + */ +typedef NS_ENUM(NSUInteger, GRPCCallSafety) { + /** Signal that there is no guarantees on how the call affects the server state. */ + GRPCCallSafetyDefault = 0, + /** Signal that the call is idempotent. gRPC is free to use PUT verb. */ + GRPCCallSafetyIdempotentRequest = 1, + /** + * Signal that the call is cacheable and will not affect server state. gRPC is free to use GET + * verb. + */ + GRPCCallSafetyCacheableRequest = 2, +}; + +// Compression algorithm to be used by a gRPC call +typedef NS_ENUM(NSUInteger, GRPCCompressionAlgorithm) { + GRPCCompressNone = 0, + GRPCCompressDeflate, + GRPCCompressGzip, + GRPCStreamCompressGzip, +}; + +// GRPCCompressAlgorithm is deprecated; use GRPCCompressionAlgorithm +typedef GRPCCompressionAlgorithm GRPCCompressAlgorithm; + +/** The transport to be used by a gRPC call */ +typedef NS_ENUM(NSUInteger, GRPCTransportType) { + GRPCTransportTypeDefault = 0, + /** gRPC internal HTTP/2 stack with BoringSSL */ + GRPCTransportTypeChttp2BoringSSL = 0, + /** Cronet stack */ + GRPCTransportTypeCronet, + /** Insecure channel. FOR TEST ONLY! */ + GRPCTransportTypeInsecure, +}; + +/** + * Implement this protocol to provide a token to gRPC when a call is initiated. + */ +@protocol GRPCAuthorizationProtocol + +/** + * This method is called when gRPC is about to start the call. When OAuth token is acquired, + * \a handler is expected to be called with \a token being the new token to be used for this call. + */ +- (void)getTokenWithHandler:(void (^)(NSString *_Nullable token))handler; + +@end @interface GRPCCallOptions : NSObject<NSCopying, NSMutableCopying> @@ -58,7 +104,7 @@ NS_ASSUME_NONNULL_BEGIN * this array. This parameter should not be modified by any interceptor and will * not take effect if done so. */ -@property(copy, readonly) NSArray<id<GRPCInterceptorFactory>> *interceptorFactories; +@property(copy, readonly) NSArray *interceptorFactories; // OAuth2 parameters. Users of gRPC may specify one of the following two parameters. @@ -146,23 +192,10 @@ NS_ASSUME_NONNULL_BEGIN @property(copy, readonly, nullable) NSString *PEMCertificateChain; /** - * Deprecated: this option is deprecated. Please use the property \a transport - * instead. - * * Select the transport type to be used for this call. */ @property(readonly) GRPCTransportType transportType; -/** - * The transport to be used for this call. Users may choose a native transport - * identifier defined in \a GRPCTransport or provided by a non-native transport - * implementation. If the option is left to be NULL, gRPC will use its default - * transport. - * - * This is currently an experimental option. - */ -@property(readonly) GRPCTransportId transport; - /** * Override the hostname during the TLS hostname validation process. */ @@ -234,7 +267,7 @@ NS_ASSUME_NONNULL_BEGIN * this array. This parameter should not be modified by any interceptor and will * not take effect if done so. */ -@property(copy, readwrite) NSArray<id<GRPCInterceptorFactory>> *interceptorFactories; +@property(copy, readwrite) NSArray *interceptorFactories; // OAuth2 parameters. Users of gRPC may specify one of the following two parameters. @@ -324,23 +357,10 @@ NS_ASSUME_NONNULL_BEGIN @property(copy, readwrite, nullable) NSString *PEMCertificateChain; /** - * Deprecated: this option is deprecated. Please use the property \a transport - * instead. - * * Select the transport type to be used for this call. */ @property(readwrite) GRPCTransportType transportType; -/** - * The transport to be used for this call. Users may choose a native transport - * identifier defined in \a GRPCTransport or provided by a non-native ttransport - * implementation. If the option is left to be NULL, gRPC will use its default - * transport. - * - * An interceptor must not change the value of this option. - */ -@property(readwrite) GRPCTransportId transport; - /** * Override the hostname during the TLS hostname validation process. */ diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.m index 7f88098eb6fe1856edfdd4ec5c50493f492b5baa..392e42a9d47d2a2884a2f6db7b8e8409a80ccd7f 100644 --- a/src/objective-c/GRPCClient/GRPCCallOptions.m +++ b/src/objective-c/GRPCClient/GRPCCallOptions.m @@ -17,14 +17,13 @@ */ #import "GRPCCallOptions.h" -#import "GRPCTransport.h" #import "internal/GRPCCallOptions+Internal.h" // The default values for the call options. static NSString *const kDefaultServerAuthority = nil; static const NSTimeInterval kDefaultTimeout = 0; static const BOOL kDefaultFlowControlEnabled = NO; -static NSArray<id<GRPCInterceptorFactory>> *const kDefaultInterceptorFactories = nil; +static NSArray *const kDefaultInterceptorFactories = nil; static NSDictionary *const kDefaultInitialMetadata = nil; static NSString *const kDefaultUserAgentPrefix = nil; static const NSUInteger kDefaultResponseSizeLimit = 0; @@ -42,7 +41,6 @@ static NSString *const kDefaultPEMCertificateChain = nil; static NSString *const kDefaultOauth2AccessToken = nil; static const id<GRPCAuthorizationProtocol> kDefaultAuthTokenProvider = nil; static const GRPCTransportType kDefaultTransportType = GRPCTransportTypeChttp2BoringSSL; -static const GRPCTransportId kDefaultTransport = NULL; static NSString *const kDefaultHostNameOverride = nil; static const id kDefaultLogContext = nil; static NSString *const kDefaultChannelPoolDomain = nil; @@ -64,7 +62,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) { NSString *_serverAuthority; NSTimeInterval _timeout; BOOL _flowControlEnabled; - NSArray<id<GRPCInterceptorFactory>> *_interceptorFactories; + NSArray *_interceptorFactories; NSString *_oauth2AccessToken; id<GRPCAuthorizationProtocol> _authTokenProvider; NSDictionary *_initialMetadata; @@ -82,7 +80,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) { NSString *_PEMPrivateKey; NSString *_PEMCertificateChain; GRPCTransportType _transportType; - GRPCTransportId _transport; NSString *_hostNameOverride; id<NSObject> _logContext; NSString *_channelPoolDomain; @@ -110,7 +107,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) { @synthesize PEMPrivateKey = _PEMPrivateKey; @synthesize PEMCertificateChain = _PEMCertificateChain; @synthesize transportType = _transportType; -@synthesize transport = _transport; @synthesize hostNameOverride = _hostNameOverride; @synthesize logContext = _logContext; @synthesize channelPoolDomain = _channelPoolDomain; @@ -138,7 +134,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) { PEMPrivateKey:kDefaultPEMPrivateKey PEMCertificateChain:kDefaultPEMCertificateChain transportType:kDefaultTransportType - transport:kDefaultTransport hostNameOverride:kDefaultHostNameOverride logContext:kDefaultLogContext channelPoolDomain:kDefaultChannelPoolDomain @@ -148,7 +143,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) { - (instancetype)initWithServerAuthority:(NSString *)serverAuthority timeout:(NSTimeInterval)timeout flowControlEnabled:(BOOL)flowControlEnabled - interceptorFactories:(NSArray<id<GRPCInterceptorFactory>> *)interceptorFactories + interceptorFactories:(NSArray *)interceptorFactories oauth2AccessToken:(NSString *)oauth2AccessToken authTokenProvider:(id<GRPCAuthorizationProtocol>)authTokenProvider initialMetadata:(NSDictionary *)initialMetadata @@ -166,7 +161,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) { PEMPrivateKey:(NSString *)PEMPrivateKey PEMCertificateChain:(NSString *)PEMCertificateChain transportType:(GRPCTransportType)transportType - transport:(GRPCTransportId)transport hostNameOverride:(NSString *)hostNameOverride logContext:(id)logContext channelPoolDomain:(NSString *)channelPoolDomain @@ -199,7 +193,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) { _PEMPrivateKey = [PEMPrivateKey copy]; _PEMCertificateChain = [PEMCertificateChain copy]; _transportType = transportType; - _transport = transport; _hostNameOverride = [hostNameOverride copy]; _logContext = logContext; _channelPoolDomain = [channelPoolDomain copy]; @@ -231,7 +224,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) { PEMPrivateKey:_PEMPrivateKey PEMCertificateChain:_PEMCertificateChain transportType:_transportType - transport:_transport hostNameOverride:_hostNameOverride logContext:_logContext channelPoolDomain:_channelPoolDomain @@ -264,7 +256,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) { PEMPrivateKey:[_PEMPrivateKey copy] PEMCertificateChain:[_PEMCertificateChain copy] transportType:_transportType - transport:_transport hostNameOverride:[_hostNameOverride copy] logContext:_logContext channelPoolDomain:[_channelPoolDomain copy] @@ -289,7 +280,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) { if (!areObjectsEqual(callOptions.PEMCertificateChain, _PEMCertificateChain)) return NO; if (!areObjectsEqual(callOptions.hostNameOverride, _hostNameOverride)) return NO; if (!(callOptions.transportType == _transportType)) return NO; - if (!(TransportIdIsEqual(callOptions.transport, _transport))) return NO; if (!areObjectsEqual(callOptions.logContext, _logContext)) return NO; if (!areObjectsEqual(callOptions.channelPoolDomain, _channelPoolDomain)) return NO; if (!(callOptions.channelID == _channelID)) return NO; @@ -314,7 +304,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) { result ^= _PEMCertificateChain.hash; result ^= _hostNameOverride.hash; result ^= _transportType; - result ^= TransportIdHash(_transport); result ^= _logContext.hash; result ^= _channelPoolDomain.hash; result ^= _channelID; @@ -347,7 +336,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) { @dynamic PEMPrivateKey; @dynamic PEMCertificateChain; @dynamic transportType; -@dynamic transport; @dynamic hostNameOverride; @dynamic logContext; @dynamic channelPoolDomain; @@ -375,7 +363,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) { PEMPrivateKey:kDefaultPEMPrivateKey PEMCertificateChain:kDefaultPEMCertificateChain transportType:kDefaultTransportType - transport:kDefaultTransport hostNameOverride:kDefaultHostNameOverride logContext:kDefaultLogContext channelPoolDomain:kDefaultChannelPoolDomain @@ -405,7 +392,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) { PEMPrivateKey:_PEMPrivateKey PEMCertificateChain:_PEMCertificateChain transportType:_transportType - transport:_transport hostNameOverride:_hostNameOverride logContext:_logContext channelPoolDomain:_channelPoolDomain @@ -436,7 +422,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) { PEMPrivateKey:_PEMPrivateKey PEMCertificateChain:_PEMCertificateChain transportType:_transportType - transport:_transport hostNameOverride:_hostNameOverride logContext:_logContext channelPoolDomain:_channelPoolDomain @@ -460,7 +445,7 @@ static BOOL areObjectsEqual(id obj1, id obj2) { _flowControlEnabled = flowControlEnabled; } -- (void)setInterceptorFactories:(NSArray<id<GRPCInterceptorFactory>> *)interceptorFactories { +- (void)setInterceptorFactories:(NSArray *)interceptorFactories { _interceptorFactories = interceptorFactories; } @@ -553,10 +538,6 @@ static BOOL areObjectsEqual(id obj1, id obj2) { _transportType = transportType; } -- (void)setTransport:(GRPCTransportId)transport { - _transport = transport; -} - - (void)setHostNameOverride:(NSString *)hostNameOverride { _hostNameOverride = [hostNameOverride copy]; } diff --git a/src/objective-c/GRPCClient/GRPCDispatchable.h b/src/objective-c/GRPCClient/GRPCDispatchable.h deleted file mode 100644 index 650103603d4304e599d6e6d9f3f4c0c3c8764cce..0000000000000000000000000000000000000000 --- a/src/objective-c/GRPCClient/GRPCDispatchable.h +++ /dev/null @@ -1,30 +0,0 @@ - -/* - * - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * An object that processes its methods with a dispatch queue. - */ -@protocol GRPCDispatchable - -/** - * The dispatch queue where the object's methods should be run on. - */ -@property(atomic, readonly) dispatch_queue_t dispatchQueue; - -@end diff --git a/src/objective-c/GRPCClient/GRPCInterceptor.h b/src/objective-c/GRPCClient/GRPCInterceptor.h index 509749769b333c4619d0236decd28bbe51e99619..3b62c1b3ec03fe07fe97da95c99a4464755e5bd9 100644 --- a/src/objective-c/GRPCClient/GRPCInterceptor.h +++ b/src/objective-c/GRPCClient/GRPCInterceptor.h @@ -106,20 +106,22 @@ */ #import "GRPCCall.h" -#import "GRPCDispatchable.h" NS_ASSUME_NONNULL_BEGIN @class GRPCInterceptorManager; @class GRPCInterceptor; -@class GRPCRequestOptions; -@class GRPCCallOptions; -@protocol GRPCResponseHandler; /** * The GRPCInterceptorInterface defines the request events that can occur to an interceptr. */ -@protocol GRPCInterceptorInterface<NSObject, GRPCDispatchable> +@protocol GRPCInterceptorInterface<NSObject> + +/** + * The queue on which all methods of this interceptor should be dispatched on. The queue must be a + * serial queue. + */ +@property(readonly) dispatch_queue_t requestDispatchQueue; /** * To start the call. This method will only be called once for each instance. @@ -169,20 +171,19 @@ NS_ASSUME_NONNULL_BEGIN * invoke shutDown method of its corresponding manager so that references to other interceptors can * be released. */ -@interface GRPCInterceptorManager : NSObject<GRPCInterceptorInterface, GRPCResponseHandler> +@interface GRPCInterceptorManager : NSObject - (instancetype)init NS_UNAVAILABLE; + (instancetype) new NS_UNAVAILABLE; -- (nullable instancetype)initWithFactories:(nullable NSArray<id<GRPCInterceptorFactory>> *)factories - previousInterceptor:(nullable id<GRPCResponseHandler>)previousInterceptor - transportId:(GRPCTransportId)transportId; +- (nullable instancetype)initWithNextInterceptor:(id<GRPCInterceptorInterface>)nextInterceptor + NS_DESIGNATED_INITIALIZER; -/** - * Notify the manager that the interceptor has shut down and the manager should release references - * to other interceptors and stop forwarding requests/responses. - */ +/** Set the previous interceptor in the chain. Can only be set once. */ +- (void)setPreviousInterceptor:(id<GRPCResponseHandler>)previousInterceptor; + +/** Indicate shutdown of the interceptor; release the reference to other interceptors */ - (void)shutDown; // Methods to forward GRPCInterceptorInterface calls to the next interceptor @@ -234,6 +235,7 @@ NS_ASSUME_NONNULL_BEGIN @interface GRPCInterceptor : NSObject<GRPCInterceptorInterface, GRPCResponseHandler> - (instancetype)init NS_UNAVAILABLE; + + (instancetype) new NS_UNAVAILABLE; /** @@ -241,7 +243,9 @@ NS_ASSUME_NONNULL_BEGIN * that this interceptor's methods are dispatched onto. */ - (nullable instancetype)initWithInterceptorManager:(GRPCInterceptorManager *)interceptorManager - dispatchQueue:(dispatch_queue_t)dispatchQueue; + requestDispatchQueue:(dispatch_queue_t)requestDispatchQueue + responseDispatchQueue:(dispatch_queue_t)responseDispatchQueue + NS_DESIGNATED_INITIALIZER; // Default implementation of GRPCInterceptorInterface diff --git a/src/objective-c/GRPCClient/GRPCInterceptor.m b/src/objective-c/GRPCClient/GRPCInterceptor.m index a7ffe05bddcd91d098cd7b8d6eed280af3b73f90..a385ecd781330b5de3620d2ece66059b346e68ed 100644 --- a/src/objective-c/GRPCClient/GRPCInterceptor.m +++ b/src/objective-c/GRPCClient/GRPCInterceptor.m @@ -19,253 +19,117 @@ #import <Foundation/Foundation.h> #import "GRPCInterceptor.h" -#import "private/GRPCTransport+Private.h" - -@interface GRPCInterceptorManager ()<GRPCInterceptorInterface, GRPCResponseHandler> - -@end @implementation GRPCInterceptorManager { id<GRPCInterceptorInterface> _nextInterceptor; id<GRPCResponseHandler> _previousInterceptor; - GRPCInterceptor *_thisInterceptor; - dispatch_queue_t _dispatchQueue; - NSArray<id<GRPCInterceptorFactory>> *_factories; - GRPCTransportId _transportId; - BOOL _shutDown; } -- (instancetype)initWithFactories:(NSArray<id<GRPCInterceptorFactory>> *)factories - previousInterceptor:(id<GRPCResponseHandler>)previousInterceptor - transportId:(nonnull GRPCTransportId)transportId { +- (instancetype)initWithNextInterceptor:(id<GRPCInterceptorInterface>)nextInterceptor { if ((self = [super init])) { - if (factories.count == 0) { - [NSException raise:NSInternalInconsistencyException - format:@"Interceptor manager must have factories"]; - } - _thisInterceptor = [factories[0] createInterceptorWithManager:self]; - if (_thisInterceptor == nil) { - return nil; - } - _previousInterceptor = previousInterceptor; - _factories = factories; - // Generate interceptor -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 - if (@available(iOS 8.0, macOS 10.10, *)) { - _dispatchQueue = dispatch_queue_create( - NULL, - dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0)); - } else { -#else - { -#endif - _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); - } - dispatch_set_target_queue(_dispatchQueue, _thisInterceptor.dispatchQueue); - _transportId = transportId; + _nextInterceptor = nextInterceptor; } + return self; } -- (void)shutDown { - dispatch_async(_dispatchQueue, ^{ - self->_nextInterceptor = nil; - self->_previousInterceptor = nil; - self->_thisInterceptor = nil; - self->_shutDown = YES; - }); +- (void)setPreviousInterceptor:(id<GRPCResponseHandler>)previousInterceptor { + _previousInterceptor = previousInterceptor; } -- (void)createNextInterceptor { - NSAssert(_nextInterceptor == nil, @"Starting the next interceptor more than once"); - NSAssert(_factories.count > 0, @"Interceptor manager of transport cannot start next interceptor"); - if (_nextInterceptor != nil) { - NSLog(@"Starting the next interceptor more than once"); - return; - } - NSMutableArray<id<GRPCInterceptorFactory>> *interceptorFactories = [NSMutableArray - arrayWithArray:[_factories subarrayWithRange:NSMakeRange(1, _factories.count - 1)]]; - while (_nextInterceptor == nil) { - if (interceptorFactories.count == 0) { - _nextInterceptor = - [[GRPCTransportManager alloc] initWithTransportId:_transportId previousInterceptor:self]; - break; - } else { - _nextInterceptor = [[GRPCInterceptorManager alloc] initWithFactories:interceptorFactories - previousInterceptor:self - transportId:_transportId]; - if (_nextInterceptor == nil) { - [interceptorFactories removeObjectAtIndex:0]; - } - } - } - NSAssert(_nextInterceptor != nil, @"Failed to create interceptor or transport."); - if (_nextInterceptor == nil) { - NSLog(@"Failed to create interceptor or transport."); - } +- (void)shutDown { + _nextInterceptor = nil; + _previousInterceptor = nil; } - (void)startNextInterceptorWithRequest:(GRPCRequestOptions *)requestOptions callOptions:(GRPCCallOptions *)callOptions { - if (_nextInterceptor == nil && !_shutDown) { - [self createNextInterceptor]; - } - if (_nextInterceptor == nil) { - return; + if (_nextInterceptor != nil) { + id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor; + dispatch_async(copiedNextInterceptor.requestDispatchQueue, ^{ + [copiedNextInterceptor startWithRequestOptions:requestOptions callOptions:callOptions]; + }); } - id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor; - dispatch_async(copiedNextInterceptor.dispatchQueue, ^{ - [copiedNextInterceptor startWithRequestOptions:requestOptions callOptions:callOptions]; - }); } - (void)writeNextInterceptorWithData:(id)data { - if (_nextInterceptor == nil && !_shutDown) { - [self createNextInterceptor]; - } - if (_nextInterceptor == nil) { - return; + if (_nextInterceptor != nil) { + id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor; + dispatch_async(copiedNextInterceptor.requestDispatchQueue, ^{ + [copiedNextInterceptor writeData:data]; + }); } - id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor; - dispatch_async(copiedNextInterceptor.dispatchQueue, ^{ - [copiedNextInterceptor writeData:data]; - }); } - (void)finishNextInterceptor { - if (_nextInterceptor == nil && !_shutDown) { - [self createNextInterceptor]; - } - if (_nextInterceptor == nil) { - return; + if (_nextInterceptor != nil) { + id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor; + dispatch_async(copiedNextInterceptor.requestDispatchQueue, ^{ + [copiedNextInterceptor finish]; + }); } - id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor; - dispatch_async(copiedNextInterceptor.dispatchQueue, ^{ - [copiedNextInterceptor finish]; - }); } - (void)cancelNextInterceptor { - if (_nextInterceptor == nil && !_shutDown) { - [self createNextInterceptor]; - } - if (_nextInterceptor == nil) { - return; + if (_nextInterceptor != nil) { + id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor; + dispatch_async(copiedNextInterceptor.requestDispatchQueue, ^{ + [copiedNextInterceptor cancel]; + }); } - id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor; - dispatch_async(copiedNextInterceptor.dispatchQueue, ^{ - [copiedNextInterceptor cancel]; - }); } /** Notify the next interceptor in the chain to receive more messages */ - (void)receiveNextInterceptorMessages:(NSUInteger)numberOfMessages { - if (_nextInterceptor == nil && !_shutDown) { - [self createNextInterceptor]; - } - if (_nextInterceptor == nil) { - return; + if (_nextInterceptor != nil) { + id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor; + dispatch_async(copiedNextInterceptor.requestDispatchQueue, ^{ + [copiedNextInterceptor receiveNextMessages:numberOfMessages]; + }); } - id<GRPCInterceptorInterface> copiedNextInterceptor = _nextInterceptor; - dispatch_async(copiedNextInterceptor.dispatchQueue, ^{ - [copiedNextInterceptor receiveNextMessages:numberOfMessages]; - }); } // Methods to forward GRPCResponseHandler callbacks to the previous object /** Forward initial metadata to the previous interceptor in the chain */ -- (void)forwardPreviousInterceptorWithInitialMetadata:(NSDictionary *)initialMetadata { - if (_previousInterceptor == nil) { - return; +- (void)forwardPreviousInterceptorWithInitialMetadata:(nullable NSDictionary *)initialMetadata { + if ([_previousInterceptor respondsToSelector:@selector(didReceiveInitialMetadata:)]) { + id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor; + dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{ + [copiedPreviousInterceptor didReceiveInitialMetadata:initialMetadata]; + }); } - id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor; - dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{ - [copiedPreviousInterceptor didReceiveInitialMetadata:initialMetadata]; - }); } /** Forward a received message to the previous interceptor in the chain */ - (void)forwardPreviousInterceptorWithData:(id)data { - if (_previousInterceptor == nil) { - return; + if ([_previousInterceptor respondsToSelector:@selector(didReceiveData:)]) { + id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor; + dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{ + [copiedPreviousInterceptor didReceiveData:data]; + }); } - id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor; - dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{ - [copiedPreviousInterceptor didReceiveData:data]; - }); } /** Forward call close and trailing metadata to the previous interceptor in the chain */ -- (void)forwardPreviousInterceptorCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata - error:(NSError *)error { - if (_previousInterceptor == nil) { - return; +- (void)forwardPreviousInterceptorCloseWithTrailingMetadata: + (nullable NSDictionary *)trailingMetadata + error:(nullable NSError *)error { + if ([_previousInterceptor respondsToSelector:@selector(didCloseWithTrailingMetadata:error:)]) { + id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor; + dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{ + [copiedPreviousInterceptor didCloseWithTrailingMetadata:trailingMetadata error:error]; + }); } - id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor; - dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{ - [copiedPreviousInterceptor didCloseWithTrailingMetadata:trailingMetadata error:error]; - }); } /** Forward write completion to the previous interceptor in the chain */ - (void)forwardPreviousInterceptorDidWriteData { - if (_previousInterceptor == nil) { - return; - } - id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor; - dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{ - [copiedPreviousInterceptor didWriteData]; - }); -} - -- (dispatch_queue_t)dispatchQueue { - return _dispatchQueue; -} - -- (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions - callOptions:(GRPCCallOptions *)callOptions { - [_thisInterceptor startWithRequestOptions:requestOptions callOptions:callOptions]; -} - -- (void)writeData:(id)data { - [_thisInterceptor writeData:data]; -} - -- (void)finish { - [_thisInterceptor finish]; -} - -- (void)cancel { - [_thisInterceptor cancel]; -} - -- (void)receiveNextMessages:(NSUInteger)numberOfMessages { - [_thisInterceptor receiveNextMessages:numberOfMessages]; -} - -- (void)didReceiveInitialMetadata:(nullable NSDictionary *)initialMetadata { - if ([_thisInterceptor respondsToSelector:@selector(didReceiveInitialMetadata:)]) { - [_thisInterceptor didReceiveInitialMetadata:initialMetadata]; - } -} - -- (void)didReceiveData:(id)data { - if ([_thisInterceptor respondsToSelector:@selector(didReceiveData:)]) { - [_thisInterceptor didReceiveData:data]; - } -} - -- (void)didCloseWithTrailingMetadata:(nullable NSDictionary *)trailingMetadata - error:(nullable NSError *)error { - if ([_thisInterceptor respondsToSelector:@selector(didCloseWithTrailingMetadata:error:)]) { - [_thisInterceptor didCloseWithTrailingMetadata:trailingMetadata error:error]; - } -} - -- (void)didWriteData { - if ([_thisInterceptor respondsToSelector:@selector(didWriteData)]) { - [_thisInterceptor didWriteData]; + if ([_previousInterceptor respondsToSelector:@selector(didWriteData)]) { + id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor; + dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{ + [copiedPreviousInterceptor didWriteData]; + }); } } @@ -273,21 +137,28 @@ @implementation GRPCInterceptor { GRPCInterceptorManager *_manager; - dispatch_queue_t _dispatchQueue; + dispatch_queue_t _requestDispatchQueue; + dispatch_queue_t _responseDispatchQueue; } - (instancetype)initWithInterceptorManager:(GRPCInterceptorManager *)interceptorManager - dispatchQueue:(dispatch_queue_t)dispatchQueue { + requestDispatchQueue:(dispatch_queue_t)requestDispatchQueue + responseDispatchQueue:(dispatch_queue_t)responseDispatchQueue { if ((self = [super init])) { _manager = interceptorManager; - _dispatchQueue = dispatchQueue; + _requestDispatchQueue = requestDispatchQueue; + _responseDispatchQueue = responseDispatchQueue; } return self; } +- (dispatch_queue_t)requestDispatchQueue { + return _requestDispatchQueue; +} + - (dispatch_queue_t)dispatchQueue { - return _dispatchQueue; + return _responseDispatchQueue; } - (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions diff --git a/src/objective-c/GRPCClient/GRPCTransport.h b/src/objective-c/GRPCClient/GRPCTransport.h deleted file mode 100644 index d5637922152bb64b861314b96979e04ca39a8f02..0000000000000000000000000000000000000000 --- a/src/objective-c/GRPCClient/GRPCTransport.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -// The interface for a transport implementation - -#import "GRPCInterceptor.h" - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark Transport ID - -/** - * The default transport implementations available in gRPC. These implementations will be provided - * by gRPC by default unless explicitly excluded. - */ -extern const struct GRPCDefaultTransportImplList { - const GRPCTransportId core_secure; - const GRPCTransportId core_insecure; -} GRPCDefaultTransportImplList; - -/** Returns whether two transport id's are identical. */ -BOOL TransportIdIsEqual(GRPCTransportId lhs, GRPCTransportId rhs); - -/** Returns the hash value of a transport id. */ -NSUInteger TransportIdHash(GRPCTransportId); - -#pragma mark Transport and factory - -@protocol GRPCInterceptorInterface; -@protocol GRPCResponseHandler; -@class GRPCTransportManager; -@class GRPCRequestOptions; -@class GRPCCallOptions; -@class GRPCTransport; - -/** The factory method to create a transport. */ -@protocol GRPCTransportFactory<NSObject> - -- (GRPCTransport *)createTransportWithManager:(GRPCTransportManager *)transportManager; - -@end - -/** The registry of transport implementations. */ -@interface GRPCTransportRegistry : NSObject - -+ (instancetype)sharedInstance; - -/** - * Register a transport implementation with the registry. All transport implementations to be used - * in a process must register with the registry on process start-up in its +load: class method. - * Parameter \a transportId is the identifier of the implementation, and \a factory is the factory - * object to create the corresponding transport instance. - */ -- (void)registerTransportWithId:(GRPCTransportId)transportId - factory:(id<GRPCTransportFactory>)factory; - -@end - -/** - * Base class for transport implementations. All transport implementation should inherit from this - * class. - */ -@interface GRPCTransport : NSObject<GRPCInterceptorInterface> - -@end - -NS_ASSUME_NONNULL_END diff --git a/src/objective-c/GRPCClient/GRPCTransport.m b/src/objective-c/GRPCClient/GRPCTransport.m deleted file mode 100644 index 439acfb9cc231a3d2b51bbd48bc4882b8d062123..0000000000000000000000000000000000000000 --- a/src/objective-c/GRPCClient/GRPCTransport.m +++ /dev/null @@ -1,142 +0,0 @@ -/* - * - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#import "GRPCTransport.h" - -static const GRPCTransportId gGRPCCoreSecureId = "io.grpc.transport.core.secure"; -static const GRPCTransportId gGRPCCoreInsecureId = "io.grpc.transport.core.insecure"; - -const struct GRPCDefaultTransportImplList GRPCDefaultTransportImplList = { - .core_secure = gGRPCCoreSecureId, .core_insecure = gGRPCCoreInsecureId}; - -static const GRPCTransportId gDefaultTransportId = gGRPCCoreSecureId; - -static GRPCTransportRegistry *gTransportRegistry = nil; -static dispatch_once_t initTransportRegistry; - -BOOL TransportIdIsEqual(GRPCTransportId lhs, GRPCTransportId rhs) { - // Directly comparing pointers works because we require users to use the id provided by each - // implementation, not coming up with their own string. - return lhs == rhs; -} - -NSUInteger TransportIdHash(GRPCTransportId transportId) { - if (transportId == NULL) { - transportId = gDefaultTransportId; - } - return [NSString stringWithCString:transportId encoding:NSUTF8StringEncoding].hash; -} - -@implementation GRPCTransportRegistry { - NSMutableDictionary<NSString *, id<GRPCTransportFactory>> *_registry; - id<GRPCTransportFactory> _defaultFactory; -} - -+ (instancetype)sharedInstance { - dispatch_once(&initTransportRegistry, ^{ - gTransportRegistry = [[GRPCTransportRegistry alloc] init]; - NSAssert(gTransportRegistry != nil, @"Unable to initialize transport registry."); - if (gTransportRegistry == nil) { - NSLog(@"Unable to initialize transport registry."); - [NSException raise:NSGenericException format:@"Unable to initialize transport registry."]; - } - }); - return gTransportRegistry; -} - -- (instancetype)init { - if ((self = [super init])) { - _registry = [NSMutableDictionary dictionary]; - } - return self; -} - -- (void)registerTransportWithId:(GRPCTransportId)transportId - factory:(id<GRPCTransportFactory>)factory { - NSString *nsTransportId = [NSString stringWithCString:transportId encoding:NSUTF8StringEncoding]; - NSAssert(_registry[nsTransportId] == nil, @"The transport %@ has already been registered.", - nsTransportId); - if (_registry[nsTransportId] != nil) { - NSLog(@"The transport %@ has already been registered.", nsTransportId); - return; - } - _registry[nsTransportId] = factory; - - // if the default transport is registered, mark it. - if (0 == strcmp(transportId, gDefaultTransportId)) { - _defaultFactory = factory; - } -} - -- (id<GRPCTransportFactory>)getTransportFactoryWithId:(GRPCTransportId)transportId { - if (transportId == NULL) { - if (_defaultFactory == nil) { - [NSException raise:NSInvalidArgumentException - format:@"Unable to get default transport factory"]; - return nil; - } - return _defaultFactory; - } - NSString *nsTransportId = [NSString stringWithCString:transportId encoding:NSUTF8StringEncoding]; - id<GRPCTransportFactory> transportFactory = _registry[nsTransportId]; - if (transportFactory == nil) { - // User named a transport id that was not registered with the registry. - [NSException raise:NSInvalidArgumentException - format:@"Unable to get transport factory with id %s", transportId]; - return nil; - } - return transportFactory; -} - -@end - -@implementation GRPCTransport - -- (dispatch_queue_t)dispatchQueue { - [NSException raise:NSGenericException - format:@"Implementations should override the dispatch queue"]; - return nil; -} - -- (void)startWithRequestOptions:(nonnull GRPCRequestOptions *)requestOptions - callOptions:(nonnull GRPCCallOptions *)callOptions { - [NSException raise:NSGenericException - format:@"Implementations should override the methods of GRPCTransport"]; -} - -- (void)writeData:(nonnull id)data { - [NSException raise:NSGenericException - format:@"Implementations should override the methods of GRPCTransport"]; -} - -- (void)cancel { - [NSException raise:NSGenericException - format:@"Implementations should override the methods of GRPCTransport"]; -} - -- (void)finish { - [NSException raise:NSGenericException - format:@"Implementations should override the methods of GRPCTransport"]; -} - -- (void)receiveNextMessages:(NSUInteger)numberOfMessages { - [NSException raise:NSGenericException - format:@"Implementations should override the methods of GRPCTransport"]; -} - -@end diff --git a/src/objective-c/GRPCClient/GRPCTypes.h b/src/objective-c/GRPCClient/GRPCTypes.h deleted file mode 100644 index c804bca4eaaf0a6845106abd749562282c906ad4..0000000000000000000000000000000000000000 --- a/src/objective-c/GRPCClient/GRPCTypes.h +++ /dev/null @@ -1,187 +0,0 @@ -/* - * - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * gRPC error codes. - * Note that a few of these are never produced by the gRPC libraries, but are of - * general utility for server applications to produce. - */ -typedef NS_ENUM(NSUInteger, GRPCErrorCode) { - /** The operation was cancelled (typically by the caller). */ - GRPCErrorCodeCancelled = 1, - - /** - * Unknown error. Errors raised by APIs that do not return enough error - * information may be converted to this error. - */ - GRPCErrorCodeUnknown = 2, - - /** - * The client specified an invalid argument. Note that this differs from - * FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments that are - * problematic regardless of the state of the server (e.g., a malformed file - * name). - */ - GRPCErrorCodeInvalidArgument = 3, - - /** - * Deadline expired before operation could complete. For operations that - * change the state of the server, this error may be returned even if the - * operation has completed successfully. For example, a successful response - * from the server could have been delayed long enough for the deadline to - * expire. - */ - GRPCErrorCodeDeadlineExceeded = 4, - - /** Some requested entity (e.g., file or directory) was not found. */ - GRPCErrorCodeNotFound = 5, - - /** Some entity that we attempted to create (e.g., file or directory) already - exists. */ - GRPCErrorCodeAlreadyExists = 6, - - /** - * The caller does not have permission to execute the specified operation. - * PERMISSION_DENIED isn't used for rejections caused by exhausting some - * resource (RESOURCE_EXHAUSTED is used instead for those errors). - * PERMISSION_DENIED doesn't indicate a failure to identify the caller - * (UNAUTHENTICATED is used instead for those errors). - */ - GRPCErrorCodePermissionDenied = 7, - - /** - * The request does not have valid authentication credentials for the - * operation (e.g. the caller's identity can't be verified). - */ - GRPCErrorCodeUnauthenticated = 16, - - /** Some resource has been exhausted, perhaps a per-user quota. */ - GRPCErrorCodeResourceExhausted = 8, - - /** - * The RPC was rejected because the server is not in a state required for the - * procedure's execution. For example, a directory to be deleted may be - * non-empty, etc. The client should not retry until the server state has been - * explicitly fixed (e.g. by performing another RPC). The details depend on - * the service being called, and should be found in the NSError's userInfo. - */ - GRPCErrorCodeFailedPrecondition = 9, - - /** - * The RPC was aborted, typically due to a concurrency issue like sequencer - * check failures, transaction aborts, etc. The client should retry at a - * higher-level (e.g., restarting a read- modify-write sequence). - */ - GRPCErrorCodeAborted = 10, - - /** - * The RPC was attempted past the valid range. E.g., enumerating past the end - * of a list. Unlike INVALID_ARGUMENT, this error indicates a problem that may - * be fixed if the system state changes. For example, an RPC to get elements - * of a list will generate INVALID_ARGUMENT if asked to return the element at - * a negative index, but it will generate OUT_OF_RANGE if asked to return the - * element at an index past the current size of the list. - */ - GRPCErrorCodeOutOfRange = 11, - - /** The procedure is not implemented or not supported/enabled in this server. - */ - GRPCErrorCodeUnimplemented = 12, - - /** - * Internal error. Means some invariant expected by the server application or - * the gRPC library has been broken. - */ - GRPCErrorCodeInternal = 13, - - /** - * The server is currently unavailable. This is most likely a transient - * condition and may be corrected by retrying with a backoff. Note that it is - * not always safe to retry non-idempotent operations. - */ - GRPCErrorCodeUnavailable = 14, - - /** Unrecoverable data loss or corruption. */ - GRPCErrorCodeDataLoss = 15, -}; - -/** - * Safety remark of a gRPC method as defined in RFC 2616 Section 9.1 - */ -typedef NS_ENUM(NSUInteger, GRPCCallSafety) { - /** - * Signal that there is no guarantees on how the call affects the server - * state. - */ - GRPCCallSafetyDefault = 0, - /** Signal that the call is idempotent. gRPC is free to use PUT verb. */ - GRPCCallSafetyIdempotentRequest = 1, - /** - * Signal that the call is cacheable and will not affect server state. gRPC is - * free to use GET verb. - */ - GRPCCallSafetyCacheableRequest = 2, -}; - -// Compression algorithm to be used by a gRPC call -typedef NS_ENUM(NSUInteger, GRPCCompressionAlgorithm) { - GRPCCompressNone = 0, - GRPCCompressDeflate, - GRPCCompressGzip, - GRPCStreamCompressGzip, -}; - -// GRPCCompressAlgorithm is deprecated; use GRPCCompressionAlgorithm -typedef GRPCCompressionAlgorithm GRPCCompressAlgorithm; - -/** The transport to be used by a gRPC call */ -typedef NS_ENUM(NSUInteger, GRPCTransportType) { - GRPCTransportTypeDefault = 0, - /** gRPC internal HTTP/2 stack with BoringSSL */ - GRPCTransportTypeChttp2BoringSSL = 0, - /** Cronet stack */ - GRPCTransportTypeCronet, - /** Insecure channel. FOR TEST ONLY! */ - GRPCTransportTypeInsecure, -}; - -/** Domain of NSError objects produced by gRPC. */ -extern NSString* _Nonnull const kGRPCErrorDomain; - -/** - * Keys used in |NSError|'s |userInfo| dictionary to store the response headers - * and trailers sent by the server. - */ -extern NSString* _Nonnull const kGRPCHeadersKey; -extern NSString* _Nonnull const kGRPCTrailersKey; - -/** The id of a transport implementation. */ -typedef char* _Nonnull GRPCTransportId; - -/** - * Implement this protocol to provide a token to gRPC when a call is initiated. - */ -@protocol GRPCAuthorizationProtocol - -/** - * This method is called when gRPC is about to start the call. When OAuth token is acquired, - * \a handler is expected to be called with \a token being the new token to be used for this call. - */ -- (void)getTokenWithHandler:(void (^_Nonnull)(NSString* _Nullable token))handler; - -@end diff --git a/src/objective-c/GRPCClient/internal_testing/GRPCCall+InternalTests.m b/src/objective-c/GRPCClient/internal_testing/GRPCCall+InternalTests.m index 8f98daa6348679d409f1db3f419e42124824b5f5..1bb352f0be2f3eb0f2111d50f02079a8b03e77bc 100644 --- a/src/objective-c/GRPCClient/internal_testing/GRPCCall+InternalTests.m +++ b/src/objective-c/GRPCClient/internal_testing/GRPCCall+InternalTests.m @@ -20,7 +20,7 @@ #import "GRPCCall+InternalTests.h" -#import "../private/GRPCCore/GRPCOpBatchLog.h" +#import "../private/GRPCOpBatchLog.h" @implementation GRPCCall (InternalTests) diff --git a/src/objective-c/GRPCClient/private/GRPCCore/ChannelArgsUtil.h b/src/objective-c/GRPCClient/private/ChannelArgsUtil.h similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/ChannelArgsUtil.h rename to src/objective-c/GRPCClient/private/ChannelArgsUtil.h diff --git a/src/objective-c/GRPCClient/private/GRPCCore/ChannelArgsUtil.m b/src/objective-c/GRPCClient/private/ChannelArgsUtil.m similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/ChannelArgsUtil.m rename to src/objective-c/GRPCClient/private/ChannelArgsUtil.m diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCall+V2API.h b/src/objective-c/GRPCClient/private/GRPCCall+V2API.h similarity index 79% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCCall+V2API.h rename to src/objective-c/GRPCClient/private/GRPCCall+V2API.h index f6db3023cac376b4ead3f752145161c2364d9790..22bf16962c6a7afb290c2000ad02bf2da14a8e3f 100644 --- a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCall+V2API.h +++ b/src/objective-c/GRPCClient/private/GRPCCall+V2API.h @@ -18,6 +18,12 @@ @interface GRPCCall (V2API) +- (instancetype)initWithHost:(NSString *)host + path:(NSString *)path + callSafety:(GRPCCallSafety)safety + requestsWriter:(GRXWriter *)requestsWriter + callOptions:(GRPCCallOptions *)callOptions; + - (instancetype)initWithHost:(NSString *)host path:(NSString *)path callSafety:(GRPCCallSafety)safety diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCallInternal.h b/src/objective-c/GRPCClient/private/GRPCCallInternal.h similarity index 70% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCCallInternal.h rename to src/objective-c/GRPCClient/private/GRPCCallInternal.h index 641b1fb2e8a9968f42accb36bcda677087749da3..ac2d1cba2ec8ab20bc56bc9720aab43bfe0b0be2 100644 --- a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCallInternal.h +++ b/src/objective-c/GRPCClient/private/GRPCCallInternal.h @@ -16,22 +16,20 @@ * */ -#import <GRPCClient/GRPCTransport.h> +#import <GRPCClient/GRPCInterceptor.h> NS_ASSUME_NONNULL_BEGIN -@protocol GRPCResponseHandler; -@class GRPCCallOptions; -@protocol GRPCChannelFactory; +@interface GRPCCall2Internal : NSObject<GRPCInterceptorInterface> -@interface GRPCCall2Internal : GRPCTransport +- (instancetype)init; -- (instancetype)initWithTransportManager:(GRPCTransportManager *)transportManager; +- (void)setResponseHandler:(id<GRPCResponseHandler>)responseHandler; - (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions - callOptions:(GRPCCallOptions *)callOptions; + callOptions:(nullable GRPCCallOptions *)callOptions; -- (void)writeData:(id)data; +- (void)writeData:(NSData *)data; - (void)finish; diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCallInternal.m b/src/objective-c/GRPCClient/private/GRPCCallInternal.m similarity index 69% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCCallInternal.m rename to src/objective-c/GRPCClient/private/GRPCCallInternal.m index ea01fcaf5944f25042ebf623a6d270e7f06e9d3c..32e38158fad5b2264fcce829a45f519db13995a8 100644 --- a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCallInternal.m +++ b/src/objective-c/GRPCClient/private/GRPCCallInternal.m @@ -19,10 +19,8 @@ #import "GRPCCallInternal.h" #import <GRPCClient/GRPCCall.h> -#import <GRPCClient/GRPCInterceptor.h> #import <RxLibrary/GRXBufferedPipe.h> -#import "../GRPCTransport+Private.h" #import "GRPCCall+V2API.h" @implementation GRPCCall2Internal { @@ -30,8 +28,8 @@ GRPCRequestOptions *_requestOptions; /** Options for the call. */ GRPCCallOptions *_callOptions; - /** The interceptor manager to process responses. */ - GRPCTransportManager *_transportManager; + /** The handler of responses. */ + id<GRPCResponseHandler> _handler; /** * Make use of legacy GRPCCall to make calls. Nullified when call is finished. @@ -53,28 +51,40 @@ NSUInteger _pendingReceiveNextMessages; } -- (instancetype)initWithTransportManager:(GRPCTransportManager *)transportManager { - dispatch_queue_t dispatchQueue; +- (instancetype)init { + if ((self = [super init])) { // Set queue QoS only when iOS version is 8.0 or above and Xcode version is 9.0 or above #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 - if (@available(iOS 8.0, macOS 10.10, *)) { - dispatchQueue = dispatch_queue_create( - NULL, dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0)); - } else { + if (@available(iOS 8.0, macOS 10.10, *)) { + _dispatchQueue = dispatch_queue_create( + NULL, + dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0)); + } else { #else - { + { #endif - dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); - } - if ((self = [super init])) { + _dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); + } _pipe = [GRXBufferedPipe pipe]; - _transportManager = transportManager; - _dispatchQueue = dispatchQueue; } return self; } -- (dispatch_queue_t)dispatchQueue { +- (void)setResponseHandler:(id<GRPCResponseHandler>)responseHandler { + @synchronized(self) { + NSAssert(!_started, @"Call already started."); + if (_started) { + return; + } + _handler = responseHandler; + _initialMetadataPublished = NO; + _started = NO; + _canceled = NO; + _finished = NO; + } +} + +- (dispatch_queue_t)requestDispatchQueue { return _dispatchQueue; } @@ -92,15 +102,26 @@ return; } - GRPCCall *copiedCall = nil; @synchronized(self) { + NSAssert(_handler != nil, @"Response handler required."); + if (_handler == nil) { + NSLog(@"Invalid response handler."); + return; + } _requestOptions = requestOptions; if (callOptions == nil) { _callOptions = [[GRPCCallOptions alloc] init]; } else { _callOptions = [callOptions copy]; } + } + [self start]; +} + +- (void)start { + GRPCCall *copiedCall = nil; + @synchronized(self) { NSAssert(!_started, @"Call already started."); NSAssert(!_canceled, @"Call already canceled."); if (_started) { @@ -119,7 +140,7 @@ callOptions:_callOptions writeDone:^{ @synchronized(self) { - if (self->_transportManager) { + if (self->_handler) { [self issueDidWriteData]; } } @@ -137,7 +158,7 @@ void (^valueHandler)(id value) = ^(id value) { @synchronized(self) { - if (self->_transportManager) { + if (self->_handler) { if (!self->_initialMetadataPublished) { self->_initialMetadataPublished = YES; [self issueInitialMetadata:self->_call.responseHeaders]; @@ -150,7 +171,7 @@ }; void (^completionHandler)(NSError *errorOrNil) = ^(NSError *errorOrNil) { @synchronized(self) { - if (self->_transportManager) { + if (self->_handler) { if (!self->_initialMetadataPublished) { self->_initialMetadataPublished = YES; [self issueInitialMetadata:self->_call.responseHeaders]; @@ -186,19 +207,20 @@ _call = nil; _pipe = nil; - if (_transportManager != nil) { - [_transportManager - forwardPreviousInterceptorCloseWithTrailingMetadata:nil - error: - [NSError - errorWithDomain:kGRPCErrorDomain - code: - GRPCErrorCodeCancelled - userInfo:@{ - NSLocalizedDescriptionKey : - @"Canceled by app" - }]]; - [_transportManager shutDown]; + if ([_handler respondsToSelector:@selector(didCloseWithTrailingMetadata:error:)]) { + id<GRPCResponseHandler> copiedHandler = _handler; + _handler = nil; + dispatch_async(copiedHandler.dispatchQueue, ^{ + [copiedHandler didCloseWithTrailingMetadata:nil + error:[NSError errorWithDomain:kGRPCErrorDomain + code:GRPCErrorCodeCancelled + userInfo:@{ + NSLocalizedDescriptionKey : + @"Canceled by app" + }]]; + }); + } else { + _handler = nil; } } [copiedCall cancel]; @@ -249,25 +271,59 @@ } - (void)issueInitialMetadata:(NSDictionary *)initialMetadata { - if (initialMetadata != nil) { - [_transportManager forwardPreviousInterceptorWithInitialMetadata:initialMetadata]; + @synchronized(self) { + if (initialMetadata != nil && + [_handler respondsToSelector:@selector(didReceiveInitialMetadata:)]) { + id<GRPCResponseHandler> copiedHandler = _handler; + dispatch_async(_handler.dispatchQueue, ^{ + [copiedHandler didReceiveInitialMetadata:initialMetadata]; + }); + } } } - (void)issueMessage:(id)message { - if (message != nil) { - [_transportManager forwardPreviousInterceptorWithData:message]; + @synchronized(self) { + if (message != nil) { + if ([_handler respondsToSelector:@selector(didReceiveData:)]) { + id<GRPCResponseHandler> copiedHandler = _handler; + dispatch_async(_handler.dispatchQueue, ^{ + [copiedHandler didReceiveData:message]; + }); + } else if ([_handler respondsToSelector:@selector(didReceiveRawMessage:)]) { + id<GRPCResponseHandler> copiedHandler = _handler; + dispatch_async(_handler.dispatchQueue, ^{ + [copiedHandler didReceiveRawMessage:message]; + }); + } + } } } - (void)issueClosedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { - [_transportManager forwardPreviousInterceptorCloseWithTrailingMetadata:trailingMetadata - error:error]; - [_transportManager shutDown]; + @synchronized(self) { + if ([_handler respondsToSelector:@selector(didCloseWithTrailingMetadata:error:)]) { + id<GRPCResponseHandler> copiedHandler = _handler; + // Clean up _handler so that no more responses are reported to the handler. + _handler = nil; + dispatch_async(copiedHandler.dispatchQueue, ^{ + [copiedHandler didCloseWithTrailingMetadata:trailingMetadata error:error]; + }); + } else { + _handler = nil; + } + } } - (void)issueDidWriteData { - [_transportManager forwardPreviousInterceptorDidWriteData]; + @synchronized(self) { + if (_callOptions.flowControlEnabled && [_handler respondsToSelector:@selector(didWriteData)]) { + id<GRPCResponseHandler> copiedHandler = _handler; + dispatch_async(copiedHandler.dispatchQueue, ^{ + [copiedHandler didWriteData]; + }); + } + } } - (void)receiveNextMessages:(NSUInteger)numberOfMessages { diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCChannel.h rename to src/objective-c/GRPCClient/private/GRPCChannel.h diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m similarity index 78% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCChannel.m rename to src/objective-c/GRPCClient/private/GRPCChannel.m index cd2b4313acd646bec31be7297bcfe3ced04491ed..1a79fb04a0d5cae04cff1aee09e07b03cb86f338 100644 --- a/src/objective-c/GRPCClient/private/GRPCCore/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCChannel.m @@ -20,19 +20,18 @@ #include <grpc/support/log.h> -#import "../../internal/GRPCCallOptions+Internal.h" -#import "../GRPCTransport+Private.h" +#import "../internal/GRPCCallOptions+Internal.h" #import "ChannelArgsUtil.h" #import "GRPCChannelFactory.h" #import "GRPCChannelPool.h" #import "GRPCCompletionQueue.h" -#import "GRPCCoreFactory.h" +#import "GRPCCronetChannelFactory.h" #import "GRPCInsecureChannelFactory.h" #import "GRPCSecureChannelFactory.h" +#import "version.h" #import <GRPCClient/GRPCCall+Cronet.h> #import <GRPCClient/GRPCCallOptions.h> -#import <GRPCClient/version.h> @implementation GRPCChannelConfiguration @@ -51,48 +50,32 @@ } - (id<GRPCChannelFactory>)channelFactory { - if (_callOptions.transport != NULL) { - id<GRPCTransportFactory> transportFactory = - [[GRPCTransportRegistry sharedInstance] getTransportFactoryWithId:_callOptions.transport]; - if (! - [transportFactory respondsToSelector:@selector(createCoreChannelFactoryWithCallOptions:)]) { - // impossible because we are using GRPCCore now - [NSException raise:NSInternalInconsistencyException - format:@"Transport factory type is wrong"]; - } - id<GRPCCoreTransportFactory> coreTransportFactory = - (id<GRPCCoreTransportFactory>)transportFactory; - return [coreTransportFactory createCoreChannelFactoryWithCallOptions:_callOptions]; - } else { - // To maintain backwards compatibility with tranportType - GRPCTransportType type = _callOptions.transportType; - switch (type) { - case GRPCTransportTypeChttp2BoringSSL: - // TODO (mxyan): Remove when the API is deprecated - { - NSError *error; - id<GRPCChannelFactory> factory = [GRPCSecureChannelFactory - factoryWithPEMRootCertificates:_callOptions.PEMRootCertificates - privateKey:_callOptions.PEMPrivateKey - certChain:_callOptions.PEMCertificateChain - error:&error]; - NSAssert(factory != nil, @"Failed to create secure channel factory"); - if (factory == nil) { - NSLog(@"Error creating secure channel factory: %@", error); - } - return factory; + GRPCTransportType type = _callOptions.transportType; + switch (type) { + case GRPCTransportTypeChttp2BoringSSL: + // TODO (mxyan): Remove when the API is deprecated +#ifdef GRPC_COMPILE_WITH_CRONET + if (![GRPCCall isUsingCronet]) { +#else + { +#endif + NSError *error; + id<GRPCChannelFactory> factory = [GRPCSecureChannelFactory + factoryWithPEMRootCertificates:_callOptions.PEMRootCertificates + privateKey:_callOptions.PEMPrivateKey + certChain:_callOptions.PEMCertificateChain + error:&error]; + NSAssert(factory != nil, @"Failed to create secure channel factory"); + if (factory == nil) { + NSLog(@"Error creating secure channel factory: %@", error); } - case GRPCTransportTypeCronet: { - id<GRPCCoreTransportFactory> transportFactory = (id<GRPCCoreTransportFactory>)[ - [GRPCTransportRegistry sharedInstance] getTransportFactoryWithId:gGRPCCoreCronetId]; - return [transportFactory createCoreChannelFactoryWithCallOptions:_callOptions]; + return factory; } - case GRPCTransportTypeInsecure: - return [GRPCInsecureChannelFactory sharedInstance]; - default: - NSLog(@"Unrecognized transport type"); - return nil; - } + // fallthrough + case GRPCTransportTypeCronet: + return [GRPCCronetChannelFactory sharedInstance]; + case GRPCTransportTypeInsecure: + return [GRPCInsecureChannelFactory sharedInstance]; } } @@ -215,7 +198,6 @@ } else { channelArgs = channelConfiguration.channelArgs; } - id<GRPCChannelFactory> factory = channelConfiguration.channelFactory; _unmanagedChannel = [factory createChannelWithHost:host channelArgs:channelArgs]; NSAssert(_unmanagedChannel != NULL, @"Failed to create channel"); diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCChannelFactory.h similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCChannelFactory.h rename to src/objective-c/GRPCClient/private/GRPCChannelFactory.h diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCChannelPool+Test.h b/src/objective-c/GRPCClient/private/GRPCChannelPool+Test.h similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCChannelPool+Test.h rename to src/objective-c/GRPCClient/private/GRPCChannelPool+Test.h diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCChannelPool.h b/src/objective-c/GRPCClient/private/GRPCChannelPool.h similarity index 98% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCChannelPool.h rename to src/objective-c/GRPCClient/private/GRPCChannelPool.h index b83a28a236878408a3a86f9fb45e7d06e18722d7..e00ee69e63ab99480aeb7b843476c7e5ebf773db 100644 --- a/src/objective-c/GRPCClient/private/GRPCCore/GRPCChannelPool.h +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.h @@ -18,6 +18,8 @@ #import <GRPCClient/GRPCCallOptions.h> +#import "GRPCChannelFactory.h" + NS_ASSUME_NONNULL_BEGIN @protocol GRPCChannel; diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCChannelPool.m similarity index 98% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCChannelPool.m rename to src/objective-c/GRPCClient/private/GRPCChannelPool.m index 92f52e67b754a98394bb6cdc70a0763a323903a4..d545793fccec14cea438850b9cde3dbb7d205912 100644 --- a/src/objective-c/GRPCClient/private/GRPCCore/GRPCChannelPool.m +++ b/src/objective-c/GRPCClient/private/GRPCChannelPool.m @@ -18,16 +18,19 @@ #import <Foundation/Foundation.h> -#import "../../internal/GRPCCallOptions+Internal.h" +#import "../internal/GRPCCallOptions+Internal.h" #import "GRPCChannel.h" #import "GRPCChannelFactory.h" #import "GRPCChannelPool+Test.h" #import "GRPCChannelPool.h" #import "GRPCCompletionQueue.h" +#import "GRPCCronetChannelFactory.h" #import "GRPCInsecureChannelFactory.h" #import "GRPCSecureChannelFactory.h" #import "GRPCWrappedCall.h" +#import "version.h" +#import <GRPCClient/GRPCCall+Cronet.h> #include <grpc/support/log.h> extern const char *kCFStreamVarName; diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCompletionQueue.h b/src/objective-c/GRPCClient/private/GRPCCompletionQueue.h similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCCompletionQueue.h rename to src/objective-c/GRPCClient/private/GRPCCompletionQueue.h diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCompletionQueue.m b/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCCompletionQueue.m rename to src/objective-c/GRPCClient/private/GRPCCompletionQueue.m diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/GRPCCoreCronetFactory.h b/src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/GRPCCoreCronetFactory.h deleted file mode 100644 index 83d279d2c72e573a007be33d03fb50c1d89380d4..0000000000000000000000000000000000000000 --- a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/GRPCCoreCronetFactory.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#import "../GRPCCoreFactory.h" - -/** - * The factory for gRPC Core + Cronet transport implementation. The - * implementation is not part of the default transports of gRPC and is for - * testing purpose only on Github. - * - * To use this transport, a user must include the GRPCCoreCronet module as a - * dependency of the project and use gGRPCCoreCronetId in call options to - * specify that this is the transport to be used for a call. - */ -@interface GRPCCoreCronetFactory : NSObject<GRPCCoreTransportFactory> - -@end diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/GRPCCoreCronetFactory.m b/src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/GRPCCoreCronetFactory.m deleted file mode 100644 index 5772694fc5402465e97f78beba54e20b83971052..0000000000000000000000000000000000000000 --- a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/GRPCCoreCronetFactory.m +++ /dev/null @@ -1,54 +0,0 @@ -/* - * - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#import "GRPCCoreCronetFactory.h" - -#import <GRPCClient/GRPCCall+Cronet.h> -#import <GRPCClient/GRPCTransport.h> - -#import "../GRPCCallInternal.h" -#import "../GRPCCoreFactory.h" -#import "GRPCCronetChannelFactory.h" - -static GRPCCoreCronetFactory *gGRPCCoreCronetFactory = nil; -static dispatch_once_t gInitGRPCCoreCronetFactory; - -@implementation GRPCCoreCronetFactory - -+ (instancetype)sharedInstance { - dispatch_once(&gInitGRPCCoreCronetFactory, ^{ - gGRPCCoreCronetFactory = [[GRPCCoreCronetFactory alloc] init]; - }); - return gGRPCCoreCronetFactory; -} - -+ (void)load { - [[GRPCTransportRegistry sharedInstance] - registerTransportWithId:gGRPCCoreCronetId - factory:[GRPCCoreCronetFactory sharedInstance]]; -} - -- (GRPCTransport *)createTransportWithManager:(GRPCTransportManager *)transportManager { - return [[GRPCCall2Internal alloc] initWithTransportManager:transportManager]; -} - -- (id<GRPCChannelFactory>)createCoreChannelFactoryWithCallOptions:(GRPCCallOptions *)callOptions { - return [GRPCCronetChannelFactory sharedInstance]; -} - -@end diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreFactory.h b/src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreFactory.h deleted file mode 100644 index 3cd312d4ad045aee2c383c3a4453f170b4b5850e..0000000000000000000000000000000000000000 --- a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreFactory.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#import <GRPCClient/GRPCTransport.h> - -NS_ASSUME_NONNULL_BEGIN - -@protocol GRPCChannelFactory; -@protocol GRPCCallOptions; - -/** The interface for transport implementations that are based on Core. */ -@protocol GRPCCoreTransportFactory<GRPCTransportFactory> - -/** Get the channel factory for GRPCChannel from call options. */ -- (nullable id<GRPCChannelFactory>)createCoreChannelFactoryWithCallOptions: - (GRPCCallOptions *)callOptions; - -@end - -/** The factory for gRPC Core + CFStream + TLS secure channel transport implementation. */ -@interface GRPCCoreSecureFactory : NSObject<GRPCCoreTransportFactory> - -@end - -/** The factory for gRPC Core + CFStream + insecure channel transport implementation. */ -@interface GRPCCoreInsecureFactory : NSObject<GRPCCoreTransportFactory> - -@end - -NS_ASSUME_NONNULL_END diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreFactory.m b/src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreFactory.m deleted file mode 100644 index 19d7231a203816d7a5e33b8dcb2f4a0a73a37369..0000000000000000000000000000000000000000 --- a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreFactory.m +++ /dev/null @@ -1,90 +0,0 @@ -/* - * - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#import "GRPCCoreFactory.h" - -#import <GRPCClient/GRPCTransport.h> - -#import "GRPCCallInternal.h" -#import "GRPCInsecureChannelFactory.h" -#import "GRPCSecureChannelFactory.h" - -static GRPCCoreSecureFactory *gGRPCCoreSecureFactory = nil; -static GRPCCoreInsecureFactory *gGRPCCoreInsecureFactory = nil; -static dispatch_once_t gInitGRPCCoreSecureFactory; -static dispatch_once_t gInitGRPCCoreInsecureFactory; - -@implementation GRPCCoreSecureFactory - -+ (instancetype)sharedInstance { - dispatch_once(&gInitGRPCCoreSecureFactory, ^{ - gGRPCCoreSecureFactory = [[GRPCCoreSecureFactory alloc] init]; - }); - return gGRPCCoreSecureFactory; -} - -+ (void)load { - [[GRPCTransportRegistry sharedInstance] - registerTransportWithId:GRPCDefaultTransportImplList.core_secure - factory:[self sharedInstance]]; -} - -- (GRPCTransport *)createTransportWithManager:(GRPCTransportManager *)transportManager { - return [[GRPCCall2Internal alloc] initWithTransportManager:transportManager]; -} - -- (id<GRPCChannelFactory>)createCoreChannelFactoryWithCallOptions:(GRPCCallOptions *)callOptions { - NSError *error; - id<GRPCChannelFactory> factory = - [GRPCSecureChannelFactory factoryWithPEMRootCertificates:callOptions.PEMRootCertificates - privateKey:callOptions.PEMPrivateKey - certChain:callOptions.PEMCertificateChain - error:&error]; - if (error != nil) { - NSLog(@"Unable to create secure channel factory"); - return nil; - } - return factory; -} - -@end - -@implementation GRPCCoreInsecureFactory - -+ (instancetype)sharedInstance { - dispatch_once(&gInitGRPCCoreInsecureFactory, ^{ - gGRPCCoreInsecureFactory = [[GRPCCoreInsecureFactory alloc] init]; - }); - return gGRPCCoreInsecureFactory; -} - -+ (void)load { - [[GRPCTransportRegistry sharedInstance] - registerTransportWithId:GRPCDefaultTransportImplList.core_insecure - factory:[self sharedInstance]]; -} - -- (GRPCTransport *)createTransportWithManager:(GRPCTransportManager *)transportManager { - return [[GRPCCall2Internal alloc] initWithTransportManager:transportManager]; -} - -- (id<GRPCChannelFactory>)createCoreChannelFactoryWithCallOptions:(GRPCCallOptions *)callOptions { - return [GRPCInsecureChannelFactory sharedInstance]; -} - -@end diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/GRPCCronetChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.h similarity index 96% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/GRPCCronetChannelFactory.h rename to src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.h index 138ddf1f73010df8506bc38917f6b619be6902f0..738dfdb737029115642ce18ebf330275a213b58b 100644 --- a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/GRPCCronetChannelFactory.h +++ b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.h @@ -15,7 +15,7 @@ * limitations under the License. * */ -#import "../GRPCChannelFactory.h" +#import "GRPCChannelFactory.h" @class GRPCChannel; typedef struct stream_engine stream_engine; diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/GRPCCronetChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m similarity index 76% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/GRPCCronetChannelFactory.m rename to src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m index da3f3afd8558f88a79ebbec16acc9785a55dea76..5bcb021dc4bc1f37d5b4ab0339688832933adedc 100644 --- a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/GRPCCronetChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCCronetChannelFactory.m @@ -18,8 +18,10 @@ #import "GRPCCronetChannelFactory.h" -#import "../ChannelArgsUtil.h" -#import "../GRPCChannel.h" +#import "ChannelArgsUtil.h" +#import "GRPCChannel.h" + +#ifdef GRPC_COMPILE_WITH_CRONET #import <Cronet/Cronet.h> #include <grpc/grpc_cronet.h> @@ -57,3 +59,21 @@ } @end + +#else + +@implementation GRPCCronetChannelFactory + ++ (instancetype)sharedInstance { + NSAssert(NO, @"Must enable macro GRPC_COMPILE_WITH_CRONET to build Cronet channel."); + return nil; +} + +- (grpc_channel *)createChannelWithHost:(NSString *)host channelArgs:(NSDictionary *)args { + NSAssert(NO, @"Must enable macro GRPC_COMPILE_WITH_CRONET to build Cronet channel."); + return NULL; +} + +@end + +#endif diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCHost.h b/src/objective-c/GRPCClient/private/GRPCHost.h similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCHost.h rename to src/objective-c/GRPCClient/private/GRPCHost.h diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m similarity index 82% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCHost.m rename to src/objective-c/GRPCClient/private/GRPCHost.m index 1f6a25ff78f066aa84db39d859b0de559390ba75..63ffc92741134b5bcea64a23a08f29d0eef77d35 100644 --- a/src/objective-c/GRPCClient/private/GRPCCore/GRPCHost.m +++ b/src/objective-c/GRPCClient/private/GRPCHost.m @@ -21,16 +21,17 @@ #import <GRPCClient/GRPCCall+Cronet.h> #import <GRPCClient/GRPCCall.h> #import <GRPCClient/GRPCCallOptions.h> -#import <GRPCClient/GRPCTransport.h> #include <grpc/grpc.h> #include <grpc/grpc_security.h> -#import "../../internal/GRPCCallOptions+Internal.h" +#import "../internal/GRPCCallOptions+Internal.h" #import "GRPCChannelFactory.h" #import "GRPCCompletionQueue.h" +#import "GRPCCronetChannelFactory.h" #import "GRPCSecureChannelFactory.h" #import "NSDictionary+GRPC.h" +#import "version.h" NS_ASSUME_NONNULL_BEGIN @@ -112,12 +113,20 @@ static NSMutableDictionary *gHostCache; options.PEMPrivateKey = _PEMPrivateKey; options.PEMCertificateChain = _PEMCertificateChain; options.hostNameOverride = _hostNameOverride; - if (_transportType == GRPCTransportTypeInsecure) { - options.transport = GRPCDefaultTransportImplList.core_insecure; - } else if ([GRPCCall isUsingCronet]) { - options.transport = gGRPCCoreCronetId; - } else { - options.transport = GRPCDefaultTransportImplList.core_secure; +#ifdef GRPC_COMPILE_WITH_CRONET + // By old API logic, insecure channel precedes Cronet channel; Cronet channel preceeds default + // channel. + if ([GRPCCall isUsingCronet]) { + if (_transportType == GRPCTransportTypeInsecure) { + options.transportType = GRPCTransportTypeInsecure; + } else { + NSAssert(_transportType == GRPCTransportTypeDefault, @"Invalid transport type"); + options.transportType = GRPCTransportTypeCronet; + } + } else +#endif + { + options.transportType = _transportType; } options.logContext = _logContext; @@ -126,14 +135,16 @@ static NSMutableDictionary *gHostCache; + (GRPCCallOptions *)callOptionsForHost:(NSString *)host { // TODO (mxyan): Remove when old API is deprecated + NSURL *hostURL = [NSURL URLWithString:[@"https://" stringByAppendingString:host]]; + if (hostURL.host && hostURL.port == nil) { + host = [hostURL.host stringByAppendingString:@":443"]; + } + GRPCCallOptions *callOptions = nil; @synchronized(gHostCache) { - GRPCHost *hostConfig = [GRPCHost hostWithAddress:host]; - callOptions = [hostConfig callOptions]; + callOptions = [gHostCache[host] callOptions]; } - NSAssert(callOptions != nil, @"Unable to create call options object"); if (callOptions == nil) { - NSLog(@"Unable to create call options object"); callOptions = [[GRPCCallOptions alloc] init]; } return callOptions; diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCInsecureChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.h similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCInsecureChannelFactory.h rename to src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.h diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCInsecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCInsecureChannelFactory.m rename to src/objective-c/GRPCClient/private/GRPCInsecureChannelFactory.m diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCOpBatchLog.h b/src/objective-c/GRPCClient/private/GRPCOpBatchLog.h similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCOpBatchLog.h rename to src/objective-c/GRPCClient/private/GRPCOpBatchLog.h diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCOpBatchLog.m b/src/objective-c/GRPCClient/private/GRPCOpBatchLog.m similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCOpBatchLog.m rename to src/objective-c/GRPCClient/private/GRPCOpBatchLog.m diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCReachabilityFlagNames.xmacro.h b/src/objective-c/GRPCClient/private/GRPCReachabilityFlagNames.xmacro.h similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCReachabilityFlagNames.xmacro.h rename to src/objective-c/GRPCClient/private/GRPCReachabilityFlagNames.xmacro.h diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCRequestHeaders.h b/src/objective-c/GRPCClient/private/GRPCRequestHeaders.h similarity index 95% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCRequestHeaders.h rename to src/objective-c/GRPCClient/private/GRPCRequestHeaders.h index 0fced0c385a77c454a4f99f6bb95a50a1855a788..545ff1cea820ce0a47d11da0fb8f81fe296b6399 100644 --- a/src/objective-c/GRPCClient/private/GRPCCore/GRPCRequestHeaders.h +++ b/src/objective-c/GRPCClient/private/GRPCRequestHeaders.h @@ -18,7 +18,7 @@ #import <Foundation/Foundation.h> -#import <GRPCClient/GRPCCallLegacy.h> +#import "../GRPCCall.h" @interface GRPCRequestHeaders : NSMutableDictionary diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCRequestHeaders.m b/src/objective-c/GRPCClient/private/GRPCRequestHeaders.m similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCRequestHeaders.m rename to src/objective-c/GRPCClient/private/GRPCRequestHeaders.m diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCSecureChannelFactory.h b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCSecureChannelFactory.h rename to src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.h diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCSecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCSecureChannelFactory.m rename to src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m diff --git a/src/objective-c/GRPCClient/private/GRPCTransport+Private.h b/src/objective-c/GRPCClient/private/GRPCTransport+Private.h deleted file mode 100644 index 2dc7357c363b6d8ccd1740172219f0fa74171994..0000000000000000000000000000000000000000 --- a/src/objective-c/GRPCClient/private/GRPCTransport+Private.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#import <GRPCClient/GRPCInterceptor.h> -#import <GRPCClient/GRPCTransport.h> - -NS_ASSUME_NONNULL_BEGIN - -/** - * Private interfaces of the transport registry. - */ -@interface GRPCTransportRegistry (Private) - -/** - * Get a transport implementation's factory by its transport id. If the transport id was not - * registered with the registry, the default transport factory (core + secure) is returned. If the - * default transport does not exist, an exception is thrown. - */ -- (id<GRPCTransportFactory>)getTransportFactoryWithId:(GRPCTransportId)transportId; - -@end - -@interface GRPCTransportManager : NSObject<GRPCInterceptorInterface> - -- (instancetype)initWithTransportId:(GRPCTransportId)transportId - previousInterceptor:(id<GRPCResponseHandler>)previousInterceptor; - -/** - * Notify the manager that the transport has shut down and the manager should release references to - * its response handler and stop forwarding requests/responses. - */ -- (void)shutDown; - -/** Forward initial metadata to the previous interceptor in the interceptor chain */ -- (void)forwardPreviousInterceptorWithInitialMetadata:(nullable NSDictionary *)initialMetadata; - -/** Forward a received message to the previous interceptor in the interceptor chain */ -- (void)forwardPreviousInterceptorWithData:(nullable id)data; - -/** Forward call close and trailing metadata to the previous interceptor in the interceptor chain */ -- (void)forwardPreviousInterceptorCloseWithTrailingMetadata: - (nullable NSDictionary *)trailingMetadata - error:(nullable NSError *)error; - -/** Forward write completion to the previous interceptor in the interceptor chain */ -- (void)forwardPreviousInterceptorDidWriteData; - -@end - -NS_ASSUME_NONNULL_END diff --git a/src/objective-c/GRPCClient/private/GRPCTransport+Private.m b/src/objective-c/GRPCClient/private/GRPCTransport+Private.m deleted file mode 100644 index 9072f7afbe2d4786850e77904b2c6348d0d2b32c..0000000000000000000000000000000000000000 --- a/src/objective-c/GRPCClient/private/GRPCTransport+Private.m +++ /dev/null @@ -1,131 +0,0 @@ -/* - * - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#import "GRPCTransport+Private.h" - -#import <GRPCClient/GRPCTransport.h> - -@implementation GRPCTransportManager { - GRPCTransportId _transportId; - GRPCTransport *_transport; - id<GRPCResponseHandler> _previousInterceptor; - dispatch_queue_t _dispatchQueue; -} - -- (instancetype)initWithTransportId:(GRPCTransportId)transportId - previousInterceptor:(id<GRPCResponseHandler>)previousInterceptor { - if ((self = [super init])) { - id<GRPCTransportFactory> factory = - [[GRPCTransportRegistry sharedInstance] getTransportFactoryWithId:transportId]; - - _transport = [factory createTransportWithManager:self]; - NSAssert(_transport != nil, @"Failed to create transport with id: %s", transportId); - if (_transport == nil) { - NSLog(@"Failed to create transport with id: %s", transportId); - return nil; - } - _previousInterceptor = previousInterceptor; - _dispatchQueue = _transport.dispatchQueue; - _transportId = transportId; - } - return self; -} - -- (void)shutDown { - dispatch_async(_dispatchQueue, ^{ - self->_transport = nil; - self->_previousInterceptor = nil; - }); -} - -- (dispatch_queue_t)dispatchQueue { - return _dispatchQueue; -} - -- (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions - callOptions:(GRPCCallOptions *)callOptions { - if (_transportId != callOptions.transport) { - [NSException raise:NSInvalidArgumentException - format:@"Interceptors cannot change the call option 'transport'"]; - return; - } - [_transport startWithRequestOptions:requestOptions callOptions:callOptions]; -} - -- (void)writeData:(id)data { - [_transport writeData:data]; -} - -- (void)finish { - [_transport finish]; -} - -- (void)cancel { - [_transport cancel]; -} - -- (void)receiveNextMessages:(NSUInteger)numberOfMessages { - [_transport receiveNextMessages:numberOfMessages]; -} - -/** Forward initial metadata to the previous interceptor in the chain */ -- (void)forwardPreviousInterceptorWithInitialMetadata:(NSDictionary *)initialMetadata { - if (initialMetadata == nil || _previousInterceptor == nil) { - return; - } - id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor; - dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{ - [copiedPreviousInterceptor didReceiveInitialMetadata:initialMetadata]; - }); -} - -/** Forward a received message to the previous interceptor in the chain */ -- (void)forwardPreviousInterceptorWithData:(id)data { - if (data == nil || _previousInterceptor == nil) { - return; - } - id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor; - dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{ - [copiedPreviousInterceptor didReceiveData:data]; - }); -} - -/** Forward call close and trailing metadata to the previous interceptor in the chain */ -- (void)forwardPreviousInterceptorCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata - error:(NSError *)error { - if (_previousInterceptor == nil) { - return; - } - id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor; - dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{ - [copiedPreviousInterceptor didCloseWithTrailingMetadata:trailingMetadata error:error]; - }); -} - -/** Forward write completion to the previous interceptor in the chain */ -- (void)forwardPreviousInterceptorDidWriteData { - if (_previousInterceptor == nil) { - return; - } - id<GRPCResponseHandler> copiedPreviousInterceptor = _previousInterceptor; - dispatch_async(copiedPreviousInterceptor.dispatchQueue, ^{ - [copiedPreviousInterceptor didWriteData]; - }); -} - -@end diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCWrappedCall.h b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCWrappedCall.h rename to src/objective-c/GRPCClient/private/GRPCWrappedCall.h diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCWrappedCall.m rename to src/objective-c/GRPCClient/private/GRPCWrappedCall.m diff --git a/src/objective-c/GRPCClient/private/GRPCCore/NSData+GRPC.h b/src/objective-c/GRPCClient/private/NSData+GRPC.h similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/NSData+GRPC.h rename to src/objective-c/GRPCClient/private/NSData+GRPC.h diff --git a/src/objective-c/GRPCClient/private/GRPCCore/NSData+GRPC.m b/src/objective-c/GRPCClient/private/NSData+GRPC.m similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/NSData+GRPC.m rename to src/objective-c/GRPCClient/private/NSData+GRPC.m diff --git a/src/objective-c/GRPCClient/private/GRPCCore/NSDictionary+GRPC.h b/src/objective-c/GRPCClient/private/NSDictionary+GRPC.h similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/NSDictionary+GRPC.h rename to src/objective-c/GRPCClient/private/NSDictionary+GRPC.h diff --git a/src/objective-c/GRPCClient/private/GRPCCore/NSDictionary+GRPC.m b/src/objective-c/GRPCClient/private/NSDictionary+GRPC.m similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/NSDictionary+GRPC.m rename to src/objective-c/GRPCClient/private/NSDictionary+GRPC.m diff --git a/src/objective-c/GRPCClient/private/GRPCCore/NSError+GRPC.h b/src/objective-c/GRPCClient/private/NSError+GRPC.h similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/NSError+GRPC.h rename to src/objective-c/GRPCClient/private/NSError+GRPC.h diff --git a/src/objective-c/GRPCClient/private/GRPCCore/NSError+GRPC.m b/src/objective-c/GRPCClient/private/NSError+GRPC.m similarity index 96% rename from src/objective-c/GRPCClient/private/GRPCCore/NSError+GRPC.m rename to src/objective-c/GRPCClient/private/NSError+GRPC.m index 5b5fc6263c5dea20fc8ba4ebf1d8ff637fcf794e..3eefed88d638e90959406b738ff292317679465c 100644 --- a/src/objective-c/GRPCClient/private/GRPCCore/NSError+GRPC.m +++ b/src/objective-c/GRPCClient/private/NSError+GRPC.m @@ -18,9 +18,10 @@ #import "NSError+GRPC.h" -#import <GRPCClient/GRPCTypes.h> #include <grpc/grpc.h> +NSString *const kGRPCErrorDomain = @"io.grpc"; + @implementation NSError (GRPC) + (instancetype)grpc_errorFromStatusCode:(grpc_status_code)statusCode details:(const char *)details diff --git a/src/objective-c/GRPCClient/version.h b/src/objective-c/GRPCClient/private/version.h similarity index 100% rename from src/objective-c/GRPCClient/version.h rename to src/objective-c/GRPCClient/private/version.h diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h index c91adc7b7cdbc1ec314ab66b4e0437961462f10a..12db46adeda5cc076b00d88e06192977ffdf96fc 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.h +++ b/src/objective-c/ProtoRPC/ProtoRPC.h @@ -17,16 +17,12 @@ */ #import <Foundation/Foundation.h> - -// import legacy header for compatibility with users using the ProtoRPC interface -#import "ProtoRPCLegacy.h" +#import <GRPCClient/GRPCCall.h> #import "ProtoMethod.h" NS_ASSUME_NONNULL_BEGIN -@class GRPCRequestOptions; -@class GRPCCallOptions; @class GPBMessage; /** An object can implement this protocol to receive responses from server from a call. */ @@ -164,3 +160,35 @@ NS_ASSUME_NONNULL_BEGIN @end NS_ASSUME_NONNULL_END + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnullability-completeness" + +__attribute__((deprecated("Please use GRPCProtoCall."))) @interface ProtoRPC + : GRPCCall + + /** + * host parameter should not contain the scheme (http:// or https://), only the name or IP + * addr and the port number, for example @"localhost:5050". + */ + - + (instancetype)initWithHost : (NSString *)host method + : (GRPCProtoMethod *)method requestsWriter : (GRXWriter *)requestsWriter responseClass + : (Class)responseClass responsesWriteable + : (id<GRXWriteable>)responsesWriteable NS_DESIGNATED_INITIALIZER; + +- (void)start; +@end + +/** + * This subclass is empty now. Eventually we'll remove ProtoRPC class + * to avoid potential naming conflict + */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + @interface GRPCProtoCall : ProtoRPC +#pragma clang diagnostic pop + + @end + +#pragma clang diagnostic pop diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m index dbfa3c0f23da4a25adfea8fb65599cbe00358588..4700fdd1124044b40375263d7dd81132515edbdf 100644 --- a/src/objective-c/ProtoRPC/ProtoRPC.m +++ b/src/objective-c/ProtoRPC/ProtoRPC.m @@ -27,6 +27,24 @@ #import <RxLibrary/GRXWriteable.h> #import <RxLibrary/GRXWriter+Transformations.h> +/** + * Generate an NSError object that represents a failure in parsing a proto class. + */ +static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsingError) { + NSDictionary *info = @{ + NSLocalizedDescriptionKey : @"Unable to parse response from the server", + NSLocalizedRecoverySuggestionErrorKey : + @"If this RPC is idempotent, retry " + @"with exponential backoff. Otherwise, query the server status before " + @"retrying.", + NSUnderlyingErrorKey : parsingError, + @"Expected class" : expectedClass, + @"Received value" : proto, + }; + // TODO(jcanizales): Use kGRPCErrorDomain and GRPCErrorCodeInternal when they're public. + return [NSError errorWithDomain:@"io.grpc" code:13 userInfo:info]; +} + @implementation GRPCUnaryProtoCall { GRPCStreamingProtoCall *_call; GPBMessage *_message; @@ -273,3 +291,76 @@ } @end + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" +@implementation ProtoRPC { +#pragma clang diagnostic pop + id<GRXWriteable> _responseWriteable; +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wobjc-designated-initializers" +- (instancetype)initWithHost:(NSString *)host + path:(NSString *)path + requestsWriter:(GRXWriter *)requestsWriter { + [NSException raise:NSInvalidArgumentException + format:@"Please use ProtoRPC's designated initializer instead."]; + return nil; +} +#pragma clang diagnostic pop + +// Designated initializer +- (instancetype)initWithHost:(NSString *)host + method:(GRPCProtoMethod *)method + requestsWriter:(GRXWriter *)requestsWriter + responseClass:(Class)responseClass + responsesWriteable:(id<GRXWriteable>)responsesWriteable { + // Because we can't tell the type system to constrain the class, we need to check at runtime: + if (![responseClass respondsToSelector:@selector(parseFromData:error:)]) { + [NSException raise:NSInvalidArgumentException + format:@"A protobuf class to parse the responses must be provided."]; + } + // A writer that serializes the proto messages to send. + GRXWriter *bytesWriter = [requestsWriter map:^id(GPBMessage *proto) { + if (![proto isKindOfClass:[GPBMessage class]]) { + [NSException raise:NSInvalidArgumentException + format:@"Request must be a proto message: %@", proto]; + } + return [proto data]; + }]; + if ((self = [super initWithHost:host path:method.HTTPPath requestsWriter:bytesWriter])) { + __weak ProtoRPC *weakSelf = self; + + // A writeable that parses the proto messages received. + _responseWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { + // TODO(jcanizales): This is done in the main thread, and needs to happen in another thread. + NSError *error = nil; + id parsed = [responseClass parseFromData:value error:&error]; + if (parsed) { + [responsesWriteable writeValue:parsed]; + } else { + [weakSelf finishWithError:ErrorForBadProto(value, responseClass, error)]; + } + } + completionHandler:^(NSError *errorOrNil) { + [responsesWriteable writesFinishedWithError:errorOrNil]; + }]; + } + return self; +} + +- (void)start { + [self startWithWriteable:_responseWriteable]; +} + +- (void)startWithWriteable:(id<GRXWriteable>)writeable { + [super startWithWriteable:writeable]; + // Break retain cycles. + _responseWriteable = nil; +} +@end + +@implementation GRPCProtoCall + +@end diff --git a/src/objective-c/ProtoRPC/ProtoRPCLegacy.h b/src/objective-c/ProtoRPC/ProtoRPCLegacy.h deleted file mode 100644 index b8d4003f6957a8f6aaabeeef02e039ff399b325f..0000000000000000000000000000000000000000 --- a/src/objective-c/ProtoRPC/ProtoRPCLegacy.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#import <GRPCClient/GRPCCallLegacy.h> - -// Import category headers for Swift build -#import <GRPCClient/GRPCCall+ChannelArg.h> -#import <GRPCClient/GRPCCall+ChannelCredentials.h> -#import <GRPCClient/GRPCCall+Cronet.h> -#import <GRPCClient/GRPCCall+OAuth2.h> -#import <GRPCClient/GRPCCall+Tests.h> -#import <RxLibrary/GRXWriteable.h> - -@class GRPCProtoMethod; -@class GRXWriter; -@protocol GRXWriteable; - -__attribute__((deprecated("Please use GRPCProtoCall."))) @interface ProtoRPC - : GRPCCall - - /** - * host parameter should not contain the scheme (http:// or https://), only the name or IP - * addr and the port number, for example @"localhost:5050". - */ - - - (instancetype)initWithHost : (NSString *)host method - : (GRPCProtoMethod *)method requestsWriter : (GRXWriter *)requestsWriter responseClass - : (Class)responseClass responsesWriteable - : (id<GRXWriteable>)responsesWriteable NS_DESIGNATED_INITIALIZER; - -- (void)start; - -@end - -/** - * This subclass is empty now. Eventually we'll remove ProtoRPC class - * to avoid potential naming conflict - */ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - @interface GRPCProtoCall - : ProtoRPC -#pragma clang diagnostic pop - - @end - - /** - * Generate an NSError object that represents a failure in parsing a proto class. For gRPC - * internal use only. - */ - NSError * - ErrorForBadProto(id proto, Class expectedClass, NSError *parsingError); diff --git a/src/objective-c/ProtoRPC/ProtoRPCLegacy.m b/src/objective-c/ProtoRPC/ProtoRPCLegacy.m deleted file mode 100644 index 4ba93674063fbffaabfa8f16fd4819bc5bd01406..0000000000000000000000000000000000000000 --- a/src/objective-c/ProtoRPC/ProtoRPCLegacy.m +++ /dev/null @@ -1,121 +0,0 @@ -/* - * - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#import "ProtoRPCLegacy.h" - -#import "ProtoMethod.h" - -#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS -#import <Protobuf/GPBProtocolBuffers.h> -#else -#import <GPBProtocolBuffers.h> -#endif -#import <GRPCClient/GRPCCall.h> -#import <RxLibrary/GRXWriteable.h> -#import <RxLibrary/GRXWriter+Transformations.h> - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-implementations" -@implementation ProtoRPC { -#pragma clang diagnostic pop - id<GRXWriteable> _responseWriteable; -} - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wobjc-designated-initializers" -- (instancetype)initWithHost:(NSString *)host - path:(NSString *)path - requestsWriter:(GRXWriter *)requestsWriter { - [NSException raise:NSInvalidArgumentException - format:@"Please use ProtoRPC's designated initializer instead."]; - return nil; -} -#pragma clang diagnostic pop - -// Designated initializer -- (instancetype)initWithHost:(NSString *)host - method:(GRPCProtoMethod *)method - requestsWriter:(GRXWriter *)requestsWriter - responseClass:(Class)responseClass - responsesWriteable:(id<GRXWriteable>)responsesWriteable { - // Because we can't tell the type system to constrain the class, we need to check at runtime: - if (![responseClass respondsToSelector:@selector(parseFromData:error:)]) { - [NSException raise:NSInvalidArgumentException - format:@"A protobuf class to parse the responses must be provided."]; - } - // A writer that serializes the proto messages to send. - GRXWriter *bytesWriter = [requestsWriter map:^id(GPBMessage *proto) { - if (![proto isKindOfClass:[GPBMessage class]]) { - [NSException raise:NSInvalidArgumentException - format:@"Request must be a proto message: %@", proto]; - } - return [proto data]; - }]; - if ((self = [super initWithHost:host path:method.HTTPPath requestsWriter:bytesWriter])) { - __weak ProtoRPC *weakSelf = self; - - // A writeable that parses the proto messages received. - _responseWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { - // TODO(jcanizales): This is done in the main thread, and needs to happen in another thread. - NSError *error = nil; - id parsed = [responseClass parseFromData:value error:&error]; - if (parsed) { - [responsesWriteable writeValue:parsed]; - } else { - [weakSelf finishWithError:ErrorForBadProto(value, responseClass, error)]; - } - } - completionHandler:^(NSError *errorOrNil) { - [responsesWriteable writesFinishedWithError:errorOrNil]; - }]; - } - return self; -} - -- (void)start { - [self startWithWriteable:_responseWriteable]; -} - -- (void)startWithWriteable:(id<GRXWriteable>)writeable { - [super startWithWriteable:writeable]; - // Break retain cycles. - _responseWriteable = nil; -} -@end - -@implementation GRPCProtoCall - -@end - -/** - * Generate an NSError object that represents a failure in parsing a proto class. - */ -NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsingError) { - NSDictionary *info = @{ - NSLocalizedDescriptionKey : @"Unable to parse response from the server", - NSLocalizedRecoverySuggestionErrorKey : - @"If this RPC is idempotent, retry " - @"with exponential backoff. Otherwise, query the server status before " - @"retrying.", - NSUnderlyingErrorKey : parsingError, - @"Expected class" : expectedClass, - @"Received value" : proto, - }; - // TODO(jcanizales): Use kGRPCErrorDomain and GRPCErrorCodeInternal when they're public. - return [NSError errorWithDomain:@"io.grpc" code:13 userInfo:info]; -} diff --git a/src/objective-c/ProtoRPC/ProtoService.h b/src/objective-c/ProtoRPC/ProtoService.h index fd8a86bb2b29c2d8956fa728ee5e91e61e2988e6..900ec8d0e1ea7d69b2e0674506cf11c3800bf531 100644 --- a/src/objective-c/ProtoRPC/ProtoService.h +++ b/src/objective-c/ProtoRPC/ProtoService.h @@ -18,12 +18,14 @@ #import <Foundation/Foundation.h> -#import <GRPCClient/GRPCCallOptions.h> -#import "ProtoRPC.h" - +@class GRPCProtoCall; @protocol GRXWriteable; @class GRXWriter; @class GRPCCallOptions; +@class GRPCProtoCall; +@class GRPCUnaryProtoCall; +@class GRPCStreamingProtoCall; +@protocol GRPCProtoResponseHandler; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wnullability-completeness" @@ -36,6 +38,15 @@ __attribute__((deprecated("Please use GRPCProtoService."))) @interface ProtoServ : (nonnull NSString *)packageName serviceName : (nonnull NSString *)serviceName callOptions : (nullable GRPCCallOptions *)callOptions NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithHost:(NSString *)host + packageName:(NSString *)packageName + serviceName:(NSString *)serviceName; + +- (GRPCProtoCall *)RPCToMethod:(NSString *)method + requestsWriter:(GRXWriter *)requestsWriter + responseClass:(Class)responseClass + responsesWriteable:(id<GRXWriteable>)responsesWriteable; + - (nullable GRPCUnaryProtoCall *)RPCToMethod:(nonnull NSString *)method message:(nonnull id)message responseHandler:(nonnull id<GRPCProtoResponseHandler>)handler @@ -47,18 +58,6 @@ __attribute__((deprecated("Please use GRPCProtoService."))) @interface ProtoServ callOptions:(nullable GRPCCallOptions *)callOptions responseClass:(nonnull Class)responseClass; -@end - - @interface ProtoService(Legacy) - - - (instancetype)initWithHost : (NSString *)host packageName - : (NSString *)packageName serviceName : (NSString *)serviceName; - -- (GRPCProtoCall *)RPCToMethod:(NSString *)method - requestsWriter:(GRXWriter *)requestsWriter - responseClass:(Class)responseClass - responsesWriteable:(id<GRXWriteable>)responsesWriteable; - @end #pragma clang diagnostic pop diff --git a/src/objective-c/ProtoRPC/ProtoService.m b/src/objective-c/ProtoRPC/ProtoService.m index e84cab8903f9610a23d6c4c945fccc165bf32eae..80a1f2f226c34cc8815dbfc5f1c3ddd6beac7eaa 100644 --- a/src/objective-c/ProtoRPC/ProtoService.m +++ b/src/objective-c/ProtoRPC/ProtoService.m @@ -29,21 +29,15 @@ #pragma clang diagnostic ignored "-Wdeprecated-implementations" @implementation ProtoService { #pragma clang diagnostic pop - - GRPCCallOptions *_callOptions; NSString *_host; NSString *_packageName; NSString *_serviceName; + GRPCCallOptions *_callOptions; } -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wnonnull" -// Do not call the default init method - (instancetype)init { - [NSException raise:NSGenericException format:@"Do not call init method of ProtoService"]; - return [self initWithHost:nil packageName:nil serviceName:nil callOptions:nil]; + return [self initWithHost:nil packageName:nil serviceName:nil]; } -#pragma clang diagnostic pop // Designated initializer - (instancetype)initWithHost:(NSString *)host @@ -64,6 +58,38 @@ return self; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wobjc-designated-initializers" +// Do not call designated initializer here due to nullability incompatibility. This method is from +// old API and does not assert on nullability of the parameters. + +- (instancetype)initWithHost:(NSString *)host + packageName:(NSString *)packageName + serviceName:(NSString *)serviceName { + if ((self = [super init])) { + _host = [host copy]; + _packageName = [packageName copy]; + _serviceName = [serviceName copy]; + _callOptions = nil; + } + return self; +} + +#pragma clang diagnostic pop + +- (GRPCProtoCall *)RPCToMethod:(NSString *)method + requestsWriter:(GRXWriter *)requestsWriter + responseClass:(Class)responseClass + responsesWriteable:(id<GRXWriteable>)responsesWriteable { + GRPCProtoMethod *methodName = + [[GRPCProtoMethod alloc] initWithPackage:_packageName service:_serviceName method:method]; + return [[GRPCProtoCall alloc] initWithHost:_host + method:methodName + requestsWriter:requestsWriter + responseClass:responseClass + responsesWriteable:responsesWriteable]; +} + - (GRPCUnaryProtoCall *)RPCToMethod:(NSString *)method message:(id)message responseHandler:(id<GRPCProtoResponseHandler>)handler diff --git a/src/objective-c/ProtoRPC/ProtoServiceLegacy.h b/src/objective-c/ProtoRPC/ProtoServiceLegacy.h deleted file mode 100644 index 7b0b7a4de7e3814de01fb4123ba7f215b824bdaa..0000000000000000000000000000000000000000 --- a/src/objective-c/ProtoRPC/ProtoServiceLegacy.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#import "ProtoService.h" - -@class GRPCProtoCall; -@class GRXWriter; -@protocol GRXWriteable; diff --git a/src/objective-c/ProtoRPC/ProtoServiceLegacy.m b/src/objective-c/ProtoRPC/ProtoServiceLegacy.m deleted file mode 100644 index 6aa64955381119add6c538d515c3214094c6bfd9..0000000000000000000000000000000000000000 --- a/src/objective-c/ProtoRPC/ProtoServiceLegacy.m +++ /dev/null @@ -1,71 +0,0 @@ -/* - * - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#import <objc/runtime.h> - -#import "ProtoMethod.h" -#import "ProtoRPCLegacy.h" -#import "ProtoService.h" - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-implementations" -@implementation ProtoService (Legacy) -#pragma clang diagnostic pop - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wobjc-designated-initializers" -// Do not call designated initializer here due to nullability incompatibility. This method is from -// old API and does not assert on nullability of the parameters. - -- (instancetype)initWithHost:(NSString *)host - packageName:(NSString *)packageName - serviceName:(NSString *)serviceName { - if ((self = [super init])) { - Ivar hostIvar = class_getInstanceVariable([ProtoService class], "_host"); - Ivar packageNameIvar = class_getInstanceVariable([ProtoService class], "_packageName"); - Ivar serviceNameIvar = class_getInstanceVariable([ProtoService class], "_serviceName"); - - object_setIvar(self, hostIvar, [host copy]); - object_setIvar(self, packageNameIvar, [packageName copy]); - object_setIvar(self, serviceNameIvar, [serviceName copy]); - } - return self; -} -#pragma clang diagnostic pop - -- (GRPCProtoCall *)RPCToMethod:(NSString *)method - requestsWriter:(GRXWriter *)requestsWriter - responseClass:(Class)responseClass - responsesWriteable:(id<GRXWriteable>)responsesWriteable { - Ivar hostIvar = class_getInstanceVariable([ProtoService class], "_host"); - Ivar packageNameIvar = class_getInstanceVariable([ProtoService class], "_packageName"); - Ivar serviceNameIvar = class_getInstanceVariable([ProtoService class], "_serviceName"); - NSString *host = object_getIvar(self, hostIvar); - NSString *packageName = object_getIvar(self, packageNameIvar); - NSString *serviceName = object_getIvar(self, serviceNameIvar); - - GRPCProtoMethod *methodName = - [[GRPCProtoMethod alloc] initWithPackage:packageName service:serviceName method:method]; - return [[GRPCProtoCall alloc] initWithHost:host - method:methodName - requestsWriter:requestsWriter - responseClass:responseClass - responsesWriteable:responsesWriteable]; -} - -@end diff --git a/src/objective-c/examples/tvOS-sample/tvOS-sample/ViewController.m b/src/objective-c/examples/tvOS-sample/tvOS-sample/ViewController.m index 9c46626012161df775b166068624c848644c8e04..c94ee8c256977346074e13307302330928265543 100644 --- a/src/objective-c/examples/tvOS-sample/tvOS-sample/ViewController.m +++ b/src/objective-c/examples/tvOS-sample/tvOS-sample/ViewController.m @@ -25,8 +25,6 @@ #import "src/objective-c/examples/RemoteTestClient/Messages.pbobjc.h" #import "src/objective-c/examples/RemoteTestClient/Test.pbrpc.h" #endif -#import <GRPCClient/GRPCCallOptions.h> -#import <ProtoRPC/ProtoRPC.h> @interface ViewController ()<GRPCProtoResponseHandler> diff --git a/src/objective-c/examples/watchOS-sample/WatchKit-Extension/InterfaceController.m b/src/objective-c/examples/watchOS-sample/WatchKit-Extension/InterfaceController.m index ce204a9c1462e92a52ff6fd071e2d6287b5ac146..3e97767cf0cffd3bae072f1cdc81b7e62965a722 100644 --- a/src/objective-c/examples/watchOS-sample/WatchKit-Extension/InterfaceController.m +++ b/src/objective-c/examples/watchOS-sample/WatchKit-Extension/InterfaceController.m @@ -24,8 +24,6 @@ #import "src/objective-c/examples/RemoteTestClient/Messages.pbobjc.h" #import "src/objective-c/examples/RemoteTestClient/Test.pbrpc.h" #endif -#import <GRPCClient/GRPCCallOptions.h> -#import <ProtoRPC/ProtoRPC.h> @interface InterfaceController ()<GRPCProtoResponseHandler> diff --git a/src/objective-c/tests/BUILD b/src/objective-c/tests/BUILD index 65a32d742a910f4f6cb41075c510c231be0ec24c..fed92596b17d2a640c73820571d4d0f82a667179 100644 --- a/src/objective-c/tests/BUILD +++ b/src/objective-c/tests/BUILD @@ -95,12 +95,19 @@ tvos_application( deps = ["host-lib"], ) +grpc_objc_testing_library( + name = "CronetConfig", + srcs = ["ConfigureCronet.m"], + hdrs = ["ConfigureCronet.h"], +) + grpc_objc_testing_library( name = "InteropTests-lib", hdrs = ["InteropTests/InteropTests.h"], srcs = ["InteropTests/InteropTests.m"], deps = [ ":InteropTestsBlockCallbacks-lib", + ":CronetConfig", ], ) @@ -193,6 +200,7 @@ ios_unit_test( ":InteropTestsRemote-lib", ":InteropTestsLocalSSL-lib", ":InteropTestsLocalCleartext-lib", + # ":InteropTestsMulitpleChannels-lib", # needs Cronet ], test_host = ":ios-host", ) diff --git a/src/objective-c/tests/ConfigureCronet.h b/src/objective-c/tests/ConfigureCronet.h index ba0efc4df663dca679955f7febc258319ee541b6..cc5c038f3c61db280d20509297356b5d44dd9c74 100644 --- a/src/objective-c/tests/ConfigureCronet.h +++ b/src/objective-c/tests/ConfigureCronet.h @@ -16,6 +16,8 @@ * */ +#ifdef GRPC_COMPILE_WITH_CRONET + #ifdef __cplusplus extern "C" { #endif @@ -28,3 +30,5 @@ void configureCronet(void); #ifdef __cplusplus } #endif + +#endif diff --git a/src/objective-c/tests/ConfigureCronet.m b/src/objective-c/tests/ConfigureCronet.m index 6fc7e0ee9f59a4fa3d89f2e7ebb3ad4507877a69..ab137e28cad0875438bb0a0d38c3d4e93024ee0f 100644 --- a/src/objective-c/tests/ConfigureCronet.m +++ b/src/objective-c/tests/ConfigureCronet.m @@ -16,6 +16,8 @@ * */ +#ifdef GRPC_COMPILE_WITH_CRONET + #import "ConfigureCronet.h" #import <Cronet/Cronet.h> @@ -33,3 +35,5 @@ void configureCronet(void) { [Cronet startNetLogToFile:@"cronet_netlog.json" logBytes:YES]; }); } + +#endif diff --git a/src/objective-c/tests/CronetTests/InteropTestsRemoteWithCronet.m b/src/objective-c/tests/CronetTests/InteropTestsRemoteWithCronet.m index aa1af301b960795fae74b35eea1092c77b38346f..a2a79c463167d851df013e1501f2b1544f7eed34 100644 --- a/src/objective-c/tests/CronetTests/InteropTestsRemoteWithCronet.m +++ b/src/objective-c/tests/CronetTests/InteropTestsRemoteWithCronet.m @@ -22,7 +22,6 @@ #import <Cronet/Cronet.h> #import <GRPCClient/GRPCCall+Cronet.h> -#import "../ConfigureCronet.h" #import "InteropTests.h" // The server address is derived from preprocessor macro, which is @@ -41,19 +40,12 @@ static int32_t kRemoteInteropServerOverhead = 12; @implementation InteropTestsRemoteWithCronet -+ (void)setUp { - configureCronet(); - [GRPCCall useCronetWithEngine:[Cronet getGlobalEngine]]; - - [super setUp]; -} - + (NSString *)host { return kRemoteSSLHost; } -+ (GRPCTransportId)transport { - return gGRPCCoreCronetId; ++ (BOOL)useCronet { + return YES; } - (int32_t)encodingOverhead { diff --git a/src/objective-c/tests/InteropTests/InteropTests.h b/src/objective-c/tests/InteropTests/InteropTests.h index a4adecd541574ac1e8da434ed124582ca2f2676d..28fcbff9695a7dafaffd066244cf1946b5e31e0a 100644 --- a/src/objective-c/tests/InteropTests/InteropTests.h +++ b/src/objective-c/tests/InteropTests/InteropTests.h @@ -48,19 +48,11 @@ - (int32_t)encodingOverhead; /** - * DEPRECATED: \a transportType is a deprecated option. Please use \a transport instead. - * * The type of transport to be used. The base implementation returns default. Subclasses should * override to appropriate settings. */ + (GRPCTransportType)transportType; -/* - * The transport to be used. The base implementation returns NULL. Subclasses should override to - * appropriate settings. - */ -+ (GRPCTransportId)transport; - /** * The root certificates to be used. The base implementation returns nil. Subclasses should override * to appropriate settings. @@ -73,4 +65,9 @@ */ + (NSString *)hostNameOverride; +/** + * Whether to use Cronet for all the v1 API tests in the test suite. + */ ++ (BOOL)useCronet; + @end diff --git a/src/objective-c/tests/InteropTests/InteropTests.m b/src/objective-c/tests/InteropTests/InteropTests.m index 21198f7bad9762b6e8ceb7b5b29ef4ff656c0c18..a8f7db7ee9343bad1af9961e027fe366fb216c58 100644 --- a/src/objective-c/tests/InteropTests/InteropTests.m +++ b/src/objective-c/tests/InteropTests/InteropTests.m @@ -20,6 +20,9 @@ #include <grpc/status.h> +#ifdef GRPC_COMPILE_WITH_CRONET +#import <Cronet/Cronet.h> +#endif #import <GRPCClient/GRPCCall+ChannelArg.h> #import <GRPCClient/GRPCCall+Cronet.h> #import <GRPCClient/GRPCCall+Interceptor.h> @@ -35,6 +38,7 @@ #import "src/objective-c/tests/RemoteTestClient/Test.pbobjc.h" #import "src/objective-c/tests/RemoteTestClient/Test.pbrpc.h" +#import "../ConfigureCronet.h" #import "InteropTestsBlockCallbacks.h" #define TEST_TIMEOUT 32 @@ -87,8 +91,9 @@ BOOL isRemoteInteropTest(NSString *host) { - (GRPCInterceptor *)createInterceptorWithManager:(GRPCInterceptorManager *)interceptorManager { dispatch_queue_t queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); - return - [[GRPCInterceptor alloc] initWithInterceptorManager:interceptorManager dispatchQueue:queue]; + return [[GRPCInterceptor alloc] initWithInterceptorManager:interceptorManager + requestDispatchQueue:queue + responseDispatchQueue:queue]; } @end @@ -96,19 +101,21 @@ BOOL isRemoteInteropTest(NSString *host) { @interface HookInterceptorFactory : NSObject<GRPCInterceptorFactory> - (instancetype) - initWithDispatchQueue:(dispatch_queue_t)dispatchQueue - startHook:(void (^)(GRPCRequestOptions *requestOptions, GRPCCallOptions *callOptions, - GRPCInterceptorManager *manager))startHook - writeDataHook:(void (^)(id data, GRPCInterceptorManager *manager))writeDataHook - finishHook:(void (^)(GRPCInterceptorManager *manager))finishHook -receiveNextMessagesHook:(void (^)(NSUInteger numberOfMessages, - GRPCInterceptorManager *manager))receiveNextMessagesHook - responseHeaderHook:(void (^)(NSDictionary *initialMetadata, - GRPCInterceptorManager *manager))responseHeaderHook - responseDataHook:(void (^)(id data, GRPCInterceptorManager *manager))responseDataHook - responseCloseHook:(void (^)(NSDictionary *trailingMetadata, NSError *error, - GRPCInterceptorManager *manager))responseCloseHook - didWriteDataHook:(void (^)(GRPCInterceptorManager *manager))didWriteDataHook; +initWithRequestDispatchQueue:(dispatch_queue_t)requestDispatchQueue + responseDispatchQueue:(dispatch_queue_t)responseDispatchQueue + startHook:(void (^)(GRPCRequestOptions *requestOptions, + GRPCCallOptions *callOptions, + GRPCInterceptorManager *manager))startHook + writeDataHook:(void (^)(id data, GRPCInterceptorManager *manager))writeDataHook + finishHook:(void (^)(GRPCInterceptorManager *manager))finishHook + receiveNextMessagesHook:(void (^)(NSUInteger numberOfMessages, + GRPCInterceptorManager *manager))receiveNextMessagesHook + responseHeaderHook:(void (^)(NSDictionary *initialMetadata, + GRPCInterceptorManager *manager))responseHeaderHook + responseDataHook:(void (^)(id data, GRPCInterceptorManager *manager))responseDataHook + responseCloseHook:(void (^)(NSDictionary *trailingMetadata, NSError *error, + GRPCInterceptorManager *manager))responseCloseHook + didWriteDataHook:(void (^)(GRPCInterceptorManager *manager))didWriteDataHook; - (GRPCInterceptor *)createInterceptorWithManager:(GRPCInterceptorManager *)interceptorManager; @@ -118,7 +125,8 @@ receiveNextMessagesHook:(void (^)(NSUInteger numberOfMessages, - (instancetype) initWithInterceptorManager:(GRPCInterceptorManager *)interceptorManager - dispatchQueue:(dispatch_queue_t)dispatchQueue + requestDispatchQueue:(dispatch_queue_t)requestDispatchQueue + responseDispatchQueue:(dispatch_queue_t)responseDispatchQueue startHook:(void (^)(GRPCRequestOptions *requestOptions, GRPCCallOptions *callOptions, GRPCInterceptorManager *manager))startHook @@ -147,25 +155,29 @@ initWithInterceptorManager:(GRPCInterceptorManager *)interceptorManager void (^_responseCloseHook)(NSDictionary *trailingMetadata, NSError *error, GRPCInterceptorManager *manager); void (^_didWriteDataHook)(GRPCInterceptorManager *manager); - dispatch_queue_t _dispatchQueue; + dispatch_queue_t _requestDispatchQueue; + dispatch_queue_t _responseDispatchQueue; } - (instancetype) - initWithDispatchQueue:(dispatch_queue_t)dispatchQueue - startHook:(void (^)(GRPCRequestOptions *requestOptions, GRPCCallOptions *callOptions, - GRPCInterceptorManager *manager))startHook - writeDataHook:(void (^)(id data, GRPCInterceptorManager *manager))writeDataHook - finishHook:(void (^)(GRPCInterceptorManager *manager))finishHook -receiveNextMessagesHook:(void (^)(NSUInteger numberOfMessages, - GRPCInterceptorManager *manager))receiveNextMessagesHook - responseHeaderHook:(void (^)(NSDictionary *initialMetadata, - GRPCInterceptorManager *manager))responseHeaderHook - responseDataHook:(void (^)(id data, GRPCInterceptorManager *manager))responseDataHook - responseCloseHook:(void (^)(NSDictionary *trailingMetadata, NSError *error, - GRPCInterceptorManager *manager))responseCloseHook - didWriteDataHook:(void (^)(GRPCInterceptorManager *manager))didWriteDataHook { +initWithRequestDispatchQueue:(dispatch_queue_t)requestDispatchQueue + responseDispatchQueue:(dispatch_queue_t)responseDispatchQueue + startHook:(void (^)(GRPCRequestOptions *requestOptions, + GRPCCallOptions *callOptions, + GRPCInterceptorManager *manager))startHook + writeDataHook:(void (^)(id data, GRPCInterceptorManager *manager))writeDataHook + finishHook:(void (^)(GRPCInterceptorManager *manager))finishHook + receiveNextMessagesHook:(void (^)(NSUInteger numberOfMessages, + GRPCInterceptorManager *manager))receiveNextMessagesHook + responseHeaderHook:(void (^)(NSDictionary *initialMetadata, + GRPCInterceptorManager *manager))responseHeaderHook + responseDataHook:(void (^)(id data, GRPCInterceptorManager *manager))responseDataHook + responseCloseHook:(void (^)(NSDictionary *trailingMetadata, NSError *error, + GRPCInterceptorManager *manager))responseCloseHook + didWriteDataHook:(void (^)(GRPCInterceptorManager *manager))didWriteDataHook { if ((self = [super init])) { - _dispatchQueue = dispatchQueue; + _requestDispatchQueue = requestDispatchQueue; + _responseDispatchQueue = responseDispatchQueue; _startHook = startHook; _writeDataHook = writeDataHook; _finishHook = finishHook; @@ -180,7 +192,8 @@ receiveNextMessagesHook:(void (^)(NSUInteger numberOfMessages, - (GRPCInterceptor *)createInterceptorWithManager:(GRPCInterceptorManager *)interceptorManager { return [[HookInterceptor alloc] initWithInterceptorManager:interceptorManager - dispatchQueue:_dispatchQueue + requestDispatchQueue:_requestDispatchQueue + responseDispatchQueue:_responseDispatchQueue startHook:_startHook writeDataHook:_writeDataHook finishHook:_finishHook @@ -205,16 +218,22 @@ receiveNextMessagesHook:(void (^)(NSUInteger numberOfMessages, GRPCInterceptorManager *manager); void (^_didWriteDataHook)(GRPCInterceptorManager *manager); GRPCInterceptorManager *_manager; - dispatch_queue_t _dispatchQueue; + dispatch_queue_t _requestDispatchQueue; + dispatch_queue_t _responseDispatchQueue; +} + +- (dispatch_queue_t)requestDispatchQueue { + return _requestDispatchQueue; } - (dispatch_queue_t)dispatchQueue { - return _dispatchQueue; + return _responseDispatchQueue; } - (instancetype) initWithInterceptorManager:(GRPCInterceptorManager *)interceptorManager - dispatchQueue:(dispatch_queue_t)dispatchQueue + requestDispatchQueue:(dispatch_queue_t)requestDispatchQueue + responseDispatchQueue:(dispatch_queue_t)responseDispatchQueue startHook:(void (^)(GRPCRequestOptions *requestOptions, GRPCCallOptions *callOptions, GRPCInterceptorManager *manager))startHook @@ -228,7 +247,9 @@ initWithInterceptorManager:(GRPCInterceptorManager *)interceptorManager responseCloseHook:(void (^)(NSDictionary *trailingMetadata, NSError *error, GRPCInterceptorManager *manager))responseCloseHook didWriteDataHook:(void (^)(GRPCInterceptorManager *manager))didWriteDataHook { - if ((self = [super initWithInterceptorManager:interceptorManager dispatchQueue:dispatchQueue])) { + if ((self = [super initWithInterceptorManager:interceptorManager + requestDispatchQueue:requestDispatchQueue + responseDispatchQueue:responseDispatchQueue])) { _startHook = startHook; _writeDataHook = writeDataHook; _finishHook = finishHook; @@ -237,7 +258,8 @@ initWithInterceptorManager:(GRPCInterceptorManager *)interceptorManager _responseDataHook = responseDataHook; _responseCloseHook = responseCloseHook; _didWriteDataHook = didWriteDataHook; - _dispatchQueue = dispatchQueue; + _requestDispatchQueue = requestDispatchQueue; + _responseDispatchQueue = responseDispatchQueue; _manager = interceptorManager; } return self; @@ -298,7 +320,8 @@ initWithInterceptorManager:(GRPCInterceptorManager *)interceptorManager @property BOOL enabled; -- (instancetype)initWithDispatchQueue:(dispatch_queue_t)dispatchQueue; +- (instancetype)initWithRequestDispatchQueue:(dispatch_queue_t)requestDispatchQueue + responseDispatchQueue:(dispatch_queue_t)responseDispatchQueue; - (void)setStartHook:(void (^)(GRPCRequestOptions *requestOptions, GRPCCallOptions *callOptions, GRPCInterceptorManager *manager))startHook @@ -317,23 +340,26 @@ initWithInterceptorManager:(GRPCInterceptorManager *)interceptorManager @implementation GlobalInterceptorFactory -- (instancetype)initWithDispatchQueue:(dispatch_queue_t)dispatchQueue { +- (instancetype)initWithRequestDispatchQueue:(dispatch_queue_t)requestDispatchQueue + responseDispatchQueue:(dispatch_queue_t)responseDispatchQueue { _enabled = NO; - return [super initWithDispatchQueue:dispatchQueue - startHook:nil - writeDataHook:nil - finishHook:nil - receiveNextMessagesHook:nil - responseHeaderHook:nil - responseDataHook:nil - responseCloseHook:nil - didWriteDataHook:nil]; + return [super initWithRequestDispatchQueue:requestDispatchQueue + responseDispatchQueue:responseDispatchQueue + startHook:nil + writeDataHook:nil + finishHook:nil + receiveNextMessagesHook:nil + responseHeaderHook:nil + responseDataHook:nil + responseCloseHook:nil + didWriteDataHook:nil]; } - (GRPCInterceptor *)createInterceptorWithManager:(GRPCInterceptorManager *)interceptorManager { if (_enabled) { return [[HookInterceptor alloc] initWithInterceptorManager:interceptorManager - dispatchQueue:_dispatchQueue + requestDispatchQueue:_requestDispatchQueue + responseDispatchQueue:_responseDispatchQueue startHook:_startHook writeDataHook:_writeDataHook finishHook:_finishHook @@ -399,15 +425,10 @@ static dispatch_once_t initGlobalInterceptorFactory; return 0; } -// For backwards compatibility + (GRPCTransportType)transportType { return GRPCTransportTypeChttp2BoringSSL; } -+ (GRPCTransportId)transport { - return NULL; -} - + (NSString *)PEMRootCertificates { return nil; } @@ -416,11 +437,26 @@ static dispatch_once_t initGlobalInterceptorFactory; return nil; } ++ (BOOL)useCronet { + return NO; +} + + (void)setUp { +#ifdef GRPC_COMPILE_WITH_CRONET + configureCronet(); + if ([self useCronet]) { + [GRPCCall useCronetWithEngine:[Cronet getGlobalEngine]]; + } +#endif +#ifdef GRPC_CFSTREAM + setenv(kCFStreamVarName, "1", 1); +#endif + dispatch_once(&initGlobalInterceptorFactory, ^{ dispatch_queue_t globalInterceptorQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); globalInterceptorFactory = - [[GlobalInterceptorFactory alloc] initWithDispatchQueue:globalInterceptorQueue]; + [[GlobalInterceptorFactory alloc] initWithRequestDispatchQueue:globalInterceptorQueue + responseDispatchQueue:globalInterceptorQueue]; [GRPCCall2 registerGlobalInterceptor:globalInterceptorFactory]; }); } @@ -466,9 +502,7 @@ static dispatch_once_t initGlobalInterceptorFactory; GPBEmpty *request = [GPBEmpty message]; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - // For backwards compatibility options.transportType = [[self class] transportType]; - options.transport = [[self class] transport]; options.PEMRootCertificates = [[self class] PEMRootCertificates]; options.hostNameOverride = [[self class] hostNameOverride]; @@ -497,9 +531,7 @@ static dispatch_once_t initGlobalInterceptorFactory; GPBEmpty *request = [GPBEmpty message]; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - // For backwards compatibility options.transportType = [[self class] transportType]; - options.transport = [[self class] transport]; options.PEMRootCertificates = [[self class] PEMRootCertificates]; options.hostNameOverride = [[self class] hostNameOverride]; @@ -576,9 +608,7 @@ static dispatch_once_t initGlobalInterceptorFactory; request.payload.body = [NSMutableData dataWithLength:271828]; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - // For backwards compatibility options.transportType = [[self class] transportType]; - options.transport = [[self class] transport]; options.PEMRootCertificates = [[self class] PEMRootCertificates]; options.hostNameOverride = [[self class] hostNameOverride]; @@ -626,9 +656,7 @@ static dispatch_once_t initGlobalInterceptorFactory; request.responseStatus.code = GRPC_STATUS_CANCELLED; } GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - // For backwards compatibility options.transportType = [[self class] transportType]; - options.transport = [[self class] transport]; options.PEMRootCertificates = [[self class] PEMRootCertificates]; options.hostNameOverride = [[self class] hostNameOverride]; @@ -930,9 +958,7 @@ static dispatch_once_t initGlobalInterceptorFactory; id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index] requestedResponseSize:responses[index]]; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - // For backwards compatibility options.transportType = [[self class] transportType]; - options.transport = [[self class] transport]; options.PEMRootCertificates = [[self class] PEMRootCertificates]; options.hostNameOverride = [[self class] hostNameOverride]; @@ -984,9 +1010,7 @@ static dispatch_once_t initGlobalInterceptorFactory; id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index] requestedResponseSize:responses[index]]; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - // For backwards compatibility options.transportType = [[self class] transportType]; - options.transport = [[self class] transport]; options.PEMRootCertificates = [[self class] PEMRootCertificates]; options.hostNameOverride = [[self class] hostNameOverride]; options.flowControlEnabled = YES; @@ -1143,9 +1167,7 @@ static dispatch_once_t initGlobalInterceptorFactory; __block BOOL receivedResponse = NO; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - // For backwards compatibility options.transportType = self.class.transportType; - options.transport = [[self class] transport]; options.PEMRootCertificates = self.class.PEMRootCertificates; options.hostNameOverride = [[self class] hostNameOverride]; @@ -1178,9 +1200,7 @@ static dispatch_once_t initGlobalInterceptorFactory; [self expectationWithDescription:@"Call completed."]; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - // For backwards compatibility options.transportType = self.class.transportType; - options.transport = [[self class] transport]; options.PEMRootCertificates = self.class.PEMRootCertificates; options.hostNameOverride = [[self class] hostNameOverride]; @@ -1266,47 +1286,48 @@ static dispatch_once_t initGlobalInterceptorFactory; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } -- (void)testKeepaliveWithV2API { +#ifndef GRPC_COMPILE_WITH_CRONET +- (void)testKeepalive { XCTAssertNotNil([[self class] host]); - if ([[self class] transport] == gGRPCCoreCronetId) { - // Cronet does not support keepalive - return; - } __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Keepalive"]; - NSNumber *kRequestSize = @27182; - NSNumber *kResponseSize = @31415; + [GRPCCall setKeepaliveWithInterval:1500 timeout:0 forHost:[[self class] host]]; - id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:kRequestSize - requestedResponseSize:kResponseSize]; - GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - options.transportType = [[self class] transportType]; - options.transport = [[self class] transport]; - options.PEMRootCertificates = [[self class] PEMRootCertificates]; - options.hostNameOverride = [[self class] hostNameOverride]; - options.keepaliveInterval = 1.5; - options.keepaliveTimeout = 0; + NSArray *requests = @[ @27182, @8 ]; + NSArray *responses = @[ @31415, @9 ]; - __block GRPCStreamingProtoCall *call = [_service - fullDuplexCallWithResponseHandler: - [[InteropTestsBlockCallbacks alloc] - initWithInitialMetadataCallback:nil - messageCallback:nil - closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { - XCTAssertNotNil(error); - XCTAssertEqual( - error.code, GRPC_STATUS_UNAVAILABLE, - @"Received status %ld instead of UNAVAILABLE (14).", - error.code); - [expectation fulfill]; - }] - callOptions:options]; - [call writeMessage:request]; - [call start]; + GRXBufferedPipe *requestsBuffer = [[GRXBufferedPipe alloc] init]; + + __block int index = 0; + + id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index] + requestedResponseSize:responses[index]]; + [requestsBuffer writeValue:request]; + + [_service + fullDuplexCallWithRequestsWriter:requestsBuffer + eventHandler:^(BOOL done, RMTStreamingOutputCallResponse *response, + NSError *error) { + if (index == 0) { + XCTAssertNil(error, @"Finished with unexpected error: %@", error); + XCTAssertTrue(response, @"Event handler called without an event."); + XCTAssertFalse(done); + index++; + } else { + // Keepalive should kick after 1s elapsed and fails the call. + XCTAssertNotNil(error); + XCTAssertEqual(error.code, GRPC_STATUS_UNAVAILABLE); + XCTAssertEqualObjects( + error.localizedDescription, @"keepalive watchdog timeout", + @"Unexpected failure that is not keepalive watchdog timeout."); + XCTAssertTrue(done); + [expectation fulfill]; + } + }]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; - [call finish]; } +#endif - (void)testDefaultInterceptor { XCTAssertNotNil([[self class] host]); @@ -1321,9 +1342,7 @@ static dispatch_once_t initGlobalInterceptorFactory; id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index] requestedResponseSize:responses[index]]; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - // For backwards compatibility options.transportType = [[self class] transportType]; - options.transport = [[self class] transport]; options.PEMRootCertificates = [[self class] PEMRootCertificates]; options.hostNameOverride = [[self class] hostNameOverride]; options.interceptorFactories = @[ [[DefaultInterceptorFactory alloc] init] ]; @@ -1378,7 +1397,8 @@ static dispatch_once_t initGlobalInterceptorFactory; __block NSUInteger responseCloseCount = 0; __block NSUInteger didWriteDataCount = 0; id<GRPCInterceptorFactory> factory = [[HookInterceptorFactory alloc] - initWithDispatchQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL) + initWithRequestDispatchQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL) + responseDispatchQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL) startHook:^(GRPCRequestOptions *requestOptions, GRPCCallOptions *callOptions, GRPCInterceptorManager *manager) { startCount++; @@ -1426,9 +1446,7 @@ static dispatch_once_t initGlobalInterceptorFactory; id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index] requestedResponseSize:responses[index]]; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - // For backwards compatibility options.transportType = [[self class] transportType]; - options.transport = [[self class] transport]; options.PEMRootCertificates = [[self class] PEMRootCertificates]; options.hostNameOverride = [[self class] hostNameOverride]; options.flowControlEnabled = YES; @@ -1506,7 +1524,8 @@ static dispatch_once_t initGlobalInterceptorFactory; __block NSUInteger responseDataCount = 0; __block NSUInteger responseCloseCount = 0; id<GRPCInterceptorFactory> factory = [[HookInterceptorFactory alloc] - initWithDispatchQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL) + initWithRequestDispatchQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL) + responseDispatchQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL) startHook:^(GRPCRequestOptions *requestOptions, GRPCCallOptions *callOptions, GRPCInterceptorManager *manager) { startCount++; @@ -1533,7 +1552,6 @@ static dispatch_once_t initGlobalInterceptorFactory; // finish must happen after the hijacking, so directly reply with a close [manager forwardPreviousInterceptorCloseWithTrailingMetadata:@{@"grpc-status" : @"0"} error:nil]; - [manager shutDown]; } receiveNextMessagesHook:nil responseHeaderHook:^(NSDictionary *initialMetadata, GRPCInterceptorManager *manager) { @@ -1560,9 +1578,7 @@ static dispatch_once_t initGlobalInterceptorFactory; id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index] requestedResponseSize:responses[index]]; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - // For backwards compatibility options.transportType = [[self class] transportType]; - options.transport = [[self class] transport]; options.PEMRootCertificates = [[self class] PEMRootCertificates]; options.hostNameOverride = [[self class] hostNameOverride]; options.interceptorFactories = @[ [[DefaultInterceptorFactory alloc] init], factory ]; @@ -1671,9 +1687,7 @@ static dispatch_once_t initGlobalInterceptorFactory; id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index] requestedResponseSize:responses[index]]; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - // For backwards compatibility options.transportType = [[self class] transportType]; - options.transport = [[self class] transport]; options.PEMRootCertificates = [[self class] PEMRootCertificates]; options.hostNameOverride = [[self class] hostNameOverride]; options.flowControlEnabled = YES; @@ -1728,15 +1742,16 @@ static dispatch_once_t initGlobalInterceptorFactory; - (void)testConflictingGlobalInterceptors { id<GRPCInterceptorFactory> factory = [[HookInterceptorFactory alloc] - initWithDispatchQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL) - startHook:nil - writeDataHook:nil - finishHook:nil - receiveNextMessagesHook:nil - responseHeaderHook:nil - responseDataHook:nil - responseCloseHook:nil - didWriteDataHook:nil]; + initWithRequestDispatchQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL) + responseDispatchQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL) + startHook:nil + writeDataHook:nil + finishHook:nil + receiveNextMessagesHook:nil + responseHeaderHook:nil + responseDataHook:nil + responseCloseHook:nil + didWriteDataHook:nil]; @try { [GRPCCall2 registerGlobalInterceptor:factory]; XCTFail(@"Did not receive an exception when registering global interceptor the second time"); @@ -1760,7 +1775,8 @@ static dispatch_once_t initGlobalInterceptorFactory; __block NSUInteger didWriteDataCount = 0; id<GRPCInterceptorFactory> factory = [[HookInterceptorFactory alloc] - initWithDispatchQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL) + initWithRequestDispatchQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL) + responseDispatchQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL) startHook:^(GRPCRequestOptions *requestOptions, GRPCCallOptions *callOptions, GRPCInterceptorManager *manager) { startCount++; @@ -1856,9 +1872,7 @@ static dispatch_once_t initGlobalInterceptorFactory; id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index] requestedResponseSize:responses[index]]; GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; - // For backwards compatibility options.transportType = [[self class] transportType]; - options.transport = [[self class] transport]; options.PEMRootCertificates = [[self class] PEMRootCertificates]; options.hostNameOverride = [[self class] hostNameOverride]; options.flowControlEnabled = YES; diff --git a/src/objective-c/tests/InteropTests/InteropTestsLocalCleartext.m b/src/objective-c/tests/InteropTests/InteropTestsLocalCleartext.m index 2e638099e1e7b2fe24133248da47afaede6a005c..a9c6918333229e261b3a57692dde6297ae604f92 100644 --- a/src/objective-c/tests/InteropTests/InteropTestsLocalCleartext.m +++ b/src/objective-c/tests/InteropTests/InteropTestsLocalCleartext.m @@ -17,7 +17,6 @@ */ #import <GRPCClient/GRPCCall+Tests.h> -#import <GRPCClient/GRPCTransport.h> #import <GRPCClient/internal_testing/GRPCCall+InternalTests.h> #import "InteropTests.h" @@ -61,8 +60,8 @@ static int32_t kLocalInteropServerOverhead = 10; [GRPCCall useInsecureConnectionsForHost:kLocalCleartextHost]; } -+ (GRPCTransportId)transport { - return GRPCDefaultTransportImplList.core_insecure; ++ (GRPCTransportType)transportType { + return GRPCTransportTypeInsecure; } @end diff --git a/src/objective-c/tests/InteropTests/InteropTestsLocalSSL.m b/src/objective-c/tests/InteropTests/InteropTestsLocalSSL.m index 30d8f4c34af0db6fd3127f9ec547904b32f2f19b..e8222f602f4a30510881925fc65442b7d59a14d0 100644 --- a/src/objective-c/tests/InteropTests/InteropTestsLocalSSL.m +++ b/src/objective-c/tests/InteropTests/InteropTestsLocalSSL.m @@ -17,7 +17,6 @@ */ #import <GRPCClient/GRPCCall+Tests.h> -#import <GRPCClient/GRPCTransport.h> #import <GRPCClient/internal_testing/GRPCCall+InternalTests.h> #import "InteropTests.h" @@ -57,8 +56,8 @@ static int32_t kLocalInteropServerOverhead = 10; return kLocalInteropServerOverhead; // bytes } -+ (GRPCTransportId)transport { - return GRPCDefaultTransportImplList.core_secure; ++ (GRPCTransportType)transportType { + return GRPCTransportTypeChttp2BoringSSL; } - (void)setUp { diff --git a/src/objective-c/tests/InteropTests/InteropTestsMultipleChannels.m b/src/objective-c/tests/InteropTests/InteropTestsMultipleChannels.m index dc48391cbccb9d2a56f364da070fcf82d158fa3d..98893a466bd8bead3015b232a1069af0bf94409c 100644 --- a/src/objective-c/tests/InteropTests/InteropTestsMultipleChannels.m +++ b/src/objective-c/tests/InteropTests/InteropTestsMultipleChannels.m @@ -18,8 +18,9 @@ #import <XCTest/XCTest.h> +#ifdef GRPC_COMPILE_WITH_CRONET #import <Cronet/Cronet.h> -#import <GRPCClient/GRPCCallOptions.h> +#endif #import <RxLibrary/GRXBufferedPipe.h> #import "src/objective-c/tests/RemoteTestClient/Messages.pbobjc.h" #import "src/objective-c/tests/RemoteTestClient/Test.pbobjc.h" diff --git a/src/objective-c/tests/InteropTests/InteropTestsRemote.m b/src/objective-c/tests/InteropTests/InteropTestsRemote.m index 2dd8f0aed89e7e3d2d01a2eb1e90d2f120c2c929..c1cd9b81efc7da2695b40c7916ac3b9cb7312aa2 100644 --- a/src/objective-c/tests/InteropTests/InteropTestsRemote.m +++ b/src/objective-c/tests/InteropTests/InteropTestsRemote.m @@ -53,8 +53,14 @@ static int32_t kRemoteInteropServerOverhead = 12; return kRemoteInteropServerOverhead; // bytes } +#ifdef GRPC_COMPILE_WITH_CRONET ++ (GRPCTransportType)transportType { + return GRPCTransportTypeCronet; +} +#else + (GRPCTransportType)transportType { return GRPCTransportTypeChttp2BoringSSL; } +#endif @end diff --git a/src/objective-c/tests/Podfile b/src/objective-c/tests/Podfile index c83e8861e933b40e09085e4fcaaef365ee815a7d..c2297aa00fdbbcabdcc52ccf827f53f1fb1618ca 100644 --- a/src/objective-c/tests/Podfile +++ b/src/objective-c/tests/Podfile @@ -30,23 +30,23 @@ target 'MacTests' do grpc_deps end +target 'UnitTests' do + platform :ios, '8.0' + grpc_deps +end + %w( - UnitTests InteropTests + CronetTests ).each do |target_name| target target_name do platform :ios, '8.0' grpc_deps - end -end -target 'CronetTests' do - platform :ios, '8.0' - grpc_deps - - pod 'gRPC/GRPCCoreCronet', :path => GRPC_LOCAL_SRC - pod 'CronetFramework', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c" - pod 'gRPC-Core/Tests', :path => GRPC_LOCAL_SRC, :inhibit_warnings => true + pod 'gRPC-Core/Cronet-Implementation', :path => GRPC_LOCAL_SRC + pod 'CronetFramework', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c" + pod 'gRPC-Core/Tests', :path => GRPC_LOCAL_SRC, :inhibit_warnings => true + end end # gRPC-Core.podspec needs to be modified to be successfully used for local development. A Podfile's @@ -103,7 +103,7 @@ post_install do |installer| # the test target 'InteropTestsRemoteWithCronet' # Activate GRPCCall+InternalTests functions for the dedicated build configuration 'Test', which will # be used by all test targets using it. - if /gRPC(-macOS|-iOS|-tvOS|\.|-[0-9a-f])/.match(target.name) + if /gRPC-(mac|i|tv)OS/.match(target.name) target.build_configurations.each do |config| if config.name == 'Cronet' config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = '$(inherited) COCOAPODS=1 GRPC_COMPILE_WITH_CRONET=1 GRPC_TEST_OBJC=1' @@ -114,7 +114,7 @@ post_install do |installer| end # Enable NSAssert on gRPC - if /(gRPC|ProtoRPC|RxLibrary)/.match(target.name) + if /(gRPC|ProtoRPC|RxLibrary)-(mac|i|tv)OS/.match(target.name) target.build_configurations.each do |config| if config.name != 'Release' config.build_settings['ENABLE_NS_ASSERTIONS'] = 'YES' diff --git a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj index 6cb9f5560b90e02679ffbdeecfb00450fd8244c0..a88838fdc8b779547e733eb3bd28221c044e3aa4 100644 --- a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj +++ b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj @@ -8,14 +8,15 @@ /* Begin PBXBuildFile section */ 5E0282E9215AA697007AC99D /* NSErrorUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E0282E8215AA697007AC99D /* NSErrorUnitTests.m */; }; - 5E08D07023021E3B006D76EA /* InteropTestsMultipleChannels.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7F487722778226006656AD /* InteropTestsMultipleChannels.m */; }; 5E3F14842278B461007C6D90 /* InteropTestsBlockCallbacks.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E3F14832278B461007C6D90 /* InteropTestsBlockCallbacks.m */; }; 5E3F14852278BF5D007C6D90 /* InteropTestsBlockCallbacks.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E3F14832278B461007C6D90 /* InteropTestsBlockCallbacks.m */; }; 5E3F14862278BFFF007C6D90 /* InteropTestsBlockCallbacks.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E3F14832278B461007C6D90 /* InteropTestsBlockCallbacks.m */; }; 5E3F148D22792856007C6D90 /* ConfigureCronet.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E3F1487227918AA007C6D90 /* ConfigureCronet.m */; }; + 5E3F148E22792AF5007C6D90 /* ConfigureCronet.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E3F1487227918AA007C6D90 /* ConfigureCronet.m */; }; 5E7F486422775B37006656AD /* InteropTestsRemoteWithCronet.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EE84BF31D4717E40050C6CC /* InteropTestsRemoteWithCronet.m */; }; 5E7F486522775B41006656AD /* CronetUnitTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5EAD6D261E27047400002378 /* CronetUnitTests.mm */; }; 5E7F486E22778086006656AD /* CoreCronetEnd2EndTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5E7F486D22778086006656AD /* CoreCronetEnd2EndTests.mm */; }; + 5E7F487922778226006656AD /* InteropTestsMultipleChannels.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7F487722778226006656AD /* InteropTestsMultipleChannels.m */; }; 5E7F487D22778256006656AD /* ChannelPoolTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7F487B22778256006656AD /* ChannelPoolTest.m */; }; 5E7F487E22778256006656AD /* ChannelTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7F487C22778256006656AD /* ChannelTests.m */; }; 5E7F4880227782C1006656AD /* APIv2Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7F487F227782C1006656AD /* APIv2Tests.m */; }; @@ -33,7 +34,6 @@ 5EA4770322736178000F72FC /* InteropTestsLocalSSL.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */; }; 5EA477042273617B000F72FC /* InteropTestsLocalCleartext.m in Sources */ = {isa = PBXBuildFile; fileRef = 63715F551B780C020029CB0B /* InteropTestsLocalCleartext.m */; }; 5EA4770522736AC4000F72FC /* TestCertificates.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */; }; - 5ECFED8623030DCC00626501 /* TestCertificates.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */; }; 65EB19E418B39A8374D407BB /* libPods-CronetTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1B1511C20E16A8422B58D61A /* libPods-CronetTests.a */; }; 903163C7FE885838580AEC7A /* libPods-InteropTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D457AD9797664CFA191C3280 /* libPods-InteropTests.a */; }; 953CD2942A3A6D6CE695BE87 /* libPods-MacTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 276873A05AC5479B60DF6079 /* libPods-MacTests.a */; }; @@ -515,6 +515,7 @@ 5EA476F12272816A000F72FC /* Frameworks */, 5EA476F22272816A000F72FC /* Resources */, D11CB94CF56A1E53760D29D8 /* [CP] Copy Pods Resources */, + 0FEFD5FC6B323AC95549AE4A /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -629,7 +630,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 5ECFED8623030DCC00626501 /* TestCertificates.bundle in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -678,6 +678,24 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + 0FEFD5FC6B323AC95549AE4A /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-InteropTests/Pods-InteropTests-frameworks.sh", + "${PODS_ROOT}/CronetFramework/Cronet.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cronet.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-InteropTests/Pods-InteropTests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; 292EA42A76AC7933A37235FD /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -703,7 +721,7 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-CronetTests/Pods-CronetTests-resources.sh", - "${PODS_CONFIGURATION_BUILD_DIR}/gRPC.default-GRPCCoreCronet/gRPCCertificates.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/gRPC-iOS/gRPCCertificates.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( @@ -880,7 +898,6 @@ files = ( 5E3F14852278BF5D007C6D90 /* InteropTestsBlockCallbacks.m in Sources */, 5E3F148D22792856007C6D90 /* ConfigureCronet.m in Sources */, - 5E08D07023021E3B006D76EA /* InteropTestsMultipleChannels.m in Sources */, 5E7F486E22778086006656AD /* CoreCronetEnd2EndTests.mm in Sources */, 5E7F488522778A88006656AD /* InteropTests.m in Sources */, 5E7F486422775B37006656AD /* InteropTestsRemoteWithCronet.m in Sources */, @@ -893,7 +910,9 @@ buildActionMask = 2147483647; files = ( 5E3F14842278B461007C6D90 /* InteropTestsBlockCallbacks.m in Sources */, + 5E3F148E22792AF5007C6D90 /* ConfigureCronet.m in Sources */, 5E7F488922778B04006656AD /* InteropTestsRemote.m in Sources */, + 5E7F487922778226006656AD /* InteropTestsMultipleChannels.m in Sources */, 5EA477042273617B000F72FC /* InteropTestsLocalCleartext.m in Sources */, 5EA4770322736178000F72FC /* InteropTestsLocalSSL.m in Sources */, 5E7F488422778A88006656AD /* InteropTests.m in Sources */, diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTests.xcscheme index cbde360a33810f31e00c97ab9a5a72b1b85ad5ff..adb3c366af2d06b46b474f7ccab2d8dc4e664ccb 100644 --- a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTests.xcscheme +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTests.xcscheme @@ -23,7 +23,7 @@ </BuildActionEntries> </BuildAction> <TestAction - buildConfiguration = "Test" + buildConfiguration = "Cronet" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> @@ -48,7 +48,7 @@ </AdditionalOptions> </TestAction> <LaunchAction - buildConfiguration = "Test" + buildConfiguration = "Cronet" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" launchStyle = "0" @@ -70,7 +70,7 @@ </AdditionalOptions> </LaunchAction> <ProfileAction - buildConfiguration = "Test" + buildConfiguration = "Release" shouldUseLaunchSchemeArgsEnv = "YES" savedToolIdentifier = "" useCustomWorkingDirectory = "NO" @@ -86,7 +86,7 @@ </MacroExpansion> </ProfileAction> <AnalyzeAction - buildConfiguration = "Test"> + buildConfiguration = "Cronet"> </AnalyzeAction> <ArchiveAction buildConfiguration = "Release" diff --git a/src/objective-c/tests/UnitTests/ChannelPoolTest.m b/src/objective-c/tests/UnitTests/ChannelPoolTest.m index 0b1eca389b93d65069d9febbbd50b1da2a3c99c2..eab8c5193fb9832bc2b109e1fb79673cfffbdd28 100644 --- a/src/objective-c/tests/UnitTests/ChannelPoolTest.m +++ b/src/objective-c/tests/UnitTests/ChannelPoolTest.m @@ -18,9 +18,9 @@ #import <XCTest/XCTest.h> -#import "../../GRPCClient/private/GRPCCore/GRPCChannel.h" -#import "../../GRPCClient/private/GRPCCore/GRPCChannelPool+Test.h" -#import "../../GRPCClient/private/GRPCCore/GRPCCompletionQueue.h" +#import "../../GRPCClient/private/GRPCChannel.h" +#import "../../GRPCClient/private/GRPCChannelPool+Test.h" +#import "../../GRPCClient/private/GRPCCompletionQueue.h" #define TEST_TIMEOUT 32 diff --git a/src/objective-c/tests/UnitTests/ChannelTests.m b/src/objective-c/tests/UnitTests/ChannelTests.m index 1ed0f16ecafb23643262ee2e2a29a1388908a79d..df78e8b11629a45f8f0c42423613326b2ab95d50 100644 --- a/src/objective-c/tests/UnitTests/ChannelTests.m +++ b/src/objective-c/tests/UnitTests/ChannelTests.m @@ -19,11 +19,11 @@ #import <XCTest/XCTest.h> #import "../../GRPCClient/GRPCCallOptions.h" -#import "../../GRPCClient/private/GRPCCore/GRPCChannel.h" -#import "../../GRPCClient/private/GRPCCore/GRPCChannelPool+Test.h" -#import "../../GRPCClient/private/GRPCCore/GRPCChannelPool.h" -#import "../../GRPCClient/private/GRPCCore/GRPCCompletionQueue.h" -#import "../../GRPCClient/private/GRPCCore/GRPCWrappedCall.h" +#import "../../GRPCClient/private/GRPCChannel.h" +#import "../../GRPCClient/private/GRPCChannelPool+Test.h" +#import "../../GRPCClient/private/GRPCChannelPool.h" +#import "../../GRPCClient/private/GRPCCompletionQueue.h" +#import "../../GRPCClient/private/GRPCWrappedCall.h" static NSString *kDummyHost = @"dummy.host"; static NSString *kDummyPath = @"/dummy/path"; diff --git a/src/objective-c/tests/UnitTests/NSErrorUnitTests.m b/src/objective-c/tests/UnitTests/NSErrorUnitTests.m index 74e5794c48006916d01fea14691451bd8179402c..8a4f03a44603b13e978355f0887f586ec7c61cc1 100644 --- a/src/objective-c/tests/UnitTests/NSErrorUnitTests.m +++ b/src/objective-c/tests/UnitTests/NSErrorUnitTests.m @@ -20,7 +20,7 @@ #import <GRPCClient/GRPCCall.h> -#import "../../GRPCClient/private/GRPCCore/NSError+GRPC.h" +#import "../../GRPCClient/private/NSError+GRPC.h" @interface NSErrorUnitTests : XCTestCase diff --git a/templates/gRPC-ProtoRPC.podspec.template b/templates/gRPC-ProtoRPC.podspec.template index e94f149ee4aa2cd8ea4ac411bbdf240b025bf6e5..457d2988036235c5bfc1adf3fcebc447941c0e00 100644 --- a/templates/gRPC-ProtoRPC.podspec.template +++ b/templates/gRPC-ProtoRPC.podspec.template @@ -44,40 +44,22 @@ s.module_name = name s.header_dir = name - s.default_subspec = 'Main', 'Legacy', 'Legacy-Header' + src_dir = 'src/objective-c/ProtoRPC' - s.subspec 'Legacy-Header' do |ss| - ss.header_mappings_dir = "src/objective-c/ProtoRPC" - ss.public_header_files = "src/objective-c/ProtoRPC/ProtoRPCLegacy.h" - ss.source_files = "src/objective-c/ProtoRPC/ProtoRPCLegacy.h" - end + s.default_subspec = 'Main' s.subspec 'Main' do |ss| - ss.header_mappings_dir = "src/objective-c/ProtoRPC" - ss.dependency "#{s.name}/Legacy-Header", version - ss.dependency 'gRPC/Interface', version - ss.dependency 'Protobuf', '~> 3.0' - - ss.source_files = "src/objective-c/ProtoRPC/ProtoMethod.{h,m}", - "src/objective-c/ProtoRPC/ProtoRPC.{h,m}", - "src/objective-c/ProtoRPC/ProtoService.{h,m}" - end - - s.subspec 'Legacy' do |ss| - ss.header_mappings_dir = "src/objective-c/ProtoRPC" - ss.dependency "#{s.name}/Main", version - ss.dependency "#{s.name}/Legacy-Header", version - ss.dependency 'gRPC/GRPCCore', version + ss.header_mappings_dir = "#{src_dir}" + ss.dependency 'gRPC', version ss.dependency 'gRPC-RxLibrary', version ss.dependency 'Protobuf', '~> 3.0' - ss.source_files = "src/objective-c/ProtoRPC/ProtoRPCLegacy.m", - "src/objective-c/ProtoRPC/ProtoServiceLegacy.m" + ss.source_files = "#{src_dir}/*.{h,m}" end # CFStream is now default. Leaving this subspec only for compatibility purpose. s.subspec 'CFStream' do |ss| - ss.dependency "#{s.name}/Legacy", version + ss.dependency "#{s.name}/Main", version end s.pod_target_xcconfig = { diff --git a/templates/gRPC-RxLibrary.podspec.template b/templates/gRPC-RxLibrary.podspec.template index 772265dadda134b481fd29c6fa4d0eb709db83a3..9389c5ecd8d2fe0d616c1463cac97866eda68fac 100644 --- a/templates/gRPC-RxLibrary.podspec.template +++ b/templates/gRPC-RxLibrary.podspec.template @@ -44,23 +44,6 @@ s.module_name = name s.header_dir = name - s.default_subspec = 'Interface', 'Implementation' - - src_dir = 'src/objective-c/RxLibrary' - s.subspec 'Interface' do |ss| - ss.header_mappings_dir = "#{src_dir}" - ss.source_files = "#{src_dir}/*.h" - ss.public_header_files = "#{src_dir}/*.h" - end - - s.subspec 'Implementation' do |ss| - ss.header_mappings_dir = "#{src_dir}" - ss.source_files = "#{src_dir}/*.m", "#{src_dir}/**/*.{h,m}" - ss.private_header_files = "#{src_dir}/**/*.h" - - ss.dependency "#{s.name}/Interface" - end - src_dir = 'src/objective-c/RxLibrary' s.source_files = "#{src_dir}/*.{h,m}", "#{src_dir}/**/*.{h,m}" s.private_header_files = "#{src_dir}/private/*.h" diff --git a/templates/gRPC.podspec.template b/templates/gRPC.podspec.template index e705edc1748acc256499e29e062677ff6c4390fd..8cb380ede03da2270b02ae0511dc63db58381021 100644 --- a/templates/gRPC.podspec.template +++ b/templates/gRPC.podspec.template @@ -43,7 +43,13 @@ s.module_name = name s.header_dir = name - s.default_subspec = 'Interface', 'GRPCCore', 'Interface-Legacy' + src_dir = 'src/objective-c/GRPCClient' + + s.dependency 'gRPC-RxLibrary', version + s.default_subspec = 'Main' + + # Certificates, to be able to establish TLS connections: + s.resource_bundles = { 'gRPCCertificates' => ['etc/roots.pem'] } s.pod_target_xcconfig = { # This is needed by all pods that depend on gRPC-RxLibrary: @@ -51,103 +57,29 @@ 'CLANG_WARN_STRICT_PROTOTYPES' => 'NO', } - s.subspec 'Interface-Legacy' do |ss| - ss.header_mappings_dir = 'src/objective-c/GRPCClient' - - ss.public_header_files = "GRPCClient/GRPCCall+ChannelArg.h", - "GRPCClient/GRPCCall+ChannelCredentials.h", - "GRPCClient/GRPCCall+Cronet.h", - "GRPCClient/GRPCCall+OAuth2.h", - "GRPCClient/GRPCCall+Tests.h", - "src/objective-c/GRPCClient/GRPCCallLegacy.h", - "src/objective-c/GRPCClient/GRPCTypes.h" - - ss.source_files = "GRPCClient/GRPCCall+ChannelArg.h", - "GRPCClient/GRPCCall+ChannelCredentials.h", - "GRPCClient/GRPCCall+Cronet.h", - "GRPCClient/GRPCCall+OAuth2.h", - "GRPCClient/GRPCCall+Tests.h", - "src/objective-c/GRPCClient/GRPCCallLegacy.h", - "src/objective-c/GRPCClient/GRPCTypes.h" - ss.dependency "gRPC-RxLibrary/Interface", version - end + s.subspec 'Main' do |ss| + ss.header_mappings_dir = "#{src_dir}" - s.subspec 'Interface' do |ss| - ss.header_mappings_dir = 'src/objective-c/GRPCClient' - - ss.public_header_files = 'src/objective-c/GRPCClient/GRPCCall.h', - 'src/objective-c/GRPCClient/GRPCCall+Interceptor.h', - 'src/objective-c/GRPCClient/GRPCCallOptions.h', - 'src/objective-c/GRPCClient/GRPCInterceptor.h', - 'src/objective-c/GRPCClient/GRPCTransport.h', - 'src/objective-c/GRPCClient/GRPCDispatchable.h', - 'src/objective-c/GRPCClient/version.h' - - ss.source_files = 'src/objective-c/GRPCClient/GRPCCall.h', - 'src/objective-c/GRPCClient/GRPCCall.m', - 'src/objective-c/GRPCClient/GRPCCall+Interceptor.h', - 'src/objective-c/GRPCClient/GRPCCall+Interceptor.m', - 'src/objective-c/GRPCClient/GRPCCallOptions.h', - 'src/objective-c/GRPCClient/GRPCCallOptions.m', - 'src/objective-c/GRPCClient/GRPCDispatchable.h', - 'src/objective-c/GRPCClient/GRPCInterceptor.h', - 'src/objective-c/GRPCClient/GRPCInterceptor.m', - 'src/objective-c/GRPCClient/GRPCTransport.h', - 'src/objective-c/GRPCClient/GRPCTransport.m', - 'src/objective-c/GRPCClient/internal/*.h', - 'src/objective-c/GRPCClient/private/GRPCTransport+Private.h', - 'src/objective-c/GRPCClient/private/GRPCTransport+Private.m', - 'src/objective-c/GRPCClient/version.h' - - ss.dependency "#{s.name}/Interface-Legacy", version - end + ss.source_files = "#{src_dir}/*.{h,m}", "#{src_dir}/**/*.{h,m}" + ss.exclude_files = "#{src_dir}/GRPCCall+GID.{h,m}" + ss.private_header_files = "#{src_dir}/private/*.h", "#{src_dir}/internal/*.h" - s.subspec 'GRPCCore' do |ss| - ss.header_mappings_dir = 'src/objective-c/GRPCClient' - - ss.public_header_files = 'src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h', - 'src/objective-c/GRPCClient/GRPCCall+Cronet.h', - 'src/objective-c/GRPCClient/GRPCCall+OAuth2.h', - 'src/objective-c/GRPCClient/GRPCCall+Tests.h', - 'src/objective-c/GRPCClient/GRPCCall+ChannelArg.h', - 'src/objective-c/GRPCClient/internal_testing/*.h' - ss.private_header_files = 'src/objective-c/GRPCClient/private/GRPCCore/*.h' - ss.source_files = 'src/objective-c/GRPCClient/internal_testing/*.{h,m}', - 'src/objective-c/GRPCClient/private/GRPCCore/*.{h,m}', - 'src/objective-c/GRPCClient/GRPCCall+ChannelArg.h', - 'src/objective-c/GRPCClient/GRPCCall+ChannelArg.m', - 'src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h', - 'src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.m', - 'src/objective-c/GRPCClient/GRPCCall+Cronet.h', - 'src/objective-c/GRPCClient/GRPCCall+Cronet.m', - 'src/objective-c/GRPCClient/GRPCCall+OAuth2.h', - 'src/objective-c/GRPCClient/GRPCCall+OAuth2.m', - 'src/objective-c/GRPCClient/GRPCCall+Tests.h', - 'src/objective-c/GRPCClient/GRPCCall+Tests.m', - 'src/objective-c/GRPCClient/GRPCCallLegacy.m' - - # Certificates, to be able to establish TLS connections: - ss.resource_bundles = { 'gRPCCertificates' => ['etc/roots.pem'] } - - ss.dependency "#{s.name}/Interface-Legacy", version - ss.dependency "#{s.name}/Interface", version ss.dependency 'gRPC-Core', version - ss.dependency 'gRPC-RxLibrary', version - end - - s.subspec 'GRPCCoreCronet' do |ss| - ss.header_mappings_dir = 'src/objective-c/GRPCClient' - - ss.source_files = 'src/objective-c/GRPCClient/GRPCCall+Cronet.h', - 'src/objective-c/GRPCClient/GRPCCall+Cronet.m', - 'src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/*.{h,m}' - ss.dependency "#{s.name}/GRPCCore", version - ss.dependency 'gRPC-Core/Cronet-Implementation', version - ss.dependency 'CronetFramework' end # CFStream is now default. Leaving this subspec only for compatibility purpose. s.subspec 'CFStream' do |ss| - ss.dependency "#{s.name}/GRPCCore", version + ss.dependency "#{s.name}/Main", version + end + + s.subspec 'GID' do |ss| + ss.ios.deployment_target = '7.0' + + ss.header_mappings_dir = "#{src_dir}" + + ss.source_files = "#{src_dir}/GRPCCall+GID.{h,m}" + + ss.dependency "#{s.name}/Main", version + ss.dependency 'Google/SignIn' end end diff --git a/templates/src/objective-c/GRPCClient/version.h.template b/templates/src/objective-c/GRPCClient/private/version.h.template similarity index 100% rename from templates/src/objective-c/GRPCClient/version.h.template rename to templates/src/objective-c/GRPCClient/private/version.h.template