*
**************************************************************************/
+#include "../config.h"
+
+#include <queue>
+
+#ifdef USE_HOTLOADING
+#include <sys/inotify.h>
+#include <sys/ioctl.h>
+#endif
+
#include <boost/algorithm/string.hpp>
+#include <boost/weak_ptr.hpp>
-#include "log.hh"
+#include <stlplus/portability/file_system.hpp>
+
+#include "hash.hh"
#include "resource.hh"
+#ifndef BUF_SIZE
+#define BUF_SIZE 4096
+#endif
+
+
namespace moof {
+
+static std::string search_paths_;
+
+typedef boost::weak_ptr<resource> resource_weakptr;
+static hash<std::string,resource_weakptr,hash_function> resource_table_;
// static member
-std::vector<std::string> resource::search_paths_;
+resource::type_lookup_ptr resource::type_lookup_;
-void resource::add_search_paths(const std::string& paths)
+#ifdef USE_HOTLOADING
+static hash<int,std::string,hash_function> monitor_lookup_;
+static int monitor_fd_ = inotify_init1(IN_NONBLOCK);
+#endif
+
+int resource::reload_as_needed()
{
- std::vector<std::string> pathList;
- boost::split(pathList, paths, boost::is_any_of(":"));
+ int num_resources = 0;
+
+#ifdef USE_HOTLOADING
+ log_info("hotloading?");
+ char bytes[BUF_SIZE];
+ int num_bytes;
+ if (0 < (num_bytes = read(monitor_fd_, bytes, num_bytes)))
+ {
+ char* end = bytes + num_bytes;
+ char* byte = bytes;
+
+ log_warning("num_bytes:", num_bytes);
+ log_error("1");
- add_search_paths(pathList);
+ while (byte < end)
+ {
+ struct inotify_event* event = (struct inotify_event*)byte;
+
+ if (event->mask & IN_IGNORED)
+ {
+ log_warning("watch", event->wd, "removed");
+ }
+
+ log_error("2");
+ hash<int,std::string,hash_function>::iterator it;
+ it = monitor_lookup_.find(event->wd);
+ if (it != monitor_lookup_.end())
+ {
+ log_error("3");
+ std::string path = (*it).second;
+ monitor_lookup_.erase(it);
+ resource::reload(path);
+ }
+
+ byte += sizeof(*event) + event->len;
+
+ ++num_resources;
+ }
+ }
+#endif
+
+ return num_resources;
}
-void resource::add_search_paths(const std::vector<std::string>& pathList)
+
+resource::~resource()
{
- std::vector<std::string>::const_iterator it;
- for (it = pathList.begin(); it != pathList.end(); ++it)
- {
- std::string path(*it);
+#ifdef USE_HOTLOADING
+ inotify_rm_watch(monitor_fd_, wd_);
+#endif
+}
- ASSERT(!path.empty() && "empty search path string");
- // add a slash if there isn't one already
- if (*path.rbegin() != '/') path += '/';
+resource_ptr resource::load(const std::string& path)
+{
+ std::string extension = stlplus::extension_part(path);
+
+ if (!find(path)) return resource_ptr();
+
+ hash<std::string,resource_weakptr,hash_function>::iterator it;
+ it = resource_table_.find(path);
+ if (it != resource_table_.end())
+ {
+ resource_weakptr rsrc = (*it).second;
+ resource_ptr locked = rsrc.lock();
+ if (locked) return locked;
+ }
-#if defined(_WIN32)
- boost::replace_all(path, "/", "\\");
+ std::map<std::string,loader_ptr>::iterator jt;
+ jt = type_lookup_->find(extension);
+ if (jt != type_lookup_->end())
+ {
+ resource_ptr rsrc((*jt).second->load(path));
+ rsrc->set_loader(path, (*jt).second);
+ resource_table_[path] = rsrc;
+
+#ifdef USE_HOTLOADING
+ int wd = inotify_add_watch(monitor_fd_,
+ path.c_str(), IN_MODIFY);
+ rsrc->set_watch_descriptor(wd);
+ monitor_lookup_[wd] = path;
#endif
- search_paths_.push_back(path);
- log_info << "added search path " << path << std::endl;
+ log_info("loaded", rsrc.get());
+ return rsrc;
}
+
+ return resource_ptr();
}
-bool resource::find_path(std::string& path,
- const std::string& prefix,
- const std::string& extension)
+resource_ptr resource::reload(std::string& path)
{
- FILE* file = open_file(path, prefix, extension);
- if (file)
+ log_info("reloading...", path);
+ hash<std::string,resource_weakptr,hash_function>::iterator it;
+ it = resource_table_.find(path);
+ if (it != resource_table_.end())
{
- fclose(file);
- return true;
+ resource_weakptr rsrc = (*it).second;
+ resource_ptr locked = rsrc.lock();
+ if (locked)
+ {
+ locked->reload();
+ return locked;
+ }
}
- return false;
+ return load(path);
}
-FILE* resource::open_file(std::string& path,
- const std::string& prefix,
- const std::string& extension,
- const std::string& mode)
+void resource::reload()
{
-#if defined(_WIN32)
- // windows always has to be a little different
- boost::replace_all(path, "/", "\\");
- std::string temp_prefix(prefix);
- boost::replace_all(temp_prefix, "/", "\\");
- std::vector<std::string> preList;
- boost::split(preList, temp_prefix, boost::is_any_of(":"));
-#else
- std::vector<std::string> preList;
- boost::split(preList, prefix, boost::is_any_of(":"));
+ log_info("reloaded", path_);
+
+ resource* resource = loader_->load(path_);
+ //*this = *resource;
+ resource_ = resource->resource_;
+ typeinfo_ = resource->typeinfo_;
+ unloader_ = resource->unloader_;
+
+#ifdef USE_HOTLOADING
+ int wd = inotify_add_watch(monitor_fd_,
+ path_.c_str(), IN_MODIFY);
+ set_watch_descriptor(wd);
+ monitor_lookup_[wd] = path_;
#endif
- std::vector<std::string> postList;
- boost::split(postList, extension, boost::is_any_of(":"));
+ delete resource;
+}
- std::vector<std::string>::iterator it;
- for (it = search_paths_.begin(); it != search_paths_.end(); ++it)
- {
- std::vector<std::string>::iterator jt;
- for (jt = preList.begin(); jt != preList.end(); ++jt)
- {
- std::vector<std::string>::iterator kt;
- for (kt = postList.begin(); kt != postList.end(); ++kt)
- {
- std::string realPath(*it);
- realPath += *jt;
- realPath += path;
- realPath += ".";
- realPath += *kt;
-
- FILE* file = fopen(realPath.c_str(), mode.c_str());
- if (file)
- {
- path = realPath;
- return file;
- }
- }
- }
- // check path relative to search path
- std::string realPath(*it);
- realPath += path;
+void resource::add_search_paths(const std::string& paths)
+{
+ search_paths_ = paths;
+}
+
- FILE* file = fopen(realPath.c_str(), mode.c_str());
- if (file)
- {
- path = realPath;
- return file;
- }
- }
+bool resource::find(const std::string& path)
+{
+ return !stlplus::lookup(path, search_paths_, ":").empty();
+}
- // last ditch effort; maybe it's already a path to a valid resource
- return fopen(path.c_str(), mode.c_str());
+FILE* resource::open_file(const std::string& path, const std::string& mode)
+{
+ std::string file = stlplus::lookup(path, search_paths_, ":");
+ return fopen(file.c_str(), mode.c_str());
}