OSDN Git Service

NotificationManagerでタイマーをリピートをサポートする
authorKazuhiro Fujieda <fujieda@users.osdn.me>
Tue, 7 Nov 2017 14:30:02 +0000 (23:30 +0900)
committerKazuhiro Fujieda <fujieda@users.osdn.me>
Sat, 27 Jan 2018 08:33:48 +0000 (17:33 +0900)
KancolleSniffer.Test/NotificationManagerTest.cs
KancolleSniffer/KancolleSniffer.csproj
KancolleSniffer/NotificationManager.cs

index b685f31..c23afcd 100644 (file)
@@ -23,8 +23,15 @@ namespace KancolleSniffer.Test
     {\r
         private class MockTimer : NotificationManager.ITimer\r
         {\r
-            private int _elapsed;\r
+            private int _elapsed, _totalElapsed;\r
             private bool _enabled;\r
+            private DateTime _start = new DateTime(2017, 11, 1);\r
+            private DateTime _now;\r
+\r
+            public MockTimer()\r
+            {\r
+                _now = _start;\r
+            }\r
 \r
             public int Interval { get; set; }\r
 \r
@@ -34,6 +41,7 @@ namespace KancolleSniffer.Test
                 set\r
                 {\r
                     _enabled = value;\r
+                    _start += TimeSpan.FromMilliseconds(_elapsed);\r
                     _elapsed = 0;\r
                 }\r
             }\r
@@ -50,16 +58,26 @@ namespace KancolleSniffer.Test
                 Enabled = false;\r
             }\r
 \r
+            public DateTime Now => _now;\r
+\r
+            public int Elapsed => _totalElapsed;\r
+\r
             public void ElapseTime(int millis)\r
             {\r
+                _totalElapsed += millis;\r
                 if (!Enabled)\r
+                {\r
+                    _now = _start += TimeSpan.FromMilliseconds(millis);\r
                     return;\r
+                }\r
                 var after = _elapsed + millis;\r
                 for (var n = _elapsed / Interval; n < after / Interval; n++)\r
                 {\r
+                    _now = _start + TimeSpan.FromMilliseconds((n + 1) * Interval);\r
                     Tick?.Invoke(this, EventArgs.Empty);\r
                 }\r
                 _elapsed = after;\r
+                _now = _start + TimeSpan.FromMilliseconds(_elapsed);\r
             }\r
         }\r
 \r
@@ -126,5 +144,161 @@ namespace KancolleSniffer.Test
             timer.ElapseTime(1000);\r
             PAssert.That(() => new Message {Title = "建造が終わりました", Body = "第二ドック", Name = "建造完了"}.Equals(result));\r
         }\r
