202 lines
5.8 KiB
C++
202 lines
5.8 KiB
C++
#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
|