/** @file * @author Edouard DUPIN * @copyright 2014, Edouard DUPIN, all right reserved * @license MPL v2.0 (see license file) */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static ethread::Mutex g_mutex; static etk::Uri g_basePath; static etk::String g_baseDBName = etk::String(SERVICE_NAME) + "-database.json"; class FileProperty { public: uint64_t m_id; //!< use local reference ID to have faster access on the file ... etk::String m_fileName; // Sha 512 etk::String m_name; etk::String m_mineType; echrono::Time m_creationData; etk::Map m_metadata; }; static etk::Vector m_listFile; class Album { public: uint32_t m_id; //!< use local reference ID to have faster access on the file ... uint32_t m_parentId; //!< parent Album ID etk::String m_name; //!< name of the Album etk::String m_description; //!< description of the album etk::Vector m_listMedia; //!< List of media in this album }; static etk::Vector m_listAlbum; static uint64_t m_lastMaxId = 0; static bool g_needToStore = false; static uint64_t createUniqueID() { m_lastMaxId++; return m_lastMaxId; } namespace appl { class PictureService : public zeus::service::Picture { private: //ememory::SharedPtr& m_client; zeus::ProxyClientProperty m_client; etk::String m_userName; public: /* PictureService(ememory::SharedPtr& _client, const etk::String& _userName) : m_client(_client), m_userName(_userName) { APPL_WARNING("New PictureService ... for user: "); } */ PictureService(uint16_t _clientId) { APPL_VERBOSE("New PictureService ... for user: " << _clientId); } ~PictureService() { APPL_VERBOSE("delete PictureService ..."); } public: uint32_t mediaIdCount() override { ethread::UniqueLock lock(g_mutex); // TODO : Check right ... return m_listFile.size(); } etk::Vector mediaIdGetRange(uint32_t _start, uint32_t _stop) override { ethread::UniqueLock lock(g_mutex); // TODO : Check right ... etk::Vector out; for (size_t iii=_start; iii mediaGet(uint32_t _mediaId) override { ethread::UniqueLock lock(g_mutex); // TODO : Check right ... //Check if the file exist: bool find = false; FileProperty property; for (auto &it : m_listFile) { if (it.m_id == _mediaId) { find = true; property = it; break; } } if (find == false) { throw etk::exception::InvalidArgument("Wrong file name ..."); } etk::Uri tmpp = g_basePath; tmpp.setPath(g_basePath.getPath() / property.m_fileName + "." + zeus::getExtention(property.m_mineType)); return zeus::File::create(tmpp.getString(), property.m_mineType); } uint32_t mediaAdd(zeus::ProxyFile _dataFile) override { ethread::UniqueLock lock(g_mutex); // TODO : Check right ... uint64_t id = createUniqueID(); auto futType = _dataFile.getMineType(); auto futName = _dataFile.getName(); etk::Uri tmpFileName = g_basePath; tmpFileName.setPath(g_basePath.getPath() / "tmpImport_" + etk::toString(id)); etk::String sha512String = zeus::storeInFile(_dataFile, tmpFileName.getString()); futType.wait(); futName.wait(); // TODO : Get internal data of the file and remove all the meta-data ==> proper files ... for (auto &it : m_listFile) { if (it.m_fileName == sha512String) { APPL_INFO("File already registered at " << it.m_creationData); // TODO : Check if data is identical ... // remove temporary file etk::uri::remove(tmpFileName); return it.m_id; } } // move the file at the good position: APPL_DEBUG("move temporay file in : " << g_basePath << sha512String); if (etk::uri::fileSize(tmpFileName) == 0) { APPL_ERROR("try to store an empty file"); throw etk::exception::RuntimeError("file size == 0"); } etk::Uri tmpFileNameDest = g_basePath; tmpFileNameDest.setPath(g_basePath.getPath() / sha512String + "." + zeus::getExtention(futType.get())); etk::uri::move(tmpFileName, tmpFileNameDest); FileProperty property; property.m_id = id; property.m_fileName = sha512String; property.m_name = futName.get(); property.m_mineType = futType.get(); property.m_creationData = echrono::Time::now(); m_listFile.pushBack(property); g_needToStore = true; APPL_DEBUG(" filename : " << sha512String); return id; } void mediaRemove(uint32_t _mediaId) override { ethread::UniqueLock lock(g_mutex); // TODO : Check right ... //Check if the file exist: bool find = false; FileProperty property; for (auto it = m_listFile.begin(); it != m_listFile.end(); /* No increment */) { if (it->m_id == _mediaId) { it = m_listFile.erase(it); find = true; property = *it; } else { ++it; } } if (find == false) { throw etk::exception::InvalidArgument("Wrong file name ..."); } // Remove media in all Album ... for (auto &it : m_listAlbum) { for (auto elem = it.m_listMedia.begin(); elem != it.m_listMedia.end(); /* No increment */) { if (*elem == _mediaId) { elem = it.m_listMedia.erase(elem); } else { ++elem; } } } // Real Remove definitly the file // TODO : Set it in a trash ... For a while ... etk::Uri tmpFileName = g_basePath; tmpFileName.setPath(g_basePath.getPath() / property.m_fileName + "." + zeus::getExtention(property.m_mineType)); if (etk::uri::remove(tmpFileName) == false) { throw etk::exception::RuntimeError("Can not remove file ..."); } } etk::Vector mediaMetadataGetKeys(uint32_t _mediaId) override { etk::Vector out; for (auto &it : m_listFile) { if (it.m_id == _mediaId) { for (auto &itM : it.m_metadata) { out.pushBack(itM.first); } return out; } } throw etk::exception::InvalidArgument("Wrong Album ID ..."); } etk::String mediaMetadataGetKey(uint32_t _mediaId, etk::String _key) override { etk::Vector out; for (auto &it : m_listFile) { if (it.m_id == _mediaId) { auto itM = it.m_metadata.find(_key); if (itM != it.m_metadata.end()) { return itM->second; } return ""; } } throw etk::exception::InvalidArgument("Wrong Album ID ..."); } void mediaMetadataSetKey(uint32_t _mediaId, etk::String _key, etk::String _value) override { for (auto &it : m_listFile) { if (it.m_id == _mediaId) { it.m_metadata.set(_key, _value); return; } } throw etk::exception::InvalidArgument("Wrong Album ID ..."); } uint32_t albumCreate(etk::String _albumName) override { ethread::UniqueLock lock(g_mutex); // TODO : Check right ... for (auto &it : m_listAlbum) { if (it.m_name == _albumName) { return it.m_id; } } Album album; album.m_id = createUniqueID(); album.m_name = _albumName; m_listAlbum.pushBack(album); return album.m_id; } void albumRemove(uint32_t _albumId) override { ethread::UniqueLock lock(g_mutex); // TODO : Check right ... for (auto it = m_listAlbum.begin(); it != m_listAlbum.end(); /* No increment */) { if (it->m_id == _albumId) { it = m_listAlbum.erase(it); return; } ++it; } throw etk::exception::InvalidArgument("Wrong Album ID ..."); } etk::Vector albumGetList() override { ethread::UniqueLock lock(g_mutex); etk::Vector out; for (auto &it : m_listAlbum) { out.pushBack(it.m_id); } return out; } etk::String albumNameGet(uint32_t _albumId) override { ethread::UniqueLock lock(g_mutex); for (auto &it : m_listAlbum) { if (it.m_id == _albumId) { return it.m_name; } } throw etk::exception::InvalidArgument("Wrong Album ID ..."); return ""; } void albumNameSet(uint32_t _albumId, etk::String _albumName) override { ethread::UniqueLock lock(g_mutex); for (auto &it : m_listAlbum) { if (it.m_id == _albumId) { it.m_name = _albumName; return; } } throw etk::exception::InvalidArgument("Wrong Album ID ..."); } etk::String albumDescriptionGet(uint32_t _albumId) override { ethread::UniqueLock lock(g_mutex); for (auto &it : m_listAlbum) { if (it.m_id == _albumId) { return it.m_description; } } throw etk::exception::InvalidArgument("Wrong Album ID ..."); return ""; } void albumDescriptionSet(uint32_t _albumId, etk::String _desc) override { ethread::UniqueLock lock(g_mutex); for (auto &it : m_listAlbum) { if (it.m_id == _albumId) { it.m_description = _desc; return; } } throw etk::exception::InvalidArgument("Wrong Album ID ..."); } void albumMediaAdd(uint32_t _albumId, uint32_t _mediaId) override { ethread::UniqueLock lock(g_mutex); for (auto &it : m_listAlbum) { if (it.m_id == _albumId) { for (auto &elem : it.m_listMedia) { if (elem == _mediaId) { // already intalles return; } } it.m_listMedia.pushBack(_mediaId); return; } } throw etk::exception::InvalidArgument("Wrong Album ID ..."); } void albumMediaRemove(uint32_t _albumId, uint32_t _mediaId) override { ethread::UniqueLock lock(g_mutex); for (auto &it : m_listAlbum) { if (it.m_id == _albumId) { for (auto elem = it.m_listMedia.begin(); elem != it.m_listMedia.end(); /* No increment */) { if (*elem == _mediaId) { elem = it.m_listMedia.erase(elem); return; } ++elem; } // Media not find ... ==> not a problem ... return; } } throw etk::exception::InvalidArgument("Wrong Album ID ..."); } uint32_t albumMediaCount(uint32_t _albumId) override { ethread::UniqueLock lock(g_mutex); for (auto &it : m_listAlbum) { if (it.m_id == _albumId) { return it.m_listMedia.size(); } } throw etk::exception::InvalidArgument("Wrong Album ID ..."); return 0; } etk::Vector albumMediaIdGet(uint32_t _albumId, uint32_t _start, uint32_t _stop) override { ethread::UniqueLock lock(g_mutex); for (auto &it : m_listAlbum) { if (it.m_id == _albumId) { etk::Vector out; for (size_t iii=_start; iii LOAD error"); } ejson::Array listFilesArray = database["list-files"].toArray(); for (const auto itArray: listFilesArray) { ejson::Object fileElement = itArray.toObject(); FileProperty property; property.m_id = fileElement["id"].toNumber().getU64(); APPL_INFO("get ID : " << property.m_id); property.m_fileName = fileElement["file-name"].toString().get(); property.m_name = fileElement["name"].toString().get(); property.m_mineType = fileElement["mine-type"].toString().get(); property.m_creationData = echrono::Time(fileElement["add-date"].toNumber().getU64()*1000); if (m_lastMaxId < property.m_id) { m_lastMaxId = property.m_id+1; } ejson::Object tmpObj = fileElement["meta"].toObject(); if (tmpObj.exist() == true) { for (auto itValue = tmpObj.begin(); itValue != tmpObj.end(); ++itValue) { property.m_metadata.set(itValue.getKey(), (*itValue).toString().get()); } } if (property.m_fileName == "") { APPL_ERROR("Can not access on the file : ... No name "); } else { m_listFile.pushBack(property); } } ejson::Array listAlbumArray = database["list-album"].toArray(); for (const auto itArray: listAlbumArray) { ejson::Object albumElement = itArray.toObject(); Album album; album.m_id = albumElement["id"].toNumber().getU64(); album.m_parentId = albumElement["parent"].toNumber().getU64(); album.m_name = albumElement["name"].toString().get(); album.m_description = albumElement["desc"].toString().get(); ejson::Array listMadiaArray = albumElement["media"].toArray(); for (const auto itArrayMedia: listMadiaArray) { uint64_t tmp = itArrayMedia.toNumber().getU64(); album.m_listMedia.pushBack(tmp); } m_listAlbum.pushBack(album); } g_needToStore = false; } ETK_EXPORT_API bool SERVICE_IO_init(int _argc, const char *_argv[], etk::Uri _basePath) { g_basePath = _basePath; ethread::UniqueLock lock(g_mutex); APPL_WARNING("Load USER: " << g_basePath); load_db(); APPL_WARNING("new USER: [STOP]"); return true; } ETK_EXPORT_API bool SERVICE_IO_uninit() { ethread::UniqueLock lock(g_mutex); store_db(); APPL_WARNING("delete USER [STOP]"); return true; } ETK_EXPORT_API void SERVICE_IO_peridic_call() { if (g_needToStore == false) { return; } // try lock mutex: if (g_mutex.tryLock() == false) { return; } store_db(); g_mutex.unLock(); } ZEUS_SERVICE_PICTURE_DECLARE(appl::PictureService);