Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #ifndef RVIZ_RPC_CLIENT_H
00031 #define RVIZ_RPC_CLIENT_H
00032
00033
00034 #include "exceptions.h"
00035 #include "request_wrapper.h"
00036 #include "response_wrapper.h"
00037 #include "method_response.h"
00038 #include <rve_common/uuid.h>
00039
00040 #include <string>
00041 #include <boost/shared_ptr.hpp>
00042 #include <boost/make_shared.hpp>
00043 #include <boost/function.hpp>
00044 #include <boost/bind.hpp>
00045
00046 namespace ros
00047 {
00048 class NodeHandle;
00049 }
00050
00051 namespace rve_rpc
00052 {
00053
00054 template<typename Req, typename Res>
00055 class Method
00056 {
00057 private:
00058 struct SyncCallHelper
00059 {
00060 SyncCallHelper()
00061 : received(false)
00062 {}
00063
00064 void cb(const MethodResponse<Res>& res)
00065 {
00066 response = res;
00067 received = true;
00068 }
00069
00070 bool received;
00071 MethodResponse<Res> response;
00072 };
00073
00074 public:
00075 typedef boost::shared_ptr<Req> ReqPtr;
00076 typedef boost::shared_ptr<Req const> ReqConstPtr;
00077 typedef boost::shared_ptr<Res> ResPtr;
00078 typedef boost::shared_ptr<Res const> ResConstPtr;
00079
00080 typedef boost::function<void(const RequestWrapperPtr&, const boost::function<void(const ResponseWrapperConstPtr&)>)> CallFn;
00081 typedef boost::function<void(const MethodResponse<Res>&)> ResponseCallback;
00082 typedef boost::function<void()> PumpFn;
00083
00084 Method() {}
00085
00086 Method(const std::string& name, const CallFn& c, const PumpFn& pump)
00087 {
00088 name_ = name;
00089 call_fn_ = c;
00090 pump_fn_ = pump;
00091 }
00092
00093 void callAsync(const ReqConstPtr& req, const ResponseCallback& cb)
00094 {
00095 ROS_ASSERT(!name_.empty());
00096
00097 RequestWrapperPtr request(boost::make_shared<RequestWrapper>());
00098 request->method = name_;
00099 request->message.message = req;
00100 request->message.serialize = serialize<Req>;
00101 request->message.serialized_length = serializedLength<Req>;
00102 request->message.ti = &typeid(Req);
00103
00104 call_fn_(request, boost::bind(&Method::responseCallback, this, _1, cb));
00105 }
00106
00107 void callAsync(const ReqConstPtr& req)
00108 {
00109 callAsync(req, ResponseCallback());
00110 }
00111
00112 ResConstPtr call(const ReqConstPtr& req)
00113 {
00114 SyncCallHelper h;
00115 callAsync(req, boost::bind(&SyncCallHelper::cb, &h, _1));
00116
00117 while (!h.received)
00118 {
00119 pump_fn_();
00120 }
00121
00122 uint32_t error_code = h.response.error_code;
00123 if (error_code == Response::SUCCESS)
00124 {
00125 return h.response.response;
00126 }
00127 else if (error_code == Response::EXCEPTION)
00128 {
00129 throw CallException(h.response.error_string);
00130 }
00131 else if (error_code == Response::UNKNOWN_METHOD)
00132 {
00133 std::stringstream ss;
00134 ss << "Server does not have method [" << h.response.error_string << "]";
00135 throw CallException(ss.str());
00136 }
00137 else
00138 {
00139 std::stringstream ss;
00140 ss << "Unknown error code [" << error_code << "]";
00141 throw CallException(ss.str());
00142 }
00143 }
00144
00145 private:
00146 void responseCallback(const ResponseWrapperConstPtr& res, const ResponseCallback& cb)
00147 {
00148 if (cb)
00149 {
00150 MethodResponse<Res> mr;
00151 if (res->error_code == 0)
00152 {
00153 mr.response = res->instantiate<Res>();
00154 }
00155 mr.error_code = res->error_code;
00156 mr.error_string = res->error_string;
00157 cb(mr);
00158 }
00159 }
00160
00161 CallFn call_fn_;
00162 PumpFn pump_fn_;
00163 std::string name_;
00164 };
00165
00166 class Client
00167 {
00168 private:
00169 struct MethodInfo
00170 {
00171 std::string name;
00172 std::string request_md5sum;
00173 std::string request_datatype;
00174 std::string request_definition;
00175 std::string response_md5sum;
00176 std::string response_datatype;
00177 std::string response_definition;
00178 };
00179
00180 public:
00181 Client(const std::string& name, const ros::NodeHandle& nh);
00182 void connect();
00183 void connectAsync();
00184 void disconnect();
00185 void waitForConnection();
00186 bool isConnected();
00187 void flush();
00188
00189 template<typename Req, typename Res>
00190 Method<Req, Res> addMethod(const std::string& name)
00191 {
00192 Method<Req, Res> method(name, boost::bind(&Client::call, this, _1, _2), boost::bind(&Client::pump, this));
00193 MethodInfo info;
00194 info.name = name;
00195 info.request_md5sum = ros::message_traits::md5sum<Req>();
00196 info.request_datatype = ros::message_traits::datatype<Req>();
00197 info.request_definition = ros::message_traits::definition<Req>();
00198 info.response_md5sum = ros::message_traits::md5sum<Res>();
00199 info.response_datatype = ros::message_traits::datatype<Res>();
00200 info.response_definition = ros::message_traits::definition<Res>();
00201 addMethod(info);
00202 return method;
00203 }
00204
00205 private:
00206 void addMethod(const MethodInfo& name);
00207 void call(const RequestWrapperPtr& req, const boost::function<void(const ResponseWrapperConstPtr&)>& response_cb);
00208 void pump();
00209
00210 struct Impl;
00211 typedef boost::shared_ptr<Impl> ImplPtr;
00212 ImplPtr impl_;
00213 };
00214 typedef boost::shared_ptr<Client> ClientPtr;
00215
00216 }
00217
00218 #endif // RVIZ_RPC_CLIENT_H