Пример #1
0
        private TResponse RequestCore <TResponse>(RequestBase request, object context = null)
            where TResponse : class
        {
            string dataRequest    = JsonConvert.SerializeObject(new object[] { request });
            Uri    uri            = GenerateUrl(request.QueryArguments);
            object jsonData       = null;
            int    requestDelay   = options.ApiRequestDelay;
            int    remainingRetry = options.ApiRequestAttempts;

            while (remainingRetry-- > 0)
            {
                string dataResult = webClient.PostRequestJson(uri, dataRequest);

                if (string.IsNullOrEmpty(dataResult) ||
                    (jsonData = JsonConvert.DeserializeObject(dataResult)) == null ||
                    jsonData is long ||
                    (jsonData is JArray && ((JArray)jsonData)[0].Type == JTokenType.Integer))
                {
                    ApiResultCode apiCode = jsonData == null
                      ? ApiResultCode.RequestFailedRetry
                      : jsonData is long
                                            ?(ApiResultCode)Enum.ToObject(typeof(ApiResultCode), jsonData)
                                                : (ApiResultCode)((JArray)jsonData)[0].Value <int>();

                    if (apiCode != ApiResultCode.Ok)
                    {
                        ApiRequestFailed?.Invoke(this, new ApiRequestFailedEventArgs(uri, options.ApiRequestAttempts - remainingRetry, requestDelay, apiCode, dataResult));
                    }

                    if (apiCode == ApiResultCode.RequestFailedRetry)
                    {
                        Thread.Sleep(requestDelay = (int)Math.Round(requestDelay * options.ApiRequestDelayExponentialFactor));
                        continue;
                    }

                    if (apiCode != ApiResultCode.Ok)
                    {
                        throw new ApiException(apiCode);
                    }
                }

                break;
            }

            JsonSerializerSettings settings = new JsonSerializerSettings();

            settings.Context = new StreamingContext(StreamingContextStates.All, context);

            string data = ((JArray)jsonData)[0].ToString();

            return((typeof(TResponse) == typeof(string)) ? data as TResponse : JsonConvert.DeserializeObject <TResponse>(data, settings));
        }
 private void OnApiRequestFailed(object sender, ApiRequestFailedEventArgs e)
 {
     ApiRequestFailed?.Invoke(sender, e);
 }
