1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
/**
* @file mega/request.h
* @brief Generic request interface
*
* (c) 2013-2014 by Mega Limited, Auckland, New Zealand
*
* This file is part of the MEGA SDK - Client Access Engine.
*
* Applications using the MEGA API must present a valid application key
* and comply with the the rules set forth in the Terms of Service.
*
* The MEGA SDK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* @copyright Simplified (2-clause) BSD License.
*
* You should have received a copy of the license along with this
* program.
*/
#ifndef MEGA_REQUEST_H
#define MEGA_REQUEST_H 1
#include "json.h"
#include "types.h"
#include <mega/common/badge_forward.h>
namespace mega {
// API request
class MEGA_API Request
{
private:
vector<unique_ptr<Command>> cmds;
string jsonresponse;
JSON json;
size_t processindex = 0;
JSONSplitter mJsonSplitter;
size_t mChunkedProgress = 0;
// once we send the commands, any retry must be for exactly
// the same JSON, or idempotence will not work properly
mutable string cachedJSON;
mutable string cachedIdempotenceId;
mutable string cachedCounts;
public:
void add(Command*);
size_t size() const;
string get(MegaClient* client, char reqidCounter[10], string& idempotenceId) const;
void serverresponse(string&& movestring, MegaClient*);
void servererror(const std::string &e, MegaClient* client);
void process(MegaClient* client);
bool processCmdJSON(Command* cmd, bool couldBeError, JSON& jsonResponse);
bool processSeqTag(Command* cmd, bool withJSON, bool& parsedOk, bool inSeqTagArray, JSON& processingJson);
m_off_t processChunk(const char* chunk, MegaClient*);
m_off_t totalChunkedProgress();
void clear();
bool empty() const;
void swap(Request&);
bool stopProcessing = false;
// if contains only one command and that command is FetchNodes
bool isFetchNodes() const;
Command* getCurrentCommand();
};
class MEGA_API RequestDispatcher
{
// these ones have been sent to the server, but we haven't received the response yet
Request inflightreq;
retryreason_t inflightFailReason = RETRY_NONE;
// client-server request double-buffering, in batches of up to MAX_COMMANDS
deque<Request> nextreqs;
// flags for dealing with resetting everything from a command in progress
bool processing = false;
bool clearWhenSafe = false;
static const int MAX_COMMANDS = 10000;
// unique request ID
char reqid[10];
public:
RequestDispatcher(PrnGen&);
// Queue a command to be send to MEGA. Some commands must go in their own batch (in case other commands fail the whole batch), determined by the Command's `batchSeparately` field.
void add(common::Badge<MegaClient> badge, Command*);
// Commands are waiting and could be sent (could be a retry if connection failed etc) (they are not already sent, not awaiting response)
bool readyToSend() const;
// True if we started sending a Request and haven't received a server response yet,
// and stays true even through network errors, retries, etc until we get that response
bool cmdsInflight() const;
// True if there is a request that has failed and needs retry because the API returned
// an error: -3 or -4
bool retryReasonIsApi() const;
Command* getCurrentCommand(bool currSeqtagSeen);
/**
* @brief get the set of commands to be sent to the server (could be a retry)
* @param includesFetchingNodes set to whether the commands include fetch nodes
*/
string serverrequest(bool& includesFetchingNodes, MegaClient* client, string& idempotenceId);
// Once we get a successful reply from the server, call this to complete everything
// Since we need to support idempotence, we cannot add anything more to the in-progress request
void serverresponse(string&& movestring, MegaClient*);
// Call this function when a chunk of data is received from the server for chunked requests
// The return value is the number of bytes that must be discarded. The chunk in the next call
// must start with the data that was not discarded in the previous call
size_t serverChunk(const char *chunk, MegaClient*);
// Amount of data consumed for chunked requests, 0 for non-chunked requests
size_t chunkedProgress();
// If we need to retry (eg due to networking issue, abandoned req, server refusal etc) call this and we will abandon that attempt.
// The req will be retried via the next serverrequest(), and idempotence takes care of avoiding duplicate actions
void inflightFailure(retryreason_t reason);
// If the server itself reports failure, use this one to resolve (commands are all failed)
// and we will move to the next Request
void servererror(const std::string &e, MegaClient*);
void continueProcessing(MegaClient* client);
void clear();
#if defined(MEGA_MEASURE_CODE) || defined(DEBUG)
Request deferredRequests;
std::function<bool(Command*)> deferRequests;
void sendDeferred();
#endif
#ifdef MEGA_MEASURE_CODE
uint64_t csRequestsSent = 0, csRequestsCompleted = 0;
uint64_t csBatchesSent = 0, csBatchesReceived = 0;
#endif
};
} // namespace
#endif
|