@@ -5,12 +5,16 @@ package software.aws.toolkits.jetbrains.services.amazonq.lsp.auth
5
5
6
6
import com.intellij.openapi.Disposable
7
7
import com.intellij.openapi.project.Project
8
+ import com.intellij.util.concurrency.AppExecutorUtil
8
9
import org.eclipse.lsp4j.jsonrpc.messages.ResponseMessage
9
10
import software.aws.toolkits.core.TokenConnectionSettings
11
+ import software.aws.toolkits.core.utils.getLogger
12
+ import software.aws.toolkits.core.utils.warn
10
13
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnection
11
14
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
12
15
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManagerListener
13
16
import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
17
+ import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.BearerTokenAuthState
14
18
import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.BearerTokenProvider
15
19
import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.BearerTokenProviderListener
16
20
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
@@ -26,6 +30,9 @@ import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileSe
26
30
import software.aws.toolkits.jetbrains.utils.isQConnected
27
31
import software.aws.toolkits.jetbrains.utils.isQExpired
28
32
import java.util.concurrent.CompletableFuture
33
+ import java.util.concurrent.ScheduledExecutorService
34
+ import java.util.concurrent.ScheduledFuture
35
+ import java.util.concurrent.TimeUnit
29
36
30
37
class DefaultAuthCredentialsService (
31
38
private val project : Project ,
@@ -34,7 +41,12 @@ class DefaultAuthCredentialsService(
34
41
) : AuthCredentialsService,
35
42
BearerTokenProviderListener ,
36
43
ToolkitConnectionManagerListener ,
37
- QRegionProfileSelectedListener {
44
+ QRegionProfileSelectedListener ,
45
+ Disposable {
46
+
47
+ private val scheduler: ScheduledExecutorService = AppExecutorUtil .getAppScheduledExecutorService()
48
+ private var tokenSyncTask: ScheduledFuture <* >? = null
49
+ private val tokenSyncIntervalSeconds = 10L
38
50
39
51
init {
40
52
project.messageBus.connect(serverInstance).apply {
@@ -49,6 +61,47 @@ class DefaultAuthCredentialsService(
49
61
updateConfiguration()
50
62
}
51
63
}
64
+
65
+ // Start periodic token sync
66
+ startPeriodicTokenSync()
67
+ }
68
+
69
+ private fun startPeriodicTokenSync () {
70
+ tokenSyncTask = scheduler.scheduleWithFixedDelay(
71
+ {
72
+ try {
73
+ if (isQConnected(project)) {
74
+ if (isQExpired(project)) {
75
+ val manager = ToolkitConnectionManager .getInstance(project)
76
+ val connection = manager.activeConnectionForFeature(QConnection .getInstance()) ? : return @scheduleWithFixedDelay
77
+
78
+ // Try to refresh the token if it's in NEEDS_REFRESH state
79
+ val tokenProvider = (connection.getConnectionSettings() as ? TokenConnectionSettings )
80
+ ?.tokenProvider
81
+ ?.delegate
82
+ ?.let { it as ? BearerTokenProvider } ? : return @scheduleWithFixedDelay
83
+
84
+ if (tokenProvider.state() == BearerTokenAuthState .NEEDS_REFRESH ) {
85
+ try {
86
+ tokenProvider.resolveToken()
87
+ // Now that the token is refreshed, update it in Flare
88
+ updateTokenFromActiveConnection()
89
+ } catch (e: Exception ) {
90
+ LOG .warn(e) { " Failed to refresh bearer token" }
91
+ }
92
+ }
93
+ } else {
94
+ updateTokenFromActiveConnection()
95
+ }
96
+ }
97
+ } catch (e: Exception ) {
98
+ LOG .warn(e) { " Failed to sync bearer token to Flare" }
99
+ }
100
+ },
101
+ tokenSyncIntervalSeconds,
102
+ tokenSyncIntervalSeconds,
103
+ TimeUnit .SECONDS
104
+ )
52
105
}
53
106
54
107
override fun updateTokenCredentials (accessToken : String , encrypted : Boolean ): CompletableFuture <ResponseMessage > {
@@ -134,4 +187,13 @@ class DefaultAuthCredentialsService(
134
187
server.updateConfiguration(payload)
135
188
} ? : (CompletableFuture .failedFuture(IllegalStateException (" LSP Server not running" )))
136
189
}
190
+
191
+ override fun dispose () {
192
+ tokenSyncTask?.cancel(false )
193
+ tokenSyncTask = null
194
+ }
195
+
196
+ companion object {
197
+ private val LOG = getLogger<DefaultAuthCredentialsService >()
198
+ }
137
199
}
0 commit comments