mirror of https://github.com/grpc/grpc.git
Resolve a conflict between adding write buffer hint and the change of API Conflicts: src/cpp/server/async_server_context.ccpull/388/head
commit
280744ec64
158 changed files with 3546 additions and 1312 deletions
@ -0,0 +1,26 @@ |
|||||||
|
C++ Client implementation for Cloud Pub/Sub service (TIPS) |
||||||
|
(https://developers.google.com/apis-explorer/#p/pubsub/v1beta1/). |
||||||
|
|
||||||
|
"Google Cloud Pub/Sub" API needs to be enabled at |
||||||
|
https://console.developers.google.com/project to open the access for a client. |
||||||
|
Select the project name, select the "APIs" under "APIs & auth", and turn |
||||||
|
on "Google Cloud Pub/Sub" API. |
||||||
|
|
||||||
|
To run the client from Google Compute Engine (GCE), the GCE instance needs to |
||||||
|
be created with scope "https://www.googleapis.com/auth/cloud-platform" as below: |
||||||
|
|
||||||
|
gcloud compute instances create instance-name |
||||||
|
--image debian-7 --scopes https://www.googleapis.com/auth/cloud-platform |
||||||
|
|
||||||
|
To run the client from GCE: |
||||||
|
make tips_client |
||||||
|
bins/opt/tips_client --project_id="your project id" |
||||||
|
|
||||||
|
A service account credential is required to run the client from other |
||||||
|
environments, which can be generated as a JSON key file from |
||||||
|
https://console.developers.google.com/project/. To run the client with a service |
||||||
|
account credential: |
||||||
|
|
||||||
|
bins/opt/tips_client |
||||||
|
--project_id="your project id" |
||||||
|
--service_account_key_file="absolute path to the JSON key file" |
@ -0,0 +1,118 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* Copyright 2014, 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 <grpc++/client_context.h> |
||||||
|
|
||||||
|
#include "examples/tips/subscriber.h" |
||||||
|
|
||||||
|
using tech::pubsub::Topic; |
||||||
|
using tech::pubsub::DeleteTopicRequest; |
||||||
|
using tech::pubsub::GetTopicRequest; |
||||||
|
using tech::pubsub::SubscriberService; |
||||||
|
using tech::pubsub::ListTopicsRequest; |
||||||
|
using tech::pubsub::ListTopicsResponse; |
||||||
|
using tech::pubsub::PublishRequest; |
||||||
|
using tech::pubsub::PubsubMessage; |
||||||
|
|
||||||
|
namespace grpc { |
||||||
|
namespace examples { |
||||||
|
namespace tips { |
||||||
|
|
||||||
|
Subscriber::Subscriber(std::shared_ptr<ChannelInterface> channel) |
||||||
|
: stub_(SubscriberService::NewStub(channel)) { |
||||||
|
} |
||||||
|
|
||||||
|
void Subscriber::Shutdown() { |
||||||
|
stub_.reset(); |
||||||
|
} |
||||||
|
|
||||||
|
Status Subscriber::CreateSubscription(const grpc::string& topic, |
||||||
|
const grpc::string& name) { |
||||||
|
tech::pubsub::Subscription request; |
||||||
|
tech::pubsub::Subscription response; |
||||||
|
ClientContext context; |
||||||
|
|
||||||
|
request.set_topic(topic); |
||||||
|
request.set_name(name); |
||||||
|
|
||||||
|
return stub_->CreateSubscription(&context, request, &response); |
||||||
|
} |
||||||
|
|
||||||
|
Status Subscriber::GetSubscription(const grpc::string& name, |
||||||
|
grpc::string* topic) { |
||||||
|
tech::pubsub::GetSubscriptionRequest request; |
||||||
|
tech::pubsub::Subscription response; |
||||||
|
ClientContext context; |
||||||
|
|
||||||
|
request.set_subscription(name); |
||||||
|
|
||||||
|
Status s = stub_->GetSubscription(&context, request, &response); |
||||||
|
*topic = response.topic(); |
||||||
|
return s; |
||||||
|
} |
||||||
|
|
||||||
|
Status Subscriber::DeleteSubscription(const grpc::string& name) { |
||||||
|
tech::pubsub::DeleteSubscriptionRequest request; |
||||||
|
proto2::Empty response; |
||||||
|
ClientContext context; |
||||||
|
|
||||||
|
request.set_subscription(name); |
||||||
|
|
||||||
|
return stub_->DeleteSubscription(&context, request, &response); |
||||||
|
} |
||||||
|
|
||||||
|
Status Subscriber::Pull(const grpc::string& name, grpc::string* data) { |
||||||
|
tech::pubsub::PullRequest request; |
||||||
|
tech::pubsub::PullResponse response; |
||||||
|
ClientContext context; |
||||||
|
|
||||||
|
request.set_subscription(name); |
||||||
|
Status s = stub_->Pull(&context, request, &response); |
||||||
|
if (s.IsOk()) { |
||||||
|
tech::pubsub::PubsubEvent event = response.pubsub_event(); |
||||||
|
if (event.has_message()) { |
||||||
|
*data = event.message().data(); |
||||||
|
} |
||||||
|
tech::pubsub::AcknowledgeRequest ack; |
||||||
|
proto2::Empty empty; |
||||||
|
ClientContext ack_context; |
||||||
|
ack.set_subscription(name); |
||||||
|
ack.add_ack_id(response.ack_id()); |
||||||
|
stub_->Acknowledge(&ack_context, ack, &empty); |
||||||
|
} |
||||||
|
return s; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace tips
|
||||||
|
} // namespace examples
|
||||||
|
} // namespace grpc
|
@ -0,0 +1,157 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* Copyright 2014, 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 <grpc++/channel_arguments.h> |
||||||
|
#include <grpc++/channel_interface.h> |
||||||
|
#include <grpc++/client_context.h> |
||||||
|
#include <grpc++/create_channel.h> |
||||||
|
#include <grpc++/server.h> |
||||||
|
#include <grpc++/server_builder.h> |
||||||
|
#include <grpc++/server_context.h> |
||||||
|
#include <grpc++/status.h> |
||||||
|
#include <gtest/gtest.h> |
||||||
|
|
||||||
|
#include "examples/tips/subscriber.h" |
||||||
|
#include "test/core/util/port.h" |
||||||
|
#include "test/core/util/test_config.h" |
||||||
|
|
||||||
|
namespace grpc { |
||||||
|
namespace testing { |
||||||
|
namespace { |
||||||
|
|
||||||
|
const char kTopic[] = "test topic"; |
||||||
|
const char kSubscriptionName[] = "subscription name"; |
||||||
|
const char kData[] = "Message data"; |
||||||
|
|
||||||
|
class SubscriberServiceImpl : public tech::pubsub::SubscriberService::Service { |
||||||
|
public: |
||||||
|
Status CreateSubscription(ServerContext* context, |
||||||
|
const tech::pubsub::Subscription* request, |
||||||
|
tech::pubsub::Subscription* response) override { |
||||||
|
EXPECT_EQ(request->topic(), kTopic); |
||||||
|
EXPECT_EQ(request->name(), kSubscriptionName); |
||||||
|
return Status::OK; |
||||||
|
} |
||||||
|
|
||||||
|
Status GetSubscription(ServerContext* context, |
||||||
|
const tech::pubsub::GetSubscriptionRequest* request, |
||||||
|
tech::pubsub::Subscription* response) override { |
||||||
|
EXPECT_EQ(request->subscription(), kSubscriptionName); |
||||||
|
response->set_topic(kTopic); |
||||||
|
return Status::OK; |
||||||
|
} |
||||||
|
|
||||||
|
Status DeleteSubscription( |
||||||
|
ServerContext* context, |
||||||
|
const tech::pubsub::DeleteSubscriptionRequest* request, |
||||||
|
proto2::Empty* response) override { |
||||||
|
EXPECT_EQ(request->subscription(), kSubscriptionName); |
||||||
|
return Status::OK; |
||||||
|
} |
||||||
|
|
||||||
|
Status Pull(ServerContext* context, |
||||||
|
const tech::pubsub::PullRequest* request, |
||||||
|
tech::pubsub::PullResponse* response) override { |
||||||
|
EXPECT_EQ(request->subscription(), kSubscriptionName); |
||||||
|
response->set_ack_id("1"); |
||||||
|
response->mutable_pubsub_event()->mutable_message()->set_data(kData); |
||||||
|
return Status::OK; |
||||||
|
} |
||||||
|
|
||||||
|
Status Acknowledge(ServerContext* context, |
||||||
|
const tech::pubsub::AcknowledgeRequest* request, |
||||||
|
proto2::Empty* response) override { |
||||||
|
return Status::OK; |
||||||
|
} |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
class SubscriberTest : public ::testing::Test { |
||||||
|
protected: |
||||||
|
// Setup a server and a client for SubscriberService.
|
||||||
|
void SetUp() override { |
||||||
|
int port = grpc_pick_unused_port_or_die(); |
||||||
|
server_address_ << "localhost:" << port; |
||||||
|
ServerBuilder builder; |
||||||
|
builder.AddPort(server_address_.str()); |
||||||
|
builder.RegisterService(service_.service()); |
||||||
|
server_ = builder.BuildAndStart(); |
||||||
|
|
||||||
|
channel_ = CreateChannel(server_address_.str(), ChannelArguments()); |
||||||
|
|
||||||
|
subscriber_.reset(new grpc::examples::tips::Subscriber(channel_)); |
||||||
|
} |
||||||
|
|
||||||
|
void TearDown() override { |
||||||
|
server_->Shutdown(); |
||||||
|
subscriber_->Shutdown(); |
||||||
|
} |
||||||
|
|
||||||
|
std::ostringstream server_address_; |
||||||
|
std::unique_ptr<Server> server_; |
||||||
|
SubscriberServiceImpl service_; |
||||||
|
|
||||||
|
std::shared_ptr<ChannelInterface> channel_; |
||||||
|
|
||||||
|
std::unique_ptr<grpc::examples::tips::Subscriber> subscriber_; |
||||||
|
}; |
||||||
|
|
||||||
|
TEST_F(SubscriberTest, TestSubscriber) { |
||||||
|
EXPECT_TRUE(subscriber_->CreateSubscription(kTopic, |
||||||
|
kSubscriptionName).IsOk()); |
||||||
|
|
||||||
|
grpc::string topic; |
||||||
|
EXPECT_TRUE(subscriber_->GetSubscription(kSubscriptionName, |
||||||
|
&topic).IsOk()); |
||||||
|
EXPECT_EQ(topic, kTopic); |
||||||
|
|
||||||
|
grpc::string data; |
||||||
|
EXPECT_TRUE(subscriber_->Pull(kSubscriptionName, |
||||||
|
&data).IsOk()); |
||||||
|
|
||||||
|
EXPECT_TRUE(subscriber_->DeleteSubscription(kSubscriptionName).IsOk()); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace testing
|
||||||
|
} // namespace grpc
|
||||||
|
|
||||||
|
int main(int argc, char** argv) { |
||||||
|
grpc_test_init(argc, argv); |
||||||
|
grpc_init(); |
||||||
|
::testing::InitGoogleTest(&argc, argv); |
||||||
|
gpr_log(GPR_INFO, "Start test ..."); |
||||||
|
int result = RUN_ALL_TESTS(); |
||||||
|
grpc_shutdown(); |
||||||
|
return result; |
||||||
|
} |
@ -1,42 +0,0 @@ |
|||||||
/*
|
|
||||||
* |
|
||||||
* Copyright 2014, 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_SUPPORT_THD_POSIX_H__ |
|
||||||
#define __GRPC_SUPPORT_THD_POSIX_H__ |
|
||||||
/* Posix variant of gpr_thd_platform.h. */ |
|
||||||
|
|
||||||
#include <pthread.h> |
|
||||||
|
|
||||||
typedef pthread_t gpr_thd_id; |
|
||||||
|
|
||||||
#endif /* __GRPC_SUPPORT_THD_POSIX_H__ */ |
|
@ -0,0 +1,2 @@ |
|||||||
|
*.userprefs |
||||||
|
test-results |
@ -0,0 +1,22 @@ |
|||||||
|
gRPC C# |
||||||
|
======= |
||||||
|
|
||||||
|
A C# implementation of gRPC, Google's RPC library. |
||||||
|
|
||||||
|
EXPERIMENTAL ONLY |
||||||
|
----------------- |
||||||
|
|
||||||
|
**This gRPC C# implementation is work-in-progress and is not expected to work yet.** |
||||||
|
|
||||||
|
- The implementation is a wrapper around gRPC C core library |
||||||
|
- Code only runs under mono currently, building gGRPC C core library under Windows |
||||||
|
is in progress. |
||||||
|
- It is very possible that some parts of the code will be heavily refactored or |
||||||
|
completely rewritten. |
||||||
|
|
||||||
|
CONTENTS |
||||||
|
-------- |
||||||
|
|
||||||
|
- ext: |
||||||
|
The extension library that wraps C API to be more digestible by C#. |
||||||
|
|
@ -0,0 +1,113 @@ |
|||||||
|
#include <grpc/grpc.h> |
||||||
|
#include <grpc/support/log.h> |
||||||
|
#include <grpc/support/slice.h> |
||||||
|
|
||||||
|
#include <string.h> |
||||||
|
|
||||||
|
grpc_byte_buffer *string_to_byte_buffer(const char *buffer, size_t len) { |
||||||
|
gpr_slice slice = gpr_slice_from_copied_buffer(buffer, len); |
||||||
|
grpc_byte_buffer *bb = grpc_byte_buffer_create(&slice, 1); |
||||||
|
gpr_slice_unref(slice); |
||||||
|
return bb; |
||||||
|
} |
||||||
|
|
||||||
|
void grpc_call_start_write_from_copied_buffer(grpc_call *call, |
||||||
|
const char *buffer, size_t len, |
||||||
|
void *tag, gpr_uint32 flags) { |
||||||
|
grpc_byte_buffer *byte_buffer = string_to_byte_buffer(buffer, len); |
||||||
|
GPR_ASSERT(grpc_call_start_write_old(call, byte_buffer, tag, flags) == |
||||||
|
GRPC_CALL_OK); |
||||||
|
grpc_byte_buffer_destroy(byte_buffer); |
||||||
|
} |
||||||
|
|
||||||
|
grpc_completion_type grpc_event_type(const grpc_event *event) { |
||||||
|
return event->type; |
||||||
|
} |
||||||
|
|
||||||
|
grpc_op_error grpc_event_write_accepted(const grpc_event *event) { |
||||||
|
GPR_ASSERT(event->type == GRPC_WRITE_ACCEPTED); |
||||||
|
return event->data.invoke_accepted; |
||||||
|
} |
||||||
|
|
||||||
|
grpc_op_error grpc_event_finish_accepted(const grpc_event *event) { |
||||||
|
GPR_ASSERT(event->type == GRPC_FINISH_ACCEPTED); |
||||||
|
return event->data.finish_accepted; |
||||||
|
} |
||||||
|
|
||||||
|
grpc_status_code grpc_event_finished_status(const grpc_event *event) { |
||||||
|
GPR_ASSERT(event->type == GRPC_FINISHED); |
||||||
|
return event->data.finished.status; |
||||||
|
} |
||||||
|
|
||||||
|
const char *grpc_event_finished_details(const grpc_event *event) { |
||||||
|
GPR_ASSERT(event->type == GRPC_FINISHED); |
||||||
|
return event->data.finished.details; |
||||||
|
} |
||||||
|
|
||||||
|
gpr_intptr grpc_event_read_length(const grpc_event *event) { |
||||||
|
GPR_ASSERT(event->type == GRPC_READ); |
||||||
|
if (!event->data.read) { |
||||||
|
return -1; |
||||||
|
} |
||||||
|
return grpc_byte_buffer_length(event->data.read); |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* Copies data from read event to a buffer. Fatal error occurs if |
||||||
|
* buffer is too small. |
||||||
|
*/ |
||||||
|
void grpc_event_read_copy_to_buffer(const grpc_event *event, char *buffer, |
||||||
|
size_t buffer_len) { |
||||||
|
grpc_byte_buffer_reader *reader; |
||||||
|
gpr_slice slice; |
||||||
|
size_t offset = 0; |
||||||
|
|
||||||
|
GPR_ASSERT(event->type == GRPC_READ); |
||||||
|
reader = grpc_byte_buffer_reader_create(event->data.read); |
||||||
|
|
||||||
|
GPR_ASSERT(event->data.read); |
||||||
|
while (grpc_byte_buffer_reader_next(reader, &slice)) { |
||||||
|
size_t len = GPR_SLICE_LENGTH(slice); |
||||||
|
GPR_ASSERT(offset + len <= buffer_len); |
||||||
|
memcpy(buffer + offset, GPR_SLICE_START_PTR(slice), |
||||||
|
GPR_SLICE_LENGTH(slice)); |
||||||
|
offset += len; |
||||||
|
gpr_slice_unref(slice); |
||||||
|
} |
||||||
|
grpc_byte_buffer_reader_destroy(reader); |
||||||
|
} |
||||||
|
|
||||||
|
grpc_call *grpc_event_call(const grpc_event *event) { |
||||||
|
/* we only allow this for newly incoming server calls. */ |
||||||
|
GPR_ASSERT(event->type == GRPC_SERVER_RPC_NEW); |
||||||
|
return event->call; |
||||||
|
} |
||||||
|
|
||||||
|
const char *grpc_event_server_rpc_new_method(const grpc_event *event) { |
||||||
|
GPR_ASSERT(event->type == GRPC_SERVER_RPC_NEW); |
||||||
|
return event->data.server_rpc_new.method; |
||||||
|
} |
||||||
|
|
||||||
|
grpc_completion_type grpc_completion_queue_next_with_callback( |
||||||
|
grpc_completion_queue *cq) { |
||||||
|
grpc_event *ev; |
||||||
|
grpc_completion_type t; |
||||||
|
void (*callback)(grpc_event *); |
||||||
|
|
||||||
|
ev = grpc_completion_queue_next(cq, gpr_inf_future); |
||||||
|
t = ev->type; |
||||||
|
if (ev->tag) { |
||||||
|
/* call the callback in ev->tag */ |
||||||
|
/* C forbids to cast object pointers to function pointers, so
|
||||||
|
* we cast to intptr first. |
||||||
|
*/ |
||||||
|
callback = (void (*)(grpc_event *))(gpr_intptr)ev->tag; |
||||||
|
(*callback)(ev); |
||||||
|
} |
||||||
|
grpc_event_finish(ev); |
||||||
|
|
||||||
|
/* return completion type to allow some handling for events that have no
|
||||||
|
* tag - such as GRPC_QUEUE_SHUTDOWN |
||||||
|
*/ |
||||||
|
return t; |
||||||
|
} |
@ -0,0 +1,2 @@ |
|||||||
|
build |
||||||
|
node_modules |
@ -1,6 +0,0 @@ |
|||||||
<?php |
|
||||||
function getNewPort() { |
|
||||||
static $port = 10000; |
|
||||||
$port += 1; |
|
||||||
return $port; |
|
||||||
} |
|
@ -0,0 +1,44 @@ |
|||||||
|
# Copyright 2014, 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. |
||||||
|
|
||||||
|
# Generated by the protocol buffer compiler. DO NOT EDIT! |
||||||
|
# source: google/protobuf/empty.proto |
||||||
|
|
||||||
|
require 'google/protobuf' |
||||||
|
|
||||||
|
Google::Protobuf::DescriptorPool.generated_pool.build do |
||||||
|
add_message "google.protobuf.Empty" do |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
module Google |
||||||
|
module Protobuf |
||||||
|
Empty = Google::Protobuf::DescriptorPool.generated_pool.lookup("google.protobuf.Empty").msgclass |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,278 @@ |
|||||||
|
#!/usr/bin/env ruby |
||||||
|
|
||||||
|
# Copyright 2014, 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. |
||||||
|
|
||||||
|
# pubsub_demo demos accesses the Google PubSub API via its gRPC interface |
||||||
|
# |
||||||
|
# TODO: update the Usage once the usable auth gem is available |
||||||
|
# $ SSL_CERT_FILE=<path/to/ssl/certs> \ |
||||||
|
# path/to/pubsub_demo.rb \ |
||||||
|
# --service_account_key_file=<path_to_service_account> \ |
||||||
|
# [--action=<chosen_demo_action> ] |
||||||
|
# |
||||||
|
# There are options related to the chosen action, see #parse_args below. |
||||||
|
# - the possible actions are given by the method names of NamedAction class |
||||||
|
# - the default action is list_some_topics |
||||||
|
|
||||||
|
this_dir = File.expand_path(File.dirname(__FILE__)) |
||||||
|
lib_dir = File.join(File.dirname(File.dirname(this_dir)), 'lib') |
||||||
|
$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir) |
||||||
|
$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir) |
||||||
|
|
||||||
|
require 'optparse' |
||||||
|
|
||||||
|
require 'grpc' |
||||||
|
require 'google/protobuf' |
||||||
|
|
||||||
|
require 'google/protobuf/empty' |
||||||
|
require 'tech/pubsub/proto/pubsub' |
||||||
|
require 'tech/pubsub/proto/pubsub_services' |
||||||
|
|
||||||
|
# loads the certificates used to access the test server securely. |
||||||
|
def load_prod_cert |
||||||
|
fail 'could not find a production cert' if ENV['SSL_CERT_FILE'].nil? |
||||||
|
p "loading prod certs from #{ENV['SSL_CERT_FILE']}" |
||||||
|
File.open(ENV['SSL_CERT_FILE']).read |
||||||
|
end |
||||||
|
|
||||||
|
# creates a SSL Credentials from the production certificates. |
||||||
|
def ssl_creds |
||||||
|
GRPC::Core::Credentials.new(load_prod_cert) |
||||||
|
end |
||||||
|
|
||||||
|
# Builds the metadata authentication update proc. |
||||||
|
# |
||||||
|
# TODO: replace this once the ruby usable auth repo is available. |
||||||
|
def auth_proc(opts) |
||||||
|
if GRPC::Auth::GCECredentials.on_gce? |
||||||
|
return GRPC::Auth::GCECredentials.new.updater_proc |
||||||
|
end |
||||||
|
fd = StringIO.new(File.read(opts.oauth_key_file)) |
||||||
|
GRPC::Auth::ServiceAccountCredentials.new(opts.oauth_scope, fd).updater_proc |
||||||
|
end |
||||||
|
|
||||||
|
# Creates a stub for accessing the publisher service. |
||||||
|
def publisher_stub(opts) |
||||||
|
address = "#{opts.host}:#{opts.port}" |
||||||
|
stub_clz = Tech::Pubsub::PublisherService::Stub # shorter |
||||||
|
logger.info("... access PublisherService at #{address}") |
||||||
|
stub_clz.new(address, |
||||||
|
creds: ssl_creds, update_metadata: auth_proc(opts), |
||||||
|
GRPC::Core::Channel::SSL_TARGET => opts.host) |
||||||
|
end |
||||||
|
|
||||||
|
# Creates a stub for accessing the subscriber service. |
||||||
|
def subscriber_stub(opts) |
||||||
|
address = "#{opts.host}:#{opts.port}" |
||||||
|
stub_clz = Tech::Pubsub::SubscriberService::Stub # shorter |
||||||
|
logger.info("... access SubscriberService at #{address}") |
||||||
|
stub_clz.new(address, |
||||||
|
creds: ssl_creds, update_metadata: auth_proc(opts), |
||||||
|
GRPC::Core::Channel::SSL_TARGET => opts.host) |
||||||
|
end |
||||||
|
|
||||||
|
# defines methods corresponding to each interop test case. |
||||||
|
class NamedActions |
||||||
|
include Tech::Pubsub |
||||||
|
|
||||||
|
# Initializes NamedActions |
||||||
|
# |
||||||
|
# @param pub [Stub] a stub for accessing the publisher service |
||||||
|
# @param sub [Stub] a stub for accessing the publisher service |
||||||
|
# @param args [Args] provides access to the command line |
||||||
|
def initialize(pub, sub, args) |
||||||
|
@pub = pub |
||||||
|
@sub = sub |
||||||
|
@args = args |
||||||
|
end |
||||||
|
|
||||||
|
# Removes the test topic if it exists |
||||||
|
def remove_topic |
||||||
|
name = test_topic_name |
||||||
|
p "... removing Topic #{name}" |
||||||
|
@pub.delete_topic(DeleteTopicRequest.new(topic: name)) |
||||||
|
p "removed Topic: #{name} OK" |
||||||
|
rescue GRPC::BadStatus => e |
||||||
|
p "Could not delete a topics: rpc failed with '#{e}'" |
||||||
|
end |
||||||
|
|
||||||
|
# Creates a test topic |
||||||
|
def create_topic |
||||||
|
name = test_topic_name |
||||||
|
p "... creating Topic #{name}" |
||||||
|
resp = @pub.create_topic(Topic.new(name: name)) |
||||||
|
p "created Topic: #{resp.name} OK" |
||||||
|
rescue GRPC::BadStatus => e |
||||||
|
p "Could not create a topics: rpc failed with '#{e}'" |
||||||
|
end |
||||||
|
|
||||||
|
# Lists topics in the project |
||||||
|
def list_some_topics |
||||||
|
p 'Listing topics' |
||||||
|
p '-------------_' |
||||||
|
list_project_topics.topic.each { |t| p t.name } |
||||||
|
rescue GRPC::BadStatus => e |
||||||
|
p "Could not list topics: rpc failed with '#{e}'" |
||||||
|
end |
||||||
|
|
||||||
|
# Checks if a topics exists in a project |
||||||
|
def check_exists |
||||||
|
name = test_topic_name |
||||||
|
p "... checking for topic #{name}" |
||||||
|
exists = topic_exists?(name) |
||||||
|
p "#{name} is a topic" if exists |
||||||
|
p "#{name} is not a topic" unless exists |
||||||
|
rescue GRPC::BadStatus => e |
||||||
|
p "Could not check for a topics: rpc failed with '#{e}'" |
||||||
|
end |
||||||
|
|
||||||
|
# Publishes some messages |
||||||
|
def random_pub_sub |
||||||
|
topic_name, sub_name = test_topic_name, test_sub_name |
||||||
|
create_topic_if_needed(topic_name) |
||||||
|
@sub.create_subscription(Subscription.new(name: sub_name, |
||||||
|
topic: topic_name)) |
||||||
|
msg_count = rand(10..30) |
||||||
|
msg_count.times do |x| |
||||||
|
msg = PubsubMessage.new(data: "message #{x}") |
||||||
|
@pub.publish(PublishRequest.new(topic: topic_name, message: msg)) |
||||||
|
end |
||||||
|
p "Sent #{msg_count} messages to #{topic_name}, checking for them now." |
||||||
|
batch = @sub.pull_batch(PullBatchRequest.new(subscription: sub_name, |
||||||
|
max_events: msg_count)) |
||||||
|
ack_ids = batch.pull_responses.map { |x| x.ack_id } |
||||||
|
p "Got #{ack_ids.size} messages; acknowledging them.." |
||||||
|
@sub.acknowledge(AcknowledgeRequest.new(subscription: sub_name, |
||||||
|
ack_id: ack_ids)) |
||||||
|
p "Test messages were acknowledged OK, deleting the subscription" |
||||||
|
del_req = DeleteSubscriptionRequest.new(subscription: sub_name) |
||||||
|
@sub.delete_subscription(del_req) |
||||||
|
rescue GRPC::BadStatus => e |
||||||
|
p "Could not do random pub sub: rpc failed with '#{e}'" |
||||||
|
end |
||||||
|
|
||||||
|
private |
||||||
|
|
||||||
|
# test_topic_name is the topic name to use in this test. |
||||||
|
def test_topic_name |
||||||
|
unless @args.topic_name.nil? |
||||||
|
return "/topics/#{@args.project_id}/#{@args.topic_name}" |
||||||
|
end |
||||||
|
now_text = Time.now.utc.strftime('%Y%m%d%H%M%S%L') |
||||||
|
"/topics/#{@args.project_id}/#{ENV['USER']}-#{now_text}" |
||||||
|
end |
||||||
|
|
||||||
|
# test_sub_name is the subscription name to use in this test. |
||||||
|
def test_sub_name |
||||||
|
unless @args.sub_name.nil? |
||||||
|
return "/subscriptions/#{@args.project_id}/#{@args.sub_name}" |
||||||
|
end |
||||||
|
now_text = Time.now.utc.strftime('%Y%m%d%H%M%S%L') |
||||||
|
"/subscriptions/#{@args.project_id}/#{ENV['USER']}-#{now_text}" |
||||||
|
end |
||||||
|
|
||||||
|
# determines if the topic name exists |
||||||
|
def topic_exists?(name) |
||||||
|
topics = list_project_topics.topic.map { |t| t.name } |
||||||
|
topics.include?(name) |
||||||
|
end |
||||||
|
|
||||||
|
def create_topic_if_needed(name) |
||||||
|
return if topic_exists?(name) |
||||||
|
@pub.create_topic(Topic.new(name: name)) |
||||||
|
end |
||||||
|
|
||||||
|
def list_project_topics |
||||||
|
q = "cloud.googleapis.com/project in (/projects/#{@args.project_id})" |
||||||
|
@pub.list_topics(ListTopicsRequest.new(query: q)) |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
# Args is used to hold the command line info. |
||||||
|
Args = Struct.new(:host, :oauth_scope, :oauth_key_file, :port, :action, |
||||||
|
:project_id, :topic_name, :sub_name) |
||||||
|
|
||||||
|
# validates the the command line options, returning them as an Arg. |
||||||
|
def parse_args |
||||||
|
args = Args.new('pubsub-staging.googleapis.com', |
||||||
|
'https://www.googleapis.com/auth/pubsub', |
||||||
|
nil, 443, 'list_some_topics', 'stoked-keyword-656') |
||||||
|
OptionParser.new do |opts| |
||||||
|
opts.on('--oauth_scope scope', |
||||||
|
'Scope for OAuth tokens') { |v| args['oauth_scope'] = v } |
||||||
|
opts.on('--server_host SERVER_HOST', 'server hostname') do |v| |
||||||
|
args.host = v |
||||||
|
end |
||||||
|
opts.on('--server_port SERVER_PORT', 'server port') do |v| |
||||||
|
args.port = v |
||||||
|
end |
||||||
|
opts.on('--service_account_key_file PATH', |
||||||
|
'Path to the service account json key file') do |v| |
||||||
|
args.oauth_key_file = v |
||||||
|
end |
||||||
|
|
||||||
|
# instance_methods(false) gives only the methods defined in that class. |
||||||
|
scenes = NamedActions.instance_methods(false).map { |t| t.to_s } |
||||||
|
scene_list = scenes.join(',') |
||||||
|
opts.on("--action CODE", scenes, {}, 'pick a demo action', |
||||||
|
" (#{scene_list})") do |v| |
||||||
|
args.action = v |
||||||
|
end |
||||||
|
|
||||||
|
# Set the remaining values. |
||||||
|
%w(project_id topic_name sub_name).each do |o| |
||||||
|
opts.on("--#{o} VALUE", "#{o}") do |v| |
||||||
|
args[o] = v |
||||||
|
end |
||||||
|
end |
||||||
|
end.parse! |
||||||
|
_check_args(args) |
||||||
|
end |
||||||
|
|
||||||
|
def _check_args(args) |
||||||
|
%w(host port action).each do |a| |
||||||
|
if args[a].nil? |
||||||
|
raise OptionParser::MissingArgument.new("please specify --#{a}") |
||||||
|
end |
||||||
|
end |
||||||
|
if args['oauth_key_file'].nil? || args['oauth_scope'].nil? |
||||||
|
fail(OptionParser::MissingArgument, |
||||||
|
'please specify both of --service_account_key_file and --oauth_scope') |
||||||
|
end |
||||||
|
args |
||||||
|
end |
||||||
|
|
||||||
|
def main |
||||||
|
args = parse_args |
||||||
|
pub, sub = publisher_stub(args), subscriber_stub(args) |
||||||
|
NamedActions.new(pub, sub, args).method(args.action).call |
||||||
|
end |
||||||
|
|
||||||
|
main |
@ -0,0 +1,174 @@ |
|||||||
|
# Copyright 2014, 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. |
||||||
|
|
||||||
|
# Generated by the protocol buffer compiler. DO NOT EDIT! |
||||||
|
# source: tech/pubsub/proto/pubsub.proto |
||||||
|
|
||||||
|
require 'google/protobuf' |
||||||
|
|
||||||
|
require 'google/protobuf/empty' |
||||||
|
Google::Protobuf::DescriptorPool.generated_pool.build do |
||||||
|
add_message "tech.pubsub.Topic" do |
||||||
|
optional :name, :string, 1 |
||||||
|
end |
||||||
|
add_message "tech.pubsub.PubsubMessage" do |
||||||
|
optional :data, :string, 1 |
||||||
|
optional :message_id, :string, 3 |
||||||
|
end |
||||||
|
add_message "tech.pubsub.GetTopicRequest" do |
||||||
|
optional :topic, :string, 1 |
||||||
|
end |
||||||
|
add_message "tech.pubsub.PublishRequest" do |
||||||
|
optional :topic, :string, 1 |
||||||
|
optional :message, :message, 2, "tech.pubsub.PubsubMessage" |
||||||
|
end |
||||||
|
add_message "tech.pubsub.PublishBatchRequest" do |
||||||
|
optional :topic, :string, 1 |
||||||
|
repeated :messages, :message, 2, "tech.pubsub.PubsubMessage" |
||||||
|
end |
||||||
|
add_message "tech.pubsub.PublishBatchResponse" do |
||||||
|
repeated :message_ids, :string, 1 |
||||||
|
end |
||||||
|
add_message "tech.pubsub.ListTopicsRequest" do |
||||||
|
optional :query, :string, 1 |
||||||
|
optional :max_results, :int32, 2 |
||||||
|
optional :page_token, :string, 3 |
||||||
|
end |
||||||
|
add_message "tech.pubsub.ListTopicsResponse" do |
||||||
|
repeated :topic, :message, 1, "tech.pubsub.Topic" |
||||||
|
optional :next_page_token, :string, 2 |
||||||
|
end |
||||||
|
add_message "tech.pubsub.DeleteTopicRequest" do |
||||||
|
optional :topic, :string, 1 |
||||||
|
end |
||||||
|
add_message "tech.pubsub.Subscription" do |
||||||
|
optional :name, :string, 1 |
||||||
|
optional :topic, :string, 2 |
||||||
|
optional :query, :string, 3 |
||||||
|
optional :truncation_policy, :message, 4, "tech.pubsub.Subscription.TruncationPolicy" |
||||||
|
optional :push_config, :message, 5, "tech.pubsub.PushConfig" |
||||||
|
optional :ack_deadline_seconds, :int32, 6 |
||||||
|
optional :garbage_collect_seconds, :int64, 7 |
||||||
|
end |
||||||
|
add_message "tech.pubsub.Subscription.TruncationPolicy" do |
||||||
|
optional :max_bytes, :int64, 1 |
||||||
|
optional :max_age_seconds, :int64, 2 |
||||||
|
end |
||||||
|
add_message "tech.pubsub.PushConfig" do |
||||||
|
optional :push_endpoint, :string, 1 |
||||||
|
end |
||||||
|
add_message "tech.pubsub.PubsubEvent" do |
||||||
|
optional :subscription, :string, 1 |
||||||
|
optional :message, :message, 2, "tech.pubsub.PubsubMessage" |
||||||
|
optional :truncated, :bool, 3 |
||||||
|
optional :deleted, :bool, 4 |
||||||
|
end |
||||||
|
add_message "tech.pubsub.GetSubscriptionRequest" do |
||||||
|
optional :subscription, :string, 1 |
||||||
|
end |
||||||
|
add_message "tech.pubsub.ListSubscriptionsRequest" do |
||||||
|
optional :query, :string, 1 |
||||||
|
optional :max_results, :int32, 3 |
||||||
|
optional :page_token, :string, 4 |
||||||
|
end |
||||||
|
add_message "tech.pubsub.ListSubscriptionsResponse" do |
||||||
|
repeated :subscription, :message, 1, "tech.pubsub.Subscription" |
||||||
|
optional :next_page_token, :string, 2 |
||||||
|
end |
||||||
|
add_message "tech.pubsub.TruncateSubscriptionRequest" do |
||||||
|
optional :subscription, :string, 1 |
||||||
|
end |
||||||
|
add_message "tech.pubsub.DeleteSubscriptionRequest" do |
||||||
|
optional :subscription, :string, 1 |
||||||
|
end |
||||||
|
add_message "tech.pubsub.ModifyPushConfigRequest" do |
||||||
|
optional :subscription, :string, 1 |
||||||
|
optional :push_config, :message, 2, "tech.pubsub.PushConfig" |
||||||
|
end |
||||||
|
add_message "tech.pubsub.PullRequest" do |
||||||
|
optional :subscription, :string, 1 |
||||||
|
optional :return_immediately, :bool, 2 |
||||||
|
end |
||||||
|
add_message "tech.pubsub.PullResponse" do |
||||||
|
optional :ack_id, :string, 1 |
||||||
|
optional :pubsub_event, :message, 2, "tech.pubsub.PubsubEvent" |
||||||
|
end |
||||||
|
add_message "tech.pubsub.PullBatchRequest" do |
||||||
|
optional :subscription, :string, 1 |
||||||
|
optional :return_immediately, :bool, 2 |
||||||
|
optional :max_events, :int32, 3 |
||||||
|
end |
||||||
|
add_message "tech.pubsub.PullBatchResponse" do |
||||||
|
repeated :pull_responses, :message, 2, "tech.pubsub.PullResponse" |
||||||
|
end |
||||||
|
add_message "tech.pubsub.ModifyAckDeadlineRequest" do |
||||||
|
optional :subscription, :string, 1 |
||||||
|
optional :ack_id, :string, 2 |
||||||
|
optional :ack_deadline_seconds, :int32, 3 |
||||||
|
end |
||||||
|
add_message "tech.pubsub.AcknowledgeRequest" do |
||||||
|
optional :subscription, :string, 1 |
||||||
|
repeated :ack_id, :string, 2 |
||||||
|
end |
||||||
|
add_message "tech.pubsub.NackRequest" do |
||||||
|
optional :subscription, :string, 1 |
||||||
|
repeated :ack_id, :string, 2 |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
module Tech |
||||||
|
module Pubsub |
||||||
|
Topic = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.Topic").msgclass |
||||||
|
PubsubMessage = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.PubsubMessage").msgclass |
||||||
|
GetTopicRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.GetTopicRequest").msgclass |
||||||
|
PublishRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.PublishRequest").msgclass |
||||||
|
PublishBatchRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.PublishBatchRequest").msgclass |
||||||
|
PublishBatchResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.PublishBatchResponse").msgclass |
||||||
|
ListTopicsRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.ListTopicsRequest").msgclass |
||||||
|
ListTopicsResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.ListTopicsResponse").msgclass |
||||||
|
DeleteTopicRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.DeleteTopicRequest").msgclass |
||||||
|
Subscription = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.Subscription").msgclass |
||||||
|
Subscription::TruncationPolicy = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.Subscription.TruncationPolicy").msgclass |
||||||
|
PushConfig = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.PushConfig").msgclass |
||||||
|
PubsubEvent = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.PubsubEvent").msgclass |
||||||
|
GetSubscriptionRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.GetSubscriptionRequest").msgclass |
||||||
|
ListSubscriptionsRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.ListSubscriptionsRequest").msgclass |
||||||
|
ListSubscriptionsResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.ListSubscriptionsResponse").msgclass |
||||||
|
TruncateSubscriptionRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.TruncateSubscriptionRequest").msgclass |
||||||
|
DeleteSubscriptionRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.DeleteSubscriptionRequest").msgclass |
||||||
|
ModifyPushConfigRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.ModifyPushConfigRequest").msgclass |
||||||
|
PullRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.PullRequest").msgclass |
||||||
|
PullResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.PullResponse").msgclass |
||||||
|
PullBatchRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.PullBatchRequest").msgclass |
||||||
|
PullBatchResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.PullBatchResponse").msgclass |
||||||
|
ModifyAckDeadlineRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.ModifyAckDeadlineRequest").msgclass |
||||||
|
AcknowledgeRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.AcknowledgeRequest").msgclass |
||||||
|
NackRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("tech.pubsub.NackRequest").msgclass |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,103 @@ |
|||||||
|
# Copyright 2014, 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. |
||||||
|
|
||||||
|
# Generated by the protocol buffer compiler. DO NOT EDIT! |
||||||
|
# Source: tech/pubsub/proto/pubsub.proto for package 'tech.pubsub' |
||||||
|
|
||||||
|
require 'grpc' |
||||||
|
require 'google/protobuf/empty' |
||||||
|
require 'tech/pubsub/proto/pubsub' |
||||||
|
|
||||||
|
module Tech |
||||||
|
module Pubsub |
||||||
|
module PublisherService |
||||||
|
|
||||||
|
# TODO: add proto service documentation here |
||||||
|
class Service |
||||||
|
|
||||||
|
include GRPC::GenericService |
||||||
|
|
||||||
|
self.marshal_class_method = :encode |
||||||
|
self.unmarshal_class_method = :decode |
||||||
|
self.service_name = 'tech.pubsub.PublisherService' |
||||||
|
|
||||||
|
rpc :CreateTopic, Topic, Topic |
||||||
|
rpc :Publish, PublishRequest, Google::Protobuf::Empty |
||||||
|
rpc :PublishBatch, PublishBatchRequest, PublishBatchResponse |
||||||
|
rpc :GetTopic, GetTopicRequest, Topic |
||||||
|
rpc :ListTopics, ListTopicsRequest, ListTopicsResponse |
||||||
|
rpc :DeleteTopic, DeleteTopicRequest, Google::Protobuf::Empty |
||||||
|
end |
||||||
|
|
||||||
|
Stub = Service.rpc_stub_class |
||||||
|
end |
||||||
|
module SubscriberService |
||||||
|
|
||||||
|
# TODO: add proto service documentation here |
||||||
|
class Service |
||||||
|
|
||||||
|
include GRPC::GenericService |
||||||
|
|
||||||
|
self.marshal_class_method = :encode |
||||||
|
self.unmarshal_class_method = :decode |
||||||
|
self.service_name = 'tech.pubsub.SubscriberService' |
||||||
|
|
||||||
|
rpc :CreateSubscription, Subscription, Subscription |
||||||
|
rpc :GetSubscription, GetSubscriptionRequest, Subscription |
||||||
|
rpc :ListSubscriptions, ListSubscriptionsRequest, ListSubscriptionsResponse |
||||||
|
rpc :DeleteSubscription, DeleteSubscriptionRequest, Google::Protobuf::Empty |
||||||
|
rpc :TruncateSubscription, TruncateSubscriptionRequest, Google::Protobuf::Empty |
||||||
|
rpc :ModifyPushConfig, ModifyPushConfigRequest, Google::Protobuf::Empty |
||||||
|
rpc :Pull, PullRequest, PullResponse |
||||||
|
rpc :PullBatch, PullBatchRequest, PullBatchResponse |
||||||
|
rpc :ModifyAckDeadline, ModifyAckDeadlineRequest, Google::Protobuf::Empty |
||||||
|
rpc :Acknowledge, AcknowledgeRequest, Google::Protobuf::Empty |
||||||
|
rpc :Nack, NackRequest, Google::Protobuf::Empty |
||||||
|
end |
||||||
|
|
||||||
|
Stub = Service.rpc_stub_class |
||||||
|
end |
||||||
|
module PushEndpointService |
||||||
|
|
||||||
|
# TODO: add proto service documentation here |
||||||
|
class Service |
||||||
|
|
||||||
|
include GRPC::GenericService |
||||||
|
|
||||||
|
self.marshal_class_method = :encode |
||||||
|
self.unmarshal_class_method = :decode |
||||||
|
self.service_name = 'tech.pubsub.PushEndpointService' |
||||||
|
|
||||||
|
rpc :HandlePubsubEvent, PubsubEvent, Google::Protobuf::Empty |
||||||
|
end |
||||||
|
|
||||||
|
Stub = Service.rpc_stub_class |
||||||
|
end |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,69 @@ |
|||||||
|
# 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. |
||||||
|
|
||||||
|
require 'faraday' |
||||||
|
require 'grpc/auth/signet' |
||||||
|
|
||||||
|
module Google |
||||||
|
module RPC |
||||||
|
# Module Auth provides classes that provide Google-specific authentication |
||||||
|
# used to access Google gRPC services. |
||||||
|
module Auth |
||||||
|
# Extends Signet::OAuth2::Client so that the auth token is obtained from |
||||||
|
# the GCE metadata server. |
||||||
|
class GCECredentials < Signet::OAuth2::Client |
||||||
|
COMPUTE_AUTH_TOKEN_URI = 'http://metadata/computeMetadata/v1/'\ |
||||||
|
'instance/service-accounts/default/token' |
||||||
|
COMPUTE_CHECK_URI = 'http://metadata.google.internal' |
||||||
|
|
||||||
|
# Detect if this appear to be a GCE instance, by checking if metadata |
||||||
|
# is available |
||||||
|
def self.on_gce?(options = {}) |
||||||
|
c = options[:connection] || Faraday.default_connection |
||||||
|
resp = c.get(COMPUTE_CHECK_URI) |
||||||
|
return false unless resp.status == 200 |
||||||
|
return false unless resp.headers.key?('Metadata-Flavor') |
||||||
|
return resp.headers['Metadata-Flavor'] == 'Google' |
||||||
|
rescue Faraday::ConnectionFailed |
||||||
|
return false |
||||||
|
end |
||||||
|
|
||||||
|
# Overrides the super class method to change how access tokens are |
||||||
|
# fetched. |
||||||
|
def fetch_access_token(options = {}) |
||||||
|
c = options[:connection] || Faraday.default_connection |
||||||
|
c.headers = { 'Metadata-Flavor' => 'Google' } |
||||||
|
resp = c.get(COMPUTE_AUTH_TOKEN_URI) |
||||||
|
Signet::OAuth2.parse_credentials(resp.body, |
||||||
|
resp.headers['content-type']) |
||||||
|
end |
||||||
|
end |
||||||
|
end |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,68 @@ |
|||||||
|
# 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. |
||||||
|
|
||||||
|
require 'grpc/auth/signet' |
||||||
|
require 'multi_json' |
||||||
|
require 'openssl' |
||||||
|
|
||||||
|
# Reads the private key and client email fields from service account JSON key. |
||||||
|
def read_json_key(json_key_io) |
||||||
|
json_key = MultiJson.load(json_key_io.read) |
||||||
|
fail 'missing client_email' unless json_key.key?('client_email') |
||||||
|
fail 'missing private_key' unless json_key.key?('private_key') |
||||||
|
[json_key['private_key'], json_key['client_email']] |
||||||
|
end |
||||||
|
|
||||||
|
module Google |
||||||
|
module RPC |
||||||
|
# Module Auth provides classes that provide Google-specific authentication |
||||||
|
# used to access Google gRPC services. |
||||||
|
module Auth |
||||||
|
# Authenticates requests using Google's Service Account credentials. |
||||||
|
# (cf https://developers.google.com/accounts/docs/OAuth2ServiceAccount) |
||||||
|
class ServiceAccountCredentials < Signet::OAuth2::Client |
||||||
|
TOKEN_CRED_URI = 'https://www.googleapis.com/oauth2/v3/token' |
||||||
|
AUDIENCE = TOKEN_CRED_URI |
||||||
|
|
||||||
|
# Initializes a ServiceAccountCredentials. |
||||||
|
# |
||||||
|
# @param scope [string|array] the scope(s) to access |
||||||
|
# @param json_key_io [IO] an IO from which the JSON key can be read |
||||||
|
def initialize(scope, json_key_io) |
||||||
|
private_key, client_email = read_json_key(json_key_io) |
||||||
|
super(token_credential_uri: TOKEN_CRED_URI, |
||||||
|
audience: AUDIENCE, |
||||||
|
scope: scope, |
||||||
|
issuer: client_email, |
||||||
|
signing_key: OpenSSL::PKey::RSA.new(private_key)) |
||||||
|
end |
||||||
|
end |
||||||
|
end |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,67 @@ |
|||||||
|
# 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. |
||||||
|
|
||||||
|
require 'signet/oauth_2/client' |
||||||
|
|
||||||
|
module Signet |
||||||
|
# Signet::OAuth2 supports OAuth2 authentication. |
||||||
|
module OAuth2 |
||||||
|
AUTH_METADATA_KEY = :Authorization |
||||||
|
# Signet::OAuth2::Client creates an OAuth2 client |
||||||
|
# |
||||||
|
# Here client is re-opened to add the #apply and #apply! methods which |
||||||
|
# update a hash map with the fetched authentication token |
||||||
|
# |
||||||
|
# Eventually, this change may be merged into signet itself, or some other |
||||||
|
# package that provides Google-specific auth via signet, and this extension |
||||||
|
# will be unnecessary. |
||||||
|
class Client |
||||||
|
# Updates a_hash updated with the authentication token |
||||||
|
def apply!(a_hash, opts = {}) |
||||||
|
# fetch the access token there is currently not one, or if the client |
||||||
|
# has expired |
||||||
|
fetch_access_token!(opts) if access_token.nil? || expired? |
||||||
|
a_hash[AUTH_METADATA_KEY] = "Bearer #{access_token}" |
||||||
|
end |
||||||
|
|
||||||
|
# Returns a clone of a_hash updated with the authentication token |
||||||
|
def apply(a_hash, opts = {}) |
||||||
|
a_copy = a_hash.clone |
||||||
|
apply!(a_copy, opts) |
||||||
|
a_copy |
||||||
|
end |
||||||
|
|
||||||
|
# Returns a reference to the #apply method, suitable for passing as |
||||||
|
# a closure |
||||||
|
def updater_proc |
||||||
|
lambda(&method(:apply)) |
||||||
|
end |
||||||
|
end |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,163 @@ |
|||||||
|
# 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. |
||||||
|
|
||||||
|
spec_dir = File.expand_path(File.join(File.dirname(__FILE__))) |
||||||
|
$LOAD_PATH.unshift(spec_dir) |
||||||
|
$LOAD_PATH.uniq! |
||||||
|
|
||||||
|
require 'faraday' |
||||||
|
require 'spec_helper' |
||||||
|
|
||||||
|
def build_json_response(payload) |
||||||
|
[200, |
||||||
|
{ 'Content-Type' => 'application/json; charset=utf-8' }, |
||||||
|
MultiJson.dump(payload)] |
||||||
|
end |
||||||
|
|
||||||
|
WANTED_AUTH_KEY = :Authorization |
||||||
|
|
||||||
|
shared_examples 'apply/apply! are OK' do |
||||||
|
# tests that use these examples need to define |
||||||
|
# |
||||||
|
# @client which should be an auth client |
||||||
|
# |
||||||
|
# @make_auth_stubs, which should stub out the expected http behaviour of the |
||||||
|
# auth client |
||||||
|
describe '#fetch_access_token' do |
||||||
|
it 'should set access_token to the fetched value' do |
||||||
|
token = '1/abcdef1234567890' |
||||||
|
stubs = make_auth_stubs with_access_token: token |
||||||
|
c = Faraday.new do |b| |
||||||
|
b.adapter(:test, stubs) |
||||||
|
end |
||||||
|
|
||||||
|
@client.fetch_access_token!(connection: c) |
||||||
|
expect(@client.access_token).to eq(token) |
||||||
|
stubs.verify_stubbed_calls |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
describe '#apply!' do |
||||||
|
it 'should update the target hash with fetched access token' do |
||||||
|
token = '1/abcdef1234567890' |
||||||
|
stubs = make_auth_stubs with_access_token: token |
||||||
|
c = Faraday.new do |b| |
||||||
|
b.adapter(:test, stubs) |
||||||
|
end |
||||||
|
|
||||||
|
md = { foo: 'bar' } |
||||||
|
@client.apply!(md, connection: c) |
||||||
|
want = { :foo => 'bar', WANTED_AUTH_KEY => "Bearer #{token}" } |
||||||
|
expect(md).to eq(want) |
||||||
|
stubs.verify_stubbed_calls |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
describe 'updater_proc' do |
||||||
|
it 'should provide a proc that updates a hash with the access token' do |
||||||
|
token = '1/abcdef1234567890' |
||||||
|
stubs = make_auth_stubs with_access_token: token |
||||||
|
c = Faraday.new do |b| |
||||||
|
b.adapter(:test, stubs) |
||||||
|
end |
||||||
|
|
||||||
|
md = { foo: 'bar' } |
||||||
|
the_proc = @client.updater_proc |
||||||
|
got = the_proc.call(md, connection: c) |
||||||
|
want = { :foo => 'bar', WANTED_AUTH_KEY => "Bearer #{token}" } |
||||||
|
expect(got).to eq(want) |
||||||
|
stubs.verify_stubbed_calls |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
describe '#apply' do |
||||||
|
it 'should not update the original hash with the access token' do |
||||||
|
token = '1/abcdef1234567890' |
||||||
|
stubs = make_auth_stubs with_access_token: token |
||||||
|
c = Faraday.new do |b| |
||||||
|
b.adapter(:test, stubs) |
||||||
|
end |
||||||
|
|
||||||
|
md = { foo: 'bar' } |
||||||
|
@client.apply(md, connection: c) |
||||||
|
want = { foo: 'bar' } |
||||||
|
expect(md).to eq(want) |
||||||
|
stubs.verify_stubbed_calls |
||||||
|
end |
||||||
|
|
||||||
|
it 'should add the token to the returned hash' do |
||||||
|
token = '1/abcdef1234567890' |
||||||
|
stubs = make_auth_stubs with_access_token: token |
||||||
|
c = Faraday.new do |b| |
||||||
|
b.adapter(:test, stubs) |
||||||
|
end |
||||||
|
|
||||||
|
md = { foo: 'bar' } |
||||||
|
got = @client.apply(md, connection: c) |
||||||
|
want = { :foo => 'bar', WANTED_AUTH_KEY => "Bearer #{token}" } |
||||||
|
expect(got).to eq(want) |
||||||
|
stubs.verify_stubbed_calls |
||||||
|
end |
||||||
|
|
||||||
|
it 'should not fetch a new token if the current is not expired' do |
||||||
|
token = '1/abcdef1234567890' |
||||||
|
stubs = make_auth_stubs with_access_token: token |
||||||
|
c = Faraday.new do |b| |
||||||
|
b.adapter(:test, stubs) |
||||||
|
end |
||||||
|
|
||||||
|
n = 5 # arbitrary |
||||||
|
n.times do |_t| |
||||||
|
md = { foo: 'bar' } |
||||||
|
got = @client.apply(md, connection: c) |
||||||
|
want = { :foo => 'bar', WANTED_AUTH_KEY => "Bearer #{token}" } |
||||||
|
expect(got).to eq(want) |
||||||
|
end |
||||||
|
stubs.verify_stubbed_calls |
||||||
|
end |
||||||
|
|
||||||
|
it 'should fetch a new token if the current one is expired' do |
||||||
|
token_1 = '1/abcdef1234567890' |
||||||
|
token_2 = '2/abcdef1234567890' |
||||||
|
|
||||||
|
[token_1, token_2].each do |t| |
||||||
|
stubs = make_auth_stubs with_access_token: t |
||||||
|
c = Faraday.new do |b| |
||||||
|
b.adapter(:test, stubs) |
||||||
|
end |
||||||
|
md = { foo: 'bar' } |
||||||
|
got = @client.apply(md, connection: c) |
||||||
|
want = { :foo => 'bar', WANTED_AUTH_KEY => "Bearer #{t}" } |
||||||
|
expect(got).to eq(want) |
||||||
|
stubs.verify_stubbed_calls |
||||||
|
@client.expires_at -= 3601 # default is to expire in 1hr |
||||||
|
end |
||||||
|
end |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,108 @@ |
|||||||
|
# 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. |
||||||
|
|
||||||
|
spec_dir = File.expand_path(File.join(File.dirname(__FILE__))) |
||||||
|
$LOAD_PATH.unshift(spec_dir) |
||||||
|
$LOAD_PATH.uniq! |
||||||
|
|
||||||
|
require 'apply_auth_examples' |
||||||
|
require 'faraday' |
||||||
|
require 'grpc/auth/compute_engine' |
||||||
|
require 'spec_helper' |
||||||
|
|
||||||
|
describe Google::RPC::Auth::GCECredentials do |
||||||
|
MD_URI = '/computeMetadata/v1/instance/service-accounts/default/token' |
||||||
|
GCECredentials = Google::RPC::Auth::GCECredentials |
||||||
|
|
||||||
|
before(:example) do |
||||||
|
@client = GCECredentials.new |
||||||
|
end |
||||||
|
|
||||||
|
def make_auth_stubs(with_access_token: '') |
||||||
|
Faraday::Adapter::Test::Stubs.new do |stub| |
||||||
|
stub.get(MD_URI) do |env| |
||||||
|
headers = env[:request_headers] |
||||||
|
expect(headers['Metadata-Flavor']).to eq('Google') |
||||||
|
build_json_response( |
||||||
|
'access_token' => with_access_token, |
||||||
|
'token_type' => 'Bearer', |
||||||
|
'expires_in' => 3600) |
||||||
|
end |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
it_behaves_like 'apply/apply! are OK' |
||||||
|
|
||||||
|
describe '#on_gce?' do |
||||||
|
it 'should be true when Metadata-Flavor is Google' do |
||||||
|
stubs = Faraday::Adapter::Test::Stubs.new do |stub| |
||||||
|
stub.get('/') do |_env| |
||||||
|
[200, |
||||||
|
{ 'Metadata-Flavor' => 'Google' }, |
||||||
|
''] |
||||||
|
end |
||||||
|
end |
||||||
|
c = Faraday.new do |b| |
||||||
|
b.adapter(:test, stubs) |
||||||
|
end |
||||||
|
expect(GCECredentials.on_gce?(connection: c)).to eq(true) |
||||||
|
stubs.verify_stubbed_calls |
||||||
|
end |
||||||
|
|
||||||
|
it 'should be false when Metadata-Flavor is not Google' do |
||||||
|
stubs = Faraday::Adapter::Test::Stubs.new do |stub| |
||||||
|
stub.get('/') do |_env| |
||||||
|
[200, |
||||||
|
{ 'Metadata-Flavor' => 'NotGoogle' }, |
||||||
|
''] |
||||||
|
end |
||||||
|
end |
||||||
|
c = Faraday.new do |b| |
||||||
|
b.adapter(:test, stubs) |
||||||
|
end |
||||||
|
expect(GCECredentials.on_gce?(connection: c)).to eq(false) |
||||||
|
stubs.verify_stubbed_calls |
||||||
|
end |
||||||
|
|
||||||
|
it 'should be false if the response is not 200' do |
||||||
|
stubs = Faraday::Adapter::Test::Stubs.new do |stub| |
||||||
|
stub.get('/') do |_env| |
||||||
|
[404, |
||||||
|
{ 'Metadata-Flavor' => 'Google' }, |
||||||
|
''] |
||||||
|
end |
||||||
|
end |
||||||
|
c = Faraday.new do |b| |
||||||
|
b.adapter(:test, stubs) |
||||||
|
end |
||||||
|
expect(GCECredentials.on_gce?(connection: c)).to eq(false) |
||||||
|
stubs.verify_stubbed_calls |
||||||
|
end |
||||||
|
end |
||||||
|
end |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue