/*] 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 #include #include #include #include "hash.hh" #include "resource.hh" #if HAVE_CONFIG_H #include "../config.h" #endif #ifdef USE_HOTLOADING #include #include #endif #ifndef BUF_SIZE #define BUF_SIZE 4096 #endif namespace moof { static std::vector search_paths_; typedef boost::weak_ptr resource_weakptr; static hash resource_table_; // static member resource::type_lookup_ptr 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); if (!find(path)) return resource_ptr(); 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; } std::map::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 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) { std::vector pathList; boost::split(pathList, paths, boost::is_any_of(":")); add_search_paths(pathList); } void resource::add_search_paths(const std::vector& pathList) { std::vector::const_iterator it; for (it = pathList.begin(); it != pathList.end(); ++it) { std::string path(*it); ASSERT(!path.empty() && "empty search path string"); // add a slash if there isn't one already if (*path.rbegin() != '/') path += '/'; #if defined(_WIN32) //boost::replace_all(path, "/", "\\"); #endif search_paths_.push_back(path); log_info << "added search path " << path << std::endl; } } bool resource::find(const std::string& path) { FILE* file = open_file(path); if (file) { fclose(file); return true; } return false; } FILE* resource::open_file(const std::string& path, const std::string& mode) { #if defined(_WIN32) // windows always has to be a little different //boost::replace_all(path, "/", "\\"); #endif std::vector::iterator it; for (it = search_paths_.begin(); it != search_paths_.end(); ++it) { // check path relative to search path std::string complete_path(*it); complete_path += path; FILE* file = fopen(complete_path.c_str(), mode.c_str()); if (file) return file; } // last ditch effort; maybe it's already a path to a valid resource return fopen(path.c_str(), mode.c_str()); } } // namespace moof