From 9ef27d4882895907758ea678f5fdaf69503d87f1 Mon Sep 17 00:00:00 2001 From: Johannes Buechele <johannes@bujo.at> Date: Wed, 26 Jul 2023 17:28:53 +0200 Subject: [PATCH] added ipfs cluster support --- .gitignore | 1 + .../faircommons/ipfs_service/api/IpfsApi.java | 31 ---------- .../config/IpfsServiceConfiguration.java | 2 + .../service/IpfsClusterService.java | 56 +++++++++++++++++++ .../service/IpfsDaemonService.java | 32 +++++++++++ .../ipfs_service/service/IpfsService.java | 38 +------------ .../service/IpfsServiceMessageHandler.java | 8 ++- .../ipfs_service/models/IpfsAddView.java | 17 ++++++ .../src/main/resources/application.yml | 3 + faircommons-services/pom.xml | 2 +- 10 files changed, 119 insertions(+), 71 deletions(-) delete mode 100644 faircommons-services/ipfs-service/src/main/java/eu/fairkom/faircommons/ipfs_service/api/IpfsApi.java create mode 100644 faircommons-services/ipfs-service/src/main/java/eu/fairkom/faircommons/ipfs_service/service/IpfsClusterService.java create mode 100644 faircommons-services/ipfs-service/src/main/java/eu/fairkom/faircommons/ipfs_service/service/IpfsDaemonService.java create mode 100644 faircommons-services/ipfs-service/src/main/lombok/eu/fairkom/faircommons/ipfs_service/models/IpfsAddView.java diff --git a/.gitignore b/.gitignore index a6d7dc8..a4ede89 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ .idea/**/usage.statistics.xml .idea/**/dictionaries .idea/**/shelf +faircommons-services/ipfs-service/ipfs-service.iml # AWS User-specific .idea/**/aws.xml diff --git a/faircommons-services/ipfs-service/src/main/java/eu/fairkom/faircommons/ipfs_service/api/IpfsApi.java b/faircommons-services/ipfs-service/src/main/java/eu/fairkom/faircommons/ipfs_service/api/IpfsApi.java deleted file mode 100644 index 04bed1b..0000000 --- a/faircommons-services/ipfs-service/src/main/java/eu/fairkom/faircommons/ipfs_service/api/IpfsApi.java +++ /dev/null @@ -1,31 +0,0 @@ -package eu.fairkom.faircommons.ipfs_service.api; - -import eu.fairkom.faircommons.ipfs_service.service.IpfsService; -import org.springframework.core.io.Resource; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.multipart.MultipartFile; - -import java.io.IOException; - -@RestController -@RequestMapping("/ipfs") -public class IpfsApi { - private final IpfsService ipfsService; - - public IpfsApi(IpfsService ipfsService) { - this.ipfsService = ipfsService; - } - - @PostMapping(value = "upload") - public String uploadFile(@RequestParam("file") MultipartFile file) throws IOException { - return ipfsService.saveFile(file.getInputStream()); - } - - @GetMapping(value = "/{hash}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) - public ResponseEntity<Resource> loadFile(@PathVariable("hash") String hash) { - var file = ipfsService.loadFile(hash); - return ResponseEntity.ok(file); - } -} diff --git a/faircommons-services/ipfs-service/src/main/java/eu/fairkom/faircommons/ipfs_service/config/IpfsServiceConfiguration.java b/faircommons-services/ipfs-service/src/main/java/eu/fairkom/faircommons/ipfs_service/config/IpfsServiceConfiguration.java index d0a1c34..a2ecf24 100644 --- a/faircommons-services/ipfs-service/src/main/java/eu/fairkom/faircommons/ipfs_service/config/IpfsServiceConfiguration.java +++ b/faircommons-services/ipfs-service/src/main/java/eu/fairkom/faircommons/ipfs_service/config/IpfsServiceConfiguration.java @@ -6,6 +6,7 @@ import eu.fairkom.faircommons.common.security.SecurityWebAutoConfiguration; import io.ipfs.api.IPFS; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; @@ -18,6 +19,7 @@ import org.springframework.context.annotation.Import; @Import(value = {SecurityWebAutoConfiguration.class}) public class IpfsServiceConfiguration { @Bean + @ConditionalOnProperty(prefix = "ipfs", name = "service", havingValue = "daemon") IPFS ipfsClient(@Value("${ipfs.host}") String host, @Value("${ipfs.port}") int port) { return new IPFS(host, port); } diff --git a/faircommons-services/ipfs-service/src/main/java/eu/fairkom/faircommons/ipfs_service/service/IpfsClusterService.java b/faircommons-services/ipfs-service/src/main/java/eu/fairkom/faircommons/ipfs_service/service/IpfsClusterService.java new file mode 100644 index 0000000..f3e10fc --- /dev/null +++ b/faircommons-services/ipfs-service/src/main/java/eu/fairkom/faircommons/ipfs_service/service/IpfsClusterService.java @@ -0,0 +1,56 @@ +package eu.fairkom.faircommons.ipfs_service.service; + +import eu.fairkom.faircommons.ipfs_service.models.IpfsAddView; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.core.io.InputStreamResource; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; + +import java.io.InputStream; + +@Service +@ConditionalOnProperty(prefix = "ipfs", name = "service", havingValue = "cluster") +public class IpfsClusterService implements IpfsService { + private static final Logger logger = LoggerFactory.getLogger(IpfsClusterService.class); + private static final String UPLOAD_ENDPOINT = "/add?pin=true"; + private final RestTemplate restTemplate; + + public IpfsClusterService(RestTemplateBuilder restTemplateBuilder, + @Value("${ipfs.url}") String baseUrl) { + this.restTemplate = restTemplateBuilder.rootUri(baseUrl) + .build(); + } + + /** + * Uploads a file to IPFS. + * @param inputStream The InputStream of the file to upload. + * @return the CID of the uploaded file. + */ + @Override + public String uploadFile(InputStream inputStream) { + try { + var body = new LinkedMultiValueMap<>(); + body.set("file", new InputStreamResource(inputStream)); + + var headers = new HttpHeaders(); + headers.setContentType(MediaType.MULTIPART_FORM_DATA); + + var requestEntity = new HttpEntity<>(body, headers); + var response = restTemplate.postForEntity(UPLOAD_ENDPOINT, requestEntity, IpfsAddView.class); + + return response.getBody().getCid(); + } catch (RestClientException e) { + logger.error("Error uploading file to IPFS", e); + throw new RuntimeException("Failed to upload file to IPFS.", e); + } + } +} diff --git a/faircommons-services/ipfs-service/src/main/java/eu/fairkom/faircommons/ipfs_service/service/IpfsDaemonService.java b/faircommons-services/ipfs-service/src/main/java/eu/fairkom/faircommons/ipfs_service/service/IpfsDaemonService.java new file mode 100644 index 0000000..21945b8 --- /dev/null +++ b/faircommons-services/ipfs-service/src/main/java/eu/fairkom/faircommons/ipfs_service/service/IpfsDaemonService.java @@ -0,0 +1,32 @@ +package eu.fairkom.faircommons.ipfs_service.service; + +import io.ipfs.api.IPFS; +import io.ipfs.api.NamedStreamable; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; + +@Service +@ConditionalOnProperty(prefix = "ipfs", name = "service", havingValue = "daemon") +public class IpfsDaemonService implements IpfsService { + private final IPFS ipfsClient; + + public IpfsDaemonService(IPFS ipfsClient) { + this.ipfsClient = ipfsClient; + } + + @Override + public String uploadFile(InputStream inputStream) { + try { + var inputStreamWrapper = new NamedStreamable.InputStreamWrapper(inputStream); + var merkleNode = ipfsClient.add(inputStreamWrapper).get(0); + + return merkleNode.hash.toBase58(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } +} diff --git a/faircommons-services/ipfs-service/src/main/java/eu/fairkom/faircommons/ipfs_service/service/IpfsService.java b/faircommons-services/ipfs-service/src/main/java/eu/fairkom/faircommons/ipfs_service/service/IpfsService.java index 8206061..5176bea 100644 --- a/faircommons-services/ipfs-service/src/main/java/eu/fairkom/faircommons/ipfs_service/service/IpfsService.java +++ b/faircommons-services/ipfs-service/src/main/java/eu/fairkom/faircommons/ipfs_service/service/IpfsService.java @@ -1,41 +1,7 @@ package eu.fairkom.faircommons.ipfs_service.service; -import io.ipfs.api.IPFS; -import io.ipfs.api.NamedStreamable; -import io.ipfs.multihash.Multihash; -import org.springframework.core.io.InputStreamResource; -import org.springframework.core.io.Resource; -import org.springframework.stereotype.Service; - -import java.io.IOException; import java.io.InputStream; -import java.io.UncheckedIOException; - -@Service -public class IpfsService { - private final IPFS ipfsClient; - - public IpfsService(IPFS ipfsClient) { - this.ipfsClient = ipfsClient; - } - - public String saveFile(InputStream inputStream) { - try { - var inputStreamWrapper = new NamedStreamable.InputStreamWrapper(inputStream); - var merkleNode = ipfsClient.add(inputStreamWrapper).get(0); - - return merkleNode.hash.toBase58(); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - public Resource loadFile(String hash) { - try { - var filePointer = Multihash.fromBase58(hash); - return new InputStreamResource(ipfsClient.catStream(filePointer)); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } +public interface IpfsService { + String uploadFile(InputStream inputStream); } diff --git a/faircommons-services/ipfs-service/src/main/java/eu/fairkom/faircommons/ipfs_service/service/IpfsServiceMessageHandler.java b/faircommons-services/ipfs-service/src/main/java/eu/fairkom/faircommons/ipfs_service/service/IpfsServiceMessageHandler.java index a7a1040..e7fa30b 100644 --- a/faircommons-services/ipfs-service/src/main/java/eu/fairkom/faircommons/ipfs_service/service/IpfsServiceMessageHandler.java +++ b/faircommons-services/ipfs-service/src/main/java/eu/fairkom/faircommons/ipfs_service/service/IpfsServiceMessageHandler.java @@ -21,7 +21,9 @@ public class IpfsServiceMessageHandler extends MessageHandler { private final MinioService minioService; private final IpfsService ipfsService; - public IpfsServiceMessageHandler(RabbitTemplate rabbitTemplate, MinioService minioService, IpfsService ipfsService) { + public IpfsServiceMessageHandler(RabbitTemplate rabbitTemplate, + MinioService minioService, + IpfsService ipfsService) { super(rabbitTemplate); this.minioService = minioService; this.ipfsService = ipfsService; @@ -33,7 +35,7 @@ public class IpfsServiceMessageHandler extends MessageHandler { var filename = message.getWorkFile().getFilenameWithPrefix(); try (var workFileStream = minioService.downloadFile(userId, filename)) { - var cid = ipfsService.saveFile(workFileStream); + var cid = ipfsService.uploadFile(workFileStream); var ipfsEntry = buildIpfsEntryView("", cid); logger.info("Work File successfully saved to IPFS. Sending success event."); @@ -47,7 +49,7 @@ public class IpfsServiceMessageHandler extends MessageHandler { public void handleMetaDataMessage(MetaDataMessage message) { try (var metaDataStream = new ByteArrayInputStream(message.getMetaData().getBytes(StandardCharsets.UTF_8))) { - var cid = ipfsService.saveFile(metaDataStream); + var cid = ipfsService.uploadFile(metaDataStream); var ipfsEntry = buildIpfsEntryView("", cid); logger.info("Meta Data successfully saved to IPFS. Sending success event."); diff --git a/faircommons-services/ipfs-service/src/main/lombok/eu/fairkom/faircommons/ipfs_service/models/IpfsAddView.java b/faircommons-services/ipfs-service/src/main/lombok/eu/fairkom/faircommons/ipfs_service/models/IpfsAddView.java new file mode 100644 index 0000000..08c4f15 --- /dev/null +++ b/faircommons-services/ipfs-service/src/main/lombok/eu/fairkom/faircommons/ipfs_service/models/IpfsAddView.java @@ -0,0 +1,17 @@ +package eu.fairkom.faircommons.ipfs_service.models; + +import lombok.Builder; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +import java.util.List; + +@Value +@Builder +@Jacksonized +public class IpfsAddView { + String name; + String cid; + int size; + List<String> allocations; +} diff --git a/faircommons-services/ipfs-service/src/main/resources/application.yml b/faircommons-services/ipfs-service/src/main/resources/application.yml index 7c39f32..7c4df3e 100644 --- a/faircommons-services/ipfs-service/src/main/resources/application.yml +++ b/faircommons-services/ipfs-service/src/main/resources/application.yml @@ -20,6 +20,9 @@ minio: bucketPrefix: fairregister- region: eu-central-1 +ipfs: + service: daemon + security: web: resource: diff --git a/faircommons-services/pom.xml b/faircommons-services/pom.xml index 852218a..59e758f 100644 --- a/faircommons-services/pom.xml +++ b/faircommons-services/pom.xml @@ -6,7 +6,7 @@ <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> - <version>3.0.5</version> + <version>3.1.2</version> <relativePath/> <!-- lookup parent from repository --> </parent> -- GitLab