FTP Like Azure File Writes

View Snippet
                    using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Windows.Forms;
using System.Threading.Tasks;

using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
using Microsoft.WindowsAzure.ServiceRuntime;

namespace AzureBlobFileSyncUtility
{
    public partial class Form1 : Form
    {

        private static TextBoxStreamWriter _debugStreamWriter = null;
        private static CloudBlobContainer _blobContainer = null;
        private static CloudBlobClient _blobClient = null;
        private static CloudStorageAccount _cloudStorageAccount = null;
        private static bool _azureConnected = false;
        private static string _rootFolderPath = null;

        public Form1()
        {
            InitializeComponent();
            this.ShowLogDate = true;
            this.HideThreadId = true;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            _rootFolderPath = txtRootFolderPath.Text.ToLower();

            _debugStreamWriter = new TextBoxStreamWriter(txtDebug, null, this);
            TextWriterTraceListener writer = new TextWriterTraceListener(_debugStreamWriter);
            Debug.Listeners.Add(writer);
            Debug.WriteLine("Now redirecting debug output.");
        }

        public string FilterString
        {
            get;
            set;
        }

        public bool ShowLogDate
        {
            get;
            set;
        }

        public bool HideThreadId
        {
            get;
            set;
        }

        private void btnConnectToAzure_Click(object sender, EventArgs e)
        {
            Task.Factory.StartNew(AzureConnect);
        }

        private static void AzureConnect()
        {
            _cloudStorageAccount = CloudStorageAccount.Parse("XYZ");
            _blobClient = _cloudStorageAccount.CreateCloudBlobClient();
            _blobContainer = _blobClient.GetContainerReference("abc");
            _azureConnected = true;
            Debug.WriteLine("Connected to Azure...");
        }

        private void btnAzureFirstTimeUpload_Click(object sender, EventArgs e)
        {
            Task.Factory.StartNew(UploadFirstTime, TaskCreationOptions.LongRunning);
        }

        private static void UploadFirstTime()
        {
            if (!_azureConnected)
            {
                Debug.WriteLine("Connect to Azure first...");
                return;
            }

            FileInfo[] files = (new DirectoryInfo(_rootFolderPath)).GetFiles("*.*", SearchOption.AllDirectories);
            Debug.WriteLine("Got file list: " + files.Length.ToString());

            for (int i = 0; i < files.Length; i++)
            {
                AppStateManager.State.CachedFileInfo.Add(new CachedFileInfo(files[i]));

                CloudBlob blob = null;
                string fileName = files[i].FullName.ToLower().Replace(_rootFolderPath, "").ToLower();
                fileName = fileName.Replace("", "/");

                blob = _blobContainer.GetBlobReference(fileName);

                if (!blob.Exists())
                {
                    Debug.WriteLine(i.ToString() + "" + files.Length.ToString() + "> Uploading blob: " + fileName);
                    blob.UploadFile(files[i].FullName);

                    blob.Properties.ContentType = GetContentType(Path.GetExtension(files[i].FullName));

                    if (blob.Properties.ContentType == null)
                    {
                        Debug.WriteLine(i.ToString() + "" + files.Length.ToString() + "> Skipping content type for: " + fileName + " to NULL");
                        continue;
                    }

                    Debug.WriteLine(i.ToString() + "" + files.Length.ToString() + "> Content type of: " + fileName + " to " + blob.Properties.ContentType);
                    blob.SetProperties();
                }
                else
                {
                    Debug.WriteLine(i.ToString() + "" + files.Length.ToString() + "> Blob exists: " + fileName);
                }
            }

            AppStateManager.SaveState();
            Debug.WriteLine("Completed Upload Process.");
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            AppStateManager.SaveState();
        }

        private void btnRegenerateFileState_Click(object sender, EventArgs e)
        {
            Task.Factory.StartNew(RegenerateFileState, TaskCreationOptions.LongRunning);
        }

        private static void RegenerateFileState()
        {
            FileInfo[] files = (new DirectoryInfo(_rootFolderPath)).GetFiles("*.*", SearchOption.AllDirectories);
            Debug.WriteLine("Got file list: " + files.Length.ToString());

            for (int i = 0; i < files.Length; i++)
            {
                AppStateManager.State.CachedFileInfo.Add(new CachedFileInfo(files[i]));
            }

            AppStateManager.SaveState();
            Debug.WriteLine("Completed state generation.");
        }

