Compare commits

...

2 Commits
main ... yu

Author SHA1 Message Date
yhy
9d9fb69cbb rpc 部分逻辑 未完成 2025-01-22 17:58:45 +08:00
yhy
df8789f6c6 临时保存 2025-01-21 16:35:26 +08:00
24 changed files with 2976 additions and 37 deletions

2
.gitignore vendored
View File

@ -1,4 +1,4 @@
bin/
build/
lib/
core*
protobuf/

View File

@ -2,18 +2,25 @@ cmake_minimum_required(VERSION 3.0)
project(tinyrpc)
set(CMAKE_CXX_STANDARD 17)
enable_language(CXX ASM)
add_compile_options(-g -Wall -std=c++11)
add_compile_options(-g -Wall)
include_directories(includes/coroutine)
include_directories(includes/log)
include_directories(includes/net)
include_directories(includes/net/tcp)
include_directories(includes/net/tinypb)
aux_source_directory(${CMAKE_SOURCE_DIR}/src SRC_LIST)
aux_source_directory(${CMAKE_SOURCE_DIR}/src/coroutine COROUTINE_SRC_LIST)
aux_source_directory(${CMAKE_SOURCE_DIR}/src/net NET_SRC_LIST)
aux_source_directory(${CMAKE_SOURCE_DIR}/src/net/tcp TCP_SRC_LIST)
aux_source_directory(${CMAKE_SOURCE_DIR}/src/net/tinypb TINYPB_SRC_LIST)
set(ASM_FILES ${CMAKE_SOURCE_DIR}/src/coroutine/coctx_swap.S)
@ -25,9 +32,11 @@ set(LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin)
add_library(tinyrpc
# ${SRC_LIST}
${COROUTINE_SRC_LIST}
${TCP_SRC_LIST}
${NET_SRC_LIST}
${TINYPB_SRC_LIST}
${ASM_FILES}
)
@ -38,5 +47,53 @@ add_executable(test_tinyrpc
${TEST_SRC_LIST}
)
# abseil-cpp
add_subdirectory(./third_party/abseil-cpp absl)
set(ABSEL_LIBARARY
absl::absl_check
absl::absl_log
absl::algorithm
absl::base
absl::bind_front
absl::bits
absl::btree
absl::cleanup
absl::cord
absl::core_headers
absl::debugging
absl::die_if_null
absl::dynamic_annotations
absl::flags
absl::flat_hash_map
absl::flat_hash_set
absl::function_ref
absl::hash
absl::layout
absl::log_initialize
absl::log_severity
absl::memory
absl::node_hash_map
absl::node_hash_set
absl::optional
absl::span
absl::status
absl::statusor
absl::strings
absl::synchronization
absl::time
absl::type_traits
absl::utility
absl::variant
)
#
target_link_libraries(tinyrpc PRIVATE protobuf) # Protobuf
target_link_libraries(tinyrpc PRIVATE ${ABSEL_LIBARARY}) # Protobuf
target_link_libraries(test_tinyrpc PRIVATE tinyrpc)
target_link_libraries(test_tinyrpc PUBLIC stdc++)

View File

@ -0,0 +1,38 @@
#pragma once
#include "tcp_buffer.hpp"
#include <cstdint>
#include <netinet/in.h>
namespace tinyrpc {
struct AbstractData {
AbstractData() = default;
virtual ~AbstractData() = default;
};
class AbstractCoder {
public:
AbstractCoder() = default;
virtual ~AbstractCoder() = default;
virtual bool encoder(TcpBuffer& buffer, AbstractData& data) = 0; // 编码
virtual bool decoder(TcpBuffer& buffer, AbstractData& data) = 0; // 解码
// virtual std::string getProtocalType() = 0;
private:
};
inline int32_t getInt32FromNetByte(char& buf) {
int32_t tmp;
memcpy(&tmp, &buf, sizeof(tmp));
return ntohl(tmp);
}
}

View File

@ -0,0 +1,20 @@
#pragma once
#include "abstract_coder.hpp"
#include "tcp_connection.hpp"
namespace tinyrpc {
class AbstractDispatcher {
public:
AbstractDispatcher() = default;
virtual ~AbstractDispatcher() = default;
virtual void dispatcher(TcpConnection& conn, AbstractData& data, AbstractData& respond) = 0;
private:
};
}

