diff --git a/server/src/main/java/org/eclipse/openvsx/ExtensionProcessor.java b/server/src/main/java/org/eclipse/openvsx/ExtensionProcessor.java index d32ed4558..38793ce9d 100644 --- a/server/src/main/java/org/eclipse/openvsx/ExtensionProcessor.java +++ b/server/src/main/java/org/eclipse/openvsx/ExtensionProcessor.java @@ -339,12 +339,7 @@ public FileResource getBinary(ExtensionVersion extVersion, String binaryName) { binary.setExtension(extVersion); binary.setName(binaryName); binary.setType(FileResource.DOWNLOAD); - try { - binary.setContent(Files.readAllBytes(extensionFile.getPath())); - } catch (IOException e) { - throw new RuntimeException(e); - } - + binary.setContent(null); return binary; } diff --git a/server/src/main/java/org/eclipse/openvsx/ExtensionService.java b/server/src/main/java/org/eclipse/openvsx/ExtensionService.java index 8e362e4f1..1caa5d052 100644 --- a/server/src/main/java/org/eclipse/openvsx/ExtensionService.java +++ b/server/src/main/java/org/eclipse/openvsx/ExtensionService.java @@ -23,13 +23,11 @@ import org.eclipse.openvsx.cache.CacheService; import org.eclipse.openvsx.entities.*; import org.eclipse.openvsx.publish.PublishExtensionVersionHandler; -import org.eclipse.openvsx.publish.PublishExtensionVersionJobRequest; import org.eclipse.openvsx.repositories.RepositoryService; import org.eclipse.openvsx.search.SearchUtilService; import org.eclipse.openvsx.util.ErrorResultException; import org.eclipse.openvsx.util.TempFile; import org.eclipse.openvsx.util.TimeUtil; -import org.jobrunr.scheduling.JobRequestScheduler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; @@ -52,9 +50,6 @@ public class ExtensionService { @Autowired PublishExtensionVersionHandler publishHandler; - @Autowired - JobRequestScheduler scheduler; - @Value("${ovsx.publishing.require-license:false}") boolean requireLicense; @@ -66,14 +61,10 @@ public ExtensionVersion mirrorVersion(TempFile extensionFile, String signatureNa } public ExtensionVersion publishVersion(InputStream content, PersonalAccessToken token) { - try(var extensionFile = createExtensionFile(content)) { - var download = doPublish(extensionFile, null, token, TimeUtil.getCurrentUTC(), true); - publishHandler.persistDownload(download); - scheduler.enqueue(new PublishExtensionVersionJobRequest(download.getId())); - return download.getExtension(); - } catch (IOException e) { - throw new RuntimeException(e); - } + var extensionFile = createExtensionFile(content); + var download = doPublish(extensionFile, null, token, TimeUtil.getCurrentUTC(), true); + publishHandler.publishAsync(download, extensionFile, this); + return download.getExtension(); } private FileResource doPublish(TempFile extensionFile, String binaryName, PersonalAccessToken token, LocalDateTime timestamp, boolean checkDependencies) { diff --git a/server/src/main/java/org/eclipse/openvsx/entities/AdminStatistics.java b/server/src/main/java/org/eclipse/openvsx/entities/AdminStatistics.java index 31ac57de5..203b06b8a 100644 --- a/server/src/main/java/org/eclipse/openvsx/entities/AdminStatistics.java +++ b/server/src/main/java/org/eclipse/openvsx/entities/AdminStatistics.java @@ -23,7 +23,8 @@ public class AdminStatistics { @Id - @GeneratedValue + @GeneratedValue(generator = "adminStatisticsSeq") + @SequenceGenerator(name = "adminStatisticsSeq", sequenceName = "admin_statistics_seq") long id; int year; diff --git a/server/src/main/java/org/eclipse/openvsx/entities/AzureDownloadCountProcessedItem.java b/server/src/main/java/org/eclipse/openvsx/entities/AzureDownloadCountProcessedItem.java index da0403309..ea25d052b 100644 --- a/server/src/main/java/org/eclipse/openvsx/entities/AzureDownloadCountProcessedItem.java +++ b/server/src/main/java/org/eclipse/openvsx/entities/AzureDownloadCountProcessedItem.java @@ -16,7 +16,8 @@ public class AzureDownloadCountProcessedItem { @Id - @GeneratedValue + @GeneratedValue(generator = "azureDownloadCountProcessedItemSeq") + @SequenceGenerator(name = "azureDownloadCountProcessedItemSeq", sequenceName = "azure_download_count_processed_item_seq") long id; String name; diff --git a/server/src/main/java/org/eclipse/openvsx/entities/Download.java b/server/src/main/java/org/eclipse/openvsx/entities/Download.java index 0847e1279..8c470e687 100644 --- a/server/src/main/java/org/eclipse/openvsx/entities/Download.java +++ b/server/src/main/java/org/eclipse/openvsx/entities/Download.java @@ -16,7 +16,8 @@ public class Download { @Id - @GeneratedValue + @GeneratedValue(generator = "downloadSeq") + @SequenceGenerator(name = "downloadSeq", sequenceName = "download_seq") long id; @Column(name = "file_resource_id_not_fk") diff --git a/server/src/main/java/org/eclipse/openvsx/entities/Extension.java b/server/src/main/java/org/eclipse/openvsx/entities/Extension.java index 5aaa1593c..8710e14f5 100644 --- a/server/src/main/java/org/eclipse/openvsx/entities/Extension.java +++ b/server/src/main/java/org/eclipse/openvsx/entities/Extension.java @@ -28,7 +28,8 @@ public class Extension implements Serializable { @Id - @GeneratedValue + @GeneratedValue(generator = "extensionSeq") + @SequenceGenerator(name = "extensionSeq", sequenceName = "extension_seq") long id; @Column(length = 128) diff --git a/server/src/main/java/org/eclipse/openvsx/entities/ExtensionReview.java b/server/src/main/java/org/eclipse/openvsx/entities/ExtensionReview.java index 171e7d6fa..989c876aa 100644 --- a/server/src/main/java/org/eclipse/openvsx/entities/ExtensionReview.java +++ b/server/src/main/java/org/eclipse/openvsx/entities/ExtensionReview.java @@ -11,11 +11,7 @@ import java.time.LocalDateTime; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; -import jakarta.persistence.ManyToOne; +import jakarta.persistence.*; import org.eclipse.openvsx.json.ReviewJson; import org.eclipse.openvsx.util.TimeUtil; @@ -24,8 +20,9 @@ public class ExtensionReview { @Id - @GeneratedValue - long id; + @GeneratedValue(generator = "extensionReviewSeq") + @SequenceGenerator(name = "extensionReviewSeq", sequenceName = "extension_review_seq") + long id; @ManyToOne Extension extension; diff --git a/server/src/main/java/org/eclipse/openvsx/entities/ExtensionVersion.java b/server/src/main/java/org/eclipse/openvsx/entities/ExtensionVersion.java index 33d625c1b..f34f22dda 100644 --- a/server/src/main/java/org/eclipse/openvsx/entities/ExtensionVersion.java +++ b/server/src/main/java/org/eclipse/openvsx/entities/ExtensionVersion.java @@ -41,7 +41,8 @@ public enum Type { } @Id - @GeneratedValue + @GeneratedValue(generator = "extensionVersionSeq") + @SequenceGenerator(name = "extensionVersionSeq", sequenceName = "extension_version_seq") long id; @ManyToOne diff --git a/server/src/main/java/org/eclipse/openvsx/entities/FileResource.java b/server/src/main/java/org/eclipse/openvsx/entities/FileResource.java index 19f7ca87d..9bc63e6bc 100644 --- a/server/src/main/java/org/eclipse/openvsx/entities/FileResource.java +++ b/server/src/main/java/org/eclipse/openvsx/entities/FileResource.java @@ -33,7 +33,8 @@ public class FileResource { public static final String STORAGE_AZURE = "azure-blob"; @Id - @GeneratedValue + @GeneratedValue(generator = "fileResourceSeq") + @SequenceGenerator(name = "fileResourceSeq", sequenceName = "file_resource_seq") long id; @OneToOne diff --git a/server/src/main/java/org/eclipse/openvsx/entities/MigrationItem.java b/server/src/main/java/org/eclipse/openvsx/entities/MigrationItem.java index 61270a416..963addf0a 100644 --- a/server/src/main/java/org/eclipse/openvsx/entities/MigrationItem.java +++ b/server/src/main/java/org/eclipse/openvsx/entities/MigrationItem.java @@ -9,15 +9,14 @@ * ****************************************************************************** */ package org.eclipse.openvsx.entities; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; +import jakarta.persistence.*; @Entity public class MigrationItem { @Id - @GeneratedValue + @GeneratedValue(generator = "migrationItemSeq") + @SequenceGenerator(name = "migrationItemSeq", sequenceName = "migration_item_seq") long id; String migrationScript; diff --git a/server/src/main/java/org/eclipse/openvsx/entities/Namespace.java b/server/src/main/java/org/eclipse/openvsx/entities/Namespace.java index 159e4e1f4..8cb8ec764 100644 --- a/server/src/main/java/org/eclipse/openvsx/entities/Namespace.java +++ b/server/src/main/java/org/eclipse/openvsx/entities/Namespace.java @@ -33,8 +33,9 @@ public class Namespace implements Serializable { private static final String SL_TWITTER = "twitter"; @Id - @GeneratedValue - long id; + @GeneratedValue(generator = "namespaceSeq") + @SequenceGenerator(name = "namespaceSeq", sequenceName = "namespace_seq") + long id; @Column(length = 128) String publicId; diff --git a/server/src/main/java/org/eclipse/openvsx/entities/NamespaceMembership.java b/server/src/main/java/org/eclipse/openvsx/entities/NamespaceMembership.java index 70e88594f..f4a4d4d93 100644 --- a/server/src/main/java/org/eclipse/openvsx/entities/NamespaceMembership.java +++ b/server/src/main/java/org/eclipse/openvsx/entities/NamespaceMembership.java @@ -9,12 +9,7 @@ ********************************************************************************/ package org.eclipse.openvsx.entities; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; +import jakarta.persistence.*; import org.eclipse.openvsx.json.NamespaceMembershipJson; @@ -28,7 +23,8 @@ public class NamespaceMembership implements Serializable { public static final String ROLE_CONTRIBUTOR = "contributor"; @Id - @GeneratedValue + @GeneratedValue(generator = "namespaceMembershipSeq") + @SequenceGenerator(name = "namespaceMembershipSeq", sequenceName = "namespace_membership_seq") long id; @ManyToOne diff --git a/server/src/main/java/org/eclipse/openvsx/entities/PersistedLog.java b/server/src/main/java/org/eclipse/openvsx/entities/PersistedLog.java index 9f2d09f94..2bcbf8d8e 100644 --- a/server/src/main/java/org/eclipse/openvsx/entities/PersistedLog.java +++ b/server/src/main/java/org/eclipse/openvsx/entities/PersistedLog.java @@ -11,19 +11,14 @@ import java.time.LocalDateTime; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.ForeignKey; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; +import jakarta.persistence.*; @Entity public class PersistedLog { @Id - @GeneratedValue + @GeneratedValue(generator = "persistedLogSeq") + @SequenceGenerator(name = "persistedLogSeq", sequenceName = "persisted_log_seq") long id; LocalDateTime timestamp; diff --git a/server/src/main/java/org/eclipse/openvsx/entities/PersonalAccessToken.java b/server/src/main/java/org/eclipse/openvsx/entities/PersonalAccessToken.java index 53db1915a..092975303 100644 --- a/server/src/main/java/org/eclipse/openvsx/entities/PersonalAccessToken.java +++ b/server/src/main/java/org/eclipse/openvsx/entities/PersonalAccessToken.java @@ -14,15 +14,7 @@ import java.util.List; import java.util.Objects; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.OneToMany; -import jakarta.persistence.Table; -import jakarta.persistence.UniqueConstraint; +import jakarta.persistence.*; import org.eclipse.openvsx.json.AccessTokenJson; import org.eclipse.openvsx.util.TimeUtil; @@ -32,7 +24,8 @@ public class PersonalAccessToken implements Serializable { @Id - @GeneratedValue + @GeneratedValue(generator = "personalAccessTokenSeq") + @SequenceGenerator(name = "personalAccessTokenSeq", sequenceName = "personal_access_token_seq") long id; @ManyToOne diff --git a/server/src/main/java/org/eclipse/openvsx/entities/SignatureKeyPair.java b/server/src/main/java/org/eclipse/openvsx/entities/SignatureKeyPair.java index 32372254b..7fd00c0df 100644 --- a/server/src/main/java/org/eclipse/openvsx/entities/SignatureKeyPair.java +++ b/server/src/main/java/org/eclipse/openvsx/entities/SignatureKeyPair.java @@ -9,10 +9,8 @@ * ****************************************************************************** */ package org.eclipse.openvsx.entities; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; +import jakarta.persistence.*; + import java.io.Serializable; import java.time.LocalDateTime; import java.util.Arrays; @@ -26,7 +24,8 @@ public class SignatureKeyPair implements Serializable { public static final String KEYPAIR_MODE_DELETE = "delete"; @Id - @GeneratedValue + @GeneratedValue(generator = "signatureKeyPairSeq") + @SequenceGenerator(name = "signatureKeyPairSeq", sequenceName = "signature_key_pair_seq") long id; @Column(length = 128) diff --git a/server/src/main/java/org/eclipse/openvsx/entities/UserData.java b/server/src/main/java/org/eclipse/openvsx/entities/UserData.java index fa821f814..db2c9feb7 100644 --- a/server/src/main/java/org/eclipse/openvsx/entities/UserData.java +++ b/server/src/main/java/org/eclipse/openvsx/entities/UserData.java @@ -13,12 +13,7 @@ import java.util.List; import java.util.Objects; -import jakarta.persistence.Column; -import jakarta.persistence.Convert; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; -import jakarta.persistence.OneToMany; +import jakarta.persistence.*; import org.eclipse.openvsx.json.UserJson; @@ -29,7 +24,8 @@ public class UserData implements Serializable { public static final String ROLE_PRIVILEGED = "privileged"; @Id - @GeneratedValue + @GeneratedValue(generator = "userDataSeq") + @SequenceGenerator(name = "userDataSeq", sequenceName = "user_data_seq") long id; @Column(length = 32) diff --git a/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionHandler.java b/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionHandler.java index 09284efd3..41c2a8dcc 100644 --- a/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionHandler.java +++ b/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionHandler.java @@ -10,9 +10,8 @@ package org.eclipse.openvsx.publish; import com.google.common.base.Joiner; -import jakarta.persistence.EntityManager; -import jakarta.transaction.Transactional; import org.eclipse.openvsx.ExtensionProcessor; +import org.eclipse.openvsx.ExtensionService; import org.eclipse.openvsx.ExtensionValidator; import org.eclipse.openvsx.UserService; import org.eclipse.openvsx.adapter.VSCodeIdService; @@ -24,12 +23,18 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.retry.annotation.Retryable; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; +import jakarta.persistence.EntityManager; +import jakarta.transaction.Transactional; +import java.io.IOException; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.function.Consumer; import java.util.stream.Collectors; @Component @@ -196,6 +201,50 @@ private List updateExistingPublicIds(Extension extension) { return updatedExtensions; } + @Async + @Retryable + public void publishAsync(FileResource download, TempFile extensionFile, ExtensionService extensionService) { + var extVersion = download.getExtension(); + + // Delete file resources in case publishAsync is retried + service.deleteFileResources(extVersion); + download.setId(0L); + + service.storeDownload(download, extensionFile); + service.persistResource(download); + try(var processor = new ExtensionProcessor(extensionFile)) { + Consumer consumer = resource -> { + service.storeResource(resource); + service.persistResource(resource); + }; + + if(integrityService.isEnabled()) { + var keyPair = extVersion.getSignatureKeyPair(); + if(keyPair != null) { + var signature = integrityService.generateSignature(download, extensionFile, keyPair); + consumer.accept(signature); + } else { + // Can happen when GenerateKeyPairJobRequestHandler hasn't run yet and there is no active SignatureKeyPair. + // This extension version should be assigned a SignatureKeyPair and a signature FileResource should be created + // by the ExtensionVersionSignatureJobRequestHandler migration. + logger.warn("Integrity service is enabled, but {} did not have an active key pair", NamingUtil.toLogFormat(extVersion)); + } + } + + processor.processEachResource(extVersion, consumer); + processor.getFileResources(extVersion).forEach(consumer); + consumer.accept(processor.generateSha256Checksum(extVersion)); + } + + // Update whether extension is active, the search index and evict cache + service.activateExtension(extVersion, extensionService); + try { + extensionFile.close(); + } catch (IOException e) { + logger.error("failed to delete temp file", e); + } + } + public void mirror(FileResource download, TempFile extensionFile, String signatureName) { var extVersion = download.getExtension(); service.mirrorResource(download); @@ -216,10 +265,4 @@ private FileResource getSignatureResource(String signatureName, ExtensionVersion resource.setType(FileResource.DOWNLOAD_SIG); return resource; } - - @Transactional - public void persistDownload(FileResource download) { - download.setStorageType(FileResource.STORAGE_DB); - entityManager.persist(download); - } } diff --git a/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionJob.java b/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionJob.java deleted file mode 100644 index 053530e44..000000000 --- a/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionJob.java +++ /dev/null @@ -1,86 +0,0 @@ -/** ****************************************************************************** - * Copyright (c) 2023 Precies. Software Ltd and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0. - * - * SPDX-License-Identifier: EPL-2.0 - * ****************************************************************************** */ -package org.eclipse.openvsx.publish; - -import org.eclipse.openvsx.ExtensionProcessor; -import org.eclipse.openvsx.entities.FileResource; -import org.eclipse.openvsx.migration.MigrationService; -import org.eclipse.openvsx.util.NamingUtil; -import org.jobrunr.jobs.lambdas.JobRequestHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.util.AbstractMap; -import java.util.function.Consumer; - -@Component -public class PublishExtensionVersionJob implements JobRequestHandler { - - protected final Logger logger = LoggerFactory.getLogger(PublishExtensionVersionJob.class); - - @Autowired - ExtensionVersionIntegrityService integrityService; - - @Autowired - PublishExtensionVersionJobService service; - - @Autowired - MigrationService migrations; - - @Override - public void run(PublishExtensionVersionJobRequest jobRequest) throws Exception { - var download = service.getFileResource(jobRequest.getDownloadId()); - var extVersion = download.getExtension(); - logger.info("Processing files for {}", NamingUtil.toLogFormat(extVersion)); - - // Delete file resources in case job is retried - service.deleteFileResources(extVersion); - - var content = migrations.getContent(download); - var extensionFile = migrations.getExtensionFile(new AbstractMap.SimpleEntry<>(download, content)); - try(var processor = new ExtensionProcessor(extensionFile)) { - Consumer consumer = resource -> { - service.storeResource(resource); - service.persistResource(resource); - }; - - if(integrityService.isEnabled()) { - var keyPair = extVersion.getSignatureKeyPair(); - if(keyPair != null) { - var signature = integrityService.generateSignature(download, extensionFile, keyPair); - consumer.accept(signature); - } else { - // Can happen when GenerateKeyPairJobRequestHandler hasn't run yet and there is no active SignatureKeyPair. - // This extension version should be assigned a SignatureKeyPair and a signature FileResource should be created - // by the ExtensionVersionSignatureJobRequestHandler migration. - logger.warn("Integrity service is enabled, but {} did not have an active key pair", NamingUtil.toLogFormat(extVersion)); - } - } - - processor.processEachResource(extVersion, consumer); - processor.getFileResources(extVersion).forEach(consumer); - consumer.accept(processor.generateSha256Checksum(extVersion)); - } - - service.storeDownload(download); - - // Update whether extension is active, the search index and evict cache - service.activateExtension(extVersion); - if(!download.getStorageType().equals(FileResource.STORAGE_DB)) { - // Don't store the binary content in the DB - it's now stored externally - download.setContent(null); - } - - service.updateResource(download); - logger.info("Published {}", NamingUtil.toLogFormat(extVersion)); - } -} diff --git a/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionJobRequest.java b/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionJobRequest.java deleted file mode 100644 index bcf1443cf..000000000 --- a/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionJobRequest.java +++ /dev/null @@ -1,37 +0,0 @@ -/** ****************************************************************************** - * Copyright (c) 2023 Precies. Software Ltd and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0. - * - * SPDX-License-Identifier: EPL-2.0 - * ****************************************************************************** */ -package org.eclipse.openvsx.publish; - -import org.jobrunr.jobs.lambdas.JobRequest; -import org.jobrunr.jobs.lambdas.JobRequestHandler; - -public class PublishExtensionVersionJobRequest implements JobRequest { - - private long downloadId; - - public PublishExtensionVersionJobRequest() {} - - public PublishExtensionVersionJobRequest(long downloadId) { - this.downloadId = downloadId; - } - - public long getDownloadId() { - return downloadId; - } - - public void setDownloadId(long downloadId) { - this.downloadId = downloadId; - } - - @Override - public Class getJobRequestHandler() { - return PublishExtensionVersionJob.class; - } -} diff --git a/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionJobService.java b/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionJobService.java deleted file mode 100644 index 98c23642f..000000000 --- a/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionJobService.java +++ /dev/null @@ -1,87 +0,0 @@ -/** ****************************************************************************** - * Copyright (c) 2023 Precies. Software Ltd and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0. - * - * SPDX-License-Identifier: EPL-2.0 - * ****************************************************************************** */ -package org.eclipse.openvsx.publish; - -import jakarta.persistence.EntityManager; -import jakarta.transaction.Transactional; -import org.eclipse.openvsx.ExtensionService; -import org.eclipse.openvsx.entities.ExtensionVersion; -import org.eclipse.openvsx.entities.FileResource; -import org.eclipse.openvsx.repositories.RepositoryService; -import org.eclipse.openvsx.storage.StorageUtilService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.retry.annotation.Retryable; -import org.springframework.stereotype.Component; - -@Component -public class PublishExtensionVersionJobService { - - @Autowired - EntityManager entityManager; - - @Autowired - RepositoryService repositories; - - @Autowired - StorageUtilService storageUtil; - - @Autowired - ExtensionService extensions; - - public FileResource getFileResource(long id) { - return entityManager.find(FileResource.class, id); - } - - @Transactional - public void deleteFileResources(ExtensionVersion extVersion) { - repositories.findFiles(extVersion) - .filter(f -> !f.getType().equals(FileResource.DOWNLOAD)) - .forEach(entityManager::remove); - } - - @Retryable - public void storeDownload(FileResource resource) { - // Store file resource in the DB or external storage - if (storageUtil.shouldStoreExternally(resource)) { - storageUtil.uploadFile(resource); - } else { - resource.setStorageType(FileResource.STORAGE_DB); - } - } - - @Retryable - public void storeResource(FileResource resource) { - // Store file resource in the DB or external storage - if (storageUtil.shouldStoreExternally(resource)) { - storageUtil.uploadFile(resource); - // Don't store the binary content in the DB - it's now stored externally - resource.setContent(null); - } else { - resource.setStorageType(FileResource.STORAGE_DB); - } - } - - @Transactional - public void persistResource(FileResource resource) { - entityManager.persist(resource); - } - - @Transactional - public void activateExtension(ExtensionVersion extVersion) { - extVersion.setActive(true); - extVersion = entityManager.merge(extVersion); - extensions.updateExtension(extVersion.getExtension()); - } - - @Transactional - public void updateResource(FileResource resource) { - entityManager.merge(resource); - } -} diff --git a/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionService.java b/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionService.java index eded00bd1..9c03ff6c0 100644 --- a/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionService.java +++ b/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionService.java @@ -9,23 +9,67 @@ * ****************************************************************************** */ package org.eclipse.openvsx.publish; -import jakarta.persistence.EntityManager; -import jakarta.transaction.Transactional; +import org.eclipse.openvsx.ExtensionService; import org.eclipse.openvsx.entities.Extension; +import org.eclipse.openvsx.entities.ExtensionVersion; import org.eclipse.openvsx.entities.FileResource; +import org.eclipse.openvsx.repositories.RepositoryService; import org.eclipse.openvsx.storage.StorageUtilService; +import org.eclipse.openvsx.util.ErrorResultException; +import org.eclipse.openvsx.util.TempFile; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.retry.annotation.Retryable; import org.springframework.stereotype.Component; +import jakarta.persistence.EntityManager; +import jakarta.transaction.Transactional; +import java.io.IOException; +import java.nio.file.Files; + @Component public class PublishExtensionVersionService { + @Autowired + RepositoryService repositories; + @Autowired EntityManager entityManager; @Autowired StorageUtilService storageUtil; + @Transactional + public void deleteFileResources(ExtensionVersion extVersion) { + repositories.findFiles(extVersion).forEach(entityManager::remove); + } + + @Retryable + public void storeDownload(FileResource download, TempFile extensionFile) { + if (storageUtil.shouldStoreExternally(download)) { + storageUtil.uploadFile(download, extensionFile); + } else { + try { + download.setContent(Files.readAllBytes(extensionFile.getPath())); + } catch (IOException e) { + throw new ErrorResultException("Failed to read extension file", e); + } + + download.setStorageType(FileResource.STORAGE_DB); + } + } + + @Retryable + public void storeResource(FileResource resource) { + // Store file resource in the DB or external storage + if (storageUtil.shouldStoreExternally(resource)) { + storageUtil.uploadFile(resource); + // Don't store the binary content in the DB - it's now stored externally + resource.setContent(null); + } else { + resource.setStorageType(FileResource.STORAGE_DB); + } + } + @Transactional public void mirrorResource(FileResource resource) { resource.setStorageType(storageUtil.getActiveStorageType()); @@ -34,6 +78,18 @@ public void mirrorResource(FileResource resource) { entityManager.persist(resource); } + @Transactional + public void persistResource(FileResource resource) { + entityManager.persist(resource); + } + + @Transactional + public void activateExtension(ExtensionVersion extVersion, ExtensionService extensions) { + extVersion.setActive(true); + extVersion = entityManager.merge(extVersion); + extensions.updateExtension(extVersion.getExtension()); + } + @Transactional(Transactional.TxType.REQUIRES_NEW) public void updateExtensionPublicId(Extension extension) { entityManager.merge(extension); diff --git a/server/src/main/resources/db/migration/V1_41__Fix_Entity_Sequencies.sql b/server/src/main/resources/db/migration/V1_41__Fix_Entity_Sequencies.sql new file mode 100644 index 000000000..06dbc1e64 --- /dev/null +++ b/server/src/main/resources/db/migration/V1_41__Fix_Entity_Sequencies.sql @@ -0,0 +1,2 @@ +SELECT SETVAL('download_seq', (SELECT COALESCE(MAX(id), 1) FROM download)::BIGINT); +SELECT SETVAL('file_resource_seq', (SELECT COALESCE(MAX(id), 1) FROM file_resource)::BIGINT); \ No newline at end of file diff --git a/server/src/test/java/org/eclipse/openvsx/RegistryAPITest.java b/server/src/test/java/org/eclipse/openvsx/RegistryAPITest.java index 19a4a7631..dcab83182 100644 --- a/server/src/test/java/org/eclipse/openvsx/RegistryAPITest.java +++ b/server/src/test/java/org/eclipse/openvsx/RegistryAPITest.java @@ -36,7 +36,6 @@ import org.eclipse.openvsx.storage.StorageUtilService; import org.eclipse.openvsx.util.TargetPlatform; import org.eclipse.openvsx.util.VersionService; -import org.jobrunr.scheduling.JobRequestScheduler; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -85,7 +84,7 @@ @MockBean({ ClientRegistrationRepository.class, UpstreamRegistryService.class, GoogleCloudStorageService.class, AzureBlobStorageService.class, VSCodeIdService.class, AzureDownloadCountService.class, CacheService.class, - EclipseService.class, PublishExtensionVersionService.class, SimpleMeterRegistry.class, JobRequestScheduler.class + EclipseService.class, PublishExtensionVersionService.class, SimpleMeterRegistry.class }) public class RegistryAPITest { diff --git a/server/src/test/java/org/eclipse/openvsx/eclipse/EclipseServiceTest.java b/server/src/test/java/org/eclipse/openvsx/eclipse/EclipseServiceTest.java index 8c7e2effd..a8769c7b1 100644 --- a/server/src/test/java/org/eclipse/openvsx/eclipse/EclipseServiceTest.java +++ b/server/src/test/java/org/eclipse/openvsx/eclipse/EclipseServiceTest.java @@ -39,7 +39,6 @@ import org.eclipse.openvsx.util.ErrorResultException; import org.eclipse.openvsx.util.TargetPlatform; import org.eclipse.openvsx.util.VersionService; -import org.jobrunr.scheduling.JobRequestScheduler; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -66,8 +65,9 @@ @ExtendWith(SpringExtension.class) @MockBean({ EntityManager.class, SearchUtilService.class, GoogleCloudStorageService.class, AzureBlobStorageService.class, - VSCodeIdService.class, AzureDownloadCountService.class, CacheService.class, UserService.class, - PublishExtensionVersionHandler.class, SimpleMeterRegistry.class, JobRequestScheduler.class + VSCodeIdService.class, AzureDownloadCountService.class, CacheService.class, + UserService.class, PublishExtensionVersionHandler.class, + SimpleMeterRegistry.class }) public class EclipseServiceTest {