1 // This file is part of Desktop App Toolkit,
2 // a set of libraries for developing nice desktop applications.
3 //
4 // For license and copyright information please follow this link:
5 // https://github.com/desktop-app/legal/blob/master/LEGAL
6 //
7 #include "storage/cache/storage_cache_cleaner.h"
8 
9 #include <crl/crl.h>
10 #include <QtCore/QDir>
11 #include <QtCore/QFile>
12 #include <unordered_map>
13 #include <set>
14 
15 namespace Storage {
16 namespace Cache {
17 namespace details {
18 
19 class CleanerObject {
20 public:
21 	CleanerObject(
22 		crl::weak_on_queue<CleanerObject> weak,
23 		const QString &base,
24 		base::binary_guard &&guard,
25 		FnMut<void(Error)> done);
26 
27 private:
28 	void start();
29 	void scheduleNext();
30 	void cleanNext();
31 	void done();
32 
33 	crl::weak_on_queue<CleanerObject> _weak;
34 	QString _base, _errorPath;
35 	std::vector<QString> _queue;
36 	base::binary_guard _guard;
37 	FnMut<void(Error)> _done;
38 
39 };
40 
CleanerObject(crl::weak_on_queue<CleanerObject> weak,const QString & base,base::binary_guard && guard,FnMut<void (Error)> done)41 CleanerObject::CleanerObject(
42 	crl::weak_on_queue<CleanerObject> weak,
43 	const QString &base,
44 	base::binary_guard &&guard,
45 	FnMut<void(Error)> done)
46 : _weak(std::move(weak))
47 , _base(base)
48 , _guard(std::move(guard))
49 , _done(std::move(done)) {
50 	start();
51 }
52 
start()53 void CleanerObject::start() {
54 	const auto entries = QDir(_base).entryList(
55 		QDir::Dirs | QDir::NoDotAndDotDot);
56 	for (const auto &entry : entries) {
57 		_queue.push_back(entry);
58 	}
59 	if (const auto version = ReadVersionValue(_base)) {
60 		_queue.erase(
61 			ranges::remove(_queue, QString::number(*version)),
62 			end(_queue));
63 		scheduleNext();
64 	} else {
65 		_errorPath = VersionFilePath(_base);
66 		done();
67 	}
68 }
69 
scheduleNext()70 void CleanerObject::scheduleNext() {
71 	if (_queue.empty()) {
72 		done();
73 		return;
74 	}
75 	_weak.with([](CleanerObject &that) {
76 		if (that._guard) {
77 			that.cleanNext();
78 		}
79 	});
80 }
81 
cleanNext()82 void CleanerObject::cleanNext() {
83 	const auto path = _base + _queue.back();
84 	_queue.pop_back();
85 	if (!QDir(path).removeRecursively()) {
86 		_errorPath = path;
87 	}
88 	scheduleNext();
89 }
90 
done()91 void CleanerObject::done() {
92 	if (_done) {
93 		_done(_errorPath.isEmpty()
94 			? Error::NoError()
95 			: Error{ Error::Type::IO, _errorPath });
96 	}
97 }
98 
Cleaner(const QString & base,base::binary_guard && guard,FnMut<void (Error)> done)99 Cleaner::Cleaner(
100 	const QString &base,
101 	base::binary_guard &&guard,
102 	FnMut<void(Error)> done)
103 : _wrapped(base, std::move(guard), std::move(done)) {
104 }
105 
106 Cleaner::~Cleaner() = default;
107 
108 } // namespace details
109 } // namespace Cache
110 } // namespace Storage
111