@@ -3,9 +3,12 @@ package org.digma.intellij.plugin.updates
33import com.intellij.collaboration.async.disposingScope
44import com.intellij.openapi.Disposable
55import com.intellij.openapi.components.Service
6+ import com.intellij.openapi.components.service
67import com.intellij.openapi.diagnostic.Logger
78import com.intellij.openapi.project.Project
9+ import kotlinx.coroutines.CancellationException
810import kotlinx.coroutines.delay
11+ import kotlinx.coroutines.isActive
912import kotlinx.coroutines.launch
1013import org.apache.maven.artifact.versioning.ComparableVersion
1114import org.digma.intellij.plugin.analytics.AnalyticsProviderException
@@ -23,41 +26,23 @@ import org.digma.intellij.plugin.model.rest.version.BackendVersionResponse
2326import org.digma.intellij.plugin.model.rest.version.PluginVersionResponse
2427import org.digma.intellij.plugin.model.rest.version.VersionResponse
2528import org.digma.intellij.plugin.ui.panels.DigmaResettablePanel
26- import org.jetbrains.annotations.VisibleForTesting
27- import java.time.LocalDateTime
28- import java.util.Timer
29- import java.util.TimerTask
3029import java.util.concurrent.TimeUnit
30+ import kotlin.time.Duration.Companion.minutes
3131
3232@Service(Service .Level .PROJECT )
3333class UpdatesService (private val project : Project ) : Disposable {
3434
35- companion object {
36- private val logger = Logger .getInstance(UpdatesService ::class .java)
35+ private val logger = Logger .getInstance(UpdatesService ::class .java)
3736
37+ companion object {
3838 @JvmStatic
3939 fun getInstance (project : Project ): UpdatesService {
40- return project.getService( UpdatesService :: class .java )
40+ return project.service< UpdatesService >( )
4141 }
4242 }
4343
44- private val BlackoutDurationSeconds =
45- TimeUnit .MINUTES .toSeconds(5 ) // production value
46- // TimeUnit.SECONDS.toSeconds(12) // use short period (few seconds) when debugging
47-
48- // delay for first check for update since startup
49- private val DelayMilliseconds = TimeUnit .SECONDS .toMillis(0 )
50-
51- private val PeriodMilliseconds =
52- TimeUnit .MINUTES .toMillis(5 ) // production value is 5 minutes
53- // TimeUnit.SECONDS.toMillis(12) // use short period (few seconds) when debugging
54-
55- private val timer = Timer ()
56-
5744 var affectedPanel: DigmaResettablePanel ? = null // late init
5845
59- private var blackoutStopTime: LocalDateTime = LocalDateTime .now().minusMonths(3 )
60-
6146 private var prevBackendErrorsList: List <String > = emptyList()
6247 private var stateBackendVersion: BackendVersionResponse
6348 private var statePluginVersion: PluginVersion
@@ -66,29 +51,31 @@ class UpdatesService(private val project: Project) : Disposable {
6651 stateBackendVersion = BackendVersionResponse (false , " 0.0.1" , " 0.0.1" , BackendDeploymentType .Unknown )
6752 statePluginVersion = PluginVersion (getPluginVersion())
6853
69- val fetchTask = object : TimerTask () {
70- override fun run () {
71- try {
54+ @Suppress(" UnstableApiUsage" )
55+ disposingScope().launch {
56+ try {
57+
58+ while (isActive) {
7259 checkForNewerVersions()
73- } catch (e: Exception ) {
74- Log .warnWithException(logger, e, " Exception in checkForNewerVersions" )
75- ErrorReporter .getInstance().reportError(project, " UpdatesService.checkForNewerVersions" , e)
60+ delay(5 .minutes.inWholeMilliseconds)
7661 }
62+
63+ } catch (e: CancellationException ) {
64+ Log .debugWithException(logger, e, " Exception in checkForNewerVersions" )
65+ } catch (e: Throwable ) {
66+ Log .warnWithException(logger, e, " Exception in checkForNewerVersions" )
67+ ErrorReporter .getInstance().reportError(" UpdatesService.timer" , e)
7768 }
7869 }
79-
80- timer.schedule(
81- fetchTask, DelayMilliseconds , PeriodMilliseconds
82- )
8370 }
8471
8572 override fun dispose () {
86- timer.cancel()
73+ // nothing to do , used as parent disposable
8774 }
8875
89- fun checkForNewerVersions () {
76+ private fun checkForNewerVersions () {
9077
91- Log .log(logger::debug," checking for new versions" )
78+ Log .log(logger::debug, " checking for new versions" )
9279
9380 val backendConnectionMonitor = BackendConnectionMonitor .getInstance(project)
9481 if (backendConnectionMonitor.isConnectionError()) {
@@ -100,7 +87,7 @@ class UpdatesService(private val project: Project) : Disposable {
10087 var versionsResp: VersionResponse ? = null
10188 try {
10289 versionsResp = analyticsService.getVersions(buildVersionRequest())
103- Log .log(logger::debug," got version response {}" ,versionsResp)
90+ Log .log(logger::debug, " got version response {}" , versionsResp)
10491 } catch (ase: AnalyticsServiceException ) {
10592 var logException = true
10693 if (ase.cause is AnalyticsProviderException ) {
@@ -139,13 +126,23 @@ class UpdatesService(private val project: Project) : Disposable {
139126 stateBackendVersion = versionsResp.backend
140127 statePluginVersion.latestVersion = versionsResp.plugin.latestVersion
141128
129+ // the panel is going to show the update button if shouldUpdatePlugin is true.
130+ // when user clicks the button we will open the intellij plugins settings.
131+ // sometimes the plugin list is not refreshed and user will not be able to update the plugin,
132+ // so we refresh plugins metadata before showing the button. waiting maximum 10 seconds for
133+ // the refresh to complete, and show the button anyway.
134+ if (shouldUpdatePlugin()) {
135+ // refreshPluginsMetadata returns a future that doesn't throw exception from get.
136+ val future = refreshPluginsMetadata()
137+ future.get(10 , TimeUnit .SECONDS )
138+ }
139+
142140 EDT .ensureEDT {
143141 affectedPanel?.reset()
144142 }
145143 }
146144
147- @VisibleForTesting
148- protected fun createResponseToInduceBackendUpdate (): VersionResponse {
145+ private fun createResponseToInduceBackendUpdate (): VersionResponse {
149146 val pluginVersionResp = PluginVersionResponse (false , " 0.0.1" )
150147 val backendVersionResp = BackendVersionResponse (
151148 true , " 0.0.2" , " 0.0.1" ,
@@ -155,18 +152,6 @@ class UpdatesService(private val project: Project) : Disposable {
155152 return resp
156153 }
157154
158- fun updateButtonClicked () {
159- // start blackout time that update-state won't be displayed
160- blackoutStopTime = LocalDateTime .now().plusSeconds(BlackoutDurationSeconds )
161-
162- // give some time for the user/system to make the desired update, and only then recheck for newer version
163- @Suppress(" UnstableApiUsage" )
164- disposingScope().launch {
165- delay(TimeUnit .SECONDS .toMillis(BlackoutDurationSeconds ) + 500 )
166-
167- checkForNewerVersions()
168- }
169- }
170155
171156 fun evalAndGetState (): UpdateState {
172157 Log .log(logger::debug, " evalAndGetState called" )
@@ -177,39 +162,22 @@ class UpdatesService(private val project: Project) : Disposable {
177162 )
178163 }
179164
180- @VisibleForTesting
181- protected fun isDuringBlackout (): Boolean {
182- val now = LocalDateTime .now()
183- return now < blackoutStopTime
165+ private fun shouldUpdateBackend (): Boolean {
166+ return evalHasNewerVersion(stateBackendVersion)
184167 }
185168
186- @VisibleForTesting
187- protected fun shouldUpdateBackend (): Boolean {
188- if (isDuringBlackout()) return false
189-
190- var hasNewVersion = evalHasNewerVersion(stateBackendVersion)
191- // hasNewVersion = true // use const only when debugging
192- return hasNewVersion
169+ private fun shouldUpdatePlugin (): Boolean {
170+ return evalHasNewerVersion(statePluginVersion)
193171 }
194172
195- @VisibleForTesting
196- protected fun shouldUpdatePlugin (): Boolean {
197- if (isDuringBlackout()) return false
198-
199- var hasNewVersion = evalHasNewerVersion(statePluginVersion)
200- // hasNewVersion = true // use const only when debugging
201- return hasNewVersion
202- }
203173
204- @VisibleForTesting
205- protected fun evalHasNewerVersion (backend : BackendVersionResponse ): Boolean {
174+ private fun evalHasNewerVersion (backend : BackendVersionResponse ): Boolean {
206175 val currCompVersion = ComparableVersion (backend.currentVersion)
207176 val latestCompVersion = ComparableVersion (backend.latestVersion)
208177 return latestCompVersion.newerThan(currCompVersion)
209178 }
210179
211- @VisibleForTesting
212- protected fun evalHasNewerVersion (plugin : PluginVersion ): Boolean {
180+ private fun evalHasNewerVersion (plugin : PluginVersion ): Boolean {
213181 val currCompVersion = ComparableVersion (plugin.currentVersion)
214182 val latestCompVersion = ComparableVersion (plugin.latestVersion)
215183 return latestCompVersion.newerThan(currCompVersion)
0 commit comments