Skip to content

Commit bb8386c

Browse files
committed
Cloud: convert CloudService to an EventEmitter
1 parent c07b270 commit bb8386c

File tree

4 files changed

+58
-49
lines changed

4 files changed

+58
-49
lines changed

packages/cloud/src/CloudService.ts

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as vscode from "vscode"
2+
import EventEmitter from "events"
23

34
import type {
45
CloudUserInfo,
@@ -10,7 +11,7 @@ import type {
1011
} from "@roo-code/types"
1112
import { TelemetryService } from "@roo-code/telemetry"
1213

13-
import { CloudServiceCallbacks } from "./types"
14+
import { CloudServiceEvents } from "./types"
1415
import type { AuthService } from "./auth"
1516
import { WebAuthService, StaticTokenAuthService } from "./auth"
1617
import type { SettingsService } from "./SettingsService"
@@ -19,29 +20,37 @@ import { StaticSettingsService } from "./StaticSettingsService"
1920
import { TelemetryClient } from "./TelemetryClient"
2021
import { ShareService, TaskNotFoundError } from "./ShareService"
2122

22-
export class CloudService {
23+
type AuthStateChangedPayload = CloudServiceEvents["auth-state-changed"][0]
24+
type AuthUserInfoPayload = CloudServiceEvents["user-info"][0]
25+
type SettingsPayload = CloudServiceEvents["settings-updated"][0]
26+
27+
export class CloudService extends EventEmitter<CloudServiceEvents> {
2328
private static _instance: CloudService | null = null
2429

2530
private context: vscode.ExtensionContext
26-
private callbacks: CloudServiceCallbacks
27-
private authListener: () => void
31+
private authStateListener: (data: AuthStateChangedPayload) => void
32+
private authUserInfoListener: (data: AuthUserInfoPayload) => void
2833
private authService: AuthService | null = null
29-
private settingsListener: () => void
34+
private settingsListener: (data: SettingsPayload) => void
3035
private settingsService: SettingsService | null = null
3136
private telemetryClient: TelemetryClient | null = null
3237
private shareService: ShareService | null = null
3338
private isInitialized = false
3439
private log: (...args: unknown[]) => void
3540

36-
private constructor(context: vscode.ExtensionContext, callbacks: CloudServiceCallbacks) {
41+
private constructor(context: vscode.ExtensionContext, log?: (...args: unknown[]) => void) {
42+
super()
43+
3744
this.context = context
38-
this.callbacks = callbacks
39-
this.log = callbacks.log || console.log
40-
this.authListener = () => {
41-
this.callbacks.stateChanged?.()
45+
this.log = log || console.log
46+
this.authStateListener = (data: AuthStateChangedPayload) => {
47+
this.emit("auth-state-changed", data)
48+
}
49+
this.authUserInfoListener = (data: AuthUserInfoPayload) => {
50+
this.emit("user-info", data)
4251
}
43-
this.settingsListener = () => {
44-
this.callbacks.stateChanged?.()
52+
this.settingsListener = (data: SettingsPayload) => {
53+
this.emit("settings-updated", data)
4554
}
4655
}
4756

@@ -61,8 +70,8 @@ export class CloudService {
6170

6271
await this.authService.initialize()
6372

64-
this.authService.on("auth-state-changed", this.authListener)
65-
this.authService.on("user-info", this.authListener)
73+
this.authService.on("auth-state-changed", this.authStateListener)
74+
this.authService.on("user-info", this.authUserInfoListener)
6675

6776
// Check for static settings environment variable.
6877
const staticOrgSettings = process.env.ROO_CODE_CLOUD_ORG_SETTINGS
@@ -217,8 +226,8 @@ export class CloudService {
217226

218227
public dispose(): void {
219228
if (this.authService) {
220-
this.authService.off("auth-state-changed", this.authListener)
221-
this.authService.off("user-info", this.authListener)
229+
this.authService.off("auth-state-changed", this.authStateListener)
230+
this.authService.off("user-info", this.authUserInfoListener)
222231
}
223232
if (this.settingsService) {
224233
if (this.settingsService instanceof CloudSettingsService) {
@@ -246,13 +255,13 @@ export class CloudService {
246255

247256
static async createInstance(
248257
context: vscode.ExtensionContext,
249-
callbacks: CloudServiceCallbacks = {},
258+
log?: (...args: unknown[]) => void,
250259
): Promise<CloudService> {
251260
if (this._instance) {
252261
throw new Error("CloudService instance already created")
253262
}
254263

255-
this._instance = new CloudService(context, callbacks)
264+
this._instance = new CloudService(context, log)
256265
await this._instance.initialize()
257266
return this._instance
258267
}

packages/cloud/src/__tests__/CloudService.test.ts

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import { CloudSettingsService } from "../CloudSettingsService"
99
import { ShareService, TaskNotFoundError } from "../ShareService"
1010
import { TelemetryClient } from "../TelemetryClient"
1111
import { TelemetryService } from "@roo-code/telemetry"
12-
import { CloudServiceCallbacks } from "../types"
1312

1413
vi.mock("vscode", () => ({
1514
ExtensionContext: vi.fn(),
@@ -172,23 +171,19 @@ describe("CloudService", () => {
172171

173172
describe("createInstance", () => {
174173
it("should create and initialize CloudService instance", async () => {
175-
const callbacks = {
176-
stateChanged: vi.fn(),
177-
}
174+
const mockLog = vi.fn()
178175

179-
const cloudService = await CloudService.createInstance(mockContext, callbacks)
176+
const cloudService = await CloudService.createInstance(mockContext, mockLog)
180177

181178
expect(cloudService).toBeInstanceOf(CloudService)
182179
expect(WebAuthService).toHaveBeenCalledWith(mockContext, expect.any(Function))
183180
expect(CloudSettingsService).toHaveBeenCalledWith(mockContext, mockAuthService, expect.any(Function))
184181
})
185182

186183
it("should set up event listeners for CloudSettingsService", async () => {
187-
const callbacks = {
188-
stateChanged: vi.fn(),
189-
}
184+
const mockLog = vi.fn()
190185

191-
await CloudService.createInstance(mockContext, callbacks)
186+
await CloudService.createInstance(mockContext, mockLog)
192187

193188
expect(mockSettingsService.on).toHaveBeenCalledWith("settings-updated", expect.any(Function))
194189
})
@@ -204,11 +199,9 @@ describe("CloudService", () => {
204199

205200
describe("authentication methods", () => {
206201
let cloudService: CloudService
207-
let callbacks: CloudServiceCallbacks
208202

209203
beforeEach(async () => {
210-
callbacks = { stateChanged: vi.fn() }
211-
cloudService = await CloudService.createInstance(mockContext, callbacks)
204+
cloudService = await CloudService.createInstance(mockContext)
212205
})
213206

214207
it("should delegate login to AuthService", async () => {
@@ -457,23 +450,24 @@ describe("CloudService", () => {
457450

458451
describe("settings event handling", () => {
459452
let _cloudService: CloudService
460-
let callbacks: CloudServiceCallbacks
461453

462454
beforeEach(async () => {
463-
callbacks = { stateChanged: vi.fn() }
464-
_cloudService = await CloudService.createInstance(mockContext, callbacks)
455+
_cloudService = await CloudService.createInstance(mockContext)
465456
})
466457

467-
it("should call stateChanged callback when settings are updated", async () => {
468-
// Get the settings listener that was registered
469-
const settingsListener = mockSettingsService.on.mock.calls.find(
458+
it("should emit settings-updated event when settings are updated", async () => {
459+
const settingsListener = vi.fn()
460+
_cloudService.on("settings-updated", settingsListener)
461+
462+
// Get the settings listener that was registered with the settings service
463+
const serviceSettingsListener = mockSettingsService.on.mock.calls.find(
470464
(call) => call[0] === "settings-updated",
471465
)?.[1]
472466

473-
expect(settingsListener).toBeDefined()
467+
expect(serviceSettingsListener).toBeDefined()
474468

475469
// Simulate settings update event
476-
settingsListener({
470+
const settingsData = {
477471
settings: {
478472
version: 2,
479473
defaultSettings: {},
@@ -484,9 +478,10 @@ describe("CloudService", () => {
484478
defaultSettings: {},
485479
allowList: { allowAll: true, providers: {} },
486480
},
487-
})
481+
}
482+
serviceSettingsListener(settingsData)
488483

489-
expect(callbacks.stateChanged).toHaveBeenCalled()
484+
expect(settingsListener).toHaveBeenCalledWith(settingsData)
490485
})
491486
})
492487

@@ -503,7 +498,7 @@ describe("CloudService", () => {
503498
mockAuthService.hasOrIsAcquiringActiveSession.mockReturnValue(true)
504499
mockAuthService.getState.mockReturnValue("active")
505500

506-
cloudService = await CloudService.createInstance(mockContext, {})
501+
cloudService = await CloudService.createInstance(mockContext)
507502
})
508503

509504
it("should call shareTask without retry when successful", async () => {

packages/cloud/src/types.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export interface CloudServiceCallbacks {
2-
stateChanged?: () => void
3-
log?: (...args: unknown[]) => void
4-
}
1+
import { AuthServiceEvents } from "./auth"
2+
import { SettingsServiceEvents } from "./CloudSettingsService"
3+
4+
export type CloudServiceEvents = AuthServiceEvents & SettingsServiceEvents

src/extension.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,15 @@ export async function activate(context: vscode.ExtensionContext) {
7575
const cloudLogger = createDualLogger(createOutputChannelLogger(outputChannel))
7676

7777
// Initialize Roo Code Cloud service.
78-
await CloudService.createInstance(context, {
79-
stateChanged: () => ClineProvider.getVisibleInstance()?.postStateToWebview(),
80-
log: cloudLogger,
81-
})
78+
const cloudService = await CloudService.createInstance(context, cloudLogger)
79+
const postStateListener = () => {
80+
ClineProvider.getVisibleInstance()?.postStateToWebview()
81+
}
82+
cloudService.on("auth-state-changed", postStateListener)
83+
cloudService.on("user-info", postStateListener)
84+
cloudService.on("settings-updated", postStateListener)
85+
// Add to subscriptions for proper cleanup on deactivate
86+
context.subscriptions.push(cloudService)
8287

8388
// Initialize MDM service
8489
const mdmService = await MdmService.createInstance(cloudLogger)

0 commit comments

Comments
 (0)