1+ // --------------------------------------------------------------------------------------------------------------------
2+ // <copyright file="NetworkRequestManager.cs" company="MADE Apps">
3+ // Copyright (c) MADE Apps.
4+ // </copyright>
5+ // <summary>
6+ // Defines a manager for executing queued network requests.
7+ // </summary>
8+ // --------------------------------------------------------------------------------------------------------------------
9+
10+ namespace MADE . App . Networking
11+ {
12+ using System ;
13+ using System . Collections . Concurrent ;
14+ using System . Collections . Generic ;
15+ using System . Linq ;
16+ using System . Threading ;
17+ using System . Threading . Tasks ;
18+
19+ using MADE . App . Networking . Requests ;
20+
21+ /// <summary>
22+ /// Defines a manager for executing queued network requests.
23+ /// </summary>
24+ public sealed class NetworkRequestManager : INetworkRequestManager
25+ {
26+ private Timer processTimer ;
27+
28+ private bool isProcessingRequests ;
29+
30+ /// <summary>
31+ /// Initializes a new instance of the <see cref="NetworkRequestManager"/> class.
32+ /// </summary>
33+ public NetworkRequestManager ( )
34+ {
35+ this . CurrentQueue = new ConcurrentDictionary < string , NetworkRequestCallback > ( ) ;
36+ }
37+
38+ /// <summary>
39+ /// Gets the current queue of network requests.
40+ /// </summary>
41+ public ConcurrentDictionary < string , NetworkRequestCallback > CurrentQueue { get ; }
42+
43+ /// <summary>
44+ /// Starts the manager processing the queue of network requests at a default time period of 1 minute.
45+ /// </summary>
46+ public void Start ( )
47+ {
48+ this . Start ( TimeSpan . FromMinutes ( 1 ) ) ;
49+ }
50+
51+ /// <summary>
52+ /// Starts the manager processing the queue of network requests.
53+ /// </summary>
54+ /// <param name="processPeriod">
55+ /// The time period between each process of the queue.
56+ /// </param>
57+ public void Start ( TimeSpan processPeriod )
58+ {
59+ if ( this . processTimer == null )
60+ {
61+ this . processTimer = new Timer (
62+ state => this . ProcessCurrentQueue ( ) ,
63+ null ,
64+ TimeSpan . FromMinutes ( 0 ) ,
65+ processPeriod ) ;
66+ }
67+ else
68+ {
69+ this . processTimer . Change ( TimeSpan . FromMinutes ( 0 ) , processPeriod ) ;
70+ }
71+ }
72+
73+ /// <summary>
74+ /// Stops the processing of the network manager queues.
75+ /// </summary>
76+ public void Stop ( )
77+ {
78+ this . processTimer ? . Change ( Timeout . InfiniteTimeSpan , Timeout . InfiniteTimeSpan ) ;
79+ }
80+
81+ /// <summary>
82+ /// Processes the current queue of network requests.
83+ /// </summary>
84+ public void ProcessCurrentQueue ( )
85+ {
86+ if ( this . isProcessingRequests )
87+ {
88+ return ;
89+ }
90+
91+ if ( this . CurrentQueue . Count > 0 )
92+ {
93+ return ;
94+ }
95+
96+ this . isProcessingRequests = true ;
97+
98+ try
99+ {
100+ CancellationTokenSource cts = new CancellationTokenSource ( ) ;
101+ List < Task > requestTasks = new List < Task > ( ) ;
102+ List < NetworkRequestCallback > requestCallbacks = new List < NetworkRequestCallback > ( ) ;
103+
104+ while ( this . CurrentQueue . Count > 0 )
105+ {
106+ if ( this . CurrentQueue . TryRemove (
107+ this . CurrentQueue . FirstOrDefault ( ) . Key ,
108+ out NetworkRequestCallback request ) )
109+ {
110+ requestCallbacks . Add ( request ) ;
111+ }
112+ }
113+
114+ foreach ( NetworkRequestCallback container in requestCallbacks )
115+ {
116+ requestTasks . Add ( ExecuteRequestsAsync ( this . CurrentQueue , container , cts ) ) ;
117+ }
118+ }
119+ finally
120+ {
121+ this . isProcessingRequests = false ;
122+ }
123+ }
124+
125+ /// <summary>
126+ /// Adds or updates a network request in the queue.
127+ /// </summary>
128+ /// <typeparam name="TRequest">
129+ /// The type of network request.
130+ /// </typeparam>
131+ /// <typeparam name="TResponse">
132+ /// The expected response type.
133+ /// </typeparam>
134+ /// <param name="request">
135+ /// The network request to execute.
136+ /// </param>
137+ /// <param name="successCallback">
138+ /// The action to execute when receiving a successful response.
139+ /// </param>
140+ public void AddOrUpdate < TRequest , TResponse > ( TRequest request , Action < TResponse > successCallback )
141+ where TRequest : NetworkRequest
142+ {
143+ this . AddOrUpdate < TRequest , TResponse , Exception > ( request , successCallback , null ) ;
144+ }
145+
146+ /// <summary>
147+ /// Adds or updates a network request in the queue.
148+ /// </summary>
149+ /// <typeparam name="TRequest">
150+ /// The type of network request.
151+ /// </typeparam>
152+ /// <typeparam name="TResponse">
153+ /// The expected response type.
154+ /// </typeparam>
155+ /// <typeparam name="TErrorResponse">
156+ /// The expected error response type.
157+ /// </typeparam>
158+ /// <param name="request">
159+ /// The network request to execute.
160+ /// </param>
161+ /// <param name="successCallback">
162+ /// The action to execute when receiving a successful response.
163+ /// </param>
164+ /// <param name="errorCallback">
165+ /// The action to execute when receiving an error response.
166+ /// </param>
167+ public void AddOrUpdate < TRequest , TResponse , TErrorResponse > (
168+ TRequest request ,
169+ Action < TResponse > successCallback ,
170+ Action < TErrorResponse > errorCallback )
171+ where TRequest : NetworkRequest
172+ {
173+ WeakReferenceCallback weakSuccessCallback = new WeakReferenceCallback ( successCallback , typeof ( TResponse ) ) ;
174+ WeakReferenceCallback weakErrorCallback = new WeakReferenceCallback ( errorCallback , typeof ( TErrorResponse ) ) ;
175+ NetworkRequestCallback requestCallback = new NetworkRequestCallback (
176+ request ,
177+ weakSuccessCallback ,
178+ weakErrorCallback ) ;
179+
180+ this . CurrentQueue . AddOrUpdate (
181+ request . Identifier . ToString ( ) ,
182+ requestCallback ,
183+ ( s , callback ) => requestCallback ) ;
184+ }
185+
186+ private static async Task ExecuteRequestsAsync (
187+ ConcurrentDictionary < string , NetworkRequestCallback > queue ,
188+ NetworkRequestCallback requestCallback ,
189+ CancellationTokenSource cts )
190+ {
191+ if ( cts . IsCancellationRequested )
192+ {
193+ queue . AddOrUpdate (
194+ requestCallback . Request . Identifier . ToString ( ) ,
195+ requestCallback ,
196+ ( s , callback ) => requestCallback ) ;
197+
198+ return ;
199+ }
200+
201+ NetworkRequest request = requestCallback . Request ;
202+ WeakReferenceCallback successCallback = requestCallback . SuccessCallback ;
203+ WeakReferenceCallback errorCallback = requestCallback . ErrorCallback ;
204+
205+ try
206+ {
207+ object response = await request . ExecuteAsync ( successCallback . Type ) ;
208+ successCallback . Invoke ( response ) ;
209+ }
210+ catch ( Exception ex )
211+ {
212+ successCallback . Invoke ( Activator . CreateInstance ( successCallback . Type ) ) ;
213+ errorCallback . Invoke ( ex ) ;
214+ }
215+ }
216+ }
217+ }
0 commit comments