View File

@ -0,0 +1,26 @@
#pragma once
namespace tinyrpc {
enum ErrorCode {
ERROR_PEER_CLOSED, // connect when peer close
ERROR_FAILED_CONNECT, // failed to connection peer host
ERROR_FAILED_GET_REPLY, // failed to get server reply
ERROR_FAILED_DESERIALIZE, // deserialize failed
ERROR_FAILED_SERIALIZE, // serialize failed
ERROR_FAILED_ENCODE, // encode failed
ERROR_FAILED_DECODE, // decode failed
ERROR_RPC_CALL_TIMEOUT, // call rpc timeout
ERROR_SERVICE_NOT_FOUND, // not found service name
ERROR_METHOD_NOT_FOUND, // not found method
ERROR_PARSE_SERVICE_NAME, // not found service name
ERROR_ASYNC_RPC_CALL_SINGLE_IOTHREAD, // not supoort async rpc call when only have single iothread
};
}

View File

@ -1,7 +1,6 @@
#pragma once
#include "reactor.hpp"
#include "tcp_connection.hpp"
#include <atomic>
#include <mutex>
#include <thread>
#include <unordered_map>
@ -9,11 +8,11 @@
#include <vector>
namespace tinyrpc {
class TcpServer;
class IOThread {
friend class IOThreadPool;
public:
void addClient(int fd);
void addClient(TcpServer* ser, int fd);
static IOThread* getThisIoThread();
// void removeFd(int fd);
Reactor* getReactor() {return m_reactor;}

View File

@ -1,12 +1,13 @@
#pragma once
#include "abstract_coder.hpp"
#include "coroutine.hpp"
#include "fd_event.hpp"
#include "reactor.hpp"
#include "tcp_buffer.hpp"
namespace tinyrpc {
namespace tinyrpc {
class TcpServer;
class TcpConnection {
public:
enum class State{
@ -14,9 +15,9 @@ namespace tinyrpc {
Connected
};
public:
TcpConnection(int fd, Reactor* reactor);
TcpConnection(int fd, Reactor& reactor, TcpServer& ser);
void clearClient();
void mainLoopFun();
@ -34,7 +35,8 @@ namespace tinyrpc {
State m_state{State::Connected};
TcpBuffer m_writeBuffer{};
TcpBuffer m_readBuffer{};
Reactor* m_reactor{};
Reactor& m_reactor;
TcpServer& m_server;
};
}

View File

@ -1,4 +1,6 @@
#pragma once
#include "abstract_coder.hpp"
#include "abstract_dispatcher.hpp"
#include "coroutine.hpp"
#include "io_thread.hpp"
#include "net_address.hpp"
@ -22,7 +24,10 @@ namespace tinyrpc {
TcpServer();
TcpServer(const NetAddress& addr);
TcpServer(const std::string& ip, uint16_t port);
~TcpServer();
void start();
AbstractCoder& getCoder() {return *m_coder;}
AbstractDispatcher& getDispatcher() {return *m_dispatcher;}
private:
void mainAcceptCorFun();
private:
@ -34,6 +39,8 @@ namespace tinyrpc {
// int m_conn_cnt{0};
// IOThread m_ioThread{};
IOThreadPool m_ioThreadPool{4};
AbstractCoder* m_coder{};
AbstractDispatcher* m_dispatcher{};
};
}

View File

@ -0,0 +1,19 @@
#pragma once
#include "abstract_coder.hpp"
namespace tinyrpc {
class TinypbCoder : public AbstractCoder {
public:
TinypbCoder();
~TinypbCoder();
bool encoder(TcpBuffer& buffer, AbstractData& data) override; // 编码
bool decoder(TcpBuffer& buffer, AbstractData& data) override; // 解码
private:
};
}

View File

@ -0,0 +1,31 @@
#pragma once
#include "abstract_coder.hpp"
#include <cstdint>
#include <string>
namespace tinyrpc {
struct TinypbData : public AbstractData {
TinypbData() {};
~TinypbData() {};
// char start = 0x02; // indentify start of a TinyPb protocal data
int32_t pk_len {0}; // len of all package(include start char and end char)
int32_t msg_req_len {0}; // len of msg_req
std::string msg_req; // msg_req, which identify a request
int32_t service_name_len {0}; // len of service full name
std::string service_full_name; // service full name, like QueryService.query_name
int32_t err_code {0}; // err_code, 0 -- call rpc success, otherwise -- call rpc failed. it only be seted by RpcController
int32_t err_info_len {0}; // len of err_info
std::string err_info; // err_info, empty -- call rpc success, otherwise -- call rpc failed, it will display details of reason why call rpc failed. it only be seted by RpcController
std::string pb_data; // business pb data
int32_t check_num {-1}; // check_num of all package. to check legality of data
// char end = 0x03; // identify end of a TinyPb protocal data
};
}

View File

@ -0,0 +1,27 @@
#pragma once
#include "abstract_dispatcher.hpp"
#include <unordered_map>
#include <google/protobuf/message.h>
#include <google/protobuf/service.h>
#include <google/protobuf/descriptor.h>
namespace tinyrpc {
class TinypbDispatcher : public AbstractDispatcher {
using Service = google::protobuf::Service;
using Method = google::protobuf::MethodDescriptor;
using Message = google::protobuf::Message;
public:
TinypbDispatcher();
~TinypbDispatcher();
void dispatcher(TcpConnection& conn, AbstractData& data, AbstractData& respond) override;
bool parseServiceFullName(const std::string& name, std::string& serviceName, std::string& methodName);
private:
std::unordered_map<std::string, Service*> m_service_map;
};
}

View File

@ -274,4 +274,6 @@ namespace tinyrpc {
close(m_rousefd);
t_reactor = nullptr;
}
}
}

View File

@ -3,6 +3,7 @@
#include "reactor.hpp"
#include "coroutine.hpp"
#include "tcp_connection.hpp"
#include "tcp_server.hpp"
#include <memory>
#include <mutex>
#include <thread>
@ -23,9 +24,9 @@ namespace tinyrpc {
void IOThread::addClient(int fd) {
void IOThread::addClient(TcpServer* ser, int fd) {
m_clients[fd] = std::make_shared<TcpConnection>(fd, m_reactor);
m_clients[fd] = std::make_shared<TcpConnection>(fd, *m_reactor, *ser);
}

View File

@ -1,26 +1,31 @@
#include "tcp_connection.hpp"
#include "abstract_coder.hpp"
#include "coroutine_hook.hpp"
#include "fd_event.hpp"
#include "logger.hpp"
#include "reactor.hpp"
#include "tcp_server.hpp"
#include "tinypb_data.hpp"
#include <cerrno>
#include <cstring>
#include <memory>
#include <pthread.h>
#include <unistd.h>
namespace tinyrpc {
TcpConnection::TcpConnection(int fd, Reactor* reactor) :
TcpConnection::TcpConnection(int fd, Reactor& reactor, TcpServer& ser) :
m_fdEvent(FdEventPool::getInstance()->getFdEvent(fd)),
m_mainCoroutine(std::bind(&TcpConnection::mainLoopFun, this)),
m_reactor(reactor)
m_reactor(reactor),
m_server(ser)
{
Reactor::Task task = [this] {
logger() << "conn coroutine is resume";
m_mainCoroutine.resume();
};
reactor->addTask(task, true);
reactor.addTask(task, true);
}
@ -36,7 +41,7 @@ namespace tinyrpc {
void TcpConnection::clearClient() {
logger() << "clearClient";
m_state = State::Disconnected;
m_reactor->delFdEvent(m_fdEvent);
m_reactor.delFdEvent(m_fdEvent);
m_fdEvent->reset();
close(m_fdEvent->getFd());
}
@ -110,17 +115,33 @@ namespace tinyrpc {
void TcpConnection::process() {
logger() << "process";
if(m_state == State::Disconnected) {
return;
}
if(m_writeBuffer.getWriteable() < m_readBuffer.getReadable()) {
m_writeBuffer.resize(m_readBuffer.getReadable() * 2);
}
std::memcpy(m_writeBuffer.getWriteAddress(), m_readBuffer.getReadAddress(), m_readBuffer.getReadable());
m_writeBuffer.writeOffset(m_readBuffer.getReadable());
m_readBuffer.readOffset(m_readBuffer.getReadable());
// if(m_state == State::Disconnected) {
// return;
// }
// if(m_writeBuffer.getWriteable() < m_readBuffer.getReadable()) {
// m_writeBuffer.resize(m_readBuffer.getReadable() * 2);
// }
// std::memcpy(m_writeBuffer.getWriteAddress(), m_readBuffer.getReadAddress(), m_readBuffer.getReadable());
// m_writeBuffer.writeOffset(m_readBuffer.getReadable());
// m_readBuffer.readOffset(m_readBuffer.getReadable());
logger() << "write data " << m_writeBuffer.getReadable() << " byte";
// logger() << "write data " << m_writeBuffer.getReadable() << " byte";
while(m_readBuffer.getReadable() > 0) {
std::unique_ptr<AbstractData> data(new TinypbData);
bool ret = m_server.getCoder().decoder(m_readBuffer, *data);
if(ret == false) {
logger() << "decode error";
break;
}
std::unique_ptr<AbstractData> resp(new TinypbData);
m_server.getDispatcher().dispatcher(*this, *data, *resp);
m_server.getCoder().encoder(m_writeBuffer, *resp);
}
}
TcpConnection::~TcpConnection() {

View File

@ -5,6 +5,8 @@
#include "coroutine_hook.hpp"
#include "net_address.hpp"
#include "reactor.hpp"
#include "tinypb_coder.hpp"
#include "tinypb_dispatcher.hpp"
#include <cerrno>
#include <cstring>
#include <netinet/in.h>
@ -58,21 +60,25 @@ namespace tinyrpc {
}
TcpServer::TcpServer() :
m_accept_cor(std::bind(&TcpServer::mainAcceptCorFun, this)),
m_acceptor(NetAddress())
{
m_acceptor.init();
}
TcpServer::TcpServer(const NetAddress& addr) :
m_accept_cor(std::bind(&TcpServer::mainAcceptCorFun, this)),
m_acceptor(addr)
m_acceptor(addr),
m_coder(new TinypbCoder),
m_dispatcher(new TinypbDispatcher)
{
m_acceptor.init();
}
TcpServer::TcpServer(const std::string& ip, uint16_t port) : TcpServer(NetAddress(ip, port)) {
TcpServer::TcpServer() :
TcpServer(NetAddress("127.0.0.1", 9001)) {}
TcpServer::TcpServer(const std::string& ip, uint16_t port) :
TcpServer(NetAddress(ip, port)) {}
TcpServer::~TcpServer() {
delete m_coder;
delete m_dispatcher;
}
void TcpServer::start() {
@ -93,7 +99,7 @@ namespace tinyrpc {
logger() << "new connect fd = " << fd;
logger() << " 添加 fd 到子 reactor 中 " << fd;
m_ioThreadPool.getIOThread()->addClient(fd);
m_ioThreadPool.getIOThread()->addClient(this, fd);
}
}

View File

@ -0,0 +1,217 @@
#include "tinypb_coder.hpp"
#include "abstract_coder.hpp"
#include "tinypb_data.hpp"
#include <cstdint>
#include <cstring>
#include <memory>
#include <netinet/in.h>
#include <new>
#include <vector>
namespace tinyrpc {
static const char PB_START = 0x02; // start char
static const char PB_END = 0x03; // end char
// static const int MSG_REQ_LEN = 20; // default length of msg_req
TinypbCoder::TinypbCoder() {
// TODO
}
TinypbCoder::~TinypbCoder() {
// TODO
}
bool TinypbCoder::encoder(TcpBuffer& buffer, AbstractData& data) {
TinypbData& pbdata = dynamic_cast<TinypbData&>(data);
if(pbdata.msg_req.empty()) return false;
if(pbdata.service_full_name.empty()) return false;
if(pbdata.pb_data.empty()) return false;
// TODO msg_req 处理
int32_t pk_len = 2 * sizeof(char) + 6 * sizeof(int32_t)
+ pbdata.pb_data.length() + pbdata.service_full_name.length()
+ pbdata.msg_req.length() + pbdata.err_info.length();
std::unique_ptr<char[]> buf(new char[pk_len + 1]{});
int cur_index = 0;
buf[cur_index++] = PB_START;
int32_t pk_len_net = htonl(pk_len);
memcpy(&buf[cur_index], &pk_len_net, sizeof(pk_len_net));
cur_index += sizeof(pk_len_net);
int32_t msg_req_len = pbdata.msg_req.length();
int32_t msg_req_len_net = htonl(msg_req_len);
memcpy(&buf[cur_index], &msg_req_len_net, sizeof(msg_req_len_net));
cur_index += sizeof(msg_req_len_net);
memcpy(&buf[cur_index], pbdata.msg_req.c_str(), msg_req_len);
cur_index += msg_req_len;
int32_t service_name_len = pbdata.service_full_name.length();
int32_t service_name_len_net = htonl(service_name_len);
memcpy(&buf[cur_index], &service_name_len_net, sizeof(service_name_len_net));
cur_index += sizeof(service_name_len_net);
memcpy(&buf[cur_index], pbdata.msg_req.c_str(), service_name_len);
cur_index += service_name_len;
int32_t err_code = pbdata.err_code;
int32_t err_code_net = htonl(err_code);
memcpy(&buf[cur_index], &err_code_net, sizeof(err_code_net));
cur_index += sizeof(err_code_net);
int32_t err_info_len = pbdata.err_info.length();
int32_t err_info_len_net = htonl(err_info_len);
memcpy(&buf[cur_index], &err_info_len_net, sizeof(err_info_len_net));
cur_index += sizeof(err_info_len_net);
memcpy(&buf[cur_index], pbdata.err_info.c_str(), err_info_len);
cur_index += err_info_len;
int32_t pb_data_len = pbdata.err_info.length();
memcpy(&buf[cur_index], pbdata.pb_data.c_str(), pb_data_len);
cur_index += pb_data_len;
int32_t check_num = 1;
int32_t check_num_net = htonl(check_num);
memcpy(&buf[cur_index], &check_num_net, sizeof(check_num_net));
cur_index += sizeof(check_num_net);
buf[cur_index++] = PB_END;
memcpy(buffer.getWriteAddress(), buf.get(), pk_len);
buffer.writeOffset(pk_len);
return true;
}
bool TinypbCoder::decoder(TcpBuffer& buffer, AbstractData& data) {
char* buff = static_cast<char*>(buffer.getReadAddress());
int start_index = -1;
int end_index = -1;
bool isFullPack = false;
int pack_len = -1;
for(int i = 0; i < static_cast<int>(buffer.getReadable()); i++) {
if(buff[i] == PB_START) {
if(i + 1 >= static_cast<int>(buffer.getReadable())) {
return false; // 包不完整
}
pack_len = getInt32FromNetByte(buff[i + 1]);
end_index = pack_len + i - 1;
if(end_index >= static_cast<int>(buffer.getReadable())) {
continue;
}
if(buff[end_index] == PB_END) {
isFullPack = true;
start_index = i;
break;
}
}
}
if(isFullPack == false) {
return false; // 包不完整
}
TinypbData& pbdata = dynamic_cast<TinypbData&>(data);
pbdata.pk_len = pack_len;
int cur_index = start_index + sizeof(char) + sizeof(int32_t);
if (cur_index > end_index) {
return false;
}
pbdata.msg_req_len = getInt32FromNetByte(buff[cur_index]);
cur_index = cur_index + sizeof(int32_t);
if (cur_index > end_index || cur_index + pbdata.msg_req_len - 1 > end_index) {
return false;
}
std::unique_ptr<char[]> msg_req(new char[pbdata.msg_req_len + 1]{});
memcpy(&msg_req[0], &buff[cur_index], pbdata.msg_req_len);
pbdata.msg_req = std::string(msg_req.get());
cur_index = cur_index + pbdata.msg_req_len;
if (cur_index > end_index || cur_index + static_cast<int>(sizeof(int32_t)) - 1 > end_index) {
return false;
}
pbdata.service_name_len = getInt32FromNetByte(buff[cur_index]);
if (pbdata.service_name_len > pack_len) {
return false;
}
cur_index = cur_index + sizeof(int32_t);
if (cur_index > end_index || cur_index + pbdata.service_name_len - 1 >end_index) {
return false;
}
std::unique_ptr<char[]> service_name(new char[pbdata.service_name_len + 1]{});
memcpy(&service_name[0], &buff[cur_index], pbdata.service_name_len);
pbdata.service_full_name = std::string(service_name.get());
cur_index = cur_index + pbdata.service_name_len;
if(cur_index > end_index || cur_index + static_cast<int>(sizeof(int32_t)) - 1 > end_index) {
return false;
}
pbdata.err_code = getInt32FromNetByte(buff[cur_index]);
cur_index = cur_index + sizeof(int32_t);
if(cur_index > end_index || cur_index + static_cast<int>(sizeof(int32_t)) - 1 > end_index) {
return false;
}
pbdata.err_info_len = getInt32FromNetByte(buff[cur_index]);
cur_index = cur_index + sizeof(int32_t);
if(cur_index > end_index || cur_index + pbdata.err_info_len - 1 > end_index) {
return false;
}
std::unique_ptr<char[]> err_info(new char[pbdata.err_info_len + 1]{});
memcpy(&err_info[0], &buff[cur_index], pbdata.err_info_len);
pbdata.err_info = std::string(err_info.get());
int pb_data_len = pbdata.pk_len
- pbdata.service_name_len - pbdata.msg_req_len - pbdata.err_info_len
- 2 * sizeof(char) - 6 * sizeof(int32_t);
cur_index = cur_index + pbdata.err_info_len;
if(cur_index > end_index || cur_index + pb_data_len - 1 > end_index) {
return false;
}
pbdata.pb_data = std::string(&buff[cur_index], pb_data_len);
cur_index += pb_data_len;
buffer.readOffset(cur_index - start_index);
return true;
}
}

View File

@ -0,0 +1,98 @@
#include "tinypb_dispatcher.hpp"
#include "logger.hpp"
#include "tinypb_data.hpp"
#include "error_code.hpp"
#include <cstddef>
#include <memory>
#include <sstream>
namespace tinyrpc {
TinypbDispatcher::TinypbDispatcher() {}
TinypbDispatcher::~TinypbDispatcher() {
}
void TinypbDispatcher::dispatcher(TcpConnection& conn, AbstractData& data, AbstractData& resp) {
logger() << "dispatcher";
TinypbData& pbdata = dynamic_cast<TinypbData&>(data);
TinypbData& respond = dynamic_cast<TinypbData&>(resp);
std::string service_name;
std::string method_name;
respond.service_full_name = pbdata.service_full_name;
respond.msg_req = pbdata.msg_req;
bool ret = parseServiceFullName(pbdata.service_full_name, service_name, method_name);
if(ret == false) {
respond.err_code = ERROR_PARSE_SERVICE_NAME;
std::stringstream ss;
ss << "not found service_name:[" << service_name << "]";
respond.err_info = ss.str();
return;
}
auto it = m_service_map.find(service_name);
if (it == m_service_map.end() || !(it->second)) {
respond.err_code = ERROR_SERVICE_NOT_FOUND;
std::stringstream ss;
ss << "not found service_name:[" << service_name << "]";
respond.err_info = ss.str();
return;
}
Service* service = it->second;
const Method* method = service->GetDescriptor()->FindMethodByName(method_name);
// const Method* method = nullptr;
if(method == nullptr) {
respond.err_code = ERROR_METHOD_NOT_FOUND;
std::stringstream ss;
ss << "not found service_name:[" << service_name << "]";
respond.err_info = ss.str();
return;
}
std::unique_ptr<Message> requestMsg (service->GetRequestPrototype(method).New());
ret = requestMsg->ParseFromString(pbdata.pb_data);
if(ret == false) {
respond.err_code = ERROR_FAILED_SERIALIZE;
std::stringstream ss;
ss << "faild to parse request data, request.name:[" << requestMsg->GetDescriptor()->full_name() << "]";
respond.err_info = ss.str();
return;
}
std::unique_ptr<Message> respondMsg (service->GetRequestPrototype(method).New());
auto callback = [&respond, &respondMsg] {
if(!respondMsg->SerializePartialToString(&respond.pb_data)) {
respond.pb_data = "";
logger() << respond.msg_req << "|reply error! encode reply package error";
respond.err_code = ERROR_FAILED_SERIALIZE;
respond.err_info = "failed to serilize relpy data";
} else {
logger() << respond.msg_req << "|Set server response data:" << respondMsg->ShortDebugString();
}
};
service->CallMethod(method, nullptr, requestMsg.get(), respondMsg.get(), nullptr /* callback */);
}
bool TinypbDispatcher::parseServiceFullName(const std::string& name, std::string& serviceName, std::string& methodName) {
if(name.empty()) return false;
auto pos = name.find(".");
if(pos == std::string::npos) return false;
serviceName = name.substr(0, pos);
methodName = name.substr(pos + 1);
logger() << "serviceName=" << serviceName;
logger() << "methodName=" << methodName;
return true;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,27 @@
syntax = "proto2";
package tutorial;
message Person {
optional string name = 1;
optional int32 id = 2;
optional string email = 3;
enum PhoneType {
PHONE_TYPE_UNSPECIFIED = 0;
PHONE_TYPE_MOBILE = 1;
PHONE_TYPE_HOME = 2;
PHONE_TYPE_WORK = 3;
}
message PhoneNumber {
optional string number = 1;
optional PhoneType type = 2 [default = PHONE_TYPE_HOME];
}
repeated PhoneNumber phones = 4;
}
message AddressBook {
repeated Person people = 1;
}

View File

93
test/protobuftest/main.cc Normal file
View File

@ -0,0 +1,93 @@
#include <iostream>
#include <fstream>
#include <string>
#include "addressbook.pb.h"
using namespace std;
// This function fills in a Person message based on user input.
void PromptForAddress(tutorial::Person* person) {
cout << "Enter person ID number: ";
int id;
cin >> id;
person->set_id(id);
cin.ignore(256, '\n');
cout << "Enter name: ";
getline(cin, *person->mutable_name());
cout << "Enter email address (blank for none): ";
string email;
getline(cin, email);
if (!email.empty()) {
person->set_email(email);
}
while (true) {
cout << "Enter a phone number (or leave blank to finish): ";
string number;
getline(cin, number);
if (number.empty()) {
break;
}
tutorial::Person::PhoneNumber* phone_number = person->add_phones();
phone_number->set_number(number);
cout << "Is this a mobile, home, or work phone? ";
string type;
getline(cin, type);
if (type == "mobile") {
phone_number->set_type(tutorial::Person::PHONE_TYPE_MOBILE);
} else if (type == "home") {
phone_number->set_type(tutorial::Person::PHONE_TYPE_HOME);
} else if (type == "work") {
phone_number->set_type(tutorial::Person::PHONE_TYPE_WORK);
} else {
cout << "Unknown phone type. Using default." << endl;
}
}
}
// Main function: Reads the entire address book from a file,
// adds one person based on user input, then writes it back out to the same
// file.
int main(int argc, char* argv[]) {
// Verify that the version of the library that we linked against is
// compatible with the version of the headers we compiled against.
GOOGLE_PROTOBUF_VERIFY_VERSION;
if (argc != 2) {
cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
return -1;
}
tutorial::AddressBook address_book;
{
// Read the existing address book.
fstream input(argv[1], ios::in | ios::binary);
if (!input) {
cout << argv[1] << ": File not found. Creating a new file." << endl;
} else if (!address_book.ParseFromIstream(&input)) {
cerr << "Failed to parse address book." << endl;
return -1;
}
}
// Add an address.
PromptForAddress(address_book.add_people());
{
// Write the new address book back to disk.
fstream output(argv[1], ios::out | ios::trunc | ios::binary);
if (!address_book.SerializeToOstream(&output)) {
cerr << "Failed to write address book." << endl;
return -1;
}
}
// Optional: Delete all global objects allocated by libprotobuf.
google::protobuf::ShutdownProtobufLibrary();
return 0;
}

BIN
test/protobuftest/my_program Executable file

Binary file not shown.

1
third_party/abseil-cpp vendored Submodule

@ -0,0 +1 @@
Subproject commit d7aaad83b488fd62bd51c81ecf16cd938532cc0a