You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
145 lines
3.4 KiB
145 lines
3.4 KiB
1 year ago
|
import 'dart:convert';
|
||
|
import 'dart:typed_data';
|
||
|
|
||
|
import 'package:cookie_jar/cookie_jar.dart';
|
||
|
import 'package:universal_io/io.dart';
|
||
|
|
||
|
export 'package:cookie_jar/cookie_jar.dart';
|
||
|
|
||
|
extension DynamiteHttpClientResponseBody on HttpClientResponse {
|
||
|
Future<Uint8List> get bodyBytes async {
|
||
|
final chunks = await toList();
|
||
|
if (chunks.isEmpty) {
|
||
|
return Uint8List(0);
|
||
|
}
|
||
|
return Uint8List.fromList(chunks.reduce((final value, final element) => [...value, ...element]));
|
||
|
}
|
||
|
|
||
|
Future<String> get body async => utf8.decode(await bodyBytes);
|
||
|
}
|
||
|
|
||
|
class DynamiteResponse<T, U> {
|
||
|
DynamiteResponse(
|
||
|
this.data,
|
||
|
this.headers,
|
||
|
);
|
||
|
|
||
|
final T data;
|
||
|
|
||
|
final U headers;
|
||
|
|
||
|
@override
|
||
|
String toString() => 'DynamiteResponse(data: $data, headers: $headers)';
|
||
|
}
|
||
|
|
||
|
class RawResponse {
|
||
|
RawResponse(
|
||
|
this.statusCode,
|
||
|
this.headers,
|
||
|
this.body,
|
||
|
);
|
||
|
|
||
|
final int statusCode;
|
||
|
|
||
|
final Map<String, String> headers;
|
||
|
|
||
|
final Uint8List body;
|
||
|
|
||
|
@override
|
||
|
String toString() => 'RawResponse(statusCode: $statusCode, headers: $headers, body: ${utf8.decode(body)})';
|
||
|
}
|
||
|
|
||
|
class DynamiteApiException extends RawResponse implements Exception {
|
||
|
DynamiteApiException(
|
||
|
super.statusCode,
|
||
|
super.headers,
|
||
|
super.body,
|
||
|
);
|
||
|
|
||
|
@override
|
||
|
String toString() =>
|
||
|
'DynamiteApiException(statusCode: ${super.statusCode}, headers: ${super.headers}, body: ${utf8.decode(super.body)})';
|
||
|
}
|
||
|
|
||
|
abstract class DynamiteAuthentication {
|
||
|
String get id;
|
||
|
Map<String, String> get headers;
|
||
|
}
|
||
|
|
||
|
class DynamiteHttpBasicAuthentication extends DynamiteAuthentication {
|
||
|
DynamiteHttpBasicAuthentication({
|
||
|
required this.username,
|
||
|
required this.password,
|
||
|
});
|
||
|
|
||
|
final String username;
|
||
|
|
||
|
final String password;
|
||
|
|
||
|
@override
|
||
|
String get id => 'basic_auth';
|
||
|
@override
|
||
|
Map<String, String> get headers => {
|
||
|
'Authorization': 'Basic ${base64.encode(utf8.encode('$username:$password'))}',
|
||
|
};
|
||
|
}
|
||
|
|
||
|
class DynamiteClient {
|
||
|
DynamiteClient(
|
||
|
this.baseURL, {
|
||
|
final Map<String, String>? baseHeaders,
|
||
|
final String? userAgent,
|
||
|
final HttpClient? httpClient,
|
||
|
this.cookieJar,
|
||
|
this.authentications = const [],
|
||
|
}) {
|
||
|
this.baseHeaders = {
|
||
|
...?baseHeaders,
|
||
|
};
|
||
|
this.httpClient = (httpClient ?? HttpClient())..userAgent = userAgent;
|
||
|
}
|
||
|
|
||
|
final String baseURL;
|
||
|
|
||
|
late final Map<String, String> baseHeaders;
|
||
|
|
||
|
late final HttpClient httpClient;
|
||
|
|
||
|
final CookieJar? cookieJar;
|
||
|
|
||
|
final List<DynamiteAuthentication> authentications;
|
||
|
|
||
|
Future<RawResponse> doRequest(
|
||
|
final String method,
|
||
|
final String path,
|
||
|
final Map<String, String> headers,
|
||
|
final Uint8List? body,
|
||
|
) async {
|
||
|
final uri = Uri.parse('$baseURL$path');
|
||
|
final request = await httpClient.openUrl(method, uri);
|
||
|
for (final header in {...baseHeaders, ...headers}.entries) {
|
||
|
request.headers.add(header.key, header.value);
|
||
|
}
|
||
|
if (body != null) {
|
||
|
request.add(body.toList());
|
||
|
}
|
||
|
if (cookieJar != null) {
|
||
|
request.cookies.addAll(await cookieJar!.loadForRequest(uri));
|
||
|
}
|
||
|
|
||
|
final response = await request.close();
|
||
|
if (cookieJar != null) {
|
||
|
await cookieJar!.saveFromResponse(uri, response.cookies);
|
||
|
}
|
||
|
final responseHeaders = <String, String>{};
|
||
|
response.headers.forEach((final name, final values) {
|
||
|
responseHeaders[name] = values.last;
|
||
|
});
|
||
|
return RawResponse(
|
||
|
response.statusCode,
|
||
|
responseHeaders,
|
||
|
await response.bodyBytes,
|
||
|
);
|
||
|
}
|
||
|
}
|