factor IPC out of server RPC
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include <ipc/IpcMessage.h>
|
||||
#include <rpc/RpcValue.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
// Кодек, который знает, как упаковать/распаковать 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<std::string>();
|
||||
|
||||
// аргументы (PoC: только int, читаем до конца сообщения)
|
||||
args.clear();
|
||||
while (!copy.empty()) {
|
||||
int v = copy.get<int>();
|
||||
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<int>();
|
||||
return RpcValue::fromInt(v);
|
||||
}
|
||||
|
||||
} // namespace IpcCodec
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include <ipc/IpcChannel.h>
|
||||
#include <ipc/IpcCodec.h>
|
||||
#include <rpc/RpcInvoker.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
// Серверный диспетчер, который получает 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_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <ipc/IpcChannel.h>
|
||||
#include <ipc/IpcCodec.h>
|
||||
#include <rpc/RpcValue.h>
|
||||
|
||||
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<int>());
|
||||
return IpcCodec::decodeResponse(resp);
|
||||
}
|
||||
|
||||
// Удобный шаблонный хелпер для сгенерированных прокси.
|
||||
|
||||
+8
-10
@@ -2,6 +2,8 @@
|
||||
#include "MyService.skeleton.h"
|
||||
|
||||
#include "ipc/IpcPipeChannel.h"
|
||||
#include "ipc/IpcDispatcher.h"
|
||||
#include "rpc/RpcInvoker.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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<std::string>();
|
||||
|
||||
// аргументы (PoC: только int, читаем все до конца сообщения)
|
||||
RpcArgs args;
|
||||
while (!msg.empty()) {
|
||||
int v = msg.get<int>();
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user