-
Notifications
You must be signed in to change notification settings - Fork 4
Update Mechanism #72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
overheadhunter
wants to merge
26
commits into
develop
Choose a base branch
from
feature/update-mechanism
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Update Mechanism #72
Changes from 25 commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
88f7231
Invent UpdateService
purejava a501a2b
Have multiple UpdateServices
purejava 6af0aa8
Invent @DistributionChannel
purejava a2a6f98
Drop isUpdateAvailable in favor of getLatestReleaseChecker
purejava f3f3c35
Add spawnApp()
purejava 5f29005
Add listener interfaces
purejava 28680db
Implement missing signals
purejava eaa63e5
Correlate with API as suggested in a separate PoC: UpdateMechanism an…
purejava 84076df
Reduce API surface
overheadhunter e875adb
Merge branch 'develop' into update-mechanism
overheadhunter dde78a1
API refinement
overheadhunter 0f765d6
added test case
overheadhunter 5dadcbe
multi-step update api
overheadhunter 61de9f3
add magic constants for UI to react to
overheadhunter ffc3666
update update mechanism
overheadhunter 2493753
Allow UpdateInfo to carry mechanism-specific data
overheadhunter b0d9fe4
improve type safety
overheadhunter 41d8e4c
delete unused class
overheadhunter a052dd0
Merge branch 'develop' into update-mechanism
overheadhunter 5856f28
append CHANGELOG
overheadhunter 6e3bb15
share classes for `DownloadUpdateMechanism`
overheadhunter 4dbfb11
Merge branch 'develop' into feature/update-mechanism
overheadhunter d75729e
apply suggestions from code review
overheadhunter 73332c8
no need for java.time.* deserialization
overheadhunter a522f36
implement more suggestions from code review
overheadhunter 0fa2e52
update changelog
overheadhunter File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 14 additions & 0 deletions
14
src/main/java/org/cryptomator/integrations/Localization.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| package org.cryptomator.integrations; | ||
|
|
||
| import java.util.ResourceBundle; | ||
|
|
||
| public enum Localization { | ||
| INSTANCE; | ||
|
|
||
| private final ResourceBundle resourceBundle = ResourceBundle.getBundle("IntegrationsApi"); | ||
|
|
||
| public static ResourceBundle get() { | ||
| return INSTANCE.resourceBundle; | ||
| } | ||
|
|
||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
src/main/java/org/cryptomator/integrations/update/DownloadUpdateInfo.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package org.cryptomator.integrations.update; | ||
|
|
||
| public record DownloadUpdateInfo( | ||
| DownloadUpdateMechanism updateMechanism, | ||
| String version, | ||
| DownloadUpdateMechanism.Asset asset | ||
| ) implements UpdateInfo<DownloadUpdateInfo> { | ||
| } |
130 changes: 130 additions & 0 deletions
130
src/main/java/org/cryptomator/integrations/update/DownloadUpdateMechanism.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| package org.cryptomator.integrations.update; | ||
|
|
||
| import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | ||
| import com.fasterxml.jackson.annotation.JsonProperty; | ||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||
| import org.jetbrains.annotations.Blocking; | ||
| import org.jetbrains.annotations.NotNull; | ||
| import org.jetbrains.annotations.Nullable; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| import java.io.IOException; | ||
| import java.io.InputStream; | ||
| import java.net.URI; | ||
| import java.net.http.HttpClient; | ||
| import java.net.http.HttpRequest; | ||
| import java.net.http.HttpResponse; | ||
| import java.nio.file.Files; | ||
| import java.nio.file.Path; | ||
| import java.util.HexFormat; | ||
| import java.util.List; | ||
|
|
||
| public abstract class DownloadUpdateMechanism implements UpdateMechanism<DownloadUpdateInfo> { | ||
|
|
||
| private static final Logger LOG = LoggerFactory.getLogger(DownloadUpdateMechanism.class); | ||
| private static final String LATEST_VERSION_API_URL = "https://api.cryptomator.org/connect/apps/desktop/latest-version?format=1"; | ||
| private static final ObjectMapper MAPPER = new ObjectMapper(); | ||
|
|
||
| @Override | ||
| public DownloadUpdateInfo checkForUpdate(String currentVersion, HttpClient httpClient) { | ||
| try { | ||
| HttpRequest request = HttpRequest.newBuilder().uri(URI.create(LATEST_VERSION_API_URL)).build(); | ||
| HttpResponse<InputStream> response = httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream()); | ||
| if (response.statusCode() != 200) { | ||
| LOG.warn("Failed to fetch release: HTTP {}", response.statusCode()); | ||
| return null; | ||
| } | ||
| var release = MAPPER.readValue(response.body(), LatestVersionResponse.class); | ||
| return checkForUpdate(currentVersion, release); | ||
| } catch (InterruptedException e) { | ||
| Thread.currentThread().interrupt(); | ||
| LOG.debug("Update check interrupted."); | ||
| return null; | ||
| } catch (IOException e) { | ||
| LOG.warn("Update check failed", e); | ||
| return null; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Returns the first step to prepare the update. This downloads the {@link DownloadUpdateInfo#asset() asset} to a temporary location and verifies its checksum. | ||
| * @param updateInfo The {@link DownloadUpdateInfo} retrieved from {@link #checkForUpdate(String, HttpClient)}. | ||
| * @return a new {@link UpdateStep} that can be used to monitor the download progress. | ||
| * @throws UpdateFailedException When failing to prepare a temporary download location. | ||
| */ | ||
| @Override | ||
| public UpdateStep firstStep(DownloadUpdateInfo updateInfo) throws UpdateFailedException { | ||
| try { | ||
| Path workDir = Files.createTempDirectory("cryptomator-update"); | ||
| return new FirstStep(workDir, updateInfo); | ||
| } catch (IOException e) { | ||
| throw new UpdateFailedException("Failed to create temporary directory for update", e); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Second step that is executed after the download has completed in the {@link #firstStep(DownloadUpdateInfo) first step}. | ||
| * @param workDir A temporary working directory to which the asset has been downloaded. | ||
| * @param assetPath The path of the downloaded asset. | ||
| * @param updateInfo The {@link DownloadUpdateInfo} representing the update. | ||
| * @return The next step of the update process. | ||
| * @throws IllegalStateException if preconditions aren't met. | ||
| * @throws IOException indicating an error preventing the next step from starting. | ||
| * @implSpec The returned {@link UpdateStep} must either be stateless or a new instance must be returned on each call. | ||
| */ | ||
| public abstract UpdateStep secondStep(Path workDir, Path assetPath, DownloadUpdateInfo updateInfo) throws IllegalStateException, IOException; | ||
|
|
||
| @Nullable | ||
| @Blocking | ||
| protected abstract DownloadUpdateInfo checkForUpdate(String currentVersion, LatestVersionResponse response); | ||
|
|
||
| @JsonIgnoreProperties(ignoreUnknown = true) | ||
| public record LatestVersionResponse( | ||
| @JsonProperty("latestVersion") LatestVersion latestVersion, | ||
| @JsonProperty("assets") List<Asset> assets | ||
| ) {} | ||
|
|
||
| @JsonIgnoreProperties(ignoreUnknown = true) | ||
| public record LatestVersion( | ||
| @JsonProperty("mac") String macVersion, | ||
| @JsonProperty("win") String winVersion, | ||
| @JsonProperty("linux") String linuxVersion | ||
| ) {} | ||
|
|
||
| @JsonIgnoreProperties(ignoreUnknown = true) | ||
| public record Asset( | ||
| @JsonProperty("name") String name, | ||
| @JsonProperty("digest") String digest, | ||
| @JsonProperty("size") long size, | ||
| @JsonProperty("downloadUrl") String downloadUrl | ||
| ) {} | ||
|
|
||
| private class FirstStep extends DownloadUpdateStep { | ||
| private final Path workDir; | ||
| private final DownloadUpdateInfo updateInfo; | ||
|
|
||
| public FirstStep(Path workDir, DownloadUpdateInfo updateInfo) { | ||
| var uri = URI.create(updateInfo.asset().downloadUrl); | ||
| var destination = workDir.resolve(updateInfo.asset().name); | ||
| var digest = updateInfo.asset().digest().startsWith("sha256:") | ||
| ? HexFormat.of().withLowerCase().parseHex(updateInfo.asset().digest.substring(7)) // remove "sha256:" prefix | ||
| : null; | ||
| var size = updateInfo.asset().size; | ||
| super(uri, destination, digest, size); | ||
| this.workDir = workDir; | ||
| this.updateInfo = updateInfo; | ||
| } | ||
overheadhunter marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| @Override | ||
| public @Nullable UpdateStep nextStep() throws IllegalStateException, IOException { | ||
| if (!isDone()) { | ||
| throw new IllegalStateException("Download not yet completed."); | ||
| } else if (downloadException != null) { | ||
| throw new UpdateFailedException("Download failed.", downloadException); | ||
| } | ||
| return secondStep(workDir, destination, updateInfo); | ||
| } | ||
| } | ||
|
|
||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.