zoukankan      html  css  js  c++  java
  • 缓存下载任务

    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);
                }
            }
        }
    }
    
  • 相关阅读:
    用document.onreadystatechange和document.readyState确保文档加载完毕才获取DOM
    动态修改样式和层叠样式表
    jQuery中Ajax事件顺序及各参数含义
    对于JavaScript对象的prototype和__proto__的理解
    HTML5实现“摇一摇”效果
    修改mysql错误提示语言的方法
    12个非常有用的JavaScript小技巧
    学习javascript中this用法的一些感悟
    Token 认证
    “好”的接口是怎么样的?
  • 原文地址:https://www.cnblogs.com/wywnet/p/4755259.html
Copyright © 2011-2022 走看看