From c686e1f7dcf7445ded15b4c2741d4c60f7d587c6 Mon Sep 17 00:00:00 2001 From: Joseph Cosentino Date: Fri, 28 Jun 2024 16:16:22 -0700 Subject: [PATCH] chore: finish cache impl --- .../configuration/RuntimeConfiguration.java | 78 +++++++++++++++++-- .../auth/iot/ThingAttributesCache.java | 12 +-- .../auth/iot/dto/ThingAssociationV1DTO.java | 2 +- .../auth/iot/dto/ThingDescriptionV1DTO.java | 2 +- 4 files changed, 78 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/aws/greengrass/clientdevices/auth/configuration/RuntimeConfiguration.java b/src/main/java/com/aws/greengrass/clientdevices/auth/configuration/RuntimeConfiguration.java index 85215498f..c6c6720bd 100644 --- a/src/main/java/com/aws/greengrass/clientdevices/auth/configuration/RuntimeConfiguration.java +++ b/src/main/java/com/aws/greengrass/clientdevices/auth/configuration/RuntimeConfiguration.java @@ -16,6 +16,11 @@ import com.aws.greengrass.util.Coerce; import lombok.NonNull; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -46,6 +51,16 @@ * | |---- certificateId: * | |---- "s": status * | |---- "l": lastUpdated + * | |---- "clientDeviceThingAssociations": + * | |---- "v1": + * | |---- associations: [...] + * | |---- "l": lastUpdated + * | |---- "clientDeviceThingDescription": + * | |---- "v1": + * | |---- thingName: + * | |---- "attributes": + * | |---- k:v + * | |---- "l": lastUpdated * | |---- "hostAddresses": * |---- : * |---- [...] @@ -64,6 +79,14 @@ public final class RuntimeConfiguration { static final String CERTS_STATUS_UPDATED_KEY = "l"; private static final String HOST_ADDRESSES_KEY = "hostAddresses"; + private static final String ASSOCIATIONS_KEY = "clientDeviceThingAssociations"; + private static final String ASSOCIATIONS_V1 = "v1"; + private static final String DESCRIPTION_KEY = "clientDeviceThingDescription"; + private static final String DESCRIPTION_V1 = "v1"; + private static final String LAST_UPDATED_KEY = "l"; + private static final String ASSOCIATIONS_PROP_KEY = "associations"; + private static final String ATTRIBUTES_PROP_KEY = "attributes"; + private final Topics config; @@ -206,20 +229,59 @@ public void removeCertificateV1(String certificateId) { } } - public void putThingAssociationV1(ThingAssociationV1DTO thingAssociationV1DTO) { - // TODO + public void putThingAssociationV1(ThingAssociationV1DTO dto) { + Topics t = getOrRepairTopics(config, ASSOCIATIONS_KEY, ASSOCIATIONS_V1); + t.lookup(ASSOCIATIONS_PROP_KEY).withValue(new ArrayList<>(dto.getAssociatedThingNames())); + t.lookup(LAST_UPDATED_KEY).withValue(dto.getLastUpdated().toEpochSecond(ZoneOffset.UTC)); } - public ThingAssociationV1DTO getThingAssociationV1() { - return null; // TODO + public Optional getThingAssociationV1() { + Topics t = config.findTopics(ASSOCIATIONS_KEY, ASSOCIATIONS_V1); + if (t == null) { + return Optional.empty(); + } + + Set thingNames = new HashSet<>(); + Topic associationsTopic = t.find(ASSOCIATIONS_PROP_KEY); + if (associationsTopic != null) { + thingNames.addAll(Coerce.toStringList(associationsTopic)); + } + + LocalDateTime lastFetched = null; + Topic lastFetchedTopic = t.find(LAST_UPDATED_KEY); + if (lastFetchedTopic != null) { + lastFetched = LocalDateTime.ofInstant(Instant.ofEpochMilli(Coerce.toLong(lastFetchedTopic)), + ZoneId.of("UTC")); + } + return Optional.of(new ThingAssociationV1DTO(thingNames, lastFetched)); } - public void putThingDescriptionV1(ThingDescriptionV1DTO thingDescriptionV1DTO) { - // TODO + public void putThingDescriptionV1(ThingDescriptionV1DTO dto) { + Topics t = getOrRepairTopics(config, DESCRIPTION_KEY, DESCRIPTION_V1, dto.getThingName()); + t.lookup(LAST_UPDATED_KEY).withValue(dto.getLastUpdated().toEpochSecond(ZoneOffset.UTC)); + Map attrs = new HashMap<>(dto.getAttributes()); + getOrRepairTopics(t, ATTRIBUTES_PROP_KEY).replaceAndWait(attrs); } - public ThingDescriptionV1DTO getThingDescriptionV1(String thingName) { - return null; // TODO + public Optional getThingDescriptionV1(String thingName) { + Topics t = config.findTopics(DESCRIPTION_KEY, DESCRIPTION_V1, thingName); + if (t == null) { + return Optional.empty(); + } + + Map attrs = new HashMap<>(); + Topics attributesTopic = t.findTopics(ATTRIBUTES_PROP_KEY); + if (attributesTopic != null && !attributesTopic.isEmpty()) { + attributesTopic.forEach(node -> attrs.put(node.getName(), Coerce.toString(node))); + } + + LocalDateTime lastFetched = null; + Topic lastFetchedTopic = t.find(LAST_UPDATED_KEY); + if (lastFetchedTopic != null) { + lastFetched = LocalDateTime.ofInstant(Instant.ofEpochMilli(Coerce.toLong(lastFetchedTopic)), + ZoneId.of("UTC")); + } + return Optional.of(new ThingDescriptionV1DTO(thingName, attrs, lastFetched)); } private Topics getOrRepairTopics(Topics root, String... path) { diff --git a/src/main/java/com/aws/greengrass/clientdevices/auth/iot/ThingAttributesCache.java b/src/main/java/com/aws/greengrass/clientdevices/auth/iot/ThingAttributesCache.java index 7a284bb74..15d9778f7 100644 --- a/src/main/java/com/aws/greengrass/clientdevices/auth/iot/ThingAttributesCache.java +++ b/src/main/java/com/aws/greengrass/clientdevices/auth/iot/ThingAttributesCache.java @@ -154,12 +154,12 @@ private void refresh() { private Optional> getAssociatedThingNames() { // use cached value, provided it's not stale - ThingAssociationV1DTO dto = runtimeConfiguration.getThingAssociationV1(); + Optional dto = runtimeConfiguration.getThingAssociationV1(); // TODO pull from configuration - if (dto != null && dto.getLastFetched().plusSeconds(DEFAULT_THING_ASSOCIATION_TRUST_DURATION_SECONDS) + if (dto.isPresent() && dto.get().getLastUpdated().plusSeconds(DEFAULT_THING_ASSOCIATION_TRUST_DURATION_SECONDS) .isBefore(LocalDateTime.now())) { logger.atTrace().log("Using locally cached thing associations"); - return Optional.ofNullable(dto.getAssociatedThingNames()); + return dto.map(ThingAssociationV1DTO::getAssociatedThingNames); } if (networkStateProvider.getConnectionState() == NetworkStateProvider.ConnectionState.NETWORK_DOWN) { @@ -192,12 +192,12 @@ private Optional> fetchAssociatedThingNames() { private Optional> getThingAttributes(String thingName) { // use cached value, provided it's not stale - ThingDescriptionV1DTO dto = runtimeConfiguration.getThingDescriptionV1(thingName); + Optional dto = runtimeConfiguration.getThingDescriptionV1(thingName); // TODO pull from configuration - if (dto != null && dto.getLastFetched().plusSeconds(DEFAULT_THING_DESCRIPTION_TRUST_DURATION_SECONDS) + if (dto.isPresent() && dto.get().getLastUpdated().plusSeconds(DEFAULT_THING_DESCRIPTION_TRUST_DURATION_SECONDS) .isBefore(LocalDateTime.now())) { logger.atTrace().log("Using locally cached thing description"); - return Optional.ofNullable(dto.getAttributes()); + return dto.map(ThingDescriptionV1DTO::getAttributes); } if (networkStateProvider.getConnectionState() == NetworkStateProvider.ConnectionState.NETWORK_DOWN) { diff --git a/src/main/java/com/aws/greengrass/clientdevices/auth/iot/dto/ThingAssociationV1DTO.java b/src/main/java/com/aws/greengrass/clientdevices/auth/iot/dto/ThingAssociationV1DTO.java index 1ba7343c4..219398383 100644 --- a/src/main/java/com/aws/greengrass/clientdevices/auth/iot/dto/ThingAssociationV1DTO.java +++ b/src/main/java/com/aws/greengrass/clientdevices/auth/iot/dto/ThingAssociationV1DTO.java @@ -15,5 +15,5 @@ @AllArgsConstructor public class ThingAssociationV1DTO { Set associatedThingNames; - LocalDateTime lastFetched; + LocalDateTime lastUpdated; } diff --git a/src/main/java/com/aws/greengrass/clientdevices/auth/iot/dto/ThingDescriptionV1DTO.java b/src/main/java/com/aws/greengrass/clientdevices/auth/iot/dto/ThingDescriptionV1DTO.java index 8c05c4598..66400032e 100644 --- a/src/main/java/com/aws/greengrass/clientdevices/auth/iot/dto/ThingDescriptionV1DTO.java +++ b/src/main/java/com/aws/greengrass/clientdevices/auth/iot/dto/ThingDescriptionV1DTO.java @@ -16,5 +16,5 @@ public class ThingDescriptionV1DTO { String thingName; Map attributes; - LocalDateTime lastFetched; + LocalDateTime lastUpdated; }