ppovb5fc7/gazebo/plugins/rest_web/RestWebPlugin.cc

375 lines
9.6 KiB
C++
Raw Normal View History

2019-03-04 17:11:56 +08:00
/*
* Copyright (C) 2015 Open Source Robotics Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifdef _WIN32
#include <Rpc.h>
#pragma comment(lib, "Rpcrt4.lib")
#else /* UNIX */
#include <gazebo/gazebo.hh>
#ifdef HAVE_UUID
#include <uuid/uuid.h>
#endif
#endif
#include "RestWebPlugin.hh"
using namespace gazebo;
using namespace std;
//////////////////////////////////////////////////
RestWebPlugin::RestWebPlugin()
: node(new gazebo::transport::Node()),
stopMsgProcessing(false),
requestQThread(NULL)
{
// generate a unique session ID
// On Windows
#ifdef _WIN32
UUID uuid;
C_STATUS Result = ::UuidCreate(uuid);
if (Result != RPC_S_OK)
{
gzerr << "Call to UuidCreate return a non success RPC call. " <<
"Return code: " << Result << std::endl;
}
char* szUuid = NULL;
if (::UuidToStringA(&this->data, reinterpret_cast<RPC_CSTR*>(&szUuid)) ==
RPC_S_OK)
{
this->session = szUuid;
::RpcStringFreeA(reinterpret_cast<RPC_CSTR*>(&szUuid));
}
// or on UNIX
#else
#ifdef HAVE_UUID
uuid_t uuid;
uuid_generate_random(uuid);
char s[37];
uuid_unparse(uuid, s);
this->session = s;
#endif
#endif
if (this->session.empty())
{
// alternative to uuid
this->session = common::Time::GetWallTimeAsISOString();
}
gzmsg << "REST web Session : " << this->session << endl;
}
//////////////////////////////////////////////////
RestWebPlugin::~RestWebPlugin()
{
// tell the requestQ to stop precessing
this->stopMsgProcessing = true;
if (this->requestQThread && this->requestQThread->joinable())
{
this->requestQThread->join();
delete this->requestQThread;
}
}
//////////////////////////////////////////////////
void RestWebPlugin::Init()
{
// setup our node for communication
this->node->Init();
this->subLogin = node->Subscribe("/gazebo/rest/rest_login",
&RestWebPlugin::OnRestLoginRequest, this);
this->subLogout = node->Subscribe("/gazebo/rest/rest_logout",
&RestWebPlugin::OnRestLogoutRequest, this);
this->subEvent = node->Subscribe("/gazebo/rest/rest_post",
&RestWebPlugin::OnEventRestPost, this);
this->subSimEvent = node->Subscribe("/gazebo/sim_events",
&RestWebPlugin::OnSimEvent, this);
this->requestQThread = new boost::thread(
boost::bind(&RestWebPlugin::RunRequestQ, this));
}
//////////////////////////////////////////////////
void RestWebPlugin::Load(int /*_argc*/, char ** /*_argv*/)
{
// nothing to do for now
}
//////////////////////////////////////////////////
void RestWebPlugin::OnSimEvent(ConstSimEventPtr &_msg)
{
gazebo::msgs::RestResponse msg;
std::string response;
try
{
// where to post the data on the REST server
std::string route = "/events/new";
std::string eType = _msg->type();
std::string name = _msg->name();
std::string data = _msg->data();
msgs::WorldStatistics ws = _msg->world_statistics();
msgs::Time simT = ws.sim_time();
msgs::Time realT = ws.real_time();
msgs::Time pauseT = ws.pause_time();
bool paused = ws.paused();
std::string worldName = physics::get_world()->GetName();
std::string event = "{\n";
event += "\"session\": \"" + this->session + "\", ";
event += "\"name\": \"" + name + "\", ";
event += "\"type\": \"" + eType + "\",\n";
event += "\"data\": " + data + ", ";
event += "\"world\": {";
event += "\"name\": ";
event += "\"";
event += worldName;
event += "\", ";
event += "\"paused\": ";
event += "\"";
if (paused)
event += "true";
else
event += "false";
event += "\", ";
event += "\"clock_time\": ";
event += "\"";
event += common::Time::GetWallTimeAsISOString();
event += "\", ";
event += "\"real_time\": ";
event += "\"";
event += msgs::Convert(realT).FormattedString();
event += "\", ";
event += "\"sim_time\": ";
event += "\"";
event += msgs::Convert(simT).FormattedString();
event += "\", ";
event += "\"pause_time\": ";
event += "\"";
event += msgs::Convert(pauseT).FormattedString();
event += "\"";
event += "}\n"; // world element
event += "}"; // root element
// post it with curl
this->restApi.PostJsonData(route.c_str(), event.c_str());
msg.set_type(msgs::RestResponse::SUCCESS);
}
catch(RestException &x)
{
response = "There was a problem trying to send data to the server: ";
response += x.what();
msg.set_type(msgs::RestResponse::ERROR);
// alert the user via the gui plugin
gzerr << "ERROR in REST service POST request: " << response << std::endl;
}
if (_msg->has_id())
msg.set_id(_msg->id());
msg.set_msg(response);
this->pub->Publish(msg);
}
//////////////////////////////////////////////////
void RestWebPlugin::OnEventRestPost(ConstRestPostPtr &_msg)
{
gzmsg << "RestWebPlugin::OnRestPost";
gzmsg << "[" << _msg->route() << ", " << _msg->json() << "]" << std::endl;
gzmsg << std::endl;
gazebo::msgs::RestResponse msg;
std::string response;
try
{
std::string event = "{";
event += "\"event\": " + _msg->json() + ", ";
physics::WorldPtr world = physics::get_world();
if (!world)
{
gzerr << "Can't access world before web service POST" << std::endl;
}
else
{
event += "\"session\": \"" + this->session + "\", ";
event += "\"world\": {";
event += "\"name\": ";
event += "\"";
event += world->GetName();
event += "\", ";
if (!world->IsPaused())
{
event += "\"is_running\": \"true\", ";
}
else
{
event += "\"is_running\": \"false\", ";
}
common::Time t;
event += "\"clock_time\": ";
event += "\"";
event += common::Time::GetWallTimeAsISOString();
event += "\", ";
event += "\"real_time\": ";
event += "\"";
t = world->GetRealTime();
event += t.FormattedString();
event += "\", ";
event += "\"sim_time\": ";
event += "\"";
t = world->GetSimTime();
event += t.FormattedString();
event += "\", ";
event += "\"pause_time\": ";
event += "\"";
t = world->GetPauseTime();
event += t.FormattedString();
event += "\" ";
event += "}";
}
event += "}";
this->restApi.PostJsonData(_msg->route().c_str(), event.c_str());
msg.set_type(msgs::RestResponse::SUCCESS);
}
catch(RestException &x)
{
response = "There was a problem trying to send data to the server: ";
response += x.what();
msg.set_type(msgs::RestResponse::ERROR);
// alert the user via the gui plugin
gzerr << "ERROR in REST request: " << response << std::endl;
}
if (_msg->has_id())
msg.set_id(_msg->id());
msg.set_msg(response);
this->pub->Publish(msg);
}
//////////////////////////////////////////////////
void RestWebPlugin::OnRestLoginRequest(ConstRestLoginPtr &_msg)
{
boost::mutex::scoped_lock lock(this->requestQMutex);
this->msgLoginQ.push_back(_msg);
}
//////////////////////////////////////////////////
void RestWebPlugin::OnRestLogoutRequest(ConstRestLogoutPtr &_msg)
{
boost::mutex::scoped_lock lock(this->requestQMutex);
this->restApi.Logout();
gazebo::msgs::RestResponse msg;
if (_msg->has_id())
msg.set_id(_msg->id());
msg.set_type(msgs::RestResponse::LOGOUT);
msg.set_msg("Success");
this->pub->Publish(msg);
}
//////////////////////////////////////////////////
void RestWebPlugin::ProcessLoginRequest(ConstRestLoginPtr _msg)
{
gazebo::msgs::RestResponse msg;
std::string response;
// this is executed asynchronously
try
{
this->restApi.Login(_msg->url().c_str(),
"/login",
_msg->username().c_str(),
_msg->password().c_str());
response = "Success";
msg.set_type(msgs::RestResponse::LOGIN);
}
catch(RestException &x)
{
response = "There was a problem trying to login to the server: ";
response += x.what();
msg.set_type(msgs::RestResponse::ERROR);
// alert the user via the gui plugin
gzerr << "ERROR in REST login request. : " << response << std::endl;
}
if (_msg->has_id())
msg.set_id(_msg->id());
msg.set_msg(response);
this->pub->Publish(msg);
}
//////////////////////////////////////////////////
void RestWebPlugin::RunRequestQ()
{
// be ready to send errors back to the UI
std::string path("/gazebo/rest/rest_response");
this->pub = node->Advertise<gazebo::msgs::RestResponse>(path);
// process any login or post data that ha been received
while (!this->stopMsgProcessing)
{
gazebo::common::Time::MSleep(50);
try
{
boost::shared_ptr<const gazebo::msgs::RestLogin> login;
// Grab the mutex and remove first message the queue
{
boost::mutex::scoped_lock lock(this->requestQMutex);
if (!this->msgLoginQ.empty())
{
login = this->msgLoginQ.front();
this->msgLoginQ.pop_front();
}
}
if (login)
{
this->ProcessLoginRequest(login);
}
}
catch(...)
{
gzerr << "Unhandled exception while processing request message"
<< std::endl;
}
}
}
// plugin registration
GZ_REGISTER_SYSTEM_PLUGIN(RestWebPlugin)