-
Notifications
You must be signed in to change notification settings - Fork 275
use RemoteResourceResolver in notification polling for etag and PATH handling #5165
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
Changes from 4 commits
d8b6caf
02f335b
54c7d02
d96aa00
4231ba5
ba0c57b
08c6001
de5c8be
3bcc9ea
4b80f54
0aa2074
d18b689
bc9396d
ca8e967
5dcd476
c78a536
12ffed4
0ffa31e
0d992c7
9d4a1bb
b2b9849
af54b0f
b289ce1
794364d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| // Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| package software.aws.toolkits.jetbrains.core.notifications | ||
|
|
||
| import com.intellij.openapi.application.PathManager | ||
| import com.intellij.openapi.components.service | ||
| import com.intellij.util.io.HttpRequests | ||
| import com.intellij.util.io.createDirectories | ||
| import software.aws.toolkits.core.utils.DefaultRemoteResourceResolver | ||
| import software.aws.toolkits.core.utils.RemoteResource | ||
| import software.aws.toolkits.core.utils.RemoteResourceResolver | ||
| import software.aws.toolkits.core.utils.UrlFetcher | ||
| import software.aws.toolkits.core.utils.exists | ||
| import software.aws.toolkits.core.utils.getLogger | ||
| import software.aws.toolkits.core.utils.warn | ||
| import software.aws.toolkits.jetbrains.core.saveFileFromUrl | ||
| import software.aws.toolkits.jetbrains.utils.pluginAwareExecuteOnPooledThread | ||
| import java.nio.file.Path | ||
| import java.nio.file.Paths | ||
| import java.util.concurrent.Callable | ||
| import java.util.concurrent.CompletableFuture | ||
| import java.util.concurrent.CompletionStage | ||
| import java.util.concurrent.atomic.AtomicBoolean | ||
|
|
||
| interface NotificationResourceResolverProvider { | ||
| fun get(): NotificationResourceResolver | ||
|
|
||
| companion object { | ||
| fun getInstance(): NotificationResourceResolverProvider = service() | ||
| } | ||
| } | ||
|
|
||
| class DefaultNotificationResourceResolverProvider : NotificationResourceResolverProvider { | ||
|
Check warning on line 34 in plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/notifications/NotificationResourceResolver.kt
|
||
| override fun get() = RESOLVER_INSTANCE | ||
|
|
||
| companion object { | ||
| private val RESOLVER_INSTANCE by lazy { | ||
| val cachePath = Paths.get(PathManager.getSystemPath(), "aws-notifications").createDirectories() | ||
|
|
||
| NotificationResourceResolver(HttpRequestUrlFetcher, cachePath) { | ||
| val future = CompletableFuture<Path>() | ||
| pluginAwareExecuteOnPooledThread { | ||
| try { | ||
| future.complete(it.call()) | ||
| } catch (e: Exception) { | ||
| future.completeExceptionally(e) | ||
| } | ||
| } | ||
| future | ||
| } | ||
| } | ||
|
|
||
| object HttpRequestUrlFetcher : UrlFetcher { | ||
| override fun fetch(url: String, file: Path) { | ||
| saveFileFromUrl(url, file) | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| sealed class UpdateCheckResult { | ||
| object HasUpdates : UpdateCheckResult() | ||
|
Check notice on line 63 in plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/notifications/NotificationResourceResolver.kt
|
||
|
||
| object NoUpdates : UpdateCheckResult() | ||
|
Check notice on line 64 in plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/notifications/NotificationResourceResolver.kt
|
||
|
||
| object FirstPollCheck : UpdateCheckResult() | ||
|
Check notice on line 65 in plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/notifications/NotificationResourceResolver.kt
|
||
|
||
| } | ||
|
|
||
| class NotificationResourceResolver( | ||
|
||
| private val urlFetcher: UrlFetcher, | ||
|
Check warning on line 69 in plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/notifications/NotificationResourceResolver.kt
|
||
|
||
| private val cacheBasePath: Path, | ||
| private val executor: (Callable<Path>) -> CompletionStage<Path>, | ||
|
Check warning on line 71 in plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/notifications/NotificationResourceResolver.kt
|
||
|
||
| ) : RemoteResourceResolver { | ||
| private val delegate = DefaultRemoteResourceResolver(urlFetcher, cacheBasePath, executor) | ||
| private val etagState: NotificationEtagState = NotificationEtagState.getInstance() | ||
| private val isFirstPoll = AtomicBoolean(true) | ||
|
|
||
| fun getLocalResourcePath(resourceName: String): Path? { | ||
| val expectedLocation = cacheBasePath.resolve(resourceName) | ||
| return expectedLocation.existsOrNull() | ||
| } | ||
|
|
||
| fun checkForUpdates(): UpdateCheckResult { | ||
| val hasETagUpdate = updateETags() | ||
|
|
||
| // for when we need to notify on first poll even when there's no new ETag | ||
| if (isFirstPoll.compareAndSet(true, false) && !hasETagUpdate) { | ||
| return UpdateCheckResult.FirstPollCheck | ||
| } | ||
|
|
||
| return if (hasETagUpdate) { | ||
| UpdateCheckResult.HasUpdates | ||
| } else { | ||
| UpdateCheckResult.NoUpdates | ||
| } | ||
| } | ||
|
|
||
| fun updateETags(): Boolean { | ||
|
Check notice on line 97 in plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/notifications/NotificationResourceResolver.kt
|
||
|
||
| val currentEtag = etagState.etag | ||
| val remoteEtag = getEndpointETag() | ||
| etagState.etag = remoteEtag | ||
| return currentEtag != remoteEtag | ||
| } | ||
|
|
||
| override fun resolve(resource: RemoteResource): CompletionStage<Path> { | ||
| return delegate.resolve(resource) | ||
| } | ||
|
|
||
| private fun getEndpointETag(): String = | ||
| try { | ||
| HttpRequests.request(NotificationEndpoint.getEndpoint()) | ||
|
||
| .userAgent("AWS Toolkit for JetBrains") | ||
| .connect { request -> | ||
| request.connection.headerFields["ETag"]?.firstOrNull().orEmpty() | ||
| } | ||
| } catch (e: Exception) { | ||
| LOG.warn { "Failed to fetch notification ETag: $e.message" } | ||
| throw e | ||
| } | ||
|
|
||
| companion object { | ||
| private val LOG = getLogger<NotificationResourceResolver>() | ||
| fun Path.existsOrNull() = if (this.exists()) { | ||
| this | ||
| } else { | ||
| null | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.