@@ -45,12 +45,13 @@ public abstract partial class ExchangeAPI : BaseAPI, IExchangeAPI
45
45
#region Private methods
46
46
47
47
private static readonly IReadOnlyCollection < Type > exchangeTypes = typeof ( ExchangeAPI ) . Assembly . GetTypes ( ) . Where ( type => type . IsSubclassOf ( typeof ( ExchangeAPI ) ) && ! type . IsAbstract ) . ToArray ( ) ;
48
- private static readonly ConcurrentDictionary < Type , IExchangeAPI > apis = new ConcurrentDictionary < Type , IExchangeAPI > ( ) ;
48
+ private static readonly ConcurrentDictionary < Type , Task < IExchangeAPI > > apis = new ConcurrentDictionary < Type , Task < IExchangeAPI > > ( ) ;
49
+ private static readonly SemaphoreSlim semaphore = new SemaphoreSlim ( 1 ) ;
49
50
50
51
private bool initialized ;
51
52
private bool disposed ;
52
53
53
- private static IExchangeAPI InitializeAPI ( Type ? type , Type ? knownType = null )
54
+ private static async Task < IExchangeAPI > InitializeAPIAsync ( Type ? type , Type ? knownType = null )
54
55
{
55
56
if ( type is null )
56
57
{
@@ -64,30 +65,23 @@ private static IExchangeAPI InitializeAPI(Type? type, Type? knownType = null)
64
65
}
65
66
66
67
const int retryCount = 3 ;
67
- Exception ? ex = null ;
68
-
68
+
69
69
// try up to 3 times to init
70
- for ( int i = 1 ; i <= 3 ; i ++ )
70
+ for ( int i = 1 ; i <= retryCount ; i ++ )
71
71
{
72
72
try
73
73
{
74
- api . InitializeAsync ( ) . Sync ( ) ;
75
- ex = null ;
76
- break ;
74
+ await api . InitializeAsync ( ) ;
77
75
}
78
- catch ( Exception _ex )
76
+ catch ( Exception )
79
77
{
80
- ex = _ex ;
81
- if ( i != retryCount )
78
+ if ( i == retryCount )
82
79
{
83
- Thread . Sleep ( 5000 ) ;
80
+ throw ;
84
81
}
85
- }
86
- }
87
82
88
- if ( ex != null )
89
- {
90
- throw ex ;
83
+ Thread . Sleep ( 5000 ) ;
84
+ }
91
85
}
92
86
93
87
return api ;
@@ -365,7 +359,7 @@ public void Dispose()
365
359
Cache ? . Dispose ( ) ;
366
360
367
361
// take out of global api dictionary if disposed and we are the current exchange in the dictionary
368
- if ( apis . TryGetValue ( GetType ( ) , out IExchangeAPI existing ) && this == existing )
362
+ if ( apis . TryGetValue ( GetType ( ) , out Task < IExchangeAPI > existing ) && this == existing . Result )
369
363
{
370
364
apis . TryRemove ( GetType ( ) , out _ ) ;
371
365
}
@@ -386,9 +380,17 @@ private async Task InitializeAsync()
386
380
initialized = true ;
387
381
}
388
382
389
- private static IExchangeAPI CreateExchangeAPI ( Type ? type )
383
+ /// <summary>
384
+ /// Create an exchange api, by-passing any cache. Use this method for cases
385
+ /// where you need multiple instances of the same exchange, for example
386
+ /// multiple credentials.
387
+ /// </summary>
388
+ /// <typeparam name="T">Type of exchange api to create</typeparam>
389
+ /// <returns>Created exchange api</returns>
390
+ [ Obsolete ( "Use the async version" ) ]
391
+ public static T CreateExchangeAPI < T > ( ) where T : ExchangeAPI
390
392
{
391
- return InitializeAPI ( type ) ;
393
+ return CreateExchangeAPIAsync < T > ( ) . Result ;
392
394
}
393
395
394
396
/// <summary>
@@ -398,75 +400,117 @@ private static IExchangeAPI CreateExchangeAPI(Type? type)
398
400
/// </summary>
399
401
/// <typeparam name="T">Type of exchange api to create</typeparam>
400
402
/// <returns>Created exchange api</returns>
401
- public static T CreateExchangeAPI < T > ( ) where T : ExchangeAPI
403
+ public static async Task < T > CreateExchangeAPIAsync < T > ( ) where T : ExchangeAPI
402
404
{
403
- return ( T ) CreateExchangeAPI ( typeof ( T ) ) ;
405
+ return ( T ) await InitializeAPIAsync ( typeof ( T ) ) ;
404
406
}
405
407
406
408
/// <summary>
407
409
/// Get a cached exchange API given an exchange name (see ExchangeName class)
408
410
/// </summary>
409
411
/// <param name="exchangeName">Exchange name. Must match the casing of the ExchangeName class name exactly.</param>
410
412
/// <returns>Exchange API or null if not found</returns>
413
+ [ Obsolete ( "Use the async version" ) ]
411
414
public static IExchangeAPI GetExchangeAPI ( string exchangeName )
415
+ {
416
+ return GetExchangeAPIAsync ( exchangeName ) . Result ;
417
+ }
418
+
419
+ /// <summary>
420
+ /// Get a cached exchange API given an exchange name (see ExchangeName class)
421
+ /// </summary>
422
+ /// <param name="exchangeName">Exchange name. Must match the casing of the ExchangeName class name exactly.</param>
423
+ /// <returns>Exchange API or null if not found</returns>
424
+ public static Task < IExchangeAPI > GetExchangeAPIAsync ( string exchangeName )
412
425
{
413
426
Type type = ExchangeName . GetExchangeType ( exchangeName ) ;
414
- return GetExchangeAPI ( type ) ;
427
+ return GetExchangeAPIAsync ( type ) ;
415
428
}
416
429
417
430
/// <summary>
418
431
/// Get a cached exchange API given a type
419
432
/// </summary>
420
433
/// <typeparam name="T">Type of exchange to get</typeparam>
421
434
/// <returns>Exchange API or null if not found</returns>
435
+ [ Obsolete ( "Use the async version" ) ]
422
436
public static IExchangeAPI GetExchangeAPI < T > ( ) where T : ExchangeAPI
437
+ {
438
+ return GetExchangeAPIAsync < T > ( ) . Result ;
439
+ }
440
+
441
+ public static Task < IExchangeAPI > GetExchangeAPIAsync < T > ( ) where T : ExchangeAPI
423
442
{
424
443
// note: this method will be slightly slow (milliseconds) the first time it is called due to cache miss and initialization
425
444
// subsequent calls with cache hits will be nanoseconds
426
445
Type type = typeof ( T ) ! ;
427
- return GetExchangeAPI ( type ) ;
446
+ return GetExchangeAPIAsync ( type ) ;
428
447
}
429
448
430
449
/// <summary>
431
450
/// Get a cached exchange API given a type
432
451
/// </summary>
433
452
/// <param name="type">Type of exchange</param>
434
453
/// <returns>Exchange API or null if not found</returns>
454
+ [ Obsolete ( "Use the async version" ) ]
435
455
public static IExchangeAPI GetExchangeAPI ( Type type )
436
456
{
437
- // note: this method will be slightly slow (milliseconds) the first time it is called due to cache miss and initialization
438
- // subsequent calls with cache hits will be nanoseconds
439
- return apis . GetOrAdd ( type , _exchangeName =>
457
+ return GetExchangeAPIAsync ( type ) . Result ;
458
+ }
459
+
460
+ /// <summary>
461
+ /// Get a cached exchange API given a type
462
+ /// </summary>
463
+ /// <param name="type">Type of exchange</param>
464
+ /// <returns>Exchange API or null if not found</returns>
465
+ public static async Task < IExchangeAPI > GetExchangeAPIAsync ( Type type )
466
+ {
467
+ if ( apis . TryGetValue ( type , out var result ) ) return await result ;
468
+
469
+ await semaphore . WaitAsync ( ) ;
470
+ try
440
471
{
441
- // find the api type
442
- Type ? foundType = exchangeTypes . FirstOrDefault ( t => t == type ) ;
443
- return InitializeAPI ( foundType , type ) ;
444
- } ) ;
472
+ // try again inside semaphore
473
+ if ( apis . TryGetValue ( type , out result ) ) return await result ;
474
+
475
+ // still not found, initialize it
476
+ var foundType = exchangeTypes . FirstOrDefault ( t => t == type ) ;
477
+ return await ( apis [ type ] = InitializeAPIAsync ( foundType , type ) ) ;
478
+ }
479
+ finally
480
+ {
481
+ semaphore . Release ( ) ;
482
+ }
445
483
}
446
484
447
485
/// <summary>
448
486
/// Get all cached versions of exchange APIs
449
487
/// </summary>
450
488
/// <returns>All APIs</returns>
489
+ [ Obsolete ( "Use the async version" ) ]
451
490
public static IExchangeAPI [ ] GetExchangeAPIs ( )
452
491
{
453
- foreach ( Type type in exchangeTypes )
492
+ return GetExchangeAPIsAsync ( ) . Result ;
493
+ }
494
+
495
+ /// <summary>
496
+ /// Get all cached versions of exchange APIs
497
+ /// </summary>
498
+ /// <returns>All APIs</returns>
499
+ public static async Task < IExchangeAPI [ ] > GetExchangeAPIsAsync ( )
500
+ {
501
+ var apiList = new List < IExchangeAPI > ( ) ;
502
+ foreach ( var kv in apis . ToArray ( ) )
454
503
{
455
- List < IExchangeAPI > apiList = new List < IExchangeAPI > ( ) ;
456
- foreach ( var kv in apis . ToArray ( ) )
504
+ if ( kv . Value == null )
457
505
{
458
- if ( kv . Value == null )
459
- {
460
- apiList . Add ( GetExchangeAPI ( kv . Key ) ) ;
461
- }
462
- else
463
- {
464
- apiList . Add ( kv . Value ) ;
465
- }
506
+ apiList . Add ( await GetExchangeAPIAsync ( kv . Key ) ) ;
507
+ }
508
+ else
509
+ {
510
+ apiList . Add ( await kv . Value ) ;
466
511
}
467
- return apiList . ToArray ( ) ;
468
512
}
469
- return apis . Values . ToArray ( ) ;
513
+ return apiList . ToArray ( ) ;
470
514
}
471
515
472
516
/// <summary>
0 commit comments