/*] 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 { void resource::print_types() { } void resource::manage_loader(const std::string& extension, loader_ptr& loader, bool set) { static type_lookup lookup; if (loader || set) { lookup[extension] = loader; } else { std::map::iterator it; it = lookup.find(extension); if (it != lookup.end()) loader = (*it).second; } } static std::string search_paths_; typedef boost::weak_ptr resource_weakptr; static hash resource_table_; // static member //resource::type_lookup_ptr resource::type_lookup_; //resource::type_lookup resource::type_lookup_; #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& path) { std::string extension = stlplus::extension_part(path); std::string path1 = path; if (!find(path1)) { log_error("trying to load missing resource:", path1); return resource_ptr(); } hash::iterator it; it = resource_table_.find(path1); if (it != resource_table_.end()) { resource_weakptr rsrc = (*it).second; resource_ptr locked = rsrc.lock(); if (locked) return locked; } loader_ptr loader; manage_loader(extension, loader); if (loader) { resource_ptr rsrc(loader->load(path1)); rsrc->set_loader(path1, loader); resource_table_[path1] = rsrc; #ifdef USE_HOTLOADING int wd = inotify_add_watch(monitor_fd_, path1.c_str(), IN_MODIFY); rsrc->set_watch_descriptor(wd); monitor_lookup_[wd] = path1; #endif log_info("loaded", rsrc.get()); return rsrc; } 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; } bool resource::find(const std::string& path) { //std::string file = stlplus::lookup(path, search_paths_, ":"); //log_info("found file", file, "in", search_paths_); //return !stlplus::lookup(path, search_paths_, ":").empty(); return find_file(path) != ""; } std::string resource::find_file(const std::string& name) { //log_info("looking for", name, "in", search_paths_); //return stlplus::lookup(name, search_paths_, ":"); std::vector paths; boost::split(paths, search_paths_, boost::is_any_of(":")); std::vector::iterator it; for (it = paths.begin(); it != paths.end(); ++it) { *it += "/"; *it += name; log_info("looking for", name, "in", *it); if (stlplus::file_exists(*it)) return *it; } return std::string(); } FILE* resource::open_file(const std::string& path, const std::string& mode) { return fopen(find_file(path).c_str(), mode.c_str()); } } // namespace moof