SettingsService.ts 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import * as vscode from "vscode"
  2. import {
  3. ORGANIZATION_ALLOW_ALL,
  4. OrganizationAllowList,
  5. OrganizationSettings,
  6. organizationSettingsSchema,
  7. } from "@roo-code/types"
  8. import { getRooCodeApiUrl } from "./Config"
  9. import type { AuthService } from "./auth"
  10. import { RefreshTimer } from "./RefreshTimer"
  11. const ORGANIZATION_SETTINGS_CACHE_KEY = "organization-settings"
  12. export class SettingsService {
  13. private context: vscode.ExtensionContext
  14. private authService: AuthService
  15. private settings: OrganizationSettings | undefined = undefined
  16. private timer: RefreshTimer
  17. private log: (...args: unknown[]) => void
  18. constructor(
  19. context: vscode.ExtensionContext,
  20. authService: AuthService,
  21. callback: () => void,
  22. log?: (...args: unknown[]) => void,
  23. ) {
  24. this.context = context
  25. this.authService = authService
  26. this.log = log || console.log
  27. this.timer = new RefreshTimer({
  28. callback: async () => {
  29. return await this.fetchSettings(callback)
  30. },
  31. successInterval: 30000,
  32. initialBackoffMs: 1000,
  33. maxBackoffMs: 30000,
  34. })
  35. }
  36. public initialize(): void {
  37. this.loadCachedSettings()
  38. // Clear cached settings if we have missed a log out.
  39. if (this.authService.getState() == "logged-out" && this.settings) {
  40. this.removeSettings()
  41. }
  42. this.authService.on("active-session", () => {
  43. this.timer.start()
  44. })
  45. this.authService.on("logged-out", () => {
  46. this.timer.stop()
  47. this.removeSettings()
  48. })
  49. if (this.authService.hasActiveSession()) {
  50. this.timer.start()
  51. }
  52. }
  53. private async fetchSettings(callback: () => void): Promise<boolean> {
  54. const token = this.authService.getSessionToken()
  55. if (!token) {
  56. return false
  57. }
  58. try {
  59. const response = await fetch(`${getRooCodeApiUrl()}/api/organization-settings`, {
  60. headers: {
  61. Authorization: `Bearer ${token}`,
  62. },
  63. })
  64. if (!response.ok) {
  65. this.log(
  66. "[cloud-settings] Failed to fetch organization settings:",
  67. response.status,
  68. response.statusText,
  69. )
  70. return false
  71. }
  72. const data = await response.json()
  73. const result = organizationSettingsSchema.safeParse(data)
  74. if (!result.success) {
  75. this.log("[cloud-settings] Invalid organization settings format:", result.error)
  76. return false
  77. }
  78. const newSettings = result.data
  79. if (!this.settings || this.settings.version !== newSettings.version) {
  80. this.settings = newSettings
  81. await this.cacheSettings()
  82. callback()
  83. }
  84. return true
  85. } catch (error) {
  86. this.log("[cloud-settings] Error fetching organization settings:", error)
  87. return false
  88. }
  89. }
  90. private async cacheSettings(): Promise<void> {
  91. await this.context.globalState.update(ORGANIZATION_SETTINGS_CACHE_KEY, this.settings)
  92. }
  93. private loadCachedSettings(): void {
  94. this.settings = this.context.globalState.get<OrganizationSettings>(ORGANIZATION_SETTINGS_CACHE_KEY)
  95. }
  96. public getAllowList(): OrganizationAllowList {
  97. return this.settings?.allowList || ORGANIZATION_ALLOW_ALL
  98. }
  99. public getSettings(): OrganizationSettings | undefined {
  100. return this.settings
  101. }
  102. public async removeSettings(): Promise<void> {
  103. this.settings = undefined
  104. await this.cacheSettings()
  105. }
  106. public dispose(): void {
  107. this.timer.stop()
  108. }
  109. }