commit
11537dc71c
313 changed files with 28495 additions and 8316 deletions
@ -1,189 +1,3 @@ |
|||||||
#OAuth2 on gRPC: Objective-C |
#OAuth2 on gRPC: Objective-C |
||||||
|
|
||||||
This example application demostrates how to use OAuth2 on gRPC to make authenticated API calls on |
This is the supporting code for the tutorial "[OAuth2 on gRPC: Objective-C](http://www.grpc.io/docs/tutorials/auth/oauth2-objective-c.html)." |
||||||
behalf of a user. By walking through it you'll learn how to use the Objective-C gRPC API to: |
|
||||||
|
|
||||||
- Initialize and configure a remote call object before the RPC is started. |
|
||||||
- Set request metadata elements on a call, which are semantically equivalent to HTTP request |
|
||||||
headers. |
|
||||||
- Read response metadata from a call, which is equivalent to HTTP response headers and trailers. |
|
||||||
|
|
||||||
It assumes you know the basics on how to make gRPC API calls using the Objective-C client library, |
|
||||||
as shown in the [Hello World](../helloworld) |
|
||||||
or [Route Guide](../route_guide) tutorials, |
|
||||||
and are familiar with OAuth2 concepts like _access token_. |
|
||||||
|
|
||||||
- [Example code and setup](#setup) |
|
||||||
- [Try it out!](#try) |
|
||||||
- [Create an RPC object and start it later](#rpc-object) |
|
||||||
- [Set request metadata of a call: Authorization header with an access token](#request-metadata) |
|
||||||
- [Get response metadata of a call: Auth challenge header](#response-metadata) |
|
||||||
|
|
||||||
<a name="setup"></a> |
|
||||||
## Example code and setup |
|
||||||
|
|
||||||
The example code for our tutorial is in [examples/objective-c/auth_sample](.). |
|
||||||
To download the example, clone this repository by running the following command: |
|
||||||
```shell |
|
||||||
$ git clone https://github.com/grpc/grpc.git |
|
||||||
``` |
|
||||||
|
|
||||||
Then change your current directory to `examples/objective-c/auth_sample`: |
|
||||||
```shell |
|
||||||
$ cd examples/objective-c/auth_sample |
|
||||||
``` |
|
||||||
|
|
||||||
Our example is a simple application with two views. The first one lets a user sign in and out using |
|
||||||
the OAuth2 flow of Google's [iOS SignIn library](https://developers.google.com/identity/sign-in/ios/). |
|
||||||
(Google's library is used in this example because the test gRPC service we are going to call expects |
|
||||||
Google account credentials, but neither gRPC nor the Objective-C client library is tied to any |
|
||||||
specific OAuth2 provider). The second view makes a gRPC request to the test server, using the |
|
||||||
access token obtained by the first view. |
|
||||||
|
|
||||||
Note: OAuth2 libraries need the application to register and obtain an ID from the identity provider |
|
||||||
(in the case of this example app, Google). The app's XCode project is configured using that ID, so |
|
||||||
you shouldn't copy this project "as is" for your own app: it would result in your app being |
|
||||||
identified in the consent screen as "gRPC-AuthSample", and not having access to real Google |
|
||||||
services. Instead, configure your own XCode project following the [instructions here](https://developers.google.com/identity/sign-in/ios/). |
|
||||||
|
|
||||||
As with the other examples, you also should have [Cocoapods](https://cocoapods.org/#install) |
|
||||||
installed, as well as the relevant tools to generate the client library code. You can obtain the |
|
||||||
latter by following [these setup instructions](https://github.com/grpc/homebrew-grpc). |
|
||||||
|
|
||||||
|
|
||||||
<a name="try"></a> |
|
||||||
## Try it out! |
|
||||||
|
|
||||||
To try the sample app, first have Cocoapods generate and install the client library for our .proto |
|
||||||
files: |
|
||||||
|
|
||||||
```shell |
|
||||||
$ pod install |
|
||||||
``` |
|
||||||
|
|
||||||
(This might have to compile OpenSSL, which takes around 15 minutes if Cocoapods doesn't have it yet |
|
||||||
on your computer's cache). |
|
||||||
|
|
||||||
Finally, open the XCode workspace created by Cocoapods, and run the app. |
|
||||||
|
|
||||||
The first view, `SelectUserViewController.h/m`, asks you to sign in with your Google account, and to |
|
||||||
give the "gRPC-AuthSample" app the following permissions: |
|
||||||
|
|
||||||
- View your email address. |
|
||||||
- View your basic profile info. |
|
||||||
- "Test scope for access to the Zoo service". |
|
||||||
|
|
||||||
This last permission, corresponding to the scope `https://www.googleapis.com/auth/xapi.zoo` doesn't |
|
||||||
grant any real capability: it's only used for testing. You can log out at any time. |
|
||||||
|
|
||||||
The second view, `MakeRPCViewController.h/m`, makes a gRPC request to a test server at |
|
||||||
https://grpc-test.sandbox.google.com, sending the access token along with the request. The test |
|
||||||
service simply validates the token and writes in its response which user it belongs to, and which |
|
||||||
scopes it gives access to. (The client application already knows those two values; it's a way to |
|
||||||
verify that everything went as expected). |
|
||||||
|
|
||||||
The next sections guide you step-by-step through how the gRPC call in `MakeRPCViewController` is |
|
||||||
performed. |
|
||||||
|
|
||||||
<a name="rpc-object"></a> |
|
||||||
## Create an RPC object and start it later |
|
||||||
|
|
||||||
The other basic tutorials show how to invoke an RPC by calling an asynchronous method in a generated |
|
||||||
client object. This shows how to initialize an object that represents the RPC, and configure it |
|
||||||
before starting the network request. |
|
||||||
|
|
||||||
Assume you have a proto service definition like this: |
|
||||||
|
|
||||||
```protobuf |
|
||||||
option objc_class_prefix = "AUTH"; |
|
||||||
|
|
||||||
service TestService { |
|
||||||
rpc UnaryCall(Request) returns (Response); |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
A `unaryCallWithRequest:handler:` method, with which you're already familiar, is generated for the |
|
||||||
`AUTHTestService` class: |
|
||||||
|
|
||||||
```objective-c |
|
||||||
[client unaryCallWithRequest:request handler:^(AUTHResponse *response, NSError *error) { |
|
||||||
... |
|
||||||
}]; |
|
||||||
``` |
|
||||||
|
|
||||||
In addition, an `RPCToUnaryCallWithRequest:handler:` method is generated, which returns a |
|
||||||
not-yet-started RPC object: |
|
||||||
|
|
||||||
```objective-c |
|
||||||
#import <ProtoRPC/ProtoRPC.h> |
|
||||||
|
|
||||||
ProtoRPC *call = |
|
||||||
[client RPCToUnaryCallWithRequest:request handler:^(AUTHResponse *response, NSError *error) { |
|
||||||
... |
|
||||||
}]; |
|
||||||
``` |
|
||||||
|
|
||||||
The RPC represented by this object can be started at any later time like this: |
|
||||||
|
|
||||||
```objective-c |
|
||||||
[call start]; |
|
||||||
``` |
|
||||||
|
|
||||||
<a name="request-metadata"></a> |
|
||||||
## Set request metadata of a call: Authorization header with an access token |
|
||||||
|
|
||||||
The `ProtoRPC` class has a `requestMetadata` property (inherited from `GRPCCall`) defined like this: |
|
||||||
|
|
||||||
```objective-c |
|
||||||
- (NSMutableDictionary *)requestMetadata; // nonatomic |
|
||||||
- (void)setRequestMetadata:(NSDictionary *)requestMetadata; // nonatomic, copy |
|
||||||
``` |
|
||||||
|
|
||||||
Setting it to a dictionary of metadata keys and values will have them sent on the wire when the call |
|
||||||
is started. gRPC metadata are pieces of information about the call sent by the client to the server |
|
||||||
(and vice versa). They take the form of key-value pairs and are essentially opaque to gRPC itself. |
|
||||||
|
|
||||||
```objective-c |
|
||||||
call.requestMetadata = @{@"My-Header": @"Value for this header", |
|
||||||
@"Another-Header": @"Its value"}; |
|
||||||
``` |
|
||||||
|
|
||||||
For convenience, the property is initialized with an empty `NSMutableDictionary`, so that request |
|
||||||
metadata elements can be set like this: |
|
||||||
|
|
||||||
```objective-c |
|
||||||
call.requestMetadata[@"My-Header"] = @"Value for this header"; |
|
||||||
``` |
|
||||||
|
|
||||||
If you have an access token, OAuth2 specifies it is to be sent in this format: |
|
||||||
|
|
||||||
```objective-c |
|
||||||
call.requestMetadata[@"Authorization"] = [@"Bearer " stringByAppendingString:accessToken]; |
|
||||||
``` |
|
||||||
|
|
||||||
<a name="response-metadata"></a> |
|
||||||
## Get response metadata of a call: Auth challenge header |
|
||||||
|
|
||||||
The `ProtoRPC` class also inherits a `responseMetadata` property, analogous to the request metadata |
|
||||||
we just looked at. It's defined like this: |
|
||||||
|
|
||||||
```objective-c |
|
||||||
@property(atomic, readonly) NSDictionary *responseMetadata; |
|
||||||
``` |
|
||||||
|
|
||||||
To access OAuth2's authentication challenge header you write: |
|
||||||
|
|
||||||
```objective-c |
|
||||||
call.responseMetadata[@"www-authenticate"] |
|
||||||
``` |
|
||||||
|
|
||||||
Note that, as gRPC metadata elements are mapped to HTTP/2 headers (or trailers), the keys of the |
|
||||||
response metadata are always ASCII strings in lowercase. |
|
||||||
|
|
||||||
Many uses cases of response metadata are getting more details about an RPC error. For convenience, |
|
||||||
when a `NSError` instance is passed to an RPC handler block, the response metadata dictionary can |
|
||||||
also be accessed this way: |
|
||||||
|
|
||||||
```objective-c |
|
||||||
error.userInfo[kGRPCStatusMetadataKey] |
|
||||||
``` |
|
||||||
|
@ -0,0 +1,572 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* 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 "src/core/channel/client_uchannel.h" |
||||||
|
|
||||||
|
#include <string.h> |
||||||
|
|
||||||
|
#include "src/core/census/grpc_filter.h" |
||||||
|
#include "src/core/channel/channel_args.h" |
||||||
|
#include "src/core/channel/client_channel.h" |
||||||
|
#include "src/core/channel/compress_filter.h" |
||||||
|
#include "src/core/iomgr/iomgr.h" |
||||||
|
#include "src/core/support/string.h" |
||||||
|
#include "src/core/surface/channel.h" |
||||||
|
#include "src/core/transport/connectivity_state.h" |
||||||
|
|
||||||
|
#include <grpc/support/alloc.h> |
||||||
|
#include <grpc/support/log.h> |
||||||
|
#include <grpc/support/sync.h> |
||||||
|
#include <grpc/support/useful.h> |
||||||
|
|
||||||
|
/** Microchannel (uchannel) implementation: a lightweight channel without any
|
||||||
|
* load-balancing mechanisms meant for communication from within the core. */ |
||||||
|
|
||||||
|
typedef struct call_data call_data; |
||||||
|
|
||||||
|
typedef struct client_uchannel_channel_data { |
||||||
|
/** metadata context for this channel */ |
||||||
|
grpc_mdctx *mdctx; |
||||||
|
|
||||||
|
/** master channel - the grpc_channel instance that ultimately owns
|
||||||
|
this channel_data via its channel stack. |
||||||
|
We occasionally use this to bump the refcount on the master channel |
||||||
|
to keep ourselves alive through an asynchronous operation. */ |
||||||
|
grpc_channel *master; |
||||||
|
|
||||||
|
/** connectivity state being tracked */ |
||||||
|
grpc_connectivity_state_tracker state_tracker; |
||||||
|
|
||||||
|
/** the subchannel wrapped by the microchannel */ |
||||||
|
grpc_subchannel *subchannel; |
||||||
|
|
||||||
|
/** the callback used to stay subscribed to subchannel connectivity
|
||||||
|
* notifications */ |
||||||
|
grpc_closure connectivity_cb; |
||||||
|
|
||||||
|
/** the current connectivity state of the wrapped subchannel */ |
||||||
|
grpc_connectivity_state subchannel_connectivity; |
||||||
|
|
||||||
|
gpr_mu mu_state; |
||||||
|
} channel_data; |
||||||
|
|
||||||
|
typedef enum { |
||||||
|
CALL_CREATED, |
||||||
|
CALL_WAITING_FOR_SEND, |
||||||
|
CALL_WAITING_FOR_CALL, |
||||||
|
CALL_ACTIVE, |
||||||
|
CALL_CANCELLED |
||||||
|
} call_state; |
||||||
|
|
||||||
|
struct call_data { |
||||||
|
/* owning element */ |
||||||
|
grpc_call_element *elem; |
||||||
|
|
||||||
|
gpr_mu mu_state; |
||||||
|
|
||||||
|
call_state state; |
||||||
|
gpr_timespec deadline; |
||||||
|
grpc_closure async_setup_task; |
||||||
|
grpc_transport_stream_op waiting_op; |
||||||
|
/* our child call stack */ |
||||||
|
grpc_subchannel_call *subchannel_call; |
||||||
|
grpc_linked_mdelem status; |
||||||
|
grpc_linked_mdelem details; |
||||||
|
}; |
||||||
|
|
||||||
|
static grpc_closure *merge_into_waiting_op(grpc_call_element *elem, |
||||||
|
grpc_transport_stream_op *new_op) |
||||||
|
GRPC_MUST_USE_RESULT; |
||||||
|
|
||||||
|
static void handle_op_after_cancellation(grpc_exec_ctx *exec_ctx, |
||||||
|
grpc_call_element *elem, |
||||||
|
grpc_transport_stream_op *op) { |
||||||
|
call_data *calld = elem->call_data; |
||||||
|
channel_data *chand = elem->channel_data; |
||||||
|
if (op->send_ops) { |
||||||
|
grpc_stream_ops_unref_owned_objects(op->send_ops->ops, op->send_ops->nops); |
||||||
|
op->on_done_send->cb(exec_ctx, op->on_done_send->cb_arg, 0); |
||||||
|
} |
||||||
|
if (op->recv_ops) { |
||||||
|
char status[GPR_LTOA_MIN_BUFSIZE]; |
||||||
|
grpc_metadata_batch mdb; |
||||||
|
gpr_ltoa(GRPC_STATUS_CANCELLED, status); |
||||||
|
calld->status.md = |
||||||
|
grpc_mdelem_from_strings(chand->mdctx, "grpc-status", status); |
||||||
|
calld->details.md = |
||||||
|
grpc_mdelem_from_strings(chand->mdctx, "grpc-message", "Cancelled"); |
||||||
|
calld->status.prev = calld->details.next = NULL; |
||||||
|
calld->status.next = &calld->details; |
||||||
|
calld->details.prev = &calld->status; |
||||||
|
mdb.list.head = &calld->status; |
||||||
|
mdb.list.tail = &calld->details; |
||||||
|
mdb.garbage.head = mdb.garbage.tail = NULL; |
||||||
|
mdb.deadline = gpr_inf_future(GPR_CLOCK_REALTIME); |
||||||
|
grpc_sopb_add_metadata(op->recv_ops, mdb); |
||||||
|
*op->recv_state = GRPC_STREAM_CLOSED; |
||||||
|
op->on_done_recv->cb(exec_ctx, op->on_done_recv->cb_arg, 1); |
||||||
|
} |
||||||
|
if (op->on_consumed) { |
||||||
|
op->on_consumed->cb(exec_ctx, op->on_consumed->cb_arg, 0); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
typedef struct { |
||||||
|
grpc_closure closure; |
||||||
|
grpc_call_element *elem; |
||||||
|
} waiting_call; |
||||||
|
|
||||||
|
static void perform_transport_stream_op(grpc_exec_ctx *exec_ctx, |
||||||
|
grpc_call_element *elem, |
||||||
|
grpc_transport_stream_op *op, |
||||||
|
int continuation); |
||||||
|
|
||||||
|
static int is_empty(void *p, int len) { |
||||||
|
char *ptr = p; |
||||||
|
int i; |
||||||
|
for (i = 0; i < len; i++) { |
||||||
|
if (ptr[i] != 0) return 0; |
||||||
|
} |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
static void monitor_subchannel(grpc_exec_ctx *exec_ctx, void *arg, |
||||||
|
int iomgr_success) { |
||||||
|
channel_data *chand = arg; |
||||||
|
grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, |
||||||
|
chand->subchannel_connectivity, |
||||||
|
"uchannel_monitor_subchannel"); |
||||||
|
grpc_subchannel_notify_on_state_change(exec_ctx, chand->subchannel, |
||||||
|
&chand->subchannel_connectivity, |
||||||
|
&chand->connectivity_cb); |
||||||
|
} |
||||||
|
|
||||||
|
static void started_call_locked(grpc_exec_ctx *exec_ctx, void *arg, |
||||||
|
int iomgr_success) { |
||||||
|
call_data *calld = arg; |
||||||
|
grpc_transport_stream_op op; |
||||||
|
int have_waiting; |
||||||
|
|
||||||
|
if (calld->state == CALL_CANCELLED && iomgr_success == 0) { |
||||||
|
have_waiting = !is_empty(&calld->waiting_op, sizeof(calld->waiting_op)); |
||||||
|
gpr_mu_unlock(&calld->mu_state); |
||||||
|
if (have_waiting) { |
||||||
|
handle_op_after_cancellation(exec_ctx, calld->elem, &calld->waiting_op); |
||||||
|
} |
||||||
|
} else if (calld->state == CALL_CANCELLED && calld->subchannel_call != NULL) { |
||||||
|
memset(&op, 0, sizeof(op)); |
||||||
|
op.cancel_with_status = GRPC_STATUS_CANCELLED; |
||||||
|
gpr_mu_unlock(&calld->mu_state); |
||||||
|
grpc_subchannel_call_process_op(exec_ctx, calld->subchannel_call, &op); |
||||||
|
} else if (calld->state == CALL_WAITING_FOR_CALL) { |
||||||
|
have_waiting = !is_empty(&calld->waiting_op, sizeof(calld->waiting_op)); |
||||||
|
if (calld->subchannel_call != NULL) { |
||||||
|
calld->state = CALL_ACTIVE; |
||||||
|
gpr_mu_unlock(&calld->mu_state); |
||||||
|
if (have_waiting) { |
||||||
|
grpc_subchannel_call_process_op(exec_ctx, calld->subchannel_call, |
||||||
|
&calld->waiting_op); |
||||||
|
} |
||||||
|
} else { |
||||||
|
calld->state = CALL_CANCELLED; |
||||||
|
gpr_mu_unlock(&calld->mu_state); |
||||||
|
if (have_waiting) { |
||||||
|
handle_op_after_cancellation(exec_ctx, calld->elem, &calld->waiting_op); |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
GPR_ASSERT(calld->state == CALL_CANCELLED); |
||||||
|
gpr_mu_unlock(&calld->mu_state); |
||||||
|
have_waiting = !is_empty(&calld->waiting_op, sizeof(calld->waiting_op)); |
||||||
|
if (have_waiting) { |
||||||
|
handle_op_after_cancellation(exec_ctx, calld->elem, &calld->waiting_op); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static void started_call(grpc_exec_ctx *exec_ctx, void *arg, |
||||||
|
int iomgr_success) { |
||||||
|
call_data *calld = arg; |
||||||
|
gpr_mu_lock(&calld->mu_state); |
||||||
|
started_call_locked(exec_ctx, arg, iomgr_success); |
||||||
|
} |
||||||
|
|
||||||
|
static grpc_closure *merge_into_waiting_op(grpc_call_element *elem, |
||||||
|
grpc_transport_stream_op *new_op) { |
||||||
|
call_data *calld = elem->call_data; |
||||||
|
grpc_closure *consumed_op = NULL; |
||||||
|
grpc_transport_stream_op *waiting_op = &calld->waiting_op; |
||||||
|
GPR_ASSERT((waiting_op->send_ops != NULL) + (new_op->send_ops != NULL) <= 1); |
||||||
|
GPR_ASSERT((waiting_op->recv_ops != NULL) + (new_op->recv_ops != NULL) <= 1); |
||||||
|
if (new_op->send_ops != NULL) { |
||||||
|
waiting_op->send_ops = new_op->send_ops; |
||||||
|
waiting_op->is_last_send = new_op->is_last_send; |
||||||
|
waiting_op->on_done_send = new_op->on_done_send; |
||||||
|
} |
||||||
|
if (new_op->recv_ops != NULL) { |
||||||
|
waiting_op->recv_ops = new_op->recv_ops; |
||||||
|
waiting_op->recv_state = new_op->recv_state; |
||||||
|
waiting_op->on_done_recv = new_op->on_done_recv; |
||||||
|
} |
||||||
|
if (new_op->on_consumed != NULL) { |
||||||
|
if (waiting_op->on_consumed != NULL) { |
||||||
|
consumed_op = waiting_op->on_consumed; |
||||||
|
} |
||||||
|
waiting_op->on_consumed = new_op->on_consumed; |
||||||
|
} |
||||||
|
if (new_op->cancel_with_status != GRPC_STATUS_OK) { |
||||||
|
waiting_op->cancel_with_status = new_op->cancel_with_status; |
||||||
|
} |
||||||
|
return consumed_op; |
||||||
|
} |
||||||
|
|
||||||
|
static char *cuc_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { |
||||||
|
call_data *calld = elem->call_data; |
||||||
|
channel_data *chand = elem->channel_data; |
||||||
|
grpc_subchannel_call *subchannel_call; |
||||||
|
char *result; |
||||||
|
|
||||||
|
gpr_mu_lock(&calld->mu_state); |
||||||
|
if (calld->state == CALL_ACTIVE) { |
||||||
|
subchannel_call = calld->subchannel_call; |
||||||
|
GRPC_SUBCHANNEL_CALL_REF(subchannel_call, "get_peer"); |
||||||
|
gpr_mu_unlock(&calld->mu_state); |
||||||
|
result = grpc_subchannel_call_get_peer(exec_ctx, subchannel_call); |
||||||
|
GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, subchannel_call, "get_peer"); |
||||||
|
return result; |
||||||
|
} else { |
||||||
|
gpr_mu_unlock(&calld->mu_state); |
||||||
|
return grpc_channel_get_target(chand->master); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static void perform_transport_stream_op(grpc_exec_ctx *exec_ctx, |
||||||
|
grpc_call_element *elem, |
||||||
|
grpc_transport_stream_op *op, |
||||||
|
int continuation) { |
||||||
|
call_data *calld = elem->call_data; |
||||||
|
channel_data *chand = elem->channel_data; |
||||||
|
grpc_subchannel_call *subchannel_call; |
||||||
|
grpc_transport_stream_op op2; |
||||||
|
GPR_ASSERT(elem->filter == &grpc_client_uchannel_filter); |
||||||
|
GRPC_CALL_LOG_OP(GPR_INFO, elem, op); |
||||||
|
|
||||||
|
gpr_mu_lock(&calld->mu_state); |
||||||
|
/* make sure the wrapped subchannel has been set (see
|
||||||
|
* grpc_client_uchannel_set_subchannel) */ |
||||||
|
GPR_ASSERT(chand->subchannel != NULL); |
||||||
|
|
||||||
|
switch (calld->state) { |
||||||
|
case CALL_ACTIVE: |
||||||
|
GPR_ASSERT(!continuation); |
||||||
|
subchannel_call = calld->subchannel_call; |
||||||
|
gpr_mu_unlock(&calld->mu_state); |
||||||
|
grpc_subchannel_call_process_op(exec_ctx, subchannel_call, op); |
||||||
|
break; |
||||||
|
case CALL_CANCELLED: |
||||||
|
gpr_mu_unlock(&calld->mu_state); |
||||||
|
handle_op_after_cancellation(exec_ctx, elem, op); |
||||||
|
break; |
||||||
|
case CALL_WAITING_FOR_SEND: |
||||||
|
GPR_ASSERT(!continuation); |
||||||
|
grpc_exec_ctx_enqueue(exec_ctx, merge_into_waiting_op(elem, op), 1); |
||||||
|
if (!calld->waiting_op.send_ops && |
||||||
|
calld->waiting_op.cancel_with_status == GRPC_STATUS_OK) { |
||||||
|
gpr_mu_unlock(&calld->mu_state); |
||||||
|
break; |
||||||
|
} |
||||||
|
*op = calld->waiting_op; |
||||||
|
memset(&calld->waiting_op, 0, sizeof(calld->waiting_op)); |
||||||
|
continuation = 1; |
||||||
|
/* fall through */ |
||||||
|
case CALL_WAITING_FOR_CALL: |
||||||
|
if (!continuation) { |
||||||
|
if (op->cancel_with_status != GRPC_STATUS_OK) { |
||||||
|
calld->state = CALL_CANCELLED; |
||||||
|
op2 = calld->waiting_op; |
||||||
|
memset(&calld->waiting_op, 0, sizeof(calld->waiting_op)); |
||||||
|
if (op->on_consumed) { |
||||||
|
calld->waiting_op.on_consumed = op->on_consumed; |
||||||
|
op->on_consumed = NULL; |
||||||
|
} else if (op2.on_consumed) { |
||||||
|
calld->waiting_op.on_consumed = op2.on_consumed; |
||||||
|
op2.on_consumed = NULL; |
||||||
|
} |
||||||
|
gpr_mu_unlock(&calld->mu_state); |
||||||
|
handle_op_after_cancellation(exec_ctx, elem, op); |
||||||
|
handle_op_after_cancellation(exec_ctx, elem, &op2); |
||||||
|
grpc_subchannel_cancel_waiting_call(exec_ctx, chand->subchannel, 1); |
||||||
|
} else { |
||||||
|
grpc_exec_ctx_enqueue(exec_ctx, merge_into_waiting_op(elem, op), 1); |
||||||
|
gpr_mu_unlock(&calld->mu_state); |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
/* fall through */ |
||||||
|
case CALL_CREATED: |
||||||
|
if (op->cancel_with_status != GRPC_STATUS_OK) { |
||||||
|
calld->state = CALL_CANCELLED; |
||||||
|
gpr_mu_unlock(&calld->mu_state); |
||||||
|
handle_op_after_cancellation(exec_ctx, elem, op); |
||||||
|
} else { |
||||||
|
calld->waiting_op = *op; |
||||||
|
if (op->send_ops == NULL) { |
||||||
|
calld->state = CALL_WAITING_FOR_SEND; |
||||||
|
gpr_mu_unlock(&calld->mu_state); |
||||||
|
} else { |
||||||
|
grpc_subchannel_call_create_status call_creation_status; |
||||||
|
grpc_pollset *pollset = calld->waiting_op.bind_pollset; |
||||||
|
calld->state = CALL_WAITING_FOR_CALL; |
||||||
|
grpc_closure_init(&calld->async_setup_task, started_call, calld); |
||||||
|
call_creation_status = grpc_subchannel_create_call( |
||||||
|
exec_ctx, chand->subchannel, pollset, &calld->subchannel_call, |
||||||
|
&calld->async_setup_task); |
||||||
|
if (call_creation_status == GRPC_SUBCHANNEL_CALL_CREATE_READY) { |
||||||
|
started_call_locked(exec_ctx, calld, 1); |
||||||
|
} else { |
||||||
|
gpr_mu_unlock(&calld->mu_state); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static void cuc_start_transport_stream_op(grpc_exec_ctx *exec_ctx, |
||||||
|
grpc_call_element *elem, |
||||||
|
grpc_transport_stream_op *op) { |
||||||
|
perform_transport_stream_op(exec_ctx, elem, op, 0); |
||||||
|
} |
||||||
|
|
||||||
|
static void cuc_start_transport_op(grpc_exec_ctx *exec_ctx, |
||||||
|
grpc_channel_element *elem, |
||||||
|
grpc_transport_op *op) { |
||||||
|
channel_data *chand = elem->channel_data; |
||||||
|
|
||||||
|
grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, 1); |
||||||
|
|
||||||
|
GPR_ASSERT(op->set_accept_stream == NULL); |
||||||
|
GPR_ASSERT(op->bind_pollset == NULL); |
||||||
|
|
||||||
|
if (op->on_connectivity_state_change != NULL) { |
||||||
|
grpc_connectivity_state_notify_on_state_change( |
||||||
|
exec_ctx, &chand->state_tracker, op->connectivity_state, |
||||||
|
op->on_connectivity_state_change); |
||||||
|
op->on_connectivity_state_change = NULL; |
||||||
|
op->connectivity_state = NULL; |
||||||
|
} |
||||||
|
|
||||||
|
if (op->disconnect) { |
||||||
|
grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, |
||||||
|
GRPC_CHANNEL_FATAL_FAILURE, "disconnect"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* Constructor for call_data */ |
||||||
|
static void cuc_init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, |
||||||
|
const void *server_transport_data, |
||||||
|
grpc_transport_stream_op *initial_op) { |
||||||
|
call_data *calld = elem->call_data; |
||||||
|
memset(calld, 0, sizeof(call_data)); |
||||||
|
|
||||||
|
/* TODO(ctiller): is there something useful we can do here? */ |
||||||
|
GPR_ASSERT(initial_op == NULL); |
||||||
|
|
||||||
|
GPR_ASSERT(elem->filter == &grpc_client_uchannel_filter); |
||||||
|
GPR_ASSERT(server_transport_data == NULL); |
||||||
|
gpr_mu_init(&calld->mu_state); |
||||||
|
calld->elem = elem; |
||||||
|
calld->state = CALL_CREATED; |
||||||
|
calld->deadline = gpr_inf_future(GPR_CLOCK_REALTIME); |
||||||
|
} |
||||||
|
|
||||||
|
/* Destructor for call_data */ |
||||||
|
static void cuc_destroy_call_elem(grpc_exec_ctx *exec_ctx, |
||||||
|
grpc_call_element *elem) { |
||||||
|
call_data *calld = elem->call_data; |
||||||
|
grpc_subchannel_call *subchannel_call; |
||||||
|
|
||||||
|
/* if the call got activated, we need to destroy the child stack also, and
|
||||||
|
remove it from the in-flight requests tracked by the child_entry we |
||||||
|
picked */ |
||||||
|
gpr_mu_lock(&calld->mu_state); |
||||||
|
switch (calld->state) { |
||||||
|
case CALL_ACTIVE: |
||||||
|
subchannel_call = calld->subchannel_call; |
||||||
|
gpr_mu_unlock(&calld->mu_state); |
||||||
|
GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, subchannel_call, "client_uchannel"); |
||||||
|
break; |
||||||
|
case CALL_CREATED: |
||||||
|
case CALL_CANCELLED: |
||||||
|
gpr_mu_unlock(&calld->mu_state); |
||||||
|
break; |
||||||
|
case CALL_WAITING_FOR_CALL: |
||||||
|
case CALL_WAITING_FOR_SEND: |
||||||
|
GPR_UNREACHABLE_CODE(return ); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* Constructor for channel_data */ |
||||||
|
static void cuc_init_channel_elem(grpc_exec_ctx *exec_ctx, |
||||||
|
grpc_channel_element *elem, |
||||||
|
grpc_channel *master, |
||||||
|
const grpc_channel_args *args, |
||||||
|
grpc_mdctx *metadata_context, int is_first, |
||||||
|
int is_last) { |
||||||
|
channel_data *chand = elem->channel_data; |
||||||
|
memset(chand, 0, sizeof(*chand)); |
||||||
|
grpc_closure_init(&chand->connectivity_cb, monitor_subchannel, chand); |
||||||
|
GPR_ASSERT(is_last); |
||||||
|
GPR_ASSERT(elem->filter == &grpc_client_uchannel_filter); |
||||||
|
chand->mdctx = metadata_context; |
||||||
|
chand->master = master; |
||||||
|
grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE, |
||||||
|
"client_uchannel"); |
||||||
|
gpr_mu_init(&chand->mu_state); |
||||||
|
} |
||||||
|
|
||||||
|
/* Destructor for channel_data */ |
||||||
|
static void cuc_destroy_channel_elem(grpc_exec_ctx *exec_ctx, |
||||||
|
grpc_channel_element *elem) { |
||||||
|
channel_data *chand = elem->channel_data; |
||||||
|
grpc_subchannel_state_change_unsubscribe(exec_ctx, chand->subchannel, |
||||||
|
&chand->connectivity_cb); |
||||||
|
grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker); |
||||||
|
gpr_mu_destroy(&chand->mu_state); |
||||||
|
} |
||||||
|
|
||||||
|
const grpc_channel_filter grpc_client_uchannel_filter = { |
||||||
|
cuc_start_transport_stream_op, |
||||||
|
cuc_start_transport_op, |
||||||
|
sizeof(call_data), |
||||||
|
cuc_init_call_elem, |
||||||
|
cuc_destroy_call_elem, |
||||||
|
sizeof(channel_data), |
||||||
|
cuc_init_channel_elem, |
||||||
|
cuc_destroy_channel_elem, |
||||||
|
cuc_get_peer, |
||||||
|
"client-uchannel", |
||||||
|
}; |
||||||
|
|
||||||
|
grpc_connectivity_state grpc_client_uchannel_check_connectivity_state( |
||||||
|
grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect) { |
||||||
|
channel_data *chand = elem->channel_data; |
||||||
|
grpc_connectivity_state out; |
||||||
|
out = grpc_connectivity_state_check(&chand->state_tracker); |
||||||
|
gpr_mu_lock(&chand->mu_state); |
||||||
|
if (out == GRPC_CHANNEL_IDLE && try_to_connect) { |
||||||
|
grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, |
||||||
|
GRPC_CHANNEL_CONNECTING, |
||||||
|
"uchannel_connecting_changed"); |
||||||
|
chand->subchannel_connectivity = out; |
||||||
|
grpc_subchannel_notify_on_state_change(exec_ctx, chand->subchannel, |
||||||
|
&chand->subchannel_connectivity, |
||||||
|
&chand->connectivity_cb); |
||||||
|
} |
||||||
|
gpr_mu_unlock(&chand->mu_state); |
||||||
|
return out; |
||||||
|
} |
||||||
|
|
||||||
|
void grpc_client_uchannel_watch_connectivity_state( |
||||||
|
grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, |
||||||
|
grpc_connectivity_state *state, grpc_closure *on_complete) { |
||||||
|
channel_data *chand = elem->channel_data; |
||||||
|
gpr_mu_lock(&chand->mu_state); |
||||||
|
grpc_connectivity_state_notify_on_state_change( |
||||||
|
exec_ctx, &chand->state_tracker, state, on_complete); |
||||||
|
gpr_mu_unlock(&chand->mu_state); |
||||||
|
} |
||||||
|
|
||||||
|
grpc_pollset_set *grpc_client_uchannel_get_connecting_pollset_set( |
||||||
|
grpc_channel_element *elem) { |
||||||
|
channel_data *chand = elem->channel_data; |
||||||
|
grpc_channel_element *parent_elem; |
||||||
|
gpr_mu_lock(&chand->mu_state); |
||||||
|
parent_elem = grpc_channel_stack_last_element(grpc_channel_get_channel_stack( |
||||||
|
grpc_subchannel_get_master(chand->subchannel))); |
||||||
|
gpr_mu_unlock(&chand->mu_state); |
||||||
|
return grpc_client_channel_get_connecting_pollset_set(parent_elem); |
||||||
|
} |
||||||
|
|
||||||
|
void grpc_client_uchannel_add_interested_party(grpc_exec_ctx *exec_ctx, |
||||||
|
grpc_channel_element *elem, |
||||||
|
grpc_pollset *pollset) { |
||||||
|
grpc_pollset_set *master_pollset_set = |
||||||
|
grpc_client_uchannel_get_connecting_pollset_set(elem); |
||||||
|
grpc_pollset_set_add_pollset(exec_ctx, master_pollset_set, pollset); |
||||||
|
} |
||||||
|
|
||||||
|
void grpc_client_uchannel_del_interested_party(grpc_exec_ctx *exec_ctx, |
||||||
|
grpc_channel_element *elem, |
||||||
|
grpc_pollset *pollset) { |
||||||
|
grpc_pollset_set *master_pollset_set = |
||||||
|
grpc_client_uchannel_get_connecting_pollset_set(elem); |
||||||
|
grpc_pollset_set_del_pollset(exec_ctx, master_pollset_set, pollset); |
||||||
|
} |
||||||
|
|
||||||
|
grpc_channel *grpc_client_uchannel_create(grpc_subchannel *subchannel, |
||||||
|
grpc_channel_args *args) { |
||||||
|
grpc_channel *channel = NULL; |
||||||
|
#define MAX_FILTERS 3 |
||||||
|
const grpc_channel_filter *filters[MAX_FILTERS]; |
||||||
|
grpc_mdctx *mdctx = grpc_subchannel_get_mdctx(subchannel); |
||||||
|
grpc_channel *master = grpc_subchannel_get_master(subchannel); |
||||||
|
char *target = grpc_channel_get_target(master); |
||||||
|
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; |
||||||
|
size_t n = 0; |
||||||
|
|
||||||
|
grpc_mdctx_ref(mdctx); |
||||||
|
if (grpc_channel_args_is_census_enabled(args)) { |
||||||
|
filters[n++] = &grpc_client_census_filter; |
||||||
|
} |
||||||
|
filters[n++] = &grpc_compress_filter; |
||||||
|
filters[n++] = &grpc_client_uchannel_filter; |
||||||
|
GPR_ASSERT(n <= MAX_FILTERS); |
||||||
|
|
||||||
|
channel = grpc_channel_create_from_filters(&exec_ctx, target, filters, n, |
||||||
|
args, mdctx, 1); |
||||||
|
|
||||||
|
gpr_free(target); |
||||||
|
return channel; |
||||||
|
} |
||||||
|
|
||||||
|
void grpc_client_uchannel_set_subchannel(grpc_channel *uchannel, |
||||||
|
grpc_subchannel *subchannel) { |
||||||
|
grpc_channel_element *elem = |
||||||
|
grpc_channel_stack_last_element(grpc_channel_get_channel_stack(uchannel)); |
||||||
|
channel_data *chand = elem->channel_data; |
||||||
|
GPR_ASSERT(elem->filter == &grpc_client_uchannel_filter); |
||||||
|
gpr_mu_lock(&chand->mu_state); |
||||||
|
chand->subchannel = subchannel; |
||||||
|
gpr_mu_unlock(&chand->mu_state); |
||||||
|
} |
@ -0,0 +1,70 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef GRPC_INTERNAL_CORE_CHANNEL_CLIENT_MICROCHANNEL_H |
||||||
|
#define GRPC_INTERNAL_CORE_CHANNEL_CLIENT_MICROCHANNEL_H |
||||||
|
|
||||||
|
#include "src/core/channel/channel_stack.h" |
||||||
|
#include "src/core/client_config/resolver.h" |
||||||
|
|
||||||
|
#define GRPC_MICROCHANNEL_SUBCHANNEL_ARG "grpc.microchannel_subchannel_key" |
||||||
|
|
||||||
|
/* A client microchannel (aka uchannel) is a channel wrapping a subchannel, for
|
||||||
|
* the purposes of lightweight RPC communications from within the core.*/ |
||||||
|
|
||||||
|
extern const grpc_channel_filter grpc_client_uchannel_filter; |
||||||
|
|
||||||
|
grpc_connectivity_state grpc_client_uchannel_check_connectivity_state( |
||||||
|
grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect); |
||||||
|
|
||||||
|
void grpc_client_uchannel_watch_connectivity_state( |
||||||
|
grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, |
||||||
|
grpc_connectivity_state *state, grpc_closure *on_complete); |
||||||
|
|
||||||
|
grpc_pollset_set *grpc_client_uchannel_get_connecting_pollset_set( |
||||||
|
grpc_channel_element *elem); |
||||||
|
|
||||||
|
void grpc_client_uchannel_add_interested_party(grpc_exec_ctx *exec_ctx, |
||||||
|
grpc_channel_element *channel, |
||||||
|
grpc_pollset *pollset); |
||||||
|
void grpc_client_uchannel_del_interested_party(grpc_exec_ctx *exec_ctx, |
||||||
|
grpc_channel_element *channel, |
||||||
|
grpc_pollset *pollset); |
||||||
|
|
||||||
|
grpc_channel *grpc_client_uchannel_create(grpc_subchannel *subchannel, |
||||||
|
grpc_channel_args *args); |
||||||
|
|
||||||
|
void grpc_client_uchannel_set_subchannel(grpc_channel *uchannel, |
||||||
|
grpc_subchannel *subchannel); |
||||||
|
|
||||||
|
#endif /* GRPC_INTERNAL_CORE_CHANNEL_CLIENT_MICROCHANNEL_H */ |
@ -0,0 +1,128 @@ |
|||||||
|
#!/usr/bin/env python2.7 |
||||||
|
# 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. |
||||||
|
|
||||||
|
"""Change comments style of source files from // to /** */""" |
||||||
|
|
||||||
|
import re |
||||||
|
import sys |
||||||
|
|
||||||
|
|
||||||
|
if len(sys.argv) < 2: |
||||||
|
print("Please provide at least one source file name as argument.") |
||||||
|
sys.exit() |
||||||
|
|
||||||
|
for file_name in sys.argv[1:]: |
||||||
|
|
||||||
|
print("Modifying format of {file} comments in place...".format( |
||||||
|
file=file_name, |
||||||
|
)) |
||||||
|
|
||||||
|
|
||||||
|
# Input |
||||||
|
|
||||||
|
with open(file_name, "r") as input_file: |
||||||
|
lines = input_file.readlines() |
||||||
|
|
||||||
|
def peek(): |
||||||
|
return lines[0] |
||||||
|
|
||||||
|
def read_line(): |
||||||
|
return lines.pop(0) |
||||||
|
|
||||||
|
def more_input_available(): |
||||||
|
return lines |
||||||
|
|
||||||
|
|
||||||
|
# Output |
||||||
|
|
||||||
|
output_lines = [] |
||||||
|
|
||||||
|
def write(line): |
||||||
|
output_lines.append(line) |
||||||
|
|
||||||
|
def flush_output(): |
||||||
|
with open(file_name, "w") as output_file: |
||||||
|
for line in output_lines: |
||||||
|
output_file.write(line) |
||||||
|
|
||||||
|
|
||||||
|
# Pattern matching |
||||||
|
|
||||||
|
comment_regex = r'^(\s*)//\s(.*)$' |
||||||
|
|
||||||
|
def is_comment(line): |
||||||
|
return re.search(comment_regex, line) |
||||||
|
|
||||||
|
def isnt_comment(line): |
||||||
|
return not is_comment(line) |
||||||
|
|
||||||
|
def next_line(predicate): |
||||||
|
return more_input_available() and predicate(peek()) |
||||||
|
|
||||||
|
|
||||||
|
# Transformation |
||||||
|
|
||||||
|
def indentation_of(line): |
||||||
|
match = re.search(comment_regex, line) |
||||||
|
return match.group(1) |
||||||
|
|
||||||
|
def content(line): |
||||||
|
match = re.search(comment_regex, line) |
||||||
|
return match.group(2) |
||||||
|
|
||||||
|
def format_as_block(comment_block): |
||||||
|
if len(comment_block) == 0: |
||||||
|
return [] |
||||||
|
|
||||||
|
indent = indentation_of(comment_block[0]) |
||||||
|
|
||||||
|
if len(comment_block) == 1: |
||||||
|
return [indent + "/** " + content(comment_block[0]) + " */\n"] |
||||||
|
|
||||||
|
block = ["/**"] + [" * " + content(line) for line in comment_block] + [" */"] |
||||||
|
return [indent + line.rstrip() + "\n" for line in block] |
||||||
|
|
||||||
|
|
||||||
|
# Main algorithm |
||||||
|
|
||||||
|
while more_input_available(): |
||||||
|
while next_line(isnt_comment): |
||||||
|
write(read_line()) |
||||||
|
|
||||||
|
comment_block = [] |
||||||
|
# Get all lines in the same comment block. We could restrict the indentation |
||||||
|
# to be the same as the first line of the block, but it's probably ok. |
||||||
|
while (next_line(is_comment)): |
||||||
|
comment_block.append(read_line()) |
||||||
|
|
||||||
|
for line in format_as_block(comment_block): |
||||||
|
write(line) |
||||||
|
|
||||||
|
flush_output() |
@ -0,0 +1,50 @@ |
|||||||
|
/* |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#import <GRPCClient/GRPCCall+Tests.h> |
||||||
|
|
||||||
|
#import "InteropTests.h" |
||||||
|
|
||||||
|
static NSString * const kRemoteSSLHost = @"grpc-test.sandbox.google.com"; |
||||||
|
|
||||||
|
/** Tests in InteropTests.m, sending the RPCs to a remote SSL server. */ |
||||||
|
@interface InteropTestsRemote : InteropTests |
||||||
|
@end |
||||||
|
|
||||||
|
@implementation InteropTestsRemote |
||||||
|
|
||||||
|
+ (NSString *)host { |
||||||
|
return kRemoteSSLHost; |
||||||
|
} |
||||||
|
|
||||||
|
@end |
@ -1,164 +0,0 @@ |
|||||||
/* |
|
||||||
* |
|
||||||
* 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. |
|
||||||
* |
|
||||||
*/ |
|
||||||
|
|
||||||
#import <UIKit/UIKit.h> |
|
||||||
#import <XCTest/XCTest.h> |
|
||||||
|
|
||||||
#import <GRPCClient/GRPCCall.h> |
|
||||||
#import <ProtoRPC/ProtoMethod.h> |
|
||||||
#import <RouteGuide/RouteGuide.pbobjc.h> |
|
||||||
#import <RouteGuide/RouteGuide.pbrpc.h> |
|
||||||
#import <RxLibrary/GRXWriteable.h> |
|
||||||
#import <RxLibrary/GRXWriter+Immediate.h> |
|
||||||
|
|
||||||
// These tests require a gRPC "RouteGuide" sample server to be running locally. You can compile and |
|
||||||
// run one by following the instructions here: https://github.com/grpc/grpc/blob/master/examples/cpp/cpptutorial.md#try-it-out |
|
||||||
// Be sure to have the C gRPC library installed in your system (for example, by having followed the |
|
||||||
// instructions at https://github.com/grpc/homebrew-grpc |
|
||||||
|
|
||||||
static NSString * const kRouteGuideHost = @"http://localhost:50051"; |
|
||||||
static NSString * const kPackage = @"routeguide"; |
|
||||||
static NSString * const kService = @"RouteGuide"; |
|
||||||
|
|
||||||
@interface LocalClearTextTests : XCTestCase |
|
||||||
@end |
|
||||||
|
|
||||||
@implementation LocalClearTextTests |
|
||||||
|
|
||||||
// This test currently fails: see Issue #1907. |
|
||||||
//- (void)testConnectionToLocalServer { |
|
||||||
// __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Server reachable."]; |
|
||||||
// |
|
||||||
// // This method isn't implemented by the local server. |
|
||||||
// GRPCMethodName *method = [[GRPCMethodName alloc] initWithPackage:kPackage |
|
||||||
// interface:kService |
|
||||||
// method:@"EmptyCall"]; |
|
||||||
// |
|
||||||
// GRXWriter *requestsWriter = [GRXWriter writerWithValue:[NSData data]]; |
|
||||||
// |
|
||||||
// GRPCCall *call = [[GRPCCall alloc] initWithHost:kRouteGuideHost |
|
||||||
// method:method |
|
||||||
// requestsWriter:requestsWriter]; |
|
||||||
// |
|
||||||
// id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { |
|
||||||
// XCTFail(@"Received unexpected response: %@", value); |
|
||||||
// } completionHandler:^(NSError *errorOrNil) { |
|
||||||
// XCTAssertNotNil(errorOrNil, @"Finished without error!"); |
|
||||||
// XCTAssertEqual(errorOrNil.code, 12, @"Finished with unexpected error: %@", errorOrNil); |
|
||||||
// [expectation fulfill]; |
|
||||||
// }]; |
|
||||||
// |
|
||||||
// [call startWithWriteable:responsesWriteable]; |
|
||||||
// |
|
||||||
// [self waitForExpectationsWithTimeout:8.0 handler:nil]; |
|
||||||
//} |
|
||||||
|
|
||||||
- (void)testEmptyRPC { |
|
||||||
__weak XCTestExpectation *response = [self expectationWithDescription:@"Empty response received."]; |
|
||||||
__weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."]; |
|
||||||
|
|
||||||
ProtoMethod *method = [[ProtoMethod alloc] initWithPackage:kPackage |
|
||||||
service:kService |
|
||||||
method:@"RecordRoute"]; |
|
||||||
|
|
||||||
GRXWriter *requestsWriter = [GRXWriter emptyWriter]; |
|
||||||
|
|
||||||
GRPCCall *call = [[GRPCCall alloc] initWithHost:kRouteGuideHost |
|
||||||
path:method.HTTPPath |
|
||||||
requestsWriter:requestsWriter]; |
|
||||||
|
|
||||||
id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { |
|
||||||
XCTAssertNotNil(value, @"nil value received as response."); |
|
||||||
XCTAssertEqual([value length], 0, @"Non-empty response received: %@", value); |
|
||||||
[response fulfill]; |
|
||||||
} completionHandler:^(NSError *errorOrNil) { |
|
||||||
XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil); |
|
||||||
[completion fulfill]; |
|
||||||
}]; |
|
||||||
|
|
||||||
[call startWithWriteable:responsesWriteable]; |
|
||||||
|
|
||||||
[self waitForExpectationsWithTimeout:2.0 handler:nil]; |
|
||||||
} |
|
||||||
|
|
||||||
- (void)testSimpleProtoRPC { |
|
||||||
__weak XCTestExpectation *response = [self expectationWithDescription:@"Response received."]; |
|
||||||
__weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."]; |
|
||||||
|
|
||||||
ProtoMethod *method = [[ProtoMethod alloc] initWithPackage:kPackage |
|
||||||
service:kService |
|
||||||
method:@"GetFeature"]; |
|
||||||
|
|
||||||
RGDPoint *point = [RGDPoint message]; |
|
||||||
point.latitude = 28E7; |
|
||||||
point.longitude = -15E7; |
|
||||||
GRXWriter *requestsWriter = [GRXWriter writerWithValue:[point data]]; |
|
||||||
|
|
||||||
GRPCCall *call = [[GRPCCall alloc] initWithHost:kRouteGuideHost |
|
||||||
path:method.HTTPPath |
|
||||||
requestsWriter:requestsWriter]; |
|
||||||
|
|
||||||
id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { |
|
||||||
XCTAssertNotNil(value, @"nil value received as response."); |
|
||||||
RGDFeature *feature = [RGDFeature parseFromData:value error:NULL]; |
|
||||||
XCTAssertEqualObjects(point, feature.location); |
|
||||||
XCTAssertNotNil(feature.name, @"Response's name is nil."); |
|
||||||
[response fulfill]; |
|
||||||
} completionHandler:^(NSError *errorOrNil) { |
|
||||||
XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil); |
|
||||||
[completion fulfill]; |
|
||||||
}]; |
|
||||||
|
|
||||||
[call startWithWriteable:responsesWriteable]; |
|
||||||
|
|
||||||
[self waitForExpectationsWithTimeout:2.0 handler:nil]; |
|
||||||
} |
|
||||||
|
|
||||||
- (void)testSimpleProtoRPCUsingGeneratedService { |
|
||||||
__weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."]; |
|
||||||
|
|
||||||
RGDPoint *point = [RGDPoint message]; |
|
||||||
point.latitude = 28E7; |
|
||||||
point.longitude = -15E7; |
|
||||||
|
|
||||||
RGDRouteGuide *service = [[RGDRouteGuide alloc] initWithHost:kRouteGuideHost]; |
|
||||||
[service getFeatureWithRequest:point handler:^(RGDFeature *response, NSError *error) { |
|
||||||
XCTAssertNil(error, @"Finished with unexpected error: %@", error); |
|
||||||
XCTAssertEqualObjects(point, response.location); |
|
||||||
XCTAssertNotNil(response.name, @"Response's name is nil."); |
|
||||||
[completion fulfill]; |
|
||||||
}]; |
|
||||||
|
|
||||||
[self waitForExpectationsWithTimeout:2.0 handler:nil]; |
|
||||||
} |
|
||||||
@end |
|
@ -0,0 +1,101 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<Scheme |
||||||
|
LastUpgradeVersion = "0700" |
||||||
|
version = "1.3"> |
||||||
|
<BuildAction |
||||||
|
parallelizeBuildables = "YES" |
||||||
|
buildImplicitDependencies = "YES"> |
||||||
|
<BuildActionEntries> |
||||||
|
<BuildActionEntry |
||||||
|
buildForTesting = "YES" |
||||||
|
buildForRunning = "YES" |
||||||
|
buildForProfiling = "NO" |
||||||
|
buildForArchiving = "NO" |
||||||
|
buildForAnalyzing = "YES"> |
||||||
|
<BuildableReference |
||||||
|
BuildableIdentifier = "primary" |
||||||
|
BlueprintIdentifier = "63DC84421BE152B5000708E8" |
||||||
|
BuildableName = "InteropTestsLocalCleartext.xctest" |
||||||
|
BlueprintName = "InteropTestsLocalCleartext" |
||||||
|
ReferencedContainer = "container:Tests.xcodeproj"> |
||||||
|
</BuildableReference> |
||||||
|
</BuildActionEntry> |
||||||
|
</BuildActionEntries> |
||||||
|
</BuildAction> |
||||||
|
<TestAction |
||||||
|
buildConfiguration = "Debug" |
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" |
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" |
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"> |
||||||
|
<Testables> |
||||||
|
<TestableReference |
||||||
|
skipped = "NO"> |
||||||
|
<BuildableReference |
||||||
|
BuildableIdentifier = "primary" |
||||||
|
BlueprintIdentifier = "63DC84421BE152B5000708E8" |
||||||
|
BuildableName = "InteropTestsLocalCleartext.xctest" |
||||||
|
BlueprintName = "InteropTestsLocalCleartext" |
||||||
|
ReferencedContainer = "container:Tests.xcodeproj"> |
||||||
|
</BuildableReference> |
||||||
|
<SkippedTests> |
||||||
|
<Test |
||||||
|
Identifier = "GRPCClientTests/testConnectionToRemoteServer"> |
||||||
|
</Test> |
||||||
|
<Test |
||||||
|
Identifier = "GRPCClientTests/testMetadata"> |
||||||
|
</Test> |
||||||
|
<Test |
||||||
|
Identifier = "InteropTests"> |
||||||
|
</Test> |
||||||
|
</SkippedTests> |
||||||
|
</TestableReference> |
||||||
|
</Testables> |
||||||
|
<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"> |
||||||
|
<MacroExpansion> |
||||||
|
<BuildableReference |
||||||
|
BuildableIdentifier = "primary" |
||||||
|
BlueprintIdentifier = "63DC84421BE152B5000708E8" |
||||||
|
BuildableName = "InteropTestsLocalCleartext.xctest" |
||||||
|
BlueprintName = "InteropTestsLocalCleartext" |
||||||
|
ReferencedContainer = "container:Tests.xcodeproj"> |
||||||
|
</BuildableReference> |
||||||
|
</MacroExpansion> |
||||||
|
<AdditionalOptions> |
||||||
|
</AdditionalOptions> |
||||||
|
</LaunchAction> |
||||||
|
<ProfileAction |
||||||
|
buildConfiguration = "Release" |
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES" |
||||||
|
savedToolIdentifier = "" |
||||||
|
useCustomWorkingDirectory = "NO" |
||||||
|
debugDocumentVersioning = "YES"> |
||||||
|
<MacroExpansion> |
||||||
|
<BuildableReference |
||||||
|
BuildableIdentifier = "primary" |
||||||
|
BlueprintIdentifier = "63DC84421BE152B5000708E8" |
||||||
|
BuildableName = "InteropTestsLocalCleartext.xctest" |
||||||
|
BlueprintName = "InteropTestsLocalCleartext" |
||||||
|
ReferencedContainer = "container:Tests.xcodeproj"> |
||||||
|
</BuildableReference> |
||||||
|
</MacroExpansion> |
||||||
|
</ProfileAction> |
||||||
|
<AnalyzeAction |
||||||
|
buildConfiguration = "Debug"> |
||||||
|
</AnalyzeAction> |
||||||
|
<ArchiveAction |
||||||
|
buildConfiguration = "Release" |
||||||
|
revealArchiveInOrganizer = "YES"> |
||||||
|
</ArchiveAction> |
||||||
|
</Scheme> |
@ -0,0 +1,95 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<Scheme |
||||||
|
LastUpgradeVersion = "0700" |
||||||
|
version = "1.3"> |
||||||
|
<BuildAction |
||||||
|
parallelizeBuildables = "YES" |
||||||
|
buildImplicitDependencies = "YES"> |
||||||
|
<BuildActionEntries> |
||||||
|
<BuildActionEntry |
||||||
|
buildForTesting = "YES" |
||||||
|
buildForRunning = "YES" |
||||||
|
buildForProfiling = "NO" |
||||||
|
buildForArchiving = "NO" |
||||||
|
buildForAnalyzing = "YES"> |
||||||
|
<BuildableReference |
||||||
|
BuildableIdentifier = "primary" |
||||||
|
BlueprintIdentifier = "63DC84331BE15294000708E8" |
||||||
|
BuildableName = "InteropTestsLocalSSL.xctest" |
||||||
|
BlueprintName = "InteropTestsLocalSSL" |
||||||
|
ReferencedContainer = "container:Tests.xcodeproj"> |
||||||
|
</BuildableReference> |
||||||
|
</BuildActionEntry> |
||||||
|
</BuildActionEntries> |
||||||
|
</BuildAction> |
||||||
|
<TestAction |
||||||
|
buildConfiguration = "Debug" |
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" |
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" |
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"> |
||||||
|
<Testables> |
||||||
|
<TestableReference |
||||||
|
skipped = "NO"> |
||||||
|
<BuildableReference |
||||||
|
BuildableIdentifier = "primary" |
||||||
|
BlueprintIdentifier = "63DC84331BE15294000708E8" |
||||||
|
BuildableName = "InteropTestsLocalSSL.xctest" |
||||||
|
BlueprintName = "InteropTestsLocalSSL" |
||||||
|
ReferencedContainer = "container:Tests.xcodeproj"> |
||||||
|
</BuildableReference> |
||||||
|
<SkippedTests> |
||||||
|
<Test |
||||||
|
Identifier = "InteropTests"> |
||||||
|
</Test> |
||||||
|
</SkippedTests> |
||||||
|
</TestableReference> |
||||||
|
</Testables> |
||||||
|
<MacroExpansion> |
||||||
|
<BuildableReference |
||||||
|
BuildableIdentifier = "primary" |
||||||
|
BlueprintIdentifier = "63DC84331BE15294000708E8" |
||||||
|
BuildableName = "InteropTestsLocalSSL.xctest" |
||||||
|
BlueprintName = "InteropTestsLocalSSL" |
||||||
|
ReferencedContainer = "container:Tests.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"> |
||||||
|
<MacroExpansion> |
||||||
|
<BuildableReference |
||||||
|
BuildableIdentifier = "primary" |
||||||
|
BlueprintIdentifier = "63DC84331BE15294000708E8" |
||||||
|
BuildableName = "InteropTestsLocalSSL.xctest" |
||||||
|
BlueprintName = "InteropTestsLocalSSL" |
||||||
|
ReferencedContainer = "container:Tests.xcodeproj"> |
||||||
|
</BuildableReference> |
||||||
|
</MacroExpansion> |
||||||
|
<AdditionalOptions> |
||||||
|
</AdditionalOptions> |
||||||
|
</LaunchAction> |
||||||
|
<ProfileAction |
||||||
|
buildConfiguration = "Release" |
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES" |
||||||
|
savedToolIdentifier = "" |
||||||
|
useCustomWorkingDirectory = "NO" |
||||||
|
debugDocumentVersioning = "YES"> |
||||||
|
</ProfileAction> |
||||||
|
<AnalyzeAction |
||||||
|
buildConfiguration = "Debug"> |
||||||
|
</AnalyzeAction> |
||||||
|
<ArchiveAction |
||||||
|
buildConfiguration = "Release" |
||||||
|
revealArchiveInOrganizer = "YES"> |
||||||
|
</ArchiveAction> |
||||||
|
</Scheme> |
@ -0,0 +1,95 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<Scheme |
||||||
|
LastUpgradeVersion = "0700" |
||||||
|
version = "1.3"> |
||||||
|
<BuildAction |
||||||
|
parallelizeBuildables = "YES" |
||||||
|
buildImplicitDependencies = "YES"> |
||||||
|
<BuildActionEntries> |
||||||
|
<BuildActionEntry |
||||||
|
buildForTesting = "YES" |
||||||
|
buildForRunning = "YES" |
||||||
|
buildForProfiling = "NO" |
||||||
|
buildForArchiving = "NO" |
||||||
|
buildForAnalyzing = "YES"> |
||||||
|
<BuildableReference |
||||||
|
BuildableIdentifier = "primary" |
||||||
|
BlueprintIdentifier = "63DC84221BE15267000708E8" |
||||||
|
BuildableName = "InteropTestsRemote.xctest" |
||||||
|
BlueprintName = "InteropTestsRemote" |
||||||
|
ReferencedContainer = "container:Tests.xcodeproj"> |
||||||
|
</BuildableReference> |
||||||
|
</BuildActionEntry> |
||||||
|
</BuildActionEntries> |
||||||
|
</BuildAction> |
||||||
|
<TestAction |
||||||
|
buildConfiguration = "Debug" |
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" |
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" |
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"> |
||||||
|
<Testables> |
||||||
|
<TestableReference |
||||||
|
skipped = "NO"> |
||||||
|
<BuildableReference |
||||||
|
BuildableIdentifier = "primary" |
||||||
|
BlueprintIdentifier = "63DC84221BE15267000708E8" |
||||||
|
BuildableName = "InteropTestsRemote.xctest" |
||||||
|
BlueprintName = "InteropTestsRemote" |
||||||
|
ReferencedContainer = "container:Tests.xcodeproj"> |
||||||
|
</BuildableReference> |
||||||
|
<SkippedTests> |
||||||
|
<Test |
||||||
|
Identifier = "InteropTests"> |
||||||
|
</Test> |
||||||
|
</SkippedTests> |
||||||
|
</TestableReference> |
||||||
|
</Testables> |
||||||
|
<MacroExpansion> |
||||||
|
<BuildableReference |
||||||
|
BuildableIdentifier = "primary" |
||||||
|
BlueprintIdentifier = "63DC84221BE15267000708E8" |
||||||
|
BuildableName = "InteropTestsRemote.xctest" |
||||||
|
BlueprintName = "InteropTestsRemote" |
||||||
|
ReferencedContainer = "container:Tests.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"> |
||||||
|
<MacroExpansion> |
||||||
|
<BuildableReference |
||||||
|
BuildableIdentifier = "primary" |
||||||
|
BlueprintIdentifier = "63DC84221BE15267000708E8" |
||||||
|
BuildableName = "InteropTestsRemote.xctest" |
||||||
|
BlueprintName = "InteropTestsRemote" |
||||||
|
ReferencedContainer = "container:Tests.xcodeproj"> |
||||||
|
</BuildableReference> |
||||||
|
</MacroExpansion> |
||||||
|
<AdditionalOptions> |
||||||
|
</AdditionalOptions> |
||||||
|
</LaunchAction> |
||||||
|
<ProfileAction |
||||||
|
buildConfiguration = "Release" |
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES" |
||||||
|
savedToolIdentifier = "" |
||||||
|
useCustomWorkingDirectory = "NO" |
||||||
|
debugDocumentVersioning = "YES"> |
||||||
|
</ProfileAction> |
||||||
|
<AnalyzeAction |
||||||
|
buildConfiguration = "Debug"> |
||||||
|
</AnalyzeAction> |
||||||
|
<ArchiveAction |
||||||
|
buildConfiguration = "Release" |
||||||
|
revealArchiveInOrganizer = "YES"> |
||||||
|
</ArchiveAction> |
||||||
|
</Scheme> |
@ -0,0 +1,90 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<Scheme |
||||||
|
LastUpgradeVersion = "0700" |
||||||
|
version = "1.3"> |
||||||
|
<BuildAction |
||||||
|
parallelizeBuildables = "YES" |
||||||
|
buildImplicitDependencies = "YES"> |
||||||
|
<BuildActionEntries> |
||||||
|
<BuildActionEntry |
||||||
|
buildForTesting = "YES" |
||||||
|
buildForRunning = "YES" |
||||||
|
buildForProfiling = "NO" |
||||||
|
buildForArchiving = "NO" |
||||||
|
buildForAnalyzing = "YES"> |
||||||
|
<BuildableReference |
||||||
|
BuildableIdentifier = "primary" |
||||||
|
BlueprintIdentifier = "63DC84121BE15179000708E8" |
||||||
|
BuildableName = "RxLibraryUnitTests.xctest" |
||||||
|
BlueprintName = "RxLibraryUnitTests" |
||||||
|
ReferencedContainer = "container:Tests.xcodeproj"> |
||||||
|
</BuildableReference> |
||||||
|
</BuildActionEntry> |
||||||
|
</BuildActionEntries> |
||||||
|
</BuildAction> |
||||||
|
<TestAction |
||||||
|
buildConfiguration = "Debug" |
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" |
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" |
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"> |
||||||
|
<Testables> |
||||||
|
<TestableReference |
||||||
|
skipped = "NO"> |
||||||
|
<BuildableReference |
||||||
|
BuildableIdentifier = "primary" |
||||||
|
BlueprintIdentifier = "63DC84121BE15179000708E8" |
||||||
|
BuildableName = "RxLibraryUnitTests.xctest" |
||||||
|
BlueprintName = "RxLibraryUnitTests" |
||||||
|
ReferencedContainer = "container:Tests.xcodeproj"> |
||||||
|
</BuildableReference> |
||||||
|
</TestableReference> |
||||||
|
</Testables> |
||||||
|
<MacroExpansion> |
||||||
|
<BuildableReference |
||||||
|
BuildableIdentifier = "primary" |
||||||
|
BlueprintIdentifier = "63DC84121BE15179000708E8" |
||||||
|
BuildableName = "RxLibraryUnitTests.xctest" |
||||||
|
BlueprintName = "RxLibraryUnitTests" |
||||||
|
ReferencedContainer = "container:Tests.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"> |
||||||
|
<MacroExpansion> |
||||||
|
<BuildableReference |
||||||
|
BuildableIdentifier = "primary" |
||||||
|
BlueprintIdentifier = "63DC84121BE15179000708E8" |
||||||
|
BuildableName = "RxLibraryUnitTests.xctest" |
||||||
|
BlueprintName = "RxLibraryUnitTests" |
||||||
|
ReferencedContainer = "container:Tests.xcodeproj"> |
||||||
|
</BuildableReference> |
||||||
|
</MacroExpansion> |
||||||
|
<AdditionalOptions> |
||||||
|
</AdditionalOptions> |
||||||
|
</LaunchAction> |
||||||
|
<ProfileAction |
||||||
|
buildConfiguration = "Release" |
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES" |
||||||
|
savedToolIdentifier = "" |
||||||
|
useCustomWorkingDirectory = "NO" |
||||||
|
debugDocumentVersioning = "YES"> |
||||||
|
</ProfileAction> |
||||||
|
<AnalyzeAction |
||||||
|
buildConfiguration = "Debug"> |
||||||
|
</AnalyzeAction> |
||||||
|
<ArchiveAction |
||||||
|
buildConfiguration = "Release" |
||||||
|
revealArchiveInOrganizer = "YES"> |
||||||
|
</ArchiveAction> |
||||||
|
</Scheme> |
@ -1,26 +0,0 @@ |
|||||||
<?php |
|
||||||
// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin 1.0 |
|
||||||
// Source: net/proto2/bridge/proto/message_set.proto |
|
||||||
// Date: 2014-12-03 22:02:20 |
|
||||||
|
|
||||||
namespace proto2\bridge { |
|
||||||
|
|
||||||
class MessageSet extends \DrSlump\Protobuf\Message { |
|
||||||
|
|
||||||
|
|
||||||
/** @var \Closure[] */ |
|
||||||
protected static $__extensions = array(); |
|
||||||
|
|
||||||
public static function descriptor() |
|
||||||
{ |
|
||||||
$descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'proto2.bridge.MessageSet'); |
|
||||||
|
|
||||||
foreach (self::$__extensions as $cb) { |
|
||||||
$descriptor->addField($cb(), true); |
|
||||||
} |
|
||||||
|
|
||||||
return $descriptor; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue