mirror of https://github.com/grpc/grpc.git
Merge branch 'master' of https://github.com/grpc/grpc into what-the-fuzz
commit
18c71117b0
2741 changed files with 133422 additions and 61906 deletions
@ -1,32 +1,70 @@ |
||||
git: |
||||
depth: 1 |
||||
language: objective-c |
||||
osx_image: xcode7.2 |
||||
osx_image: xcode7.3 |
||||
env: |
||||
global: |
||||
- CONFIG=opt |
||||
- TEST=objc |
||||
- JOBS=1 |
||||
matrix: |
||||
- SCHEME="RxLibraryUnitTests" |
||||
WORKSPACE="Tests.xcworkspace" TEST_PATH="src/objective-c/tests" BUILD_ONLY="false" |
||||
INTEROP_SERVER="false" |
||||
- SCHEME="InteropTestsLocalSSL" |
||||
WORKSPACE="Tests.xcworkspace" TEST_PATH="src/objective-c/tests" BUILD_ONLY="false" |
||||
INTEROP_SERVER="true" |
||||
- SCHEME="InteropTestsLocalCleartext" |
||||
WORKSPACE="Tests.xcworkspace" TEST_PATH="src/objective-c/tests" BUILD_ONLY="false" |
||||
INTEROP_SERVER="true" |
||||
# TODO(jcanizales): Make tests an app project (instead of library), so the following will work. |
||||
# - SCHEME="InteropTestsRemote" |
||||
# WORKSPACE="Tests.xcworkspace" TEST_PATH="src/objective-c/tests" BUILD_ONLY="false" |
||||
# INTEROP_SERVER="true" |
||||
- SCHEME="HelloWorld" |
||||
WORKSPACE="HelloWorld.xcworkspace" TEST_PATH="examples/objective-c/helloworld" |
||||
BUILD_ONLY="true" INTEROP_SERVER="false" |
||||
- SCHEME="RouteGuideClient" |
||||
WORKSPACE="RouteGuideClient.xcworkspace" TEST_PATH="examples/objective-c/route_guide" |
||||
BUILD_ONLY="true" INTEROP_SERVER="false" |
||||
- SCHEME="AuthSample" |
||||
WORKSPACE="AuthSample.xcworkspace" TEST_PATH="examples/objective-c/auth_sample" |
||||
BUILD_ONLY="true" INTEROP_SERVER="false" |
||||
- SCHEME="Sample" |
||||
WORKSPACE="Sample.xcworkspace" TEST_PATH="src/objective-c/examples/Sample" BUILD_ONLY="true" |
||||
INTEROP_SERVER="false" |
||||
- SCHEME="Sample" |
||||
WORKSPACE="Sample.xcworkspace" TEST_PATH="src/objective-c/examples/Sample" BUILD_ONLY="true" |
||||
INTEROP_SERVER="false" FRAMEWORKS="YES" |
||||
- SCHEME="SwiftSample" |
||||
WORKSPACE="SwiftSample.xcworkspace" TEST_PATH="src/objective-c/examples/SwiftSample" |
||||
BUILD_ONLY="true" INTEROP_SERVER="false" |
||||
before_install: |
||||
# Until Travis upgrades from Cocoapods 0.39, we need to do it here. |
||||
- pod --version |
||||
- gem uninstall cocoapods -a |
||||
- gem install cocoapods -v '1.0.1' |
||||
- pod --version |
||||
# Recent pods aren't found if we don't explicitly update Cocoapods' repo. |
||||
- pod repo update |
||||
- brew install gflags |
||||
# Pod install does this too, but we don't want the output. |
||||
- pod repo update --silent |
||||
install: |
||||
- make grpc_objective_c_plugin |
||||
- pushd src/objective-c/tests |
||||
# Needs to be verbose, or otherwise OpenSSL's prepare_command makes Travis |
||||
# time out: |
||||
- pod install --verbose |
||||
- pushd $TEST_PATH |
||||
- pod install |
||||
- popd |
||||
before_script: |
||||
- make interop_server |
||||
- bins/$CONFIG/interop_server --port=5050 & |
||||
- bins/$CONFIG/interop_server --port=5051 --use_tls & |
||||
xcode_workspace: src/objective-c/tests/Tests.xcworkspace |
||||
xcode_scheme: |
||||
- RxLibraryUnitTests |
||||
- InteropTestsLocalSSL |
||||
- InteropTestsLocalCleartext |
||||
# TODO(jcanizales): Investigate why they time out: |
||||
# - InteropTestsRemote |
||||
xcode_sdk: iphonesimulator9.2 |
||||
- if [ "${INTEROP_SERVER}" = "true" ]; then |
||||
make interop_server; |
||||
(bins/$CONFIG/interop_server --port=5050 &); |
||||
(bins/$CONFIG/interop_server --port=5051 --use_tls &); |
||||
fi |
||||
script: |
||||
- if [ "${BUILD_ONLY}" = "true" ]; then |
||||
xctool -workspace "$TEST_PATH/$WORKSPACE" -scheme "$SCHEME" |
||||
-sdk iphonesimulator9.3 build; |
||||
else |
||||
xctool -workspace "$TEST_PATH/$WORKSPACE" -scheme "$SCHEME" |
||||
-sdk iphonesimulator9.3 test; |
||||
fi |
||||
notifications: |
||||
email: false |
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,2 @@ |
||||
build/ |
||||
src/ |
@ -0,0 +1,88 @@ |
||||
# gRPC command line tool |
||||
|
||||
## Overview |
||||
|
||||
This document describes the command line tool that comes with gRPC repository. It is desireable to have command line |
||||
tools written in other languages to roughly follow the same syntax and flags. |
||||
|
||||
At this point, the tool needs to be built from source, and it should be moved out to grpc-tools repository as a stand |
||||
alone application once it is mature enough. |
||||
|
||||
## Core functionality |
||||
|
||||
The command line tool can do the following things: |
||||
|
||||
- Send unary rpc. |
||||
- Attach metadata and display received metadata. |
||||
- Handle common authentication to server. |
||||
- Infer request/response types from server reflection result. |
||||
- Find the request/response types from a given proto file. |
||||
- Read proto request in text form. |
||||
- Read request in wire form (for protobuf messages, this means serialized binary form). |
||||
- Display proto response in text form. |
||||
- Write response in wire form to a file. |
||||
|
||||
The command line tool should support the following things: |
||||
|
||||
- List server services and methods through server reflection. |
||||
- Fine-grained auth control (such as, use this oauth token to talk to the server). |
||||
- Send streaming rpc. |
||||
|
||||
## Code location |
||||
|
||||
To use the tool, you need to get the grpc repository and in the grpc directory execute |
||||
|
||||
``` |
||||
$ make grpc_cli |
||||
``` |
||||
|
||||
The main file can be found at |
||||
https://github.com/grpc/grpc/blob/master/test/cpp/util/grpc_cli.cc |
||||
|
||||
## Usage |
||||
|
||||
### Basic usage |
||||
|
||||
Send a rpc to a helloworld server at `localhost:50051`: |
||||
|
||||
``` |
||||
$ bins/opt/grpc_cli call localhost:50051 SayHello "name: 'world'" \ |
||||
--enable_ssl=false |
||||
``` |
||||
|
||||
On success, the tool will print out |
||||
|
||||
``` |
||||
Rpc succeeded with OK status |
||||
Response: |
||||
message: "Hello world" |
||||
``` |
||||
|
||||
The `localhost:50051` part indicates the server you are connecting to. `SayHello` is (part of) the |
||||
gRPC method string. Then `"name: 'world'"` is the text format of the request proto message. We are |
||||
not using ssl here by `--enable_ssl=false`. For information on more flags, look at the comments of `grpc_cli.cc`. |
||||
|
||||
### Use local proto files |
||||
|
||||
If the server does not have the server reflection service, you will need to provide local proto |
||||
files containing the service definition. The tool will try to find request/response types from |
||||
them. |
||||
|
||||
``` |
||||
$ bins/opt/grpc_cli call localhost:50051 SayHello "name: 'world'" \ |
||||
--protofiles=examples/protos/helloworld.proto --enable_ssl=false |
||||
``` |
||||
|
||||
If the proto files is not under current directory, you can use `--proto_path` to specify a new |
||||
search root. |
||||
|
||||
### Send non-proto rpc |
||||
|
||||
For using gRPC with protocols other than probobuf, you will need the exact method name string |
||||
and a file containing the raw bytes to be sent on the wire |
||||
|
||||
``` |
||||
$ bins/opt/grpc_cli call localhost:50051 /helloworld.Greeter/SayHello --input_binary_file=input.bin \ |
||||
--output_binary_file=output.bin |
||||
``` |
||||
On success, you will need to read or decode the response from the `output.bin` file. |
@ -0,0 +1,118 @@ |
||||
## **gRPC Compression** |
||||
|
||||
The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", |
||||
"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be |
||||
interpreted as described in [RFC 2119](http://www.ietf.org/rfc/rfc2119.txt). |
||||
|
||||
### Intent |
||||
|
||||
Compression is used to reduce the amount of bandwidth used between peers. The |
||||
compression supported by gRPC acts _at the individual message level_, taking |
||||
_message_ [as defined in the wire format |
||||
document](PROTOCOL-HTTP2.md). |
||||
|
||||
The implementation supports different compression algorithms. A _default |
||||
compression level_, to be used in the absence of message-specific settings, MAY |
||||
be specified for during channel creation. |
||||
|
||||
The ability to control compression settings per call and to enable/disable |
||||
compression on a per message basis MAY be used to prevent CRIME/BEAST attacks. |
||||
It also allows for asymmetric compression communication, whereby a response MAY |
||||
be compressed differently, if at all. |
||||
|
||||
### Specification |
||||
|
||||
Compression MAY be configured by the Client Application by calling the |
||||
appropriate API method. There are two scenarios where compression MAY be |
||||
configured: |
||||
|
||||
+ At channel creation time, which sets the channel default compression and |
||||
therefore the compression that SHALL be used in the absence of per-RPC |
||||
compression configuration. |
||||
+ At response time, via: |
||||
+ For unary RPCs, the {Client,Server}Context instance. |
||||
+ For streaming RPCs, the {Client,Server}Writer instance. In this case, |
||||
configuration is reduced to disabling compression altogether. |
||||
|
||||
### Compression Method Asymmetry Between Peers |
||||
|
||||
A gRPC peer MAY choose to respond using a different compression method to that |
||||
of the request, including not performing any compression, regardless of channel |
||||
and RPC settings (for example, if compression would result in small or negative |
||||
gains). |
||||
|
||||
When a message from a client compressed with an unsupported algorithm is |
||||
processed by a server, it WILL result in an `UNIMPLEMENTED` error status on the |
||||
server. The server will then include in its response a `grpc-accept-encoding` |
||||
header specifying the algorithms it does accept. If an `UNIMPLEMENTED` error |
||||
status is returned from the server despite having used one of the algorithms |
||||
from the `grpc-accept-encoding` header, the cause MUST NOT be related to |
||||
compression. Data sent from a server compressed with an algorithm not supported |
||||
by the client WILL result in an `INTERNAL` error status on the client side. |
||||
|
||||
Note that a peer MAY choose to not disclose all the encodings it supports. |
||||
However, if it receives a message compressed in an undisclosed but supported |
||||
encoding, it MUST include said encoding in the response's `grpc-accept-encoding |
||||
h`eader. |
||||
|
||||
For every message a server is requested to compress using an algorithm it knows |
||||
the client doesn't support (as indicated by the last `grpc-accept-encoding` |
||||
header received from the client), it SHALL send the message uncompressed. |
||||
|
||||
### Specific Disabling of Compression |
||||
|
||||
If the user (through the previously described mechanisms) requests to disable |
||||
compression the next message MUST be sent uncompressed. This is instrumental in |
||||
preventing BEAST/CRIME attacks. This applies to both the the unary and streaming |
||||
cases. |
||||
|
||||
### Compression Levels and Algorithms |
||||
|
||||
The set of supported algorithm is implementation dependent. In order to simplify |
||||
the public API and to operate seamlessly across implementations (both in terms |
||||
of languages but also different version of the same one), we introduce the idea |
||||
of _compression levels_ (such as "low", "medium", "high"). |
||||
|
||||
Levels map to concrete algorithms and/or their settings (such as "low" mapping |
||||
to "gzip -3" and "high" mapping to "gzip -9") automatically depending on what a |
||||
peer is known to support. A server is always aware of what its clients support, |
||||
as clients disclose it in their Message-Accept-Encoding header as part of their |
||||
initial call. A client doesn't a priori (presently) know which algorithms a |
||||
server supports. This issue can be addressed with an initial negotiation of |
||||
capabilities or an automatic retry mechanism. These features will be implemented |
||||
in the future. Currently however, compression levels are only supported at the |
||||
server side, which is aware of the client's capabilities through the incoming |
||||
Message-Accept-Encoding header. |
||||
|
||||
### Propagation to child RPCs |
||||
|
||||
The inheritance of the compression configuration by child RPCs is left up to the |
||||
implementation. Note that in the absence of changes to the parent channel, its |
||||
configuration will be used. |
||||
|
||||
### Test cases |
||||
|
||||
1. When a compression level is not specified for either the channel or the |
||||
message, the default channel level _none_ is considered: data MUST NOT be |
||||
compressed. |
||||
1. When per-RPC compression configuration isn't present for a message, the |
||||
channel compression configuration MUST be used. |
||||
1. When a compression method (including no compression) is specified for an |
||||
outgoing message, the message MUST be compressed accordingly. |
||||
1. A message compressed by a client in a way not supported by its server MUST |
||||
fail with status `UNIMPLEMENTED`, its associated description indicating the |
||||
unsupported condition as well as the supported ones. The returned |
||||
`grpc-accept-encoding` header MUST NOT contain the compression method |
||||
(encoding) used. |
||||
1. A message compressed by a server in a way not supported by its client MUST |
||||
fail with status `INTERNAL`, its associated description indicating the |
||||
unsupported condition as well as the supported ones. The returned |
||||
`grpc-accept-encoding` header MUST NOT contain the compression method |
||||
(encoding) used. |
||||
1. An ill-constructed message with its [Compressed-Flag |
||||
bit](PROTOCOL-HTTP2.md#compressed-flag) |
||||
set but lacking a |
||||
"[grpc-encoding](PROTOCOL-HTTP2.md#message-encoding)" |
||||
entry different from _identity_ in its metadata MUST fail with `INTERNAL` |
||||
status, its associated description indicating the invalid Compressed-Flag |
||||
condition. |
@ -0,0 +1,133 @@ |
||||
# gRPC (Core) Compression Cookbook |
||||
|
||||
## Introduction |
||||
|
||||
This document describes compression as implemented by the gRPC C core. See [the |
||||
full compression specification](compression.md) for details. |
||||
|
||||
### Intended Audience |
||||
|
||||
Wrapped languages developers, for the purposes of supporting compression by |
||||
interacting with the C core. |
||||
|
||||
## Criteria for GA readiness |
||||
|
||||
1. Be able to set compression at [channel](#per-channel-settings), |
||||
[call](#per-call-settings) and [message](#per-message-settings) level. |
||||
In principle this API should be based on _compression levels_ as opposed to |
||||
algorithms. See the discussion [below](#level-vs-algorithms). |
||||
1. Have unit tests covering [the cases from the |
||||
spec](https://github.com/grpc/grpc/blob/master/doc/compression.md#test-cases). |
||||
1. Interop tests implemented and passing on Jenkins. The two relevant interop |
||||
test cases are |
||||
[large_compressed_unary](https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md#large_compressed_unary) |
||||
and |
||||
[server_compressed_streaming](https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md#server_compressed_streaming). |
||||
|
||||
## Summary Flowcharts |
||||
|
||||
The following flowcharts depict the evolution of a message, both _incoming_ and |
||||
_outgoing_, irrespective of the client/server character of the call. Aspects |
||||
still not symmetric between clients and servers (e.g. the [use of compression |
||||
levels](https://github.com/grpc/grpc/blob/master/doc/compression.md#compression-levels-and-algorithms)) |
||||
are explicitly marked. The in-detail textual description for the different |
||||
scenarios is described in subsequent sections. |
||||
|
||||
## Incoming Messages |
||||
|
||||
![image](images/compression_cookbook_incoming.png) |
||||
|
||||
## Outgoing Messages |
||||
|
||||
![image](images/compression_cookbook_outgoing.png) |
||||
|
||||
## Levels vs Algorithms |
||||
|
||||
As mentioned in [the relevant discussion on the spec |
||||
document](https://github.com/grpc/grpc/blob/master/doc/compression.md#compression-levels-and-algorithms), |
||||
compression _levels_ are the primary mechanism for compression selection _at the |
||||
server side_. In the future, it'll also be at the client side. The use of levels |
||||
abstracts away the intricacies of selecting a concrete algorithm supported by a |
||||
peer, on top of removing the burden of choice from the developer. |
||||
As of this writing (Q2 2016), clients can only specify compression _algorithms_. |
||||
Clients will support levels as soon as an automatic retry/negotiation mechanism |
||||
is in place. |
||||
|
||||
## Per Channel Settings |
||||
|
||||
Compression may be configured at channel creation. This is a convenience to |
||||
avoid having to repeatedly configure compression for every call. Note that any |
||||
compression setting on individual [calls](#per-call-settings) or |
||||
[messages](#per-message-settings) overrides channel settings. |
||||
|
||||
The following aspects can be configured at channel-creation time via channel arguments: |
||||
|
||||
#### Disable Compression _Algorithms_ |
||||
|
||||
Use the channel argument key |
||||
`GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET` (from |
||||
[`grpc/impl/codegen/compression_types.h`](https://github.com/grpc/grpc/blob/master/include/grpc/impl/codegen/compression_types.h)), |
||||
takes a 32 bit bitset value. A set bit means the algorithm with that enum value |
||||
according to `grpc_compression_algorithm` is _enabled_. |
||||
For example, `GRPC_COMPRESS_GZIP` currently has a numeric value of 2. To |
||||
enable/disable GZIP for a channel, one would set/clear the 3rd LSB (eg, 0b100 = |
||||
0x4). Note that setting/clearing 0th position, that corresponding to |
||||
`GRPC_COMPRESS_NONE`, has no effect, as no-compression (a.k.a. _identity_) is |
||||
always supported. |
||||
Incoming messages compressed (ie, encoded) with a disabled algorithm will result |
||||
in the call being closed with `GRPC_STATUS_UNIMPLEMENTED`. |
||||
|
||||
#### Default Compression _Level_ |
||||
|
||||
**(currently, Q2 2016, only applicable for server side channels. It's ignored |
||||
for clients.)** |
||||
Use the channel argument key `GRPC_COMPRESSION_CHANNEL_DEFAULT_LEVEL` (from |
||||
[`grpc/impl/codegen/compression_types.h`](https://github.com/grpc/grpc/blob/master/include/grpc/impl/codegen/compression_types.h)), |
||||
valued by an integer corresponding to a value from the `grpc_compression_level` |
||||
enum. |
||||
|
||||
#### Default Compression _Algorithm_ |
||||
|
||||
Use the channel argument key `GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM` (from |
||||
[`grpc/impl/codegen/compression_types.h`](https://github.com/grpc/grpc/blob/master/include/grpc/impl/codegen/compression_types.h)), |
||||
valued by an integer corresponding to a value from the `grpc_compression_level` |
||||
enum. |
||||
|
||||
## Per Call Settings |
||||
|
||||
### Compression **Level** in Call Responses |
||||
|
||||
The server requests a compression level via initial metadata. The |
||||
`send_initial_metadata` `grpc_op` contains a `maybe_compression_level` field |
||||
with two fields, `is_set` and `compression_level`. The former must be set when |
||||
actively choosing a level to disambiguate the default value of zero (no |
||||
compression) from the proactive selection of no compression. |
||||
|
||||
The core will receive the request for the compression level and automatically |
||||
choose a compression algorithm based on its knowledge about the peer |
||||
(communicated by the client via the `grpc-accept-encoding` header. Note that the |
||||
absence of this header means no compression is supported by the client/peer). |
||||
|
||||
### Compression **Algorithm** in Call Responses |
||||
|
||||
**Server should avoid setting the compression algorithm directly**. Prefer |
||||
setting compression levels unless there's a _very_ compelling reason to choose |
||||
specific algorithms (benchmarking, testing). |
||||
|
||||
Selection of concrete compression algorithms is performed by adding a |
||||
`(GRPC_COMPRESS_REQUEST_ALGORITHM_KEY, <algorithm-name>)` key-value pair to the |
||||
initial metadata, where `GRPC_COMPRESS_REQUEST_ALGORITHM_KEY` is defined in |
||||
[`grpc/impl/codegen/compression_types.h`](https://github.com/grpc/grpc/blob/master/include/grpc/impl/codegen/compression_types.h)), |
||||
and `<algorithm-name>` is the human readable name of the algorithm as given in |
||||
[the HTTP2 spec](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md) |
||||
for `Message-Encoding` (e.g. gzip, identity, etc.). See |
||||
[`grpc_compression_algorithm_name`](https://github.com/grpc/grpc/blob/master/src/core/lib/compression/compression.c) |
||||
for the mapping between the `grpc_compression_algorithm` enum values and their |
||||
textual representation. |
||||
|
||||
## Per Message Settings |
||||
|
||||
To disable compression for a specific message, the `flags` field of `grpc_op` |
||||
instances of type `GRPC_OP_SEND_MESSAGE` must have its `GRPC_WRITE_NO_COMPRESS` |
||||
bit set. Refer to |
||||
[`grpc/impl/codegen/compression_types.h`](https://github.com/grpc/grpc/blob/master/include/grpc/impl/codegen/compression_types.h)), |
@ -0,0 +1,91 @@ |
||||
GRPC C++ STYLE GUIDE |
||||
===================== |
||||
|
||||
Background |
||||
---------- |
||||
|
||||
Here we document style rules for C++ usage in the gRPC C++ bindings |
||||
and tests. |
||||
|
||||
General |
||||
------- |
||||
|
||||
- The majority of gRPC's C++ requirements are drawn from the [Google C++ style |
||||
guide] (https://google.github.io/styleguide/cppguide.html) |
||||
- However, gRPC has some additional requirements to maintain |
||||
[portability] (#portability) |
||||
- As in C, layout rules are defined by clang-format, and all code |
||||
should be passed through clang-format. A (docker-based) script to do |
||||
so is included in [tools/distrib/clang\_format\_code.sh] |
||||
(../tools/distrib/clang_format_code.sh). |
||||
|
||||
<a name="portability"></a> |
||||
Portability Restrictions |
||||
------------------- |
||||
|
||||
gRPC supports a large number of compilers, ranging from those that are |
||||
missing many key C++11 features to those that have quite detailed |
||||
analysis. As a result, gRPC compiles with a high level of warnings and |
||||
treat all warnings as errors. gRPC also forbids the use of some common |
||||
C++11 constructs. Here are some guidelines, to be extended as needed: |
||||
- Do not use range-based for. Expressions of the form |
||||
```c |
||||
for (auto& i: vec) { |
||||
// code |
||||
} |
||||
``` |
||||
|
||||
are not allowed and should be replaced with code such as |
||||
```c |
||||
for (auto it = vec.begin; it != vec.end(); it++) { |
||||
auto& i = *it; |
||||
// code |
||||
} |
||||
``` |
||||
|
||||
- Do not use lambda of any kind (no capture, explicit capture, or |
||||
default capture). Other C++ functional features such as |
||||
`std::function` or `std::bind` are allowed |
||||
- Do not use brace-list initializers. |
||||
- Do not compare a pointer to `nullptr` . This is because gcc 4.4 |
||||
does not support `nullptr` directly and gRPC implements a subset of |
||||
its features in [include/grpc++/impl/codegen/config.h] |
||||
(../include/grpc++/impl/codegen/config.h). Instead, pointers should |
||||
be checked for validity using their implicit conversion to `bool`. |
||||
In other words, use `if (p)` rather than `if (p != nullptr)` |
||||
- Do not initialize global/static pointer variables to `nullptr`. Just let |
||||
the compiler implicitly initialize them to `nullptr` (which it will |
||||
definitely do). The reason is that `nullptr` is an actual object in |
||||
our implementation rather than just a constant pointer value, so |
||||
static/global constructors will be called in a potentially |
||||
undesirable sequence. |
||||
- Do not use `final` or `override` as these are not supported by some |
||||
compilers. Instead use `GRPC_FINAL` and `GRPC_OVERRIDE` . These |
||||
compile down to the traditional C++ forms for compilers that support |
||||
them but are just elided if the compiler does not support those features. |
||||
- In the [include] (../../../tree/master/include/grpc++) and [src] |
||||
(../../../tree/master/src/cpp) directory trees, you should also not |
||||
use certain STL objects like `std::mutex`, `std::lock_guard`, |
||||
`std::unique_lock`, `std::nullptr`, `std::thread` . Instead, use |
||||
`grpc::mutex`, `grpc::lock_guard`, etc., which are gRPC |
||||
implementations of the prominent features of these objects that are |
||||
not always available. You can use the `std` versions of those in [test] |
||||
(../../../tree/master/test/cpp) |
||||
- Similarly, in the same directories, do not use `std::chrono` unless |
||||
it is guarded by `#ifndef GRPC_CXX0X_NO_CHRONO` . For platforms that |
||||
lack`std::chrono,` there is a C-language timer called gpr_timespec that can |
||||
be used instead. |
||||
- `std::unique_ptr` must be used with extreme care in any kind of |
||||
collection. For example `vector<std::unique_ptr>` does not work in |
||||
gcc 4.4 if the vector is constructed to its full size at |
||||
initialization but does work if elements are added to the vector |
||||
using functions like `push_back`. `map` and other pair-based |
||||
collections do not work with `unique_ptr` under gcc 4.4. The issue |
||||
is that many of these collection implementations assume a copy |
||||
constructor |
||||
to be available. |
||||
- Don't use `std::this_thread` . Use `gpr_sleep_until` for sleeping a thread. |
||||
- [Some adjacent character combinations cause problems] |
||||
(https://en.wikipedia.org/wiki/Digraphs_and_trigraphs#C). If declaring a |
||||
template against some class relative to the global namespace, |
||||
`<::name` will be non-portable. Separate the `<` from the `:` and use `< ::name`. |
@ -0,0 +1,15 @@ |
||||
gRPC Fail Fast Semantics |
||||
======================== |
||||
|
||||
Fail fast requests allow terminating requests (with status UNAVAILABLE) prior |
||||
to the deadline of the request being met. |
||||
|
||||
gRPC implementations of fail fast can terminate requests whenever a channel is |
||||
in the TRANSIENT_FAILURE or SHUTDOWN states. If the channel is in any other |
||||
state (CONNECTING, READY, or IDLE) the request should not be terminated. |
||||
|
||||
Fail fast SHOULD be the default for gRPC implementations, with an option to |
||||
switch to non fail fast. |
||||
|
||||
The opposite of fail fast is 'ignore connectivity'. |
||||
|
After Width: | Height: | Size: 89 KiB |
After Width: | Height: | Size: 120 KiB |
After Width: | Height: | Size: 39 KiB |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,49 @@ |
||||
# Minimum CMake required |
||||
cmake_minimum_required(VERSION 2.8) |
||||
|
||||
# Project |
||||
project(HelloWorld CXX) |
||||
|
||||
# Protobuf |
||||
set(protobuf_MODULE_COMPATIBLE TRUE) |
||||
find_package(protobuf CONFIG REQUIRED) |
||||
message(STATUS "Using protobuf ${protobuf_VERSION}") |
||||
|
||||
# gRPC |
||||
find_package(gRPC CONFIG REQUIRED) |
||||
message(STATUS "Using gRPC ${gRPC_VERSION}") |
||||
|
||||
# gRPC C++ plugin |
||||
get_target_property(gRPC_CPP_PLUGIN_EXECUTABLE gRPC::grpc_cpp_plugin |
||||
IMPORTED_LOCATION_RELEASE) |
||||
|
||||
# Proto file |
||||
get_filename_component(hw_proto "../../protos/helloworld.proto" ABSOLUTE) |
||||
get_filename_component(hw_proto_path "${hw_proto}" PATH) |
||||
|
||||
# Generated sources |
||||
protobuf_generate_cpp(hw_proto_srcs hw_proto_hdrs "${hw_proto}") |
||||
set(hw_grpc_srcs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.grpc.pb.cc") |
||||
set(hw_grpc_hdrs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.grpc.pb.h") |
||||
add_custom_command( |
||||
OUTPUT "${hw_grpc_srcs}" "${hw_grpc_hdrs}" |
||||
COMMAND protobuf::protoc |
||||
ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}" -I "${hw_proto_path}" |
||||
--plugin=protoc-gen-grpc="${gRPC_CPP_PLUGIN_EXECUTABLE}" |
||||
"${hw_proto}" |
||||
DEPENDS "${hw_proto}") |
||||
|
||||
# Generated include directory |
||||
include_directories("${CMAKE_CURRENT_BINARY_DIR}") |
||||
|
||||
# Targets greeter_[async_](client|server) |
||||
foreach(_target |
||||
greeter_client greeter_server |
||||
greeter_async_client greeter_async_server) |
||||
add_executable(${_target} "${_target}.cc" |
||||
${hw_proto_srcs} |
||||
${hw_grpc_srcs}) |
||||
target_link_libraries(${_target} |
||||
protobuf::libprotobuf |
||||
gRPC::grpc++_unsecure) |
||||
endforeach() |
@ -0,0 +1,153 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <string> |
||||
|
||||
#include <grpc++/grpc++.h> |
||||
#include <thread> |
||||
|
||||
#include "helloworld.grpc.pb.h" |
||||
|
||||
using grpc::Channel; |
||||
using grpc::ClientAsyncResponseReader; |
||||
using grpc::ClientContext; |
||||
using grpc::CompletionQueue; |
||||
using grpc::Status; |
||||
using helloworld::HelloRequest; |
||||
using helloworld::HelloReply; |
||||
using helloworld::Greeter; |
||||
|
||||
class GreeterClient { |
||||
public: |
||||
explicit GreeterClient(std::shared_ptr<Channel> channel) |
||||
: stub_(Greeter::NewStub(channel)) {} |
||||
|
||||
// Assembles the client's payload and sends it to the server.
|
||||
void SayHello(const std::string& user) { |
||||
// Data we are sending to the server.
|
||||
HelloRequest request; |
||||
request.set_name(user); |
||||
|
||||
// Call object to store rpc data
|
||||
AsyncClientCall* call = new AsyncClientCall; |
||||
|
||||
// stub_->AsyncSayHello() performs the RPC call, returning an instance to
|
||||
// store in "call". Because we are using the asynchronous API, we need to
|
||||
// hold on to the "call" instance in order to get updates on the ongoing RPC.
|
||||
call->response_reader = stub_->AsyncSayHello(&call->context, request, &cq_); |
||||
|
||||
|
||||
// Request that, upon completion of the RPC, "reply" be updated with the
|
||||
// server's response; "status" with the indication of whether the operation
|
||||
// was successful. Tag the request with the memory address of the call object.
|
||||
call->response_reader->Finish(&call->reply, &call->status, (void*)call); |
||||
|
||||
} |
||||
|
||||
// Loop while listening for completed responses.
|
||||
// Prints out the response from the server.
|
||||
void AsyncCompleteRpc() { |
||||
void* got_tag; |
||||
bool ok = false; |
||||
|
||||
// Block until the next result is available in the completion queue "cq".
|
||||
while (cq_.Next(&got_tag, &ok)) { |
||||
// The tag in this example is the memory location of the call object
|
||||
AsyncClientCall* call = static_cast<AsyncClientCall*>(got_tag); |
||||
|
||||
// Verify that the request was completed successfully. Note that "ok"
|
||||
// corresponds solely to the request for updates introduced by Finish().
|
||||
GPR_ASSERT(ok); |
||||
|
||||
if (call->status.ok()) |
||||
std::cout << "Greeter received: " << call->reply.message() << std::endl; |
||||
else |
||||
std::cout << "RPC failed" << std::endl; |
||||
|
||||
// Once we're complete, deallocate the call object.
|
||||
delete call; |
||||
} |
||||
} |
||||
|
||||
private: |
||||
|
||||
// struct for keeping state and data information
|
||||
struct AsyncClientCall { |
||||
// Container for the data we expect from the server.
|
||||
HelloReply reply; |
||||
|
||||
// Context for the client. It could be used to convey extra information to
|
||||
// the server and/or tweak certain RPC behaviors.
|
||||
ClientContext context; |
||||
|
||||
// Storage for the status of the RPC upon completion.
|
||||
Status status; |
||||
|
||||
|
||||
std::unique_ptr<ClientAsyncResponseReader<HelloReply>> response_reader; |
||||
}; |
||||
|
||||
// Out of the passed in Channel comes the stub, stored here, our view of the
|
||||
// server's exposed services.
|
||||
std::unique_ptr<Greeter::Stub> stub_; |
||||
|
||||
// The producer-consumer queue we use to communicate asynchronously with the
|
||||
// gRPC runtime.
|
||||
CompletionQueue cq_; |
||||
}; |
||||
|
||||
int main(int argc, char** argv) { |
||||
|
||||
|
||||
// Instantiate the client. It requires a channel, out of which the actual RPCs
|
||||
// are created. This channel models a connection to an endpoint (in this case,
|
||||
// localhost at port 50051). We indicate that the channel isn't authenticated
|
||||
// (use of InsecureChannelCredentials()).
|
||||
GreeterClient greeter(grpc::CreateChannel( |
||||
"localhost:50051", grpc::InsecureChannelCredentials())); |
||||
|
||||
// Spawn reader thread that loops indefinitely
|
||||
std::thread thread_ = std::thread(&GreeterClient::AsyncCompleteRpc, &greeter); |
||||
|
||||
for (int i = 0; i < 100; i++) { |
||||
std::string user("world " + std::to_string(i)); |
||||
greeter.SayHello(user); // The actual RPC call!
|
||||
} |
||||
|
||||
std::cout << "Press control-c to quit" << std::endl << std::endl; |
||||
thread_.join(); //blocks forever
|
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1 @@ |
||||
This is the dynamic code generation variant of the Node examples. Code in these examples is generated at runtime using Protobuf.js. |
@ -0,0 +1,53 @@ |
||||
/* |
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
var PROTO_PATH = __dirname + '/../../protos/helloworld.proto'; |
||||
|
||||
var grpc = require('grpc'); |
||||
var hello_proto = grpc.load(PROTO_PATH).helloworld; |
||||
|
||||
function main() { |
||||
var client = new hello_proto.Greeter('localhost:50051', |
||||
grpc.credentials.createInsecure()); |
||||
var user; |
||||
if (process.argv.length >= 3) { |
||||
user = process.argv[2]; |
||||
} else { |
||||
user = 'world'; |
||||
} |
||||
client.sayHello({name: user}, function(err, response) { |
||||
console.log('Greeting:', response.message); |
||||
}); |
||||
} |
||||
|
||||
main(); |
@ -1,39 +0,0 @@ |
||||
// GENERATED CODE -- DO NOT EDIT!
|
||||
|
||||
var grpc = require('grpc'); |
||||
var helloworld_pb = require('./helloworld_pb.js'); |
||||
|
||||
function serialize_HelloReply(arg) { |
||||
if (!(arg instanceof helloworld_pb.HelloReply)) { |
||||
throw new Error('Expected argument of type HelloReply'); |
||||
} |
||||
return new Buffer(arg.serializeBinary()); |
||||
} |
||||
function deserialize_HelloReply(buffer_arg) { |
||||
return helloworld_pb.HelloReply.deserializeBinary(new Uint8Array(buffer_arg)); |
||||
} |
||||
function serialize_HelloRequest(arg) { |
||||
if (!(arg instanceof helloworld_pb.HelloRequest)) { |
||||
throw new Error('Expected argument of type HelloRequest'); |
||||
} |
||||
return new Buffer(arg.serializeBinary()); |
||||
} |
||||
function deserialize_HelloRequest(buffer_arg) { |
||||
return helloworld_pb.HelloRequest.deserializeBinary(new Uint8Array(buffer_arg)); |
||||
} |
||||
|
||||
var GreeterService = exports.GreeterService = { |
||||
sayHello: { |
||||
path: '/helloworld.Greeter/SayHello', |
||||
requestStream: false, |
||||
responseStream: false, |
||||
requestType: helloworld_pb.HelloRequest, |
||||
responseType: helloworld_pb.HelloReply, |
||||
requestSerialize: serialize_HelloRequest, |
||||
requestDeserialize: deserialize_HelloRequest, |
||||
responseSerialize: serialize_HelloReply, |
||||
responseDeserialize: deserialize_HelloReply, |
||||
}, |
||||
}; |
||||
|
||||
exports.GreeterClient = grpc.makeGenericClientConstructor(GreeterService); |
@ -0,0 +1,7 @@ |
||||
This is the static code generation variant of the Node examples. Code in these examples is pre-generated using protoc and the Node gRPC protoc plugin, and the generated code can be found in various `*_pb.js` files. The command line sequence for generating those files is as follows (assuming that `protoc` and `grpc_node_plugin` are present, and starting in the base directory of this package): |
||||
|
||||
```sh |
||||
cd ../protos |
||||
protoc --js_out=import_style=commonjs,binary:../node/static_codegen/ --grpc_out=../node/static_codegen --plugin=protoc-gen-grpc=grpc_node_plugin helloworld.proto |
||||
protoc --js_out=import_style=commonjs,binary:../node/static_codegen/route_guide/ --grpc_out=../node/static_codegen/route_guide/ --plugin=protoc-gen-grpc=grpc_node_plugin route_guide.proto |
||||
``` |
@ -0,0 +1,76 @@ |
||||
// GENERATED CODE -- DO NOT EDIT!
|
||||
|
||||
// Original file comments:
|
||||
// Copyright 2015, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
'use strict'; |
||||
var grpc = require('grpc'); |
||||
var helloworld_pb = require('./helloworld_pb.js'); |
||||
|
||||
function serialize_HelloReply(arg) { |
||||
if (!(arg instanceof helloworld_pb.HelloReply)) { |
||||
throw new Error('Expected argument of type HelloReply'); |
||||
} |
||||
return new Buffer(arg.serializeBinary()); |
||||
} |
||||
|
||||
function deserialize_HelloReply(buffer_arg) { |
||||
return helloworld_pb.HelloReply.deserializeBinary(new Uint8Array(buffer_arg)); |
||||
} |
||||
|
||||
function serialize_HelloRequest(arg) { |
||||
if (!(arg instanceof helloworld_pb.HelloRequest)) { |
||||
throw new Error('Expected argument of type HelloRequest'); |
||||
} |
||||
return new Buffer(arg.serializeBinary()); |
||||
} |
||||
|
||||
function deserialize_HelloRequest(buffer_arg) { |
||||
return helloworld_pb.HelloRequest.deserializeBinary(new Uint8Array(buffer_arg)); |
||||
} |
||||
|
||||
|
||||
// The greeting service definition.
|
||||
var GreeterService = exports.GreeterService = { |
||||
// Sends a greeting
|
||||
sayHello: { |
||||
path: '/helloworld.Greeter/SayHello', |
||||
requestStream: false, |
||||
responseStream: false, |
||||
requestType: helloworld_pb.HelloRequest, |
||||
responseType: helloworld_pb.HelloReply, |
||||
requestSerialize: serialize_HelloRequest, |
||||
requestDeserialize: deserialize_HelloRequest, |
||||
responseSerialize: serialize_HelloReply, |
||||
responseDeserialize: deserialize_HelloReply, |
||||
}, |
||||
}; |
||||
|
||||
exports.GreeterClient = grpc.makeGenericClientConstructor(GreeterService); |
@ -0,0 +1,5 @@ |
||||
#gRPC Basics: Node.js sample code |
||||
|
||||
The files in this folder are the samples used in [gRPC Basics: Node.js][], a detailed tutorial for using gRPC in Node.js. |
||||
|
||||
[gRPC Basics: Node.js]:http://www.grpc.io/docs/tutorials/basic/node.html |
@ -0,0 +1,247 @@ |
||||
/* |
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
var messages = require('./route_guide_pb'); |
||||
var services = require('./route_guide_grpc_pb'); |
||||
|
||||
var async = require('async'); |
||||
var fs = require('fs'); |
||||
var parseArgs = require('minimist'); |
||||
var path = require('path'); |
||||
var _ = require('lodash'); |
||||
var grpc = require('grpc'); |
||||
|
||||
var client = new services.RouteGuideClient('localhost:50051', |
||||
grpc.credentials.createInsecure()); |
||||
|
||||
var COORD_FACTOR = 1e7; |
||||
|
||||
/** |
||||
* Run the getFeature demo. Calls getFeature with a point known to have a |
||||
* feature and a point known not to have a feature. |
||||
* @param {function} callback Called when this demo is complete |
||||
*/ |
||||
function runGetFeature(callback) { |
||||
var next = _.after(2, callback); |
||||
function featureCallback(error, feature) { |
||||
if (error) { |
||||
callback(error); |
||||
} |
||||
var latitude = feature.getLocation().getLatitude(); |
||||
var longitude = feature.getLocation().getLongitude(); |
||||
if (feature.getName() === '') { |
||||
console.log('Found no feature at ' + |
||||
latitude/COORD_FACTOR + ', ' + longitude/COORD_FACTOR); |
||||
} else { |
||||
console.log('Found feature called "' + feature.getName() + '" at ' + |
||||
latitude/COORD_FACTOR + ', ' + longitude/COORD_FACTOR); |
||||
} |
||||
next(); |
||||
} |
||||
var point1 = new messages.Point(); |
||||
point1.setLatitude(409146138); |
||||
point1.setLongitude(-746188906); |
||||
var point2 = new messages.Point(); |
||||
point2.setLatitude(0); |
||||
point2.setLongitude(0); |
||||
client.getFeature(point1, featureCallback); |
||||
client.getFeature(point2, featureCallback); |
||||
} |
||||
|
||||
/** |
||||
* Run the listFeatures demo. Calls listFeatures with a rectangle containing all |
||||
* of the features in the pre-generated database. Prints each response as it |
||||
* comes in. |
||||
* @param {function} callback Called when this demo is complete |
||||
*/ |
||||
function runListFeatures(callback) { |
||||
var rect = new messages.Rectangle(); |
||||
var lo = new messages.Point(); |
||||
lo.setLatitude(400000000); |
||||
lo.setLongitude(-750000000); |
||||
rect.setLo(lo); |
||||
var hi = new messages.Point(); |
||||
hi.setLatitude(420000000); |
||||
hi.setLongitude(-730000000); |
||||
rect.setHi(hi); |
||||
console.log('Looking for features between 40, -75 and 42, -73'); |
||||
var call = client.listFeatures(rect); |
||||
call.on('data', function(feature) { |
||||
console.log('Found feature called "' + feature.getName() + '" at ' + |
||||
feature.getLocation().getLatitude()/COORD_FACTOR + ', ' + |
||||
feature.getLocation().getLongitude()/COORD_FACTOR); |
||||
}); |
||||
call.on('end', callback); |
||||
} |
||||
|
||||
/** |
||||
* Run the recordRoute demo. Sends several randomly chosen points from the |
||||
* pre-generated feature database with a variable delay in between. Prints the |
||||
* statistics when they are sent from the server. |
||||
* @param {function} callback Called when this demo is complete |
||||
*/ |
||||
function runRecordRoute(callback) { |
||||
var argv = parseArgs(process.argv, { |
||||
string: 'db_path' |
||||
}); |
||||
fs.readFile(path.resolve(argv.db_path), function(err, data) { |
||||
if (err) callback(err); |
||||
// Transform the loaded features to Feature objects
|
||||
var feature_list = _.map(JSON.parse(data), function(value) { |
||||
var feature = new messages.Feature(); |
||||
feature.setName(value.name); |
||||
var location = new messages.Point(); |
||||
location.setLatitude(value.location.latitude); |
||||
location.setLongitude(value.location.longitude); |
||||
feature.setLocation(location); |
||||
return feature; |
||||
}); |
||||
|
||||
var num_points = 10; |
||||
var call = client.recordRoute(function(error, stats) { |
||||
if (error) { |
||||
callback(error); |
||||
} |
||||
console.log('Finished trip with', stats.getPointCount(), 'points'); |
||||
console.log('Passed', stats.getFeatureCount(), 'features'); |
||||
console.log('Travelled', stats.getDistance(), 'meters'); |
||||
console.log('It took', stats.getElapsedTime(), 'seconds'); |
||||
callback(); |
||||
}); |
||||
/** |
||||
* Constructs a function that asynchronously sends the given point and then |
||||
* delays sending its callback |
||||
* @param {messages.Point} location The point to send |
||||
* @return {function(function)} The function that sends the point |
||||
*/ |
||||
function pointSender(location) { |
||||
/** |
||||
* Sends the point, then calls the callback after a delay |
||||
* @param {function} callback Called when complete |
||||
*/ |
||||
return function(callback) { |
||||
console.log('Visiting point ' + location.getLatitude()/COORD_FACTOR + |
||||
', ' + location.getLongitude()/COORD_FACTOR); |
||||
call.write(location); |
||||
_.delay(callback, _.random(500, 1500)); |
||||
}; |
||||
} |
||||
var point_senders = []; |
||||
for (var i = 0; i < num_points; i++) { |
||||
var rand_point = feature_list[_.random(0, feature_list.length - 1)]; |
||||
point_senders[i] = pointSender(rand_point.getLocation()); |
||||
} |
||||
async.series(point_senders, function() { |
||||
call.end(); |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* Run the routeChat demo. Send some chat messages, and print any chat messages |
||||
* that are sent from the server. |
||||
* @param {function} callback Called when the demo is complete |
||||
*/ |
||||
function runRouteChat(callback) { |
||||
var call = client.routeChat(); |
||||
call.on('data', function(note) { |
||||
console.log('Got message "' + note.getMessage() + '" at ' + |
||||
note.getLocation().getLatitude() + ', ' + |
||||
note.getLocation().getLongitude()); |
||||
}); |
||||
|
||||
call.on('end', callback); |
||||
|
||||
var notes = [{ |
||||
location: { |
||||
latitude: 0, |
||||
longitude: 0 |
||||
}, |
||||
message: 'First message' |
||||
}, { |
||||
location: { |
||||
latitude: 0, |
||||
longitude: 1 |
||||
}, |
||||
message: 'Second message' |
||||
}, { |
||||
location: { |
||||
latitude: 1, |
||||
longitude: 0 |
||||
}, |
||||
message: 'Third message' |
||||
}, { |
||||
location: { |
||||
latitude: 0, |
||||
longitude: 0 |
||||
}, |
||||
message: 'Fourth message' |
||||
}]; |
||||
for (var i = 0; i < notes.length; i++) { |
||||
var note = notes[i]; |
||||
console.log('Sending message "' + note.message + '" at ' + |
||||
note.location.latitude + ', ' + note.location.longitude); |
||||
var noteMsg = new messages.RouteNote(); |
||||
noteMsg.setMessage(note.message); |
||||
var location = new messages.Point(); |
||||
location.setLatitude(note.location.latitude); |
||||
location.setLongitude(note.location.longitude); |
||||
noteMsg.setLocation(location); |
||||
call.write(noteMsg); |
||||
} |
||||
call.end(); |
||||
} |
||||
|
||||
/** |
||||
* Run all of the demos in order |
||||
*/ |
||||
function main() { |
||||
async.series([ |
||||
runGetFeature, |
||||
runListFeatures, |
||||
runRecordRoute, |
||||
runRouteChat |
||||
]); |
||||
} |
||||
|
||||
if (require.main === module) { |
||||
main(); |
||||
} |
||||
|
||||
exports.runGetFeature = runGetFeature; |
||||
|
||||
exports.runListFeatures = runListFeatures; |
||||
|
||||
exports.runRecordRoute = runRecordRoute; |
||||
|
||||
exports.runRouteChat = runRouteChat; |
@ -0,0 +1,601 @@ |
||||
[{ |
||||
"location": { |
||||
"latitude": 407838351, |
||||
"longitude": -746143763 |
||||
}, |
||||
"name": "Patriots Path, Mendham, NJ 07945, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 408122808, |
||||
"longitude": -743999179 |
||||
}, |
||||
"name": "101 New Jersey 10, Whippany, NJ 07981, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 413628156, |
||||
"longitude": -749015468 |
||||
}, |
||||
"name": "U.S. 6, Shohola, PA 18458, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 419999544, |
||||
"longitude": -740371136 |
||||
}, |
||||
"name": "5 Conners Road, Kingston, NY 12401, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 414008389, |
||||
"longitude": -743951297 |
||||
}, |
||||
"name": "Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 419611318, |
||||
"longitude": -746524769 |
||||
}, |
||||
"name": "287 Flugertown Road, Livingston Manor, NY 12758, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 406109563, |
||||
"longitude": -742186778 |
||||
}, |
||||
"name": "4001 Tremley Point Road, Linden, NJ 07036, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 416802456, |
||||
"longitude": -742370183 |
||||
}, |
||||
"name": "352 South Mountain Road, Wallkill, NY 12589, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 412950425, |
||||
"longitude": -741077389 |
||||
}, |
||||
"name": "Bailey Turn Road, Harriman, NY 10926, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 412144655, |
||||
"longitude": -743949739 |
||||
}, |
||||
"name": "193-199 Wawayanda Road, Hewitt, NJ 07421, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 415736605, |
||||
"longitude": -742847522 |
||||
}, |
||||
"name": "406-496 Ward Avenue, Pine Bush, NY 12566, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 413843930, |
||||
"longitude": -740501726 |
||||
}, |
||||
"name": "162 Merrill Road, Highland Mills, NY 10930, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 410873075, |
||||
"longitude": -744459023 |
||||
}, |
||||
"name": "Clinton Road, West Milford, NJ 07480, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 412346009, |
||||
"longitude": -744026814 |
||||
}, |
||||
"name": "16 Old Brook Lane, Warwick, NY 10990, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 402948455, |
||||
"longitude": -747903913 |
||||
}, |
||||
"name": "3 Drake Lane, Pennington, NJ 08534, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 406337092, |
||||
"longitude": -740122226 |
||||
}, |
||||
"name": "6324 8th Avenue, Brooklyn, NY 11220, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 406421967, |
||||
"longitude": -747727624 |
||||
}, |
||||
"name": "1 Merck Access Road, Whitehouse Station, NJ 08889, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 416318082, |
||||
"longitude": -749677716 |
||||
}, |
||||
"name": "78-98 Schalck Road, Narrowsburg, NY 12764, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 415301720, |
||||
"longitude": -748416257 |
||||
}, |
||||
"name": "282 Lakeview Drive Road, Highland Lake, NY 12743, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 402647019, |
||||
"longitude": -747071791 |
||||
}, |
||||
"name": "330 Evelyn Avenue, Hamilton Township, NJ 08619, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 412567807, |
||||
"longitude": -741058078 |
||||
}, |
||||
"name": "New York State Reference Route 987E, Southfields, NY 10975, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 416855156, |
||||
"longitude": -744420597 |
||||
}, |
||||
"name": "103-271 Tempaloni Road, Ellenville, NY 12428, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 404663628, |
||||
"longitude": -744820157 |
||||
}, |
||||
"name": "1300 Airport Road, North Brunswick Township, NJ 08902, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 407113723, |
||||
"longitude": -749746483 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 402133926, |
||||
"longitude": -743613249 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 400273442, |
||||
"longitude": -741220915 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 411236786, |
||||
"longitude": -744070769 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 411633782, |
||||
"longitude": -746784970 |
||||
}, |
||||
"name": "211-225 Plains Road, Augusta, NJ 07822, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 415830701, |
||||
"longitude": -742952812 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 413447164, |
||||
"longitude": -748712898 |
||||
}, |
||||
"name": "165 Pedersen Ridge Road, Milford, PA 18337, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 405047245, |
||||
"longitude": -749800722 |
||||
}, |
||||
"name": "100-122 Locktown Road, Frenchtown, NJ 08825, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 418858923, |
||||
"longitude": -746156790 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 417951888, |
||||
"longitude": -748484944 |
||||
}, |
||||
"name": "650-652 Willi Hill Road, Swan Lake, NY 12783, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 407033786, |
||||
"longitude": -743977337 |
||||
}, |
||||
"name": "26 East 3rd Street, New Providence, NJ 07974, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 417548014, |
||||
"longitude": -740075041 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 410395868, |
||||
"longitude": -744972325 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 404615353, |
||||
"longitude": -745129803 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 406589790, |
||||
"longitude": -743560121 |
||||
}, |
||||
"name": "611 Lawrence Avenue, Westfield, NJ 07090, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 414653148, |
||||
"longitude": -740477477 |
||||
}, |
||||
"name": "18 Lannis Avenue, New Windsor, NY 12553, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 405957808, |
||||
"longitude": -743255336 |
||||
}, |
||||
"name": "82-104 Amherst Avenue, Colonia, NJ 07067, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 411733589, |
||||
"longitude": -741648093 |
||||
}, |
||||
"name": "170 Seven Lakes Drive, Sloatsburg, NY 10974, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 412676291, |
||||
"longitude": -742606606 |
||||
}, |
||||
"name": "1270 Lakes Road, Monroe, NY 10950, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 409224445, |
||||
"longitude": -748286738 |
||||
}, |
||||
"name": "509-535 Alphano Road, Great Meadows, NJ 07838, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 406523420, |
||||
"longitude": -742135517 |
||||
}, |
||||
"name": "652 Garden Street, Elizabeth, NJ 07202, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 401827388, |
||||
"longitude": -740294537 |
||||
}, |
||||
"name": "349 Sea Spray Court, Neptune City, NJ 07753, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 410564152, |
||||
"longitude": -743685054 |
||||
}, |
||||
"name": "13-17 Stanley Street, West Milford, NJ 07480, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 408472324, |
||||
"longitude": -740726046 |
||||
}, |
||||
"name": "47 Industrial Avenue, Teterboro, NJ 07608, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 412452168, |
||||
"longitude": -740214052 |
||||
}, |
||||
"name": "5 White Oak Lane, Stony Point, NY 10980, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 409146138, |
||||
"longitude": -746188906 |
||||
}, |
||||
"name": "Berkshire Valley Management Area Trail, Jefferson, NJ, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 404701380, |
||||
"longitude": -744781745 |
||||
}, |
||||
"name": "1007 Jersey Avenue, New Brunswick, NJ 08901, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 409642566, |
||||
"longitude": -746017679 |
||||
}, |
||||
"name": "6 East Emerald Isle Drive, Lake Hopatcong, NJ 07849, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 408031728, |
||||
"longitude": -748645385 |
||||
}, |
||||
"name": "1358-1474 New Jersey 57, Port Murray, NJ 07865, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 413700272, |
||||
"longitude": -742135189 |
||||
}, |
||||
"name": "367 Prospect Road, Chester, NY 10918, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 404310607, |
||||
"longitude": -740282632 |
||||
}, |
||||
"name": "10 Simon Lake Drive, Atlantic Highlands, NJ 07716, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 409319800, |
||||
"longitude": -746201391 |
||||
}, |
||||
"name": "11 Ward Street, Mount Arlington, NJ 07856, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 406685311, |
||||
"longitude": -742108603 |
||||
}, |
||||
"name": "300-398 Jefferson Avenue, Elizabeth, NJ 07201, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 419018117, |
||||
"longitude": -749142781 |
||||
}, |
||||
"name": "43 Dreher Road, Roscoe, NY 12776, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 412856162, |
||||
"longitude": -745148837 |
||||
}, |
||||
"name": "Swan Street, Pine Island, NY 10969, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 416560744, |
||||
"longitude": -746721964 |
||||
}, |
||||
"name": "66 Pleasantview Avenue, Monticello, NY 12701, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 405314270, |
||||
"longitude": -749836354 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 414219548, |
||||
"longitude": -743327440 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 415534177, |
||||
"longitude": -742900616 |
||||
}, |
||||
"name": "565 Winding Hills Road, Montgomery, NY 12549, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 406898530, |
||||
"longitude": -749127080 |
||||
}, |
||||
"name": "231 Rocky Run Road, Glen Gardner, NJ 08826, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 407586880, |
||||
"longitude": -741670168 |
||||
}, |
||||
"name": "100 Mount Pleasant Avenue, Newark, NJ 07104, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 400106455, |
||||
"longitude": -742870190 |
||||
}, |
||||
"name": "517-521 Huntington Drive, Manchester Township, NJ 08759, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 400066188, |
||||
"longitude": -746793294 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 418803880, |
||||
"longitude": -744102673 |
||||
}, |
||||
"name": "40 Mountain Road, Napanoch, NY 12458, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 414204288, |
||||
"longitude": -747895140 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 414777405, |
||||
"longitude": -740615601 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 415464475, |
||||
"longitude": -747175374 |
||||
}, |
||||
"name": "48 North Road, Forestburgh, NY 12777, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 404062378, |
||||
"longitude": -746376177 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 405688272, |
||||
"longitude": -749285130 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 400342070, |
||||
"longitude": -748788996 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 401809022, |
||||
"longitude": -744157964 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 404226644, |
||||
"longitude": -740517141 |
||||
}, |
||||
"name": "9 Thompson Avenue, Leonardo, NJ 07737, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 410322033, |
||||
"longitude": -747871659 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 407100674, |
||||
"longitude": -747742727 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 418811433, |
||||
"longitude": -741718005 |
||||
}, |
||||
"name": "213 Bush Road, Stone Ridge, NY 12484, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 415034302, |
||||
"longitude": -743850945 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 411349992, |
||||
"longitude": -743694161 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 404839914, |
||||
"longitude": -744759616 |
||||
}, |
||||
"name": "1-17 Bergen Court, New Brunswick, NJ 08901, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 414638017, |
||||
"longitude": -745957854 |
||||
}, |
||||
"name": "35 Oakland Valley Road, Cuddebackville, NY 12729, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 412127800, |
||||
"longitude": -740173578 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 401263460, |
||||
"longitude": -747964303 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 412843391, |
||||
"longitude": -749086026 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 418512773, |
||||
"longitude": -743067823 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 404318328, |
||||
"longitude": -740835638 |
||||
}, |
||||
"name": "42-102 Main Street, Belford, NJ 07718, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 419020746, |
||||
"longitude": -741172328 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 404080723, |
||||
"longitude": -746119569 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 401012643, |
||||
"longitude": -744035134 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 404306372, |
||||
"longitude": -741079661 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 403966326, |
||||
"longitude": -748519297 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 405002031, |
||||
"longitude": -748407866 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 409532885, |
||||
"longitude": -742200683 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 416851321, |
||||
"longitude": -742674555 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 406411633, |
||||
"longitude": -741722051 |
||||
}, |
||||
"name": "3387 Richmond Terrace, Staten Island, NY 10303, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 413069058, |
||||
"longitude": -744597778 |
||||
}, |
||||
"name": "261 Van Sickle Road, Goshen, NY 10924, USA" |
||||
}, { |
||||
"location": { |
||||
"latitude": 418465462, |
||||
"longitude": -746859398 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 411733222, |
||||
"longitude": -744228360 |
||||
}, |
||||
"name": "" |
||||
}, { |
||||
"location": { |
||||
"latitude": 410248224, |
||||
"longitude": -747127767 |
||||
}, |
||||
"name": "3 Hasta Way, Newton, NJ 07860, USA" |
||||
}] |
@ -0,0 +1,161 @@ |
||||
// GENERATED CODE -- DO NOT EDIT!
|
||||
|
||||
// Original file comments:
|
||||
// Copyright 2015, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
'use strict'; |
||||
var grpc = require('grpc'); |
||||
var route_guide_pb = require('./route_guide_pb.js'); |
||||
|
||||
function serialize_Feature(arg) { |
||||
if (!(arg instanceof route_guide_pb.Feature)) { |
||||
throw new Error('Expected argument of type Feature'); |
||||
} |
||||
return new Buffer(arg.serializeBinary()); |
||||
} |
||||
|
||||
function deserialize_Feature(buffer_arg) { |
||||
return route_guide_pb.Feature.deserializeBinary(new Uint8Array(buffer_arg)); |
||||
} |
||||
|
||||
function serialize_Point(arg) { |
||||
if (!(arg instanceof route_guide_pb.Point)) { |
||||
throw new Error('Expected argument of type Point'); |
||||
} |
||||
return new Buffer(arg.serializeBinary()); |
||||
} |
||||
|
||||
function deserialize_Point(buffer_arg) { |
||||
return route_guide_pb.Point.deserializeBinary(new Uint8Array(buffer_arg)); |
||||
} |
||||
|
||||
function serialize_Rectangle(arg) { |
||||
if (!(arg instanceof route_guide_pb.Rectangle)) { |
||||
throw new Error('Expected argument of type Rectangle'); |
||||
} |
||||
return new Buffer(arg.serializeBinary()); |
||||
} |
||||
|
||||
function deserialize_Rectangle(buffer_arg) { |
||||
return route_guide_pb.Rectangle.deserializeBinary(new Uint8Array(buffer_arg)); |
||||
} |
||||
|
||||
function serialize_RouteNote(arg) { |
||||
if (!(arg instanceof route_guide_pb.RouteNote)) { |
||||
throw new Error('Expected argument of type RouteNote'); |
||||
} |
||||
return new Buffer(arg.serializeBinary()); |
||||
} |
||||
|
||||
function deserialize_RouteNote(buffer_arg) { |
||||
return route_guide_pb.RouteNote.deserializeBinary(new Uint8Array(buffer_arg)); |
||||
} |
||||
|
||||
function serialize_RouteSummary(arg) { |
||||
if (!(arg instanceof route_guide_pb.RouteSummary)) { |
||||
throw new Error('Expected argument of type RouteSummary'); |
||||
} |
||||
return new Buffer(arg.serializeBinary()); |
||||
} |
||||
|
||||
function deserialize_RouteSummary(buffer_arg) { |
||||
return route_guide_pb.RouteSummary.deserializeBinary(new Uint8Array(buffer_arg)); |
||||
} |
||||
|
||||
|
||||
// Interface exported by the server.
|
||||
var RouteGuideService = exports.RouteGuideService = { |
||||
// A simple RPC.
|
||||
//
|
||||
// Obtains the feature at a given position.
|
||||
//
|
||||
// A feature with an empty name is returned if there's no feature at the given
|
||||
// position.
|
||||
getFeature: { |
||||
path: '/routeguide.RouteGuide/GetFeature', |
||||
requestStream: false, |
||||
responseStream: false, |
||||
requestType: route_guide_pb.Point, |
||||
responseType: route_guide_pb.Feature, |
||||
requestSerialize: serialize_Point, |
||||
requestDeserialize: deserialize_Point, |
||||
responseSerialize: serialize_Feature, |
||||
responseDeserialize: deserialize_Feature, |
||||
}, |
||||
// A server-to-client streaming RPC.
|
||||
//
|
||||
// Obtains the Features available within the given Rectangle. Results are
|
||||
// streamed rather than returned at once (e.g. in a response message with a
|
||||
// repeated field), as the rectangle may cover a large area and contain a
|
||||
// huge number of features.
|
||||
listFeatures: { |
||||
path: '/routeguide.RouteGuide/ListFeatures', |
||||
requestStream: false, |
||||
responseStream: true, |
||||
requestType: route_guide_pb.Rectangle, |
||||
responseType: route_guide_pb.Feature, |
||||
requestSerialize: serialize_Rectangle, |
||||
requestDeserialize: deserialize_Rectangle, |
||||
responseSerialize: serialize_Feature, |
||||
responseDeserialize: deserialize_Feature, |
||||
}, |
||||
// A client-to-server streaming RPC.
|
||||
//
|
||||
// Accepts a stream of Points on a route being traversed, returning a
|
||||
// RouteSummary when traversal is completed.
|
||||
recordRoute: { |
||||
path: '/routeguide.RouteGuide/RecordRoute', |
||||
requestStream: true, |
||||
responseStream: false, |
||||
requestType: route_guide_pb.Point, |
||||
responseType: route_guide_pb.RouteSummary, |
||||
requestSerialize: serialize_Point, |
||||
requestDeserialize: deserialize_Point, |
||||
responseSerialize: serialize_RouteSummary, |
||||
responseDeserialize: deserialize_RouteSummary, |
||||
}, |
||||
// A Bidirectional streaming RPC.
|
||||
//
|
||||
// Accepts a stream of RouteNotes sent while a route is being traversed,
|
||||
// while receiving other RouteNotes (e.g. from other users).
|
||||
routeChat: { |
||||
path: '/routeguide.RouteGuide/RouteChat', |
||||
requestStream: true, |
||||
responseStream: true, |
||||
requestType: route_guide_pb.RouteNote, |
||||
responseType: route_guide_pb.RouteNote, |
||||
requestSerialize: serialize_RouteNote, |
||||
requestDeserialize: deserialize_RouteNote, |
||||
responseSerialize: serialize_RouteNote, |
||||
responseDeserialize: deserialize_RouteNote, |
||||
}, |
||||
}; |
||||
|
||||
exports.RouteGuideClient = grpc.makeGenericClientConstructor(RouteGuideService); |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,261 @@ |
||||
/* |
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
var messages = require('./route_guide_pb'); |
||||
var services = require('./route_guide_grpc_pb'); |
||||
|
||||
var fs = require('fs'); |
||||
var parseArgs = require('minimist'); |
||||
var path = require('path'); |
||||
var _ = require('lodash'); |
||||
var grpc = require('grpc'); |
||||
|
||||
var COORD_FACTOR = 1e7; |
||||
|
||||
/** |
||||
* For simplicity, a point is a record type that looks like |
||||
* {latitude: number, longitude: number}, and a feature is a record type that |
||||
* looks like {name: string, location: point}. feature objects with name==='' |
||||
* are points with no feature. |
||||
*/ |
||||
|
||||
/** |
||||
* List of feature objects at points that have been requested so far. |
||||
*/ |
||||
var feature_list = []; |
||||
|
||||
/** |
||||
* Get a feature object at the given point, or creates one if it does not exist. |
||||
* @param {point} point The point to check |
||||
* @return {feature} The feature object at the point. Note that an empty name |
||||
* indicates no feature |
||||
*/ |
||||
function checkFeature(point) { |
||||
var feature; |
||||
// Check if there is already a feature object for the given point
|
||||
for (var i = 0; i < feature_list.length; i++) { |
||||
feature = feature_list[i]; |
||||
if (feature.getLocation().getLatitude() === point.getLatitude() && |
||||
feature.getLocation().getLongitude() === point.getLongitude()) { |
||||
return feature; |
||||
} |
||||
} |
||||
var name = ''; |
||||
feature = new messages.Feature(); |
||||
feature.setName(name); |
||||
feature.setLocation(point); |
||||
return feature; |
||||
} |
||||
|
||||
/** |
||||
* getFeature request handler. Gets a request with a point, and responds with a |
||||
* feature object indicating whether there is a feature at that point. |
||||
* @param {EventEmitter} call Call object for the handler to process |
||||
* @param {function(Error, feature)} callback Response callback |
||||
*/ |
||||
function getFeature(call, callback) { |
||||
callback(null, checkFeature(call.request)); |
||||
} |
||||
|
||||
/** |
||||
* listFeatures request handler. Gets a request with two points, and responds |
||||
* with a stream of all features in the bounding box defined by those points. |
||||
* @param {Writable} call Writable stream for responses with an additional |
||||
* request property for the request value. |
||||
*/ |
||||
function listFeatures(call) { |
||||
var lo = call.request.getLo(); |
||||
var hi = call.request.getHi(); |
||||
var left = _.min([lo.getLongitude(), hi.getLongitude()]); |
||||
var right = _.max([lo.getLongitude(), hi.getLongitude()]); |
||||
var top = _.max([lo.getLatitude(), hi.getLatitude()]); |
||||
var bottom = _.min([lo.getLatitude(), hi.getLatitude()]); |
||||
// For each feature, check if it is in the given bounding box
|
||||
_.each(feature_list, function(feature) { |
||||
if (feature.getName() === '') { |
||||
return; |
||||
} |
||||
if (feature.getLocation().getLongitude() >= left && |
||||
feature.getLocation().getLongitude() <= right && |
||||
feature.getLocation().getLatitude() >= bottom && |
||||
feature.getLocation().getLatitude() <= top) { |
||||
call.write(feature); |
||||
} |
||||
}); |
||||
call.end(); |
||||
} |
||||
|
||||
/** |
||||
* Calculate the distance between two points using the "haversine" formula. |
||||
* This code was taken from http://www.movable-type.co.uk/scripts/latlong.html.
|
||||
* @param start The starting point |
||||
* @param end The end point |
||||
* @return The distance between the points in meters |
||||
*/ |
||||
function getDistance(start, end) { |
||||
function toRadians(num) { |
||||
return num * Math.PI / 180; |
||||
} |
||||
var lat1 = start.getLatitude() / COORD_FACTOR; |
||||
var lat2 = end.getLatitude() / COORD_FACTOR; |
||||
var lon1 = start.getLongitude() / COORD_FACTOR; |
||||
var lon2 = end.getLongitude() / COORD_FACTOR; |
||||
var R = 6371000; // metres
|
||||
var φ1 = toRadians(lat1); |
||||
var φ2 = toRadians(lat2); |
||||
var Δφ = toRadians(lat2-lat1); |
||||
var Δλ = toRadians(lon2-lon1); |
||||
|
||||
var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) + |
||||
Math.cos(φ1) * Math.cos(φ2) * |
||||
Math.sin(Δλ/2) * Math.sin(Δλ/2); |
||||
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); |
||||
|
||||
return R * c; |
||||
} |
||||
|
||||
/** |
||||
* recordRoute handler. Gets a stream of points, and responds with statistics |
||||
* about the "trip": number of points, number of known features visited, total |
||||
* distance traveled, and total time spent. |
||||
* @param {Readable} call The request point stream. |
||||
* @param {function(Error, routeSummary)} callback The callback to pass the |
||||
* response to |
||||
*/ |
||||
function recordRoute(call, callback) { |
||||
var point_count = 0; |
||||
var feature_count = 0; |
||||
var distance = 0; |
||||
var previous = null; |
||||
// Start a timer
|
||||
var start_time = process.hrtime(); |
||||
call.on('data', function(point) { |
||||
point_count += 1; |
||||
if (checkFeature(point).name !== '') { |
||||
feature_count += 1; |
||||
} |
||||
/* For each point after the first, add the incremental distance from the |
||||
* previous point to the total distance value */ |
||||
if (previous != null) { |
||||
distance += getDistance(previous, point); |
||||
} |
||||
previous = point; |
||||
}); |
||||
call.on('end', function() { |
||||
var summary = new messages.RouteSummary(); |
||||
summary.setPointCount(point_count); |
||||
summary.setFeatureCount(feature_count); |
||||
// Cast the distance to an integer
|
||||
summary.setDistance(distance|0); |
||||
// End the timer
|
||||
summary.setElapsedTime(process.hrtime(start_time)[0]); |
||||
callback(null, summary); |
||||
}); |
||||
} |
||||
|
||||
var route_notes = {}; |
||||
|
||||
/** |
||||
* Turn the point into a dictionary key. |
||||
* @param {point} point The point to use |
||||
* @return {string} The key for an object |
||||
*/ |
||||
function pointKey(point) { |
||||
return point.getLatitude() + ' ' + point.getLongitude(); |
||||
} |
||||
|
||||
/** |
||||
* routeChat handler. Receives a stream of message/location pairs, and responds |
||||
* with a stream of all previous messages at each of those locations. |
||||
* @param {Duplex} call The stream for incoming and outgoing messages |
||||
*/ |
||||
function routeChat(call) { |
||||
call.on('data', function(note) { |
||||
var key = pointKey(note.getLocation()); |
||||
/* For each note sent, respond with all previous notes that correspond to |
||||
* the same point */ |
||||
if (route_notes.hasOwnProperty(key)) { |
||||
_.each(route_notes[key], function(note) { |
||||
call.write(note); |
||||
}); |
||||
} else { |
||||
route_notes[key] = []; |
||||
} |
||||
// Then add the new note to the list
|
||||
route_notes[key].push(note); |
||||
}); |
||||
call.on('end', function() { |
||||
call.end(); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* Get a new server with the handler functions in this file bound to the methods |
||||
* it serves. |
||||
* @return {Server} The new server object |
||||
*/ |
||||
function getServer() { |
||||
var server = new grpc.Server(); |
||||
server.addService(services.RouteGuideService, { |
||||
getFeature: getFeature, |
||||
listFeatures: listFeatures, |
||||
recordRoute: recordRoute, |
||||
routeChat: routeChat |
||||
}); |
||||
return server; |
||||
} |
||||
|
||||
if (require.main === module) { |
||||
// If this is run as a script, start a server on an unused port
|
||||
var routeServer = getServer(); |
||||
routeServer.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure()); |
||||
var argv = parseArgs(process.argv, { |
||||
string: 'db_path' |
||||
}); |
||||
fs.readFile(path.resolve(argv.db_path), function(err, data) { |
||||
if (err) throw err; |
||||
// Transform the loaded features to Feature objects
|
||||
feature_list = _.map(JSON.parse(data), function(value) { |
||||
var feature = new messages.Feature(); |
||||
feature.setName(value.name); |
||||
var location = new messages.Point(); |
||||
location.setLatitude(value.location.latitude); |
||||
location.setLongitude(value.location.longitude); |
||||
feature.setLocation(location); |
||||
return feature; |
||||
}); |
||||
routeServer.start(); |
||||
}); |
||||
} |
||||
|
||||
exports.getServer = getServer; |
@ -0,0 +1,91 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<Scheme |
||||
LastUpgradeVersion = "0730" |
||||
version = "1.3"> |
||||
<BuildAction |
||||
parallelizeBuildables = "YES" |
||||
buildImplicitDependencies = "YES"> |
||||
<BuildActionEntries> |
||||
<BuildActionEntry |
||||
buildForTesting = "YES" |
||||
buildForRunning = "YES" |
||||
buildForProfiling = "YES" |
||||
buildForArchiving = "YES" |
||||
buildForAnalyzing = "YES"> |
||||
<BuildableReference |
||||
BuildableIdentifier = "primary" |
||||
BlueprintIdentifier = "63E1E97B1B28CB2000EF0978" |
||||
BuildableName = "AuthSample.app" |
||||
BlueprintName = "AuthSample" |
||||
ReferencedContainer = "container:AuthSample.xcodeproj"> |
||||
</BuildableReference> |
||||
</BuildActionEntry> |
||||
</BuildActionEntries> |
||||
</BuildAction> |
||||
<TestAction |
||||
buildConfiguration = "Debug" |
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" |
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" |
||||
shouldUseLaunchSchemeArgsEnv = "YES"> |
||||
<Testables> |
||||
</Testables> |
||||
<MacroExpansion> |
||||
<BuildableReference |
||||
BuildableIdentifier = "primary" |
||||
BlueprintIdentifier = "63E1E97B1B28CB2000EF0978" |
||||
BuildableName = "AuthSample.app" |
||||
BlueprintName = "AuthSample" |
||||
ReferencedContainer = "container:AuthSample.xcodeproj"> |
||||
</BuildableReference> |
||||
</MacroExpansion> |
||||
<AdditionalOptions> |
||||
</AdditionalOptions> |
||||
</TestAction> |
||||
<LaunchAction |
||||
buildConfiguration = "Debug" |
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" |
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" |
||||
launchStyle = "0" |
||||
useCustomWorkingDirectory = "NO" |
||||
ignoresPersistentStateOnLaunch = "NO" |
||||
debugDocumentVersioning = "YES" |
||||
debugServiceExtension = "internal" |
||||
allowLocationSimulation = "YES"> |
||||
<BuildableProductRunnable |
||||
runnableDebuggingMode = "0"> |
||||
<BuildableReference |
||||
BuildableIdentifier = "primary" |
||||
BlueprintIdentifier = "63E1E97B1B28CB2000EF0978" |
||||
BuildableName = "AuthSample.app" |
||||
BlueprintName = "AuthSample" |
||||
ReferencedContainer = "container:AuthSample.xcodeproj"> |
||||
</BuildableReference> |
||||
</BuildableProductRunnable> |
||||
<AdditionalOptions> |
||||
</AdditionalOptions> |
||||
</LaunchAction> |
||||
<ProfileAction |
||||
buildConfiguration = "Release" |
||||
shouldUseLaunchSchemeArgsEnv = "YES" |
||||
savedToolIdentifier = "" |
||||
useCustomWorkingDirectory = "NO" |
||||
debugDocumentVersioning = "YES"> |
||||
<BuildableProductRunnable |
||||
runnableDebuggingMode = "0"> |
||||
<BuildableReference |
||||
BuildableIdentifier = "primary" |
||||
BlueprintIdentifier = "63E1E97B1B28CB2000EF0978" |
||||
BuildableName = "AuthSample.app" |
||||
BlueprintName = "AuthSample" |
||||
ReferencedContainer = "container:AuthSample.xcodeproj"> |
||||
</BuildableReference> |
||||
</BuildableProductRunnable> |
||||
</ProfileAction> |
||||
<AnalyzeAction |
||||
buildConfiguration = "Debug"> |
||||
</AnalyzeAction> |
||||
<ArchiveAction |
||||
buildConfiguration = "Release" |
||||
revealArchiveInOrganizer = "YES"> |
||||
</ArchiveAction> |
||||
</Scheme> |
@ -0,0 +1,91 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<Scheme |
||||
LastUpgradeVersion = "0730" |
||||
version = "1.3"> |
||||
<BuildAction |
||||
parallelizeBuildables = "YES" |
||||
buildImplicitDependencies = "YES"> |
||||
<BuildActionEntries> |
||||
<BuildActionEntry |
||||
buildForTesting = "YES" |
||||
buildForRunning = "YES" |
||||
buildForProfiling = "YES" |
||||
buildForArchiving = "YES" |
||||
buildForAnalyzing = "YES"> |
||||
<BuildableReference |
||||
BuildableIdentifier = "primary" |
||||
BlueprintIdentifier = "5E36905F1B2A23800040F884" |
||||
BuildableName = "HelloWorld.app" |
||||
BlueprintName = "HelloWorld" |
||||
ReferencedContainer = "container:HelloWorld.xcodeproj"> |
||||
</BuildableReference> |
||||
</BuildActionEntry> |
||||
</BuildActionEntries> |
||||
</BuildAction> |
||||
<TestAction |
||||
buildConfiguration = "Debug" |
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" |
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" |
||||
shouldUseLaunchSchemeArgsEnv = "YES"> |
||||
<Testables> |
||||
</Testables> |
||||
<MacroExpansion> |
||||
<BuildableReference |
||||
BuildableIdentifier = "primary" |
||||
BlueprintIdentifier = "5E36905F1B2A23800040F884" |
||||
BuildableName = "HelloWorld.app" |
||||
BlueprintName = "HelloWorld" |
||||
ReferencedContainer = "container:HelloWorld.xcodeproj"> |
||||
</BuildableReference> |
||||
</MacroExpansion> |
||||
<AdditionalOptions> |
||||
</AdditionalOptions> |
||||
</TestAction> |
||||
<LaunchAction |
||||
buildConfiguration = "Debug" |
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" |
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" |
||||
launchStyle = "0" |
||||
useCustomWorkingDirectory = "NO" |
||||
ignoresPersistentStateOnLaunch = "NO" |
||||
debugDocumentVersioning = "YES" |
||||
debugServiceExtension = "internal" |
||||
allowLocationSimulation = "YES"> |
||||
<BuildableProductRunnable |
||||
runnableDebuggingMode = "0"> |
||||
<BuildableReference |
||||
BuildableIdentifier = "primary" |
||||
BlueprintIdentifier = "5E36905F1B2A23800040F884" |
||||
BuildableName = "HelloWorld.app" |
||||
BlueprintName = "HelloWorld" |
||||
ReferencedContainer = "container:HelloWorld.xcodeproj"> |
||||
</BuildableReference> |
||||
</BuildableProductRunnable> |
||||
<AdditionalOptions> |
||||
</AdditionalOptions> |
||||
</LaunchAction> |
||||
<ProfileAction |
||||
buildConfiguration = "Release" |
||||
shouldUseLaunchSchemeArgsEnv = "YES" |
||||
savedToolIdentifier = "" |
||||
useCustomWorkingDirectory = "NO" |
||||
debugDocumentVersioning = "YES"> |
||||
<BuildableProductRunnable |
||||
runnableDebuggingMode = "0"> |
||||
<BuildableReference |
||||
BuildableIdentifier = "primary" |
||||
BlueprintIdentifier = "5E36905F1B2A23800040F884" |
||||
BuildableName = "HelloWorld.app" |
||||
BlueprintName = "HelloWorld" |
||||
ReferencedContainer = "container:HelloWorld.xcodeproj"> |
||||
</BuildableReference> |
||||
</BuildableProductRunnable> |
||||
</ProfileAction> |
||||
<AnalyzeAction |
||||
buildConfiguration = "Debug"> |
||||
</AnalyzeAction> |
||||
<ArchiveAction |
||||
buildConfiguration = "Release" |
||||
revealArchiveInOrganizer = "YES"> |
||||
</ArchiveAction> |
||||
</Scheme> |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue