Skip to content

Commit 7913fd0

Browse files
authored
Add support for CancellationTokens within client and services methods. (#33)
* Used (inheritdoc) for dynamic documentation commets. Classes now utilize the usage of <inheritdoc> to inherit the implemented interface documentation and reduce duplicate documentation comments. * Added ICancellableTodoistRestClient interface. The added interface inherits from ITodoistRestClient and extends it with method overloads that support cancellation. TodoistRestClient is also changed to implement ICancellableTodoistRestClient. * Added support for cancellation in TodoistClient and TodoistTokenlessClient. In TodoistClient we typically pass the cancellation token to _restClient if it implements ICancellableTodoistRestClient. The rest is just passing the cancellation token as a parameter along the method call chain. * Updated all services to support optional cancellation token in their methods. Cancellation tokens are then passed to the IAdvancedTodoistClient method calls. * Added TodoistClient constructor overload that accepts an ICancellableRestClient argument. * Removed ICancellableTodoistRestClient interface; And added cancellation tokens to ITodoistRestClient directly.
1 parent 2a0bead commit 7913fd0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+775
-1133
lines changed

src/Todoist.Net.Tests/RateLimitAwareRestClient.cs

+7-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Collections.Generic;
44
using System.Net;
55
using System.Net.Http;
6+
using System.Threading;
67
using System.Threading.Tasks;
78

89
using Xunit.Abstractions;
@@ -55,17 +56,19 @@ public async Task<HttpResponseMessage> ExecuteRequest(Func<Task<HttpResponseMess
5556

5657
public async Task<HttpResponseMessage> PostAsync(
5758
string resource,
58-
IEnumerable<KeyValuePair<string, string>> parameters)
59+
IEnumerable<KeyValuePair<string, string>> parameters,
60+
CancellationToken cancellationToken = default)
5961
{
60-
return await ExecuteRequest(() => _restClient.PostAsync(resource, parameters)).ConfigureAwait(false);
62+
return await ExecuteRequest(() => _restClient.PostAsync(resource, parameters, cancellationToken)).ConfigureAwait(false);
6163
}
6264

6365
public async Task<HttpResponseMessage> PostFormAsync(
6466
string resource,
6567
IEnumerable<KeyValuePair<string, string>> parameters,
66-
IEnumerable<ByteArrayContent> files)
68+
IEnumerable<ByteArrayContent> files,
69+
CancellationToken cancellationToken = default)
6770
{
68-
return await ExecuteRequest(() => _restClient.PostFormAsync(resource, parameters, files))
71+
return await ExecuteRequest(() => _restClient.PostFormAsync(resource, parameters, files, cancellationToken))
6972
.ConfigureAwait(false);
7073
}
7174

src/Todoist.Net/IAdvancedTodoistClient.cs

+27-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
using System;
12
using System.Collections.Generic;
23
using System.Net.Http;
4+
using System.Threading;
35
using System.Threading.Tasks;
46

57
using Todoist.Net.Models;
@@ -18,20 +20,37 @@ internal interface IAdvancedTodoistClient : ITodoistClient
1820
/// </returns>
1921
/// <exception cref="System.ArgumentNullException">Value cannot be null - commands.</exception>
2022
/// <exception cref="System.AggregateException">Command execution exception.</exception>
23+
/// <exception cref="ArgumentException">Value cannot be an empty collection.</exception>
2124
/// <exception cref="HttpRequestException">API exception.</exception>
2225
Task<string> ExecuteCommandsAsync(params Command[] commands);
2326

27+
/// <summary>
28+
/// Executes the commands asynchronous.
29+
/// </summary>
30+
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
31+
/// <param name="commands">The commands.</param>
32+
/// <returns>
33+
/// Returns <see cref="Task{TResult}" />. The task object representing the asynchronous operation
34+
/// that at completion returns the commands execution sync_token.
35+
/// </returns>
36+
/// <exception cref="System.ArgumentNullException">Value cannot be null - commands.</exception>
37+
/// <exception cref="System.AggregateException">Command execution exception.</exception>
38+
/// <exception cref="ArgumentException">Value cannot be an empty collection.</exception>
39+
/// <exception cref="HttpRequestException">API exception.</exception>
40+
Task<string> ExecuteCommandsAsync(CancellationToken cancellationToken, params Command[] commands);
41+
2442
/// <summary>
2543
/// Posts the request asynchronous.
2644
/// </summary>
2745
/// <typeparam name="T">Type of the result.</typeparam>
2846
/// <param name="resource">The resource.</param>
2947
/// <param name="parameters">The parameters.</param>
48+
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
3049
/// <returns>
3150
/// The result.
3251
/// </returns>
3352
/// <exception cref="HttpRequestException">API exception.</exception>
34-
Task<T> PostAsync<T>(string resource, ICollection<KeyValuePair<string, string>> parameters);
53+
Task<T> PostAsync<T>(string resource, ICollection<KeyValuePair<string, string>> parameters, CancellationToken cancellationToken = default);
3554

3655
/// <summary>
3756
/// Posts the asynchronous and returns a raw content.
@@ -40,36 +59,40 @@ internal interface IAdvancedTodoistClient : ITodoistClient
4059
/// <param name="resource">The resource.</param>
4160
/// <param name="parameters">The parameters.</param>
4261
/// <param name="files">The files.</param>
62+
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
4363
/// <returns>
4464
/// The result.
4565
/// </returns>
4666
/// <exception cref="HttpRequestException">API exception.</exception>
4767
Task<T> PostFormAsync<T>(
4868
string resource,
4969
ICollection<KeyValuePair<string, string>> parameters,
50-
IEnumerable<ByteArrayContent> files);
70+
IEnumerable<ByteArrayContent> files,
71+
CancellationToken cancellationToken = default);
5172

5273
/// <summary>
5374
/// Posts the asynchronous and returns a raw content.
5475
/// </summary>
5576
/// <param name="resource">The resource.</param>
5677
/// <param name="parameters">The parameters.</param>
78+
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
5779
/// <returns>
5880
/// The result.
5981
/// </returns>
6082
/// <exception cref="HttpRequestException">API exception.</exception>
61-
Task<string> PostRawAsync(string resource, ICollection<KeyValuePair<string, string>> parameters);
83+
Task<string> PostRawAsync(string resource, ICollection<KeyValuePair<string, string>> parameters, CancellationToken cancellationToken = default);
6284

6385
/// <summary>
6486
/// Processes the request asynchronous.
6587
/// </summary>
6688
/// <typeparam name="T">The type of the result.</typeparam>
6789
/// <param name="resource">The resource.</param>
6890
/// <param name="parameters">The parameters.</param>
91+
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
6992
/// <returns>
7093
/// The result of the operation.
7194
/// </returns>
7295
/// <exception cref="HttpRequestException">API exception.</exception>
73-
Task<T> ProcessPostAsync<T>(string resource, ICollection<KeyValuePair<string, string>> parameters);
96+
Task<T> ProcessPostAsync<T>(string resource, ICollection<KeyValuePair<string, string>> parameters, CancellationToken cancellationToken = default);
7497
}
7598
}

src/Todoist.Net/ITodoistClient.cs

+27
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Net.Http;
3+
using System.Threading;
34
using System.Threading.Tasks;
45

56
using Todoist.Net.Models;
@@ -135,6 +136,18 @@ public interface ITodoistClient
135136
/// <exception cref="ArgumentNullException"><paramref name="resourceTypes"/> is <see langword="null"/></exception>
136137
Task<Resources> GetResourcesAsync(params ResourceType[] resourceTypes);
137138

139+
/// <summary>
140+
/// Gets the resources asynchronous. Returns all resources if zero resource type were passed.
141+
/// </summary>
142+
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
143+
/// <param name="resourceTypes">The resource types.</param>
144+
/// <returns>
145+
/// The requested resources.
146+
/// </returns>
147+
/// <exception cref="HttpRequestException">API exception.</exception>
148+
/// <exception cref="ArgumentNullException"><paramref name="resourceTypes"/> is <see langword="null"/></exception>
149+
Task<Resources> GetResourcesAsync(CancellationToken cancellationToken, params ResourceType[] resourceTypes);
150+
138151
/// <summary>
139152
/// Gets the resources asynchronous. Returns all resources if zero resource type were passed.
140153
/// When sync token is passed in only tasks that have changed since last Sync will be returned.
@@ -147,5 +160,19 @@ public interface ITodoistClient
147160
/// <exception cref="HttpRequestException">API exception.</exception>
148161
/// <exception cref="ArgumentNullException"><paramref name="resourceTypes"/> is <see langword="null"/></exception>
149162
Task<Resources> GetResourcesAsync(string syncToken, params ResourceType[] resourceTypes);
163+
164+
/// <summary>
165+
/// Gets the resources asynchronous. Returns all resources if zero resource type were passed.
166+
/// When sync token is passed in only tasks that have changed since last Sync will be returned.
167+
/// </summary>
168+
/// <param name="syncToken">The sync token returned from Todoist for increment sync</param>
169+
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
170+
/// <param name="resourceTypes">The resource types.</param>
171+
/// <returns>
172+
/// The requested resources.
173+
/// </returns>
174+
/// <exception cref="HttpRequestException">API exception.</exception>
175+
/// <exception cref="ArgumentNullException"><paramref name="resourceTypes"/> is <see langword="null"/></exception>
176+
Task<Resources> GetResourcesAsync(string syncToken, CancellationToken cancellationToken, params ResourceType[] resourceTypes);
150177
}
151178
}

src/Todoist.Net/ITodoistRestClient.cs

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using System.Net.Http;
4+
using System.Threading;
45
using System.Threading.Tasks;
56

67
namespace Todoist.Net
@@ -15,20 +16,24 @@ public interface ITodoistRestClient : IDisposable
1516
/// </summary>
1617
/// <param name="resource">The resource.</param>
1718
/// <param name="parameters">The parameters.</param>
19+
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
1820
/// <returns>Returns <see cref="T:System.Threading.Tasks.Task" />.The task object representing the asynchronous operation.</returns>
21+
/// <exception cref="System.ArgumentException">Value cannot be null or empty - resource</exception>
1922
/// <exception cref="ArgumentNullException"><paramref name="parameters" /> is <see langword="null" /></exception>
20-
Task<HttpResponseMessage> PostAsync(string resource, IEnumerable<KeyValuePair<string, string>> parameters);
23+
Task<HttpResponseMessage> PostAsync(string resource, IEnumerable<KeyValuePair<string, string>> parameters, CancellationToken cancellationToken = default);
2124

2225
/// <summary>
2326
/// Posts the form asynchronous.
2427
/// </summary>
2528
/// <param name="resource">The resource.</param>
2629
/// <param name="parameters">The parameters.</param>
2730
/// <param name="files">The files.</param>
31+
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
2832
/// <returns>The response.</returns>
2933
Task<HttpResponseMessage> PostFormAsync(
3034
string resource,
3135
IEnumerable<KeyValuePair<string, string>> parameters,
32-
IEnumerable<ByteArrayContent> files);
36+
IEnumerable<ByteArrayContent> files,
37+
CancellationToken cancellationToken = default);
3338
}
3439
}

src/Todoist.Net/ITodoistTokenlessClient.cs

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
using System;
1+
using System;
22
using System.Net.Http;
3+
using System.Threading;
34
using System.Threading.Tasks;
45

56
using Todoist.Net.Exceptions;
@@ -17,6 +18,7 @@ public interface ITodoistTokenlessClient
1718
/// </summary>
1819
/// <param name="email">The email.</param>
1920
/// <param name="password">The password.</param>
21+
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
2022
/// <returns>
2123
/// A new instance of Todoist client.
2224
/// </returns>
@@ -27,13 +29,14 @@ public interface ITodoistTokenlessClient
2729
/// </exception>
2830
/// <exception cref="HttpRequestException">API exception.</exception>
2931
/// <exception cref="TodoistException">Unable to get token.</exception>
30-
Task<TodoistClient> LoginAsync(string email, string password);
32+
Task<TodoistClient> LoginAsync(string email, string password, CancellationToken cancellationToken = default);
3133

3234
/// <summary>
3335
/// Logins user and returns a new instance of Todoist client.
3436
/// </summary>
3537
/// <param name="email">The email.</param>
3638
/// <param name="oauthToken">The oauth token.</param>
39+
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
3740
/// <returns>
3841
/// A new instance of Todoist client.
3942
/// </returns>
@@ -44,17 +47,18 @@ public interface ITodoistTokenlessClient
4447
/// </exception>
4548
/// <exception cref="TodoistException">API exception.</exception>
4649
/// <exception cref="HttpRequestException">API exception.</exception>
47-
Task<TodoistClient> LoginWithGoogleAsync(string email, string oauthToken);
50+
Task<TodoistClient> LoginWithGoogleAsync(string email, string oauthToken, CancellationToken cancellationToken = default);
4851

4952
/// <summary>
5053
/// Registers a new user.
5154
/// </summary>
5255
/// <param name="user">The user.</param>
56+
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
5357
/// <returns>
5458
/// The user info.
5559
/// </returns>
5660
/// <exception cref="ArgumentNullException"><paramref name="user" /> is <see langword="null" /></exception>
5761
/// <exception cref="HttpRequestException">API exception.</exception>
58-
Task<UserInfo> RegisterUserAsync(UserBase user);
62+
Task<UserInfo> RegisterUserAsync(UserBase user, CancellationToken cancellationToken = default);
5963
}
60-
}
64+
}
+5-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
using System.Collections.Generic;
2-
using System.Net.Http;
1+
using System.Collections.Generic;
2+
using System.Threading;
33
using System.Threading.Tasks;
44

55
using Todoist.Net.Models;
@@ -18,18 +18,12 @@ internal ActivityService(IAdvancedTodoistClient todoistClient)
1818
_todoistClient = todoistClient;
1919
}
2020

21-
/// <summary>
22-
/// Gets list of activity logs.
23-
/// </summary>
24-
/// <param name="filter">The filter.</param>
25-
/// <returns>The activity log entries.</returns>
26-
/// <exception cref="HttpRequestException">API exception.</exception>
27-
/// <remarks>The activity log is only available for Todoist Premium.</remarks>
28-
public Task<Activity> GetAsync(LogFilter filter = null)
21+
/// <inheritdoc/>
22+
public Task<Activity> GetAsync(LogFilter filter = null, CancellationToken cancellationToken = default)
2923
{
3024
var parameters = filter != null ? filter.ToParameters() : new List<KeyValuePair<string, string>>();
3125

32-
return _todoistClient.PostAsync<Activity>("activity/get", parameters);
26+
return _todoistClient.PostAsync<Activity>("activity/get", parameters, cancellationToken);
3327
}
3428
}
3529
}

src/Todoist.Net/Services/BackupService.cs

+6-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
using System.Collections.Generic;
2-
using System.Net.Http;
1+
using System.Collections.Generic;
2+
using System.Threading;
33
using System.Threading.Tasks;
44

55
using Todoist.Net.Models;
@@ -18,17 +18,13 @@ internal BackupService(IAdvancedTodoistClient todoistClient)
1818
_todoistClient = todoistClient;
1919
}
2020

21-
/// <summary>
22-
/// Gets list of recent backup archives asynchronous.
23-
/// </summary>
24-
/// <returns>The backups information.</returns>
25-
/// <remarks>Todoist creates a backup archive of users' data on a daily basis. Backup archives can also be accessed from the web app (Todoist Settings -> Backups).</remarks>
26-
/// <exception cref="HttpRequestException">API exception.</exception>
27-
public Task<IEnumerable<Backup>> GetAsync()
21+
/// <inheritdoc/>
22+
public Task<IEnumerable<Backup>> GetAsync(CancellationToken cancellationToken = default)
2823
{
2924
return _todoistClient.PostAsync<IEnumerable<Backup>>(
3025
"backups/get",
31-
new List<KeyValuePair<string, string>>());
26+
new List<KeyValuePair<string, string>>(),
27+
cancellationToken);
3228
}
3329
}
3430
}

