Example #1
0
        /// <summary>
        /// Manages every aspect of the upload from start to finish.
        /// </summary>
        public void UploadFile()
        {
            //Create a timestamp for logging time spent
            DateTime Start = DateTime.Now;

            //Create a new upload details to hold the details of the upload
            uploadDetails = new UploadDetails();
            //Start large file upload
            StartLargeFile();
            //Upload the parts
            RunUploadWorkers();
            //Finish Large File upload
            FinishLargeFile();

            #region Output final status message.
            //Get end datetime
            DateTime End = DateTime.Now;
            //Get the difference between the two as a string
            string diffInSeconds = Math.Round((End - Start).TotalSeconds, 1).ToString();
            //Get Mbps
            //First get MB
            var MBs = fileInfo.Length * 0.00000095367432;
            //Then mb
            var Mbs = MBs * 8;
            //Then calculate Mbps
            var Mbps = Mbs / (End - Start).TotalSeconds;
            StaticHelpers.DebugLogger($"Operation Finished. Operation Took: {diffInSeconds} seconds and transferred {Math.Round(MBs, 2)}MBs at a speed of {Math.Round(Mbps, 2)}Mbps", DebugLevel.Info);
            #endregion
        }
Example #2
0
        /// <summary>
        /// Starts and is the upload worker that does the actual uploads.
        /// </summary>
        public async void StartUploadWorker()
        {
            StaticHelpers.DebugLogger("Starting an internal upload worker", DebugLevel.Verbose);
            //Get our object containing our authorisation URLs
            UploadPartsUrlDetails uploadPartsUrlDetails = await GetUploadPartUrl();


            #region Loop where work is done
            //While there are bytes still be sent
            while (uploadDetails.totalBytesSent < localFileSize)
            {
                #region Check Bandwidth Monitor
                //If the bandwidth monitor requires a reduction in usage
                if (bandwidthMonitor.reduceUsage || bandwidthMonitor.urgentReduceUsage)
                {
                    //Check thread count is greater than 1
                    if (AllThreads.Count(thread => thread.ThreadState != System.Threading.ThreadState.Stopped) > 1)
                    {
                        //Log to debug
                        StaticHelpers.DebugLogger("Received Kill Request from Bandwidth Monitor. Killing self....", DebugLevel.Verbose);
                        //Set reduceUsage to false
                        bandwidthMonitor.reduceUsage = false;
                        //Kill this thread
                        break;
                    }
                    else
                    {
                        StaticHelpers.DebugLogger("Received Kill Request from Bandwidth Monitor HOWEVER as the only remaining thread I am ignoring.", DebugLevel.Verbose);
                    }
                }
                #endregion
                #region Get details from uploadDetails & Data from file
                //Create variables outside of the lock so we can set it inside but still access it outside
                //For a snapshot of uploadDetails
                UploadDetails uploadDetailsSnapshot = new UploadDetails();
                //Create the byte array for the data we are going to use
                byte[] data = new byte[Singletons.options.PartSize * (1000 * 1000)];

                //Lock the uploadDetails
                lock (uploadDetailsLock)
                {
                    #region Check if we are on the last part or even if there are no parts left
                    //If there is nothing left to upload
                    if ((localFileSize - uploadDetails.totalBytesSent) == 0)
                    {
                        //Break out of the loop as there is no more work to do
                        break;
                    }
                    //If the remaining bytes are less the minimum part size
                    if ((localFileSize - uploadDetails.totalBytesSent) <= uploadDetails.minimumPartSize)
                    {
                        //Changes the bytes sent for part to the remaining number of bytes
                        uploadDetails.bytesSentForPart = (localFileSize - uploadDetails.totalBytesSent);
                    }
                    #endregion
                    #region Read & hash File
                    // Generate SHA1 Chunk
                    // Open stream of the file
                    FileStream f = File.OpenRead(pathToFile);
                    //Seek to the location in the file we are currently up to
                    f.Seek(uploadDetails.totalBytesSent, SeekOrigin.Begin);
                    //Read the data from the file that we are going to use this time
                    f.Read(data, 0, (int)uploadDetails.bytesSentForPart);
                    //Create a blank SHA1 hash
                    SHA1 sha1 = SHA1.Create();
                    //Hash the bytes in our current data and keep the hash in hashData
                    byte[] hashData = sha1.ComputeHash(data, 0, (int)uploadDetails.bytesSentForPart);
                    //Dispose of the hash
                    sha1.Dispose();
                    //Create a string builder to manipulate the hash
                    StringBuilder sb = new StringBuilder();
                    //Add data to every byte in the range
                    foreach (byte b in hashData)
                    {
                        sb.Append(b.ToString("x2"));
                    }
                    //Close the file read because we now have the data
                    f.Close();
                    //Add the hash to the hash array
                    uploadDetails.partSha1Array.Add(sb.ToString());
                    #endregion
                    #region Finalise Operations on uploadDetails so we can release lock
                    //Get all the values we might need to use internally. OR just make a snapshot of Upload Details? (Yes this should work!)
                    uploadDetailsSnapshot = uploadDetails.CloneMe();

                    //Update the actual uploadDetails with what we intend to do.
                    //Increment the partNo
                    uploadDetails.partNo++;
                    //Increment the totalBytesSent
                    uploadDetails.totalBytesSent = uploadDetails.totalBytesSent + uploadDetails.bytesSentForPart;
                    #endregion
                }
                #endregion
                //To count number of failed attempts
                int WebRequestAttempt = 1;
                //To allow retry of the failed request
RetryPartUpload:
                //Output urls for debugging
                //StaticHelpers.DebugLogger("UploadPartsURL is: " + uploadPartsUrlDetails.uploadUrl + ". Key is: " + uploadPartsUrlDetails.authorizationToken, DebugLevel.FullDebug);
                //Start a new web request
                HttpWebRequest uploadPartRequest = (HttpWebRequest)WebRequest.Create(uploadPartsUrlDetails.uploadUrl);
                //Set to post
                uploadPartRequest.Method = "POST";
                //Set the request timeout to 5 minutes
                uploadPartRequest.Timeout = 5 * 60 * 1000;
                //Set authorization token (using the one for the current uploadPartUrl)
                //Intentionally generating error:
                //uploadPartRequest.Headers.Add("Authorization", uploadPartsUrlDetails.authorizationToken + "r");
                uploadPartRequest.Headers.Add("Authorization", uploadPartsUrlDetails.authorizationToken);
                //Set the part number
                uploadPartRequest.Headers.Add("X-Bz-Part-Number", uploadDetailsSnapshot.partNo.ToString());
                //Set the sha1 hash from the array (minus one on the part number because 0-index array
                uploadPartRequest.Headers.Add("X-Bz-Content-Sha1", (String)uploadDetailsSnapshot.partSha1Array[(uploadDetailsSnapshot.partNo - 1)]);
                //Set content type to json
                uploadPartRequest.ContentType = "application/json; charset=utf-8";
                //Set the content length to the bytes sent for the part
                uploadPartRequest.ContentLength = uploadDetailsSnapshot.bytesSentForPart;
                //Create a stream to use for the uploadPartRequest (this may be the one to change to a filestream)
                using (Stream stream = uploadPartRequest.GetRequestStream())
                {
                    //Write the data (through the stream?) to the uploadPartRequest
                    stream.Write(data, 0, (int)uploadDetailsSnapshot.bytesSentForPart);
                    //Close the stream
                    stream.Close();
                }
                //Set upload response to null
                HttpWebResponse uploadPartResponse = null;
                //Verbose message
                StaticHelpers.DebugLogger("Starting upload of part " + uploadDetailsSnapshot.partNo, DebugLevel.Verbose);
                //Try the upload
                try
                {
                    //Try the upload and set the upload part response to the response
                    uploadPartResponse = (HttpWebResponse)uploadPartRequest.GetResponse();
                }
                //If theres an exception catch and output it
                catch (WebException e)
                {
                    if (e.Response == null)
                    {
                        StaticHelpers.DebugLogger("Upload has failed with error: " + e.Message, DebugLevel.Warn);
                    }
                    else
                    {
                        using (WebResponse r = e.Response)
                        {
                            HttpWebResponse httpResponse = (HttpWebResponse)r;
                            StaticHelpers.DebugLogger($"Internal Worker Error with API.Error code: {httpResponse.StatusCode}. Retrying....", DebugLevel.Warn);
                            using (Stream dataE = r.GetResponseStream())
                                using (var reader = new StreamReader(dataE))
                                {
                                    string text = reader.ReadToEnd();
                                    StaticHelpers.DebugLogger($"Internal Worker Error with API.Error code: {text}. Retrying....", DebugLevel.Warn);
                                }
                        }
                    }
                    //If we have failed less than 5 times
                    if (WebRequestAttempt < 5)
                    {
                        //Log a message
                        StaticHelpers.DebugLogger("Upload has failed, getting fresh uploadparturl and retrying....", DebugLevel.Verbose);
                        //Get our object containing our authorisation URLs
                        uploadPartsUrlDetails = await GetUploadPartUrl();

                        //Output fresh url for debugging
                        StaticHelpers.DebugLogger("Fresh UploadPartsURL is: " + uploadPartsUrlDetails.uploadUrl + ". Key is: " + uploadPartsUrlDetails.authorizationToken, DebugLevel.FullDebug);

                        //Wait a while
                        int secToWait = WebRequestAttempt * 2;
                        Thread.Sleep(secToWait * 1000);
                        //Increment counter
                        WebRequestAttempt++;
                        //Retry
                        goto RetryPartUpload;
                    }
                }

                //Close the upload part response
                uploadPartResponse.Close();
                //Lock so we can work on uploadDetails
                lock (uploadDetailsLock)
                {
                    //Update uploadDetails with the fact this part has been completed
                    uploadDetails.BytesConfirmedSent = uploadDetails.BytesConfirmedSent + uploadDetailsSnapshot.bytesSentForPart;
                    //Calculate the decimal amount completed
                    double decimalPercentage = (double)uploadDetails.BytesConfirmedSent / (double)localFileSize;
                    //Calculate the percentage completed
                    int percentage = (int)(decimalPercentage * 100);
                    //Output to the console the percentage completed
                    StaticHelpers.UpdateSummary($"Progress: {percentage}%");
                }
                //Log to the debugger what part we've just done
                StaticHelpers.DebugLogger("Uploaded Part " + uploadDetailsSnapshot.partNo, DebugLevel.Verbose);
            }
            #endregion
            //Check whether we have finished or if just this thread being killed:
            if (uploadDetails.totalBytesSent >= localFileSize)
            {
                //We have reached the end of parts to upload so tell the system not to upload anymore
                noMoreThreads = true;
            }


            StaticHelpers.DebugLogger("Internal upload worker is dead.", DebugLevel.Verbose);
        }