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