├── readme.md
├── src
├── Examples
│ ├── WebSocketMessageOnTimer
│ │ ├── Global.asax
│ │ ├── Models
│ │ │ └── TimeRecord.cs
│ │ ├── Controllers
│ │ │ ├── TimeController.cs
│ │ │ └── WsTimeController.cs
│ │ ├── Global.asax.cs
│ │ ├── App_Start
│ │ │ └── WebApiConfig.cs
│ │ ├── packages.config
│ │ ├── Web.Debug.config
│ │ ├── Web.Release.config
│ │ ├── index.html
│ │ ├── Properties
│ │ │ └── AssemblyInfo.cs
│ │ ├── Web.config
│ │ ├── jquery-dateFormat.min.js
│ │ ├── WebSocketMessageOnTimer.csproj
│ │ └── TaskTimer.cs
│ ├── WpfTimer
│ │ ├── packages.config
│ │ ├── App.config
│ │ ├── Properties
│ │ │ ├── Settings.settings
│ │ │ ├── Settings.Designer.cs
│ │ │ ├── AssemblyInfo.cs
│ │ │ ├── Resources.Designer.cs
│ │ │ └── Resources.resx
│ │ ├── App.xaml
│ │ ├── App.xaml.cs
│ │ ├── MainWindow.xaml
│ │ ├── MainWindow.xaml.cs
│ │ ├── WpfTimer.csproj
│ │ └── TaskTimer.cs
│ ├── WebRequestOnTimer
│ │ ├── packages.config
│ │ ├── App.config
│ │ ├── WebRequestOnTimer.sln
│ │ ├── Properties
│ │ │ └── AssemblyInfo.cs
│ │ ├── WebRequestOnTimer.csproj
│ │ └── Program.cs
│ ├── SimpleTimer
│ │ ├── app.config
│ │ ├── SimpleTimer.sln
│ │ ├── Program.cs
│ │ ├── Properties
│ │ │ └── AssemblyInfo.cs
│ │ └── SimpleTimer.csproj
│ ├── TickUntilKeyPress
│ │ ├── App.config
│ │ ├── TickUntilKeyPress.sln
│ │ ├── Program.cs
│ │ ├── Properties
│ │ │ └── AssemblyInfo.cs
│ │ └── TickUntilKeyPress.csproj
│ └── Examples.sln
├── UnitTests
│ ├── UnitTests.sln
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── TaskTimerUnitTests.csproj
│ └── TaskTimerTests.cs
└── TaskTimer.cs
├── nuget
├── build.bat
└── TaskTimer.nuspec
└── .gitignore
/readme.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ikriv/tasktimer/HEAD/readme.md
--------------------------------------------------------------------------------
/src/Examples/WebSocketMessageOnTimer/Global.asax:
--------------------------------------------------------------------------------
1 | <%@ Application Codebehind="Global.asax.cs" Inherits="WebSocketMessageOnTimer.WebApiApplication" Language="C#" %>
2 |
--------------------------------------------------------------------------------
/src/Examples/WpfTimer/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/nuget/build.bat:
--------------------------------------------------------------------------------
1 | mkdir bin
2 | copy *.nuspec bin
3 |
4 | mkdir bin\content
5 | copy ..\src\TaskTimer.cs bin\content
6 |
7 | pushd bin
8 | nuget pack TaskTimer.nuspec
9 | popd
10 |
11 |
--------------------------------------------------------------------------------
/src/Examples/WebRequestOnTimer/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/Examples/SimpleTimer/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/Examples/WpfTimer/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/Examples/TickUntilKeyPress/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/Examples/WebRequestOnTimer/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/Examples/WpfTimer/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/Examples/WebSocketMessageOnTimer/Models/TimeRecord.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Newtonsoft.Json;
3 |
4 | namespace WebSocketMessageOnTimer.Models
5 | {
6 | public class TimeRecord
7 | {
8 | [JsonProperty("timeUtc")]
9 | public DateTime TimeUtc { get; set; }
10 | }
11 | }
--------------------------------------------------------------------------------
/src/Examples/WpfTimer/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/Examples/WpfTimer/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Data;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 |
9 | namespace WpfTimer
10 | {
11 | ///
12 | /// Interaction logic for App.xaml
13 | ///
14 | public partial class App : Application
15 | {
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Examples/WebSocketMessageOnTimer/Controllers/TimeController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Web.Http;
3 | using WebSocketMessageOnTimer.Models;
4 |
5 | namespace WebSocketMessageOnTimer.Controllers
6 | {
7 | public class TimeController : ApiController
8 | {
9 | public TimeRecord GetTime()
10 | {
11 | return new TimeRecord { TimeUtc = DateTime.UtcNow };
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/Examples/WebSocketMessageOnTimer/Global.asax.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Web;
5 | using System.Web.Http;
6 | using System.Web.Routing;
7 |
8 | namespace WebSocketMessageOnTimer
9 | {
10 | public class WebApiApplication : System.Web.HttpApplication
11 | {
12 | protected void Application_Start()
13 | {
14 | GlobalConfiguration.Configure(WebApiConfig.Register);
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #OS junk files
2 | [Tt]humbs.db
3 | *.DS_Store
4 |
5 | #Visual Studio files
6 | *.[Oo]bj
7 | *.user
8 | *.aps
9 | *.pch
10 | *.vspscc
11 | *.vssscc
12 | *_i.c
13 | *_p.c
14 | *.ncb
15 | *.suo
16 | *.tlb
17 | *.tlh
18 | *.bak
19 | *.[Cc]ache
20 | *.ilk
21 | *.log
22 | *.lib
23 | *.sbr
24 | *.sdf
25 | *.opensdf
26 | *.unsuccessfulbuild
27 | ipch/
28 | obj/
29 | [Bb]in
30 | [Dd]ebug*/
31 | [Rr]elease*/
32 | .vs/
33 |
34 | #Tooling
35 | _ReSharper*/
36 | *.resharper
37 | [Tt]est[Rr]esult*
38 |
39 | #Project files
40 | [Bb]uild/
41 |
42 | #Subversion files
43 | .svn
44 |
45 | # Office Temp Files
46 | ~$*
47 |
48 | #NuGet
49 | packages/
50 |
51 | # visual studio database projects
52 | *.dbmdl
--------------------------------------------------------------------------------
/src/Examples/WebSocketMessageOnTimer/App_Start/WebApiConfig.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Web.Http;
5 |
6 | namespace WebSocketMessageOnTimer
7 | {
8 | public static class WebApiConfig
9 | {
10 | public static void Register(HttpConfiguration config)
11 | {
12 | // Web API configuration and services
13 |
14 | // Web API routes
15 | config.MapHttpAttributeRoutes();
16 |
17 | config.Routes.MapHttpRoute(
18 | name: "DefaultApi",
19 | routeTemplate: "api/{controller}/{id}",
20 | defaults: new { id = RouteParameter.Optional }
21 | );
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Examples/WebSocketMessageOnTimer/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/Examples/WpfTimer/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/Examples/SimpleTimer/SimpleTimer.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleTimer", "SimpleTimer.csproj", "{E5726784-FEE1-444A-92C9-F297DCD955F9}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {E5726784-FEE1-444A-92C9-F297DCD955F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {E5726784-FEE1-444A-92C9-F297DCD955F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {E5726784-FEE1-444A-92C9-F297DCD955F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {E5726784-FEE1-444A-92C9-F297DCD955F9}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/src/UnitTests/UnitTests.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TaskTimerUnitTests", "TaskTimerUnitTests.csproj", "{E10591A4-00EB-45D9-82E2-139F67631BCB}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {E10591A4-00EB-45D9-82E2-139F67631BCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {E10591A4-00EB-45D9-82E2-139F67631BCB}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {E10591A4-00EB-45D9-82E2-139F67631BCB}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {E10591A4-00EB-45D9-82E2-139F67631BCB}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/src/Examples/TickUntilKeyPress/TickUntilKeyPress.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TickUntilKeyPress", "TickUntilKeyPress.csproj", "{9A657E96-422E-488B-953F-5DC6BD4E0799}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {9A657E96-422E-488B-953F-5DC6BD4E0799}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {9A657E96-422E-488B-953F-5DC6BD4E0799}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {9A657E96-422E-488B-953F-5DC6BD4E0799}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {9A657E96-422E-488B-953F-5DC6BD4E0799}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/src/Examples/WebRequestOnTimer/WebRequestOnTimer.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebRequestOnTimer", "WebRequestOnTimer.csproj", "{8F82B944-AB79-4511-ACCF-C4809630D95D}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {8F82B944-AB79-4511-ACCF-C4809630D95D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {8F82B944-AB79-4511-ACCF-C4809630D95D}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {8F82B944-AB79-4511-ACCF-C4809630D95D}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {8F82B944-AB79-4511-ACCF-C4809630D95D}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/nuget/TaskTimer.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | TaskTimer
5 | 1.0.0
6 | Ivan Krivyakov
7 | ikriv
8 | https://www.apache.org/licenses/LICENSE-2.0
9 | https://github.com/ikriv/tasktimer
10 |
11 | false
12 | First release
13 | TaskTimer
14 | Generates TPL Task on timer, similar to Observable.Interval
15 | Class that returns a series of tasks that become completed on timer,
16 | similar in nature to Observable.Interval(). This allows to use timer-based activities
17 | in async/await methods with better precision than Task.Delay().
18 | Copyright (c) 2017 Ivan Krivyakov
19 | C#
20 | tpl multithreading timer observable
21 |
22 |
--------------------------------------------------------------------------------
/src/Examples/WpfTimer/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace WpfTimer.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Examples/SimpleTimer/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Linq;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 | using IKriv.Threading.Tasks;
7 |
8 | namespace SimpleTimer
9 | {
10 | class Program
11 | {
12 | private static void PrintCurrentTime()
13 | {
14 | Console.WriteLine(DateTime.UtcNow.ToString("HH:mm:ss.fff", CultureInfo.InvariantCulture));
15 | }
16 |
17 | private static async Task UseTimer()
18 | {
19 | PrintCurrentTime();
20 | Console.WriteLine("Starting timer...");
21 | var now = DateTime.UtcNow;
22 | var lastSecond = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, DateTimeKind.Utc);
23 | var nextSecond = lastSecond.AddSeconds(1);
24 |
25 | using (var timer = new TaskTimer(1000).StartAt(nextSecond))
26 | {
27 | foreach (var task in timer.Take(10))
28 | {
29 | await task;
30 | PrintCurrentTime();
31 | }
32 | }
33 |
34 | Console.WriteLine("Done");
35 | }
36 |
37 | public static void Main(string[] args)
38 | {
39 | UseTimer().Wait();
40 | }
41 |
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Examples/WebSocketMessageOnTimer/Web.Debug.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
17 |
18 |
29 |
30 |
--------------------------------------------------------------------------------
/src/Examples/WebSocketMessageOnTimer/Web.Release.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
17 |
18 |
19 |
30 |
31 |
--------------------------------------------------------------------------------
/src/Examples/WebSocketMessageOnTimer/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Web Sockets Test
5 |
6 |
10 |
11 |
12 |
13 |
14 | Web Sockets Test
15 | Awaiting server response...
16 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/Examples/TickUntilKeyPress/Program.cs:
--------------------------------------------------------------------------------
1 | using IKriv.Threading.Tasks;
2 | using System;
3 | using System.Globalization;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace TickUntilKeyPress
8 | {
9 | class Program
10 | {
11 | private static void PrintCurrentTime()
12 | {
13 | Console.WriteLine(DateTime.UtcNow.ToString("HH:mm:ss.fff", CultureInfo.InvariantCulture));
14 | }
15 |
16 | private static async Task Tick(CancellationToken token)
17 | {
18 | using (var timer = new TaskTimer(2000).CancelWith(token).Start())
19 | {
20 | try
21 | {
22 | foreach (var task in timer)
23 | {
24 | await task;
25 | PrintCurrentTime();
26 | }
27 | }
28 | catch (TaskCanceledException)
29 | {
30 | Console.WriteLine("Timer Canceled");
31 | }
32 | }
33 | }
34 |
35 | public static void Main()
36 | {
37 | Console.WriteLine("Press ENTER to stop timer");
38 | var src = new CancellationTokenSource();
39 | var task = Tick(src.Token);
40 | Console.ReadLine();
41 | src.Cancel();
42 | // ReSharper disable once MethodSupportsCancellation
43 | task.Wait();
44 | Console.WriteLine("Done");
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Examples/WebSocketMessageOnTimer/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("WebSocketMessageOnTimer")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("WebSocketMessageOnTimer")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("4c58eb91-ad55-49e3-83bd-f5dac6ecef4f")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Revision and Build Numbers
33 | // by using the '*' as shown below:
34 | [assembly: AssemblyVersion("1.0.0.0")]
35 | [assembly: AssemblyFileVersion("1.0.0.0")]
36 |
--------------------------------------------------------------------------------
/src/Examples/SimpleTimer/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("SimpleTimer")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("SimpleTimer")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("e5726784-fee1-444a-92c9-f297dcd955f9")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/src/UnitTests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("TaskTimerUnitTests")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("TaskTimerUnitTests")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("e10591a4-00eb-45d9-82e2-139f67631bcb")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/src/Examples/TickUntilKeyPress/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("TickUntilKeyPress")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("TickUntilKeyPress")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("9a657e96-422e-488b-953f-5dc6bd4e0799")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/src/Examples/WebRequestOnTimer/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("WebRequestOnTimer")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("WebRequestOnTimer")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("8f82b944-ab79-4511-accf-c4809630d95d")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/src/Examples/WpfTimer/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Runtime.CompilerServices;
4 | using System.Windows;
5 | using IKriv.Threading.Tasks;
6 |
7 | namespace WpfTimer
8 | {
9 | ///
10 | /// Interaction logic for MainWindow.xaml
11 | ///
12 | public partial class MainWindow : INotifyPropertyChanged
13 | {
14 | public MainWindow()
15 | {
16 | InitializeComponent();
17 | DataContext = this;
18 | CurrentTimeStr = "Initializing...";
19 | SampleText.Focus();
20 | Loaded += StartTimer;
21 | }
22 |
23 | public string CurrentTimeStr
24 | {
25 | get { return _currentTimeStr; }
26 | set { _currentTimeStr = value; OnPropertyChanged(); }
27 | }
28 | private string _currentTimeStr;
29 |
30 | public event PropertyChangedEventHandler PropertyChanged;
31 |
32 | protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
33 | {
34 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
35 | }
36 |
37 | private async void StartTimer(object sender, RoutedEventArgs args)
38 | {
39 | using (var timer = new TaskTimer(1000).Start())
40 | {
41 | foreach (var tick in timer)
42 | {
43 | await tick;
44 | CurrentTimeStr = DateTime.Now.ToString("MMM dd yyyy HH:mm:ss.fff");
45 | }
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Examples/WebSocketMessageOnTimer/Web.config:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
42 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/Examples/WpfTimer/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Resources;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using System.Windows;
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | [assembly: AssemblyTitle("WpfTimer")]
11 | [assembly: AssemblyDescription("")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("")]
14 | [assembly: AssemblyProduct("WpfTimer")]
15 | [assembly: AssemblyCopyright("Copyright © 2017")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | [assembly: ComVisible(false)]
23 |
24 | //In order to begin building localizable applications, set
25 | //CultureYouAreCodingWith in your .csproj file
26 | //inside a . For example, if you are using US english
27 | //in your source files, set the to en-US. Then uncomment
28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in
29 | //the line below to match the UICulture setting in the project file.
30 |
31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
32 |
33 |
34 | [assembly: ThemeInfo(
35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
36 | //(used if a resource is not found in the page,
37 | // or application resource dictionaries)
38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
39 | //(used if a resource is not found in the page,
40 | // app, or any theme specific resource dictionaries)
41 | )]
42 |
43 |
44 | // Version information for an assembly consists of the following four values:
45 | //
46 | // Major Version
47 | // Minor Version
48 | // Build Number
49 | // Revision
50 | //
51 | // You can specify all the values or you can default the Build and Revision Numbers
52 | // by using the '*' as shown below:
53 | // [assembly: AssemblyVersion("1.0.*")]
54 | [assembly: AssemblyVersion("1.0.0.0")]
55 | [assembly: AssemblyFileVersion("1.0.0.0")]
56 |
--------------------------------------------------------------------------------
/src/Examples/TickUntilKeyPress/TickUntilKeyPress.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {9A657E96-422E-488B-953F-5DC6BD4E0799}
8 | Exe
9 | Properties
10 | TickUntilKeyPress
11 | TickUntilKeyPress
12 | v4.5
13 | 512
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | AnyCPU
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | TaskTimer.cs
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
62 |
--------------------------------------------------------------------------------
/src/Examples/SimpleTimer/SimpleTimer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {E5726784-FEE1-444A-92C9-F297DCD955F9}
8 | Exe
9 | Properties
10 | SimpleTimer
11 | SimpleTimer
12 | v4.5
13 | 512
14 |
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 | false
26 |
27 |
28 | AnyCPU
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 | false
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | TaskTimer.cs
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
64 |
--------------------------------------------------------------------------------
/src/Examples/WpfTimer/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace WpfTimer.Properties
12 | {
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources
26 | {
27 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources()
34 | {
35 | }
36 |
37 | ///
38 | /// Returns the cached ResourceManager instance used by this class.
39 | ///
40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
41 | internal static global::System.Resources.ResourceManager ResourceManager
42 | {
43 | get
44 | {
45 | if ((resourceMan == null))
46 | {
47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WpfTimer.Properties.Resources", typeof(Resources).Assembly);
48 | resourceMan = temp;
49 | }
50 | return resourceMan;
51 | }
52 | }
53 |
54 | ///
55 | /// Overrides the current thread's CurrentUICulture property for all
56 | /// resource lookups using this strongly typed resource class.
57 | ///
58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
59 | internal static global::System.Globalization.CultureInfo Culture
60 | {
61 | get
62 | {
63 | return resourceCulture;
64 | }
65 | set
66 | {
67 | resourceCulture = value;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/Examples/Examples.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleTimer", "SimpleTimer\SimpleTimer.csproj", "{E5726784-FEE1-444A-92C9-F297DCD955F9}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TickUntilKeyPress", "TickUntilKeyPress\TickUntilKeyPress.csproj", "{9A657E96-422E-488B-953F-5DC6BD4E0799}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebRequestOnTimer", "WebRequestOnTimer\WebRequestOnTimer.csproj", "{8F82B944-AB79-4511-ACCF-C4809630D95D}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebSocketMessageOnTimer", "WebSocketMessageOnTimer\WebSocketMessageOnTimer.csproj", "{4C58EB91-AD55-49E3-83BD-F5DAC6ECEF4F}"
13 | EndProject
14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfTimer", "WpfTimer\WpfTimer.csproj", "{65C863CA-60C9-4CD2-A62C-EE9DC356E293}"
15 | EndProject
16 | Global
17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
18 | Debug|Any CPU = Debug|Any CPU
19 | Release|Any CPU = Release|Any CPU
20 | EndGlobalSection
21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
22 | {E5726784-FEE1-444A-92C9-F297DCD955F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {E5726784-FEE1-444A-92C9-F297DCD955F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {E5726784-FEE1-444A-92C9-F297DCD955F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {E5726784-FEE1-444A-92C9-F297DCD955F9}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {9A657E96-422E-488B-953F-5DC6BD4E0799}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {9A657E96-422E-488B-953F-5DC6BD4E0799}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {9A657E96-422E-488B-953F-5DC6BD4E0799}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {9A657E96-422E-488B-953F-5DC6BD4E0799}.Release|Any CPU.Build.0 = Release|Any CPU
30 | {8F82B944-AB79-4511-ACCF-C4809630D95D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {8F82B944-AB79-4511-ACCF-C4809630D95D}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {8F82B944-AB79-4511-ACCF-C4809630D95D}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {8F82B944-AB79-4511-ACCF-C4809630D95D}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {4C58EB91-AD55-49E3-83BD-F5DAC6ECEF4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {4C58EB91-AD55-49E3-83BD-F5DAC6ECEF4F}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {4C58EB91-AD55-49E3-83BD-F5DAC6ECEF4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {4C58EB91-AD55-49E3-83BD-F5DAC6ECEF4F}.Release|Any CPU.Build.0 = Release|Any CPU
38 | {65C863CA-60C9-4CD2-A62C-EE9DC356E293}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {65C863CA-60C9-4CD2-A62C-EE9DC356E293}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 | {65C863CA-60C9-4CD2-A62C-EE9DC356E293}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 | {65C863CA-60C9-4CD2-A62C-EE9DC356E293}.Release|Any CPU.Build.0 = Release|Any CPU
42 | EndGlobalSection
43 | GlobalSection(SolutionProperties) = preSolution
44 | HideSolutionNode = FALSE
45 | EndGlobalSection
46 | EndGlobal
47 |
--------------------------------------------------------------------------------
/src/Examples/WebSocketMessageOnTimer/Controllers/WsTimeController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Net;
4 | using System.Net.Http;
5 | using System.Net.WebSockets;
6 | using System.Text;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 | using System.Web;
10 | using System.Web.Http;
11 | using System.Web.WebSockets;
12 | using IKriv.Threading.Tasks;
13 | using Newtonsoft.Json;
14 | using WebSocketMessageOnTimer.Models;
15 |
16 | namespace WebSocketMessageOnTimer.Controllers
17 | {
18 | public class WsTimeController : ApiController
19 | {
20 | [HttpGet]
21 | public HttpResponseMessage GetMessage()
22 | {
23 | var status = HttpStatusCode.BadRequest;
24 | var context = HttpContext.Current;
25 | if (context.IsWebSocketRequest)
26 | {
27 | context.AcceptWebSocketRequest(ProcessRequest);
28 | status = HttpStatusCode.SwitchingProtocols;
29 |
30 | }
31 |
32 | return new HttpResponseMessage(status);
33 | }
34 |
35 | private async Task ProcessRequest(AspNetWebSocketContext context)
36 | {
37 | var ws = context.WebSocket;
38 | await Task.WhenAll(WriteTask(ws), ReadTask(ws));
39 | }
40 |
41 | // MUST read if we want the socket state to be updated
42 | private async Task ReadTask(WebSocket ws)
43 | {
44 | var buffer = new ArraySegment(new byte[1024]);
45 | while (true)
46 | {
47 | await ws.ReceiveAsync(buffer, CancellationToken.None).ConfigureAwait(false);
48 | if (ws.State != WebSocketState.Open) break;
49 | }
50 | }
51 |
52 | private async Task WriteTask(WebSocket ws)
53 | {
54 | using (var timer = new TaskTimer(1000).Start())
55 | {
56 | foreach (var tick in timer)
57 | {
58 | await tick.ConfigureAwait(false);
59 |
60 | EnsureWebSocketIsOpen(ws);
61 | var record = new TimeRecord {TimeUtc = DateTime.UtcNow};
62 | var buffer = Serialize(record);
63 | var sendTask = ws.SendAsync(new ArraySegment(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
64 |
65 | await sendTask.ConfigureAwait(false);
66 | EnsureWebSocketIsOpen(ws);
67 | }
68 | }
69 | }
70 |
71 | private static void EnsureWebSocketIsOpen(WebSocket ws)
72 | {
73 | var state = ws.State;
74 | if (state == WebSocketState.Open) return;
75 |
76 | var message = "Web socket is no longer open: current state is " + state;
77 | System.Diagnostics.Trace.WriteLine(message);
78 | throw new ApplicationException(message);
79 | }
80 |
81 | private static byte[] Serialize(object what)
82 | {
83 | string json = JsonConvert.SerializeObject(what);
84 | var buffer = Encoding.UTF8.GetBytes(json);
85 | return buffer;
86 | }
87 | }
88 | }
--------------------------------------------------------------------------------
/src/Examples/WebRequestOnTimer/WebRequestOnTimer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {8F82B944-AB79-4511-ACCF-C4809630D95D}
8 | Exe
9 | Properties
10 | WebRequestOnTimer
11 | WebRequestOnTimer
12 | v4.5
13 | 512
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | AnyCPU
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 |
36 | packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll
37 | True
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | TaskTimer.cs
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
67 |
--------------------------------------------------------------------------------
/src/Examples/WebSocketMessageOnTimer/jquery-dateFormat.min.js:
--------------------------------------------------------------------------------
1 | /*! jquery-dateFormat 18-05-2015 */
2 | var DateFormat={};!function(a){var b=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],c=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],d=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],e=["January","February","March","April","May","June","July","August","September","October","November","December"],f={Jan:"01",Feb:"02",Mar:"03",Apr:"04",May:"05",Jun:"06",Jul:"07",Aug:"08",Sep:"09",Oct:"10",Nov:"11",Dec:"12"},g=/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.?\d{0,3}[Z\-+]?(\d{2}:?\d{2})?/;a.format=function(){function a(a){return b[parseInt(a,10)]||a}function h(a){return c[parseInt(a,10)]||a}function i(a){var b=parseInt(a,10)-1;return d[b]||a}function j(a){var b=parseInt(a,10)-1;return e[b]||a}function k(a){return f[a]||a}function l(a){var b,c,d,e,f,g=a,h="";return-1!==g.indexOf(".")&&(e=g.split("."),g=e[0],h=e[e.length-1]),f=g.split(":"),3===f.length?(b=f[0],c=f[1],d=f[2].replace(/\s.+/,"").replace(/[a-z]/gi,""),g=g.replace(/\s.+/,"").replace(/[a-z]/gi,""),{time:g,hour:b,minute:c,second:d,millis:h}):{time:"",hour:"",minute:"",second:"",millis:""}}function m(a,b){for(var c=b-String(a).length,d=0;c>d;d++)a="0"+a;return a}return{parseDate:function(a){var b,c,d={date:null,year:null,month:null,dayOfMonth:null,dayOfWeek:null,time:null};if("number"==typeof a)return this.parseDate(new Date(a));if("function"==typeof a.getFullYear)d.year=String(a.getFullYear()),d.month=String(a.getMonth()+1),d.dayOfMonth=String(a.getDate()),d.time=l(a.toTimeString()+"."+a.getMilliseconds());else if(-1!=a.search(g))b=a.split(/[T\+-]/),d.year=b[0],d.month=b[1],d.dayOfMonth=b[2],d.time=l(b[3].split(".")[0]);else switch(b=a.split(" "),6===b.length&&isNaN(b[5])&&(b[b.length]="()"),b.length){case 6:d.year=b[5],d.month=k(b[1]),d.dayOfMonth=b[2],d.time=l(b[3]);break;case 2:c=b[0].split("-"),d.year=c[0],d.month=c[1],d.dayOfMonth=c[2],d.time=l(b[1]);break;case 7:case 9:case 10:d.year=b[3],d.month=k(b[1]),d.dayOfMonth=b[2],d.time=l(b[4]);break;case 1:c=b[0].split(""),d.year=c[0]+c[1]+c[2]+c[3],d.month=c[5]+c[6],d.dayOfMonth=c[8]+c[9],d.time=l(c[13]+c[14]+c[15]+c[16]+c[17]+c[18]+c[19]+c[20]);break;default:return null}return d.date=d.time?new Date(d.year,d.month-1,d.dayOfMonth,d.time.hour,d.time.minute,d.time.second,d.time.millis):new Date(d.year,d.month-1,d.dayOfMonth),d.dayOfWeek=String(d.date.getDay()),d},date:function(b,c){try{var d=this.parseDate(b);if(null===d)return b;for(var e,f=d.year,g=d.month,k=d.dayOfMonth,l=d.dayOfWeek,n=d.time,o="",p="",q="",r=!1,s=0;s=12?"PM":"AM",o="";break;case"p":p+=n.hour>=12?"p.m.":"a.m.",o="";break;case"E":p+=h(l),o="";break;case"'":o="",r=!0;break;default:p+=t,o=""}}return p+=q}catch(w){return console&&console.log&&console.log(w),b}},prettyDate:function(a){var b,c,d;return("string"==typeof a||"number"==typeof a)&&(b=new Date(a)),"object"==typeof a&&(b=new Date(a.toString())),c=((new Date).getTime()-b.getTime())/1e3,d=Math.floor(c/86400),isNaN(d)||0>d?void 0:60>c?"just now":120>c?"1 minute ago":3600>c?Math.floor(c/60)+" minutes ago":7200>c?"1 hour ago":86400>c?Math.floor(c/3600)+" hours ago":1===d?"Yesterday":7>d?d+" days ago":31>d?Math.ceil(d/7)+" weeks ago":d>=31?"more than 5 weeks ago":void 0},toBrowserTimeZone:function(a,b){return this.date(new Date(a),b||"MM/dd/yyyy HH:mm:ss")}}}()}(DateFormat),function(a){a.format=DateFormat.format}(jQuery);
--------------------------------------------------------------------------------
/src/UnitTests/TaskTimerUnitTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | {E10591A4-00EB-45D9-82E2-139F67631BCB}
7 | Library
8 | Properties
9 | TaskTimerUnitTests
10 | TaskTimerUnitTests
11 | v4.5
12 | 512
13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 10.0
15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
17 | False
18 | UnitTest
19 |
20 |
21 | true
22 | full
23 | false
24 | bin\Debug\
25 | DEBUG;TRACE
26 | prompt
27 | 4
28 |
29 |
30 | pdbonly
31 | true
32 | bin\Release\
33 | TRACE
34 | prompt
35 | 4
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | TaskTimer.cs
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | False
64 |
65 |
66 | False
67 |
68 |
69 | False
70 |
71 |
72 | False
73 |
74 |
75 |
76 |
77 |
78 |
79 |
86 |
--------------------------------------------------------------------------------
/src/Examples/WebRequestOnTimer/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Linq;
4 | using System.Net.Http;
5 | using System.Threading.Tasks;
6 | using IKriv.Threading.Tasks;
7 | using Newtonsoft.Json;
8 |
9 | namespace WebRequestOnTimer
10 | {
11 | struct DegMinSec
12 | {
13 | public DegMinSec(double value)
14 | {
15 | Degrees = (int)value;
16 | double min = (Math.Abs(value) - Math.Abs((Degrees)))*60;
17 | Minutes = (int) min;
18 | Seconds = (min - Minutes) * 60;
19 | }
20 |
21 | public int Degrees;
22 | public int Minutes;
23 | public double Seconds;
24 |
25 | public string ToString(bool isLatitude)
26 | {
27 | char suffix = isLatitude
28 | ? (Degrees >= 0 ? 'N' : 'S')
29 | : (Degrees >= 0 ? 'E' : 'W');
30 |
31 | return $"{Math.Abs(Degrees):0}\u00B0{Minutes:00}'{Seconds+0.5:00}\"{suffix}";
32 | }
33 | }
34 |
35 | struct Location
36 | {
37 | public double Latitude;
38 | public double Longitude;
39 |
40 | public override string ToString()
41 | {
42 | return new DegMinSec(Latitude).ToString(true) + " " + new DegMinSec(Longitude).ToString(false);
43 | }
44 | }
45 |
46 | class LocationGenerator
47 | {
48 | private readonly Random _random = new Random(DateTime.UtcNow.Ticks.GetHashCode());
49 |
50 | public Location GetRandomLocation()
51 | {
52 | // To pick a random point on the surface of a unit sphere, it is incorrect to select spherical
53 | // coordinates theta and phi from uniform distributions. If you do, the points will be bunched around the poles.
54 | // See http://mathworld.wolfram.com/SpherePointPicking.html
55 |
56 | var u = _random.NextDouble();
57 | var v = _random.NextDouble();
58 |
59 | return new Location
60 | {
61 | Latitude = Math.Acos(2*u-1) / Math.PI * 180 - 90,
62 | Longitude = -180.0 + v * 360
63 | };
64 | }
65 | }
66 |
67 | #pragma warning disable 0649 // Assigned by deserializer
68 | class DayInfo
69 | {
70 | [JsonProperty("results")] public DayInfoResults Results;
71 | [JsonProperty("status")] public string Status;
72 | }
73 |
74 | class DayInfoResults
75 | {
76 | [JsonProperty("sunrise")] public string Sunrise;
77 | [JsonProperty("sunset")] public string Sunset;
78 | [JsonProperty("day_length")] public string DayLength;
79 | }
80 | #pragma warning restore 0649
81 |
82 | class Program
83 | {
84 | private static Stopwatch _stopwatch;
85 |
86 | private static string GetCurrentTime()
87 | {
88 | return (_stopwatch.ElapsedMilliseconds / 1000.0).ToString("F3");
89 | }
90 |
91 | private static async Task PrintDayInfo(Location location)
92 | {
93 | Console.Write($"{GetCurrentTime()} {location} ");
94 |
95 | try
96 | {
97 | var url = $"https://api.sunrise-sunset.org/json?lat={location.Latitude}&lng={location.Longitude}";
98 | var http = new HttpClient();
99 | var sw = new Stopwatch();
100 | sw.Start();
101 | var json = await http.GetStringAsync(url);
102 | sw.Stop();
103 | var info = JsonConvert.DeserializeObject(json);
104 |
105 | if (info.Status == "OK")
106 | {
107 | Console.WriteLine($"Sunrise: {info.Results.Sunrise}, Day Length: {info.Results.DayLength} ({sw.ElapsedMilliseconds}ms)");
108 | }
109 | else
110 | {
111 | Console.WriteLine("Error: " + info.Status);
112 | }
113 | }
114 | catch (Exception e)
115 | {
116 | Console.WriteLine("ERROR: " + e);
117 | }
118 | }
119 |
120 | private static async Task PrintDayInfoOnTimer()
121 | {
122 | var generator = new LocationGenerator();
123 | using (var timer = new TaskTimer(1000).Start())
124 | {
125 | foreach (var task in timer.Take(20))
126 | {
127 | await task;
128 | await PrintDayInfo(generator.GetRandomLocation());
129 | }
130 | }
131 | }
132 |
133 | static void Main()
134 | {
135 | _stopwatch = new Stopwatch();
136 | _stopwatch.Start();
137 | PrintDayInfoOnTimer().Wait();
138 | }
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/src/Examples/WpfTimer/WpfTimer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {65C863CA-60C9-4CD2-A62C-EE9DC356E293}
8 | WinExe
9 | Properties
10 | WpfTimer
11 | WpfTimer
12 | v4.5
13 | 512
14 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
15 | 4
16 |
17 |
18 | AnyCPU
19 | true
20 | full
21 | false
22 | bin\Debug\
23 | DEBUG;TRACE
24 | prompt
25 | 4
26 |
27 |
28 | AnyCPU
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | 4.0
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | MSBuild:Compile
55 | Designer
56 |
57 |
58 |
59 | MSBuild:Compile
60 | Designer
61 |
62 |
63 | App.xaml
64 | Code
65 |
66 |
67 | MainWindow.xaml
68 | Code
69 |
70 |
71 |
72 |
73 | Code
74 |
75 |
76 | True
77 | True
78 | Resources.resx
79 |
80 |
81 | True
82 | Settings.settings
83 | True
84 |
85 |
86 | ResXFileCodeGenerator
87 | Resources.Designer.cs
88 |
89 |
90 |
91 | SettingsSingleFileGenerator
92 | Settings.Designer.cs
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
107 |
--------------------------------------------------------------------------------
/src/UnitTests/TaskTimerTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using IKriv.Threading.Tasks;
6 | using Microsoft.VisualStudio.TestTools.UnitTesting;
7 |
8 | namespace TaskTimerUnitTests
9 | {
10 | [TestClass]
11 | public class TaskTimerTests
12 | {
13 | private CustomTimer _customTimer;
14 | private Func _getCustomTimer;
15 |
16 | private class CustomTimer : IDisposable
17 | {
18 | private Action _callback;
19 |
20 |
21 | public CustomTimer SetCallback(Action callback)
22 | {
23 | if (_callback != null) throw new InvalidOperationException("Unexpected behavior: timer created more than once");
24 | _callback = callback;
25 | return this;
26 | }
27 |
28 | public bool IsDisposed { get; private set; }
29 |
30 |
31 | public void Tick()
32 | {
33 | _callback();
34 | }
35 |
36 | public void Dispose()
37 | {
38 | IsDisposed = true;
39 | }
40 | }
41 |
42 | private ITaskTimer GetTimer()
43 | {
44 | return new TaskTimer(0).StartOnTimer(_getCustomTimer);
45 | }
46 |
47 | private static bool IsFinished(Task task)
48 | {
49 | return task.IsCompleted || task.IsCanceled || task.IsFaulted;
50 | }
51 |
52 | [TestInitialize]
53 | public void Setup()
54 | {
55 | _customTimer = new CustomTimer();
56 | _getCustomTimer = callback => _customTimer.SetCallback(callback);
57 | }
58 |
59 | [TestMethod]
60 | public void NoTasksAreFinished_UntilTimerTicks()
61 | {
62 | using (var timer = GetTimer())
63 | {
64 | var tasks = timer.Take(10).ToArray();
65 | Assert.IsFalse(tasks.Any(IsFinished));
66 | }
67 | }
68 |
69 | [TestMethod]
70 | public void NumberOfTasksFinished_EqualsNumberOfTimerTicks()
71 | {
72 | using (var timer = GetTimer())
73 | {
74 | var tasks = timer.Take(10).ToArray();
75 |
76 | for (int i = 1; i < 10; ++i)
77 | {
78 | _customTimer.Tick();
79 | Assert.IsTrue(tasks.Take(i).All(IsFinished), $"Expected tasks {i} tasks to be finished");
80 | Assert.IsFalse(tasks.Skip(i).Any(IsFinished), $"Expected tasks after {i} to be not finished");
81 | }
82 | }
83 | }
84 |
85 | [TestMethod]
86 | public void LateTask_ComesAsComplete()
87 | {
88 | using (var timer = GetTimer())
89 | {
90 | _customTimer.Tick();
91 | var firstTask = timer.First();
92 | Assert.IsTrue(firstTask.IsCompleted);
93 | }
94 | }
95 |
96 | [TestMethod]
97 | [ExpectedException(typeof(InvalidOperationException))]
98 | public void CannotEnumerateTimerTwice()
99 | {
100 | using (var timer = GetTimer())
101 | {
102 | var unused = timer.Take(3).ToArray(); // iterate over the timer
103 |
104 | try
105 | {
106 | var unused2 = timer.Take(3).ToArray(); // iterate over the timer again
107 | }
108 | catch (InvalidOperationException e)
109 | {
110 | Assert.AreEqual("Timer cannot be enumerated twice", e.Message);
111 | throw;
112 | }
113 | }
114 | }
115 |
116 | [TestMethod]
117 | public void Dispose_DisposesTimer()
118 | {
119 | var timer = GetTimer();
120 | Assert.IsFalse(_customTimer.IsDisposed);
121 | timer.Dispose();
122 | Assert.IsTrue(_customTimer.IsDisposed);
123 | }
124 |
125 | [TestMethod]
126 | public void Cancel_CancelsAllPendingTasks()
127 | {
128 | var cancelSource = new CancellationTokenSource();
129 |
130 | using (var timer = new TaskTimer(0).CancelWith(cancelSource.Token).StartOnTimer(_getCustomTimer))
131 | {
132 | var tasks = timer.Take(10).ToArray();
133 |
134 | // tick the timer 3 times
135 | for (int i = 0; i < 3; ++i) _customTimer.Tick();
136 |
137 | cancelSource.Cancel();
138 |
139 | Assert.IsTrue(tasks.Take(3).All(t=>t.IsCompleted));
140 | Assert.IsTrue(tasks.Skip(3).All(t => t.IsCanceled));
141 | }
142 | }
143 |
144 | [TestMethod]
145 | public void TaskCreatedAfterCancel_IsCanceledImmediately()
146 | {
147 | var cancelSource = new CancellationTokenSource();
148 |
149 | using (var timer = new TaskTimer(0).CancelWith(cancelSource.Token).StartOnTimer(_getCustomTimer))
150 | {
151 | using (var enumerator = timer.GetEnumerator())
152 | {
153 | // skip 3 tasks
154 | for (int i = 0; i < 3; ++i) enumerator.MoveNext();
155 |
156 | cancelSource.Cancel();
157 |
158 | enumerator.MoveNext();
159 | var task = enumerator.Current;
160 | Assert.IsNotNull(task);
161 | Assert.IsTrue(task.IsCanceled);
162 | }
163 | }
164 | }
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/src/Examples/WpfTimer/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
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 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/src/Examples/WebSocketMessageOnTimer/WebSocketMessageOnTimer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Debug
8 | AnyCPU
9 |
10 |
11 | 2.0
12 | {4C58EB91-AD55-49E3-83BD-F5DAC6ECEF4F}
13 | {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}
14 | Library
15 | Properties
16 | WebSocketMessageOnTimer
17 | WebSocketMessageOnTimer
18 | v4.5
19 | true
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | true
30 | full
31 | false
32 | bin\
33 | DEBUG;TRACE
34 | prompt
35 | 4
36 |
37 |
38 | pdbonly
39 | true
40 | bin\
41 | TRACE
42 | prompt
43 | 4
44 |
45 |
46 |
47 | ..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll
48 | True
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 | ..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll
72 |
73 |
74 | ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll
75 |
76 |
77 | ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll
78 |
79 |
80 | ..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.3\lib\net45\System.Web.Http.WebHost.dll
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 | Global.asax
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 | Web.config
104 |
105 |
106 | Web.config
107 |
108 |
109 |
110 |
111 |
112 |
113 | 10.0
114 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 | True
124 | True
125 | 60383
126 | /
127 | http://localhost:60371/
128 | False
129 | False
130 |
131 |
132 | False
133 |
134 |
135 |
136 |
137 |
138 |
139 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
140 |
141 |
142 |
143 |
144 |
151 |
--------------------------------------------------------------------------------
/src/TaskTimer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | // ReSharper disable once CheckNamespace
8 | namespace IKriv.Threading.Tasks
9 | {
10 | ///
11 | /// Represents running task timer, a disposable infinite series of tasks
12 | ///
13 | /// Task timer must be disposed (stopped) in the end of the usage.
14 | /// In can be enumerated only once. Attempting second enumeration will cause an
15 | /// InvalidOperationException.
16 | public interface ITaskTimer : IDisposable, IEnumerable
17 | {
18 | }
19 |
20 | ///
21 | /// Generates a series of tasks that get completed on timer
22 | ///
23 | /// Use TaskTimer to perform timer-based activities in asynchronous code.
24 | /// Await on each generated task in order.
25 | public class TaskTimer
26 | {
27 | private readonly TimeSpan _period;
28 | private CancellationToken _cancellationToken = CancellationToken.None;
29 |
30 | ///
31 | /// Creates new timer with a given period in seconds
32 | ///
33 | /// Timer period in milliseconds
34 | /// Use one of the Start() overloads to start the timer
35 | public TaskTimer(int periodMs)
36 | {
37 | _period = TimeSpan.FromMilliseconds(periodMs);
38 | }
39 |
40 | ///
41 | /// Creates new timer with a given period
42 | ///
43 | /// Timer period
44 | /// Use one of the Start() overloads to start the timer
45 | public TaskTimer(TimeSpan period)
46 | {
47 | _period = period;
48 | }
49 |
50 | ///
51 | /// Sets cancellation token for the timer
52 | ///
53 | /// Cancellation token
54 | /// When signaled, the token will cancel all tasks in the series generated by the timer
55 | public TaskTimer CancelWith(CancellationToken token)
56 | {
57 | _cancellationToken = token;
58 | return this;
59 | }
60 |
61 | ///
62 | /// Starts the timer and returns a series of tasks
63 | ///
64 | /// Delay in milliseconds before first task in the series becomes completed
65 | /// Infinite series of tasks completed on timer one after the other.
66 | public ITaskTimer Start(int delayMs = 0)
67 | {
68 | return Start(TimeSpan.FromMilliseconds(delayMs));
69 | }
70 |
71 | ///
72 | /// Starts the timer and returns a series of tasks
73 | ///
74 | /// Delay before first task in the series becomes completed
75 | /// Infinite series of tasks completed on timer one after the other
76 | public ITaskTimer Start(TimeSpan delay)
77 | {
78 | Func createTimer = callback => new Timer(state => callback(), null, delay, _period);
79 | return StartOnTimer(createTimer);
80 | }
81 |
82 | ///
83 | /// Starts the timer at specific time and returns a series of tasks
84 | ///
85 | /// Absolute time when the first task in the series becomes completed
86 | /// Infinite series of tasks completed on timer one after the other
87 | public ITaskTimer StartAt(DateTime when)
88 | {
89 | var delay = when - DateTime.UtcNow;
90 | return Start(delay);
91 | }
92 |
93 | ///
94 | /// Starts the timer using custom timer object
95 | ///
96 | /// Function that accepts callback delegate and creates a timer object
97 | /// This overload is used for tests and custom scenarios. The object created by createTimer()
98 | /// should invoke the callback delegate on a periodic basis. When it does, the next task in the series
99 | /// will be marked as completed.
100 | public ITaskTimer StartOnTimer(Func createTimer)
101 | {
102 | return new DisposableEnumerable(new TaskTimerImpl(createTimer, _cancellationToken));
103 | }
104 |
105 | private class DisposableEnumerable : ITaskTimer
106 | {
107 | private readonly TaskTimerImpl _impl;
108 | private IEnumerable _tasks;
109 |
110 | public DisposableEnumerable(TaskTimerImpl impl)
111 | {
112 | _impl = impl;
113 | }
114 |
115 | public IEnumerator GetEnumerator()
116 | {
117 | if (_tasks != null) throw new InvalidOperationException("Timer cannot be enumerated twice");
118 | _tasks = _impl.GetTasks();
119 | return _tasks.GetEnumerator();
120 | }
121 |
122 | IEnumerator IEnumerable.GetEnumerator()
123 | {
124 | return GetEnumerator();
125 | }
126 |
127 | public void Dispose()
128 | {
129 | _impl.Dispose();
130 | }
131 | }
132 |
133 | private class TaskTimerImpl : IDisposable
134 | {
135 | private readonly Queue _pendingTasks = new Queue();
136 | private readonly IDisposable _timer;
137 | private long _ticks;
138 | private long _nTasks;
139 | private bool _isCanceled;
140 |
141 | private struct Void
142 | {
143 | public static readonly Void Value = new Void();
144 | }
145 |
146 | private struct Record
147 | {
148 | public long Tick;
149 | public TaskCompletionSource Promise;
150 | }
151 |
152 | public TaskTimerImpl(Func createTimer, CancellationToken token)
153 | {
154 | _timer = createTimer(OnTimer);
155 | token.Register(Cancel);
156 | }
157 |
158 | private void OnTimer()
159 | {
160 | var toComplete = new List>();
161 |
162 | lock (_pendingTasks)
163 | {
164 | ++_ticks;
165 | while (_pendingTasks.Count > 0)
166 | {
167 | var next = _pendingTasks.Peek();
168 | if (next.Tick <= _ticks)
169 | {
170 | toComplete.Add(_pendingTasks.Dequeue().Promise);
171 | }
172 | else
173 | {
174 | break;
175 | }
176 | }
177 | }
178 |
179 | foreach (var promise in toComplete) promise.SetResult(default(Void));
180 | }
181 |
182 | public IEnumerable GetTasks()
183 | {
184 | while (true)
185 | {
186 | yield return NextTask();
187 | }
188 | // ReSharper disable once IteratorNeverReturns
189 | }
190 |
191 | public void Dispose()
192 | {
193 | _timer.Dispose();
194 | }
195 |
196 | private Task NextTask()
197 | {
198 | lock (_pendingTasks)
199 | {
200 | var tick = ++_nTasks;
201 | bool isLate = tick <= _ticks;
202 |
203 | if (_isCanceled) return CreateCanceledTask();
204 |
205 | if (isLate)
206 | {
207 | return Task.FromResult(Void.Value);
208 | }
209 | else
210 | {
211 | var promise = new TaskCompletionSource();
212 | _pendingTasks.Enqueue(new Record {Tick = tick, Promise = promise});
213 | return promise.Task;
214 | }
215 | }
216 | }
217 |
218 | private void Cancel()
219 | {
220 | lock (_pendingTasks)
221 | {
222 | _isCanceled = true;
223 | foreach (var record in _pendingTasks)
224 | {
225 | record.Promise.TrySetCanceled();
226 | }
227 | }
228 | }
229 |
230 | private static Task CreateCanceledTask()
231 | {
232 | var promise = new TaskCompletionSource();
233 | promise.TrySetCanceled();
234 | return promise.Task;
235 | }
236 | }
237 | }
238 | }
239 |
--------------------------------------------------------------------------------
/src/Examples/WpfTimer/TaskTimer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | // ReSharper disable once CheckNamespace
8 | namespace IKriv.Threading.Tasks
9 | {
10 | ///
11 | /// Represents running task timer, a disposable infinite series of tasks
12 | ///
13 | /// Task timer must be disposed (stopped) in the end of the usage.
14 | /// In can be enumerated only once. Attempting second enumeration will cause an
15 | /// InvalidOperationException.
16 | public interface ITaskTimer : IDisposable, IEnumerable
17 | {
18 | }
19 |
20 | ///
21 | /// Generates a series of tasks that get completed on timer
22 | ///
23 | /// Use TaskTimer to perform timer-based activities in asynchronous code.
24 | /// Await on each generated task in order.
25 | public class TaskTimer
26 | {
27 | private readonly TimeSpan _period;
28 | private CancellationToken _cancellationToken = CancellationToken.None;
29 |
30 | ///
31 | /// Creates new timer with a given period in seconds
32 | ///
33 | /// Timer period in milliseconds
34 | /// Use one of the Start() overloads to start the timer
35 | public TaskTimer(int periodMs)
36 | {
37 | _period = TimeSpan.FromMilliseconds(periodMs);
38 | }
39 |
40 | ///
41 | /// Creates new timer with a given period
42 | ///
43 | /// Timer period
44 | /// Use one of the Start() overloads to start the timer
45 | public TaskTimer(TimeSpan period)
46 | {
47 | _period = period;
48 | }
49 |
50 | ///
51 | /// Sets cancellation token for the timer
52 | ///
53 | /// Cancellation token
54 | /// When signaled, the token will cancel all tasks in the series generated by the timer
55 | public TaskTimer CancelWith(CancellationToken token)
56 | {
57 | _cancellationToken = token;
58 | return this;
59 | }
60 |
61 | ///
62 | /// Starts the timer and returns a series of tasks
63 | ///
64 | /// Delay in milliseconds before first task in the series becomes completed
65 | /// Infinite series of tasks completed on timer one after the other.
66 | public ITaskTimer Start(int delayMs = 0)
67 | {
68 | return Start(TimeSpan.FromMilliseconds(delayMs));
69 | }
70 |
71 | ///
72 | /// Starts the timer and returns a series of tasks
73 | ///
74 | /// Delay before first task in the series becomes completed
75 | /// Infinite series of tasks completed on timer one after the other
76 | public ITaskTimer Start(TimeSpan delay)
77 | {
78 | Func createTimer = callback => new Timer(state => callback(), null, delay, _period);
79 | return StartOnTimer(createTimer);
80 | }
81 |
82 | ///
83 | /// Starts the timer at specific time and returns a series of tasks
84 | ///
85 | /// Absolute time when the first task in the series becomes completed
86 | /// Infinite series of tasks completed on timer one after the other
87 | public ITaskTimer StartAt(DateTime when)
88 | {
89 | var delay = when - DateTime.UtcNow;
90 | return Start(delay);
91 | }
92 |
93 | ///
94 | /// Starts the timer using custom timer object
95 | ///
96 | /// Function that accepts callback delegate and creates a timer object
97 | /// This overload is used for tests and custom scenarios. The object created by createTimer()
98 | /// should invoke the callback delegate on a periodic basis. When it does, the next task in the series
99 | /// will be marked as completed.
100 | public ITaskTimer StartOnTimer(Func createTimer)
101 | {
102 | return new DisposableEnumerable(new TaskTimerImpl(createTimer, _cancellationToken));
103 | }
104 |
105 | private class DisposableEnumerable : ITaskTimer
106 | {
107 | private readonly TaskTimerImpl _impl;
108 | private IEnumerable _tasks;
109 |
110 | public DisposableEnumerable(TaskTimerImpl impl)
111 | {
112 | _impl = impl;
113 | }
114 |
115 | public IEnumerator GetEnumerator()
116 | {
117 | if (_tasks != null) throw new InvalidOperationException("Timer cannot be enumerated twice");
118 | _tasks = _impl.GetTasks();
119 | return _tasks.GetEnumerator();
120 | }
121 |
122 | IEnumerator IEnumerable.GetEnumerator()
123 | {
124 | return GetEnumerator();
125 | }
126 |
127 | public void Dispose()
128 | {
129 | _impl.Dispose();
130 | }
131 | }
132 |
133 | private class TaskTimerImpl : IDisposable
134 | {
135 | private readonly Queue _pendingTasks = new Queue();
136 | private readonly IDisposable _timer;
137 | private long _ticks;
138 | private long _nTasks;
139 | private bool _isCanceled;
140 |
141 | private struct Void
142 | {
143 | public static readonly Void Value = new Void();
144 | }
145 |
146 | private struct Record
147 | {
148 | public long Tick;
149 | public TaskCompletionSource Promise;
150 | }
151 |
152 | public TaskTimerImpl(Func createTimer, CancellationToken token)
153 | {
154 | _timer = createTimer(OnTimer);
155 | token.Register(Cancel);
156 | }
157 |
158 | private void OnTimer()
159 | {
160 | var toComplete = new List>();
161 |
162 | lock (_pendingTasks)
163 | {
164 | ++_ticks;
165 | while (_pendingTasks.Count > 0)
166 | {
167 | var next = _pendingTasks.Peek();
168 | if (next.Tick <= _ticks)
169 | {
170 | toComplete.Add(_pendingTasks.Dequeue().Promise);
171 | }
172 | else
173 | {
174 | break;
175 | }
176 | }
177 | }
178 |
179 | foreach (var promise in toComplete) promise.SetResult(default(Void));
180 | }
181 |
182 | public IEnumerable GetTasks()
183 | {
184 | while (true)
185 | {
186 | yield return NextTask();
187 | }
188 | // ReSharper disable once IteratorNeverReturns
189 | }
190 |
191 | public void Dispose()
192 | {
193 | _timer.Dispose();
194 | }
195 |
196 | private Task NextTask()
197 | {
198 | lock (_pendingTasks)
199 | {
200 | var tick = ++_nTasks;
201 | bool isLate = tick <= _ticks;
202 |
203 | if (_isCanceled) return CreateCanceledTask();
204 |
205 | if (isLate)
206 | {
207 | return Task.FromResult(Void.Value);
208 | }
209 | else
210 | {
211 | var promise = new TaskCompletionSource();
212 | _pendingTasks.Enqueue(new Record {Tick = tick, Promise = promise});
213 | return promise.Task;
214 | }
215 | }
216 | }
217 |
218 | private void Cancel()
219 | {
220 | lock (_pendingTasks)
221 | {
222 | _isCanceled = true;
223 | foreach (var record in _pendingTasks)
224 | {
225 | record.Promise.TrySetCanceled();
226 | }
227 | }
228 | }
229 |
230 | private static Task CreateCanceledTask()
231 | {
232 | var promise = new TaskCompletionSource();
233 | promise.TrySetCanceled();
234 | return promise.Task;
235 | }
236 | }
237 | }
238 | }
239 |
--------------------------------------------------------------------------------
/src/Examples/WebSocketMessageOnTimer/TaskTimer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | // ReSharper disable once CheckNamespace
8 | namespace IKriv.Threading.Tasks
9 | {
10 | ///
11 | /// Represents running task timer, a disposable infinite series of tasks
12 | ///
13 | /// Task timer must be disposed (stopped) in the end of the usage.
14 | /// In can be enumerated only once. Attempting second enumeration will cause an
15 | /// InvalidOperationException.
16 | public interface ITaskTimer : IDisposable, IEnumerable
17 | {
18 | }
19 |
20 | ///
21 | /// Generates a series of tasks that get completed on timer
22 | ///
23 | /// Use TaskTimer to perform timer-based activities in asynchronous code.
24 | /// Await on each generated task in order.
25 | public class TaskTimer
26 | {
27 | private readonly TimeSpan _period;
28 | private CancellationToken _cancellationToken = CancellationToken.None;
29 |
30 | ///
31 | /// Creates new timer with a given period in seconds
32 | ///
33 | /// Timer period in milliseconds
34 | /// Use one of the Start() overloads to start the timer
35 | public TaskTimer(int periodMs)
36 | {
37 | _period = TimeSpan.FromMilliseconds(periodMs);
38 | }
39 |
40 | ///
41 | /// Creates new timer with a given period
42 | ///
43 | /// Timer period
44 | /// Use one of the Start() overloads to start the timer
45 | public TaskTimer(TimeSpan period)
46 | {
47 | _period = period;
48 | }
49 |
50 | ///
51 | /// Sets cancellation token for the timer
52 | ///
53 | /// Cancellation token
54 | /// When signaled, the token will cancel all tasks in the series generated by the timer
55 | public TaskTimer CancelWith(CancellationToken token)
56 | {
57 | _cancellationToken = token;
58 | return this;
59 | }
60 |
61 | ///
62 | /// Starts the timer and returns a series of tasks
63 | ///
64 | /// Delay in milliseconds before first task in the series becomes completed
65 | /// Infinite series of tasks completed on timer one after the other.
66 | public ITaskTimer Start(int delayMs = 0)
67 | {
68 | return Start(TimeSpan.FromMilliseconds(delayMs));
69 | }
70 |
71 | ///
72 | /// Starts the timer and returns a series of tasks
73 | ///
74 | /// Delay before first task in the series becomes completed
75 | /// Infinite series of tasks completed on timer one after the other
76 | public ITaskTimer Start(TimeSpan delay)
77 | {
78 | Func createTimer = callback => new Timer(state => callback(), null, delay, _period);
79 | return StartOnTimer(createTimer);
80 | }
81 |
82 | ///
83 | /// Starts the timer at specific time and returns a series of tasks
84 | ///
85 | /// Absolute time when the first task in the series becomes completed
86 | /// Infinite series of tasks completed on timer one after the other
87 | public ITaskTimer StartAt(DateTime when)
88 | {
89 | var delay = when - DateTime.UtcNow;
90 | return Start(delay);
91 | }
92 |
93 | ///
94 | /// Starts the timer using custom timer object
95 | ///
96 | /// Function that accepts callback delegate and creates a timer object
97 | /// This overload is used for tests and custom scenarios. The object created by createTimer()
98 | /// should invoke the callback delegate on a periodic basis. When it does, the next task in the series
99 | /// will be marked as completed.
100 | public ITaskTimer StartOnTimer(Func createTimer)
101 | {
102 | return new DisposableEnumerable(new TaskTimerImpl(createTimer, _cancellationToken));
103 | }
104 |
105 | private class DisposableEnumerable : ITaskTimer
106 | {
107 | private readonly TaskTimerImpl _impl;
108 | private IEnumerable _tasks;
109 |
110 | public DisposableEnumerable(TaskTimerImpl impl)
111 | {
112 | _impl = impl;
113 | }
114 |
115 | public IEnumerator GetEnumerator()
116 | {
117 | if (_tasks != null) throw new InvalidOperationException("Timer cannot be enumerated twice");
118 | _tasks = _impl.GetTasks();
119 | return _tasks.GetEnumerator();
120 | }
121 |
122 | IEnumerator IEnumerable.GetEnumerator()
123 | {
124 | return GetEnumerator();
125 | }
126 |
127 | public void Dispose()
128 | {
129 | _impl.Dispose();
130 | }
131 | }
132 |
133 | private class TaskTimerImpl : IDisposable
134 | {
135 | private readonly Queue _pendingTasks = new Queue();
136 | private readonly IDisposable _timer;
137 | private long _ticks;
138 | private long _nTasks;
139 | private bool _isCanceled;
140 |
141 | private struct Void
142 | {
143 | public static readonly Void Value = new Void();
144 | }
145 |
146 | private struct Record
147 | {
148 | public long Tick;
149 | public TaskCompletionSource Promise;
150 | }
151 |
152 | public TaskTimerImpl(Func createTimer, CancellationToken token)
153 | {
154 | _timer = createTimer(OnTimer);
155 | token.Register(Cancel);
156 | }
157 |
158 | private void OnTimer()
159 | {
160 | var toComplete = new List>();
161 |
162 | lock (_pendingTasks)
163 | {
164 | ++_ticks;
165 | while (_pendingTasks.Count > 0)
166 | {
167 | var next = _pendingTasks.Peek();
168 | if (next.Tick <= _ticks)
169 | {
170 | toComplete.Add(_pendingTasks.Dequeue().Promise);
171 | }
172 | else
173 | {
174 | break;
175 | }
176 | }
177 | }
178 |
179 | foreach (var promise in toComplete) promise.SetResult(default(Void));
180 | }
181 |
182 | public IEnumerable GetTasks()
183 | {
184 | while (true)
185 | {
186 | yield return NextTask();
187 | }
188 | // ReSharper disable once IteratorNeverReturns
189 | }
190 |
191 | public void Dispose()
192 | {
193 | _timer.Dispose();
194 | }
195 |
196 | private Task NextTask()
197 | {
198 | lock (_pendingTasks)
199 | {
200 | var tick = ++_nTasks;
201 | bool isLate = tick <= _ticks;
202 |
203 | if (_isCanceled) return CreateCanceledTask();
204 |
205 | if (isLate)
206 | {
207 | return Task.FromResult(Void.Value);
208 | }
209 | else
210 | {
211 | var promise = new TaskCompletionSource();
212 | _pendingTasks.Enqueue(new Record {Tick = tick, Promise = promise});
213 | return promise.Task;
214 | }
215 | }
216 | }
217 |
218 | private void Cancel()
219 | {
220 | lock (_pendingTasks)
221 | {
222 | _isCanceled = true;
223 | foreach (var record in _pendingTasks)
224 | {
225 | record.Promise.TrySetCanceled();
226 | }
227 | }
228 | }
229 |
230 | private static Task CreateCanceledTask()
231 | {
232 | var promise = new TaskCompletionSource();
233 | promise.TrySetCanceled();
234 | return promise.Task;
235 | }
236 | }
237 | }
238 | }
239 |
--------------------------------------------------------------------------------