Compare commits

...

9 Commits

Author SHA1 Message Date
BarreiroT 907acb0078 Change the time period to once a day 2026-01-14 16:32:37 -03:00
BarreiroT 09e267e0aa Fetch the banners every hour 2026-01-14 16:28:39 -03:00
Tomás Barreiro b04fcd14cd Merge branch 'main' into optimize-banner-requests 2026-01-14 09:11:08 -03:00
BarreiroT 79290ece35 Add a separate catch 2026-01-14 09:09:51 -03:00
BarreiroT cab38568dd Make another request if forceRefresh is true 2026-01-13 23:51:38 -03:00
BarreiroT 5f0d9f392b Make a single call 2026-01-13 23:50:38 -03:00
BarreiroT 84e4c9e0ef Remove redundant null 2026-01-13 23:43:15 -03:00
BarreiroT 396905cb23 Revert not fetching if no token is provided 2026-01-13 23:27:09 -03:00
BarreiroT b94520f4c9 Reduce the amount of sent banner requests 2026-01-13 23:24:06 -03:00
2 changed files with 61 additions and 25 deletions
+28 -19
View File
@@ -33,8 +33,8 @@ import { LogoutReason } from "@/services/auth/types"
import { BannerService } from "@/services/banner/BannerService"
import { featureFlagsService } from "@/services/feature-flags"
import { getDistinctId } from "@/services/logging/distinctId"
import { Logger } from "@/services/logging/Logger"
import { telemetryService } from "@/services/telemetry"
import { BannerCardData } from "@/shared/cline/banner"
import { getAxiosSettings } from "@/shared/net"
import { ShowMessageType } from "@/shared/proto/host/window"
import { getLatestAnnouncementId } from "@/utils/announcements"
@@ -80,8 +80,7 @@ export class Controller {
// Flag to prevent duplicate cancellations from spam clicking
private cancelInProgress = false
// Timer for periodic remote config fetching
private remoteConfigTimer?: NodeJS.Timeout
private timers: NodeJS.Timeout[] = []
// Public getter for workspace manager with lazy initialization - To get workspaces when task isn't initialized (Used by file mentions)
async ensureWorkspaceManager(): Promise<WorkspaceRootManager | undefined> {
@@ -111,7 +110,26 @@ export class Controller {
// Initial fetch
fetchRemoteConfig(this)
// Set up 30-second interval
this.remoteConfigTimer = setInterval(() => fetchRemoteConfig(this), 30000) // 30 seconds
this.timers.push(setInterval(() => fetchRemoteConfig(this), 30000)) // 30 seconds
}
private startBannersTimer() {
this.timers.push(
setInterval(() => {
BannerService.get()
.getActiveBanners()
.then(() => this.postStateToWebview())
}, 86_400_000),
) // 24 hours
}
private startTimers() {
try {
this.startRemoteConfigTimer()
this.startBannersTimer()
} catch (err) {
Logger.error("Error starting timers: ", err)
}
}
constructor(readonly context: vscode.ExtensionContext) {
@@ -145,7 +163,7 @@ export class Controller {
this.accountService = ClineAccountService.getInstance()
this.authService.restoreRefreshTokenAndRetrieveAuthInfo().then(() => {
this.startRemoteConfigTimer()
this.startTimers()
})
this.mcpHub = new McpHub(
@@ -170,10 +188,10 @@ export class Controller {
- https://github.com/microsoft/vscode-extension-samples/blob/main/webview-sample/src/extension.ts
*/
async dispose() {
// Clear the remote config timer
if (this.remoteConfigTimer) {
clearInterval(this.remoteConfigTimer)
this.remoteConfigTimer = undefined
// Clear the timers
if (this.timers) {
this.timers.forEach(clearInterval)
this.timers = []
}
await this.clearTask()
@@ -878,7 +896,7 @@ export class Controller {
const distinctId = getDistinctId()
const version = ExtensionRegistryInfo.version
const environment = ClineEnv.config().environment
const banners = await this.getBanners()
const banners = BannerService.get().getCachedBanners()
// Set feature flag in dictation settings based on platform
const updatedDictationSettings = {
@@ -1006,13 +1024,4 @@ export class Controller {
this.stateManager.setGlobalState("taskHistory", history)
return history
}
async getBanners(): Promise<BannerCardData[]> {
try {
return BannerService.get().getActiveBanners()
} catch (err) {
console.log(err)
return []
}
}
}
+33 -6
View File
@@ -22,6 +22,7 @@ export class BannerService {
private _controller: Controller
private _authService?: AuthService
private actionTypes: Set<string>
private _fetchPromise: Promise<Banner[]> | null = null
private constructor(controller: Controller) {
this._controller = controller
@@ -82,7 +83,7 @@ export class BannerService {
* @param forceRefresh If true, bypasses cache and fetches fresh data
* @returns Array of banners that match current environment
*/
private async fetchActiveBanners(forceRefresh = false): Promise<Banner[]> {
private async internalGetActiveBanners(forceRefresh = false): Promise<Banner[]> {
try {
// Return cached banners if still valid
const now = Date.now()
@@ -91,6 +92,22 @@ export class BannerService {
return this._cachedBanners
}
if (this._fetchPromise && !forceRefresh) {
return this._fetchPromise
}
this._fetchPromise = this.fetchActiveBanners()
return this._fetchPromise
} catch (error) {
// Log error but don't throw - banner fetching shouldn't break the extension
Logger.error("BannerService: Error getting internal banners", error)
return []
}
}
private async fetchActiveBanners(): Promise<Banner[]> {
try {
const now = Date.now()
const ideType = await this.getIdeType()
const extensionVersion = await this.getExtensionVersion()
const osType = await this.getOSType()
@@ -106,10 +123,7 @@ export class BannerService {
Logger.log(`BannerService: Fetching banners from ${url}`)
const authService = this.getAuthServiceInstance()
let token: string | null = null
if (authService) {
token = await authService.getAuthToken()
}
const token: string | null = (await authService?.getAuthToken()) || null
const headers: Record<string, string> = {
"Content-Type": "application/json",
@@ -149,6 +163,8 @@ export class BannerService {
// Log error but don't throw - banner fetching shouldn't break the extension
Logger.error("BannerService: Error fetching banners", error)
return []
} finally {
this._fetchPromise = null
}
}
@@ -427,13 +443,24 @@ export class BannerService {
* @returns Array of non-dismissed banners converted to BannerCardData format
*/
public async getActiveBanners(forceRefresh = false): Promise<BannerCardData[]> {
const allBanners = await this.fetchActiveBanners(forceRefresh)
const allBanners = await this.internalGetActiveBanners(forceRefresh)
const nonDismissedBanners = allBanners.filter((banner) => !this.isBannerDismissed(banner.id))
return nonDismissedBanners
.map((banner) => this.convertToBannerCardData(banner))
.filter((banner): banner is BannerCardData => banner !== null)
}
public getCachedBanners(): BannerCardData[] {
try {
return this._cachedBanners
.map(this.convertToBannerCardData)
.filter((banner): banner is BannerCardData => banner !== null)
} catch (err) {
Logger.error("BannerService: Error getting cached banners", err)
return []
}
}
/**
* Gets the distinct ID for the current user
* @returns distinct ID string