1 /*MT* 2 3 MediaTomb - http://www.mediatomb.cc/ 4 5 database.h - this file is part of MediaTomb. 6 7 Copyright (C) 2005 Gena Batyan <bgeradz@mediatomb.cc>, 8 Sergey 'Jin' Bostandzhyan <jin@mediatomb.cc> 9 10 Copyright (C) 2006-2010 Gena Batyan <bgeradz@mediatomb.cc>, 11 Sergey 'Jin' Bostandzhyan <jin@mediatomb.cc>, 12 Leonhard Wimmer <leo@mediatomb.cc> 13 14 MediaTomb is free software; you can redistribute it and/or modify 15 it under the terms of the GNU General Public License version 2 16 as published by the Free Software Foundation. 17 18 MediaTomb is distributed in the hope that it will be useful, 19 but WITHOUT ANY WARRANTY; without even the implied warranty of 20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 GNU General Public License for more details. 22 23 You should have received a copy of the GNU General Public License 24 version 2 along with MediaTomb; if not, write to the Free Software 25 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 26 27 $Id$ 28 */ 29 30 /// \file database.h 31 32 #ifndef __STORAGE_H__ 33 #define __STORAGE_H__ 34 35 #include <deque> 36 #include <filesystem> 37 #include <map> 38 #include <memory> 39 #include <string> 40 #include <unordered_set> 41 #include <vector> 42 namespace fs = std::filesystem; 43 44 // forward declaration 45 class AutoscanDirectory; 46 class AutoscanList; 47 class CdsObject; 48 class Config; 49 class ConfigValue; 50 class Mime; 51 enum class ScanMode; 52 class Timer; 53 54 #define BROWSE_DIRECT_CHILDREN 0x00000001 55 #define BROWSE_ITEMS 0x00000002 56 #define BROWSE_CONTAINERS 0x00000004 57 #define BROWSE_EXACT_CHILDCOUNT 0x00000008 58 #define BROWSE_TRACK_SORT 0x00000010 59 #define BROWSE_HIDE_FS_ROOT 0x00000020 60 61 class BrowseParam { 62 protected: 63 unsigned int flags; 64 std::shared_ptr<CdsObject> object; 65 66 int startingIndex {}; 67 int requestedCount {}; 68 std::string sortCrit; 69 70 // output parameters 71 int totalMatches {}; 72 73 public: BrowseParam(std::shared_ptr<CdsObject> object,unsigned int flags)74 BrowseParam(std::shared_ptr<CdsObject> object, unsigned int flags) 75 : flags(flags) 76 , object(std::move(object)) 77 { 78 } 79 getFlags()80 unsigned int getFlags() const { return flags; } getFlag(unsigned int mask)81 unsigned int getFlag(unsigned int mask) const { return flags & mask; } setFlags(unsigned int flags)82 void setFlags(unsigned int flags) { this->flags = flags; } setFlag(unsigned int mask)83 void setFlag(unsigned int mask) { flags |= mask; } changeFlag(unsigned int mask,bool value)84 void changeFlag(unsigned int mask, bool value) 85 { 86 if (value) 87 setFlag(mask); 88 else 89 clearFlag(mask); 90 } clearFlag(unsigned int mask)91 void clearFlag(unsigned int mask) { flags &= !mask; } 92 getObject()93 std::shared_ptr<CdsObject> getObject() const { return object; } 94 setRange(int startingIndex,int requestedCount)95 void setRange(int startingIndex, int requestedCount) 96 { 97 this->startingIndex = startingIndex; 98 this->requestedCount = requestedCount; 99 } setStartingIndex(int startingIndex)100 void setStartingIndex(int startingIndex) 101 { 102 this->startingIndex = startingIndex; 103 } 104 setRequestedCount(int requestedCount)105 void setRequestedCount(int requestedCount) 106 { 107 this->requestedCount = requestedCount; 108 } 109 setSortCriteria(const std::string & sortCrit)110 void setSortCriteria(const std::string& sortCrit) 111 { 112 this->sortCrit = sortCrit; 113 } 114 getStartingIndex()115 int getStartingIndex() const { return startingIndex; } getRequestedCount()116 int getRequestedCount() const { return requestedCount; } getTotalMatches()117 int getTotalMatches() const { return totalMatches; } getSortCriteria()118 const std::string& getSortCriteria() const { return sortCrit; } 119 setTotalMatches(int totalMatches)120 void setTotalMatches(int totalMatches) 121 { 122 this->totalMatches = totalMatches; 123 } 124 }; 125 126 class SearchParam { 127 protected: 128 std::string containerID; 129 std::string searchCrit; 130 std::string sortCrit; 131 int startingIndex; 132 int requestedCount; 133 bool searchableContainers; 134 135 public: SearchParam(std::string containerID,std::string searchCriteria,std::string sortCriteria,int startingIndex,int requestedCount,bool searchableContainers)136 SearchParam(std::string containerID, std::string searchCriteria, std::string sortCriteria, int startingIndex, 137 int requestedCount, bool searchableContainers) 138 : containerID(std::move(containerID)) 139 , searchCrit(std::move(searchCriteria)) 140 , sortCrit(std::move(sortCriteria)) 141 , startingIndex(startingIndex) 142 , requestedCount(requestedCount) 143 , searchableContainers(searchableContainers) 144 { 145 } getContainerId()146 const std::string& getContainerId() const { return containerID; } searchCriteria()147 const std::string& searchCriteria() const { return searchCrit; } getSearchableContainers()148 bool getSearchableContainers() const { return searchableContainers; } getStartingIndex()149 int getStartingIndex() const { return startingIndex; } getRequestedCount()150 int getRequestedCount() const { return requestedCount; } getSortCriteria()151 const std::string& getSortCriteria() const { return sortCrit; } 152 }; 153 154 class Database { 155 public: Database(std::shared_ptr<Config> config)156 explicit Database(std::shared_ptr<Config> config) 157 : config(std::move(config)) 158 { 159 } 160 virtual ~Database() = default; 161 virtual void init() = 0; 162 163 /// \brief shutdown the Database with its possible threads 164 virtual void shutdown() = 0; 165 166 virtual void addObject(const std::shared_ptr<CdsObject>& object, int* changedContainer) = 0; 167 168 /// \brief Adds a virtual container chain specified by path. 169 /// \param path container path separated by '/'. Slashes in container 170 /// titles must be escaped. 171 /// \param lastClass upnp:class of the last container in the chain, it 172 /// is only set when the container is created for the first time. 173 /// \param lastRefID reference id of the last container in the chain, 174 /// INVALID_OBJECT_ID indicates that the id will not be set. 175 /// \param containerID will be filled in by the function 176 /// \param updateID will be filled in by the function only if it is set to INVALID_OBJECT_ID 177 /// and it is necessary to update a container. Otherwise it will be left unchanged. 178 /// 179 /// The function gets a path (i.e. "/Audio/All Music/") and will create 180 /// the container path if needed. The container ID will be filled in with 181 /// the object ID of the container that is last in the path. The 182 /// updateID will hold the objectID of the container that was changed, 183 /// in case new containers were created during the operation. 184 virtual void addContainerChain(std::string path, const std::string& lastClass, int flags, int lastRefID, int* containerID, 185 std::deque<int>& updateID, const std::vector<std::pair<std::string, std::string>>& lastMetadata) 186 = 0; 187 188 /// \brief Builds the container path. Fetches the path of the 189 /// parent and adds the title 190 /// \param parentID the parent id of the parent container 191 /// \param title the title of the container to add to the path. 192 /// It will be escaped. 193 virtual fs::path buildContainerPath(int parentID, const std::string& title) = 0; 194 195 virtual void updateObject(const std::shared_ptr<CdsObject>& object, int* changedContainer) = 0; 196 197 virtual std::vector<std::shared_ptr<CdsObject>> browse(BrowseParam& param) = 0; 198 virtual std::vector<std::shared_ptr<CdsObject>> search(const SearchParam& param, int* numMatches) = 0; 199 200 virtual std::vector<std::string> getMimeTypes() = 0; 201 202 //virtual std::vector<std::shared_ptr<CdsObject>> selectObjects(const std::unique_ptr<SelectParam>& param) = 0; 203 204 /// \brief Loads a given (pc directory) object, identified by the given path 205 /// from the database 206 /// \param path the path of the object; object is interpreted as directory 207 /// \param wasRegularFile was a regular file before file was moved, now fs::is_regular_file returns false (used for inotify events) 208 /// \return the CdsObject 209 virtual std::shared_ptr<CdsObject> findObjectByPath(const fs::path& path, bool wasRegularFile = false) = 0; 210 211 /// \brief checks for a given (pc directory) object, identified by the given path 212 /// from the database 213 /// \param path the path of the object; object is interpreted as directory 214 /// \param wasRegularFile was a regular file before file was moved, now fs::is_regular_file returns false (used for inotify events) 215 /// \return the obejectID 216 virtual int findObjectIDByPath(const fs::path& fullpath, bool wasRegularFile = false) = 0; 217 218 /// \brief increments the updateIDs for the given objectIDs 219 /// \param ids pointer to the array of ids 220 /// \param size number of entries in the given array 221 /// \return a String for UPnP: a CSV list; for every existing object: 222 /// "id,update_id" 223 virtual std::string incrementUpdateIDs(const std::unordered_set<int>& ids) = 0; 224 225 /* utility methods */ 226 virtual std::shared_ptr<CdsObject> loadObject(int objectID) = 0; 227 virtual int getChildCount(int contId, bool containers = true, bool items = true, bool hideFsRoot = false) = 0; 228 229 class ChangedContainers { 230 public: 231 // Signed because IDs start at -1. 232 std::vector<std::int32_t> upnp; 233 std::vector<std::int32_t> ui; 234 }; 235 236 /// \brief Removes the object identified by the objectID from the database. 237 /// all references will be automatically removed. If the object is 238 /// a container, all children will be also removed automatically. If 239 /// the object is a reference to another object, the "all" flag 240 /// determines, if the main object will be removed too. 241 /// \param objectID the object id of the object to remove 242 /// \param all if true and the object to be removed is a reference 243 /// \param objectType pointer to an int; will be filled with the objectType of 244 /// the removed object, if not NULL 245 /// \return changed container ids 246 virtual std::unique_ptr<ChangedContainers> removeObject(int objectID, bool all) = 0; 247 248 /// \brief Get all objects under the given parentID. 249 /// \param parentID parent container 250 /// \param withoutContainer if false: all children are returned; if true: only items are returned 251 /// \return DBHash containing the objectID's - nullptr if there are none! 252 virtual std::unordered_set<int> getObjects(int parentID, bool withoutContainer) = 0; 253 254 /// \brief Remove all objects found in list 255 /// \param list a DBHash containing objectIDs that have to be removed 256 /// \param all if true and the object to be removed is a reference 257 /// \return changed container ids 258 virtual std::unique_ptr<ChangedContainers> removeObjects(const std::unordered_set<int>& list, bool all = false) = 0; 259 260 /// \brief Loads an object given by the online service ID. 261 virtual std::shared_ptr<CdsObject> loadObjectByServiceID(const std::string& serviceID) = 0; 262 263 /// \brief Return an array of object ID's for a particular service. 264 /// 265 /// In the database, the service is identified by a service id prefix. 266 virtual std::vector<int> getServiceObjectIDs(char servicePrefix) = 0; 267 268 /* accounting methods */ 269 virtual int getTotalFiles(bool isVirtual = false, const std::string& mimeType = "", const std::string& upnpClass = "") = 0; 270 271 /* internal setting methods */ 272 virtual std::string getInternalSetting(const std::string& key) = 0; 273 virtual void storeInternalSetting(const std::string& key, const std::string& value) = 0; 274 275 /* autoscan methods */ 276 virtual std::shared_ptr<AutoscanList> getAutoscanList(ScanMode scanode) = 0; 277 virtual void updateAutoscanList(ScanMode scanmode, std::shared_ptr<AutoscanList> list) = 0; 278 279 /* config methods */ 280 virtual std::vector<ConfigValue> getConfigValues() = 0; 281 virtual void removeConfigValue(const std::string& item) = 0; 282 virtual void updateConfigValue(const std::string& key, const std::string& item, const std::string& value, const std::string& status = "unchanged") = 0; 283 284 /// \brief returns the AutoscanDirectory for the given objectID or nullptr if 285 /// it's not an autoscan start point - scan id will be invalid 286 /// \param objectID the object id to get the AutoscanDirectory for 287 /// \return nullptr if the given id is no autoscan start point, 288 /// or the matching AutoscanDirectory 289 virtual std::shared_ptr<AutoscanDirectory> getAutoscanDirectory(int objectID) = 0; 290 virtual void addAutoscanDirectory(std::shared_ptr<AutoscanDirectory> adir) = 0; 291 virtual void updateAutoscanDirectory(std::shared_ptr<AutoscanDirectory> adir) = 0; 292 virtual void removeAutoscanDirectory(std::shared_ptr<AutoscanDirectory> adir) = 0; 293 virtual void checkOverlappingAutoscans(const std::shared_ptr<AutoscanDirectory>& adir) = 0; 294 295 virtual std::vector<int> getPathIDs(int objectID) = 0; 296 297 /// \brief Ensures that a container given by it's location on disk is 298 /// present in the database. If it does not exist it will be created, but 299 /// it's content will not be added. 300 /// 301 /// \param *changedContainer returns the ID for the UpdateManager 302 /// \return objectID of the container given by path 303 virtual int ensurePathExistence(const fs::path& path, int* changedContainer) = 0; 304 305 /// \brief clears the given flag in all objects in the DB 306 [[deprecated]] virtual void clearFlagInDB(int flag) = 0; 307 308 virtual std::string getFsRootName() = 0; 309 310 virtual void threadCleanup() = 0; 311 virtual bool threadCleanupRequired() const = 0; 312 313 protected: 314 /* helper for addContainerChain */ 315 static void stripAndUnescapeVirtualContainerFromPath(std::string virtualPath, std::string& first, std::string& last); 316 317 static std::shared_ptr<Database> createInstance(const std::shared_ptr<Config>& config, const std::shared_ptr<Mime>& mime, const std::shared_ptr<Timer>& timer); 318 friend class Server; 319 320 virtual std::shared_ptr<Database> getSelf() = 0; 321 322 std::shared_ptr<Config> config; 323 }; 324 325 #endif // __STORAGE_H__ 326