11package org .cryptomator .linux .update ;
22
3+ import com .fasterxml .jackson .annotation .JsonIgnoreProperties ;
4+ import com .fasterxml .jackson .annotation .JsonProperty ;
5+ import com .fasterxml .jackson .databind .ObjectMapper ;
36import org .cryptomator .integrations .common .CheckAvailability ;
47import org .cryptomator .integrations .common .DisplayName ;
58import org .cryptomator .integrations .common .OperatingSystem ;
6- import org .cryptomator .integrations .common .Priority ;
79import org .cryptomator .integrations .update .UpdateFailedException ;
810import org .cryptomator .integrations .update .UpdateMechanism ;
911import org .cryptomator .integrations .update .UpdateStep ;
1921import org .slf4j .LoggerFactory ;
2022
2123import java .io .IOException ;
24+ import java .net .URI ;
25+ import java .net .http .HttpClient ;
26+ import java .net .http .HttpRequest ;
27+ import java .net .http .HttpResponse ;
2228import java .util .Collections ;
29+ import java .util .Comparator ;
2330import java .util .List ;
2431import java .util .Map ;
2532import java .util .concurrent .CountDownLatch ;
2633import java .util .concurrent .TimeUnit ;
27- import java .util .concurrent .atomic .AtomicBoolean ;
2834
29- @ Priority (1000 )
3035@ CheckAvailability
3136@ DisplayName ("Update via Flatpak update" )
3237@ OperatingSystem (OperatingSystem .Value .LINUX )
33- public class FlatpakUpdater implements UpdateMechanism {
38+ public class FlatpakUpdater implements UpdateMechanism < FlatpakUpdateInfo > {
3439
3540 private static final Logger LOG = LoggerFactory .getLogger (FlatpakUpdater .class );
41+ private static final String FLATHUB_API_BASE_URL = "https://flathub.org/api/v2/appstream/" ;
3642 private static final String APP_NAME = "org.cryptomator.Cryptomator" ;
43+ private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper ();
3744
3845 private final UpdatePortal portal ;
3946
@@ -48,31 +55,50 @@ public boolean isSupported() {
4855 }
4956
5057 @ Override
51- public boolean isUpdateAvailable (String installedVersion ) {
52- var cdl = new CountDownLatch (1 );
53- portal .setUpdateCheckerTaskFor (APP_NAME );
54- var checkTask = portal .getUpdateCheckerTaskFor (APP_NAME );
55- var updateAvailable = new AtomicBoolean (false );
56- checkTask .setOnSucceeded (updateVersion -> {
57- updateAvailable .set (UpdateMechanism .isUpdateAvailable (updateVersion , installedVersion ));
58- cdl .countDown ();
59- });
60- checkTask .setOnFailed (error -> {
61- LOG .warn ("Error while checking for updates." , error );
62- cdl .countDown ();
63- });
58+ public FlatpakUpdateInfo checkForUpdate (String currentVersion , HttpClient httpClient ) throws UpdateFailedException {
59+ var uri = URI .create (FLATHUB_API_BASE_URL + APP_NAME );
60+ var request = HttpRequest .newBuilder (uri ).GET ().build ();
6461 try {
65- cdl .await ();
66- return updateAvailable .get ();
62+ var response = httpClient .send (request , HttpResponse .BodyHandlers .ofInputStream ());
63+ if (response .statusCode () != 200 ) {
64+ LOG .warn ("GET {} resulted in status {}" , uri , response .statusCode ());
65+ return null ;
66+ } else {
67+ var appstream = OBJECT_MAPPER .reader ().readValue (response .body (), AppstreamResponse .class );
68+ var updateVersion = appstream .releases ().stream ()
69+ .filter (release -> "stable" .equalsIgnoreCase (release .type ))
70+ .max (Comparator .comparing (AppstreamReleases ::timestamp )) // we're interested in the newest stable release
71+ .map (AppstreamReleases ::version )
72+ .orElse ("0.0.0" ); // fallback should always be smaller than current version
73+ if (UpdateMechanism .isUpdateAvailable (updateVersion , currentVersion )) {
74+ return new FlatpakUpdateInfo (updateVersion , this );
75+ } else {
76+ return null ;
77+ }
78+ }
79+ } catch (IOException e ) {
80+ throw new UpdateFailedException ("Check for updates failed." , e );
6781 } catch (InterruptedException e ) {
68- checkTask .cancel ();
6982 Thread .currentThread ().interrupt ();
70- return false ;
83+ LOG .warn ("Update check interrupted" , e );
84+ return null ;
7185 }
7286 }
7387
88+ @ JsonIgnoreProperties (ignoreUnknown = true )
89+ public record AppstreamResponse (
90+ @ JsonProperty ("releases" ) List <AppstreamReleases > releases
91+ ) {}
92+
93+ @ JsonIgnoreProperties (ignoreUnknown = true )
94+ public record AppstreamReleases (
95+ @ JsonProperty ("timestamp" ) long timestamp ,
96+ @ JsonProperty ("version" ) String version ,
97+ @ JsonProperty ("type" ) String type
98+ ) {}
99+
74100 @ Override
75- public UpdateStep firstStep () throws UpdateFailedException {
101+ public UpdateStep firstStep (FlatpakUpdateInfo updateInfo ) throws UpdateFailedException {
76102 var monitorPath = portal .CreateUpdateMonitor (UpdatePortal .OPTIONS_DUMMY );
77103 if (monitorPath == null ) {
78104 throw new UpdateFailedException ("Failed to create UpdateMonitor on DBus" );
@@ -205,7 +231,7 @@ public UpdateStep applyUpdate() throws IllegalStateException, IOException {
205231 Map <String , Variant <?>> options = UpdatePortal .OPTIONS_DUMMY ;
206232 var pid = portal .Spawn (cwdPath , argv , fds , envs , flags , options ).longValue ();
207233 LOG .info ("Spawned updated Cryptomator process with PID {}" , pid );
208- return null ;
234+ return UpdateStep . EXIT ;
209235 }
210236 }
211237
0 commit comments