+\r
+        /// <summary>\r
+        /// 通知をリピートさせる\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void SingleRepeatableNotification()\r
+        {\r
+            var timer = new MockTimer();\r
+            Message result = null;\r
+            var manager =\r
+                new NotificationManager((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, timer);\r
+            var expected = new Message {Title = "遠征が終わりました", Body = "防空射撃演習", Name = "遠征終了"};\r
+            while (true)\r
+            {\r
+                switch (timer.Elapsed)\r
+                {\r
+                    case 0:\r
+                        manager.Enqueue("遠征終了", "防空射撃演習", 2);\r
+                        PAssert.That(() => expected.Equals(result));\r
+                        break;\r
+                    case 2000:\r
+                        PAssert.That(() => expected.Equals(result));\r
+                        break;\r
+                    case 4000:\r
+                        PAssert.That(() => expected.Equals(result));\r
+                        return;\r
+                    default:\r
+                        PAssert.That(() => result == null, timer.Elapsed.ToString());\r
+                        break;\r
+                }\r
+                result = null;\r
+                timer.ElapseTime(1000);\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// 二つの通知をリピートさせる\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void TwoRepeatableNotofication()\r
+        {\r
+            var timer = new MockTimer();\r
+            Message result = null;\r
+            var manager =\r
+                new NotificationManager((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, timer);\r
+            var ensei = new Message {Title = "遠征が終わりました", Body = "防空射撃演習", Name = "遠征終了"};\r
+            var hakuchi = new Message {Title = "泊地修理 第一艦隊", Body = "20分経過しました。", Name = "泊地修理20分経過"};\r
+            while (true)\r
+            {\r
+                switch (timer.Elapsed)\r
+                {\r
+                    case 0:\r
+                        manager.Enqueue("遠征終了", "防空射撃演習", 10);\r
+                        PAssert.That(() => ensei.Equals(result));\r
+                        break;\r
+                    case 2000:\r
+                        manager.Enqueue("泊地修理20分経過", 0, "", 5);\r
+                        PAssert.That(() => hakuchi.Equals(result));\r
+                        break;\r
+                    case 7000:\r
+                        PAssert.That(() => hakuchi.Equals(result), "泊地修理2回目");\r
+                        break;\r
+                    case 10000:\r
+                        PAssert.That(() => ensei.Equals(result), "遠征終了2回目");\r
+                        return;\r
+                    default:\r
+                        PAssert.That(() => result == null, timer.Elapsed.ToString());\r
+                        break;\r
+                }\r
+                result = null;\r
+                timer.ElapseTime(1000);\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// スケジュールがぶつかる二つの通知をリピートさせる\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void TwoRepeatableNotification1SecDelay()\r
+        {\r
+            var timer = new MockTimer();\r
+            Message result = null;\r
+            var manager =\r
+                new NotificationManager((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, timer);\r
+            var ensei = new Message {Title = "遠征が終わりました", Body = "防空射撃演習", Name = "遠征終了"};\r
+            var hakuchi = new Message {Title = "泊地修理 第一艦隊", Body = "20分経過しました。", Name = "泊地修理20分経過"};\r
+            while (true)\r
+            {\r
+                switch (timer.Elapsed)\r
+                {\r
+                    case 0:\r
+                        manager.Enqueue("遠征終了", "防空射撃演習", 3);\r
+                        PAssert.That(() => ensei.Equals(result));\r
+                        break;\r
+                    case 1000:\r
+                        manager.Enqueue("泊地修理20分経過", 0, "", 2);\r
+                        break;\r
+                    case 2000:\r
+                        PAssert.That(() => hakuchi.Equals(result));\r
+                        break;\r
+                    case 4000:\r
+                        PAssert.That(() => ensei.Equals(result), "遠征終了2回目");\r
+                        break;\r
+                    case 6000:\r
+                        PAssert.That(() => hakuchi.Equals(result), "泊地修理2回目");\r
+                        return;\r
+                    default:\r
+                        PAssert.That(() => result == null, timer.Elapsed.ToString());\r
+                        break;\r
+                }\r
+                result = null;\r
+                timer.ElapseTime(1000);\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// リピートしている通知を止める\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void RemoveRepeatableNotification()\r
+        {\r
+            var timer = new MockTimer();\r
+            Message result = null;\r
+            var manager =\r
+                new NotificationManager((t, b, n) => { result = new Message {Title = t, Body = b, Name = n}; }, timer);\r
+            var ensei = new Message {Title = "遠征が終わりました", Body = "防空射撃演習", Name = "遠征終了"};\r
+            var hakuchi = new Message {Title = "入渠が終わりました", Body = "綾波改二", Name = "入渠終了"};\r
+            while (true)\r
+            {\r
+                switch (timer.Elapsed)\r
+                {\r
+                    case 0:\r
+                        manager.Enqueue("遠征終了", "防空射撃演習", 10);\r
+                        PAssert.That(() => ensei.Equals(result));\r
+                        break;\r
+                    case 2000:\r
+                        manager.Enqueue("入渠終了", "綾波改二", 5);\r
+                        PAssert.That(() => hakuchi.Equals(result));\r
+                        break;\r
+                    case 3000:\r
+                        manager.StopRepeat("入渠終了");\r
+                        break;\r
+                    case 7000:\r
+                        PAssert.That(() => result == null, "入渠終了2回目はない");\r
+                        break;\r
+                    case 10000:\r
+                        PAssert.That(() => ensei.Equals(result), "遠征終了2回目");\r
+                        return;\r
+                    default:\r
+                        PAssert.That(() => result == null, timer.Elapsed.ToString());\r
+                        break;\r
+                }\r
+                result = null;\r
+                timer.ElapseTime(1000);\r
+            }\r
+        }\r
     }\r
 }
\ No newline at end of file
index d7ce292..e9de585 100644 (file)
@@ -25,6 +25,7 @@
     <Prefer32Bit>false</Prefer32Bit>\r
     <DocumentationFile>\r
     </DocumentationFile>\r
+    <LangVersion>latest</LangVersion>\r
   </PropertyGroup>\r
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">\r
     <PlatformTarget>AnyCPU</PlatformTarget>\r
@@ -35,6 +36,7 @@
     <ErrorReport>prompt</ErrorReport>\r
     <WarningLevel>4</WarningLevel>\r
     <Prefer32Bit>false</Prefer32Bit>\r
+    <LangVersion>latest</LangVersion>\r
   </PropertyGroup>\r
   <PropertyGroup>\r
     <ApplicationIcon>app.ico</ApplicationIcon>\r
index 708c130..3c58d7c 100644 (file)
@@ -15,6 +15,7 @@
 using System;\r
 using System.Collections.Generic;\r
 using System.IO;\r
+using System.Linq;\r
 using System.Windows.Forms;\r
 \r
 namespace KancolleSniffer\r
@@ -28,27 +29,34 @@ namespace KancolleSniffer
             public string Key { get; set; }\r
             public int Fleet { get; set; }\r
             public string Subject { get; set; }\r
+            public int Repeat { get; set; }\r
+            public DateTime Schedule { get; set; }\r
         }\r
 \r
         public NotificationManager(Action<string, string, string> ring, ITimer timer = null)\r
         {\r
-\r
             _notificationQueue = new NotificationQueue(ring, timer);\r
         }\r
 \r
-        public void Enqueue(string key, int fleet, string subject)\r
+        public void Enqueue(string key, int fleet, string subject, int repeat = 0)\r
         {\r
             _notificationQueue.Enqueue(new Notification\r
             {\r
                 Key = key,\r
                 Fleet = fleet,\r
-                Subject = subject\r
+                Subject = subject,\r
+                Repeat = repeat\r
             });\r
         }\r
 \r
-        public void Enqueue(string key, string subject)\r
+        public void Enqueue(string key, string subject, int repeat = 0)\r
         {\r
-            Enqueue(key, 0, subject);\r
+            Enqueue(key, 0, subject, repeat);\r
+        }\r
+\r
+        public void StopRepeat(string key)\r
+        {\r
+            _notificationQueue.StopRepeat(key);\r
         }\r
 \r
         private class NotificationConfig\r
@@ -235,6 +243,7 @@ namespace KancolleSniffer
             event EventHandler Tick;\r
             void Start();\r
             void Stop();\r
+            DateTime Now { get; }\r
         }\r
 \r
         public class TimerWrapper : ITimer\r
@@ -262,20 +271,23 @@ namespace KancolleSniffer
             public void Start() => _timer.Start();\r
 \r
             public void Stop() => _timer.Stop();\r
+\r
+            public DateTime Now => DateTime.Now;\r
         }\r
 \r
         private class NotificationQueue\r
         {\r
             private readonly Action<string, string, string> _ring;\r
-            private readonly Queue<Notification> _queue = new Queue<Notification>();\r
+            private readonly List<Notification> _queue = new List<Notification>();\r
             private readonly ITimer _timer;\r
             private readonly NotificationConfig _notificationConfig = new NotificationConfig();\r
+            private DateTime _lastRing;\r
 \r
-            public NotificationQueue(Action<string, string, string> ring, ITimer timer)\r
+            public NotificationQueue(Action<string, string, string> ring, ITimer timer = null)\r
             {\r
                 _ring = ring;\r
                 _timer = timer ?? new TimerWrapper();\r
-                _timer.Interval = 2000;\r
+                _timer.Interval = 1000;\r
                 _timer.Tick += TimerOnTick;\r
             }\r
 \r
@@ -286,28 +298,42 @@ namespace KancolleSniffer
                     _timer.Stop();\r
                     return;\r
                 }\r
-                var notification = _queue.Dequeue();\r
-                Ring(notification);\r
+                Ring();\r
             }\r
 \r
             public void Enqueue(Notification notification)\r
             {\r
-                if (_timer.Enabled)\r
+                _queue.Add(notification);\r
+                Ring();\r
+                if (_queue.Count > 0)\r
+                    _timer.Start();\r
+            }\r
+\r
+            public void StopRepeat(string key)\r
+            {\r
+                _queue.RemoveAll(n => n.Key.Substring(0, 4) == key.Substring(0, 4) && n.Schedule != default);\r
+            }\r
+\r
+            private void Ring()\r
+            {\r
+                var now = _timer.Now;\r
+                if (now - _lastRing < TimeSpan.FromSeconds(2))\r
+                    return;\r
+                var notification = _queue.FirstOrDefault(n => n.Schedule.CompareTo(now) <= 0);\r
+                if (notification == null)\r
+                    return;\r
+                if (notification.Repeat == 0)\r
                 {\r
-                    _queue.Enqueue(notification);\r
+                    _queue.Remove(notification);\r
                 }\r
                 else\r
                 {\r
-                    Ring(notification);\r
-                    _timer.Start();\r
+                    notification.Schedule = _timer.Now + TimeSpan.FromSeconds(notification.Repeat);\r
                 }\r
-            }\r
-\r
-            private void Ring(Notification notification)\r
-            {\r
                 var message =\r
                     _notificationConfig.GenerateMessage(notification);\r
                 _ring(message.Title, message.Body, message.Name);\r
+                _lastRing = now;\r
             }\r
         }\r
     }\r