Пример #3
0
        /// <summary>
        /// Upload a stream on Mega.co.nz and attach created node to selected parent
        /// </summary>
        /// <param name="stream">Data to upload</param>
        /// <param name="name">Created node name</param>
        /// <param name="parent">Node to attach the uploaded file (all types except <see cref="NodeType.File" /> are supported)</param>
        /// <returns>Created node</returns>
        /// <exception cref="NotSupportedException">Not logged in</exception>
        /// <exception cref="ApiException">Mega.co.nz service reports an error</exception>
        /// <exception cref="ArgumentNullException">stream or name or parent is null</exception>
        /// <exception cref="ArgumentException">parent is not valid (all types except <see cref="NodeType.File" /> are supported)</exception>
        public INode Upload(Stream stream, string name, INode parent, DateTime?modificationDate = null, CancellationToken?cancellationToken = null)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }

            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentNullException("name");
            }

            if (parent == null)
            {
                throw new ArgumentNullException("parent");
            }

            if (parent.Type == NodeType.File)
            {
                throw new ArgumentException("Invalid parent node");
            }

            EnsureLoggedIn();

            if (cancellationToken.HasValue)
            {
                stream = new CancellableStream(stream, cancellationToken.Value);
            }

            string completionHandle = string.Empty;
            int    requestDelay     = options.ApiRequestDelay;
            int    remainingRetry   = options.ApiRequestAttempts;

            while (remainingRetry-- > 0)
            {
                // Retrieve upload URL
                UploadUrlRequest  uploadRequest  = new UploadUrlRequest(stream.Length);
                UploadUrlResponse uploadResponse = Request <UploadUrlResponse>(uploadRequest);

                ApiResultCode apiResult = ApiResultCode.Ok;
                using (MegaAesCtrStreamCrypter encryptedStream = new MegaAesCtrStreamCrypter(stream))
                {
                    var chunkStartPosition  = 0;
                    var chunksSizesToUpload = ComputeChunksSizesToUpload(encryptedStream.ChunksPositions, encryptedStream.Length).ToArray();
                    Uri uri = null;
                    for (int i = 0; i < chunksSizesToUpload.Length; i++)
                    {
                        completionHandle = string.Empty;

                        int    chunkSize   = chunksSizesToUpload[i];
                        byte[] chunkBuffer = new byte[chunkSize];
                        encryptedStream.Read(chunkBuffer, 0, chunkSize);

                        using (MemoryStream chunkStream = new MemoryStream(chunkBuffer))
                        {
                            uri = new Uri(uploadResponse.Url + "/" + chunkStartPosition);
                            chunkStartPosition += chunkSize;
                            try
                            {
                                completionHandle = webClient.PostRequestRaw(uri, chunkStream);
                                if (string.IsNullOrEmpty(completionHandle))
                                {
                                    apiResult = ApiResultCode.Ok;
                                    continue;
                                }

                                long retCode;
                                if (completionHandle.FromBase64().Length != 27 && long.TryParse(completionHandle, out retCode))
                                {
                                    apiResult = (ApiResultCode)retCode;
                                    break;
                                }
                            }
                            catch (Exception ex)
                            {
                                apiResult = ApiResultCode.RequestFailedRetry;
                                ApiRequestFailed?.Invoke(this, new ApiRequestFailedEventArgs(uri, remainingRetry, requestDelay, apiResult, ex));

                                break;
                            }
                        }
                    }

                    if (apiResult != ApiResultCode.Ok)
                    {
                        ApiRequestFailed?.Invoke(this, new ApiRequestFailedEventArgs(uri, remainingRetry, requestDelay, apiResult, completionHandle));

                        if (apiResult == ApiResultCode.RequestFailedRetry || apiResult == ApiResultCode.RequestFailedPermanetly || apiResult == ApiResultCode.TooManyRequests)
                        {
                            // Restart upload from the beginning
                            Thread.Sleep(requestDelay = (int)Math.Round(requestDelay * options.ApiRequestDelayExponentialFactor));

                            // Reset steam position
                            stream.Seek(0, SeekOrigin.Begin);

                            continue;
                        }

                        throw new ApiException(apiResult);
                    }

                    // Encrypt attributes
                    byte[] cryptedAttributes = Crypto.EncryptAttributes(new Attributes(name, stream, modificationDate), encryptedStream.FileKey);

                    // Compute the file key
                    byte[] fileKey = new byte[32];
                    for (int i = 0; i < 8; i++)
                    {
                        fileKey[i]      = (byte)(encryptedStream.FileKey[i] ^ encryptedStream.Iv[i]);
                        fileKey[i + 16] = encryptedStream.Iv[i];
                    }

                    for (int i = 8; i < 16; i++)
                    {
                        fileKey[i]      = (byte)(encryptedStream.FileKey[i] ^ encryptedStream.MetaMac[i - 8]);
                        fileKey[i + 16] = encryptedStream.MetaMac[i - 8];
                    }

                    byte[] encryptedKey = Crypto.EncryptKey(fileKey, masterKey);

                    CreateNodeRequest createNodeRequest  = CreateNodeRequest.CreateFileNodeRequest(parent, cryptedAttributes.ToBase64(), encryptedKey.ToBase64(), fileKey, completionHandle);
                    GetNodesResponse  createNodeResponse = Request <GetNodesResponse>(createNodeRequest, masterKey);
                    return(createNodeResponse.Nodes[0]);
                }
            }

            throw new UploadException(completionHandle);
        }