mirror of https://github.com/grpc/grpc.git
Merge branch 'master' of https://github.com/grpc/grpc into fix-bazel-0.20
commit
dc4b538c4d
311 changed files with 6580 additions and 2399 deletions
@ -1,47 +1,60 @@ |
||||
workspace(name="com_github_grpc_grpc") |
||||
workspace(name = "com_github_grpc_grpc") |
||||
|
||||
load("//bazel:grpc_deps.bzl", "grpc_deps", "grpc_test_only_deps") |
||||
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") |
||||
|
||||
grpc_deps() |
||||
|
||||
grpc_test_only_deps() |
||||
|
||||
register_execution_platforms( |
||||
"//third_party/toolchains:all", |
||||
) |
||||
|
||||
register_toolchains( |
||||
"//third_party/toolchains:all", |
||||
) |
||||
|
||||
new_http_archive( |
||||
name="cython", |
||||
sha256="d68138a2381afbdd0876c3cb2a22389043fa01c4badede1228ee073032b07a27", |
||||
urls=[ |
||||
name = "cython", |
||||
build_file = "//third_party:cython.BUILD", |
||||
sha256 = "d68138a2381afbdd0876c3cb2a22389043fa01c4badede1228ee073032b07a27", |
||||
strip_prefix = "cython-c2b80d87658a8525ce091cbe146cb7eaa29fed5c", |
||||
urls = [ |
||||
"https://github.com/cython/cython/archive/c2b80d87658a8525ce091cbe146cb7eaa29fed5c.tar.gz", |
||||
], |
||||
strip_prefix="cython-c2b80d87658a8525ce091cbe146cb7eaa29fed5c", |
||||
build_file="//third_party:cython.BUILD", |
||||
) |
||||
|
||||
load("//third_party/py:python_configure.bzl", "python_configure") |
||||
python_configure(name="local_config_python") |
||||
|
||||
python_configure(name = "local_config_python") |
||||
|
||||
git_repository( |
||||
name="io_bazel_rules_python", |
||||
remote="https://github.com/bazelbuild/rules_python.git", |
||||
commit="8b5d0683a7d878b28fffe464779c8a53659fc645", |
||||
name = "io_bazel_rules_python", |
||||
commit = "8b5d0683a7d878b28fffe464779c8a53659fc645", |
||||
remote = "https://github.com/bazelbuild/rules_python.git", |
||||
) |
||||
|
||||
load("@io_bazel_rules_python//python:pip.bzl", "pip_repositories", "pip_import") |
||||
|
||||
pip_repositories() |
||||
|
||||
pip_import( |
||||
name="grpc_python_dependencies", |
||||
requirements="//:requirements.bazel.txt", |
||||
name = "grpc_python_dependencies", |
||||
requirements = "//:requirements.bazel.txt", |
||||
) |
||||
|
||||
load("@grpc_python_dependencies//:requirements.bzl", "pip_install") |
||||
|
||||
pip_install() |
||||
|
||||
# NOTE(https://github.com/pubref/rules_protobuf/pull/196): Switch to upstream repo after this gets merged. |
||||
git_repository( |
||||
name="org_pubref_rules_protobuf", |
||||
remote="https://github.com/ghostwriternr/rules_protobuf", |
||||
tag="v0.8.2.1-alpha", |
||||
name = "org_pubref_rules_protobuf", |
||||
remote = "https://github.com/ghostwriternr/rules_protobuf", |
||||
tag = "v0.8.2.1-alpha", |
||||
) |
||||
|
||||
load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_repositories") |
||||
|
||||
py_proto_repositories() |
||||
|
@ -0,0 +1,22 @@ |
||||
# gRPC Release Schedule |
||||
|
||||
Below is the release schedule for gRPC [Java](https://github.com/grpc/grpc-java/releases), [Go](https://github.com/grpc/grpc-go/releases) and [Core](https://github.com/grpc/grpc/releases) and its dependent languages C++, C#, Objective-C, PHP, Python and Ruby. |
||||
|
||||
Releases are scheduled every six weeks on Tuesdays on a best effort basis. In some unavoidable situations a release may be delayed or a language may skip a release altogether and do the next release to catch up with other languages. See the past releases in the links above. A six-week cycle gives us a good balance between delivering new features/fixes quickly and keeping the release overhead low. |
||||
|
||||
Releases are cut from release branches. For Core and Java repos, the release branch is cut two weeks before the scheduled release date. For Go, the branch is cut just before the release. An RC (release candidate) is published for Core and its dependent languages just after the branch cut. This RC is later promoted to release version if no further changes are made to the release branch. We do our best to keep head of master branch stable at all times regardless of release schedule. Daily build packages from master branch for C#, PHP, Python, Ruby and Protoc plugins are published on [packages.grpc.io](https://packages.grpc.io/). If you depend on gRPC in production we recommend to set up your CI system to test the RCs and, if possible, the daily builds. |
||||
|
||||
Names of gRPC releases are [here](https://github.com/grpc/grpc/blob/master/doc/g_stands_for.md). |
||||
|
||||
Release |Scheduled Branch Cut|Scheduled Release Date |
||||
--------|--------------------|------------- |
||||
v1.17.0 |Nov 19, 2018 |Dec 4, 2018 |
||||
v1.18.0 |Jan 2, 2019 |Jan 15, 2019 |
||||
v1.19.0 |Feb 12, 2019 |Feb 26, 2019 |
||||
v1.20.0 |Mar 26, 2019 |Apr 9, 2019 |
||||
v1.21.0 |May 7, 2019 |May 21, 2019 |
||||
v1.22.0 |Jun 18, 2019 |Jul 2, 2019 |
||||
v1.23.0 |Jul 30, 2019 |Aug 13, 2019 |
||||
v1.24.0 |Sept 10, 2019 |Sept 24, 2019 |
||||
v1.25.0 |Oct 22, 2019 |Nov 5, 2019 |
||||
v1.26.0 |Dec 3, 2019 |Dec 17, 2019 |
@ -0,0 +1,12 @@ |
||||
gRPC Channelz |
||||
==================== |
||||
|
||||
What is gRPC Channelz? |
||||
--------------------------------------------- |
||||
|
||||
Design Document `gRPC Channelz <https://github.com/grpc/proposal/blob/master/A14-channelz.md>`_ |
||||
|
||||
Module Contents |
||||
--------------- |
||||
|
||||
.. automodule:: grpc_channelz.v1.channelz |
@ -0,0 +1,66 @@ |
||||
Pod::Spec.new do |s| |
||||
s.name = "HelloWorld" |
||||
s.version = "0.0.1" |
||||
s.license = "Apache License, Version 2.0" |
||||
s.authors = { 'gRPC contributors' => 'grpc-io@googlegroups.com' } |
||||
s.homepage = "https://grpc.io/" |
||||
s.summary = "HelloWorld example" |
||||
s.source = { :git => 'https://github.com/grpc/grpc.git' } |
||||
|
||||
s.ios.deployment_target = "7.1" |
||||
s.osx.deployment_target = "10.9" |
||||
|
||||
# Base directory where the .proto files are. |
||||
src = "../../protos" |
||||
|
||||
# Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients. |
||||
s.dependency "!ProtoCompiler-gRPCPlugin", "~> 1.0" |
||||
|
||||
# Pods directory corresponding to this app's Podfile, relative to the location of this podspec. |
||||
pods_root = 'Pods' |
||||
|
||||
# Path where Cocoapods downloads protoc and the gRPC plugin. |
||||
protoc_dir = "#{pods_root}/!ProtoCompiler" |
||||
protoc = "#{protoc_dir}/protoc" |
||||
plugin = "#{pods_root}/!ProtoCompiler-gRPCPlugin/grpc_objective_c_plugin" |
||||
|
||||
# Directory where the generated files will be placed. |
||||
dir = "#{pods_root}/#{s.name}" |
||||
|
||||
s.prepare_command = <<-CMD |
||||
mkdir -p #{dir} |
||||
#{protoc} \ |
||||
--plugin=protoc-gen-grpc=#{plugin} \ |
||||
--objc_out=#{dir} \ |
||||
--grpc_out=#{dir} \ |
||||
-I #{src} \ |
||||
-I #{protoc_dir} \ |
||||
#{src}/helloworld.proto |
||||
CMD |
||||
|
||||
# Files generated by protoc |
||||
s.subspec "Messages" do |ms| |
||||
ms.source_files = "#{dir}/*.pbobjc.{h,m}", "#{dir}/**/*.pbobjc.{h,m}" |
||||
ms.header_mappings_dir = dir |
||||
ms.requires_arc = false |
||||
# The generated files depend on the protobuf runtime. |
||||
ms.dependency "Protobuf" |
||||
end |
||||
|
||||
# Files generated by the gRPC plugin |
||||
s.subspec "Services" do |ss| |
||||
ss.source_files = "#{dir}/*.pbrpc.{h,m}", "#{dir}/**/*.pbrpc.{h,m}" |
||||
ss.header_mappings_dir = dir |
||||
ss.requires_arc = true |
||||
# The generated files depend on the gRPC runtime, and on the files generated by protoc. |
||||
ss.dependency "gRPC-ProtoRPC" |
||||
ss.dependency "#{s.name}/Messages" |
||||
end |
||||
|
||||
s.pod_target_xcconfig = { |
||||
# This is needed by all pods that depend on Protobuf: |
||||
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1', |
||||
# This is needed by all pods that depend on gRPC-RxLibrary: |
||||
'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES', |
||||
} |
||||
end |
@ -0,0 +1,399 @@ |
||||
// !$*UTF8*$! |
||||
{ |
||||
archiveVersion = 1; |
||||
classes = { |
||||
}; |
||||
objectVersion = 50; |
||||
objects = { |
||||
|
||||
/* Begin PBXBuildFile section */ |
||||
5EF711A4215174880077496F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EF711A3215174880077496F /* AppDelegate.m */; }; |
||||
5EF711A7215174880077496F /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EF711A6215174880077496F /* ViewController.m */; }; |
||||
5EF711A9215174890077496F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5EF711A8215174890077496F /* Assets.xcassets */; }; |
||||
5EF711AC215174890077496F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5EF711AA215174890077496F /* Main.storyboard */; }; |
||||
5EF711AF215174890077496F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EF711AE215174890077496F /* main.m */; }; |
||||
827B966E84F6A63FD0F3F6BC /* libPods-HelloWorld.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 369D887F6054EBA486218C69 /* libPods-HelloWorld.a */; }; |
||||
/* End PBXBuildFile section */ |
||||
|
||||
/* Begin PBXFileReference section */ |
||||
2AAF8E8BA7DBFD2D3886AA25 /* Pods-HelloWorld.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld.release.xcconfig"; path = "Pods/Target Support Files/Pods-HelloWorld/Pods-HelloWorld.release.xcconfig"; sourceTree = "<group>"; }; |
||||
369D887F6054EBA486218C69 /* libPods-HelloWorld.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HelloWorld.a"; sourceTree = BUILT_PRODUCTS_DIR; }; |
||||
5EF7119F215174870077496F /* HelloWorld.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloWorld.app; sourceTree = BUILT_PRODUCTS_DIR; }; |
||||
5EF711A2215174880077496F /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; }; |
||||
5EF711A3215174880077496F /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; }; |
||||
5EF711A5215174880077496F /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; }; |
||||
5EF711A6215174880077496F /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; }; |
||||
5EF711A8215174890077496F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; |
||||
5EF711AB215174890077496F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; |
||||
5EF711AD215174890077496F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; |
||||
5EF711AE215174890077496F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; }; |
||||
5EF711B0215174890077496F /* HelloWorld.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = HelloWorld.entitlements; sourceTree = "<group>"; }; |
||||
CA4699782F6344C8E67C9FEE /* Pods-HelloWorld.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld.debug.xcconfig"; path = "Pods/Target Support Files/Pods-HelloWorld/Pods-HelloWorld.debug.xcconfig"; sourceTree = "<group>"; }; |
||||
/* End PBXFileReference section */ |
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */ |
||||
5EF7119C215174870077496F /* Frameworks */ = { |
||||
isa = PBXFrameworksBuildPhase; |
||||
buildActionMask = 2147483647; |
||||
files = ( |
||||
827B966E84F6A63FD0F3F6BC /* libPods-HelloWorld.a in Frameworks */, |
||||
); |
||||
runOnlyForDeploymentPostprocessing = 0; |
||||
}; |
||||
/* End PBXFrameworksBuildPhase section */ |
||||
|
||||
/* Begin PBXGroup section */ |
||||
5EF71196215174870077496F = { |
||||
isa = PBXGroup; |
||||
children = ( |
||||
5EF711AE215174890077496F /* main.m */, |
||||
5EF711A1215174870077496F /* HelloWorld */, |
||||
5EF711A0215174870077496F /* Products */, |
||||
8D3EFBB796129582177142C4 /* Pods */, |
||||
A986548CB5622AF6CC3ECCCE /* Frameworks */, |
||||
); |
||||
sourceTree = "<group>"; |
||||
}; |
||||
5EF711A0215174870077496F /* Products */ = { |
||||
isa = PBXGroup; |
||||
children = ( |
||||
5EF7119F215174870077496F /* HelloWorld.app */, |
||||
); |
||||
name = Products; |
||||
sourceTree = "<group>"; |
||||
}; |
||||
5EF711A1215174870077496F /* HelloWorld */ = { |
||||
isa = PBXGroup; |
||||
children = ( |
||||
5EF711A2215174880077496F /* AppDelegate.h */, |
||||
5EF711A3215174880077496F /* AppDelegate.m */, |
||||
5EF711A5215174880077496F /* ViewController.h */, |
||||
5EF711A6215174880077496F /* ViewController.m */, |
||||
5EF711A8215174890077496F /* Assets.xcassets */, |
||||
5EF711AA215174890077496F /* Main.storyboard */, |
||||
5EF711AD215174890077496F /* Info.plist */, |
||||
5EF711B0215174890077496F /* HelloWorld.entitlements */, |
||||
); |
||||
path = HelloWorld; |
||||
sourceTree = "<group>"; |
||||
}; |
||||
8D3EFBB796129582177142C4 /* Pods */ = { |
||||
isa = PBXGroup; |
||||
children = ( |
||||
CA4699782F6344C8E67C9FEE /* Pods-HelloWorld.debug.xcconfig */, |
||||
2AAF8E8BA7DBFD2D3886AA25 /* Pods-HelloWorld.release.xcconfig */, |
||||
); |
||||
name = Pods; |
||||
sourceTree = "<group>"; |
||||
}; |
||||
A986548CB5622AF6CC3ECCCE /* Frameworks */ = { |
||||
isa = PBXGroup; |
||||
children = ( |
||||
369D887F6054EBA486218C69 /* libPods-HelloWorld.a */, |
||||
); |
||||
name = Frameworks; |
||||
sourceTree = "<group>"; |
||||
}; |
||||
/* End PBXGroup section */ |
||||
|
||||
/* Begin PBXNativeTarget section */ |
||||
5EF7119E215174870077496F /* HelloWorld */ = { |
||||
isa = PBXNativeTarget; |
||||
buildConfigurationList = 5EF711B3215174890077496F /* Build configuration list for PBXNativeTarget "HelloWorld" */; |
||||
buildPhases = ( |
||||
3694AEA482289A5BDD5EA5A4 /* [CP] Check Pods Manifest.lock */, |
||||
5EF7119B215174870077496F /* Sources */, |
||||
5EF7119C215174870077496F /* Frameworks */, |
||||
5EF7119D215174870077496F /* Resources */, |
||||
DF5241368CCEAA9DC73E7EA8 /* [CP] Copy Pods Resources */, |
||||
); |
||||
buildRules = ( |
||||
); |
||||
dependencies = ( |
||||
); |
||||
name = HelloWorld; |
||||
productName = HelloWorld; |
||||
productReference = 5EF7119F215174870077496F /* HelloWorld.app */; |
||||
productType = "com.apple.product-type.application"; |
||||
}; |
||||
/* End PBXNativeTarget section */ |
||||
|
||||
/* Begin PBXProject section */ |
||||
5EF71197215174870077496F /* Project object */ = { |
||||
isa = PBXProject; |
||||
attributes = { |
||||
LastUpgradeCheck = 0930; |
||||
ORGANIZATIONNAME = gRPC; |
||||
TargetAttributes = { |
||||
5EF7119E215174870077496F = { |
||||
CreatedOnToolsVersion = 9.3; |
||||
SystemCapabilities = { |
||||
com.apple.Sandbox = { |
||||
enabled = 0; |
||||
}; |
||||
}; |
||||
}; |
||||
}; |
||||
}; |
||||
buildConfigurationList = 5EF7119A215174870077496F /* Build configuration list for PBXProject "HelloWorld" */; |
||||
compatibilityVersion = "Xcode 9.3"; |
||||
developmentRegion = en; |
||||
hasScannedForEncodings = 0; |
||||
knownRegions = ( |
||||
en, |
||||
Base, |
||||
); |
||||
mainGroup = 5EF71196215174870077496F; |
||||
productRefGroup = 5EF711A0215174870077496F /* Products */; |
||||
projectDirPath = ""; |
||||
projectRoot = ""; |
||||
targets = ( |
||||
5EF7119E215174870077496F /* HelloWorld */, |
||||
); |
||||
}; |
||||
/* End PBXProject section */ |
||||
|
||||
/* Begin PBXResourcesBuildPhase section */ |
||||
5EF7119D215174870077496F /* Resources */ = { |
||||
isa = PBXResourcesBuildPhase; |
||||
buildActionMask = 2147483647; |
||||
files = ( |
||||
5EF711A9215174890077496F /* Assets.xcassets in Resources */, |
||||
5EF711AC215174890077496F /* Main.storyboard in Resources */, |
||||
); |
||||
runOnlyForDeploymentPostprocessing = 0; |
||||
}; |
||||
/* End PBXResourcesBuildPhase section */ |
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */ |
||||
3694AEA482289A5BDD5EA5A4 /* [CP] Check Pods Manifest.lock */ = { |
||||
isa = PBXShellScriptBuildPhase; |
||||
buildActionMask = 2147483647; |
||||
files = ( |
||||
); |
||||
inputPaths = ( |
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock", |
||||
"${PODS_ROOT}/Manifest.lock", |
||||
); |
||||
name = "[CP] Check Pods Manifest.lock"; |
||||
outputPaths = ( |
||||
"$(DERIVED_FILE_DIR)/Pods-HelloWorld-checkManifestLockResult.txt", |
||||
); |
||||
runOnlyForDeploymentPostprocessing = 0; |
||||
shellPath = /bin/sh; |
||||
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; |
||||
}; |
||||
DF5241368CCEAA9DC73E7EA8 /* [CP] Copy Pods Resources */ = { |
||||
isa = PBXShellScriptBuildPhase; |
||||
buildActionMask = 2147483647; |
||||
files = ( |
||||
); |
||||
inputPaths = ( |
||||
"${SRCROOT}/Pods/Target Support Files/Pods-HelloWorld/Pods-HelloWorld-resources.sh", |
||||
"${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle", |
||||
); |
||||
name = "[CP] Copy Pods Resources"; |
||||
outputPaths = ( |
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle", |
||||
); |
||||
runOnlyForDeploymentPostprocessing = 0; |
||||
shellPath = /bin/sh; |
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-HelloWorld/Pods-HelloWorld-resources.sh\"\n"; |
||||
showEnvVarsInLog = 0; |
||||
}; |
||||
/* End PBXShellScriptBuildPhase section */ |
||||
|
||||
/* Begin PBXSourcesBuildPhase section */ |
||||
5EF7119B215174870077496F /* Sources */ = { |
||||
isa = PBXSourcesBuildPhase; |
||||
buildActionMask = 2147483647; |
||||
files = ( |
||||
5EF711A7215174880077496F /* ViewController.m in Sources */, |
||||
5EF711AF215174890077496F /* main.m in Sources */, |
||||
5EF711A4215174880077496F /* AppDelegate.m in Sources */, |
||||
); |
||||
runOnlyForDeploymentPostprocessing = 0; |
||||
}; |
||||
/* End PBXSourcesBuildPhase section */ |
||||
|
||||
/* Begin PBXVariantGroup section */ |
||||
5EF711AA215174890077496F /* Main.storyboard */ = { |
||||
isa = PBXVariantGroup; |
||||
children = ( |
||||
5EF711AB215174890077496F /* Base */, |
||||
); |
||||
name = Main.storyboard; |
||||
sourceTree = "<group>"; |
||||
}; |
||||
/* End PBXVariantGroup section */ |
||||
|
||||
/* Begin XCBuildConfiguration section */ |
||||
5EF711B1215174890077496F /* Debug */ = { |
||||
isa = XCBuildConfiguration; |
||||
buildSettings = { |
||||
ALWAYS_SEARCH_USER_PATHS = NO; |
||||
CLANG_ANALYZER_NONNULL = YES; |
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; |
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; |
||||
CLANG_CXX_LIBRARY = "libc++"; |
||||
CLANG_ENABLE_MODULES = YES; |
||||
CLANG_ENABLE_OBJC_ARC = YES; |
||||
CLANG_ENABLE_OBJC_WEAK = YES; |
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; |
||||
CLANG_WARN_BOOL_CONVERSION = YES; |
||||
CLANG_WARN_COMMA = YES; |
||||
CLANG_WARN_CONSTANT_CONVERSION = YES; |
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; |
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; |
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES; |
||||
CLANG_WARN_EMPTY_BODY = YES; |
||||
CLANG_WARN_ENUM_CONVERSION = YES; |
||||
CLANG_WARN_INFINITE_RECURSION = YES; |
||||
CLANG_WARN_INT_CONVERSION = YES; |
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; |
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; |
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; |
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; |
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; |
||||
CLANG_WARN_STRICT_PROTOTYPES = YES; |
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES; |
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; |
||||
CLANG_WARN_UNREACHABLE_CODE = YES; |
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; |
||||
CODE_SIGN_IDENTITY = "-"; |
||||
COPY_PHASE_STRIP = NO; |
||||
DEBUG_INFORMATION_FORMAT = dwarf; |
||||
ENABLE_STRICT_OBJC_MSGSEND = YES; |
||||
ENABLE_TESTABILITY = YES; |
||||
GCC_C_LANGUAGE_STANDARD = gnu11; |
||||
GCC_DYNAMIC_NO_PIC = NO; |
||||
GCC_NO_COMMON_BLOCKS = YES; |
||||
GCC_OPTIMIZATION_LEVEL = 0; |
||||
GCC_PREPROCESSOR_DEFINITIONS = ( |
||||
"DEBUG=1", |
||||
"$(inherited)", |
||||
); |
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; |
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; |
||||
GCC_WARN_UNDECLARED_SELECTOR = YES; |
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; |
||||
GCC_WARN_UNUSED_FUNCTION = YES; |
||||
GCC_WARN_UNUSED_VARIABLE = YES; |
||||
MACOSX_DEPLOYMENT_TARGET = 10.13; |
||||
MTL_ENABLE_DEBUG_INFO = YES; |
||||
ONLY_ACTIVE_ARCH = YES; |
||||
SDKROOT = macosx; |
||||
}; |
||||
name = Debug; |
||||
}; |
||||
5EF711B2215174890077496F /* Release */ = { |
||||
isa = XCBuildConfiguration; |
||||
buildSettings = { |
||||
ALWAYS_SEARCH_USER_PATHS = NO; |
||||
CLANG_ANALYZER_NONNULL = YES; |
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; |
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; |
||||
CLANG_CXX_LIBRARY = "libc++"; |
||||
CLANG_ENABLE_MODULES = YES; |
||||
CLANG_ENABLE_OBJC_ARC = YES; |
||||
CLANG_ENABLE_OBJC_WEAK = YES; |
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; |
||||
CLANG_WARN_BOOL_CONVERSION = YES; |
||||
CLANG_WARN_COMMA = YES; |
||||
CLANG_WARN_CONSTANT_CONVERSION = YES; |
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; |
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; |
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES; |
||||
CLANG_WARN_EMPTY_BODY = YES; |
||||
CLANG_WARN_ENUM_CONVERSION = YES; |
||||
CLANG_WARN_INFINITE_RECURSION = YES; |
||||
CLANG_WARN_INT_CONVERSION = YES; |
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; |
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; |
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; |
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; |
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; |
||||
CLANG_WARN_STRICT_PROTOTYPES = YES; |
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES; |
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; |
||||
CLANG_WARN_UNREACHABLE_CODE = YES; |
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; |
||||
CODE_SIGN_IDENTITY = "-"; |
||||
COPY_PHASE_STRIP = NO; |
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; |
||||
ENABLE_NS_ASSERTIONS = NO; |
||||
ENABLE_STRICT_OBJC_MSGSEND = YES; |
||||
GCC_C_LANGUAGE_STANDARD = gnu11; |
||||
GCC_NO_COMMON_BLOCKS = YES; |
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; |
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; |
||||
GCC_WARN_UNDECLARED_SELECTOR = YES; |
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; |
||||
GCC_WARN_UNUSED_FUNCTION = YES; |
||||
GCC_WARN_UNUSED_VARIABLE = YES; |
||||
MACOSX_DEPLOYMENT_TARGET = 10.13; |
||||
MTL_ENABLE_DEBUG_INFO = NO; |
||||
SDKROOT = macosx; |
||||
}; |
||||
name = Release; |
||||
}; |
||||
5EF711B4215174890077496F /* Debug */ = { |
||||
isa = XCBuildConfiguration; |
||||
baseConfigurationReference = CA4699782F6344C8E67C9FEE /* Pods-HelloWorld.debug.xcconfig */; |
||||
buildSettings = { |
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; |
||||
CODE_SIGN_STYLE = Automatic; |
||||
COMBINE_HIDPI_IMAGES = YES; |
||||
INFOPLIST_FILE = HelloWorld/Info.plist; |
||||
LD_RUNPATH_SEARCH_PATHS = ( |
||||
"$(inherited)", |
||||
"@executable_path/../Frameworks", |
||||
); |
||||
PRODUCT_BUNDLE_IDENTIFIER = io.grpc.HelloWorld; |
||||
PRODUCT_NAME = "$(TARGET_NAME)"; |
||||
}; |
||||
name = Debug; |
||||
}; |
||||
5EF711B5215174890077496F /* Release */ = { |
||||
isa = XCBuildConfiguration; |
||||
baseConfigurationReference = 2AAF8E8BA7DBFD2D3886AA25 /* Pods-HelloWorld.release.xcconfig */; |
||||
buildSettings = { |
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; |
||||
CODE_SIGN_STYLE = Automatic; |
||||
COMBINE_HIDPI_IMAGES = YES; |
||||
INFOPLIST_FILE = HelloWorld/Info.plist; |
||||
LD_RUNPATH_SEARCH_PATHS = ( |
||||
"$(inherited)", |
||||
"@executable_path/../Frameworks", |
||||
); |
||||
PRODUCT_BUNDLE_IDENTIFIER = io.grpc.HelloWorld; |
||||
PRODUCT_NAME = "$(TARGET_NAME)"; |
||||
}; |
||||
name = Release; |
||||
}; |
||||
/* End XCBuildConfiguration section */ |
||||
|
||||
/* Begin XCConfigurationList section */ |
||||
5EF7119A215174870077496F /* Build configuration list for PBXProject "HelloWorld" */ = { |
||||
isa = XCConfigurationList; |
||||
buildConfigurations = ( |
||||
5EF711B1215174890077496F /* Debug */, |
||||
5EF711B2215174890077496F /* Release */, |
||||
); |
||||
defaultConfigurationIsVisible = 0; |
||||
defaultConfigurationName = Release; |
||||
}; |
||||
5EF711B3215174890077496F /* Build configuration list for PBXNativeTarget "HelloWorld" */ = { |
||||
isa = XCConfigurationList; |
||||
buildConfigurations = ( |
||||
5EF711B4215174890077496F /* Debug */, |
||||
5EF711B5215174890077496F /* Release */, |
||||
); |
||||
defaultConfigurationIsVisible = 0; |
||||
defaultConfigurationName = Release; |
||||
}; |
||||
/* End XCConfigurationList section */ |
||||
}; |
||||
rootObject = 5EF71197215174870077496F /* Project object */; |
||||
} |
@ -0,0 +1,25 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 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 <Cocoa/Cocoa.h> |
||||
|
||||
@interface AppDelegate : NSObject <NSApplicationDelegate> |
||||
|
||||
|
||||
@end |
||||
|
@ -0,0 +1,58 @@ |
||||
{ |
||||
"images" : [ |
||||
{ |
||||
"idiom" : "mac", |
||||
"size" : "16x16", |
||||
"scale" : "1x" |
||||
}, |
||||
{ |
||||
"idiom" : "mac", |
||||
"size" : "16x16", |
||||
"scale" : "2x" |
||||
}, |
||||
{ |
||||
"idiom" : "mac", |
||||
"size" : "32x32", |
||||
"scale" : "1x" |
||||
}, |
||||
{ |
||||
"idiom" : "mac", |
||||
"size" : "32x32", |
||||
"scale" : "2x" |
||||
}, |
||||
{ |
||||
"idiom" : "mac", |
||||
"size" : "128x128", |
||||
"scale" : "1x" |
||||
}, |
||||
{ |
||||
"idiom" : "mac", |
||||
"size" : "128x128", |
||||
"scale" : "2x" |
||||
}, |
||||
{ |
||||
"idiom" : "mac", |
||||
"size" : "256x256", |
||||
"scale" : "1x" |
||||
}, |
||||
{ |
||||
"idiom" : "mac", |
||||
"size" : "256x256", |
||||
"scale" : "2x" |
||||
}, |
||||
{ |
||||
"idiom" : "mac", |
||||
"size" : "512x512", |
||||
"scale" : "1x" |
||||
}, |
||||
{ |
||||
"idiom" : "mac", |
||||
"size" : "512x512", |
||||
"scale" : "2x" |
||||
} |
||||
], |
||||
"info" : { |
||||
"version" : 1, |
||||
"author" : "xcode" |
||||
} |
||||
} |
@ -0,0 +1,6 @@ |
||||
{ |
||||
"info" : { |
||||
"version" : 1, |
||||
"author" : "xcode" |
||||
} |
||||
} |
@ -0,0 +1,717 @@ |
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="11134" systemVersion="15F34" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS"> |
||||
<dependencies> |
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11134"/> |
||||
</dependencies> |
||||
<scenes> |
||||
<!--Application--> |
||||
<scene sceneID="JPo-4y-FX3"> |
||||
<objects> |
||||
<application id="hnw-xV-0zn" sceneMemberID="viewController"> |
||||
<menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6"> |
||||
<items> |
||||
<menuItem title="HelloWorld" id="1Xt-HY-uBw"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<menu key="submenu" title="HelloWorld" systemMenu="apple" id="uQy-DD-JDr"> |
||||
<items> |
||||
<menuItem title="About HelloWorld" id="5kV-Vb-QxS"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="orderFrontStandardAboutPanel:" target="Ady-hI-5gd" id="Exp-CZ-Vem"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/> |
||||
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/> |
||||
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/> |
||||
<menuItem title="Services" id="NMo-om-nkz"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/> |
||||
</menuItem> |
||||
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/> |
||||
<menuItem title="Hide HelloWorld" keyEquivalent="h" id="Olw-nP-bQN"> |
||||
<connections> |
||||
<action selector="hide:" target="Ady-hI-5gd" id="PnN-Uc-m68"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO"> |
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> |
||||
<connections> |
||||
<action selector="hideOtherApplications:" target="Ady-hI-5gd" id="VT4-aY-XCT"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Show All" id="Kd2-mp-pUS"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="unhideAllApplications:" target="Ady-hI-5gd" id="Dhg-Le-xox"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/> |
||||
<menuItem title="Quit HelloWorld" keyEquivalent="q" id="4sb-4s-VLi"> |
||||
<connections> |
||||
<action selector="terminate:" target="Ady-hI-5gd" id="Te7-pn-YzF"/> |
||||
</connections> |
||||
</menuItem> |
||||
</items> |
||||
</menu> |
||||
</menuItem> |
||||
<menuItem title="File" id="dMs-cI-mzQ"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<menu key="submenu" title="File" id="bib-Uj-vzu"> |
||||
<items> |
||||
<menuItem title="New" keyEquivalent="n" id="Was-JA-tGl"> |
||||
<connections> |
||||
<action selector="newDocument:" target="Ady-hI-5gd" id="4Si-XN-c54"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Open…" keyEquivalent="o" id="IAo-SY-fd9"> |
||||
<connections> |
||||
<action selector="openDocument:" target="Ady-hI-5gd" id="bVn-NM-KNZ"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Open Recent" id="tXI-mr-wws"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="oas-Oc-fiZ"> |
||||
<items> |
||||
<menuItem title="Clear Menu" id="vNY-rz-j42"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="clearRecentDocuments:" target="Ady-hI-5gd" id="Daa-9d-B3U"/> |
||||
</connections> |
||||
</menuItem> |
||||
</items> |
||||
</menu> |
||||
</menuItem> |
||||
<menuItem isSeparatorItem="YES" id="m54-Is-iLE"/> |
||||
<menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG"> |
||||
<connections> |
||||
<action selector="performClose:" target="Ady-hI-5gd" id="HmO-Ls-i7Q"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Save…" keyEquivalent="s" id="pxx-59-PXV"> |
||||
<connections> |
||||
<action selector="saveDocument:" target="Ady-hI-5gd" id="teZ-XB-qJY"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Save As…" keyEquivalent="S" id="Bw7-FT-i3A"> |
||||
<connections> |
||||
<action selector="saveDocumentAs:" target="Ady-hI-5gd" id="mDf-zr-I0C"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Revert to Saved" keyEquivalent="r" id="KaW-ft-85H"> |
||||
<connections> |
||||
<action selector="revertDocumentToSaved:" target="Ady-hI-5gd" id="iJ3-Pv-kwq"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem isSeparatorItem="YES" id="aJh-i4-bef"/> |
||||
<menuItem title="Page Setup…" keyEquivalent="P" id="qIS-W8-SiK"> |
||||
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/> |
||||
<connections> |
||||
<action selector="runPageLayout:" target="Ady-hI-5gd" id="Din-rz-gC5"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Print…" keyEquivalent="p" id="aTl-1u-JFS"> |
||||
<connections> |
||||
<action selector="print:" target="Ady-hI-5gd" id="qaZ-4w-aoO"/> |
||||
</connections> |
||||
</menuItem> |
||||
</items> |
||||
</menu> |
||||
</menuItem> |
||||
<menuItem title="Edit" id="5QF-Oa-p0T"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<menu key="submenu" title="Edit" id="W48-6f-4Dl"> |
||||
<items> |
||||
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg"> |
||||
<connections> |
||||
<action selector="undo:" target="Ady-hI-5gd" id="M6e-cu-g7V"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam"> |
||||
<connections> |
||||
<action selector="redo:" target="Ady-hI-5gd" id="oIA-Rs-6OD"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/> |
||||
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG"> |
||||
<connections> |
||||
<action selector="cut:" target="Ady-hI-5gd" id="YJe-68-I9s"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU"> |
||||
<connections> |
||||
<action selector="copy:" target="Ady-hI-5gd" id="G1f-GL-Joy"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL"> |
||||
<connections> |
||||
<action selector="paste:" target="Ady-hI-5gd" id="UvS-8e-Qdg"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk"> |
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> |
||||
<connections> |
||||
<action selector="pasteAsPlainText:" target="Ady-hI-5gd" id="cEh-KX-wJQ"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Delete" id="pa3-QI-u2k"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="delete:" target="Ady-hI-5gd" id="0Mk-Ml-PaM"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m"> |
||||
<connections> |
||||
<action selector="selectAll:" target="Ady-hI-5gd" id="VNm-Mi-diN"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/> |
||||
<menuItem title="Find" id="4EN-yA-p0u"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<menu key="submenu" title="Find" id="1b7-l0-nxx"> |
||||
<items> |
||||
<menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W"> |
||||
<connections> |
||||
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="cD7-Qs-BN4"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz"> |
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> |
||||
<connections> |
||||
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="WD3-Gg-5AJ"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye"> |
||||
<connections> |
||||
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="NDo-RZ-v9R"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV"> |
||||
<connections> |
||||
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="HOh-sY-3ay"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt"> |
||||
<connections> |
||||
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="U76-nv-p5D"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd"> |
||||
<connections> |
||||
<action selector="centerSelectionInVisibleArea:" target="Ady-hI-5gd" id="IOG-6D-g5B"/> |
||||
</connections> |
||||
</menuItem> |
||||
</items> |
||||
</menu> |
||||
</menuItem> |
||||
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg"> |
||||
<items> |
||||
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI"> |
||||
<connections> |
||||
<action selector="showGuessPanel:" target="Ady-hI-5gd" id="vFj-Ks-hy3"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7"> |
||||
<connections> |
||||
<action selector="checkSpelling:" target="Ady-hI-5gd" id="fz7-VC-reM"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/> |
||||
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="toggleContinuousSpellChecking:" target="Ady-hI-5gd" id="7w6-Qz-0kB"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="toggleGrammarChecking:" target="Ady-hI-5gd" id="muD-Qn-j4w"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="toggleAutomaticSpellingCorrection:" target="Ady-hI-5gd" id="2lM-Qi-WAP"/> |
||||
</connections> |
||||
</menuItem> |
||||
</items> |
||||
</menu> |
||||
</menuItem> |
||||
<menuItem title="Substitutions" id="9ic-FL-obx"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr"> |
||||
<items> |
||||
<menuItem title="Show Substitutions" id="z6F-FW-3nz"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="orderFrontSubstitutionsPanel:" target="Ady-hI-5gd" id="oku-mr-iSq"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/> |
||||
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="toggleSmartInsertDelete:" target="Ady-hI-5gd" id="3IJ-Se-DZD"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Smart Quotes" id="hQb-2v-fYv"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="toggleAutomaticQuoteSubstitution:" target="Ady-hI-5gd" id="ptq-xd-QOA"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Smart Dashes" id="rgM-f4-ycn"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="toggleAutomaticDashSubstitution:" target="Ady-hI-5gd" id="oCt-pO-9gS"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Smart Links" id="cwL-P1-jid"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="toggleAutomaticLinkDetection:" target="Ady-hI-5gd" id="Gip-E3-Fov"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Data Detectors" id="tRr-pd-1PS"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="toggleAutomaticDataDetection:" target="Ady-hI-5gd" id="R1I-Nq-Kbl"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Text Replacement" id="HFQ-gK-NFA"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="toggleAutomaticTextReplacement:" target="Ady-hI-5gd" id="DvP-Fe-Py6"/> |
||||
</connections> |
||||
</menuItem> |
||||
</items> |
||||
</menu> |
||||
</menuItem> |
||||
<menuItem title="Transformations" id="2oI-Rn-ZJC"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<menu key="submenu" title="Transformations" id="c8a-y6-VQd"> |
||||
<items> |
||||
<menuItem title="Make Upper Case" id="vmV-6d-7jI"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="uppercaseWord:" target="Ady-hI-5gd" id="sPh-Tk-edu"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Make Lower Case" id="d9M-CD-aMd"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="lowercaseWord:" target="Ady-hI-5gd" id="iUZ-b5-hil"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Capitalize" id="UEZ-Bs-lqG"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="capitalizeWord:" target="Ady-hI-5gd" id="26H-TL-nsh"/> |
||||
</connections> |
||||
</menuItem> |
||||
</items> |
||||
</menu> |
||||
</menuItem> |
||||
<menuItem title="Speech" id="xrE-MZ-jX0"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<menu key="submenu" title="Speech" id="3rS-ZA-NoH"> |
||||
<items> |
||||
<menuItem title="Start Speaking" id="Ynk-f8-cLZ"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="startSpeaking:" target="Ady-hI-5gd" id="654-Ng-kyl"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Stop Speaking" id="Oyz-dy-DGm"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="stopSpeaking:" target="Ady-hI-5gd" id="dX8-6p-jy9"/> |
||||
</connections> |
||||
</menuItem> |
||||
</items> |
||||
</menu> |
||||
</menuItem> |
||||
</items> |
||||
</menu> |
||||
</menuItem> |
||||
<menuItem title="Format" id="jxT-CU-nIS"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<menu key="submenu" title="Format" id="GEO-Iw-cKr"> |
||||
<items> |
||||
<menuItem title="Font" id="Gi5-1S-RQB"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<menu key="submenu" title="Font" systemMenu="font" id="aXa-aM-Jaq"> |
||||
<items> |
||||
<menuItem title="Show Fonts" keyEquivalent="t" id="Q5e-8K-NDq"> |
||||
<connections> |
||||
<action selector="orderFrontFontPanel:" target="YLy-65-1bz" id="WHr-nq-2xA"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Bold" tag="2" keyEquivalent="b" id="GB9-OM-e27"> |
||||
<connections> |
||||
<action selector="addFontTrait:" target="YLy-65-1bz" id="hqk-hr-sYV"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Italic" tag="1" keyEquivalent="i" id="Vjx-xi-njq"> |
||||
<connections> |
||||
<action selector="addFontTrait:" target="YLy-65-1bz" id="IHV-OB-c03"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Underline" keyEquivalent="u" id="WRG-CD-K1S"> |
||||
<connections> |
||||
<action selector="underline:" target="Ady-hI-5gd" id="FYS-2b-JAY"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem isSeparatorItem="YES" id="5gT-KC-WSO"/> |
||||
<menuItem title="Bigger" tag="3" keyEquivalent="+" id="Ptp-SP-VEL"> |
||||
<connections> |
||||
<action selector="modifyFont:" target="YLy-65-1bz" id="Uc7-di-UnL"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Smaller" tag="4" keyEquivalent="-" id="i1d-Er-qST"> |
||||
<connections> |
||||
<action selector="modifyFont:" target="YLy-65-1bz" id="HcX-Lf-eNd"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem isSeparatorItem="YES" id="kx3-Dk-x3B"/> |
||||
<menuItem title="Kern" id="jBQ-r6-VK2"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<menu key="submenu" title="Kern" id="tlD-Oa-oAM"> |
||||
<items> |
||||
<menuItem title="Use Default" id="GUa-eO-cwY"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="useStandardKerning:" target="Ady-hI-5gd" id="6dk-9l-Ckg"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Use None" id="cDB-IK-hbR"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="turnOffKerning:" target="Ady-hI-5gd" id="U8a-gz-Maa"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Tighten" id="46P-cB-AYj"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="tightenKerning:" target="Ady-hI-5gd" id="hr7-Nz-8ro"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Loosen" id="ogc-rX-tC1"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="loosenKerning:" target="Ady-hI-5gd" id="8i4-f9-FKE"/> |
||||
</connections> |
||||
</menuItem> |
||||
</items> |
||||
</menu> |
||||
</menuItem> |
||||
<menuItem title="Ligatures" id="o6e-r0-MWq"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<menu key="submenu" title="Ligatures" id="w0m-vy-SC9"> |
||||
<items> |
||||
<menuItem title="Use Default" id="agt-UL-0e3"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="useStandardLigatures:" target="Ady-hI-5gd" id="7uR-wd-Dx6"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Use None" id="J7y-lM-qPV"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="turnOffLigatures:" target="Ady-hI-5gd" id="iX2-gA-Ilz"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Use All" id="xQD-1f-W4t"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="useAllLigatures:" target="Ady-hI-5gd" id="KcB-kA-TuK"/> |
||||
</connections> |
||||
</menuItem> |
||||
</items> |
||||
</menu> |
||||
</menuItem> |
||||
<menuItem title="Baseline" id="OaQ-X3-Vso"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<menu key="submenu" title="Baseline" id="ijk-EB-dga"> |
||||
<items> |
||||
<menuItem title="Use Default" id="3Om-Ey-2VK"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="unscript:" target="Ady-hI-5gd" id="0vZ-95-Ywn"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Superscript" id="Rqc-34-cIF"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="superscript:" target="Ady-hI-5gd" id="3qV-fo-wpU"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Subscript" id="I0S-gh-46l"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="subscript:" target="Ady-hI-5gd" id="Q6W-4W-IGz"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Raise" id="2h7-ER-AoG"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="raiseBaseline:" target="Ady-hI-5gd" id="4sk-31-7Q9"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Lower" id="1tx-W0-xDw"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="lowerBaseline:" target="Ady-hI-5gd" id="OF1-bc-KW4"/> |
||||
</connections> |
||||
</menuItem> |
||||
</items> |
||||
</menu> |
||||
</menuItem> |
||||
<menuItem isSeparatorItem="YES" id="Ndw-q3-faq"/> |
||||
<menuItem title="Show Colors" keyEquivalent="C" id="bgn-CT-cEk"> |
||||
<connections> |
||||
<action selector="orderFrontColorPanel:" target="Ady-hI-5gd" id="mSX-Xz-DV3"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem isSeparatorItem="YES" id="iMs-zA-UFJ"/> |
||||
<menuItem title="Copy Style" keyEquivalent="c" id="5Vv-lz-BsD"> |
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> |
||||
<connections> |
||||
<action selector="copyFont:" target="Ady-hI-5gd" id="GJO-xA-L4q"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Paste Style" keyEquivalent="v" id="vKC-jM-MkH"> |
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> |
||||
<connections> |
||||
<action selector="pasteFont:" target="Ady-hI-5gd" id="JfD-CL-leO"/> |
||||
</connections> |
||||
</menuItem> |
||||
</items> |
||||
</menu> |
||||
</menuItem> |
||||
<menuItem title="Text" id="Fal-I4-PZk"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<menu key="submenu" title="Text" id="d9c-me-L2H"> |
||||
<items> |
||||
<menuItem title="Align Left" keyEquivalent="{" id="ZM1-6Q-yy1"> |
||||
<connections> |
||||
<action selector="alignLeft:" target="Ady-hI-5gd" id="zUv-R1-uAa"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Center" keyEquivalent="|" id="VIY-Ag-zcb"> |
||||
<connections> |
||||
<action selector="alignCenter:" target="Ady-hI-5gd" id="spX-mk-kcS"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Justify" id="J5U-5w-g23"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="alignJustified:" target="Ady-hI-5gd" id="ljL-7U-jND"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Align Right" keyEquivalent="}" id="wb2-vD-lq4"> |
||||
<connections> |
||||
<action selector="alignRight:" target="Ady-hI-5gd" id="r48-bG-YeY"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem isSeparatorItem="YES" id="4s2-GY-VfK"/> |
||||
<menuItem title="Writing Direction" id="H1b-Si-o9J"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<menu key="submenu" title="Writing Direction" id="8mr-sm-Yjd"> |
||||
<items> |
||||
<menuItem title="Paragraph" enabled="NO" id="ZvO-Gk-QUH"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
</menuItem> |
||||
<menuItem id="YGs-j5-SAR"> |
||||
<string key="title"> Default</string> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="makeBaseWritingDirectionNatural:" target="Ady-hI-5gd" id="qtV-5e-UBP"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem id="Lbh-J2-qVU"> |
||||
<string key="title"> Left to Right</string> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="makeBaseWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="S0X-9S-QSf"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem id="jFq-tB-4Kx"> |
||||
<string key="title"> Right to Left</string> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="makeBaseWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="5fk-qB-AqJ"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem isSeparatorItem="YES" id="swp-gr-a21"/> |
||||
<menuItem title="Selection" enabled="NO" id="cqv-fj-IhA"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
</menuItem> |
||||
<menuItem id="Nop-cj-93Q"> |
||||
<string key="title"> Default</string> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="makeTextWritingDirectionNatural:" target="Ady-hI-5gd" id="lPI-Se-ZHp"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem id="BgM-ve-c93"> |
||||
<string key="title"> Left to Right</string> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="makeTextWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="caW-Bv-w94"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem id="RB4-Sm-HuC"> |
||||
<string key="title"> Right to Left</string> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="makeTextWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="EXD-6r-ZUu"/> |
||||
</connections> |
||||
</menuItem> |
||||
</items> |
||||
</menu> |
||||
</menuItem> |
||||
<menuItem isSeparatorItem="YES" id="fKy-g9-1gm"/> |
||||
<menuItem title="Show Ruler" id="vLm-3I-IUL"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="toggleRuler:" target="Ady-hI-5gd" id="FOx-HJ-KwY"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Copy Ruler" keyEquivalent="c" id="MkV-Pr-PK5"> |
||||
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/> |
||||
<connections> |
||||
<action selector="copyRuler:" target="Ady-hI-5gd" id="71i-fW-3W2"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Paste Ruler" keyEquivalent="v" id="LVM-kO-fVI"> |
||||
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/> |
||||
<connections> |
||||
<action selector="pasteRuler:" target="Ady-hI-5gd" id="cSh-wd-qM2"/> |
||||
</connections> |
||||
</menuItem> |
||||
</items> |
||||
</menu> |
||||
</menuItem> |
||||
</items> |
||||
</menu> |
||||
</menuItem> |
||||
<menuItem title="View" id="H8h-7b-M4v"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<menu key="submenu" title="View" id="HyV-fh-RgO"> |
||||
<items> |
||||
<menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5"> |
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> |
||||
<connections> |
||||
<action selector="toggleToolbarShown:" target="Ady-hI-5gd" id="BXY-wc-z0C"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Customize Toolbar…" id="1UK-8n-QPP"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="runToolbarCustomizationPalette:" target="Ady-hI-5gd" id="pQI-g3-MTW"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem isSeparatorItem="YES" id="hB3-LF-h0Y"/> |
||||
<menuItem title="Show Sidebar" keyEquivalent="s" id="kIP-vf-haE"> |
||||
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/> |
||||
<connections> |
||||
<action selector="toggleSourceList:" target="Ady-hI-5gd" id="iwa-gc-5KM"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa"> |
||||
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/> |
||||
<connections> |
||||
<action selector="toggleFullScreen:" target="Ady-hI-5gd" id="dU3-MA-1Rq"/> |
||||
</connections> |
||||
</menuItem> |
||||
</items> |
||||
</menu> |
||||
</menuItem> |
||||
<menuItem title="Window" id="aUF-d1-5bR"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo"> |
||||
<items> |
||||
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV"> |
||||
<connections> |
||||
<action selector="performMiniaturize:" target="Ady-hI-5gd" id="VwT-WD-YPe"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem title="Zoom" id="R4o-n2-Eq4"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="performZoom:" target="Ady-hI-5gd" id="DIl-cC-cCs"/> |
||||
</connections> |
||||
</menuItem> |
||||
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/> |
||||
<menuItem title="Bring All to Front" id="LE2-aR-0XJ"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<connections> |
||||
<action selector="arrangeInFront:" target="Ady-hI-5gd" id="DRN-fu-gQh"/> |
||||
</connections> |
||||
</menuItem> |
||||
</items> |
||||
</menu> |
||||
</menuItem> |
||||
<menuItem title="Help" id="wpr-3q-Mcd"> |
||||
<modifierMask key="keyEquivalentModifierMask"/> |
||||
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ"> |
||||
<items> |
||||
<menuItem title="HelloWorld Help" keyEquivalent="?" id="FKE-Sm-Kum"> |
||||
<connections> |
||||
<action selector="showHelp:" target="Ady-hI-5gd" id="y7X-2Q-9no"/> |
||||
</connections> |
||||
</menuItem> |
||||
</items> |
||||
</menu> |
||||
</menuItem> |
||||
</items> |
||||
</menu> |
||||
<connections> |
||||
<outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/> |
||||
</connections> |
||||
</application> |
||||
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModuleProvider=""/> |
||||
<customObject id="YLy-65-1bz" customClass="NSFontManager"/> |
||||
<customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> |
||||
</objects> |
||||
<point key="canvasLocation" x="75" y="0.0"/> |
||||
</scene> |
||||
<!--Window Controller--> |
||||
<scene sceneID="R2V-B0-nI4"> |
||||
<objects> |
||||
<windowController id="B8D-0N-5wS" sceneMemberID="viewController"> |
||||
<window key="window" title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="IQv-IB-iLA"> |
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/> |
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> |
||||
<rect key="contentRect" x="196" y="240" width="480" height="270"/> |
||||
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/> |
||||
<connections> |
||||
<outlet property="delegate" destination="B8D-0N-5wS" id="98r-iN-zZc"/> |
||||
</connections> |
||||
</window> |
||||
<connections> |
||||
<segue destination="XfG-lQ-9wD" kind="relationship" relationship="window.shadowedContentViewController" id="cq2-FE-JQM"/> |
||||
</connections> |
||||
</windowController> |
||||
<customObject id="Oky-zY-oP4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> |
||||
</objects> |
||||
<point key="canvasLocation" x="75" y="250"/> |
||||
</scene> |
||||
<!--View Controller--> |
||||
<scene sceneID="hIz-AP-VOD"> |
||||
<objects> |
||||
<viewController id="XfG-lQ-9wD" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController"> |
||||
<view key="view" wantsLayer="YES" id="m2S-Jp-Qdl"> |
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="270"/> |
||||
<autoresizingMask key="autoresizingMask"/> |
||||
</view> |
||||
</viewController> |
||||
<customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> |
||||
</objects> |
||||
<point key="canvasLocation" x="75" y="655"/> |
||||
</scene> |
||||
</scenes> |
||||
</document> |
@ -0,0 +1,5 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
||||
<plist version="1.0"> |
||||
<dict/> |
||||
</plist> |
@ -0,0 +1,32 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
||||
<plist version="1.0"> |
||||
<dict> |
||||
<key>CFBundleDevelopmentRegion</key> |
||||
<string>$(DEVELOPMENT_LANGUAGE)</string> |
||||
<key>CFBundleExecutable</key> |
||||
<string>$(EXECUTABLE_NAME)</string> |
||||
<key>CFBundleIconFile</key> |
||||
<string></string> |
||||
<key>CFBundleIdentifier</key> |
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> |
||||
<key>CFBundleInfoDictionaryVersion</key> |
||||
<string>6.0</string> |
||||
<key>CFBundleName</key> |
||||
<string>$(PRODUCT_NAME)</string> |
||||
<key>CFBundlePackageType</key> |
||||
<string>APPL</string> |
||||
<key>CFBundleShortVersionString</key> |
||||
<string>1.0</string> |
||||
<key>CFBundleVersion</key> |
||||
<string>1</string> |
||||
<key>LSMinimumSystemVersion</key> |
||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string> |
||||
<key>NSHumanReadableCopyright</key> |
||||
<string>Copyright © 2018 gRPC. All rights reserved.</string> |
||||
<key>NSMainStoryboardFile</key> |
||||
<string>Main</string> |
||||
<key>NSPrincipalClass</key> |
||||
<string>NSApplication</string> |
||||
</dict> |
||||
</plist> |
@ -0,0 +1,25 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 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 <Cocoa/Cocoa.h> |
||||
|
||||
@interface ViewController : NSViewController |
||||
|
||||
|
||||
@end |
||||
|
@ -0,0 +1,9 @@ |
||||
source 'https://github.com/CocoaPods/Specs.git' |
||||
platform :macos, '10.9' |
||||
|
||||
install! 'cocoapods', :deterministic_uuids => false |
||||
|
||||
target 'HelloWorld' do |
||||
# Depend on the generated HelloWorld library. |
||||
pod 'HelloWorld', :path => '.' |
||||
end |
@ -0,0 +1,6 @@ |
||||
# gRPC Objective-C Mac OS Hello World Example |
||||
|
||||
A hello world example app on Mac OS. Note that Mac OS is not a first class supported platform of gRPC |
||||
Objective-C library. This example is only for reference. |
||||
|
||||
Refer to [Hello World Example](../helloworld) for instructions on installation and running. |
@ -0,0 +1,43 @@ |
||||
/* |
||||
* |
||||
* Copyright 2018 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 <Cocoa/Cocoa.h> |
||||
|
||||
#import <GRPCClient/GRPCCall+ChannelArg.h> |
||||
#import <GRPCClient/GRPCCall+Tests.h> |
||||
#import <HelloWorld/Helloworld.pbrpc.h> |
||||
|
||||
static NSString * const kHostAddress = @"localhost:50051"; |
||||
|
||||
int main(int argc, const char * argv[]) { |
||||
@autoreleasepool { |
||||
[GRPCCall useInsecureConnectionsForHost:kHostAddress]; |
||||
[GRPCCall setUserAgentPrefix:@"HelloWorld/1.0" forHost:kHostAddress]; |
||||
|
||||
HLWGreeter *client = [[HLWGreeter alloc] initWithHost:kHostAddress]; |
||||
|
||||
HLWHelloRequest *request = [HLWHelloRequest message]; |
||||
request.name = @"Objective-C"; |
||||
|
||||
[client sayHelloWithRequest:request handler:^(HLWHelloReply *response, NSError *error) { |
||||
NSLog(@"%@", response.message); |
||||
}]; |
||||
} |
||||
|
||||
return NSApplicationMain(argc, argv); |
||||
} |
@ -1,178 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 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. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#include "src/core/ext/filters/client_channel/method_params.h" |
||||
#include "src/core/lib/channel/status_util.h" |
||||
#include "src/core/lib/gpr/string.h" |
||||
#include "src/core/lib/gprpp/memory.h" |
||||
|
||||
// As per the retry design, we do not allow more than 5 retry attempts.
|
||||
#define MAX_MAX_RETRY_ATTEMPTS 5 |
||||
|
||||
namespace grpc_core { |
||||
namespace internal { |
||||
|
||||
namespace { |
||||
|
||||
bool ParseWaitForReady( |
||||
grpc_json* field, ClientChannelMethodParams::WaitForReady* wait_for_ready) { |
||||
if (field->type != GRPC_JSON_TRUE && field->type != GRPC_JSON_FALSE) { |
||||
return false; |
||||
} |
||||
*wait_for_ready = field->type == GRPC_JSON_TRUE |
||||
? ClientChannelMethodParams::WAIT_FOR_READY_TRUE |
||||
: ClientChannelMethodParams::WAIT_FOR_READY_FALSE; |
||||
return true; |
||||
} |
||||
|
||||
// Parses a JSON field of the form generated for a google.proto.Duration
|
||||
// proto message, as per:
|
||||
// https://developers.google.com/protocol-buffers/docs/proto3#json
|
||||
bool ParseDuration(grpc_json* field, grpc_millis* duration) { |
||||
if (field->type != GRPC_JSON_STRING) return false; |
||||
size_t len = strlen(field->value); |
||||
if (field->value[len - 1] != 's') return false; |
||||
UniquePtr<char> buf(gpr_strdup(field->value)); |
||||
*(buf.get() + len - 1) = '\0'; // Remove trailing 's'.
|
||||
char* decimal_point = strchr(buf.get(), '.'); |
||||
int nanos = 0; |
||||
if (decimal_point != nullptr) { |
||||
*decimal_point = '\0'; |
||||
nanos = gpr_parse_nonnegative_int(decimal_point + 1); |
||||
if (nanos == -1) { |
||||
return false; |
||||
} |
||||
int num_digits = static_cast<int>(strlen(decimal_point + 1)); |
||||
if (num_digits > 9) { // We don't accept greater precision than nanos.
|
||||
return false; |
||||
} |
||||
for (int i = 0; i < (9 - num_digits); ++i) { |
||||
nanos *= 10; |
||||
} |
||||
} |
||||
int seconds = |
||||
decimal_point == buf.get() ? 0 : gpr_parse_nonnegative_int(buf.get()); |
||||
if (seconds == -1) return false; |
||||
*duration = seconds * GPR_MS_PER_SEC + nanos / GPR_NS_PER_MS; |
||||
return true; |
||||
} |
||||
|
||||
UniquePtr<ClientChannelMethodParams::RetryPolicy> ParseRetryPolicy( |
||||
grpc_json* field) { |
||||
auto retry_policy = MakeUnique<ClientChannelMethodParams::RetryPolicy>(); |
||||
if (field->type != GRPC_JSON_OBJECT) return nullptr; |
||||
for (grpc_json* sub_field = field->child; sub_field != nullptr; |
||||
sub_field = sub_field->next) { |
||||
if (sub_field->key == nullptr) return nullptr; |
||||
if (strcmp(sub_field->key, "maxAttempts") == 0) { |
||||
if (retry_policy->max_attempts != 0) return nullptr; // Duplicate.
|
||||
if (sub_field->type != GRPC_JSON_NUMBER) return nullptr; |
||||
retry_policy->max_attempts = gpr_parse_nonnegative_int(sub_field->value); |
||||
if (retry_policy->max_attempts <= 1) return nullptr; |
||||
if (retry_policy->max_attempts > MAX_MAX_RETRY_ATTEMPTS) { |
||||
gpr_log(GPR_ERROR, |
||||
"service config: clamped retryPolicy.maxAttempts at %d", |
||||
MAX_MAX_RETRY_ATTEMPTS); |
||||
retry_policy->max_attempts = MAX_MAX_RETRY_ATTEMPTS; |
||||
} |
||||
} else if (strcmp(sub_field->key, "initialBackoff") == 0) { |
||||
if (retry_policy->initial_backoff > 0) return nullptr; // Duplicate.
|
||||
if (!ParseDuration(sub_field, &retry_policy->initial_backoff)) { |
||||
return nullptr; |
||||
} |
||||
if (retry_policy->initial_backoff == 0) return nullptr; |
||||
} else if (strcmp(sub_field->key, "maxBackoff") == 0) { |
||||
if (retry_policy->max_backoff > 0) return nullptr; // Duplicate.
|
||||
if (!ParseDuration(sub_field, &retry_policy->max_backoff)) { |
||||
return nullptr; |
||||
} |
||||
if (retry_policy->max_backoff == 0) return nullptr; |
||||
} else if (strcmp(sub_field->key, "backoffMultiplier") == 0) { |
||||
if (retry_policy->backoff_multiplier != 0) return nullptr; // Duplicate.
|
||||
if (sub_field->type != GRPC_JSON_NUMBER) return nullptr; |
||||
if (sscanf(sub_field->value, "%f", &retry_policy->backoff_multiplier) != |
||||
1) { |
||||
return nullptr; |
||||
} |
||||
if (retry_policy->backoff_multiplier <= 0) return nullptr; |
||||
} else if (strcmp(sub_field->key, "retryableStatusCodes") == 0) { |
||||
if (!retry_policy->retryable_status_codes.Empty()) { |
||||
return nullptr; // Duplicate.
|
||||
} |
||||
if (sub_field->type != GRPC_JSON_ARRAY) return nullptr; |
||||
for (grpc_json* element = sub_field->child; element != nullptr; |
||||
element = element->next) { |
||||
if (element->type != GRPC_JSON_STRING) return nullptr; |
||||
grpc_status_code status; |
||||
if (!grpc_status_code_from_string(element->value, &status)) { |
||||
return nullptr; |
||||
} |
||||
retry_policy->retryable_status_codes.Add(status); |
||||
} |
||||
if (retry_policy->retryable_status_codes.Empty()) return nullptr; |
||||
} |
||||
} |
||||
// Make sure required fields are set.
|
||||
if (retry_policy->max_attempts == 0 || retry_policy->initial_backoff == 0 || |
||||
retry_policy->max_backoff == 0 || retry_policy->backoff_multiplier == 0 || |
||||
retry_policy->retryable_status_codes.Empty()) { |
||||
return nullptr; |
||||
} |
||||
return retry_policy; |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
RefCountedPtr<ClientChannelMethodParams> |
||||
ClientChannelMethodParams::CreateFromJson(const grpc_json* json) { |
||||
RefCountedPtr<ClientChannelMethodParams> method_params = |
||||
MakeRefCounted<ClientChannelMethodParams>(); |
||||
for (grpc_json* field = json->child; field != nullptr; field = field->next) { |
||||
if (field->key == nullptr) continue; |
||||
if (strcmp(field->key, "waitForReady") == 0) { |
||||
if (method_params->wait_for_ready_ != WAIT_FOR_READY_UNSET) { |
||||
return nullptr; // Duplicate.
|
||||
} |
||||
if (!ParseWaitForReady(field, &method_params->wait_for_ready_)) { |
||||
return nullptr; |
||||
} |
||||
} else if (strcmp(field->key, "timeout") == 0) { |
||||
if (method_params->timeout_ > 0) return nullptr; // Duplicate.
|
||||
if (!ParseDuration(field, &method_params->timeout_)) return nullptr; |
||||
} else if (strcmp(field->key, "retryPolicy") == 0) { |
||||
if (method_params->retry_policy_ != nullptr) { |
||||
return nullptr; // Duplicate.
|
||||
} |
||||
method_params->retry_policy_ = ParseRetryPolicy(field); |
||||
if (method_params->retry_policy_ == nullptr) return nullptr; |
||||
} |
||||
} |
||||
return method_params; |
||||
} |
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc_core
|
@ -1,78 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_METHOD_PARAMS_H |
||||
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_METHOD_PARAMS_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/channel/status_util.h" |
||||
#include "src/core/lib/gprpp/ref_counted.h" |
||||
#include "src/core/lib/gprpp/ref_counted_ptr.h" |
||||
#include "src/core/lib/iomgr/exec_ctx.h" // for grpc_millis |
||||
#include "src/core/lib/json/json.h" |
||||
|
||||
namespace grpc_core { |
||||
namespace internal { |
||||
|
||||
class ClientChannelMethodParams : public RefCounted<ClientChannelMethodParams> { |
||||
public: |
||||
enum WaitForReady { |
||||
WAIT_FOR_READY_UNSET = 0, |
||||
WAIT_FOR_READY_FALSE, |
||||
WAIT_FOR_READY_TRUE |
||||
}; |
||||
|
||||
struct RetryPolicy { |
||||
int max_attempts = 0; |
||||
grpc_millis initial_backoff = 0; |
||||
grpc_millis max_backoff = 0; |
||||
float backoff_multiplier = 0; |
||||
StatusCodeSet retryable_status_codes; |
||||
}; |
||||
|
||||
/// Creates a method_parameters object from \a json.
|
||||
/// Intended for use with ServiceConfig::CreateMethodConfigTable().
|
||||
static RefCountedPtr<ClientChannelMethodParams> CreateFromJson( |
||||
const grpc_json* json); |
||||
|
||||
grpc_millis timeout() const { return timeout_; } |
||||
WaitForReady wait_for_ready() const { return wait_for_ready_; } |
||||
const RetryPolicy* retry_policy() const { return retry_policy_.get(); } |
||||
|
||||
private: |
||||
// So New() can call our private ctor.
|
||||
template <typename T, typename... Args> |
||||
friend T* grpc_core::New(Args&&... args); |
||||
|
||||
// So Delete() can call our private dtor.
|
||||
template <typename T> |
||||
friend void grpc_core::Delete(T*); |
||||
|
||||
ClientChannelMethodParams() {} |
||||
virtual ~ClientChannelMethodParams() {} |
||||
|
||||
grpc_millis timeout_ = 0; |
||||
WaitForReady wait_for_ready_ = WAIT_FOR_READY_UNSET; |
||||
UniquePtr<RetryPolicy> retry_policy_; |
||||
}; |
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_METHOD_PARAMS_H */ |
@ -0,0 +1,384 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 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. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/ext/filters/client_channel/resolver_result_parsing.h" |
||||
|
||||
#include <ctype.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#include "src/core/ext/filters/client_channel/client_channel.h" |
||||
#include "src/core/ext/filters/client_channel/lb_policy_registry.h" |
||||
#include "src/core/lib/channel/status_util.h" |
||||
#include "src/core/lib/gpr/string.h" |
||||
#include "src/core/lib/gprpp/memory.h" |
||||
|
||||
// As per the retry design, we do not allow more than 5 retry attempts.
|
||||
#define MAX_MAX_RETRY_ATTEMPTS 5 |
||||
|
||||
namespace grpc_core { |
||||
namespace internal { |
||||
|
||||
namespace { |
||||
|
||||
// Converts string format from JSON to proto.
|
||||
grpc_core::UniquePtr<char> ConvertCamelToSnake(const char* camel) { |
||||
const size_t size = strlen(camel); |
||||
char* snake = static_cast<char*>(gpr_malloc(size * 2)); |
||||
size_t j = 0; |
||||
for (size_t i = 0; i < size; ++i) { |
||||
if (isupper(camel[i])) { |
||||
snake[j++] = '_'; |
||||
snake[j++] = tolower(camel[i]); |
||||
} else { |
||||
snake[j++] = camel[i]; |
||||
} |
||||
} |
||||
snake[j] = '\0'; |
||||
return grpc_core::UniquePtr<char>(snake); |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
ProcessedResolverResult::ProcessedResolverResult( |
||||
const grpc_channel_args* resolver_result, bool parse_retry) { |
||||
ProcessServiceConfig(resolver_result, parse_retry); |
||||
// If no LB config was found above, just find the LB policy name then.
|
||||
if (lb_policy_config_ == nullptr) ProcessLbPolicyName(resolver_result); |
||||
} |
||||
|
||||
void ProcessedResolverResult::ProcessServiceConfig( |
||||
const grpc_channel_args* resolver_result, bool parse_retry) { |
||||
const grpc_arg* channel_arg = |
||||
grpc_channel_args_find(resolver_result, GRPC_ARG_SERVICE_CONFIG); |
||||
const char* service_config_json = grpc_channel_arg_get_string(channel_arg); |
||||
if (service_config_json != nullptr) { |
||||
service_config_json_.reset(gpr_strdup(service_config_json)); |
||||
service_config_ = grpc_core::ServiceConfig::Create(service_config_json); |
||||
if (service_config_ != nullptr) { |
||||
if (parse_retry) { |
||||
channel_arg = |
||||
grpc_channel_args_find(resolver_result, GRPC_ARG_SERVER_URI); |
||||
const char* server_uri = grpc_channel_arg_get_string(channel_arg); |
||||
GPR_ASSERT(server_uri != nullptr); |
||||
grpc_uri* uri = grpc_uri_parse(server_uri, true); |
||||
GPR_ASSERT(uri->path[0] != '\0'); |
||||
server_name_ = uri->path[0] == '/' ? uri->path + 1 : uri->path; |
||||
service_config_->ParseGlobalParams(ParseServiceConfig, this); |
||||
grpc_uri_destroy(uri); |
||||
} else { |
||||
service_config_->ParseGlobalParams(ParseServiceConfig, this); |
||||
} |
||||
method_params_table_ = service_config_->CreateMethodConfigTable( |
||||
ClientChannelMethodParams::CreateFromJson); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void ProcessedResolverResult::ProcessLbPolicyName( |
||||
const grpc_channel_args* resolver_result) { |
||||
const char* lb_policy_name = nullptr; |
||||
// Prefer the LB policy name found in the service config. Note that this is
|
||||
// checking the deprecated loadBalancingPolicy field, rather than the new
|
||||
// loadBalancingConfig field.
|
||||
if (service_config_ != nullptr) { |
||||
lb_policy_name = service_config_->GetLoadBalancingPolicyName(); |
||||
} |
||||
// Otherwise, find the LB policy name set by the client API.
|
||||
if (lb_policy_name == nullptr) { |
||||
const grpc_arg* channel_arg = |
||||
grpc_channel_args_find(resolver_result, GRPC_ARG_LB_POLICY_NAME); |
||||
lb_policy_name = grpc_channel_arg_get_string(channel_arg); |
||||
} |
||||
// Special case: If at least one balancer address is present, we use
|
||||
// the grpclb policy, regardless of what the resolver has returned.
|
||||
const grpc_arg* channel_arg = |
||||
grpc_channel_args_find(resolver_result, GRPC_ARG_LB_ADDRESSES); |
||||
if (channel_arg != nullptr && channel_arg->type == GRPC_ARG_POINTER) { |
||||
grpc_lb_addresses* addresses = |
||||
static_cast<grpc_lb_addresses*>(channel_arg->value.pointer.p); |
||||
if (grpc_lb_addresses_contains_balancer_address(*addresses)) { |
||||
if (lb_policy_name != nullptr && |
||||
gpr_stricmp(lb_policy_name, "grpclb") != 0) { |
||||
gpr_log(GPR_INFO, |
||||
"resolver requested LB policy %s but provided at least one " |
||||
"balancer address -- forcing use of grpclb LB policy", |
||||
lb_policy_name); |
||||
} |
||||
lb_policy_name = "grpclb"; |
||||
} |
||||
} |
||||
// Use pick_first if nothing was specified and we didn't select grpclb
|
||||
// above.
|
||||
if (lb_policy_name == nullptr) lb_policy_name = "pick_first"; |
||||
lb_policy_name_.reset(gpr_strdup(lb_policy_name)); |
||||
} |
||||
|
||||
void ProcessedResolverResult::ParseServiceConfig( |
||||
const grpc_json* field, ProcessedResolverResult* parsing_state) { |
||||
parsing_state->ParseLbConfigFromServiceConfig(field); |
||||
if (parsing_state->server_name_ != nullptr) { |
||||
parsing_state->ParseRetryThrottleParamsFromServiceConfig(field); |
||||
} |
||||
} |
||||
|
||||
void ProcessedResolverResult::ParseLbConfigFromServiceConfig( |
||||
const grpc_json* field) { |
||||
if (lb_policy_config_ != nullptr) return; // Already found.
|
||||
// Find the LB config global parameter.
|
||||
if (field->key == nullptr || strcmp(field->key, "loadBalancingConfig") != 0 || |
||||
field->type != GRPC_JSON_ARRAY) { |
||||
return; // Not valid lb config array.
|
||||
} |
||||
// Find the first LB policy that this client supports.
|
||||
for (grpc_json* lb_config = field->child; lb_config != nullptr; |
||||
lb_config = lb_config->next) { |
||||
if (lb_config->type != GRPC_JSON_OBJECT) return; |
||||
// Find the policy object.
|
||||
grpc_json* policy = nullptr; |
||||
for (grpc_json* field = lb_config->child; field != nullptr; |
||||
field = field->next) { |
||||
if (field->key == nullptr || strcmp(field->key, "policy") != 0 || |
||||
field->type != GRPC_JSON_OBJECT) { |
||||
return; |
||||
} |
||||
if (policy != nullptr) return; // Duplicate.
|
||||
policy = field; |
||||
} |
||||
// Find the specific policy content since the policy object is of type
|
||||
// "oneof".
|
||||
grpc_json* policy_content = nullptr; |
||||
for (grpc_json* field = policy->child; field != nullptr; |
||||
field = field->next) { |
||||
if (field->key == nullptr || field->type != GRPC_JSON_OBJECT) return; |
||||
if (policy_content != nullptr) return; // Violate "oneof" type.
|
||||
policy_content = field; |
||||
} |
||||
grpc_core::UniquePtr<char> lb_policy_name = |
||||
ConvertCamelToSnake(policy_content->key); |
||||
if (!grpc_core::LoadBalancingPolicyRegistry::LoadBalancingPolicyExists( |
||||
lb_policy_name.get())) { |
||||
continue; |
||||
} |
||||
lb_policy_name_ = std::move(lb_policy_name); |
||||
lb_policy_config_ = policy_content->child; |
||||
return; |
||||
} |
||||
} |
||||
|
||||
void ProcessedResolverResult::ParseRetryThrottleParamsFromServiceConfig( |
||||
const grpc_json* field) { |
||||
if (strcmp(field->key, "retryThrottling") == 0) { |
||||
if (retry_throttle_data_ != nullptr) return; // Duplicate.
|
||||
if (field->type != GRPC_JSON_OBJECT) return; |
||||
int max_milli_tokens = 0; |
||||
int milli_token_ratio = 0; |
||||
for (grpc_json* sub_field = field->child; sub_field != nullptr; |
||||
sub_field = sub_field->next) { |
||||
if (sub_field->key == nullptr) return; |
||||
if (strcmp(sub_field->key, "maxTokens") == 0) { |
||||
if (max_milli_tokens != 0) return; // Duplicate.
|
||||
if (sub_field->type != GRPC_JSON_NUMBER) return; |
||||
max_milli_tokens = gpr_parse_nonnegative_int(sub_field->value); |
||||
if (max_milli_tokens == -1) return; |
||||
max_milli_tokens *= 1000; |
||||
} else if (strcmp(sub_field->key, "tokenRatio") == 0) { |
||||
if (milli_token_ratio != 0) return; // Duplicate.
|
||||
if (sub_field->type != GRPC_JSON_NUMBER) return; |
||||
// We support up to 3 decimal digits.
|
||||
size_t whole_len = strlen(sub_field->value); |
||||
uint32_t multiplier = 1; |
||||
uint32_t decimal_value = 0; |
||||
const char* decimal_point = strchr(sub_field->value, '.'); |
||||
if (decimal_point != nullptr) { |
||||
whole_len = static_cast<size_t>(decimal_point - sub_field->value); |
||||
multiplier = 1000; |
||||
size_t decimal_len = strlen(decimal_point + 1); |
||||
if (decimal_len > 3) decimal_len = 3; |
||||
if (!gpr_parse_bytes_to_uint32(decimal_point + 1, decimal_len, |
||||
&decimal_value)) { |
||||
return; |
||||
} |
||||
uint32_t decimal_multiplier = 1; |
||||
for (size_t i = 0; i < (3 - decimal_len); ++i) { |
||||
decimal_multiplier *= 10; |
||||
} |
||||
decimal_value *= decimal_multiplier; |
||||
} |
||||
uint32_t whole_value; |
||||
if (!gpr_parse_bytes_to_uint32(sub_field->value, whole_len, |
||||
&whole_value)) { |
||||
return; |
||||
} |
||||
milli_token_ratio = |
||||
static_cast<int>((whole_value * multiplier) + decimal_value); |
||||
if (milli_token_ratio <= 0) return; |
||||
} |
||||
} |
||||
retry_throttle_data_ = |
||||
grpc_core::internal::ServerRetryThrottleMap::GetDataForServer( |
||||
server_name_, max_milli_tokens, milli_token_ratio); |
||||
} |
||||
} |
||||
|
||||
namespace { |
||||
|
||||
bool ParseWaitForReady( |
||||
grpc_json* field, ClientChannelMethodParams::WaitForReady* wait_for_ready) { |
||||
if (field->type != GRPC_JSON_TRUE && field->type != GRPC_JSON_FALSE) { |
||||
return false; |
||||
} |
||||
*wait_for_ready = field->type == GRPC_JSON_TRUE |
||||
? ClientChannelMethodParams::WAIT_FOR_READY_TRUE |
||||
: ClientChannelMethodParams::WAIT_FOR_READY_FALSE; |
||||
return true; |
||||
} |
||||
|
||||
// Parses a JSON field of the form generated for a google.proto.Duration
|
||||
// proto message, as per:
|
||||
// https://developers.google.com/protocol-buffers/docs/proto3#json
|
||||
bool ParseDuration(grpc_json* field, grpc_millis* duration) { |
||||
if (field->type != GRPC_JSON_STRING) return false; |
||||
size_t len = strlen(field->value); |
||||
if (field->value[len - 1] != 's') return false; |
||||
UniquePtr<char> buf(gpr_strdup(field->value)); |
||||
*(buf.get() + len - 1) = '\0'; // Remove trailing 's'.
|
||||
char* decimal_point = strchr(buf.get(), '.'); |
||||
int nanos = 0; |
||||
if (decimal_point != nullptr) { |
||||
*decimal_point = '\0'; |
||||
nanos = gpr_parse_nonnegative_int(decimal_point + 1); |
||||
if (nanos == -1) { |
||||
return false; |
||||
} |
||||
int num_digits = static_cast<int>(strlen(decimal_point + 1)); |
||||
if (num_digits > 9) { // We don't accept greater precision than nanos.
|
||||
return false; |
||||
} |
||||
for (int i = 0; i < (9 - num_digits); ++i) { |
||||
nanos *= 10; |
||||
} |
||||
} |
||||
int seconds = |
||||
decimal_point == buf.get() ? 0 : gpr_parse_nonnegative_int(buf.get()); |
||||
if (seconds == -1) return false; |
||||
*duration = seconds * GPR_MS_PER_SEC + nanos / GPR_NS_PER_MS; |
||||
return true; |
||||
} |
||||
|
||||
UniquePtr<ClientChannelMethodParams::RetryPolicy> ParseRetryPolicy( |
||||
grpc_json* field) { |
||||
auto retry_policy = MakeUnique<ClientChannelMethodParams::RetryPolicy>(); |
||||
if (field->type != GRPC_JSON_OBJECT) return nullptr; |
||||
for (grpc_json* sub_field = field->child; sub_field != nullptr; |
||||
sub_field = sub_field->next) { |
||||
if (sub_field->key == nullptr) return nullptr; |
||||
if (strcmp(sub_field->key, "maxAttempts") == 0) { |
||||
if (retry_policy->max_attempts != 0) return nullptr; // Duplicate.
|
||||
if (sub_field->type != GRPC_JSON_NUMBER) return nullptr; |
||||
retry_policy->max_attempts = gpr_parse_nonnegative_int(sub_field->value); |
||||
if (retry_policy->max_attempts <= 1) return nullptr; |
||||
if (retry_policy->max_attempts > MAX_MAX_RETRY_ATTEMPTS) { |
||||
gpr_log(GPR_ERROR, |
||||
"service config: clamped retryPolicy.maxAttempts at %d", |
||||
MAX_MAX_RETRY_ATTEMPTS); |
||||
retry_policy->max_attempts = MAX_MAX_RETRY_ATTEMPTS; |
||||
} |
||||
} else if (strcmp(sub_field->key, "initialBackoff") == 0) { |
||||
if (retry_policy->initial_backoff > 0) return nullptr; // Duplicate.
|
||||
if (!ParseDuration(sub_field, &retry_policy->initial_backoff)) { |
||||
return nullptr; |
||||
} |
||||
if (retry_policy->initial_backoff == 0) return nullptr; |
||||
} else if (strcmp(sub_field->key, "maxBackoff") == 0) { |
||||
if (retry_policy->max_backoff > 0) return nullptr; // Duplicate.
|
||||
if (!ParseDuration(sub_field, &retry_policy->max_backoff)) { |
||||
return nullptr; |
||||
} |
||||
if (retry_policy->max_backoff == 0) return nullptr; |
||||
} else if (strcmp(sub_field->key, "backoffMultiplier") == 0) { |
||||
if (retry_policy->backoff_multiplier != 0) return nullptr; // Duplicate.
|
||||
if (sub_field->type != GRPC_JSON_NUMBER) return nullptr; |
||||
if (sscanf(sub_field->value, "%f", &retry_policy->backoff_multiplier) != |
||||
1) { |
||||
return nullptr; |
||||
} |
||||
if (retry_policy->backoff_multiplier <= 0) return nullptr; |
||||
} else if (strcmp(sub_field->key, "retryableStatusCodes") == 0) { |
||||
if (!retry_policy->retryable_status_codes.Empty()) { |
||||
return nullptr; // Duplicate.
|
||||
} |
||||
if (sub_field->type != GRPC_JSON_ARRAY) return nullptr; |
||||
for (grpc_json* element = sub_field->child; element != nullptr; |
||||
element = element->next) { |
||||
if (element->type != GRPC_JSON_STRING) return nullptr; |
||||
grpc_status_code status; |
||||
if (!grpc_status_code_from_string(element->value, &status)) { |
||||
return nullptr; |
||||
} |
||||
retry_policy->retryable_status_codes.Add(status); |
||||
} |
||||
if (retry_policy->retryable_status_codes.Empty()) return nullptr; |
||||
} |
||||
} |
||||
// Make sure required fields are set.
|
||||
if (retry_policy->max_attempts == 0 || retry_policy->initial_backoff == 0 || |
||||
retry_policy->max_backoff == 0 || retry_policy->backoff_multiplier == 0 || |
||||
retry_policy->retryable_status_codes.Empty()) { |
||||
return nullptr; |
||||
} |
||||
return retry_policy; |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
RefCountedPtr<ClientChannelMethodParams> |
||||
ClientChannelMethodParams::CreateFromJson(const grpc_json* json) { |
||||
RefCountedPtr<ClientChannelMethodParams> method_params = |
||||
MakeRefCounted<ClientChannelMethodParams>(); |
||||
for (grpc_json* field = json->child; field != nullptr; field = field->next) { |
||||
if (field->key == nullptr) continue; |
||||
if (strcmp(field->key, "waitForReady") == 0) { |
||||
if (method_params->wait_for_ready_ != WAIT_FOR_READY_UNSET) { |
||||
return nullptr; // Duplicate.
|
||||
} |
||||
if (!ParseWaitForReady(field, &method_params->wait_for_ready_)) { |
||||
return nullptr; |
||||
} |
||||
} else if (strcmp(field->key, "timeout") == 0) { |
||||
if (method_params->timeout_ > 0) return nullptr; // Duplicate.
|
||||
if (!ParseDuration(field, &method_params->timeout_)) return nullptr; |
||||
} else if (strcmp(field->key, "retryPolicy") == 0) { |
||||
if (method_params->retry_policy_ != nullptr) { |
||||
return nullptr; // Duplicate.
|
||||
} |
||||
method_params->retry_policy_ = ParseRetryPolicy(field); |
||||
if (method_params->retry_policy_ == nullptr) return nullptr; |
||||
} |
||||
} |
||||
return method_params; |
||||
} |
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc_core
|
@ -0,0 +1,146 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_RESULT_PARSING_H |
||||
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_RESULT_PARSING_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/ext/filters/client_channel/retry_throttle.h" |
||||
#include "src/core/lib/channel/status_util.h" |
||||
#include "src/core/lib/gprpp/ref_counted.h" |
||||
#include "src/core/lib/gprpp/ref_counted_ptr.h" |
||||
#include "src/core/lib/iomgr/exec_ctx.h" // for grpc_millis |
||||
#include "src/core/lib/json/json.h" |
||||
#include "src/core/lib/slice/slice_hash_table.h" |
||||
#include "src/core/lib/transport/service_config.h" |
||||
|
||||
namespace grpc_core { |
||||
namespace internal { |
||||
|
||||
class ClientChannelMethodParams; |
||||
|
||||
// A table mapping from a method name to its method parameters.
|
||||
typedef grpc_core::SliceHashTable< |
||||
grpc_core::RefCountedPtr<ClientChannelMethodParams>> |
||||
ClientChannelMethodParamsTable; |
||||
|
||||
// A container of processed fields from the resolver result. Simplifies the
|
||||
// usage of resolver result.
|
||||
class ProcessedResolverResult { |
||||
public: |
||||
// Processes the resolver result and populates the relative members
|
||||
// for later consumption. Tries to parse retry parameters only if parse_retry
|
||||
// is true.
|
||||
ProcessedResolverResult(const grpc_channel_args* resolver_result, |
||||
bool parse_retry); |
||||
|
||||
// Getters. Any managed object's ownership is transferred.
|
||||
grpc_core::UniquePtr<char> service_config_json() { |
||||
return std::move(service_config_json_); |
||||
} |
||||
grpc_core::RefCountedPtr<ServerRetryThrottleData> retry_throttle_data() { |
||||
return std::move(retry_throttle_data_); |
||||
} |
||||
grpc_core::RefCountedPtr<ClientChannelMethodParamsTable> |
||||
method_params_table() { |
||||
return std::move(method_params_table_); |
||||
} |
||||
grpc_core::UniquePtr<char> lb_policy_name() { |
||||
return std::move(lb_policy_name_); |
||||
} |
||||
grpc_json* lb_policy_config() { return lb_policy_config_; } |
||||
|
||||
private: |
||||
// Finds the service config; extracts LB config and (maybe) retry throttle
|
||||
// params from it.
|
||||
void ProcessServiceConfig(const grpc_channel_args* resolver_result, |
||||
bool parse_retry); |
||||
|
||||
// Finds the LB policy name (when no LB config was found).
|
||||
void ProcessLbPolicyName(const grpc_channel_args* resolver_result); |
||||
|
||||
// Parses the service config. Intended to be used by
|
||||
// ServiceConfig::ParseGlobalParams.
|
||||
static void ParseServiceConfig(const grpc_json* field, |
||||
ProcessedResolverResult* parsing_state); |
||||
// Parses the LB config from service config.
|
||||
void ParseLbConfigFromServiceConfig(const grpc_json* field); |
||||
// Parses the retry throttle parameters from service config.
|
||||
void ParseRetryThrottleParamsFromServiceConfig(const grpc_json* field); |
||||
|
||||
// Service config.
|
||||
grpc_core::UniquePtr<char> service_config_json_; |
||||
grpc_core::UniquePtr<grpc_core::ServiceConfig> service_config_; |
||||
// LB policy.
|
||||
grpc_json* lb_policy_config_ = nullptr; |
||||
grpc_core::UniquePtr<char> lb_policy_name_; |
||||
// Retry throttle data.
|
||||
char* server_name_ = nullptr; |
||||
grpc_core::RefCountedPtr<ServerRetryThrottleData> retry_throttle_data_; |
||||
// Method params table.
|
||||
grpc_core::RefCountedPtr<ClientChannelMethodParamsTable> method_params_table_; |
||||
}; |
||||
|
||||
// The parameters of a method.
|
||||
class ClientChannelMethodParams : public RefCounted<ClientChannelMethodParams> { |
||||
public: |
||||
enum WaitForReady { |
||||
WAIT_FOR_READY_UNSET = 0, |
||||
WAIT_FOR_READY_FALSE, |
||||
WAIT_FOR_READY_TRUE |
||||
}; |
||||
|
||||
struct RetryPolicy { |
||||
int max_attempts = 0; |
||||
grpc_millis initial_backoff = 0; |
||||
grpc_millis max_backoff = 0; |
||||
float backoff_multiplier = 0; |
||||
StatusCodeSet retryable_status_codes; |
||||
}; |
||||
|
||||
/// Creates a method_parameters object from \a json.
|
||||
/// Intended for use with ServiceConfig::CreateMethodConfigTable().
|
||||
static RefCountedPtr<ClientChannelMethodParams> CreateFromJson( |
||||
const grpc_json* json); |
||||
|
||||
grpc_millis timeout() const { return timeout_; } |
||||
WaitForReady wait_for_ready() const { return wait_for_ready_; } |
||||
const RetryPolicy* retry_policy() const { return retry_policy_.get(); } |
||||
|
||||
private: |
||||
// So New() can call our private ctor.
|
||||
template <typename T, typename... Args> |
||||
friend T* grpc_core::New(Args&&... args); |
||||
|
||||
// So Delete() can call our private dtor.
|
||||
template <typename T> |
||||
friend void grpc_core::Delete(T*); |
||||
|
||||
ClientChannelMethodParams() {} |
||||
virtual ~ClientChannelMethodParams() {} |
||||
|
||||
grpc_millis timeout_ = 0; |
||||
WaitForReady wait_for_ready_ = WAIT_FOR_READY_UNSET; |
||||
UniquePtr<RetryPolicy> retry_policy_; |
||||
}; |
||||
|
||||
} // namespace internal
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_RESULT_PARSING_H */ |
@ -0,0 +1,51 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 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. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/ext/transport/chttp2/transport/context_list.h" |
||||
|
||||
namespace { |
||||
void (*write_timestamps_callback_g)(void*, grpc_core::Timestamps*) = nullptr; |
||||
} |
||||
|
||||
namespace grpc_core { |
||||
void ContextList::Execute(void* arg, grpc_core::Timestamps* ts, |
||||
grpc_error* error) { |
||||
ContextList* head = static_cast<ContextList*>(arg); |
||||
ContextList* to_be_freed; |
||||
while (head != nullptr) { |
||||
if (error == GRPC_ERROR_NONE && ts != nullptr) { |
||||
if (write_timestamps_callback_g) { |
||||
ts->byte_offset = static_cast<uint32_t>(head->byte_offset_); |
||||
write_timestamps_callback_g(head->s_->context, ts); |
||||
} |
||||
} |
||||
GRPC_CHTTP2_STREAM_UNREF(static_cast<grpc_chttp2_stream*>(head->s_), |
||||
"timestamp"); |
||||
to_be_freed = head; |
||||
head = head->next_; |
||||
grpc_core::Delete(to_be_freed); |
||||
} |
||||
} |
||||
|
||||
void grpc_http2_set_write_timestamps_callback( |
||||
void (*fn)(void*, grpc_core::Timestamps*)) { |
||||
write_timestamps_callback_g = fn; |
||||
} |
||||
} /* namespace grpc_core */ |
@ -0,0 +1,72 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_CONTEXT_LIST_H |
||||
#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_CONTEXT_LIST_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/iomgr/buffer_list.h" |
||||
|
||||
#include "src/core/ext/transport/chttp2/transport/internal.h" |
||||
|
||||
namespace grpc_core { |
||||
/** A list of RPC Contexts */ |
||||
class ContextList { |
||||
public: |
||||
/* Creates a new element with \a context as the value and appends it to the
|
||||
* list. */ |
||||
static void Append(ContextList** head, grpc_chttp2_stream* s) { |
||||
/* Make sure context is not already present */ |
||||
GRPC_CHTTP2_STREAM_REF(s, "timestamp"); |
||||
|
||||
#ifndef NDEBUG |
||||
ContextList* ptr = *head; |
||||
while (ptr != nullptr) { |
||||
if (ptr->s_ == s) { |
||||
GPR_ASSERT( |
||||
false && |
||||
"Trying to append a stream that is already present in the list"); |
||||
} |
||||
ptr = ptr->next_; |
||||
} |
||||
#endif |
||||
|
||||
/* Create a new element in the list and add it at the front */ |
||||
ContextList* elem = grpc_core::New<ContextList>(); |
||||
elem->s_ = s; |
||||
elem->byte_offset_ = s->byte_counter; |
||||
elem->next_ = *head; |
||||
*head = elem; |
||||
} |
||||
|
||||
/* Executes a function \a fn with each context in the list and \a ts. It also
|
||||
* frees up the entire list after this operation. */ |
||||
static void Execute(void* arg, grpc_core::Timestamps* ts, grpc_error* error); |
||||
|
||||
private: |
||||
grpc_chttp2_stream* s_ = nullptr; |
||||
ContextList* next_ = nullptr; |
||||
size_t byte_offset_ = 0; |
||||
}; |
||||
|
||||
void grpc_http2_set_write_timestamps_callback( |
||||
void (*fn)(void*, grpc_core::Timestamps*)); |
||||
} /* namespace grpc_core */ |
||||
|
||||
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_CONTEXT_LIST_H */ |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue