diff --git a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart index 66fb93e0bc..1e67721d5d 100644 --- a/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart +++ b/packages/logging_cloudwatch/aws_logging_cloudwatch/lib/src/remote_constraint_provider.dart @@ -14,6 +14,7 @@ import 'package:aws_logging_cloudwatch/src/file_storage/file_storage.vm.dart' if (dart.library.html) 'package:aws_logging_cloudwatch/src/file_storage/file_storage.web.dart' as storage; import 'package:aws_signature_v4/aws_signature_v4.dart'; +import 'package:meta/meta.dart'; /// {@template aws_logging_cloudwatch.remote_logging_constraint_provider} /// An Interface to provide custom implementation for @@ -25,15 +26,15 @@ abstract class RemoteLoggingConstraintProvider { LoggingConstraint? get loggingConstraint; } -/// {@template aws_logging_cloudwatch.default_remote_logging_constraint_provider} -/// Default implementation of [RemoteLoggingConstraintProvider] to fetch -/// [LoggingConstraint] from an http endpoint periodically. +/// {@template aws_logging_cloudwatch.base_remote_constraints_provider} +/// Base class for [RemoteLoggingConstraintProvider] to provide +/// [LoggingConstraint] from a remote location and cache it. /// {@endtemplate} -class DefaultRemoteLoggingConstraintProvider +base class BaseRemoteLoggingConstraintProvider with AWSDebuggable, AWSLoggerMixin implements RemoteLoggingConstraintProvider { - /// {@macro aws_logging_cloudwatch.default_remote_logging_constraint_provider} - DefaultRemoteLoggingConstraintProvider({ + /// {@macro aws_logging_cloudwatch.base_remote_constraints_provider} + BaseRemoteLoggingConstraintProvider({ required DefaultRemoteConfiguration config, required AWSCredentialsProvider credentialsProvider, }) : _config = config, @@ -46,9 +47,6 @@ class DefaultRemoteLoggingConstraintProvider LoggingConstraint? _loggingConstraint; - /// The signer to sign the request. - static const _signer = AWSSigV4Signer(); - final AWSHttpClient _awsHttpClient = AWSHttpClient(); // The timer to refresh the constraint periodically. @@ -57,10 +55,11 @@ class DefaultRemoteLoggingConstraintProvider /// Whether the periodic fetch is running. bool _isRunning = false; + /// Retrives the runtime type name used for logging. @override - String get runtimeTypeName => 'DefaultRemoteLoggingConstraintProvider'; + String get runtimeTypeName => 'BaseRemoteConstraintsProvider'; - /// Initializes the [DefaultRemoteLoggingConstraintProvider] by fetching + /// Initializes the [BaseRemoteLoggingConstraintProvider] by fetching /// the constraint from the endpoint initially and then /// starting the refresh timer afterwards. Future init() async { @@ -74,16 +73,32 @@ class DefaultRemoteLoggingConstraintProvider return null; } - Future _saveConstraintLocally(LoggingConstraint constraint) async { - await storage.saveConstraintLocally(constraint.toJson()); + /// Creates a request to fetch the constraint from the endpoint. + @protected + Future createRequest() async { + final uri = Uri.parse(_config.endpoint); + return AWSHttpRequest( + method: AWSHttpMethod.get, + uri: uri, + headers: const { + AWSHeaders.accept: 'application/json; charset=utf-8', + }, + ); } + /// Fetches the constraint from the endpoint and caches it. Future _fetchAndCacheConstraintFromEndpoint() async { try { - final constraint = await _fetchConstraintFromEndpoint(); - if (constraint != null) { - _loggingConstraint = constraint; - await _saveConstraintLocally(constraint); + final request = await createRequest(); + final operation = _awsHttpClient.send(request); + final response = await operation.response; + final body = await response.decodeBody(); + if (response.statusCode == 200) { + final fetchedConstraint = LoggingConstraint.fromJson( + jsonDecode(body) as Map, + ); + _loggingConstraint = fetchedConstraint; + await storage.saveConstraintLocally(fetchedConstraint.toJson()); } } on Exception catch (exception) { throw Exception( @@ -96,53 +111,7 @@ class DefaultRemoteLoggingConstraintProvider } } - Future _fetchConstraintFromEndpoint() async { - final uri = Uri.parse(_config.endpoint); - - final request = AWSHttpRequest( - method: AWSHttpMethod.get, - uri: uri, - headers: { - AWSHeaders.host: uri.host, - }, - ); - - final scope = AWSCredentialScope( - region: _config.region, - service: AWSService.apiGatewayManagementApi, - ); - - final signedRequest = await _signer.sign( - request, - credentialScope: scope, - ); - - final newRequest = AWSHttpRequest( - method: signedRequest.method, - uri: signedRequest.uri, - headers: { - ...signedRequest.headers, - AWSHeaders.accept: 'application/json; charset=utf-8', - }, - ); - - final operation = _awsHttpClient.send(newRequest); - - final response = await operation.response; - - final body = await response.decodeBody(); - - if (response.statusCode == 200) { - final fetchedConstraint = LoggingConstraint.fromJson( - jsonDecode(body) as Map, - ); - return fetchedConstraint; - } - throw Exception( - 'Failed to fetch logging constraint from ${_config.endpoint}', - ); - } - + /// Returns [LoggingConstraint] from cache or `null` if cache is missing. @override LoggingConstraint? get loggingConstraint => _loggingConstraint; @@ -164,8 +133,46 @@ class DefaultRemoteLoggingConstraintProvider } } +/// {@template aws_logging_cloudwatch.default_remote_logging_constraint_provider} +/// Default implementation of [RemoteLoggingConstraintProvider] to fetch +/// [LoggingConstraint] from an http endpoint periodically. +/// {@endtemplate} +final class DefaultRemoteLoggingConstraintProvider + extends BaseRemoteLoggingConstraintProvider { + /// {@macro aws_logging_cloudwatch.default_remote_logging_constraint_provider} + DefaultRemoteLoggingConstraintProvider({ + required super.config, + required this.credentialsProvider, + }) : super(credentialsProvider: credentialsProvider); + + /// The credentials provider to use for signing the request. + final AWSCredentialsProvider credentialsProvider; + + /// The signer to use for signing the request. + final AWSSigV4Signer _signer = const AWSSigV4Signer(); + + @override + Future createRequest() async { + final baseRequest = await super.createRequest(); + final scope = AWSCredentialScope( + region: _config.region, + service: AWSService.apiGatewayManagementApi, + ); + + final signedRequest = await _signer.sign( + baseRequest, + credentialScope: scope, + ); + + final newRequest = + AWSHttpRequest(method: signedRequest.method, uri: signedRequest.uri); + + return newRequest; + } +} + /// {@template aws_logging_cloudwatch.default_remote_configuration} -/// The configuration for [DefaultRemoteLoggingConstraintProvider] +/// The configuration for [BaseRemoteLoggingConstraintProvider] /// {@endtemplate} class DefaultRemoteConfiguration { /// {@macro aws_logging_cloudwatch.default_remote_configuration}