/*] Copyright (c) 2009-2010, Charles McGarvey [************************** **] All rights reserved. * * vi:ts=4 sw=4 tw=75 * * Distributable under the terms and conditions of the 2-clause BSD license; * see the file COPYING for a complete text of the license. * **************************************************************************/ #include "config.h" #ifdef USE_HOTLOADING #include #include #endif #include #include #include #include #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; 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; } } 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() { 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"); 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; } resource::~resource() { #ifdef USE_HOTLOADING inotify_rm_watch(monitor_fd_, wd_); #endif } resource_ptr resource::load(const std::string& name, const std::string& ext) { return load_with_path(find_file(name, ext)); } resource_ptr resource::load(const std::string& name) { return load_with_path(find_file(name)); } 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 log_info("loaded", rsrc.get()); return rsrc; } log_warning("cannot load resource of unknown type:", path); return resource_ptr(); } resource_ptr resource::reload(std::string& path) { log_info("reloading...", 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) { locked->reload(); return locked; } } return load(path); } void resource::reload() { 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 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 = paths.begin(); it != paths.end(); ++it) { 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()) { *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; } } log_error("cannot find resource file:", name); return std::string(); } 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); } } // namespace moof