缓存下载任务

using NewTempo.Ftp;
using NshowAdClient.Events;
using NshowAdClient.Helper;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace NshowAdClient.Services
{

    public class CacheFileEventArgs : EventArgs
    {
        public bool IsFaulted { get; private set; }

        public CacheFileModel CacheFile { get; private set; }

        public CacheFileEventArgs(CacheFileModel cacheFile)
        {
            CacheFile = cacheFile;
            IsFaulted = false;
        }

        public CacheFileEventArgs()
        {
            IsFaulted = true;
        }
    }

    public class CacheFileModel
    {
        public CacheFileModel()
        {
            CreateTime = DateTime.Now;
            LastUseTime = DateTime.Now;
        }

        public string RemoteFile { get; set; }

        public string LocalFile { get; set; }

        public DateTime CreateTime { get; set; }

        public DateTime LastUseTime { get; set; }
    }


    /// <summary>
    /// 文件缓存接口
    /// </summary>
    public interface IFileCache
    {
        void GetUserFile(string remoteFile, int userId, EventHandler<CacheFileEventArgs> action);

        void GetShareFile(string remoteFile, EventHandler<CacheFileEventArgs> action);
    }


    public class FileCacheMgr : IFileCache
    {
        /// <summary>
        /// 缓存内容的目录
        /// </summary>
        private const string CacheDir = "CacheFile";

        /// <summary>
        /// 缓存数据的文件名
        /// </summary>
        private const string CacheDataFile = "file.cache";

        // ReSharper disable once InconsistentNaming
        private static readonly FileCacheMgr instance = new FileCacheMgr();
        public static FileCacheMgr Instance { get { return instance; } }
        private FileCacheMgr()
        {
            Initialize();
        }

        /// <summary>
        /// 缓存数据文件的读写锁
        /// </summary>
        readonly object _cacheDataFileLock = new object();

        /// <summary>
        /// 管理缓存数据的锁对象
        /// </summary>
        readonly object _cacheLock = new object();

        /// <summary>
        /// 缓存数据任务的锁对象
        /// </summary>
        readonly object _cacheTaskLock = new object();

        /// <summary>
        /// 缓存数据字典
        /// Key : url
        /// Value : CacheModel
        /// </summary>
        Dictionary<string, CacheFileModel> _cacheDict = new Dictionary<string, CacheFileModel>();

        /// <summary>
        /// 下载任务字典
        ///     Key:RemoteUlr
        ///     Value:任务完成时的回调
        /// </summary>
        readonly Dictionary<string, WeakDelegateCollection<CacheFileEventArgs>> _cacheTaskDict = new Dictionary<string, WeakDelegateCollection<CacheFileEventArgs>>();

        void Initialize()
        {
            LoadCacheData();
        }

        #region CacheDataOperation

        /// <summary>
        /// 读取缓存
        /// </summary>
        void LoadCacheData()
        {
            lock (_cacheDataFileLock)
            {
                try
                {
                    //缓存数据文件不存在则删除缓存文件夹的内容
                    if (!File.Exists(CacheDataFile) && Directory.Exists(CacheDir))
                        Directory.Delete(CacheDir, true);

                    var xs = new XmlSerializer(typeof(List<CacheFileModel>));
                    using (Stream stream = new FileStream(CacheDataFile, FileMode.Open,
                        FileAccess.Read))
                    {
                        var list = xs.Deserialize(stream) as List<CacheFileModel>
                            ?? new List<CacheFileModel>();
                        _cacheDict = list.ToDictionary(m => m.RemoteFile);
                    }
                }
                catch (Exception ex)
                {
                    Logger.Error("读取文件缓存数据失败!", ex);
                }
            }
        }

        /// <summary>
        /// 保存
        /// </summary>
        void SaveCacheData()
        {
            lock (_cacheDataFileLock)
            {
                try
                {
                    var xs = new XmlSerializer(typeof(List<CacheFileModel>));
                    using (Stream stream = new FileStream(CacheDataFile, FileMode.Create,
                        FileAccess.Write))
                    {
                        xs.Serialize(stream, _cacheDict.Values.ToList<CacheFileModel>());
                    }
                }
                catch (Exception ex)
                {
                    Logger.Error("读取文件缓存数据失败!", ex);
                    File.Delete(CacheDataFile);
                }
            }
        }

        /// <summary>
        /// 清除过期的缓存数据
        /// </summary>
        public void CleanExpireCache()
        {
            try
            {
                List<string> cleanList = new List<string>();
                foreach (var item in _cacheDict)
                {
                    if (DateTime.Now - item.Value.LastUseTime > TimeSpan.FromDays(7))
                        cleanList.Add(item.Key);
                }

                foreach (var item in cleanList)
                {
                    File.Delete(_cacheDict[item].LocalFile);
                    _cacheDict.Remove(item);
                }

                SaveCacheData();
            }
            catch (Exception e)
            {
                Logger.Error("清理过期缓存数据失败!", e);
            }
        }

        /// <summary>
        /// 添加缓存数据
        /// </summary>
        /// <param name="model">数据实体</param>
        void AddCacheData(CacheFileModel model)
        {
            if (model == null)
                throw new ArgumentNullException("model");

            lock (_cacheLock)
            {
                if (_cacheDict.ContainsKey(model.RemoteFile) == false)
                {
                    _cacheDict.Add(model.RemoteFile, model);
                    SaveCacheData();
                }
            }
        }

        /// <summary>
        /// 提出缓存数据
        /// </summary>
        /// <param name="model">数据实体</param>
        void RemoveCacheData(CacheFileModel model)
        {
            if (model == null)
                throw new ArgumentNullException("model");

            lock (_cacheLock)
            {
                if (File.Exists(model.LocalFile))
                    File.Delete(model.LocalFile);

                if (_cacheDict.ContainsKey(model.RemoteFile))
                {
                    _cacheDict.Remove(model.RemoteFile);
                    SaveCacheData();
                }
            }
        }

        #endregion CacheDataOperation


        /// <summary>
        /// 获取用户的资源文件
        /// </summary>
        /// <param name="remoteFile">远程文件</param>
        /// <param name="userId">用户Id</param>
        /// <param name="callback">获取文件的回调(成功或失败)</param>
        public void GetUserFile(string remoteFile, int userId, EventHandler<CacheFileEventArgs> callback)
        {
            GetCacheFile(remoteFile, callback, () => FtpHelpService.GetClientFtp(userId));
        }

        /// <summary>
        /// 获取共享资源文件
        /// </summary>
        /// <param name="remoteFile">远程文件</param>
        /// <param name="callback">获取文件的回调</param>
        public void GetShareFile(string remoteFile, EventHandler<CacheFileEventArgs> callback)
        {
            GetCacheFile(remoteFile, callback, FtpHelpService.GetShareFtp);
        }

        /// <summary>
        /// 获取缓存文件
        ///     如果缓存不存在则创建下载任务
        /// </summary>
        /// <param name="remoteFile">远程文件</param>
        /// <param name="callback">获取文件的回调</param>
        /// <param name="getFtpFunc">获取FTP的委托(不存在缓存文件时,使用该FTP下载文件)</param>
        void GetCacheFile(string remoteFile, EventHandler<CacheFileEventArgs> callback, Func<MyFtp> getFtpFunc)
        {
            if (_cacheDict.ContainsKey(remoteFile))
            {
                CacheFileModel cache = _cacheDict[remoteFile];
                if (File.Exists(cache.LocalFile))
                {
                    cache.LastUseTime = DateTime.Now;
                    SaveCacheData();

                    if (callback != null)
                    {
                        callback(this, new CacheFileEventArgs(cache));
                    }

                    //跳出方法
                    return;
                }
                else
                {
                    //本地文件不存在
                    _cacheDict.Remove(remoteFile);
                }
            }

            //添加下载远程文件任务
            CreateDownloadTask(remoteFile, getFtpFunc(), callback);
        }

        void CreateDownloadTask(string remoteFile, MyFtp myFtp, EventHandler<CacheFileEventArgs> callback)
        {
            lock (_cacheTaskLock)
            {
                bool exist = _cacheTaskDict.ContainsKey(remoteFile);

                AddCallbackToDictNoLock(remoteFile, callback);
                if (exist == false)
                {
                    Task.Factory.StartNew(() => DownloadFileWork(remoteFile, myFtp, callback),
                        TaskCreationOptions.PreferFairness);
                }
            }
        }

        void DownloadFileWork(string remoteFile, MyFtp myFtp, EventHandler<CacheFileEventArgs> callback)
        {
            string localFile = Path.Combine(CacheDir, Guid.NewGuid().ToString() + Path.GetExtension(remoteFile));
            string path = Path.GetDirectoryName(localFile);
            if (Directory.Exists(path) == false)
            {
                Directory.CreateDirectory(path);
            }

            var eventArgs = new CacheFileEventArgs();
            try
            {
                bool dlRet = myFtp.Download(remoteFile, localFile);

                if (dlRet && File.Exists(localFile))
                {
                    var cacheModel = new CacheFileModel()
                    {
                        RemoteFile = remoteFile,
                        LocalFile = localFile,
                    };
                    eventArgs = new CacheFileEventArgs(cacheModel);

                    //保存缓存信息
                    AddCacheData(cacheModel);
                }
            }
            finally
            {
                try
                {
                    InvokeCallback(remoteFile, eventArgs);
                }
                finally
                {
                    RemoveCallback(remoteFile);
                }
            }
        }

        void AddCallbackToDictNoLock(string remoteFile, EventHandler<CacheFileEventArgs> callback)
        {
            if (_cacheTaskDict.ContainsKey(remoteFile) == false)
                _cacheTaskDict.Add(remoteFile, new WeakDelegateCollection<CacheFileEventArgs>());
            var weakEvent = _cacheTaskDict[remoteFile];
            weakEvent.WeakEvent += callback;
        }

        void RemoveCallback(string remoteFile)
        {
            lock (_cacheTaskLock)
            {
                if (_cacheTaskDict.ContainsKey(remoteFile))
                    _cacheTaskDict.Remove(remoteFile);
            }
        }

        void InvokeCallback(string remoteFile, CacheFileEventArgs args)
        {
            lock (_cacheTaskLock)
            {
                if (_cacheTaskDict.ContainsKey(remoteFile) == false)
                    return;
                _cacheTaskDict[remoteFile].Invoke(this, args);
            }
        }
    }
}
原文地址:https://www.cnblogs.com/wywnet/p/4755259.html