From 43f67275e28b3dbdb0dde85868707130904f3f50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=B5=D1=80=D0=B3=D0=B5=D0=B9=20=D0=9C=D0=B0=D1=80?= =?UTF-8?q?=D0=B8=D0=BD=D0=BA=D0=B5=D0=B2=D0=B8=D1=87?= Date: Wed, 3 Dec 2025 18:27:08 +0700 Subject: [PATCH] factor IPC out of server RPC --- include/ipc/IpcCodec.h | 61 +++++++++++++++++++++++++++++++++++++++++ include/ipc/IpcDispatcher.h | 47 +++++++++++++++++++++++++++++++ include/proxy/ProxyMarshaller.h | 16 ++++------- src/server.cpp | 18 ++++++------ tools/templates/skeleton.cpp.j2 | 26 ++++-------------- tools/templates/skeleton.h.j2 | 8 +++--- 6 files changed, 130 insertions(+), 46 deletions(-) create mode 100644 include/ipc/IpcCodec.h create mode 100644 include/ipc/IpcDispatcher.h diff --git a/include/ipc/IpcCodec.h b/include/ipc/IpcCodec.h new file mode 100644 index 0000000..d66ed59 --- /dev/null +++ b/include/ipc/IpcCodec.h @@ -0,0 +1,61 @@ +#pragma once + +#include +#include + +#include + +// Кодек, который знает, как упаковать/распаковать RPC-запросы/ответы +// в/IpcMessage. Живёт в IPC-слое, но опирается на типы RPC-ядра +// (RpcValue/RpcArgs). +namespace IpcCodec { + +// Запрос: имя метода + вектор аргументов. +inline IpcMessage encodeRequest(const std::string& method, + const RpcArgs& args) { + IpcMessage msg; + + // имя метода + msg.add(method); + + // аргументы (PoC: только int) + for (const auto& a : args) { + msg.add(a.asInt()); + } + + return msg; +} + +inline void decodeRequest(const IpcMessage& msg, + std::string& method, + RpcArgs& args) { + IpcMessage copy = msg; + + // имя метода + method = copy.get(); + + // аргументы (PoC: только int, читаем до конца сообщения) + args.clear(); + while (!copy.empty()) { + int v = copy.get(); + args.emplace_back(RpcValue::fromInt(v)); + } +} + +// Ответ: одно RpcValue (PoC: считаем, что это int). +inline IpcMessage encodeResponse(const RpcValue& result) { + IpcMessage msg; + msg.add(result.asInt()); // PoC: только int + return msg; +} + +inline RpcValue decodeResponse(const IpcMessage& msg) { + IpcMessage copy = msg; + int v = copy.get(); + return RpcValue::fromInt(v); +} + +} // namespace IpcCodec + + + diff --git a/include/ipc/IpcDispatcher.h b/include/ipc/IpcDispatcher.h new file mode 100644 index 0000000..02b12c9 --- /dev/null +++ b/include/ipc/IpcDispatcher.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include + +#include + +// Серверный диспетчер, который получает IpcMessage с канала, +// декодирует его в RPC-вызов, вызывает RpcInvoker и шлёт ответ. +class IpcDispatcher { +public: + IpcDispatcher(IpcChannel& ch, RpcInvoker& invoker) + : channel_(ch) + , invoker_(invoker) {} + + // Обработать один запрос. Возвращает false, если получили "пустое" + // сообщение и цикл стоит завершить. + bool handleOnce() { + IpcMessage req = channel_.receive(); + if (req.empty()) { + return false; + } + + std::string method; + RpcArgs args; + IpcCodec::decodeRequest(req, method, args); + + RpcValue result = invoker_.dispatch(method, args); + IpcMessage resp = IpcCodec::encodeResponse(result); + channel_.send(resp); + return true; + } + + // Простой цикл обработки до тех пор, пока канал не вернёт пустое сообщение. + void loop() { + while (handleOnce()) { + } + } + +private: + IpcChannel& channel_; + RpcInvoker& invoker_; +}; + + + diff --git a/include/proxy/ProxyMarshaller.h b/include/proxy/ProxyMarshaller.h index 73ea2ef..30803e2 100644 --- a/include/proxy/ProxyMarshaller.h +++ b/include/proxy/ProxyMarshaller.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include class ProxyMarshaller { @@ -9,22 +10,15 @@ public: // Базовый type-erased вызов: принимает вектор RpcValue и возвращает RpcValue. RpcValue call(const std::string& method, const RpcArgs& args) { - IpcMessage msg; - - // имя метода - msg.add(method); - - // аргументы (PoC: только int) - for (const auto& a : args) { - msg.add(a.asInt()); - } + // упаковать запрос в IpcMessage + IpcMessage msg = IpcCodec::encodeRequest(method, args); // отправить channel.send(msg); - // получить ответ + // получить ответ и распаковать IpcMessage resp = channel.receive(); - return RpcValue::fromInt(resp.get()); + return IpcCodec::decodeResponse(resp); } // Удобный шаблонный хелпер для сгенерированных прокси. diff --git a/src/server.cpp b/src/server.cpp index b9097aa..be2be01 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2,6 +2,8 @@ #include "MyService.skeleton.h" #include "ipc/IpcPipeChannel.h" +#include "ipc/IpcDispatcher.h" +#include "rpc/RpcInvoker.h" #include @@ -14,17 +16,13 @@ int main() { // Сервер читает из fifo_to_server и пишет в fifo_to_client. IpcPipeChannel ch("/tmp/fifo_to_server", "/tmp/fifo_to_client"); - // RPC‑уровень: скелет поверх того же канала. + // RPC‑уровень: инвокер и скелет, который лишь регистрирует методы. + RpcInvoker invoker; MyService realObj; - MyServiceSkeleton skeleton(realObj); + MyServiceSkeleton skeleton(realObj, invoker); - while (true) { - IpcMessage req = ch.receive(); - if (req.empty()) { - break; - } - IpcMessage resp = skeleton.dispatch(req); - ch.send(resp); - } + // IPC‑диспетчер, который декодирует IpcMessage в RPC-вызовы и обратно. + IpcDispatcher dispatcher(ch, invoker); + dispatcher.loop(); } diff --git a/tools/templates/skeleton.cpp.j2 b/tools/templates/skeleton.cpp.j2 index eeb2e05..1b972b2 100644 --- a/tools/templates/skeleton.cpp.j2 +++ b/tools/templates/skeleton.cpp.j2 @@ -1,7 +1,7 @@ #include "{{ cls.name }}.skeleton.h" -{{ cls.name }}Skeleton::{{ cls.name }}Skeleton({{ cls.name }}& obj) -{ +{{ cls.name }}Skeleton::{{ cls.name }}Skeleton({{ cls.name }}& obj, RpcInvoker& inv) + : invoker(inv) { {% for m in cls.methods %} invoker.registerMethod(&obj, "{{ cls.name }}.{{ m.name }}", @@ -9,24 +9,8 @@ {% endfor %} } -IpcMessage {{ cls.name }}Skeleton::dispatch(const IpcMessage& req) { - // Перепаковываем IpcMessage в RpcArgs и вызываем type-erased инвокер. - IpcMessage msg = req; - - // имя метода - std::string method = msg.get(); - - // аргументы (PoC: только int, читаем все до конца сообщения) - RpcArgs args; - while (!msg.empty()) { - int v = msg.get(); - args.emplace_back(RpcValue::fromInt(v)); - } - - RpcValue result = invoker.dispatch(method, args); - - IpcMessage resp; - resp.add(result.asInt()); // PoC: только int - return resp; +RpcValue {{ cls.name }}Skeleton::dispatch(const std::string& method, + const RpcArgs& args) { + return invoker.dispatch(method, args); } diff --git a/tools/templates/skeleton.h.j2 b/tools/templates/skeleton.h.j2 index 6d5f590..0822c1c 100644 --- a/tools/templates/skeleton.h.j2 +++ b/tools/templates/skeleton.h.j2 @@ -2,14 +2,14 @@ #include "{{ cls.name }}.h" #include "rpc/RpcInvoker.h" -#include "ipc/IpcMessage.h" class {{ cls.name }}Skeleton { public: - explicit {{ cls.name }}Skeleton({{ cls.name }}& obj); + explicit {{ cls.name }}Skeleton({{ cls.name }}& obj, RpcInvoker& invoker); - IpcMessage dispatch(const IpcMessage& req); + // IPC-независимый диспетчер: принимает имя метода и RpcArgs. + RpcValue dispatch(const std::string& method, const RpcArgs& args); private: - RpcInvoker invoker; + RpcInvoker& invoker; };