diff --git a/.gitignore b/.gitignore index 543823a..ea62484 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ bin/ build/ lib/ -core* \ No newline at end of file +protobuf/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 50251c1..7d7cdb7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,18 +2,22 @@ cmake_minimum_required(VERSION 3.0) project(tinyrpc) +# set(CMAKE_CXX_STANDARD 14) + 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/log) include_directories(includes/net) 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/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) @@ -28,6 +32,7 @@ add_library(tinyrpc ${COROUTINE_SRC_LIST} ${TCP_SRC_LIST} ${NET_SRC_LIST} + ${TINYPB_SRC_LIST} ${ASM_FILES} ) @@ -39,4 +44,5 @@ add_executable(test_tinyrpc ) target_link_libraries(test_tinyrpc PRIVATE tinyrpc) -target_link_libraries(test_tinyrpc PUBLIC stdc++) \ No newline at end of file +target_link_libraries(test_tinyrpc PUBLIC protobuf) +target_link_libraries(test_tinyrpc PUBLIC stdc++) diff --git a/includes/net/abstract_coder.hpp b/includes/net/abstract_coder.hpp new file mode 100644 index 0000000..15c92bf --- /dev/null +++ b/includes/net/abstract_coder.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include "tcp_buffer.hpp" +#include +#include + + +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); + } + +} \ No newline at end of file diff --git a/includes/net/abstract_dispatcher.hpp b/includes/net/abstract_dispatcher.hpp new file mode 100644 index 0000000..dd38442 --- /dev/null +++ b/includes/net/abstract_dispatcher.hpp @@ -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: + + + + }; +} \ No newline at end of file diff --git a/includes/net/error_code.hpp b/includes/net/error_code.hpp new file mode 100644 index 0000000..1a3becc --- /dev/null +++ b/includes/net/error_code.hpp @@ -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 + +}; + +} \ No newline at end of file diff --git a/includes/net/tcp/io_thread.hpp b/includes/net/tcp/io_thread.hpp index d801771..b36f597 100644 --- a/includes/net/tcp/io_thread.hpp +++ b/includes/net/tcp/io_thread.hpp @@ -1,7 +1,6 @@ #pragma once #include "reactor.hpp" #include "tcp_connection.hpp" -#include #include #include #include @@ -9,11 +8,11 @@ #include 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;} diff --git a/includes/net/tcp/tcp_connection.hpp b/includes/net/tcp/tcp_connection.hpp index eed07df..b456f67 100644 --- a/includes/net/tcp/tcp_connection.hpp +++ b/includes/net/tcp/tcp_connection.hpp @@ -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; }; } \ No newline at end of file diff --git a/includes/net/tcp/tcp_server.hpp b/includes/net/tcp/tcp_server.hpp index ef91ebf..460e5c3 100644 --- a/includes/net/tcp/tcp_server.hpp +++ b/includes/net/tcp/tcp_server.hpp @@ -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{}; }; } \ No newline at end of file diff --git a/includes/net/tinypb/tinypb_coder.hpp b/includes/net/tinypb/tinypb_coder.hpp new file mode 100644 index 0000000..6f6a4a7 --- /dev/null +++ b/includes/net/tinypb/tinypb_coder.hpp @@ -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: + + + }; + + + +} \ No newline at end of file diff --git a/includes/net/tinypb/tinypb_data.hpp b/includes/net/tinypb/tinypb_data.hpp new file mode 100644 index 0000000..ac86985 --- /dev/null +++ b/includes/net/tinypb/tinypb_data.hpp @@ -0,0 +1,31 @@ +#pragma once + + +#include "abstract_coder.hpp" +#include +#include + +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 + }; + + + +} \ No newline at end of file diff --git a/includes/net/tinypb/tinypb_dispatcher.hpp b/includes/net/tinypb/tinypb_dispatcher.hpp new file mode 100644 index 0000000..7575aa7 --- /dev/null +++ b/includes/net/tinypb/tinypb_dispatcher.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "abstract_dispatcher.hpp" +#include +#include +#include +#include + +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 m_service_map; + + }; + + + +} \ No newline at end of file diff --git a/src/net/tcp/io_thread.cc b/src/net/tcp/io_thread.cc index 6255b2c..521470a 100644 --- a/src/net/tcp/io_thread.cc +++ b/src/net/tcp/io_thread.cc @@ -3,6 +3,7 @@ #include "reactor.hpp" #include "coroutine.hpp" #include "tcp_connection.hpp" +#include "tcp_server.hpp" #include #include #include @@ -23,9 +24,9 @@ namespace tinyrpc { - void IOThread::addClient(int fd) { + void IOThread::addClient(TcpServer* ser, int fd) { - m_clients[fd] = std::make_shared(fd, m_reactor); + m_clients[fd] = std::make_shared(fd, *m_reactor, *ser); } diff --git a/src/net/tcp/tcp_connection.cc b/src/net/tcp/tcp_connection.cc index 70ce853..45419b9 100644 --- a/src/net/tcp/tcp_connection.cc +++ b/src/net/tcp/tcp_connection.cc @@ -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 #include +#include #include #include 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,31 @@ 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 data(new TinypbData); + + bool ret = m_server.getCoder().decoder(m_readBuffer, *data); + if(ret == false) { + logger() << "decode error"; + break; + } + std::unique_ptr resp(new TinypbData); + m_server.getDispatcher().dispatcher(*this, *data, *resp); + + } + } TcpConnection::~TcpConnection() { diff --git a/src/net/tcp/tcp_server.cc b/src/net/tcp/tcp_server.cc index 7e705f9..40f0c5b 100644 --- a/src/net/tcp/tcp_server.cc +++ b/src/net/tcp/tcp_server.cc @@ -5,6 +5,8 @@ #include "coroutine_hook.hpp" #include "net_address.hpp" #include "reactor.hpp" +#include "tinypb_coder.hpp" +#include "tinypb_dispatcher.hpp" #include #include #include @@ -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); } } diff --git a/src/net/tinypb/tinypb_coder.cc b/src/net/tinypb/tinypb_coder.cc new file mode 100644 index 0000000..b931b63 --- /dev/null +++ b/src/net/tinypb/tinypb_coder.cc @@ -0,0 +1,215 @@ +#include "tinypb_coder.hpp" +#include "abstract_coder.hpp" +#include "tinypb_data.hpp" +#include +#include +#include +#include +#include +#include + + +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(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 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(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(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 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 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 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; + } + +} + diff --git a/src/net/tinypb/tinypb_dispatcher.cc b/src/net/tinypb/tinypb_dispatcher.cc new file mode 100644 index 0000000..1a94dd4 --- /dev/null +++ b/src/net/tinypb/tinypb_dispatcher.cc @@ -0,0 +1,61 @@ +#include "tinypb_dispatcher.hpp" +#include "logger.hpp" +#include "tinypb_data.hpp" +#include "error_code.hpp" +#include + +namespace tinyrpc { + TinypbDispatcher::TinypbDispatcher() {} + // TODO + TinypbDispatcher::~TinypbDispatcher() { + + } + void TinypbDispatcher::dispatcher(TcpConnection& conn, AbstractData& data, AbstractData& resp) { + logger() << "dispatcher"; + TinypbData& pbdata = dynamic_cast(data); + TinypbData& respond = dynamic_cast(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; + } + +} +