2 #ifndef _QICORE_FILEOPERATION_HPP_
3 #define _QICORE_FILEOPERATION_HPP_
7 #include <boost/filesystem/fstream.hpp>
8 #include <boost/filesystem/operations.hpp>
9 #include <qi/detail/warn_push_ignore_deprecated.hpp>
26 auto task = std::move(_task);
29 task->promise.future().cancel();
42 : _task(std::move(other._task))
51 _task = std::move(other._task);
66 throw std::runtime_error{
"Tried to start an invalid FileOperation" };
69 if (_task->isLaunched.swap(
true))
71 throw std::runtime_error{
"Called FileOperation::start() more than once!" };
90 boost::shared_ptr<Task> sharedTask = std::move(_task);
94 throw std::runtime_error(
"Called FileOperation::detach() but no task is owned!");
97 if (!sharedTask->isLaunched._value)
99 throw std::runtime_error(
"Called FileOperation::detach() but task was not started!");
102 auto future = sharedTask->promise.future();
103 future.connect([sharedTask](
const Future<void>&){});
120 bool isValid()
const {
return _task ?
true :
false; }
123 explicit operator bool()
const {
return isValid(); }
127 :
public boost::enable_shared_from_this<Task>
139 virtual ~Task() =
default;
158 void fail(
const std::string& errorMessage)
160 promise.setError(errorMessage);
178 virtual void start() = 0;
192 : _task{ std::move(task) }
195 throw std::runtime_error(
"FileOperation requires a non-null task on constrution.");
219 :
FileOperation(boost::make_shared<Task>(std::move(file), std::move(localPath)))
230 , localPath(std::move(localFilePath))
234 void start()
override
250 if (localPath.isEmpty()) {
254 localFile.open(localPath.bfsPath(), std::ios::out | std::ios::binary);
255 if (!localFile.is_open())
257 fail(
"Failed to create local file copy.");
263 void write(Buffer buffer)
265 if (localFile.is_open())
266 localFile.write(static_cast<const char*>(buffer.data()), buffer.totalSize());
268 std::cout.write(static_cast<const char*>(buffer.data()), buffer.totalSize());
269 bytesWritten += buffer.totalSize();
270 assert(fileSize >= bytesWritten);
272 const double progress =
static_cast<double>(bytesWritten) / static_cast<double>(fileSize);
273 notifyProgressed(progress);
278 static const size_t ARBITRARY_BYTES_TO_READ_PER_CYCLE = 512 * 1024;
279 auto myself = shared_from_this();
281 const auto readFuncName = isRemoteDeprecated ?
"_read" :
"read";
283 sourceFile.async<Buffer>(readFuncName, bytesWritten, ARBITRARY_BYTES_TO_READ_PER_CYCLE)
284 .connect([
this, myself](Future<Buffer> futureBuffer)
286 if (futureBuffer.hasError())
288 fail(futureBuffer.error());
292 if (promise.isCancelRequested())
299 write(futureBuffer.value());
300 if (bytesWritten < fileSize)
308 void clearLocalFile()
310 if (localFile.is_open())
312 boost::filesystem::remove(localPath);
315 boost::filesystem::ofstream localFile;
316 std::streamsize bytesWritten = 0;
317 const qi::Path localPath;
332 #include <qi/detail/warn_pop_ignore_deprecated.hpp>
const bool isRemoteDeprecated
qi::Future< void > start()
Object< FileOperation > FileOperationPtr
Pointer to a file operation with sharing semantic.
FileOperation(FileOperation &&other)
ProgressNotifierPtr notifier() const
qi::Object< File > FilePtr
Pointer to a file with shared/remote semantic.
FutureSync< void > copyToLocal(FilePtr file, Path localPath)
boost::shared_ptr< Task > TaskPtr
qi::Object< ProgressNotifier > ProgressNotifierPtr
Pointer to a ProgressNotifier with shared/remote semantic.
void fail(const std::string &errorMessage)
FileOperation(const FileOperation &)=delete
FileOperation & operator=(const FileOperation &)=delete
const ProgressNotifierPtr localNotifier
ProgressNotifierPtr createProgressNotifier(Future< void > operationFuture={})
const ProgressNotifierPtr remoteNotifier
void notifyProgressed(double newProgress)
FileCopyToLocal(qi::FilePtr file, qi::Path localPath)
auto operator()() -> decltype(start())
Call operator: calls start()
FileOperation(TaskPtr task)
qi::Atomic< bool > isLaunched
const std::streamsize fileSize
FileOperation & operator=(FileOperation &&other)
qi::Future< void > detach()