Skip to content

Commit

Permalink
chore: refactored DefaultRemoteLoggingConstraintProvider to separate …
Browse files Browse the repository at this point in the history
…createRequest from the rest of the class, allowing for signed and unsigned requests to be sent
  • Loading branch information
khatruong2009 committed Sep 8, 2023
1 parent 529b34a commit c045708
Showing 1 changed file with 72 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -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.
Expand All @@ -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<LoggingConstraint?> init() async {
Expand All @@ -74,16 +73,32 @@ class DefaultRemoteLoggingConstraintProvider
return null;
}

Future<void> _saveConstraintLocally(LoggingConstraint constraint) async {
await storage.saveConstraintLocally(constraint.toJson());
/// Creates a request to fetch the constraint from the endpoint.
@protected
Future<AWSHttpRequest> 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<void> _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<String, dynamic>,
);
_loggingConstraint = fetchedConstraint;
await storage.saveConstraintLocally(fetchedConstraint.toJson());
}
} on Exception catch (exception) {
throw Exception(
Expand All @@ -96,53 +111,7 @@ class DefaultRemoteLoggingConstraintProvider
}
}

Future<LoggingConstraint?> _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<String, dynamic>,
);
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;

Expand All @@ -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<AWSHttpRequest> 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}
Expand Down

0 comments on commit c045708

Please sign in to comment.