JSONTopologyLoader.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. // Copyright (c) 2016-2017 Josh Blum
  2. // SPDX-License-Identifier: BSL-1.0
  3. #include <Pothos/Plugin.hpp>
  4. #include <Pothos/Framework.hpp>
  5. #include <Poco/Path.h>
  6. #include <Poco/File.h>
  7. #include <fstream>
  8. #include <map>
  9. #include <json.hpp>
  10. using json = nlohmann::json;
  11. /***********************************************************************
  12. * The topology factory loads args into a JSON description
  13. * and creates and returns an instance of the topology
  14. **********************************************************************/
  15. static Pothos::Object opaqueJSONTopologyFactory(
  16. const std::string &jsonStr,
  17. const Pothos::Object *args,
  18. const size_t numArgs)
  19. {
  20. //parse the json formatted string into a JSON object
  21. json topObj;
  22. try
  23. {
  24. topObj = json::parse(jsonStr);
  25. }
  26. catch (const std::exception &ex)
  27. {
  28. throw Pothos::DataFormatException(ex.what());
  29. }
  30. //apply the global variable overlays
  31. auto &globalsArray = topObj["globals"];
  32. if (numArgs > globalsArray.size())
  33. {
  34. throw Pothos::InvalidArgumentException("too many args passed to factory");
  35. }
  36. for (size_t i = 0; i < numArgs; i++)
  37. {
  38. if (not globalsArray[i].is_object())
  39. {
  40. throw Pothos::DataFormatException("global entry not a JSON object");
  41. }
  42. globalsArray[i]["value"] = args[i].toString();
  43. }
  44. //create the topology from the JSON string
  45. return Pothos::Object(Pothos::Topology::make(topObj.dump()));
  46. }
  47. /***********************************************************************
  48. * Load a JSON topology described by a config file section
  49. **********************************************************************/
  50. static std::vector<Pothos::PluginPath> JSONTopologyLoader(const std::map<std::string, std::string> &config)
  51. {
  52. std::vector<Pothos::PluginPath> entries;
  53. //config file path set by caller
  54. const auto confFilePathIt = config.find("confFilePath");
  55. if (confFilePathIt == config.end() or confFilePathIt->second.empty())
  56. throw Pothos::Exception("missing confFilePath");
  57. //determine JSON description file path
  58. const auto jsonIt = config.find("json");
  59. if (jsonIt == config.end() or jsonIt->second.empty())
  60. throw Pothos::Exception("JSON file not specified");
  61. Poco::Path jsonPath(jsonIt->second);
  62. jsonPath.makeAbsolute(Poco::Path(confFilePathIt->second).makeParent());
  63. if (not Poco::File(jsonPath).exists())
  64. throw Pothos::Exception(jsonPath.toString() + " does not exist");
  65. //get the plugin path
  66. const auto pathIt = config.find("path");
  67. if (pathIt == config.end() or pathIt->second.empty())
  68. throw Pothos::Exception("missing plugin path");
  69. const auto pluginPath = Pothos::PluginPath("/blocks", pathIt->second);
  70. //parse the file into a string
  71. std::ifstream ifs(Poco::Path::expand(jsonPath.toString()));
  72. const std::string json((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
  73. //create an entry for the factory
  74. const auto factory = Pothos::Callable(&opaqueJSONTopologyFactory).bind(json, 0);
  75. Pothos::PluginRegistry::addCall(pluginPath, factory);
  76. entries.push_back(pluginPath);
  77. return entries;
  78. }
  79. /***********************************************************************
  80. * loader registration
  81. **********************************************************************/
  82. pothos_static_block(pothosFrameworkRegisterJSONTopologyLoader)
  83. {
  84. Pothos::PluginRegistry::addCall("/framework/conf_loader/json_topology", &JSONTopologyLoader);
  85. }