hproselet/hprose_cli.hpp

202 lines
5.8 KiB
C++
Raw Normal View History

2022-12-15 02:05:06 +00:00
#ifndef _HPROSE_CLI_HPP_
#define _HPROSE_CLI_HPP_
#include <functional>
#include <memory>
#include <unordered_map>
#include "hprose_ed.hpp"
#include "hprose_types.hpp"
template<typename... RETS>
struct HproseRPCCallback {
template<typename T>
void CallImpl(HproseReader& reader, T rcb, const std::function<void()>& arg_ref) {
auto vals = HproseValueHelperTuple<RETS...>().FromReader(reader);
arg_ref();
CallImplMultiArg(rcb, vals, std::make_index_sequence<sizeof...(RETS)>{});
}
template<typename T, size_t... I>
void CallImplMultiArg(T rcb, std::tuple<RETS...>& vals, std::index_sequence<I...>) {
rcb(std::get<I>(vals)...);
}
};
template<typename RET>
struct HproseRPCCallback<RET> {
template<typename T>
void CallImpl(HproseReader& reader, T rcb, const std::function<void()>& arg_ref) {
auto val = HproseValueHelper<RET>().FromReader(reader);
arg_ref();
rcb(val);
}
};
template<>
struct HproseRPCCallback<void> {
template<typename T>
void CallImpl(HproseReader& reader, T rcb, const std::function<void()>& arg_ref) {
reader.SkipValue();
arg_ref();
rcb();
}
};
template<typename T>
struct HproseResultArg {
using type = void;
};
template<typename RET>
struct HproseResultArg<std::function<RET()>> {
using type = HproseRPCCallback<void>;
};
template<typename RET, typename... ARGS>
struct HproseResultArg<std::function<RET(ARGS...)>> {
using type = HproseRPCCallback<std::remove_cv_t<std::remove_reference_t<ARGS>>...>;
};
class HproseRPCInfo {
public:
HproseRPCInfo(const std::string& name) : method(name) {}
template<typename... ARGS>
HproseRPCInfo& PushArgs(ARGS... args) {
arg_cb = [args = std::make_tuple(args...)](HproseWriter& writer) {
HproseValueHelper<std::tuple<ARGS...>>().ToWriter(args, writer);
};
return *this;
}
template<typename... ARGS>
HproseRPCInfo& PushRefArgs(ARGS&... args) {
ref_cb = [argrefs = std::tie(std::forward<ARGS&>(args)...)](HproseReader& reader) mutable {
argrefs = std::move(HproseValueHelperTuple<ARGS...>().FromReader(reader));
};
ref = true;
return PushArgs(std::forward<ARGS&>(args)...);
}
template<typename T>
HproseRPCInfo& Expect(T rcb) {
res_cb = [rcb](HproseReader& reader, const std::function<void()>& arg_ref) {
using rpc_arg_type = HproseResultArg<typename FunctionType<T>::type>;
typename rpc_arg_type::type().CallImpl(reader, rcb, arg_ref);
};
return *this;
}
HproseRPCInfo& Catch(std::function<void(const std::string&)> ecb) {
err_cb = ecb;
return *this;
}
void WriteRequest(HproseWriter& writer) const {
writer.WriteTag(Tags::Call);
HproseValueHelperString().ToWriter(method, writer);
if(arg_cb)
arg_cb(writer);
if(ref)
writer.WriteTag(Tags::True);
}
void Return(HproseReader& reader) {
auto tag = reader.ReadTag();
if(tag == Tags::Error) {
auto msg = HproseValueHelperString().FromReader(reader);
if(err_cb)
err_cb(msg);
} else {
auto cb = [this, &reader]() {
if(ref && ref_cb && reader.CheckTag(Tags::Argument, true))
ref_cb(reader);
};
if(res_cb)
res_cb(reader, cb);
else {
reader.SkipValue();
cb();
}
}
}
void Error(const std::string& msg) { if(err_cb) err_cb(msg); }
protected:
bool ref = false;
std::string method;
std::function<void(HproseReader&, std::function<void()>)> res_cb;
std::function<void(HproseReader&)> ref_cb;
std::function<void(HproseWriter&)> arg_cb;
std::function<void(const std::string&)> err_cb;
};
class HproseClient {
public:
template<typename SVC>
void UseConnector(SVC& svc) {
apply_handler = [&svc, this](uint32_t id, std::shared_ptr<std::vector<HproseRPCInfo>> rpcs) {
if(rpcs == nullptr) {
auto& rpcs = results[id];
svc.SendRequest(id, rpcs);
} else
svc.SendRequestNoReturn(id, rpcs);
};
svc.SetPacketHandler([this](uint32_t id, HproseReader& reader) {
auto iter = results.find(id);
if(iter != results.end()) {
for(auto& inf : iter->second)
inf.Return(reader);
}
results.erase(iter);
});
svc.SetErrorHandler([this](uint32_t id, const std::string& msg) {
auto& infos = results[id];
for(auto& inf : infos)
inf.Error(msg);
results.erase(id);
});
}
HproseRPCInfo& Call(const std::string& name) {
auto pre_multiid = multiid;
multiid = 0;
auto& ret = MultiCall(name);
MultiApply();
multiid = pre_multiid;
return ret;
}
HproseRPCInfo& MultiCall(const std::string& name) {
if(multiid == 0)
multiid = callid++;
auto& infos = results[multiid];
infos.emplace_back(name);
return infos.back();
}
void MultiApply() {
if(multiid == 0)
return;
apply_handler(multiid, nullptr);
multiid = 0;
}
HproseRPCInfo& CallNoReturn(const std::string& name) {
auto rpcinfos = std::make_shared<std::vector<HproseRPCInfo>>();
rpcinfos->emplace_back(name);
apply_handler(callid++, rpcinfos);
return rpcinfos->at(0);
}
protected:
uint32_t callid = 1;
uint32_t multiid = 0;
std::function<void(uint32_t, std::shared_ptr<std::vector<HproseRPCInfo>>)> apply_handler;
std::unordered_map<uint32_t, std::vector<HproseRPCInfo>> results;
};
#endif