ChipMaster's trial hacks on C++CMS starting with v1.2.1. Not sure I'll follow on with the v2 since it looks to be breaking and mostly frivolous.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

301 lines
6.8 KiB

  1. #define CPPCMS_SOURCE
  2. #include "views_pool.h"
  3. #include "json.h"
  4. #include "config.h"
  5. #include "cppcms_error.h"
  6. #ifdef CPPCMS_USE_EXTERNAL_BOOST
  7. # include <boost/thread.hpp>
  8. # include <boost/format.hpp>
  9. #else // Internal Boost
  10. # include <cppcms_boost/thread.hpp>
  11. # include <cppcms_boost/format.hpp>
  12. namespace boost = cppcms_boost;
  13. #endif
  14. #ifdef CPPCMS_WIN32
  15. #include <windows.h>
  16. #include <process.h>
  17. #else
  18. #include <dlfcn.h>
  19. #endif
  20. #include <sys/types.h>
  21. #include <sys/stat.h>
  22. namespace cppcms {
  23. namespace impl {
  24. #ifdef CPPCMS_WIN32
  25. class shared_object : public util::noncopyable {
  26. public:
  27. static std::string name(std::string file,std::string path);
  28. shared_object(std::string file_name,bool reloadable)
  29. {
  30. if(reloadable) {
  31. #ifdef CPPCMS_WIN_NATIVE
  32. int pid=_getpid();
  33. #else
  34. int pid=getpid();
  35. #endif
  36. file_name_ = (boost::format("%1%.tmp-%2%.dll",std::locale::classic()) % file_name % pid).str();
  37. if(!CopyFile(file_name.c_str(),file_name_.c_str(),1)) {
  38. throw cppcms_error("Failed to copy file "+file_name+" to "+file_name_);
  39. }
  40. remove_=true;
  41. }
  42. else {
  43. file_name_ = file_name;
  44. remove_=false;
  45. }
  46. handler_ = LoadLibrary(file_name_.c_str());
  47. if(!handler_) {
  48. if(remove_)
  49. DeleteFile(file_name_.c_str());
  50. throw cppcms_error("Failed to load library "+file_name);
  51. }
  52. }
  53. ~shared_object()
  54. {
  55. FreeLibrary(handler_);
  56. if(remove_) {
  57. DeleteFile(file_name_.c_str());
  58. }
  59. }
  60. FARPROC symbol(std::string const &name) const
  61. {
  62. return GetProcAddress(handler_,name.c_str());
  63. }
  64. private:
  65. HMODULE handler_;
  66. std::string file_name_;
  67. bool remove_;
  68. };
  69. #else
  70. class shared_object : public util::noncopyable {
  71. public:
  72. static std::string name(std::string file,std::string path);
  73. shared_object(std::string file_name,bool unused)
  74. {
  75. handler_ = dlopen(file_name.c_str(),RTLD_LAZY);
  76. if(!handler_) {
  77. throw cppcms_error("Failed to load library "+file_name);
  78. }
  79. }
  80. ~shared_object()
  81. {
  82. dlclose(handler_);
  83. }
  84. void *symbol(std::string const &name) const
  85. {
  86. return dlsym(handler_,name.c_str());
  87. }
  88. private:
  89. void *handler_;
  90. };
  91. #endif
  92. std::string shared_object::name(std::string file,std::string path)
  93. {
  94. #ifdef CPPCMS_LIBRARY_PREFIX
  95. return path+"/"+CPPCMS_LIBRARY_PREFIX+file+CPPCMS_LIBRARY_SUFFIX;
  96. #else
  97. return path+"/"+file+CPPCMS_LIBRARY_SUFFIX;
  98. #endif
  99. }
  100. } // impl
  101. #if !defined(HAVE_STAT) && defined(HAVE__STAT)
  102. #define stat _stat
  103. #endif
  104. struct views_pool::skin {
  105. public:
  106. skin()
  107. {
  108. }
  109. skin(std::string const &name,std::vector<std::string> const &search_path,bool reloadable) :
  110. reloadable_(true),
  111. skin_name_(name)
  112. {
  113. for(unsigned i=0;i<search_path.size();i++) {
  114. struct stat st;
  115. std::string file_name = impl::shared_object::name(name,search_path[i]);
  116. if(::stat(file_name.c_str(),&st) < 0)
  117. continue;
  118. file_name_ = file_name;
  119. time_stamp_ = st.st_mtime;
  120. shared_object_.reset(new impl::shared_object(file_name,reloadable));
  121. return;
  122. }
  123. throw cppcms_error("Can't load skin " + name);
  124. }
  125. void copy_mapping(skin const &other)
  126. {
  127. mapping_ = other.mapping_;
  128. }
  129. skin(std::string skin_name,std::map<std::string,view_factory_type> const &views) :
  130. reloadable_(false),
  131. skin_name_(skin_name)
  132. {
  133. mapping_=views;
  134. }
  135. bool is_updated() const
  136. {
  137. if(!reloadable_)
  138. return true;
  139. struct stat st;
  140. if(::stat(file_name_.c_str(),&st) < 0)
  141. return true;
  142. return time_stamp_ >= st.st_mtime;
  143. }
  144. void render(std::string template_name,std::ostream &output,base_content &content) const
  145. {
  146. mapping_type::const_iterator p = mapping_.find(template_name);
  147. if(p==mapping_.end())
  148. throw cppcms_error("Can't find template "+template_name + " in skin "+skin_name_);
  149. std::auto_ptr<base_view> a_view = p->second(output,&content);
  150. a_view->render();
  151. }
  152. private:
  153. bool reloadable_;
  154. std::string skin_name_;
  155. std::string file_name_;
  156. time_t time_stamp_;
  157. mapping_type mapping_;
  158. boost::shared_ptr<impl::shared_object> shared_object_;
  159. };
  160. struct views_pool::data {
  161. bool dynamic_reload;
  162. typedef std::map<std::string,skin> skins_type;
  163. skins_type skins;
  164. boost::shared_mutex lock_;
  165. std::string default_skin;
  166. std::vector<std::string> search_path;
  167. };
  168. views_pool::views_pool() :
  169. d(new data())
  170. {
  171. }
  172. std::string views_pool::default_skin() const
  173. {
  174. return d->default_skin;
  175. }
  176. views_pool::views_pool(json::value const &settings) :
  177. d(new data())
  178. {
  179. d->skins=static_instance().d->skins;
  180. std::vector<std::string> paths=settings.get("views.paths",std::vector<std::string>());
  181. d->search_path=paths;
  182. std::vector<std::string> skins=settings.get("views.skins",std::vector<std::string>());
  183. d->dynamic_reload= settings.get("views.auto_reload",false);
  184. d->default_skin = settings.get<std::string>("views.default_skin","");
  185. if(d->default_skin.empty() && d->skins.size()==1)
  186. d->default_skin=d->skins.begin()->first;
  187. if(paths.empty() || skins.empty()) {
  188. return;
  189. }
  190. for(unsigned i=0;i<skins.size();i++) {
  191. std::string name=skins[i];
  192. if(d->skins.find(name)!=d->skins.end())
  193. throw cppcms_error("Two skins with same name provided:" + name);
  194. d->skins[name]=skin(name,paths,d->dynamic_reload);
  195. }
  196. if(d->default_skin.empty())
  197. d->default_skin=skins[0];
  198. }
  199. void views_pool::render(std::string skin_name,std::string template_name,std::ostream &out,base_content &content)
  200. {
  201. if(d->dynamic_reload) {
  202. for(;;){
  203. { // Check if update
  204. boost::shared_lock<boost::shared_mutex> lock(d->lock_);
  205. data::skins_type::const_iterator p=d->skins.find(skin_name);
  206. if(p==d->skins.end())
  207. throw cppcms_error("There is no such skin:" + skin_name);
  208. if(p->second.is_updated()) {
  209. p->second.render(template_name,out,content);
  210. return;
  211. }
  212. }
  213. { // Reload
  214. boost::unique_lock<boost::shared_mutex> lock(d->lock_);
  215. data::skins_type::iterator p=d->skins.find(skin_name);
  216. if(p==d->skins.end())
  217. throw cppcms_error("There is no such skin:" + skin_name);
  218. if(!p->second.is_updated()) {
  219. d->skins.erase(p);
  220. skin new_skin = skin(skin_name,d->search_path,true);
  221. new_skin.copy_mapping(d->skins[skin_name]);
  222. d->skins[skin_name] = new_skin;
  223. }
  224. }
  225. }
  226. }
  227. else { // No need to reload
  228. data::skins_type::const_iterator p=d->skins.find(skin_name);
  229. if(p==d->skins.end())
  230. throw cppcms_error("There is no such skin:" + skin_name);
  231. p->second.render(template_name,out,content);
  232. }
  233. }
  234. views_pool::~views_pool()
  235. {
  236. }
  237. void views_pool::add_view(std::string name,mapping_type const &mapping)
  238. {
  239. data::skins_type::iterator p=d->skins.find(name);
  240. if(p!=d->skins.end())
  241. throw cppcms_error("Skin " + name + "can't be loaded twice");
  242. d->skins[name]=skin(name,mapping);
  243. }
  244. void views_pool::remove_view(std::string name)
  245. {
  246. d->skins.erase(name);
  247. }
  248. namespace { // Make sure that static views pool is loaded
  249. struct loader {
  250. loader()
  251. {
  252. views_pool::static_instance();
  253. }
  254. };
  255. } // anon
  256. views_pool &views_pool::static_instance()
  257. {
  258. static views_pool pool;
  259. return pool;
  260. }
  261. } // cppcms