Chris@465
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@465
|
2
|
Chris@465
|
3 /*
|
Chris@465
|
4 Sonic Visualiser
|
Chris@465
|
5 An audio file viewer and annotation editor.
|
Chris@465
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@465
|
7 This file copyright 2008 QMUL.
|
Chris@465
|
8
|
Chris@465
|
9 This program is free software; you can redistribute it and/or
|
Chris@465
|
10 modify it under the terms of the GNU General Public License as
|
Chris@465
|
11 published by the Free Software Foundation; either version 2 of the
|
Chris@465
|
12 License, or (at your option) any later version. See the file
|
Chris@465
|
13 COPYING included with this distribution for more information.
|
Chris@465
|
14 */
|
Chris@465
|
15
|
Chris@465
|
16 #include "CachedFile.h"
|
Chris@465
|
17
|
Chris@465
|
18 #include "base/TempDirectory.h"
|
Chris@465
|
19 #include "base/ProgressReporter.h"
|
Chris@465
|
20 #include "base/Exceptions.h"
|
Chris@465
|
21
|
Chris@465
|
22 #include <QFileInfo>
|
Chris@465
|
23 #include <QSettings>
|
Chris@465
|
24 #include <QVariant>
|
Chris@465
|
25 #include <QMap>
|
Chris@465
|
26 #include <QDir>
|
Chris@465
|
27 #include <QCryptographicHash>
|
Chris@465
|
28
|
Chris@465
|
29 QString
|
Chris@465
|
30 CachedFile::getLocalFilenameFor(QUrl url)
|
Chris@465
|
31 {
|
Chris@465
|
32 QDir dir(getCacheDirectory());
|
Chris@465
|
33
|
Chris@465
|
34 QString filename =
|
Chris@465
|
35 QString::fromLocal8Bit
|
Chris@465
|
36 (QCryptographicHash::hash(url.toString().toLocal8Bit(),
|
Chris@465
|
37 QCryptographicHash::Sha1).toHex());
|
Chris@465
|
38
|
Chris@465
|
39 return dir.filePath(filename);
|
Chris@465
|
40 }
|
Chris@465
|
41
|
Chris@465
|
42 QString
|
Chris@465
|
43 CachedFile::getCacheDirectory()
|
Chris@465
|
44 {
|
Chris@465
|
45 QDir dir = TempDirectory::getInstance()->getContainingPath();
|
Chris@465
|
46
|
Chris@465
|
47 QString cacheDirName("cache");
|
Chris@465
|
48
|
Chris@465
|
49 QFileInfo fi(dir.filePath(cacheDirName));
|
Chris@465
|
50
|
Chris@465
|
51 if ((fi.exists() && !fi.isDir()) ||
|
Chris@465
|
52 (!fi.exists() && !dir.mkdir(cacheDirName))) {
|
Chris@465
|
53
|
Chris@465
|
54 throw DirectoryCreationFailed(fi.filePath());
|
Chris@465
|
55 }
|
Chris@465
|
56
|
Chris@465
|
57 return fi.filePath();
|
Chris@465
|
58 }
|
Chris@465
|
59
|
Chris@465
|
60 CachedFile::CachedFile(QUrl url, ProgressReporter *reporter) :
|
Chris@465
|
61 m_url(url),
|
Chris@465
|
62 m_localFilename(getLocalFilenameFor(url)),
|
Chris@465
|
63 m_ok(false)
|
Chris@465
|
64 {
|
Chris@465
|
65 refresh();
|
Chris@465
|
66 }
|
Chris@465
|
67
|
Chris@465
|
68 bool
|
Chris@465
|
69 CachedFile::isOK() const
|
Chris@465
|
70 {
|
Chris@465
|
71 return m_ok;
|
Chris@465
|
72 }
|
Chris@465
|
73
|
Chris@465
|
74 QString
|
Chris@465
|
75 CachedFile::getLocalFilename() const
|
Chris@465
|
76 {
|
Chris@465
|
77 return m_localFilename;
|
Chris@465
|
78 }
|
Chris@465
|
79
|
Chris@465
|
80 void
|
Chris@465
|
81 CachedFile::refresh()
|
Chris@465
|
82 {
|
Chris@465
|
83 //!!! n.b. obvious race condition here if different CachedFile
|
Chris@465
|
84 // objects for same url used in more than one thread -- need to
|
Chris@465
|
85 // lock appropriately. also consider race condition between
|
Chris@465
|
86 // separate instances of the program
|
Chris@465
|
87
|
Chris@465
|
88 if (!QFileInfo(m_localFilename).exists()) {
|
Chris@465
|
89 updateLastRetrieval(false); // empirically!
|
Chris@465
|
90 }
|
Chris@465
|
91
|
Chris@465
|
92 QDateTime lastRetrieval = getLastRetrieval();
|
Chris@465
|
93
|
Chris@465
|
94 if (lastRetrieval.isValid()) {
|
Chris@465
|
95 // this will not be the case if the file is missing, after
|
Chris@465
|
96 // updateLastRetrieval(false) was called above
|
Chris@465
|
97 m_ok = true;
|
Chris@465
|
98 if (lastRetrieval.addDays(2) < QDateTime::currentDateTime()) { //!!!
|
Chris@465
|
99 // doesn't matter if retrieval fails -- we just don't
|
Chris@465
|
100 // update the last retrieval time
|
Chris@465
|
101
|
Chris@465
|
102 //!!! but we do want an additional last-attempted
|
Chris@465
|
103 // timestamp so as to ensure we aren't retrying the
|
Chris@465
|
104 // retrieval every single time if it isn't working
|
Chris@465
|
105
|
Chris@465
|
106 if (retrieve()) {
|
Chris@465
|
107 updateLastRetrieval(true);
|
Chris@465
|
108 }
|
Chris@465
|
109 }
|
Chris@465
|
110 } else {
|
Chris@465
|
111 // there is no acceptable file
|
Chris@465
|
112 if (retrieve()) {
|
Chris@465
|
113 m_ok = true;
|
Chris@465
|
114 updateLastRetrieval(true);
|
Chris@465
|
115 } else {
|
Chris@465
|
116 // again, we don't need to do anything here -- the last
|
Chris@465
|
117 // retrieval timestamp is already invalid
|
Chris@465
|
118 }
|
Chris@465
|
119 }
|
Chris@465
|
120 }
|
Chris@465
|
121
|
Chris@465
|
122 bool
|
Chris@465
|
123 CachedFile::retrieve()
|
Chris@465
|
124 {
|
Chris@465
|
125 //!!! need to work by retrieving the file to another name, and
|
Chris@465
|
126 //!!! then "atomically" moving it to its proper place (I'm not
|
Chris@465
|
127 //!!! sure we can do an atomic move to replace an existing file
|
Chris@465
|
128 //!!! using Qt classes, but a plain delete then copy is probably
|
Chris@465
|
129 //!!! good enough)
|
Chris@465
|
130
|
Chris@465
|
131
|
Chris@465
|
132
|
Chris@465
|
133
|
Chris@465
|
134 }
|
Chris@465
|
135
|
Chris@465
|
136 QDateTime
|
Chris@465
|
137 CachedFile::getLastRetrieval()
|
Chris@465
|
138 {
|
Chris@465
|
139 QSettings settings;
|
Chris@465
|
140 settings.beginGroup("FileCache");
|
Chris@465
|
141
|
Chris@465
|
142 QString key("last-retrieval-times");
|
Chris@465
|
143
|
Chris@465
|
144 QMap<QString, QVariant> timeMap = settings.value(key).toMap();
|
Chris@465
|
145 QDateTime lastTime = timeMap[m_localFilename].toDateTime();
|
Chris@465
|
146
|
Chris@465
|
147 settings.endGroup();
|
Chris@465
|
148 return lastTime;
|
Chris@465
|
149 }
|
Chris@465
|
150
|
Chris@465
|
151 void
|
Chris@465
|
152 CachedFile::updateLastRetrieval(bool successful)
|
Chris@465
|
153 {
|
Chris@465
|
154 //!!! note !successful does not mean "we failed to update the
|
Chris@465
|
155 //!!! file" (and so it remains the same as before); it means "the
|
Chris@465
|
156 //!!! file is not there at all"
|
Chris@465
|
157
|
Chris@465
|
158 QSettings settings;
|
Chris@465
|
159 settings.beginGroup("FileCache");
|
Chris@465
|
160
|
Chris@465
|
161 QString key("last-retrieval-times");
|
Chris@465
|
162
|
Chris@465
|
163 QMap<QString, QVariant> timeMap = settings.value(key).toMap();
|
Chris@465
|
164
|
Chris@465
|
165 QDateTime dt;
|
Chris@465
|
166 if (successful) dt = QDateTime::currentDateTime();
|
Chris@465
|
167
|
Chris@465
|
168 timeMap[m_localFilename] = dt;
|
Chris@465
|
169 settings.setValue(key, timeMap);
|
Chris@465
|
170
|
Chris@465
|
171 settings.endGroup();
|
Chris@465
|
172 }
|
Chris@465
|
173
|
Chris@465
|
174
|