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