src/Todoist.Net/Services/CommandServiceBase.cs

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using System.Net.Http;
4+
using System.Threading;
45
using System.Threading.Tasks;
56

67
using Todoist.Net.Models;
@@ -40,14 +41,15 @@ internal Command CreateEntityCommand(CommandType commandType, ComplexId id)
4041
/// Executes the command asynchronous.
4142
/// </summary>
4243
/// <param name="command">The command.</param>
44+
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
4345
/// <returns>Returns <see cref="T:System.Threading.Tasks.Task" />.The task object representing the asynchronous operation.</returns>
4446
/// <exception cref="HttpRequestException">API exception.</exception>
4547
/// <exception cref="AggregateException">Command execution exception.</exception>
46-
internal async Task ExecuteCommandAsync(Command command)
48+
internal async Task ExecuteCommandAsync(Command command, CancellationToken cancellationToken = default)
4749
{
4850
if (_queue == null)
4951
{
50-
await TodoistClient.ExecuteCommandsAsync(command).ConfigureAwait(false);
52+
await TodoistClient.ExecuteCommandsAsync(cancellationToken, command).ConfigureAwait(false);
5153
return;
5254
}
5355

src/Todoist.Net/Services/EmailService.cs

+7-21
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Net.Http;
3+
using System.Threading;
44
using System.Threading.Tasks;
55

66
using Todoist.Net.Models;
@@ -20,34 +20,20 @@ internal EmailService(IAdvancedTodoistClient todoistClient)
2020
_todoistClient = todoistClient;
2121
}
2222

23-
/// <summary>
24-
/// Disables an email address for an object.
25-
/// </summary>
26-
/// <param name="objectType">Type of the object.</param>
27-
/// <param name="objectId">The object identifier.</param>
28-
/// <returns>Returns <see cref="T:System.Threading.Tasks.Task" />.The task object representing the asynchronous operation.</returns>
29-
/// <exception cref="HttpRequestException">API exception.</exception>
30-
public Task DisableAsync(ObjectType objectType, ComplexId objectId)
23+
/// <inheritdoc/>
24+
public Task DisableAsync(ObjectType objectType, ComplexId objectId, CancellationToken cancellationToken = default)
3125
{
3226
var parameters = CreateParameters(objectType, objectId);
3327

34-
return _todoistClient.PostRawAsync("emails/disable", parameters);
28+
return _todoistClient.PostRawAsync("emails/disable", parameters, cancellationToken);
3529
}
3630

37-
/// <summary>
38-
/// Creates a new email address for an object, or gets an existing email.
39-
/// </summary>
40-
/// <param name="objectType">Type of the object.</param>
41-
/// <param name="objectId">The object identifier.</param>
42-
/// <returns>
43-
/// The email information.
44-
/// </returns>
45-
/// <exception cref="HttpRequestException">API exception.</exception>
46-
public Task<EmailInfo> GetOrCreateAsync(ObjectType objectType, ComplexId objectId)
31+
/// <inheritdoc/>
32+
public Task<EmailInfo> GetOrCreateAsync(ObjectType objectType, ComplexId objectId, CancellationToken cancellationToken = default)
4733
{
4834
var parameters = CreateParameters(objectType, objectId);
4935

50-
return _todoistClient.PostAsync<EmailInfo>("emails/get_or_create", parameters);
36+
return _todoistClient.PostAsync<EmailInfo>("emails/get_or_create", parameters, cancellationToken);
5137
}
5238

5339
private static List<KeyValuePair<string, string>> CreateParameters(ObjectType objectType, ComplexId objectId)

0 commit comments

Comments
 (0)