Skip to content

Instantly share code, notes, and snippets.

additional_commands:
protobuf_generate:
flags:
- APPEND_PATH
kwargs:
LANGUAGE: '1'
OUT_VAR: '1'
EXPORT_MACRO: '1'
PROTOC_OUT_DIR: '1'
PLUGIN: '1'
find_package(asio-grpc CONFIG REQUIRED)
add_library(proto-objects OBJECT)
target_link_libraries(proto-objects PUBLIC protobuf::libprotobuf gRPC::grpc++_unsecure)
set(PROTO_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
set(PROTO_IMPORT_DIRS "${CMAKE_CURRENT_LIST_DIR}/proto")
asio_grpc_protobuf_generate(
find_package(protobuf CONFIG REQUIRED)
find_package(gRPC CONFIG REQUIRED)
add_library(proto-objects OBJECT "${CMAKE_CURRENT_LIST_DIR}/proto/helloworld/helloworld.proto")
target_link_libraries(proto-objects PUBLIC protobuf::libprotobuf gRPC::grpc++_unsecure)
set(PROTO_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
set(PROTO_IMPORT_DIRS "${CMAKE_CURRENT_LIST_DIR}/proto")
@Tradias
Tradias / invoke_front.hpp
Created September 14, 2021 18:47
Invoke F with the largest leading subset of Args
#include <functional>
template <class F, class... Args, std::size_t... I>
constexpr decltype(auto) invoke_front_impl(F&& f, std::tuple<Args...>&& args, std::index_sequence<I...>)
{
if constexpr (std::is_invocable_v<F&&, std::tuple_element_t<I, std::tuple<Args...>>...>)
{
return std::invoke(std::forward<F>(f), std::get<I>(std::move(args))...);
}
else if constexpr (sizeof...(I) > 1)
@Tradias
Tradias / processRpc.cpp
Last active September 14, 2021 18:22
C++20 coroutines for asynchronous gRPC services
template <class CompletionToken>
auto read(grpc::ClientAsyncReader<helloworld::HelloReply>& reader, helloworld::HelloReply& reply,
CompletionToken token)
{
return boost::asio::async_initiate<CompletionToken, void(bool)>(
[&](auto completion_handler)
{
void* tag =
allocate<Operation<decltype(completion_handler)>>(std::move(completion_handler));
reader.Read(&reply, tag);
@Tradias
Tradias / operation.hpp
Last active September 14, 2021 18:23
C++20 coroutines for asynchronous gRPC services
struct TypeErasedOperation : boost::intrusive::slist_base_hook<>
{
using OnCompleteFunction = void (*)(TypeErasedOperation*, bool);
OnCompleteFunction on_complete;
void complete(bool ok) { this->on_complete(this, ok); }
TypeErasedOperation(OnCompleteFunction on_complete) : on_complete(on_complete) {}
};
@Tradias
Tradias / grpcExecutor.hpp
Last active September 14, 2021 18:23
C++20 coroutines for asynchronous gRPC services
struct GrpcContext::executor_type
{
GrpcContext* grpc_context;
template <class Function>
void execute(Function function) const
{
auto* op = allocate<Operation<Function>>(function);
grpc_context->queued_operations.push_front(*op);
grpc_context->alarm.Set(grpc_context->queue.get(), gpr_time_0(GPR_CLOCK_REALTIME),
@Tradias
Tradias / grpcContextRun.hpp
Created September 14, 2021 18:14
C++20 coroutines for asynchronous gRPC services
static constexpr void* MARKER_TAG = nullptr;
void run()
{
void* tag;
bool ok;
while (queue->Next(&tag, &ok))
{
if (MARKER_TAG == tag)
{
@Tradias
Tradias / grpcContext.hpp
Last active September 19, 2021 10:32
C++20 coroutines for asynchronous gRPC services
struct GrpcContext : boost::asio::execution_context
{
struct executor_type;
std::unique_ptr<grpc::CompletionQueue> queue;
QueuedOperations queued_operations;
grpc::Alarm alarm;
~GrpcContext()
{
@Tradias
Tradias / agrpcServerExample.cpp
Last active September 14, 2021 18:24
C++20 coroutines for asynchronous gRPC services
grpc::ServerContext server_context;
helloworld::HelloRequest request;
grpc::ServerAsyncResponseWriter<helloworld::HelloReply> writer{&server_context};
co_await request(&helloworld::Greeter::AsyncService::RequestSayHello, service,
server_context, request, writer);
helloworld::HelloReply response;
response.set_message("Hello " + request.name());
co_await finish(writer, response, grpc::Status::OK);