1 /*
2 SPDX-FileCopyrightText: 2019 Krzysztof Nowicki <krissn@op.pl>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7 #pragma once
8
9 #include <QVector>
10
11 #include "ewsjob.h"
12
13 template<typename Req, typename ReqItem, typename RespItem>
14 class EwsAbstractChunkedJob
15 {
16 public:
17 EwsAbstractChunkedJob(unsigned int chunkSize);
18 ~EwsAbstractChunkedJob() = default;
19
20 typedef QVector<ReqItem> ReqItemList;
21 typedef QVector<RespItem> RespItemList;
22
23 void setItems(const ReqItemList &items);
24 const RespItemList &responses() const;
25
26 template<typename ReqSetupFn, typename RespGetFn, typename ProgressFn, typename ResultFn>
27 void start(ReqSetupFn reqSetupFn, RespGetFn respGetFn, ProgressFn progressFn, ResultFn resultFn);
28
29 private:
30 unsigned int mChunkSize;
31 unsigned int mItemsDone;
32 Req *mRequest = nullptr;
33 ReqItemList mItems;
34 RespItemList mResponses;
35 };
36
37 template<typename Req, typename ReqItem, typename RespItem>
EwsAbstractChunkedJob(unsigned int chunkSize)38 EwsAbstractChunkedJob<Req, ReqItem, RespItem>::EwsAbstractChunkedJob(unsigned int chunkSize)
39 : mChunkSize(chunkSize)
40 , mItemsDone(0)
41 {
42 }
43
44 template<typename Req, typename ReqItem, typename RespItem>
setItems(const ReqItemList & items)45 void EwsAbstractChunkedJob<Req, ReqItem, RespItem>::setItems(const ReqItemList &items)
46 {
47 mItems = items;
48 }
49
50 template<typename Req, typename ReqItem, typename RespItem>
responses()51 const QVector<RespItem> &EwsAbstractChunkedJob<Req, ReqItem, RespItem>::responses() const
52 {
53 return mResponses;
54 }
55
56 template<typename Req, typename ReqItem, typename RespItem>
57 template<typename ReqSetupFn, typename RespGetFn, typename ProgressFn, typename ResultFn>
start(ReqSetupFn reqSetupFn,RespGetFn respGetFn,ProgressFn progressFn,ResultFn resultFn)58 void EwsAbstractChunkedJob<Req, ReqItem, RespItem>::start(ReqSetupFn reqSetupFn, RespGetFn respGetFn, ProgressFn progressFn, ResultFn resultFn)
59 {
60 int itemsToDo = qMin(mItems.size() - mItemsDone, mChunkSize);
61 if (itemsToDo == 0) {
62 resultFn(true, QString());
63 return;
64 }
65
66 mRequest = reqSetupFn(mItems.cbegin() + mItemsDone, mItems.cbegin() + mItemsDone + itemsToDo);
67 if (!mRequest) {
68 resultFn(false, QStringLiteral("Failed to set-up request"));
69 return;
70 }
71
72 mItemsDone += itemsToDo;
73
74 QObject::connect(mRequest, &KJob::result, [this, reqSetupFn, respGetFn, progressFn, resultFn, itemsToDo](KJob *job) {
75 if (job->error()) {
76 resultFn(false, job->errorString());
77 return;
78 }
79
80 Req *req = qobject_cast<Req *>(job);
81 if (!req) {
82 resultFn(false, QStringLiteral("Incorrect request object type"));
83 return;
84 }
85
86 auto responses = respGetFn(req);
87 Q_ASSERT(responses.size() == itemsToDo);
88 mResponses += responses;
89
90 progressFn(mItemsDone * 100 / mItems.size());
91
92 start(reqSetupFn, respGetFn, progressFn, resultFn);
93 });
94
95 mRequest->start();
96 }
97