import 'dart:async'; 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 get bodyBytes async { final buffer = BytesBuilder(); await forEach(buffer.add); return buffer.toBytes(); } Future get body => transform(utf8.decoder).join(); Future get jsonBody => transform(utf8.decoder).transform(json.decoder).first; Map get responseHeaders { final responseHeaders = {}; headers.forEach((final name, final values) { responseHeaders[name] = values.last; }); return responseHeaders; } } class DynamiteResponse { DynamiteResponse( this.data, this.headers, ); final T data; final U headers; @override String toString() => 'DynamiteResponse(data: $data, headers: $headers)'; } class DynamiteApiException implements Exception { DynamiteApiException( this.statusCode, this.headers, this.body, ); final int statusCode; final Map headers; final String body; @override String toString() => 'DynamiteApiException(statusCode: $statusCode, headers: $headers, body: $body)'; } abstract class DynamiteAuthentication { String get type; String get scheme; Map get headers; } class DynamiteHttpBasicAuthentication extends DynamiteAuthentication { DynamiteHttpBasicAuthentication({ required this.username, required this.password, }); final String username; final String password; @override String type = 'http'; @override String scheme = 'basic'; @override Map get headers => { 'Authorization': 'Basic ${base64.encode(utf8.encode('$username:$password'))}', }; } class DynamiteHttpBearerAuthentication extends DynamiteAuthentication { DynamiteHttpBearerAuthentication({ required this.token, }); final String token; @override String type = 'http'; @override String scheme = 'bearer'; @override Map get headers => { 'Authorization': 'Bearer $token', }; } class DynamiteClient { DynamiteClient( this.baseURL, { this.baseHeaders, final String? userAgent, final HttpClient? httpClient, this.cookieJar, this.authentications = const [], }) : httpClient = (httpClient ?? HttpClient())..userAgent = userAgent; final String baseURL; final Map? baseHeaders; final HttpClient httpClient; final CookieJar? cookieJar; final List authentications; Future doRequest( final String method, final String path, final Map 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); } return response; } }