#ifndef _HPROSE_SRV_HPP_ #define _HPROSE_SRV_HPP_ #include #include #include "hprose_ed.hpp" #include "hprose_types.hpp" template struct Invoker { template bool operator() (OBJECT* objs, HANDLER&& handler, HproseWriter& w, ARGS&... args) const { return HproseValueHelper().ToWriterWithResultTag(handler(std::forward(args)...), w); } }; template<> struct Invoker { template bool operator() (OBJECT* objs, HANDLER&& handler, HproseWriter& w, ARGS&... args) const { handler(std::forward(args)...); return HproseValueHelperNull().ToWriterWithResultTag(w); } }; template struct InvokerObj { template bool operator() (OBJECT* objs, HANDLER&& handler, HproseWriter& w, ARGS&... args) const { return HproseValueHelper().ToWriterWithResultTag((*objs.*handler)(std::forward(args)...), w); } }; template<> struct InvokerObj { template bool operator() (OBJECT* objs, HANDLER&& handler, HproseWriter& w, ARGS&... args) const { (*objs.*handler)(std::forward(args)...); return HproseValueHelperNull().ToWriterWithResultTag(w); } }; template struct HandlerType { using class_type = void; using arg_helper = std::tuple<>; using arg_type = std::tuple<>; using invoke_type = void; static constexpr int32_t arg_count = 0; }; template struct HandlerType> { using class_type = void; using arg_type = std::tuple>...>; using invoke_type = Invoker; using call_type = std::function; static constexpr int32_t arg_count = sizeof...(ARGS); }; template struct HandlerType { using class_type = CLASS; using arg_type = std::tuple>...>; using invoke_type = InvokerObj; using call_type = RET(CLASS::*)(ARGS...); static constexpr int32_t arg_count = sizeof...(ARGS); }; template struct HandlerType { using class_type = CLASS; using arg_type = std::tuple>...>; using invoke_type = InvokerObj; using call_type = RET(CLASS::*)(ARGS...) const; static constexpr int32_t arg_count = sizeof...(ARGS); }; template struct HproseInvoker { virtual void Call(OBJECT* obj, HproseReader& r, HproseWriter& w) = 0; virtual ~HproseInvoker() {}; }; template class HProseCallType : public HproseInvoker::type>::class_type> { public: using handler_type = HandlerType::type>; using args_type = typename handler_type::arg_type; HProseCallType(HANDLER h, const std::string& name) : handler(h), method(name) {} virtual void Call(typename handler_type::class_type* obj, HproseReader& r, HproseWriter& w) { args_type args; if(r.CheckTag(Tags::List, false)) args = HproseValueHelper().FromReader(r); bool ref = r.CheckTag(Tags::True, true); bool has_error = CallImpl(obj, args, w, std::make_index_sequence{}); if(ref && handler_type::arg_count > 0 && !has_error) { w.WriteTag(Tags::Argument); HproseValueHelper().ToWriter(args, w); } } template bool CallImpl(typename handler_type::class_type* obj, args_type& args, HproseWriter& w, std::index_sequence) { return typename handler_type::invoke_type()(obj, handler, w, std::get(args)...); } protected: HANDLER handler; std::string method; }; template std::unique_ptr> MakeHproseCallType(F f, const std::string& name) { return std::unique_ptr>(new HProseCallType(f, name)); } template class HproseServer { public: template void Register(const char* name, HANDLER func) { auto invoker = std::unique_ptr>(MakeHproseCallType(func, name)); rpc_calls[name] = std::move(invoker); } void HandleRequests(OBJECT* sess, HproseReader& reader, HproseWriter& writer) { auto tag = reader.ReadTag(); while(tag == Tags::Call) { auto method = HproseValueHelperString().FromReader(reader); auto iter = rpc_calls.find(method); if(iter == rpc_calls.end()) { HproseError err(std::move(std::string("Error: \"").append(method).append("\" not found."))); HproseValueHelperError().ToWriterWithResultTag(err, writer); reader.SkipValue(); reader.SkipValue(); tag = reader.ReadTag(); continue; } iter->second->Call(sess, reader, writer); tag = reader.ReadTag(); } } template void UseConnector(SVC& svc) { svc.SetObjectAllocator([this]() -> std::shared_ptr { if(obj_allocator) return obj_allocator(); return nullptr; }); svc.SetPacketHandler([this](OBJECT* obj, HproseReader& reader, HproseWriter& writer) { this->HandleRequests(obj, reader, writer); }); svc.Start(); } void SetObjectAllocator(const std::function()>& cb) { obj_allocator = cb; } protected: std::function()> obj_allocator; std::unordered_map>> rpc_calls; }; #endif