        private void btnSyncChangesToAzure_Click(object sender, EventArgs e)
        {
            Task.Factory.StartNew(SyncChangesToAzure, TaskCreationOptions.LongRunning);
        }

        private async static void SyncChangesToAzure()
        {
            if (!_azureConnected)
            {
                Debug.WriteLine("Connect to Azure first...");
                return;
            }

            if (AppStateManager.State.CachedFileInfo.Count == 0)
            {
                Debug.WriteLine("Cannot sync changes without existing file state...");
                return;
            }

            List<CachedFileInfo> originalFiles = AppStateManager.State.CachedFileInfo;

            List<FileInfo> currentFiles = (new DirectoryInfo(_rootFolderPath)).GetFiles("*.*", SearchOption.AllDirectories).ToList();
            Debug.WriteLine("Got file list: " + currentFiles.Count.ToString());
            
            Task task2 = Task.Factory.StartNew(delegate { UploadModifiedFiles(new List<CachedFileInfo>(originalFiles), new List<FileInfo>(currentFiles)); }, TaskCreationOptions.LongRunning);
            Task task3 = Task.Factory.StartNew(delegate { UploadNewFiles(new List<CachedFileInfo>(originalFiles), new List<FileInfo>(currentFiles)); }, TaskCreationOptions.LongRunning);
            Task task1 = Task.Factory.StartNew(delegate { DeleteDeletedFiles(new List<CachedFileInfo>(originalFiles), new List<FileInfo>(currentFiles)); }, TaskCreationOptions.LongRunning);

            task1.Wait();
            task2.Wait();
            task3.Wait();

            Debug.WriteLine("Update AppStateManager.State.CachedFileInfo");
            AppStateManager.State.CachedFileInfo.Clear();

            for (int i = 0; i < currentFiles.Count; i++)
            {
                AppStateManager.State.CachedFileInfo.Add(new CachedFileInfo(currentFiles[i]));
            }

            AppStateManager.SaveState();
            Debug.WriteLine("Process Initiated");
        }

        private static void UploadNewFiles(List<CachedFileInfo> originalFiles, List<FileInfo> currentFiles)
        {
            Debug.WriteLine("************* UploadNewFiles Start *************");
            List<CachedFileInfo> newFiles = new List<CachedFileInfo>();

            for (int i = 0; i < currentFiles.Count; i++)
            {
                CachedFileInfo current = (from p in originalFiles.AsParallel()
                                          where p.FullName.ToLower() == currentFiles[i].FullName.ToLower()
                                          select p).FirstOrDefault();

                if (current == null)
                {
                    newFiles.Add(new CachedFileInfo(currentFiles[i]));
                }
            }

            if (newFiles.Count > 0)
            {
                for (int i = 0; i < newFiles.Count; i++)
                {
                    UploadFileToBlob(newFiles[i], i);
                    //SetBlobContentType(newFiles[i], i, newFiles.Count);
                }
            }
            Debug.WriteLine("************* UploadNewFiles Finish *************");
        }

        private static void UploadModifiedFiles(List<CachedFileInfo> originalFiles, List<FileInfo> currentFiles)
        {
            Debug.WriteLine("************* UploadModifiedFiles Start *************");
            List<CachedFileInfo> modified = new List<CachedFileInfo>();

            for (int i = 0; i < originalFiles.Count; i++)
            {
                FileInfo current = (from p in currentFiles.AsParallel()
                                    where p.FullName.ToLower() == originalFiles[i].FullName.ToLower() &&
                                          p.LastWriteTimeUtc > originalFiles[i].LastWriteTimeUtc
                                    select p).FirstOrDefault();

                if (current != null)
                {
                    modified.Add(originalFiles[i]);
                }
            }

            if (modified.Count > 0)
            {
                for (int i = 0; i < modified.Count; i++)
                {
                    UploadFileToBlob(modified[i], i);
                }
            }

            Debug.WriteLine("************* UploadModifiedFiles Finish *************");
        }

