libvisual  0.5.0
lv_plugin_registry.cpp
1 #include "config.h"
2 #include "lv_plugin_registry.h"
3 
4 #include "lv_common.h"
5 #include "lv_actor.h"
6 #include "lv_input.h"
7 #include "lv_morph.h"
8 #include "lv_util.hpp"
9 #include "lv_libvisual.h"
10 #include "lv_module.hpp"
11 
12 #include <vector>
13 #include <unordered_map>
14 #include <cstdlib>
15 
16 namespace LV {
17 
18  namespace {
19  typedef std::unordered_map<PluginType, PluginList, std::hash<int>> PluginListMap;
20 
21  typedef const VisPluginInfo *(*PluginGetInfoFunc)();
22  }
23 
24  class PluginRegistry::Impl
25  {
26  public:
27 
28  std::vector<std::string> plugin_paths;
29 
30  PluginListMap plugin_list_map;
31 
32  PluginList get_plugins_from_dir (std::string const& dir) const;
33  };
34 
35  PluginRef* load_plugin_ref (std::string const& plugin_path)
36  {
37  // NOTE: This does not check if a plugin has already been loaded
38 
39  auto module = Module::load (plugin_path);
40  if (!module) {
41  visual_log (VISUAL_LOG_ERROR, "Cannot load plugin (%s)", plugin_path.c_str ());
42  return nullptr;
43  }
44 
45  auto plugin_version = static_cast<int*> (module->get_symbol (VISUAL_PLUGIN_VERSION_TAG));
46 
47  if (!plugin_version || *plugin_version != VISUAL_PLUGIN_API_VERSION) {
48  visual_log (VISUAL_LOG_ERROR, "Plugin %s is not compatible with version %s of libvisual",
49  plugin_path.c_str (), visual_get_version ());
50  return nullptr;
51  }
52 
53  auto get_plugin_info =
54  reinterpret_cast<PluginGetInfoFunc> (module->get_symbol ("get_plugin_info"));
55 
56  if (!get_plugin_info) {
57  visual_log (VISUAL_LOG_ERROR, "Cannot get function that returns plugin info");
58  return nullptr;
59  }
60 
61  auto plugin_info = get_plugin_info ();
62 
63  if (!plugin_info) {
64  visual_log (VISUAL_LOG_ERROR, "Cannot get plugin info");
65  return nullptr;
66  }
67 
68  auto ref = new PluginRef;
69  ref->info = plugin_info;
70  ref->file = plugin_path;
71  ref->module = module;
72 
73  return ref;
74  }
75 
76  template <>
77  LV_API PluginRegistry* Singleton<PluginRegistry>::m_instance = nullptr;
78 
79  void PluginRegistry::init ()
80  {
81  if (!m_instance)
82  m_instance = new PluginRegistry;
83  }
84 
85  PluginRegistry::PluginRegistry ()
86  : m_impl (new Impl)
87  {
88  visual_log (VISUAL_LOG_DEBUG, "Initializing plugin registry");
89 
90  // Add the standard plugin paths
91  add_path (VISUAL_PLUGIN_PATH "/actor");
92  add_path (VISUAL_PLUGIN_PATH "/input");
93  add_path (VISUAL_PLUGIN_PATH "/morph");
94  add_path (VISUAL_PLUGIN_PATH "/transform");
95 
96 #if defined(VISUAL_OS_POSIX)
97  // Add homedirectory plugin paths
98  auto const home_env = std::getenv ("HOME");
99 
100  if (home_env) {
101  std::string home_dir {home_env};
102 
103  add_path (home_dir + "/.libvisual/actor");
104  add_path (home_dir + "/.libvisual/input");
105  add_path (home_dir + "/.libvisual/morph");
106  add_path (home_dir + "/.libvisual/transform");
107  }
108 #endif
109  }
110 
112  {
113  // empty;
114  }
115 
116  void PluginRegistry::add_path (std::string const& path)
117  {
118  visual_log (VISUAL_LOG_INFO, "Adding to plugin search path: %s", path.c_str());
119 
120  m_impl->plugin_paths.push_back (path);
121 
122  auto plugins = m_impl->get_plugins_from_dir (path);
123 
124  for (auto& plugin : plugins)
125  {
126  auto& list = m_impl->plugin_list_map[plugin.info->type];
127  list.push_back (plugin);
128  }
129  }
130 
131  PluginRef const* PluginRegistry::find_plugin (PluginType type, std::string const& name) const
132  {
133  for (auto const& plugin : get_plugins_by_type (type)) {
134  if (name == plugin.info->plugname) {
135  return &plugin;
136  }
137  }
138 
139  return nullptr;
140  }
141 
142  bool PluginRegistry::has_plugin (PluginType type, std::string const& name) const
143  {
144  return find_plugin (type, name) != nullptr;
145  }
146 
147  PluginList const& PluginRegistry::get_plugins_by_type (PluginType type) const
148  {
149  static PluginList empty;
150 
151  auto match = m_impl->plugin_list_map.find (type);
152  if (match == m_impl->plugin_list_map.end ())
153  return empty;
154 
155  return match->second;
156  }
157 
158  VisPluginInfo const* PluginRegistry::get_plugin_info (PluginType type, std::string const& name) const
159  {
160  auto ref = find_plugin (type, name);
161 
162  return ref ? ref->info : nullptr;
163  }
164 
165  PluginList PluginRegistry::Impl::get_plugins_from_dir (std::string const& dir) const
166  {
167  PluginList list;
168  list.reserve (30);
169 
170  for_each_file_in_dir (dir,
171  [&] (std::string const& path) -> bool {
172  return str_has_suffix (path, Module::path_suffix ());
173  },
174  [&] (std::string const& path) -> bool {
175  auto ref = load_plugin_ref (path);
176 
177  if (ref) {
178  visual_log (VISUAL_LOG_DEBUG, "Adding plugin: %s", ref->info->name);
179  list.push_back (*ref);
180  delete ref;
181  }
182 
183  return true;
184  });
185 
186  return list;
187  }
188 
189 } // LV namespace