implement object registry
This commit is contained in:
+13
-36
@@ -1,56 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <rpc/RpcRegistry.h>
|
||||
#include <rpc/RpcValue.h>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
|
||||
// Инвокер — тонкий фасад над RpcRegistry:
|
||||
// по ObjectId находит объект и делегирует вызов его IRpcObject::invoke().
|
||||
class RpcInvoker {
|
||||
public:
|
||||
template<typename Obj, typename Ret, typename... Args>
|
||||
void registerMethod(Obj* instance,
|
||||
const std::string& name,
|
||||
Ret (Obj::*method)(Args...)) {
|
||||
handlers[name] =
|
||||
[instance, method](const RpcArgs& args) -> RpcValue {
|
||||
auto tuple = readArgs<Args...>(args);
|
||||
Ret result = std::apply(
|
||||
method, std::tuple_cat(std::make_tuple(instance), tuple));
|
||||
using ObjectId = RpcRegistry::ObjectId; // согласован с IpcCodec::ObjectId
|
||||
|
||||
// PoC: считаем, что Ret == int.
|
||||
return RpcValue::fromInt(result);
|
||||
};
|
||||
}
|
||||
explicit RpcInvoker(RpcRegistry& registry)
|
||||
: registry_(registry) {}
|
||||
|
||||
RpcValue dispatch(const std::string& method, const RpcArgs& args) const {
|
||||
auto it = handlers.find(method);
|
||||
if (it == handlers.end()) {
|
||||
RpcValue dispatch(ObjectId objectId,
|
||||
const std::string& method,
|
||||
const RpcArgs& args) const {
|
||||
IRpcObject* obj = registry_.get(objectId);
|
||||
if (!obj) {
|
||||
// PoC: в случае ошибки возвращаем 0.
|
||||
return RpcValue::fromInt(0);
|
||||
}
|
||||
|
||||
return it->second(args);
|
||||
return obj->invoke(method, args);
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename... Args, std::size_t... I>
|
||||
static std::tuple<Args...>
|
||||
readArgsImpl(const RpcArgs& args, std::index_sequence<I...>) {
|
||||
return std::tuple<Args...>{
|
||||
static_cast<Args>(args[I].asInt())...}; // PoC: только int
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
static std::tuple<Args...> readArgs(const RpcArgs& args) {
|
||||
return readArgsImpl<Args...>(
|
||||
args, std::make_index_sequence<sizeof...(Args)>{});
|
||||
}
|
||||
|
||||
std::unordered_map<std::string,
|
||||
std::function<RpcValue(const RpcArgs&)>>
|
||||
handlers;
|
||||
RpcRegistry& registry_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <rpc/RpcValue.h>
|
||||
|
||||
// Базовый интерфейс для всех RPC-объектов, живущих в реестре.
|
||||
// Каждая реализация (обычно *Skeleton) знает, как вызвать реальные методы.
|
||||
struct IRpcObject {
|
||||
virtual ~IRpcObject() = default;
|
||||
|
||||
virtual RpcValue invoke(const std::string& method,
|
||||
const RpcArgs& args) = 0;
|
||||
};
|
||||
|
||||
// Специализированный реестр объектов именно для RPC-уровня.
|
||||
// Владеет скелетонами (IRpcObject) через unique_ptr. Сами доменные объекты
|
||||
// (MyService и т.п.) живут снаружи и могут быть обёрнуты в shared_ptr.
|
||||
class RpcRegistry {
|
||||
public:
|
||||
// PoC: ObjectId храним как int-совместимый тип, чтобы его можно было
|
||||
// передавать через BaseIpcMessage, который поддерживает только int/string.
|
||||
using ObjectId = int;
|
||||
|
||||
RpcRegistry() = default;
|
||||
|
||||
// Зарегистрировать объект-обёртку (обычно Skeleton) и вернуть его
|
||||
// идентификатор. По сути, это registerSkeleton<T>(...).
|
||||
template<typename T, typename... Args>
|
||||
ObjectId registerObject(Args&&... args) {
|
||||
static_assert(std::is_base_of_v<IRpcObject, T>,
|
||||
"T must inherit IRpcObject");
|
||||
|
||||
const ObjectId id = nextId_++;
|
||||
objects_.emplace(
|
||||
id, std::make_unique<T>(std::forward<Args>(args)...));
|
||||
return id;
|
||||
}
|
||||
|
||||
// Уничтожить объект по идентификатору.
|
||||
void destroyObject(ObjectId id) {
|
||||
objects_.erase(id);
|
||||
}
|
||||
|
||||
// Найти объект по идентификатору.
|
||||
IRpcObject* get(ObjectId id) const {
|
||||
auto it = objects_.find(id);
|
||||
return it == objects_.end() ? nullptr : it->second.get();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<ObjectId, std::unique_ptr<IRpcObject>> objects_;
|
||||
ObjectId nextId_ = 0; // первый объект будет иметь id = 0 (PoC)
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user