Unravel Engine C++ Reference
Loading...
Searching...
No Matches
syncer.cpp
Go to the documentation of this file.
1#include "syncer.h"
2#include "watcher.h"
3
4namespace fs
5{
6static void ensure_directory_exists(const fs::path& path)
7{
8 fs::error_code err;
9 if(path.has_extension())
10 {
11 fs::create_directories(fs::path(path).parent_path(), err);
12 }
13 else
14 {
15 fs::create_directories(path, err);
16 }
17}
18
20{
21 unsync();
22}
23
24void syncer::set_mapping(const std::string& ref_ext,
25 const std::vector<std::string>& synced_ext,
26 on_entry_created_t on_entry_created = nullptr,
27 on_entry_modified_t on_entry_modified = nullptr,
28 on_entry_removed_t on_entry_removed = nullptr,
29 on_entry_renamed_t on_entry_renamed = nullptr)
30{
31 std::lock_guard<std::mutex> lock(mutex_);
32 auto& mapping = mapping_[ref_ext];
33 mapping.extensions = synced_ext;
34 mapping.on_entry_created = std::move(on_entry_created);
35 mapping.on_entry_modified = std::move(on_entry_modified);
36 mapping.on_entry_removed = std::move(on_entry_removed);
37 mapping.on_entry_renamed = std::move(on_entry_renamed);
38}
39
41 syncer::on_entry_modified_t on_entry_modified,
42 syncer::on_entry_removed_t on_entry_removed,
43 syncer::on_entry_renamed_t on_entry_renamed)
44{
45 std::lock_guard<std::mutex> lock(mutex_);
46 auto& mapping = mapping_[""];
47 mapping.on_entry_created = std::move(on_entry_created);
48 mapping.on_entry_modified = std::move(on_entry_modified);
49 mapping.on_entry_removed = std::move(on_entry_removed);
50 mapping.on_entry_renamed = std::move(on_entry_renamed);
51}
52
54{
55 fs::watcher::unwatch(watch_id_);
56}
57
58auto syncer::get_mapping(const std::string& ext) -> mapping
59{
60 std::lock_guard<std::mutex> lock(mutex_);
61 auto it = mapping_.find(ext);
62 if(it != mapping_.end())
63 {
64 return it->second;
65 }
66
67 return {};
68}
69
70auto syncer::get_on_created_callback(const std::string& ext) -> on_entry_created_t
71{
72 return get_mapping(ext).on_entry_created;
73}
74
75auto syncer::get_on_modified_callback(const std::string& ext) -> on_entry_modified_t
76{
77 return get_mapping(ext).on_entry_modified;
78}
79
80auto syncer::get_on_removed_callback(const std::string& ext) -> on_entry_removed_t
81{
82 return get_mapping(ext).on_entry_removed;
83}
84
85auto syncer::get_on_renamed_callback(const std::string& ext) -> on_entry_renamed_t
86{
87 return get_mapping(ext).on_entry_renamed;
88}
89
90void syncer::sync(const fs::path& reference_dir, const fs::path& synced_dir)
91{
92 unsync();
93
94 {
95 std::lock_guard<std::mutex> lock(mutex_);
96 reference_dir_ = reference_dir;
97 synced_dir_ = synced_dir;
98 reference_dir_.make_preferred();
99 synced_dir_.make_preferred();
100 ensure_directory_exists(reference_dir_);
101 ensure_directory_exists(synced_dir_);
102 }
103
104 const auto on_change = [this](const auto& entries, bool is_initial_listing)
105 {
106 for(const auto& entry : entries)
107 {
108 bool is_directory = (entry.type == fs::file_type::directory);
109 auto entry_path = entry.path;
110 std::string entry_extension;
111 while(entry_path.has_extension())
112 {
113 entry_extension = entry_path.extension().string() + entry_extension;
114 entry_path.replace_extension();
115 }
116 switch(entry.status)
117 {
119 {
120 const auto synced_entries = this->get_synced_entries(entry.path, is_directory);
121
122 for(const auto& synced_entry : synced_entries)
123 {
124 ensure_directory_exists(synced_entry);
125 }
126
127 auto callback = this->get_on_created_callback(entry_extension);
128 if(callback)
129 {
130 callback(entry_extension, entry.path, synced_entries, is_initial_listing);
131 }
132 }
133 break;
135 {
136 auto callback = this->get_on_modified_callback(entry_extension);
137 if(callback)
138 {
139 const auto synced_entries = this->get_synced_entries(entry.path, is_directory);
140 callback(entry_extension, entry.path, synced_entries, is_initial_listing);
141 }
142 }
143 break;
145 {
146 const auto callback = this->get_on_removed_callback(entry_extension);
147
148 if(callback)
149 {
150 const auto synced_entries = this->get_synced_entries(entry.path, is_directory);
151 callback(entry_extension, entry.path, synced_entries);
152 }
153 }
154 break;
156 {
157 const auto last_synced_entries = this->get_synced_entries(entry.last_path, is_directory);
158 const auto synced_entries = this->get_synced_entries(entry.path, is_directory);
159 auto callback = this->get_on_renamed_callback(entry_extension);
160
161 if(callback && synced_entries.size() == last_synced_entries.size())
162 {
163 std::vector<rename_pair_t> synced_renamed;
164 synced_renamed.reserve(synced_entries.size());
165
166 for(std::size_t i = 0; i < synced_entries.size(); ++i)
167 {
168 const auto& last_synced_entry = last_synced_entries[i];
169 const auto& synced_entry = synced_entries[i];
170 rename_pair_t p(last_synced_entry, synced_entry);
171 synced_renamed.emplace_back(std::move(p));
172 }
173 rename_pair_t p(entry.last_path, entry.path);
174 callback(entry_extension, p, synced_renamed);
175 }
176 }
177
178 break;
179 default:
180 break;
181 }
182 }
183 };
184 using namespace std::literals;
185 const fs::path watch_dir = get_watch_path();
186 watch_id_ = fs::watcher::watch(watch_dir, pattern_filter("*"), true, true, 500ms, on_change);
187}
188
189auto syncer::get_synced_entries(const fs::path& path, bool is_directory) -> std::vector<fs::path>
190{
191 std::vector<fs::path> synced_entries;
192 auto synced_dir = get_synced_directory(path);
193
194 if(is_directory)
195 {
196 synced_entries.emplace_back(std::move(synced_dir));
197 }
198 else
199 {
200 auto entry_path = path;
201 std::string entry_extension;
202 while(entry_path.has_extension())
203 {
204 auto ext = entry_path.extension().string() + entry_extension;
205 entry_extension = ext;
206 entry_path.replace_extension();
207 }
208
209 {
210 std::lock_guard<std::mutex> lock(mutex_);
211 auto it = mapping_.find(entry_extension);
212 if(it != mapping_.end())
213 {
214 const auto& mapping = it->second;
215 const auto& extensions = mapping.extensions;
216
217 synced_entries.reserve(extensions.size());
218 for(const auto& cache_ext : extensions)
219 {
220 fs::path file = synced_dir / path.filename();
221 file.concat(cache_ext);
222
223 synced_entries.emplace_back(std::move(file));
224 }
225 }
226 }
227 }
228
229 return synced_entries;
230}
231
232auto syncer::get_watch_path() -> fs::path
233{
234 std::lock_guard<std::mutex> lock(mutex_);
235 const fs::path watch_dir = reference_dir_;
236 return watch_dir;
237}
238
239auto syncer::get_synced_directory(const fs::path& path) -> fs::path
240{
241 fs::path result;
242
243 {
244 std::lock_guard<std::mutex> lock(mutex_);
245 result = fs::replace(path, reference_dir_, synced_dir_);
246 }
247
248 fs::error_code err;
249 if(fs::is_directory(path, err) || !path.has_extension())
250 {
251 return result;
252 }
253
254 return result.parent_path();
255}
256} // namespace fs
A filter that combines include and exclude patterns for file/directory filtering.
std::pair< fs::path, fs::path > rename_pair_t
Definition syncer.h:16
std::function< void(const std::string &, const fs::path &, const std::vector< fs::path > &, bool)> on_entry_created_t
Definition syncer.h:18
std::function< void(const std::string &, const fs::path &, const std::vector< fs::path > &, bool)> on_entry_modified_t
Definition syncer.h:19
void unsync()
Stops syncing.
Definition syncer.cpp:53
void set_mapping(const std::string &ref_ext, const std::vector< std::string > &synced_ext, on_entry_created_t on_entry_created, on_entry_modified_t on_entry_modified, on_entry_removed_t on_entry_removed, on_entry_renamed_t on_entry_renamed)
Remaps a specific extension of the reference directory to extensions of the synced directory....
Definition syncer.cpp:24
std::function< void(const std::string &, const rename_pair_t &, const std::vector< rename_pair_t > &)> on_entry_renamed_t
Definition syncer.h:21
void sync(const fs::path &reference_dir, const fs::path &synced_dir)
Start syncing the synced_dir with reference to the reference_dir i.e changes that occur in the refere...
Definition syncer.cpp:90
void set_directory_mapping(on_entry_created_t on_entry_created, on_entry_modified_t on_entry_modified, on_entry_removed_t on_entry_removed, on_entry_renamed_t on_entry_renamed)
Definition syncer.cpp:40
std::function< void(const std::string &, const fs::path &, const std::vector< fs::path > &)> on_entry_removed_t
Definition syncer.h:20
static void unwatch(std::uint64_t key)
Un-watches a previously registered file or directory.
Definition watcher.cpp:426
static auto watch(const fs::path &path, const pattern_filter &filter, bool recursive, bool initial_list, clock_t::duration poll_interval, notify_callback callback) -> std::uint64_t
Watches a file or directory for modification and call back the specified std::function....
Definition watcher.cpp:416
Definition cache.hpp:11
path replace(const path &_path, const path &_sequence, const path &_new_sequence)
Replacing any occurences of the specified path sequence with another.
std::vector< std::string > extensions
Definition syncer.h:25
on_entry_removed_t on_entry_removed
Definition syncer.h:28
on_entry_modified_t on_entry_modified
Definition syncer.h:27
on_entry_renamed_t on_entry_renamed
Definition syncer.h:29
on_entry_created_t on_entry_created
Definition syncer.h:26