Compare commits

...

1 Commits
main ... tmp

Author SHA1 Message Date
yhy
df8789f6c6 临时保存 2025-01-21 16:35:26 +08:00
16 changed files with 511 additions and 36 deletions

2
.gitignore vendored
View File

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

View File

@ -2,18 +2,22 @@ cmake_minimum_required(VERSION 3.0)
project(tinyrpc) project(tinyrpc)
# set(CMAKE_CXX_STANDARD 14)
enable_language(CXX ASM) enable_language(CXX ASM)
add_compile_options(-g -Wall -std=c++11) add_compile_options(-g -Wall -std=c++17)
include_directories(includes/coroutine) include_directories(includes/coroutine)
include_directories(includes/log) include_directories(includes/log)
include_directories(includes/net) include_directories(includes/net)
include_directories(includes/net/tcp) include_directories(includes/net/tcp)
include_directories(includes/net/tinypb)
aux_source_directory(${CMAKE_SOURCE_DIR}/src/coroutine COROUTINE_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 NET_SRC_LIST)
aux_source_directory(${CMAKE_SOURCE_DIR}/src/net/tcp TCP_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) set(ASM_FILES ${CMAKE_SOURCE_DIR}/src/coroutine/coctx_swap.S)
@ -28,6 +32,7 @@ add_library(tinyrpc
${COROUTINE_SRC_LIST} ${COROUTINE_SRC_LIST}
${TCP_SRC_LIST} ${TCP_SRC_LIST}
${NET_SRC_LIST} ${NET_SRC_LIST}
${TINYPB_SRC_LIST}
${ASM_FILES} ${ASM_FILES}
) )
@ -39,4 +44,5 @@ add_executable(test_tinyrpc
) )
target_link_libraries(test_tinyrpc PRIVATE tinyrpc) target_link_libraries(test_tinyrpc PRIVATE tinyrpc)
target_link_libraries(test_tinyrpc PUBLIC protobuf)
target_link_libraries(test_tinyrpc PUBLIC stdc++) 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 #pragma once
#include "reactor.hpp" #include "reactor.hpp"
#include "tcp_connection.hpp" #include "tcp_connection.hpp"
#include <atomic>
#include <mutex> #include <mutex>
#include <thread> #include <thread>
#include <unordered_map> #include <unordered_map>
@ -9,11 +8,11 @@
#include <vector> #include <vector>
namespace tinyrpc { namespace tinyrpc {
class TcpServer;
class IOThread { class IOThread {
friend class IOThreadPool; friend class IOThreadPool;
public: public:
void addClient(int fd); void addClient(TcpServer* ser, int fd);
static IOThread* getThisIoThread(); static IOThread* getThisIoThread();
// void removeFd(int fd); // void removeFd(int fd);
Reactor* getReactor() {return m_reactor;} Reactor* getReactor() {return m_reactor;}

View File

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

View File

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

@ -3,6 +3,7 @@
#include "reactor.hpp" #include "reactor.hpp"
#include "coroutine.hpp" #include "coroutine.hpp"
#include "tcp_connection.hpp" #include "tcp_connection.hpp"
#include "tcp_server.hpp"
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <thread> #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 "tcp_connection.hpp"
#include "abstract_coder.hpp"
#include "coroutine_hook.hpp" #include "coroutine_hook.hpp"
#include "fd_event.hpp" #include "fd_event.hpp"
#include "logger.hpp" #include "logger.hpp"
#include "reactor.hpp" #include "reactor.hpp"
#include "tcp_server.hpp"
#include "tinypb_data.hpp"
#include <cerrno> #include <cerrno>
#include <cstring> #include <cstring>
#include <memory>
#include <pthread.h> #include <pthread.h>
#include <unistd.h> #include <unistd.h>
namespace tinyrpc { namespace tinyrpc {
TcpConnection::TcpConnection(int fd, Reactor* reactor) : TcpConnection::TcpConnection(int fd, Reactor& reactor, TcpServer& ser) :
m_fdEvent(FdEventPool::getInstance()->getFdEvent(fd)), m_fdEvent(FdEventPool::getInstance()->getFdEvent(fd)),
m_mainCoroutine(std::bind(&TcpConnection::mainLoopFun, this)), m_mainCoroutine(std::bind(&TcpConnection::mainLoopFun, this)),
m_reactor(reactor) m_reactor(reactor),
m_server(ser)
{ {
Reactor::Task task = [this] { Reactor::Task task = [this] {
logger() << "conn coroutine is resume"; logger() << "conn coroutine is resume";
m_mainCoroutine.resume(); m_mainCoroutine.resume();
}; };
reactor->addTask(task, true); reactor.addTask(task, true);
} }
@ -36,7 +41,7 @@ namespace tinyrpc {
void TcpConnection::clearClient() { void TcpConnection::clearClient() {
logger() << "clearClient"; logger() << "clearClient";
m_state = State::Disconnected; m_state = State::Disconnected;
m_reactor->delFdEvent(m_fdEvent); m_reactor.delFdEvent(m_fdEvent);
m_fdEvent->reset(); m_fdEvent->reset();
close(m_fdEvent->getFd()); close(m_fdEvent->getFd());
} }
@ -110,17 +115,31 @@ namespace tinyrpc {
void TcpConnection::process() { void TcpConnection::process() {
logger() << "process"; logger() << "process";
if(m_state == State::Disconnected) { // if(m_state == State::Disconnected) {
return; // return;
} // }
if(m_writeBuffer.getWriteable() < m_readBuffer.getReadable()) { // if(m_writeBuffer.getWriteable() < m_readBuffer.getReadable()) {
m_writeBuffer.resize(m_readBuffer.getReadable() * 2); // m_writeBuffer.resize(m_readBuffer.getReadable() * 2);
} // }
std::memcpy(m_writeBuffer.getWriteAddress(), m_readBuffer.getReadAddress(), m_readBuffer.getReadable()); // std::memcpy(m_writeBuffer.getWriteAddress(), m_readBuffer.getReadAddress(), m_readBuffer.getReadable());
m_writeBuffer.writeOffset(m_readBuffer.getReadable()); // m_writeBuffer.writeOffset(m_readBuffer.getReadable());
m_readBuffer.readOffset(m_readBuffer.getReadable()); // m_readBuffer.readOffset(m_readBuffer.getReadable());
// 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);
}
logger() << "write data " << m_writeBuffer.getReadable() << " byte";
} }
TcpConnection::~TcpConnection() { TcpConnection::~TcpConnection() {

View File

@ -5,6 +5,8 @@
#include "coroutine_hook.hpp" #include "coroutine_hook.hpp"
#include "net_address.hpp" #include "net_address.hpp"
#include "reactor.hpp" #include "reactor.hpp"
#include "tinypb_coder.hpp"
#include "tinypb_dispatcher.hpp"
#include <cerrno> #include <cerrno>
#include <cstring> #include <cstring>
#include <netinet/in.h> #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) : TcpServer::TcpServer(const NetAddress& addr) :
m_accept_cor(std::bind(&TcpServer::mainAcceptCorFun, this)), 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(); 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() { void TcpServer::start() {
@ -93,7 +99,7 @@ namespace tinyrpc {
logger() << "new connect fd = " << fd; logger() << "new connect fd = " << fd;
logger() << " 添加 fd 到子 reactor 中 " << fd; logger() << " 添加 fd 到子 reactor 中 " << fd;
m_ioThreadPool.getIOThread()->addClient(fd); m_ioThreadPool.getIOThread()->addClient(this, fd);
} }
} }

View File

@ -0,0 +1,215 @@
#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);
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 < buffer.getReadable(); i++) {
if(buff[i] == PB_START) {
if(i + 1 >= buffer.getReadable()) {
return false; // 包不完整
}
pack_len = getInt32FromNetByte(buff[i + 1]);
end_index = pack_len + i - 1;
if(end_index >= 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 + 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 + 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 + 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);
return true;
}
}

View File

@ -0,0 +1,61 @@
#include "tinypb_dispatcher.hpp"
#include "logger.hpp"
#include "tinypb_data.hpp"
#include "error_code.hpp"
#include <sstream>
namespace tinyrpc {
TinypbDispatcher::TinypbDispatcher() {}
// TODO
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 google::protobuf::MethodDescriptor* method = service->GetDescriptor()->FindMethodByName(method_name);
}
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;
}
}