zhaolei
2020-11-20 921de2254ff5712a44ed8575ee8efe34252f6603
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#if !NET45
using Microsoft.Extensions.Options;
#endif
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
 
namespace Prow.Tasks
{
    /// <summary>
    /// 持久化到物理文件操作类
    /// </summary>
#if !NET45
    internal class FileStorage : IStorage
#else
    public class FileStorage : IStorage
#endif
    {
        /// <summary>
        /// 获得/设置 物理文件持久化文件目录名称 默认 TaskStorage
        /// </summary>
        public FileStorageOptions Options { get; private set; }
 
        /// <summary>
        /// 获得 上一次操作异常信息实例
        /// </summary>
        public Exception? Exception { get; set; }
 
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="options"></param>
#if !NET45
        public FileStorage(IOptionsMonitor<FileStorageOptions> options)
        {
            options.OnChange(op => Options = op);
            Options = options.CurrentValue;
        }
#else
        public FileStorage(FileStorageOptions options)
        {
            Options = options;
        }
#endif
 
        /// <summary>
        /// 从物理文件加载 ITrigger 触发器
        /// </summary>
        /// <param name="schedulerName">任务调度器名称</param>
        /// <param name="trigger"></param>
        /// <returns></returns>
        public bool Load(string schedulerName, ITrigger trigger)
        {
            // 从文件加载
            Exception = null;
            var ret = true;
            if (Options.Enabled)
            {
                var fileName = RetrieveFileNameBySchedulerName(schedulerName);
                if (File.Exists(fileName))
                {
                    try
                    {
                        lock (locker) trigger.Deserialize(fileName, Options);
                    }
                    catch (Exception ex)
                    {
                        Exception = ex;
                        ret = false;
                        // load 失败删除文件防止一直 load 出错
                        var target = $"{fileName}.err";
                        if (File.Exists(target)) File.Delete(target);
                        File.Move(fileName, $"{fileName}.err");
                    }
                }
            }
            return ret;
        }
 
        private static readonly object locker = new object();
        /// <summary>
        /// 持久化 ITrigger 实例到物理文件
        /// </summary>
        /// <param name="schedulerName">任务调度器名称</param>
        /// <param name="trigger"></param>
        /// <returns></returns>
        public bool Save(string schedulerName, ITrigger trigger)
        {
            if (trigger == null) throw new ArgumentNullException(nameof(trigger));
 
            Exception = null;
            var ret = true;
            if (Options.Enabled)
            {
                try
                {
                    lock (locker)
                    {
                        var fileName = RetrieveFileNameBySchedulerName(schedulerName);
                        trigger.Serialize(fileName, Options);
                    }
                }
                catch (Exception ex) { Exception = ex; ret = false; }
            }
            return ret;
        }
 
        /// <summary>
        /// 移除指定任务调度
        /// </summary>
        /// <param name="schedulerNames">要移除调度名称集合</param>
        public bool Remove(IEnumerable<string> schedulerNames)
        {
            var ret = true;
            if (Options.DeleteFileByRemoveEvent)
            {
                schedulerNames.AsParallel().ForAll(name =>
                {
                    var fileName = RetrieveFileNameBySchedulerName(name);
                    try
                    {
                        if (File.Exists(fileName))
                        {
                            lock (locker)
                            {
                                File.Delete(fileName);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Exception = ex;
                        ret = false;
                    }
                });
            }
            return ret;
        }
 
        /// <summary>
        /// 通过指定调度器名称获得持久化文件名称
        /// </summary>
        /// <param name="schedulerName">调度器名称</param>
        /// <returns></returns>
        protected string RetrieveFileNameBySchedulerName(string schedulerName)
        {
#if !NET45
            var folder = Options.Folder.GetOSPlatformPath();
#else
            var folder = Options.Folder;
#endif
            return Path.Combine(AppDomain.CurrentDomain.BaseDirectory ?? "", folder, $"{schedulerName}.bin");
        }
    }
}