7
7
using System ;
8
8
using System . Linq ;
9
9
using System . Threading . Tasks ;
10
- using System . Threading ; // Interlocked
11
-
12
- // https://support.box.com/hc/en-us/community/posts/360049144934-Refresh-Token-Expiring-in-1-hour
13
10
14
11
namespace ClassTranscribeDatabase . Services
15
12
{
16
13
public class BoxAPI
17
14
{
18
- private static int refreshing = 0 ;
19
15
private readonly SlackLogger _slack ;
20
16
private readonly ILogger _logger ;
21
- private readonly BoxConfig _config ;
22
17
public BoxAPI ( ILogger < BoxAPI > logger , SlackLogger slack )
23
18
{
24
19
_logger = logger ;
25
20
_slack = slack ;
26
- _config = new BoxConfig ( Globals . appSettings . BOX_CLIENT_ID , Globals . appSettings . BOX_CLIENT_SECRET , new Uri ( "http://locahost" ) ) ;
27
21
}
28
22
29
- // Used by Controller/BoxController.cs
30
23
// To generate authCode on a browser open,
31
24
// https://account.box.com/api/oauth2/authorize?client_id=[CLIENT_ID]&response_type=code
32
25
/// <summary>Updates Box accessToken and refreshToken values in the Dictionary table.
@@ -37,11 +30,30 @@ public async Task CreateAccessTokenAsync(string authCode)
37
30
// This implementation is overly chatty with the database, but we rarely create access tokens so it is not a problem
38
31
using ( var _context = CTDbContext . CreateDbContext ( ) )
39
32
{
40
- var client = new Box . V2 . BoxClient ( _config ) ;
33
+ if ( ! await _context . Dictionaries . Where ( d => d . Key == CommonUtils . BOX_ACCESS_TOKEN ) . AnyAsync ( ) )
34
+ {
35
+ _context . Dictionaries . Add ( new Dictionary
36
+ {
37
+ Key = CommonUtils . BOX_ACCESS_TOKEN
38
+ } ) ;
39
+ await _context . SaveChangesAsync ( ) ;
40
+ }
41
+ if ( ! await _context . Dictionaries . Where ( d => d . Key == CommonUtils . BOX_REFRESH_TOKEN ) . AnyAsync ( ) )
42
+ {
43
+ _context . Dictionaries . Add ( new Dictionary
44
+ {
45
+ Key = CommonUtils . BOX_REFRESH_TOKEN
46
+ } ) ;
47
+ await _context . SaveChangesAsync ( ) ;
48
+ }
49
+
50
+
51
+ var accessToken = _context . Dictionaries . Where ( d => d . Key == CommonUtils . BOX_ACCESS_TOKEN ) . First ( ) ;
52
+ var refreshToken = _context . Dictionaries . Where ( d => d . Key == CommonUtils . BOX_REFRESH_TOKEN ) . First ( ) ;
53
+ var config = new BoxConfig ( Globals . appSettings . BOX_CLIENT_ID , Globals . appSettings . BOX_CLIENT_SECRET , new Uri ( "http://locahost" ) ) ;
54
+ var client = new Box . V2 . BoxClient ( config ) ;
41
55
var auth = await client . Auth . AuthenticateAsync ( authCode ) ;
42
56
_logger . LogInformation ( "Created Box Tokens" ) ;
43
- //Dictionary accessToken,refreshToken;
44
- var ( accessToken , refreshToken ) = await getOrCreateDatabaseEntries ( _context ) ;
45
57
accessToken . Value = auth . AccessToken ;
46
58
refreshToken . Value = auth . RefreshToken ;
47
59
await _context . SaveChangesAsync ( ) ;
@@ -52,42 +64,23 @@ public async Task CreateAccessTokenAsync(string authCode)
52
64
/// </summary>
53
65
public async Task RefreshAccessTokenAsync ( )
54
66
{
55
- _logger . LogInformation ( "RefreshAccessTokenAsync: Starting" ) ;
56
67
try
57
68
{
58
69
using ( var _context = CTDbContext . CreateDbContext ( ) )
59
70
{
60
- // Dictionary accessToken,refreshToken ;
61
- var ( accessToken , refreshToken ) = await getOrCreateDatabaseEntries ( _context ) ;
62
-
71
+ var accessToken = await _context . Dictionaries . Where ( d => d . Key == CommonUtils . BOX_ACCESS_TOKEN ) . FirstAsync ( ) ;
72
+ var refreshToken = await _context . Dictionaries . Where ( d => d . Key == CommonUtils . BOX_REFRESH_TOKEN ) . FirstAsync ( ) ;
73
+ var config = new BoxConfig ( Globals . appSettings . BOX_CLIENT_ID , Globals . appSettings . BOX_CLIENT_SECRET , new Uri ( "http://locahost" ) ) ;
63
74
var auth = new OAuthSession ( accessToken . Value , refreshToken . Value , 3600 , "bearer" ) ;
64
- var client = new BoxClient ( _config , auth ) ;
75
+ var client = new BoxClient ( config , auth ) ;
65
76
/// Try to refresh the access token
66
77
auth = await client . Auth . RefreshAccessTokenAsync ( auth . AccessToken ) ;
67
- _logger . LogInformation ( "RefreshAccessTokenAsync: Complete (RefreshAccessTokenAsync returned)" ) ;
68
78
/// Create the client again
69
- client = new BoxClient ( _config , auth ) ;
70
- if ( accessToken . Value != auth . AccessToken )
71
- {
72
- _logger . LogInformation ( $ "Access Token Changed to ({ auth . AccessToken . Substring ( 4 ) } ...)") ;
73
- }
74
- else
75
- {
76
- _logger . LogInformation ( $ "Access Token Unchanged ({ auth . AccessToken . Substring ( 4 ) } ...)") ;
77
- }
78
- if ( refreshToken . Value != auth . RefreshToken )
79
- {
80
- _logger . LogInformation ( $ "Refresh Token Changed to ({ auth . RefreshToken . Substring ( 4 ) } ...") ;
81
- }
82
- else
83
- {
84
- _logger . LogInformation ( $ "Refresh Token Unchanged ({ auth . RefreshToken . Substring ( 4 ) } ...") ;
85
- }
86
-
79
+ client = new BoxClient ( config , auth ) ;
80
+ _logger . LogInformation ( "Refreshed Tokens" ) ;
87
81
accessToken . Value = auth . AccessToken ;
88
82
refreshToken . Value = auth . RefreshToken ;
89
83
await _context . SaveChangesAsync ( ) ;
90
- _logger . LogInformation ( "RefreshAccessTokenAsync: Complete (database updated)" ) ;
91
84
}
92
85
}
93
86
catch ( Box . V2 . Exceptions . BoxSessionInvalidatedException e )
@@ -96,111 +89,24 @@ public async Task RefreshAccessTokenAsync()
96
89
await _slack . PostErrorAsync ( e , "Box Token Failure." ) ;
97
90
throw ;
98
91
}
99
- _logger . LogInformation ( "RefreshAccessTokenAsync: returning" ) ;
100
-
101
- }
102
- public async Task < ( Dictionary , Dictionary ) > getOrCreateDatabaseEntries ( CTDbContext context )
103
- {
104
- // sanity check- expect 0 or 1 entries for key
105
- if ( await context . Dictionaries . Where ( d=> d . Key == CommonUtils . BOX_ACCESS_TOKEN ) . CountAsync ( ) > 1
106
- || await context . Dictionaries . Where ( d=> d . Key == CommonUtils . BOX_REFRESH_TOKEN ) . CountAsync ( ) > 1 )
107
- { // should never happen
108
- var badEntries = context . Dictionaries . Where ( d=> d . Key == CommonUtils . BOX_ACCESS_TOKEN || d . Key == CommonUtils . BOX_REFRESH_TOKEN ) ;
109
- context . Dictionaries . RemoveRange ( badEntries ) ;
110
- await context . SaveChangesAsync ( ) ;
111
- }
112
- var changed = false ;
113
-
114
- var accessToken = await context . Dictionaries . Where ( d => d . Key == CommonUtils . BOX_ACCESS_TOKEN ) . FirstOrDefaultAsync ( ) ;
115
- var refreshToken = await context . Dictionaries . Where ( d => d . Key == CommonUtils . BOX_REFRESH_TOKEN ) . FirstOrDefaultAsync ( ) ;
116
-
117
- if ( accessToken == null )
118
- {
119
- accessToken = new Dictionary
120
- {
121
- Key = CommonUtils . BOX_ACCESS_TOKEN
122
- } ;
123
- context . Dictionaries . Add ( accessToken ) ;
124
- changed = true ;
125
- }
126
- if ( refreshToken == null )
127
- {
128
- refreshToken = new Dictionary
129
- {
130
- Key = CommonUtils . BOX_REFRESH_TOKEN
131
- } ;
132
- context . Dictionaries . Add ( refreshToken ) ;
133
- changed = true ;
134
- }
135
- if ( changed )
136
- {
137
- await context . SaveChangesAsync ( ) ;
138
- }
139
- return ( accessToken , refreshToken ) ;
140
92
}
141
-
142
93
/// <summary>
143
94
/// Creates a new box client, after first refreshing the access and refresh token.
144
95
/// </summary>
145
96
public async Task < BoxClient > GetBoxClientAsync ( )
146
97
{
147
98
// Todo RefreshAccessTokenAsync could return this information for us; and avoid another trip to the database
148
- int attempt = 1 ;
149
- int maxAttempt = 10 ;
150
- while ( attempt < maxAttempt )
99
+ await RefreshAccessTokenAsync ( ) ;
100
+ BoxClient boxClient ;
101
+ using ( var _context = CTDbContext . CreateDbContext ( ) )
151
102
{
152
- using ( var _context = CTDbContext . CreateDbContext ( ) )
153
- {
154
- _logger . LogInformation ( $ "GetBoxClientAsync: Attempt { attempt } of { maxAttempt } to get valid client") ;
155
- // var accessToken = await _context.Dictionaries.Where(d => d.Key == CommonUtils.BOX_ACCESS_TOKEN).FirstOrDefaultAsync();
156
- //Dictionary accessToken,refreshToken;
157
-
158
- var ( accessToken , refreshToken ) = await getOrCreateDatabaseEntries ( _context ) ;
159
-
160
- if ( string . IsNullOrEmpty ( accessToken . Value ) )
161
- {
162
- _logger . LogInformation ( $ "GetBoxClientAsync: Attempting box client using access token ({ accessToken . Value . Substring ( 4 ) } ...") ;
163
- try
164
- {
165
- var auth = new OAuthSession ( accessToken . Value , "" , 3600 , "bearer" ) ;
166
-
167
- var client = new BoxClient ( _config , auth ) ;
168
- _logger . LogInformation ( $ "GetBoxClientAsync: Attempt { attempt } returning client using existing access token") ;
169
- return client ; // Normal return here
170
- }
171
- catch ( Exception e )
172
- {
173
- _logger . LogInformation ( e , "GetBoxClientAsync: Existing access token is invalid" ) ;
174
- }
175
- }
176
- }
177
- if ( refreshing > 0 )
178
- {
179
- var sleep = 5 + 5 * attempt ;
180
- _logger . LogInformation ( $ "GetBoxClientAsync: refresh in progress - Sleeping { sleep } seconds - Give time for another thread to refresh the token before retrying") ;
181
- await Task . Delay ( sleep * 1000 ) ;
182
- }
183
- else
184
- {
185
- Interlocked . Increment ( ref refreshing ) ; // threadsafe refreshing ++;
186
- _logger . LogInformation ( $ "GetBoxClientAsync: Calling RefreshAccessTokenAsync") ;
187
- await RefreshAccessTokenAsync ( ) ;
188
- Interlocked . Decrement ( ref refreshing ) ;
189
- }
103
+ var accessToken = await _context . Dictionaries . Where ( d => d . Key == CommonUtils . BOX_ACCESS_TOKEN ) . FirstAsync ( ) ;
104
+ var refreshToken = await _context . Dictionaries . Where ( d => d . Key == CommonUtils . BOX_REFRESH_TOKEN ) . FirstAsync ( ) ;
105
+ var config = new BoxConfig ( Globals . appSettings . BOX_CLIENT_ID , Globals . appSettings . BOX_CLIENT_SECRET , new Uri ( "http://locahost" ) ) ;
106
+ var auth = new OAuthSession ( accessToken . Value , refreshToken . Value , 3600 , "bearer" ) ;
107
+ boxClient = new Box . V2 . BoxClient ( config , auth ) ;
190
108
}
191
- _logger . LogError ( "Failed to authenticate with Box" ) ;
192
- throw new Exception ( "Failed to authenticate with Box" ) ;
193
- // BoxClient boxClient;
194
- // using (var _context = CTDbContext.CreateDbContext())
195
- // {
196
- // var accessToken = await _context.Dictionaries.Where(d => d.Key == CommonUtils.BOX_ACCESS_TOKEN).FirstAsync();
197
- // var refreshToken = await _context.Dictionaries.Where(d => d.Key == CommonUtils.BOX_REFRESH_TOKEN).FirstAsync();
198
- // var config = new BoxConfig(Globals.appSettings.BOX_CLIENT_ID, Globals.appSettings.BOX_CLIENT_SECRET, new Uri("http://locahost"));
199
- // var auth = new OAuthSession(accessToken.Value, refreshToken.Value, 3600, "bearer");
200
- // boxClient = new Box.V2.BoxClient(config, auth);
201
- // }
202
- // return boxClient;
109
+ return boxClient ;
203
110
}
204
111
}
205
112
}
206
-
0 commit comments