Skip to content

Commit 4ec8f1c

Browse files
fix: refactor HttpService (#149)
* wip: http service * fix: persist client in httpservice [#63] * fix: pr changes --------- Co-authored-by: Simon Lightfoot <[email protected]>
1 parent bf73a7e commit 4ec8f1c

File tree

6 files changed

+113
-63
lines changed

6 files changed

+113
-63
lines changed

packages/clerk_auth/lib/src/clerk_api/api.dart

+14-12
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,23 @@ class Api with Logging {
2222
/// Create an [Api] object
2323
///
2424
Api({
25-
required AuthConfig config,
25+
required this.config,
26+
required this.httpService,
2627
required Persistor persistor,
27-
required HttpService httpService,
28-
}) : _config = config,
29-
_tokenCache = TokenCache(
28+
}) : _tokenCache = TokenCache(
3029
persistor: persistor,
3130
publishableKey: config.publishableKey,
3231
),
33-
_httpService = httpService,
3432
_domain = _deriveDomainFrom(config.publishableKey),
3533
_testMode = config.isTestMode;
3634

37-
final AuthConfig _config;
35+
/// The config used to initialise this api instance.
36+
final AuthConfig config;
37+
38+
/// The [HttpService] used to send the server requests.
39+
final HttpService httpService;
40+
3841
final TokenCache _tokenCache;
39-
final HttpService _httpService;
4042
final String _domain;
4143

4244
bool _testMode;
@@ -62,7 +64,7 @@ class Api with Logging {
6264
/// Initialise the API
6365
Future<void> initialize() async {
6466
await _tokenCache.initialize();
65-
if (_config.sessionTokenPollMode == SessionTokenPollMode.hungry) {
67+
if (config.sessionTokenPollMode == SessionTokenPollMode.hungry) {
6668
await _pollForSessionToken();
6769
}
6870
}
@@ -86,7 +88,7 @@ class Api with Logging {
8688
final body = json.decode(resp.body) as Map<String, dynamic>;
8789
final env = Environment.fromJson(body);
8890

89-
_testMode = env.config.testMode && _config.isTestMode;
91+
_testMode = env.config.testMode && config.isTestMode;
9092
_multiSessionMode = env.config.singleSessionMode == false;
9193

9294
return env;
@@ -727,7 +729,7 @@ class Api with Logging {
727729
try {
728730
final length = await file.length();
729731
final stream = http.ByteStream(file.openRead());
730-
final resp = await _httpService.sendByteStream(
732+
final resp = await httpService.sendByteStream(
731733
method,
732734
uri,
733735
stream,
@@ -818,7 +820,7 @@ class Api with Logging {
818820
_queryParams(method, withSession: withSession, params: parsedParams);
819821
final uri = _uri(path, params: queryParams);
820822

821-
final resp = await _httpService.send(
823+
final resp = await httpService.send(
822824
method,
823825
uri,
824826
headers: headers,
@@ -873,7 +875,7 @@ class Api with Logging {
873875
}) {
874876
return {
875877
HttpHeaders.acceptHeader: 'application/json',
876-
HttpHeaders.acceptLanguageHeader: _config.localesLookup().join(', '),
878+
HttpHeaders.acceptLanguageHeader: config.localesLookup().join(', '),
877879
HttpHeaders.contentTypeHeader: method.isGet
878880
? 'application/json'
879881
: 'application/x-www-form-urlencoded',

packages/clerk_auth/lib/src/clerk_api/token_cache.dart

+14-15
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,14 @@ class TokenCache {
1313
/// Create a [TokenCache] instance
1414
///
1515
TokenCache({
16-
required Persistor persistor,
16+
required this.persistor,
1717
required String publishableKey,
18-
}) //
19-
: _persistor = persistor,
20-
_cacheId = publishableKey.hashCode;
18+
}) : _cacheId = publishableKey.hashCode;
2119

22-
final Persistor _persistor;
23-
final int _cacheId;
20+
/// The [Persistor] used to store session and client data
21+
final Persistor persistor;
2422

23+
final int _cacheId;
2524
final _sessionTokens = <String, SessionToken>{};
2625

2726
String _sessionId = '';
@@ -51,10 +50,10 @@ class TokenCache {
5150
/// Initialise the cache
5251
Future<void> initialize() async {
5352
// Read all stored variables first before assignment
54-
final sessionId = await _persistor.read(_sessionIdKey) ?? '';
53+
final sessionId = await persistor.read(_sessionIdKey) ?? '';
5554
_sessionId = sessionId;
5655

57-
final sessionTokens = await _persistor.read(_sessionTokenKey);
56+
final sessionTokens = await persistor.read(_sessionTokenKey);
5857
if (sessionTokens case String sessionTokens) {
5958
final sessionTokenData =
6059
json.decode(sessionTokens) as Map<String, dynamic>;
@@ -67,10 +66,10 @@ class TokenCache {
6766
}
6867
}
6968

70-
final clientToken = await _persistor.read(_clientTokenKey) ?? '';
69+
final clientToken = await persistor.read(_clientTokenKey) ?? '';
7170
_clientToken = clientToken;
7271

73-
final clientId = await _persistor.read(_clientIdKey) ?? '';
72+
final clientId = await persistor.read(_clientIdKey) ?? '';
7473
_clientId = clientId;
7574
}
7675

@@ -82,7 +81,7 @@ class TokenCache {
8281
_clientId = '';
8382
_sessionTokens.clear();
8483
for (final key in _persistorKeys) {
85-
_persistor.delete(key);
84+
persistor.delete(key);
8685
}
8786
}
8887

@@ -93,7 +92,7 @@ class TokenCache {
9392
if (_sessionId == id) return;
9493

9594
_sessionId = id;
96-
_persistor.write(_sessionIdKey, id);
95+
persistor.write(_sessionIdKey, id);
9796
}
9897

9998
/// Get the [clientToken]
@@ -103,7 +102,7 @@ class TokenCache {
103102
if (token == _clientToken) return;
104103

105104
_clientToken = token;
106-
_persistor.write(_clientTokenKey, token);
105+
persistor.write(_clientTokenKey, token);
107106
}
108107

109108
/// Get the [clientId]
@@ -113,7 +112,7 @@ class TokenCache {
113112
if (_clientId == id) return;
114113

115114
_clientId = id;
116-
_persistor.write(_clientIdKey, id);
115+
persistor.write(_clientIdKey, id);
117116
}
118117

119118
/// Get the [sessionTokenFor] for a [orgId]
@@ -137,7 +136,7 @@ class TokenCache {
137136
final id = _sessionTokenId(sessionToken.orgId, templateName);
138137
if (token != _sessionTokens[id]?.jwt) {
139138
_sessionTokens[id] = sessionToken;
140-
_persistor.write(_sessionTokenKey, json.encode(_sessionTokens));
139+
persistor.write(_sessionTokenKey, json.encode(_sessionTokens));
141140
}
142141

143142
return _sessionTokens[id]!;

packages/clerk_auth/lib/src/clerk_auth/auth.dart

+25-17
Original file line numberDiff line numberDiff line change
@@ -26,29 +26,35 @@ class Auth {
2626
/// Create an [Auth] object using appropriate Clerk credentials
2727
Auth({
2828
required this.config,
29-
Persistor persistor = Persistor.none,
30-
HttpService httpService = const DefaultHttpService(),
31-
}) : telemetry = Telemetry(
32-
config: config,
33-
persistor: persistor,
34-
httpService: httpService,
35-
),
36-
_api = Api(
37-
config: config,
38-
persistor: persistor,
39-
httpService: httpService,
40-
);
29+
required Persistor persistor,
30+
HttpService? httpService,
31+
}) {
32+
this.httpService = httpService ?? DefaultHttpService();
33+
telemetry = Telemetry(
34+
config: config,
35+
persistor: persistor,
36+
httpService: this.httpService,
37+
);
38+
_api = Api(
39+
config: config,
40+
persistor: persistor,
41+
httpService: this.httpService,
42+
);
43+
}
4144

4245
/// Use 'English' as the default locale
4346
static List<String> defaultLocalesLookup() => <String>['en'];
4447

45-
/// The service to send telemetry to the back end
46-
final Telemetry telemetry;
47-
4848
/// The configuration object
4949
final AuthConfig config;
5050

51-
final Api _api;
51+
/// The [HttpService] used to communicate with the backend.
52+
late final HttpService httpService;
53+
54+
/// The service to send telemetry to the back end
55+
late final Telemetry telemetry;
56+
57+
late final Api _api;
5258
Timer? _clientTimer;
5359

5460
static const _codeLength = 6;
@@ -106,6 +112,7 @@ class Auth {
106112
/// object is made
107113
///
108114
Future<void> initialize() async {
115+
await httpService.initialise();
109116
await _api.initialize();
110117
final [client, env] = await Future.wait([
111118
_api.createClient(),
@@ -131,8 +138,9 @@ class Auth {
131138
///
132139
void terminate() {
133140
_clientTimer?.cancel();
134-
telemetry.terminate();
135141
_api.terminate();
142+
telemetry.terminate();
143+
httpService.terminate();
136144
}
137145

138146
/// Refresh the current [Client]

packages/clerk_auth/lib/src/clerk_auth/http_service.dart

+46-17
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
import 'dart:async';
12
import 'dart:io';
23

34
import 'package:clerk_auth/src/utils/extensions.dart';
4-
import 'package:http/http.dart';
5+
import 'package:http/http.dart' as http;
56

67
/// Enum detailing [HttpMethod]s used by the Clerk API
78
enum HttpMethod {
@@ -33,10 +34,25 @@ enum HttpMethod {
3334
/// Abstract class defining the interface to call the
3435
/// Clerk back-end over http
3536
///
36-
abstract class HttpService {
37+
abstract interface class HttpService {
38+
/// Construct a [HttpService]
39+
const HttpService();
40+
41+
/// Initialises this instance of the http service
42+
///
43+
/// It is possible that [initialise] will be called
44+
/// multiple times, and must be prepared for that to happen
45+
Future<void> initialise();
46+
47+
/// Terminates this instance of the http service
48+
///
49+
/// It is possible that [terminate] will be called
50+
/// multiple times, and must be prepared for that to happen
51+
void terminate();
52+
3753
/// [send] data to the back end, and receive a [Response]
3854
///
39-
Future<Response> send(
55+
Future<http.Response> send(
4056
HttpMethod method,
4157
Uri uri, {
4258
Map<String, String>? headers,
@@ -46,30 +62,43 @@ abstract class HttpService {
4662

4763
/// Upload a [File] to the back end, and receive a [Response]
4864
///
49-
Future<Response> sendByteStream(
65+
Future<http.Response> sendByteStream(
5066
HttpMethod method,
5167
Uri uri,
52-
ByteStream byteStream,
68+
http.ByteStream byteStream,
5369
int length,
5470
Map<String, String> headers,
5571
);
5672
}
5773

5874
/// Default implementation of [HttpService]
5975
///
60-
class DefaultHttpService implements HttpService {
76+
class DefaultHttpService extends HttpService {
6177
/// Constructor
62-
const DefaultHttpService();
78+
DefaultHttpService();
79+
80+
http.Client? _client;
81+
82+
@override
83+
Future<void> initialise() async {
84+
_client ??= http.Client();
85+
}
86+
87+
@override
88+
void terminate() {
89+
_client?.close();
90+
_client = null;
91+
}
6392

6493
@override
65-
Future<Response> send(
94+
Future<http.Response> send(
6695
HttpMethod method,
6796
Uri uri, {
6897
Map<String, String>? headers,
6998
Map<String, dynamic>? params,
7099
String? body,
71100
}) async {
72-
final request = Request(method.toString(), uri);
101+
final request = http.Request(method.toString(), uri);
73102

74103
if (headers case Map<String, String> headers) {
75104
request.headers.addAll(headers);
@@ -83,30 +112,30 @@ class DefaultHttpService implements HttpService {
83112
request.body = body;
84113
}
85114

86-
final streamedResponse = await request.send();
87-
return Response.fromStream(streamedResponse);
115+
final streamedResponse = await _client!.send(request);
116+
return http.Response.fromStream(streamedResponse);
88117
}
89118

90119
@override
91-
Future<Response> sendByteStream(
120+
Future<http.Response> sendByteStream(
92121
HttpMethod method,
93122
Uri uri,
94-
ByteStream byteStream,
123+
http.ByteStream byteStream,
95124
int length,
96125
Map<String, String> headers,
97126
) async {
98-
final request = MultipartRequest(method.toString(), uri);
127+
final request = http.MultipartRequest(method.toString(), uri);
99128
request.headers.addAll(headers);
100129

101-
final multipartFile = MultipartFile(
130+
final multipartFile = http.MultipartFile(
102131
'file',
103132
byteStream,
104133
length,
105134
filename: byteStream.hashCode.toString(),
106135
);
107136
request.files.add(multipartFile);
108137

109-
final streamedResponse = await request.send();
110-
return Response.fromStream(streamedResponse);
138+
final streamedResponse = await _client!.send(request);
139+
return http.Response.fromStream(streamedResponse);
111140
}
112141
}

packages/clerk_auth/test/test_helpers.dart

+12
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ class TestLogPrinter extends Printer {
3737
class TestHttpService implements HttpService {
3838
final _expectations = <String, List<Response>>{};
3939

40+
@override
41+
Future<void> initialise() async {}
42+
43+
@override
44+
void terminate() {}
45+
4046
@override
4147
Future<Response> send(
4248
HttpMethod method,
@@ -131,6 +137,12 @@ const noneHttpService = NoneHttpService();
131137
class NoneHttpService implements HttpService {
132138
const NoneHttpService();
133139

140+
@override
141+
Future<void> initialise() async {}
142+
143+
@override
144+
void terminate() {}
145+
134146
@override
135147
Future<Response> send(
136148
HttpMethod method,

0 commit comments

Comments
 (0)