/src/lib/ContentDatabase/ContentDatabase.cpp

https://github.com/u-voelkel/fuppes · C++ · 405 lines · 302 code · 87 blank · 16 comment · 54 complexity · 4b5eb2abb3fdc0eb52474d5a3aacd162 MD5 · raw file

  1. /*
  2. * This file is part of fuppes
  3. *
  4. * (c) 2013 Ulrich Völkel <u-voelkel@users.sourceforge.net>
  5. *
  6. * For the full copyright and license information, please view the COPYING
  7. * file that was distributed with this source code.
  8. */
  9. #include "ContentDatabase.h"
  10. #include "../Database/ObjectManager.h"
  11. #include "../Database/TableManager.h"
  12. #include "../Database/QueryBuilder.h"
  13. #include "../Log/Log.h"
  14. object_id_t ContentDatabase::ContentDatabase::m_objectId = 0;
  15. uint32_t ContentDatabase::ContentDatabase::m_systemUpdateId = 0;
  16. object_id_t ContentDatabase::ContentDatabase::getObjectId() // static
  17. {
  18. return ++ContentDatabase::m_objectId;
  19. }
  20. uint32_t ContentDatabase::ContentDatabase::getSystemUpdateId() // static
  21. {
  22. return ContentDatabase::m_systemUpdateId;
  23. }
  24. ContentDatabase::ContentDatabase::ContentDatabase(Configuration& configuration, CFileDetails& fileDetails, Plugin::Manager& pluginManager, VirtualContainer::Manager& virtualContainerMgr) :
  25. m_configuration(configuration),
  26. m_fileDetails(fileDetails),
  27. m_virtualContainerMgr(virtualContainerMgr),
  28. m_scanDirectoryThread(*this),
  29. m_updateThread(*this, configuration, fileDetails, pluginManager, virtualContainerMgr),
  30. m_removeMissingThread(*this)
  31. {
  32. m_fam = NULL;
  33. m_status = Idle;
  34. }
  35. ContentDatabase::ContentDatabase::~ContentDatabase()
  36. {
  37. m_updateThread.stop();
  38. m_scanDirectoryThread.stop();
  39. m_removeMissingThread.stop();
  40. m_updateThread.close();
  41. m_scanDirectoryThread.close();
  42. m_removeMissingThread.close();
  43. if (NULL != m_fam) {
  44. m_fam->stop();
  45. m_fam->close();
  46. delete m_fam;
  47. }
  48. }
  49. void ContentDatabase::ContentDatabase::init()
  50. {
  51. if (m_configuration.isReadonly()) {
  52. return;
  53. }
  54. Database::ObjectManager objMgr;
  55. objMgr.getMaxObjectId(ContentDatabase::m_objectId);
  56. // setup file alteration monitoring
  57. m_fam = Fam::Monitor::createMonitor(*this, false);
  58. Database::QueryResult result;
  59. objMgr.getAllContainerPaths(result);
  60. for (size_t i = 0; i < result.size(); i++) {
  61. m_fam->addWatch(result.getRow(i)->getColumnString("PATH"), true);
  62. }
  63. m_fam->start();
  64. }
  65. void ContentDatabase::ContentDatabase::insertDirectory(const std::string path, const std::string name, const object_id_t parentId, Database::ObjectManager& objMgr)
  66. {
  67. Database::Item dir;
  68. objMgr.findOneByFilename(path, "", dir, false);
  69. if (0 != dir.id) {
  70. return;
  71. }
  72. dir.objectId = ContentDatabase::getObjectId();
  73. dir.parentId = parentId;
  74. dir.type = CONTAINER_STORAGEFOLDER;
  75. dir.path = path;
  76. dir.title = ToUTF8(name, m_configuration.getLocalCharset());
  77. dir.modified = fuppes::DateTime::now().toInt();
  78. dir.updated = 0;
  79. objMgr.persist(dir);
  80. m_fam->addWatch(path);
  81. }
  82. void ContentDatabase::ContentDatabase::insertFile(const std::string path, const std::string name, const object_id_t parentId, Database::ObjectManager& objMgr)
  83. {
  84. Database::Item file;
  85. objMgr.findOneByFilename(path, name, file, false);
  86. if (0 != file.id) {
  87. return;
  88. }
  89. std::string filename = path + name;
  90. file.type = m_fileDetails.GetObjectType(filename);
  91. if (OBJECT_TYPE_UNKNOWN == file.type) {
  92. return;
  93. }
  94. file.visible = !m_fileDetails.isAlbumArtFile(filename);
  95. file.objectId = ContentDatabase::getObjectId();
  96. file.parentId = parentId;
  97. file.title = fuppes::FormatHelper::fileNameToTitle(name, m_configuration.getLocalCharset());
  98. file.path = path;
  99. file.filename = name;
  100. file.extension = ExtractFileExt(name);
  101. file.size = fuppes::File::getSize(filename);
  102. file.modified = fuppes::File::lastModified(filename);
  103. if (0 == file.modified) {
  104. file.modified = fuppes::DateTime::now().toInt();
  105. }
  106. file.updated = 0;
  107. objMgr.persist(file);
  108. }
  109. void ContentDatabase::ContentDatabase::onScanDirectoryThreadFinished(const bool stopped)
  110. {
  111. if (!stopped) {
  112. m_updateThread.stop();
  113. m_updateThread.close();
  114. m_status = UpdateMetadata;
  115. m_updateThread.start();
  116. }
  117. else {
  118. m_status = Stopped;
  119. }
  120. }
  121. void ContentDatabase::ContentDatabase::onUpdateThreadFinished(const bool stopped)
  122. {
  123. m_status = stopped ? Stopped : Idle;
  124. }
  125. void ContentDatabase::ContentDatabase::onRemoveMissingThreadFinished(const bool stopped)
  126. {
  127. if(!stopped) {
  128. m_scanDirectoryThread.stop();
  129. m_scanDirectoryThread.close();
  130. m_status = ScanDirectories;
  131. m_scanDirectoryThread.start(m_fam);
  132. }
  133. else {
  134. m_status = Stopped;
  135. }
  136. }
  137. void ContentDatabase::ContentDatabase::rebuild()
  138. {
  139. logExt("contentdb") << "rebuild database";
  140. Database::TableManager tblMgr;
  141. tblMgr.empty();
  142. m_virtualContainerMgr.setConnection(Database::Connection::getDefaultConnection());
  143. m_virtualContainerMgr.rebuildContainerLayouts(false);
  144. update();
  145. }
  146. void ContentDatabase::ContentDatabase::update()
  147. {
  148. logExt("contentdb") << "update database";
  149. m_scanDirectoryThread.stop();
  150. m_updateThread.stop();
  151. m_scanDirectoryThread.close();
  152. m_updateThread.close();
  153. // insert shared directories
  154. Database::ObjectManager objMgr;
  155. Database::Item dir;
  156. SharedObjects_t sharedObjects = m_configuration.getSharedObjects();
  157. for (size_t i = 0; i < sharedObjects.size(); i++) {
  158. if (SharedObject::directory != sharedObjects.at(i).type) {
  159. continue;
  160. }
  161. dir.clear();
  162. objMgr.findOneByFilename(sharedObjects.at(i).path, "", dir, false);
  163. if (0 != dir.id) {
  164. continue;
  165. }
  166. std::string title;
  167. ExtractFolderFromPath(sharedObjects.at(i).path, &title);
  168. dir.objectId = ContentDatabase::getObjectId();
  169. dir.parentId = 0;
  170. dir.type = CONTAINER_STORAGEFOLDER;
  171. dir.path = sharedObjects.at(i).path;
  172. dir.title = ToUTF8(title, m_configuration.getLocalCharset());
  173. dir.modified = fuppes::DateTime::now().toInt();
  174. dir.updated = 0;
  175. objMgr.persist(dir);
  176. m_fam->addWatch(dir.path);
  177. logDbg("contentdb") << "inserted directory" << dir.path;
  178. }
  179. m_status = RemoveMissing;
  180. m_removeMissingThread.stop();
  181. m_removeMissingThread.close();
  182. m_removeMissingThread.start();
  183. }
  184. void ContentDatabase::ContentDatabase::onDirectoryCreateEvent(const std::string path, const std::string name)
  185. {
  186. Database::ObjectManager objMgr;
  187. Database::Item parent;
  188. objMgr.findOneByFilename(path, "", parent, false);
  189. if (0 == parent.id) {
  190. return;
  191. }
  192. // if the parent is already marked as modified we can ignore this event
  193. if (parent.updated < parent.modified) {
  194. return;
  195. }
  196. insertDirectory(path + name + "/", name, parent.objectId, objMgr);
  197. if (!m_scanDirectoryThread.running()) {
  198. m_scanDirectoryThread.close();
  199. m_scanDirectoryThread.start();
  200. }
  201. }
  202. void ContentDatabase::ContentDatabase::onDirectoryDeleteEvent(const std::string path)
  203. {
  204. m_scanDirectoryThread.stop();
  205. m_updateThread.stop();
  206. Database::ObjectManager objMgr;
  207. Database::Item dir;
  208. objMgr.findOneByFilename(path, "", dir, false);
  209. if (0 == dir.id) {
  210. return;
  211. }
  212. m_fam->removeWatch(dir.path);
  213. objMgr.remove(dir);
  214. }
  215. void ContentDatabase::ContentDatabase::onDirectoryMoveEvent(const std::string oldpath, const std::string oldname, const std::string path, const std::string name)
  216. {
  217. Database::ObjectManager objMgr;
  218. Database::Item dir;
  219. objMgr.findOneByFilename(oldpath + oldname + "/", "", dir, false);
  220. if (0 == dir.id) {
  221. return;
  222. }
  223. // moved
  224. Database::Item parent;
  225. if (0 != oldpath.compare(path)) {
  226. objMgr.findOneByFilename(path, "", parent, false);
  227. if (0 == parent.id) {
  228. return;
  229. }
  230. dir.parentId = parent.objectId;
  231. }
  232. // renamed
  233. if (0 != oldname.compare(name)) {
  234. dir.title = ToUTF8(name, m_configuration.getLocalCharset());
  235. }
  236. dir.path = path + name + "/";
  237. objMgr.persist(dir);
  238. m_fam->removeWatch(oldpath + oldname + "/");
  239. m_fam->addWatch(dir.path);
  240. }
  241. void ContentDatabase::ContentDatabase::onFileCreateEvent(const std::string path, const std::string name)
  242. {
  243. Database::ObjectManager objMgr;
  244. Database::Item dir;
  245. objMgr.findOneByFilename(path, "", dir, false);
  246. if (0 == dir.id) {
  247. return;
  248. }
  249. insertFile(path, name, dir.objectId, objMgr);
  250. if (!m_updateThread.running()) {
  251. m_updateThread.close();
  252. m_updateThread.start();
  253. }
  254. }
  255. void ContentDatabase::ContentDatabase::onFileDeleteEvent(const std::string path, const std::string name)
  256. {
  257. Database::ObjectManager objMgr;
  258. Database::Item file;
  259. objMgr.findOneByFilename(path, name, file, false);
  260. if (0 == file.id) {
  261. return;
  262. }
  263. objMgr.remove(file);
  264. }
  265. void ContentDatabase::ContentDatabase::onFileMoveEvent(const std::string oldpath, const std::string oldname, const std::string path, const std::string name)
  266. {
  267. Database::ObjectManager objMgr;
  268. Database::Item file;
  269. objMgr.findOneByFilename(oldpath, oldname, file, false);
  270. if (0 == file.id) {
  271. return;
  272. }
  273. // moved
  274. Database::Item parent;
  275. if (0 != oldpath.compare(path)) {
  276. objMgr.findOneByFilename(path, "", parent, false);
  277. if (0 == parent.id) {
  278. return;
  279. }
  280. file.parentId = parent.objectId;
  281. }
  282. // renamed
  283. if (0 != oldname.compare(name)) {
  284. file.filename = name;
  285. file.extension = ExtractFileExt(name);
  286. // check if the old title was created from the filename
  287. std::string oldtitle;
  288. ExtractFolderFromPath(oldpath, &oldtitle);
  289. oldtitle = ToUTF8(oldtitle, m_configuration.getLocalCharset());
  290. if (0 == file.title.compare(oldtitle)) {
  291. std::string title;
  292. ExtractFolderFromPath(path, &title);
  293. file.title = ToUTF8(title, m_configuration.getLocalCharset());
  294. }
  295. }
  296. file.path = path;
  297. objMgr.persist(file);
  298. }
  299. void ContentDatabase::ContentDatabase::onFileModifiedEvent(const std::string path, const std::string name)
  300. {
  301. Database::ObjectManager objMgr;
  302. Database::Item file;
  303. objMgr.findOneByFilename(path, name, file, false);
  304. if (0 == file.id) {
  305. return;
  306. }
  307. time_t lastModified = fuppes::File::lastModified(path + name);
  308. if (lastModified <= file.modified) {
  309. return;
  310. }
  311. file.size = fuppes::File::getSize(path + name);
  312. file.modified = lastModified;
  313. objMgr.persist(file);
  314. if (!m_updateThread.running()) {
  315. m_updateThread.close();
  316. m_updateThread.start();
  317. }
  318. }