Skip to content
This repository has been archived by the owner on Feb 3, 2025. It is now read-only.

[Gazebo 11] Allow gazebo to download models from Fuel in the sdf files #2822

Merged
merged 20 commits into from
Sep 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 55 additions & 13 deletions gazebo/Server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,15 @@
#include <sdf/sdf.hh>

#include <ignition/math/Rand.hh>
#include "ignition/common/Profiler.hh"
#include <ignition/common/Profiler.hh>
#include <ignition/common/Filesystem.hh>
#include <ignition/common/URI.hh>
#ifdef _WIN32
// DELETE is defined in winnt.h and causes a problem with
// ignition::fuel_tools::REST::DELETE
#undef DELETE
#endif
#include <ignition/fuel_tools/Interface.hh>

#include "gazebo/gazebo.hh"
#include "gazebo/transport/transport.hh"
Expand Down Expand Up @@ -385,15 +393,6 @@ bool Server::GetInitialized() const
bool Server::LoadFile(const std::string &_filename,
const std::string &_physics)
{
// Quick test for a valid file
FILE *test = fopen(common::find_file(_filename).c_str(), "r");
if (!test)
{
gzerr << "Could not open file[" << _filename << "]\n";
return false;
}
fclose(test);

// Load the world file
sdf::SDFPtr sdf(new sdf::SDF);
if (!sdf::init(sdf))
Expand All @@ -402,10 +401,53 @@ bool Server::LoadFile(const std::string &_filename,
return false;
}

if (!sdf::readFile(common::find_file(_filename), sdf))
std::string filename = _filename;
auto filenameUri = ignition::common::URI(filename);

if (filenameUri.Scheme() == "http" || filenameUri.Scheme() == "https")
{
gzerr << "Unable to read sdf file[" << _filename << "]\n";
return false;
std::string downloadedDir = common::FuelModelDatabase::Instance()->WorldPath(filename);
// Find the first sdf file in the world path for now, the later intention is
// to load an optional world config file first and if that does not exist,
// continue to load the first sdf file found as done below
for (ignition::common::DirIter file(downloadedDir);
file != ignition::common::DirIter(); ++file)
{
std::string current(*file);
if (ignition::common::isFile(current))
{
std::string fileName = ignition::common::basename(current);
std::string::size_type fileExtensionIndex = fileName.rfind(".");
std::string fileExtension = fileName.substr(fileExtensionIndex + 1);

if (fileExtension == "sdf" || fileExtension == "world")
{
filename = current.c_str();
if (!sdf::readFile(filename, sdf))
{
gzerr << "Unable to read SDF from URL[" << filename << "]\n";
return false;
}
}
}
}
}
else
{
// Quick test for a valid file
FILE *test = fopen(common::find_file(filename).c_str(), "r");
if (!test)
{
gzerr << "Could not open file[" << filename << "]\n";
return false;
}
fclose(test);

if (!sdf::readFile(common::find_file(filename), sdf))
{
gzerr << "Unable to read sdf file[" << filename << "]\n";
return false;
}
}

return this->LoadImpl(sdf->Root(), _physics);
Expand Down
22 changes: 20 additions & 2 deletions gazebo/common/CommonIface.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,16 @@
#include "gazebo/common/Console.hh"
#include "gazebo/common/CommonIface.hh"
#include "gazebo/common/Exception.hh"
#include "gazebo/common/FuelModelDatabase.hh"
#include "gazebo/common/SystemPaths.hh"

#ifdef _WIN32
// DELETE is defined in winnt.h and causes a problem with
// ignition::fuel_tools::REST::DELETE
#undef DELETE
#endif
#include "ignition/fuel_tools/Interface.hh"

using namespace gazebo;

#ifdef _WIN32
Expand Down Expand Up @@ -156,13 +164,23 @@ void common::add_search_path_suffix(const std::string &_suffix)
/////////////////////////////////////////////////
std::string common::find_file(const std::string &_file)
{
return common::SystemPaths::Instance()->FindFile(_file, true);
std::string path = common::FuelModelDatabase::Instance()->ModelPath(_file);
if (path.empty())
{
path = common::SystemPaths::Instance()->FindFile(_file, true);
}
return path;
}

/////////////////////////////////////////////////
chapulina marked this conversation as resolved.
Show resolved Hide resolved
std::string common::find_file(const std::string &_file, bool _searchLocalPath)
{
return common::SystemPaths::Instance()->FindFile(_file, _searchLocalPath);
std::string path = common::FuelModelDatabase::Instance()->ModelPath(_file);
if (path.empty())
{
path = common::SystemPaths::Instance()->FindFile(_file, _searchLocalPath);
}
return path;
}

/////////////////////////////////////////////////
Expand Down
89 changes: 77 additions & 12 deletions gazebo/common/FuelModelDatabase.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,14 @@

#include <ignition/common/Console.hh>
#include <ignition/common/Filesystem.hh>
#include <ignition/common/URI.hh>
#ifdef _WIN32
// DELETE is defined in winnt.h and causes a problem with
// ignition::fuel_tools::REST::DELETE
#undef DELETE
#endif
#include <ignition/fuel_tools/FuelClient.hh>
#include <ignition/fuel_tools/WorldIdentifier.hh>
#include <sdf/sdf.hh>

#include "gazebo/gazebo_config.h"
Expand Down Expand Up @@ -208,31 +215,90 @@ std::string FuelModelDatabase::ModelPath(const std::string &_uri,

if (fuelUri.Scheme() != "http" && fuelUri.Scheme() != "https")
{
gzwarn << "URI not supported by Fuel [" << _uri << "]" << std::endl;
return std::string();
}
ahcorde marked this conversation as resolved.
Show resolved Hide resolved

std::string path;
std::string fileUrl;
ignition::fuel_tools::ModelIdentifier model;
using namespace ignition::fuel_tools;

if (!_forceDownload)
if ((this->dataPtr->fuelClient->ParseModelUrl(fuelUri, model) &&
!this->dataPtr->fuelClient->CachedModel(fuelUri, path))
|| _forceDownload)
{
if (this->dataPtr->fuelClient->CachedModel(fuelUri, path))
Result result_download =
this->dataPtr->fuelClient->DownloadModel(fuelUri, path);
if (result_download != Result(ResultType::FETCH) ||
result_download != Result(ResultType::FETCH_ALREADY_EXISTS))
{
gzerr << "Unable to download model[" << _uri << "]" << std::endl;
return std::string();
}
else
{
return path;
gzmsg << "Downloaded model URL: " << std::endl
<< " " << _uri << std::endl
<< " to: " << std::endl
<< " " << path << std::endl;
}
}
if (path.empty()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (path.empty()) {
if (path.empty())
{

if ((this->dataPtr->fuelClient->ParseModelFileUrl(fuelUri, model, fileUrl) &&
!this->dataPtr->fuelClient->CachedModelFile(fuelUri, path))
|| _forceDownload)
{
auto modelUri = _uri.substr(0,
_uri.find("files", model.UniqueName().size())-1);
Result result_download =
this->dataPtr->fuelClient->DownloadModel(ignition::common::URI(modelUri), path);
if (result_download != Result(ResultType::FETCH) ||
result_download != Result(ResultType::FETCH_ALREADY_EXISTS))
{
gzerr << "Unable to download model[" << _uri << "]" << std::endl;
return std::string();
}
else
{
gzmsg << "Downloaded model URL: " << std::endl
<< " " << _uri << std::endl
<< " to: " << std::endl
<< " " << path << std::endl;
path += "/" + fileUrl;
}
}
}

if (!this->dataPtr->fuelClient->DownloadModel(fuelUri, path))
return path;
}

/////////////////////////////////////////////////
std::string FuelModelDatabase::WorldPath(const std::string &_uri, const bool _forceDownload)
{
auto fuelUri = ignition::common::URI(_uri);

if (fuelUri.Scheme() != "http" && fuelUri.Scheme() != "https")
{
gzerr << "Unable to download model[" << _uri << "]" << std::endl;
return std::string();
}
else

std::string path;
std::string fileUrl;
ignition::fuel_tools::WorldIdentifier world;

if ((this->dataPtr->fuelClient->ParseWorldUrl(fuelUri, world) &&
!this->dataPtr->fuelClient->CachedWorld(fuelUri, path)) || _forceDownload)
{
gzmsg << "Downloaded model URL: " << std::endl
<< " " << _uri << std::endl
<< " to: " << std::endl
<< " " << path << std::endl;
this->dataPtr->fuelClient->DownloadWorld(fuelUri, path);
}
// Download the world, if it's a world file URI
else if (this->dataPtr->fuelClient->ParseWorldFileUrl(fuelUri, world, fileUrl) &&
!this->dataPtr->fuelClient->CachedWorldFile(fuelUri, path))
{
auto worldUri = _uri.substr(0,
_uri.find("files", world.UniqueName().size())-1);
this->dataPtr->fuelClient->DownloadWorld(ignition::common::URI(worldUri), path);
path += "/" + fileUrl;
}

return path;
Expand All @@ -256,4 +322,3 @@ std::string FuelModelDatabase::CachedFilePath(const std::string &_uri)

return path;
}

15 changes: 15 additions & 0 deletions gazebo/common/FuelModelDatabase.hh
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
#include <memory>
#include <string>
#include <vector>
#ifdef _WIN32
// DELETE is defined in winnt.h and causes a problem with
// ignition::fuel_tools::REST::DELETE
#undef DELETE
#endif
#include <ignition/fuel_tools/ClientConfig.hh>
#include <ignition/fuel_tools/ModelIdentifier.hh>

Expand Down Expand Up @@ -103,6 +108,16 @@ namespace gazebo
public: std::string ModelPath(const std::string &_uri,
const bool _forceDownload = false);

/// \brief Get the local path to a world.
///
/// Get the path to a world based on a URI. If the world is on
/// a remote server, then the model fetched and installed locally.
/// \param[in] _uri the model uri
/// \param[in] _forceDownload True to skip searching local cache.
/// \return Local path to a world directory
public: std::string WorldPath(const std::string &_uri,
const bool _forceDownload = false);

/// \brief Get the full local path to a cached file based on its URI.
/// \param[in] _uri The file's URI
/// \return Local path to the file
Expand Down
21 changes: 0 additions & 21 deletions gazebo/gui/InsertModelWidget.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,21 +48,6 @@ using namespace gui;

static bool gInsertModelWidgetDeleted = false;

/////////////////////////////////////////////////
// TODO: Remove this once Fuel support is fully functional
bool usingFuel()
{
auto useFuel = std::getenv("USE_IGNITION_FUEL");
if (!useFuel || *useFuel == '\0')
return false;

std::string useFuelStr(useFuel);
std::transform(useFuelStr.begin(), useFuelStr.end(),
useFuelStr.begin(), ::tolower);

return useFuelStr != "false" && useFuelStr != "0";
}

/////////////////////////////////////////////////
InsertModelWidget::InsertModelWidget(QWidget *_parent)
: QWidget(_parent), dataPtr(new InsertModelWidgetPrivate)
Expand Down Expand Up @@ -523,9 +508,6 @@ bool InsertModelWidget::IsPathAccessible(const boost::filesystem::path &_path)
/////////////////////////////////////////////////
void InsertModelWidget::InitializeFuelServers()
{
if (!usingFuel())
return;

// Get the list of Ignition Fuel servers.
auto servers = common::FuelModelDatabase::Instance()->Servers();

Expand All @@ -550,9 +532,6 @@ void InsertModelWidget::InitializeFuelServers()
/////////////////////////////////////////////////
void InsertModelWidget::PopulateFuelServers()
{
if (!usingFuel())
return;

// Get the list of Ignition Fuel servers.
auto servers = common::FuelModelDatabase::Instance()->Servers();

Expand Down
2 changes: 1 addition & 1 deletion gazebo/rendering/RenderEngine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ void RenderEngine::LoadPlugins()
/////////////////////////////////////////////////
void RenderEngine::AddResourcePath(const std::string &_uri)
{
if (_uri == "__default__" || _uri.empty())
if (_uri.find("__default__") != std::string::npos || _uri.empty())
return;

std::string path = common::find_file_path(_uri);
Expand Down
Loading