diff --git a/api/src/main/java/org/cardanofoundation/tokenmetadata/registry/api/controller/HealthApi.java b/api/src/main/java/org/cardanofoundation/tokenmetadata/registry/api/controller/HealthApi.java new file mode 100644 index 0000000..0823732 --- /dev/null +++ b/api/src/main/java/org/cardanofoundation/tokenmetadata/registry/api/controller/HealthApi.java @@ -0,0 +1,24 @@ +package org.cardanofoundation.tokenmetadata.registry.api.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.cardanofoundation.tokenmetadata.registry.api.model.rest.HealthResponse; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +@Validated +@Tag(name = "health", description = "Health Endpoint for the cardano token metadata registry") +public interface HealthApi { + + @Operation(operationId = "getHealthStatus", summary = "Returns health status of service including if the initial sync is done", responses = { + @ApiResponse(responseCode = "200", content = @Content(mediaType = "application/json", schema = @Schema(implementation = HealthResponse.class))) + }) + @RequestMapping(method = RequestMethod.GET, value = "/health", produces = {"application/json;charset=utf-8"}) + ResponseEntity getHealthStatus(); + +} diff --git a/api/src/main/java/org/cardanofoundation/tokenmetadata/registry/api/controller/HealthApiController.java b/api/src/main/java/org/cardanofoundation/tokenmetadata/registry/api/controller/HealthApiController.java new file mode 100644 index 0000000..08ef470 --- /dev/null +++ b/api/src/main/java/org/cardanofoundation/tokenmetadata/registry/api/controller/HealthApiController.java @@ -0,0 +1,31 @@ +package org.cardanofoundation.tokenmetadata.registry.api.controller; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.cardanofoundation.tokenmetadata.registry.api.model.rest.HealthResponse; +import org.cardanofoundation.tokenmetadata.registry.service.SyncStatus; +import org.cardanofoundation.tokenmetadata.registry.service.TokenMetadataSyncService; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@CrossOrigin +@RequestMapping("${openapi.metadataServer.base-path:}") +@Slf4j +@RequiredArgsConstructor +public class HealthApiController implements HealthApi { + + private final TokenMetadataSyncService tokenMetadataSyncService; + + @Override + public ResponseEntity getHealthStatus() { + SyncStatus syncStatus = tokenMetadataSyncService.getSyncStatus(); + return new ResponseEntity<>(HealthResponse.builder() + .synced(syncStatus.isInitialSyncDone()) + .syncStatus(syncStatus.getSyncStatus().toString()) + .build(), HttpStatus.OK); + } +} diff --git a/api/src/main/java/org/cardanofoundation/tokenmetadata/registry/api/model/rest/HealthResponse.java b/api/src/main/java/org/cardanofoundation/tokenmetadata/registry/api/model/rest/HealthResponse.java new file mode 100644 index 0000000..ad16ae5 --- /dev/null +++ b/api/src/main/java/org/cardanofoundation/tokenmetadata/registry/api/model/rest/HealthResponse.java @@ -0,0 +1,25 @@ +package org.cardanofoundation.tokenmetadata.registry.api.model.rest; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.cardanofoundation.tokenmetadata.registry.model.enums.SyncStatusEnum; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class HealthResponse { + + @JsonProperty("synced") + @Valid + private boolean synced; + + @JsonProperty("syncStatus") + @Valid + private String syncStatus; + +} diff --git a/api/src/main/resources/api.yaml b/api/src/main/resources/api.yaml index 9c28e1e..9516bac 100644 --- a/api/src/main/resources/api.yaml +++ b/api/src/main/resources/api.yaml @@ -18,6 +18,19 @@ x-tagGroups: - v1 queries - v2 queries paths: + /health: + get: + summary: "Get Health status" + tags: + - v1 queries + operationId: "health" + responses: + 200: + description: "Health Response including if initial sync is done and current syncing status." + content: + application/json;charset=utf-8: + schema: + $ref: '#/components/schemas/HealthResponse' /metadata/{subject}: get: summary: "Query All Properties" @@ -545,6 +558,13 @@ components: type: array items: $ref: '#/components/schemas/Property' + HealthResponse: + type: object + properties: + synced: + type: boolean + syncStatus: + type: string BatchRequest: required: - subjects diff --git a/common/src/main/java/org/cardanofoundation/tokenmetadata/registry/model/enums/SyncStatusEnum.java b/common/src/main/java/org/cardanofoundation/tokenmetadata/registry/model/enums/SyncStatusEnum.java new file mode 100644 index 0000000..b2a4d62 --- /dev/null +++ b/common/src/main/java/org/cardanofoundation/tokenmetadata/registry/model/enums/SyncStatusEnum.java @@ -0,0 +1,23 @@ +package org.cardanofoundation.tokenmetadata.registry.model.enums; + +import org.cardanofoundation.tokenmetadata.registry.util.Constants; + +public enum SyncStatusEnum { + + SYNC_NOT_STARTED(Constants.SYNC_NOT_STARTED), + SYNC_IN_PROGRESS(Constants.SYNC_IN_PROGRESS), + SYNC_DONE(Constants.SYNC_DONE), + SYNC_ERROR(Constants.SYNC_ERROR), + SYNC_IN_EXTRA_JOB(Constants.SYNC_IN_EXTRA_JOB); + + private final String text; + + SyncStatusEnum(final String text) { + this.text = text; + } + + @Override + public String toString() { + return text; + } +} diff --git a/common/src/main/java/org/cardanofoundation/tokenmetadata/registry/service/SyncStatus.java b/common/src/main/java/org/cardanofoundation/tokenmetadata/registry/service/SyncStatus.java new file mode 100644 index 0000000..dfd3744 --- /dev/null +++ b/common/src/main/java/org/cardanofoundation/tokenmetadata/registry/service/SyncStatus.java @@ -0,0 +1,14 @@ +package org.cardanofoundation.tokenmetadata.registry.service; + +import lombok.Builder; +import lombok.Data; +import org.cardanofoundation.tokenmetadata.registry.model.enums.SyncStatusEnum; + +@Builder +@Data +public class SyncStatus { + + private boolean isInitialSyncDone; + private SyncStatusEnum syncStatus; + +} diff --git a/common/src/main/java/org/cardanofoundation/tokenmetadata/registry/service/TokenMetadataSyncService.java b/common/src/main/java/org/cardanofoundation/tokenmetadata/registry/service/TokenMetadataSyncService.java index 4c4dee4..c467202 100644 --- a/common/src/main/java/org/cardanofoundation/tokenmetadata/registry/service/TokenMetadataSyncService.java +++ b/common/src/main/java/org/cardanofoundation/tokenmetadata/registry/service/TokenMetadataSyncService.java @@ -1,10 +1,14 @@ package org.cardanofoundation.tokenmetadata.registry.service; -import lombok.AllArgsConstructor; +import jakarta.annotation.PostConstruct; +import lombok.Getter; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.cardanofoundation.tokenmetadata.registry.model.Mapping; import org.cardanofoundation.tokenmetadata.registry.model.MappingDetails; import org.cardanofoundation.tokenmetadata.registry.model.MappingUpdateDetails; +import org.cardanofoundation.tokenmetadata.registry.model.enums.SyncStatusEnum; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.io.File; @@ -12,15 +16,11 @@ import java.util.Arrays; import java.util.Collection; import java.util.Optional; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; import java.util.stream.Stream; -import static java.util.stream.Collectors.groupingBy; - @Service @Slf4j -@AllArgsConstructor +@RequiredArgsConstructor public class TokenMetadataSyncService { private final GitService gitService; @@ -29,8 +29,25 @@ public class TokenMetadataSyncService { private final TokenMappingService tokenMappingService; + @Value("${token.metadata.job.enabled}") + private boolean isMetadataJobEnabled; + + @Getter + private SyncStatus syncStatus; + + @PostConstruct + private void initSyncStatus() { + if(isMetadataJobEnabled) { + syncStatus = new SyncStatus(false, SyncStatusEnum.SYNC_NOT_STARTED); + } else { + syncStatus = new SyncStatus(true, SyncStatusEnum.SYNC_IN_EXTRA_JOB); + } + } + public void synchronizeDatabase() { + syncStatus.setSyncStatus(SyncStatusEnum.SYNC_IN_PROGRESS); + Optional repoPathOpt = gitService.cloneCardanoTokenRegistryGitRepository(); if (repoPathOpt.isPresent()) { @@ -64,10 +81,15 @@ public void synchronizeDatabase() { }); + syncStatus.setSyncStatus(SyncStatusEnum.SYNC_DONE); + syncStatus.setInitialSyncDone(true); + } else { log.warn("cardano-token-registry could not be cloned"); + syncStatus.setSyncStatus(SyncStatusEnum.SYNC_ERROR); } } + } diff --git a/common/src/main/java/org/cardanofoundation/tokenmetadata/registry/util/Constants.java b/common/src/main/java/org/cardanofoundation/tokenmetadata/registry/util/Constants.java new file mode 100644 index 0000000..a8ff080 --- /dev/null +++ b/common/src/main/java/org/cardanofoundation/tokenmetadata/registry/util/Constants.java @@ -0,0 +1,13 @@ +package org.cardanofoundation.tokenmetadata.registry.util; + +public class Constants { + + private Constants() {} + + public static String SYNC_NOT_STARTED = "Sync not started"; + public static String SYNC_IN_PROGRESS = "Sync in progress"; + public static String SYNC_DONE = "Sync done"; + public static String SYNC_ERROR = "Error while syncing"; + public static String SYNC_IN_EXTRA_JOB = "Sync will be done in a different job. Status unkown"; + +}