1 /// <summary>
2 /// 提供计时器服务
3 /// </summary>
4 public class TimerService
5 {
6 private static TimerService _Instance = null;
7
8 public static TimerService Instance
9 {
10 get
11 {
12 if (_Instance == null)
13 {
14 //实例化对象,并启动计时器服务
15 _Instance = new TimerService();
16 _Instance.timer = new System.Timers.Timer();
17 _Instance.timer.Interval = 1000;
18 _Instance.timer.Elapsed += _Instance.Timer_Elapsed;
19 _Instance.timer.Start();
20 }
21 return _Instance;
22 }
23 }
24
25 /// <summary>
26 /// 定时器读写锁
27 /// </summary>
28 private UsingLock<Object> Lock = new UsingLock<object>();
29
30 /// <summary>
31 /// 已注册的事件列表
32 /// </summary>
33 private List<TimerEventInfomation> SubscribedEvents = new List<TimerEventInfomation>();
34
35 /// <summary>
36 /// 计时器,每秒计时一次
37 /// </summary>
38 private System.Timers.Timer timer = new System.Timers.Timer();
39
40 /// <summary>
41 /// 获取当前时间戳
42 /// </summary>
43 /// <returns></returns>
44 private long GetTime()
45 {
46 return GetTime(DateTime.Now);
47 }
48
49 /// <summary>
50 /// 获取指定日期时间的时间戳
51 /// </summary>
52 /// <param name="time"></param>
53 /// <returns></returns>
54 public static long GetTime(DateTime time)
55 {
56 return Convert.ToInt32(time.Subtract(DateTime.Parse("1970-01-01")).TotalSeconds);
57 }
58
59 /// <summary>
60 /// 每秒触发一次该事件
61 /// </summary>
62 /// <param name="sender"></param>
63 /// <param name="e"></param>
64 private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
65 {
66 var time = GetTime();
67 using (Lock.Write())
68 {
69 var triggers = this.SubscribedEvents.Where(t => t.EventTime == time).ToList();
70 foreach (var item in triggers)
71 {
72 //异步执行回调
73 item.EventCallback?.BeginInvoke(item, new AsyncCallback((d) => { }), null);
74 }
75 //移除全部本次已回调的对象列表
76 foreach (var item in triggers)
77 {
78 this.SubscribedEvents.Remove(item);
79 }
80 }
81 }
82
83 /// <summary>
84 /// 添加一个事件到计时器
85 /// </summary>
86 /// <param name="info"></param>
87 public void Add(TimerEventInfomation info)
88 {
89 using (Lock.Write())
90 {
91 if (info.EventTime <= GetTime())
92 {
93 return;
94 }
95 Logs.Info($"为活动{info.ActiveID}新增计时器 -> " + Newtonsoft.Json.JsonConvert.SerializeObject(info));
96 this.SubscribedEvents.Add(info);
97 }
98 }
99
100 /// <summary>
101 /// 无则新增,有则更新,新增返回true,更新返回false
102 /// </summary>
103 /// <param name="info"></param>
104 public bool Set(TimerEventInfomation info)
105 {
106 using (Lock.Write())
107 {
108 var obj = this.SubscribedEvents.Where(t => t.ActiveID == info.ActiveID && t.Category == info.Category).FirstOrDefault();
109 if (obj == null)
110 {
111 obj.EventTime = info.EventTime;
112 obj.callbackObject = info.callbackObject;
113 obj.EventCallback = info.EventCallback;
114 Logs.Info($"为活动{info.ActiveID}更新计时器 -> " + Newtonsoft.Json.JsonConvert.SerializeObject(info));
115 return false;
116 }
117 else
118 {
119 this.SubscribedEvents.Add(info);
120 Logs.Info($"为活动{info.ActiveID}新增计时器 -> " + Newtonsoft.Json.JsonConvert.SerializeObject(info));
121 return true;
122 }
123 }
124 }
125
126 /// <summary>
127 /// 清空指定活动的计时器
128 /// </summary>
129 public int Remove(int ActiveID)
130 {
131 using (Lock.Write())
132 {
133 var Removes = this.SubscribedEvents.FindAll(t => t.ActiveID == ActiveID).ToList();
134 if (Removes != null && Removes.Count > 0)
135 {
136 Logs.Info($"移除活动{ActiveID}全部计时器 -> " + Newtonsoft.Json.JsonConvert.SerializeObject(Removes));
137 }
138 return this.SubscribedEvents.RemoveAll(t => t.ActiveID == ActiveID);
139 }
140 }
141
142 /// <summary>
143 /// 移除掉指定类别的计时器,通常应用在举牌倒计时器,或者报名倒计时器,报名人满即将开始时自动清除报名倒计时器,或者活动成功结束后需要清理掉倒计时器
144 /// </summary>
145 /// <param name="ActiveID"></param>
146 /// <param name="category"></param>
147 public int Remove(int ActiveID, TimerEventInfomationCategorys category)
148 {
149 using (Lock.Write())
150 {
151 return this.SubscribedEvents.RemoveAll(t => t.ActiveID == ActiveID && t.Category == category);
152 }
153 }
154
155 /// <summary>
156 /// 重载版本
157 /// </summary>
158 /// <param name="ActiveID"></param>
159 /// <param name="eventTime"></param>
160 /// <param name="sender"></param>
161 /// <param name="callback"></param>
162 public void Add(int ActiveID, DateTime eventTime, object sender, Action<Object> callback)
163 {
164 if (eventTime <= DateTime.Now) { return; }
165 using (Lock.Write())
166 {
167 var info = new TimerEventInfomation() { ActiveID = ActiveID, EventTime = GetTime(eventTime), callbackObject = sender, EventCallback = callback };
168 Logs.Info($"为活动{info.ActiveID}新增计时器 -> " + Newtonsoft.Json.JsonConvert.SerializeObject(info));
169 this.SubscribedEvents.Add(info);
170 }
171 }
172
173 /// <summary>
174 /// 用于重置符合指定条件的计时器计时时间
175 /// </summary>
176 /// <param name="ActiveID"></param>
177 /// <param name="category"></param>
178 /// <param name="time"></param>
179 public void ResetTime(int ActiveID, TimerEventInfomationCategorys category, DateTime time)
180 {
181 if (time <= DateTime.Now) { return; }
182 using (Lock.Write())
183 {
184 var ms = this.SubscribedEvents.Where(t => t.ActiveID == ActiveID && t.Category == category).ToList();
185 ms.ForEach(new Action<TimerEventInfomation>((t) =>
186 {
187 t.EventTime = GetTime(time);
188 }));
189 Logs.Info($"为活动{ActiveID}更新类别{category.ToString()}计时器时间 -> " + Newtonsoft.Json.JsonConvert.SerializeObject(ms));
190 }
191 }
192
193 /// <summary>
194 /// 计时器事件消息对象
195 /// </summary>
196 public class TimerEventInfomation
197 {
198 /// <summary>
199 /// 关联此事件的活动ID,用于批量重置或清除指定活动的全部事件
200 /// </summary>
201 public int ActiveID { get; set; }
202
203 /// <summary>
204 /// 标识,用于对计时器事件归类,方便通过该标识结合
205 /// </summary>
206 public TimerEventInfomationCategorys Category { get; set; } = TimerEventInfomationCategorys.通用;
207
208 /// <summary>
209 /// 事件时间,指定事件触发的具体时间
210 /// </summary>
211 public long EventTime { get; set; }
212
213 /// <summary>
214 /// 回调时的参数对象
215 /// </summary>
216 public Object callbackObject = null;
217
218 /// <summary>
219 /// 定时器自动触发的回调事件,当事件引发时,自动触发该回调
220 /// </summary>
221 public Action<Object> EventCallback { get; set; }
222 }
223
224 /// <summary>
225 /// 归类枚举
226 /// </summary>
227 public enum TimerEventInfomationCategorys
228 {
229 通用 = 0,
230 /// <summary>
231 /// 表明活动已经开始,举牌进行中,等待目标时间表明倒计时时间已到
232 /// </summary>
233 落拍倒计时 = 2,
234 /// <summary>
235 /// 应用于定时开拍类活动,表示定时开拍,非定拍类活动不会使用到此枚举
236 /// </summary>
237 定拍倒计时 = 3,
238 /// <summary>
239 /// 开拍倒计时,指活动正式开始前的30秒倒计时期间,定时该计时器用于处理活动正式开始
240 /// </summary>
241 开拍倒计时 = 4,
242 /// <summary>
243 /// 托管自动举牌,人工出价类,每次有人出价时,自动重置,用于从托管用户中获取一个用户自动执行举牌,时间为倒计时剩余3秒时。举牌的同时自动重置。
244 /// </summary>
245 托管自动举牌 = 5,
246 /// <summary>
247 /// 提供给新活动自动轮询的计时器对象
248 /// </summary>
249 新活动轮询 = 6
250 }
251 }