X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2Fmoof%2Fresource.cc;h=57bd99b927df9fabfdee70f22faeae208c2d823b;hp=3512878bb039f5cede9b164940c744eccadd664f;hb=151f60a78d5e45c8d46c3e793fdefee306c6dc4c;hpb=831f04d4bc19a390415ac0bbac4331c7a65509bc diff --git a/src/moof/resource.cc b/src/moof/resource.cc index 3512878..57bd99b 100644 --- a/src/moof/resource.cc +++ b/src/moof/resource.cc @@ -9,121 +9,264 @@ * **************************************************************************/ +#include "config.h" + +#ifdef USE_HOTLOADING +#include +#include +#endif + +#include + #include +#include +#include -#include "log.hh" +#include "hash.hh" #include "resource.hh" +#ifndef BUF_SIZE +#define BUF_SIZE 4096 +#endif + + namespace moof { + +bool resource::call_registry(const std::string& extension, + loader_ptr& loader, + registry_action action) +{ + static type_lookup table; -// static member -std::vector resource::search_paths_; + switch (action) + { + case set: + { + if (loader) table[extension] = loader; + else table.erase(extension); + break; + } + case lookup: + { + std::map::iterator it; + it = table.find(extension); + if (it != table.end()) loader = (*it).second; + break; + } + } -void resource::add_search_paths(const std::string& paths) + return loader; +} + +static std::string search_paths_; + +typedef boost::weak_ptr resource_weakptr; +static hash resource_table_; + +static hash prefix_table_; + + +#ifdef USE_HOTLOADING +static hash monitor_lookup_; +static int monitor_fd_ = inotify_init1(IN_NONBLOCK); +#endif + +int resource::reload_as_needed() { - std::vector 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::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& pathList) + +resource::~resource() { - std::vector::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"); +resource_ptr resource::load(const std::string& name, + const std::string& ext) +{ + return load_with_path(find_file(name, ext)); +} - // add a slash if there isn't one already - if (*path.rbegin() != '/') path += '/'; +resource_ptr resource::load(const std::string& name) +{ + return load_with_path(find_file(name)); +} -#if defined(_WIN32) - boost::replace_all(path, "/", "\\"); + +resource_ptr resource::load_with_path(const std::string& path) +{ + std::string extension = stlplus::extension_part(path); + + hash::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; + } + + loader_ptr loader; + call_registry(extension, loader, lookup); + if (loader) + { + resource_ptr rsrc(loader->load(path)); + rsrc->set_loader(path, loader); + 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; } + + log_warning("cannot load resource of unknown type:", path); + 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::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 preList; - boost::split(preList, temp_prefix, boost::is_any_of(":")); -#else - std::vector 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 postList; - boost::split(postList, extension, boost::is_any_of(":")); + delete resource; +} + + +void resource::add_search_paths(const std::string& paths) +{ + search_paths_ = paths; +} + + +std::string resource::find_file(const std::string& name) +{ + std::vector paths; + boost::split(paths, search_paths_, boost::is_any_of(":")); + + std::string ext = stlplus::extension_part(name); + std::string prefix("hi"); + + loader_ptr loader; + call_registry(ext, loader, lookup); + if (loader) prefix = loader->prefix(); + + log_info("find_file:", ext, prefix); std::vector::iterator it; - for (it = search_paths_.begin(); it != search_paths_.end(); ++it) + for (it = paths.begin(); it != paths.end(); ++it) { - std::vector::iterator jt; - for (jt = preList.begin(); jt != preList.end(); ++jt) + std::string path = stlplus::create_filespec(*it, name); + log_info("looking for", name, "at", path); + if (stlplus::file_exists(path)) return path; + + // try it with the prefix added + if (!prefix.empty()) { - std::vector::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; - } - } + *it = stlplus::create_filespec(*it, prefix); + path = stlplus::create_filespec(*it, name); + log_info("looking for", name, "at", path); + if (stlplus::file_exists(path)) return path; } + } - // check path relative to search path - std::string realPath(*it); - realPath += path; - FILE* file = fopen(realPath.c_str(), mode.c_str()); - if (file) - { - path = realPath; - return file; - } - } + log_error("cannot find resource file:", name); + return std::string(); +} - // last ditch effort; maybe it's already a path to a valid resource - return fopen(path.c_str(), mode.c_str()); +std::string resource::find_file(const std::string& name, + const std::string& ext) +{ + std::string actual_ext = stlplus::extension_part(name); + if (actual_ext != ext) + { + return find_file(stlplus::create_filename(name, ext)); + } + return find_file(name); }