        private static void DeleteDeletedFiles(List<CachedFileInfo> originalFiles, List<FileInfo> currentFiles)
        {
            Debug.WriteLine("************* DeleteDeletedFiles Start *************");

            List<CachedFileInfo> deleted = new List<CachedFileInfo>();

            Debug.WriteLine("Find out deleted files & delete them first.");
            for (int i = 0; i < originalFiles.Count; i++)
            {
                FileInfo exists = (from p in currentFiles.AsParallel()
                                   where p.FullName.ToLower() == originalFiles[i].FullName.ToLower()
                                   select p).FirstOrDefault();

                if (exists == null)
                {
                    deleted.Add(originalFiles[i]);
                }
            }

            CloudBlob blob = null;
            string fileName = null;

            if (deleted.Count > 0)
            {
                for (int i = 0; i < deleted.Count; i++)
                {
                    fileName = deleted[i].FullName.ToLower().Replace(_rootFolderPath, "").ToLower();
                    fileName = fileName.Replace("", "/");

                    blob = _blobContainer.GetBlobReference(fileName);
                    Debug.WriteLine(i.ToString() + "" + deleted.Count.ToString() + "> Deleting blob: " + fileName);
                    blob.DeleteIfExists();
                }
            }

            Debug.WriteLine("************* DeleteDeletedFiles Finish *************");
        }

        private static void UploadFileToBlob(CachedFileInfo modified, int index)
        {
            string fileName = modified.FullName.ToLower().Replace(_rootFolderPath, "").ToLower();
            fileName = fileName.Replace("", "/");

            CloudBlob blob = _blobContainer.GetBlobReference(fileName);
            Debug.WriteLine(index.ToString() + "> Uploading blob: " + fileName);
            blob.UploadFile(modified.FullName);

            blob.Properties.ContentType = GetContentType(Path.GetExtension(modified.FullName));

            if (blob.Properties.ContentType == null)
            {
                Debug.WriteLine(index.ToString() + "> Skipping the fix of content type for: " + fileName + " to NULL");
                return;
            }

            Debug.WriteLine(index.ToString() + "> Fixing content type of: " + fileName + " to " + blob.Properties.ContentType);

            blob.SetProperties();
        }

        private void txtRootFolderPath_TextChanged(object sender, EventArgs e)
        {
            _rootFolderPath = txtRootFolderPath.Text.ToLower();
        }

        private static string GetContentType(string extension)
        {
            switch (extension.ToLowerInvariant())
            {
                case ".jpg":
                case ".jpeg":
                    return "image/jpeg";
                case ".png":
                    return "image/png";
                case ".gif":
                    return "image/gif";
                case ".ico":
                    return "image/x-icon";
                case ".css":
                    return "text/css";
                case ".js":
                    return "text/javascript";
                case ".svg":
                    return "image/svg+xml";
                case ".mp3":
                    return "audio/mpeg";
                case ".mp4":
                    return "video/mp4";
                case ".eot":
                    return "application/vnd.ms-fontobject";
                case ".woff":
                    return "application/x-woff";
                case ".ttf":
                    return "font/ttf";
                case ".otf":
                    return "font/otf";
            }

            return null;
        }

        private void btnFixAzureContentTypes_Click(object sender, EventArgs e)
        {
            Task.Factory.StartNew(FixAzureContentTypes, TaskCreationOptions.LongRunning);
        }

        private static void FixAzureContentTypes()
        {
            if (!_azureConnected)
            {
                Debug.WriteLine("Connect to Azure first...");
                return;
            }

            if (AppStateManager.State.CachedFileInfo.Count == 0)
            {
                Debug.WriteLine("Cannot fix content types without existing file state...");
                return;
            }

            string cacheControlHeader = "public, max-age=" + (60 * 60 * 24 * 15).ToString(); //15 days in seconds
            List<CachedFileInfo> originalFiles = AppStateManager.State.CachedFileInfo;

            for (int i = 0; i < originalFiles.Count; i++)
            {
                SetBlobContentType(originalFiles[i], i, originalFiles.Count);                
            }

            Debug.WriteLine("Operation completed");
        }

        private static void SetBlobContentType(CachedFileInfo file, int index, int totalCount)
        {
            string fileName = file.FullName.ToLower().Replace(_rootFolderPath, "").ToLower();
            fileName = fileName.Replace("", "/");

            CloudBlob blob = _blobContainer.GetBlobReference(fileName);

            if (blob.Exists())
            {
                blob.Properties.ContentType = GetContentType(Path.GetExtension(file.FullName));

                if (blob.Properties.ContentType == null)
                {
                    Debug.WriteLine(index.ToString() + "" + totalCount.ToString() + "> Skipping the fix of content type for: " + fileName + " to NULL");
                    return;
                }

                Debug.WriteLine(index.ToString() + "" + totalCount.ToString() + "> Fixing content type of: " + fileName + " to " + blob.Properties.ContentType);

                blob.SetProperties();
            }
        }
    }
}