Skip to content

Commit e51d050

Browse files
committed
Use SSE to track CRC status change and logs
Signed-off-by: Yevhen Vydolob <yvydolob@redhat.com>
1 parent caccc05 commit e51d050

9 files changed

+412
-50
lines changed

src/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import type { Preset } from './types';
2020

21+
export const PRE_SSE_VERSION = '2.29.0';
22+
2123
// copied from https://github.com/crc-org/crc/blob/632676d7c9ba0c030736c3d914984c4e140c1bf5/pkg/crc/constants/constants.go#L198
2224

2325
export function getDefaultCPUs(preset: Preset): number {

src/crc-delete.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export function registerDeleteCommand(): void {
3333
}
3434

3535
export async function deleteCrc(suppressNotification = false): Promise<boolean> {
36-
if (crcStatus.status.CrcStatus === 'No Cluster') {
36+
if (crcStatus.status.CrcStatus === 'NoVm') {
3737
if (!suppressNotification) {
3838
await extensionApi.window.showNotification({
3939
silent: false,

src/crc-status.ts

Lines changed: 60 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,23 @@
1818

1919
import * as extensionApi from '@podman-desktop/api';
2020
import type { Status, CrcStatus as CrcStatusApi } from './types';
21-
import { commander } from './daemon-commander';
21+
import { commander, getCrcApiUrl } from './daemon-commander';
2222
import { isNeedSetup } from './crc-setup';
23+
import { EventSource } from './events/eventsource';
24+
import type { CrcVersion } from './crc-cli';
25+
import { compare } from 'compare-versions';
26+
import { PRE_SSE_VERSION } from './constants';
2327

2428
const defaultStatus: Status = { CrcStatus: 'Unknown', Preset: 'openshift' };
2529
const setupStatus: Status = { CrcStatus: 'Need Setup', Preset: 'Unknown' };
2630
const errorStatus: Status = { CrcStatus: 'Error', Preset: 'Unknown' };
2731

2832
export class CrcStatus {
29-
private updateTimer: NodeJS.Timer;
3033
private _status: Status;
3134
private isSetupGoing: boolean;
35+
private statusEventSource: EventSource;
36+
private crcVersion: CrcVersion;
37+
private updateTimer: NodeJS.Timer;
3238
private statusChangeEventEmitter = new extensionApi.EventEmitter<Status>();
3339
public readonly onStatusChange = this.statusChangeEventEmitter.event;
3440

@@ -37,30 +43,61 @@ export class CrcStatus {
3743
}
3844

3945
startStatusUpdate(): void {
40-
if (this.updateTimer) {
41-
return; // we already set timer
42-
}
43-
this.updateTimer = setInterval(async () => {
44-
try {
45-
// we don't need to update status while setup is going
46-
if (this.isSetupGoing) {
47-
this._status = createStatus('Starting', this._status.Preset);
48-
return;
46+
if (compare(this.crcVersion.version, PRE_SSE_VERSION, '<=')) {
47+
if (this.updateTimer) {
48+
return; // we already set timer
49+
}
50+
this.updateTimer = setInterval(async () => {
51+
try {
52+
// we don't need to update status while setup is going
53+
if (this.isSetupGoing) {
54+
this._status = createStatus('Starting', this._status.Preset);
55+
return;
56+
}
57+
const oldStatus = this._status;
58+
this._status = await commander.status();
59+
// notify listeners when status changed
60+
if (oldStatus.CrcStatus !== this._status.CrcStatus) {
61+
this.statusChangeEventEmitter.fire(this._status);
62+
}
63+
} catch (e) {
64+
console.error('CRC Status tick: ' + e);
65+
this._status = defaultStatus;
4966
}
50-
const oldStatus = this._status;
51-
this._status = await commander.status();
52-
// notify listeners when status changed
53-
if (oldStatus.CrcStatus !== this._status.CrcStatus) {
67+
}, 2000);
68+
} else {
69+
if (this.statusEventSource) {
70+
return;
71+
}
72+
73+
this.statusEventSource = new EventSource(getCrcApiUrl() + '/events?stream=status_change');
74+
this.statusEventSource.on('status_change', (e: MessageEvent) => {
75+
const data = e.data;
76+
try {
77+
if (this.isSetupGoing) {
78+
this._status = createStatus('Starting', this._status.Preset);
79+
return;
80+
}
81+
console.error(`On Status: ${data}`);
82+
this._status = JSON.parse(data).status;
5483
this.statusChangeEventEmitter.fire(this._status);
84+
} catch (err) {
85+
console.error(err);
86+
this._status = defaultStatus;
5587
}
56-
} catch (e) {
57-
console.error('CRC Status tick: ' + e);
88+
});
89+
this.statusEventSource.on('error', e => {
90+
console.error(e);
5891
this._status = defaultStatus;
59-
}
60-
}, 2000);
92+
});
93+
}
6194
}
6295

6396
stopStatusUpdate(): void {
97+
if (this.statusEventSource) {
98+
this.statusEventSource.close();
99+
this.statusEventSource = undefined;
100+
}
64101
if (this.updateTimer) {
65102
clearInterval(this.updateTimer);
66103
}
@@ -74,7 +111,8 @@ export class CrcStatus {
74111
this._status = errorStatus;
75112
}
76113

77-
async initialize(): Promise<void> {
114+
async initialize(crcVersion: CrcVersion): Promise<void> {
115+
this.crcVersion = crcVersion;
78116
if (isNeedSetup) {
79117
this._status = setupStatus;
80118
return;
@@ -107,7 +145,7 @@ export class CrcStatus {
107145
case 'Stopping':
108146
return 'stopping';
109147
case 'Stopped':
110-
case 'No Cluster':
148+
case 'NoVm':
111149
return 'stopped';
112150
default:
113151
return 'unknown';
@@ -124,7 +162,7 @@ export class CrcStatus {
124162
return 'stopping';
125163
case 'Stopped':
126164
return 'configured';
127-
case 'No Cluster':
165+
case 'NoVm':
128166
return 'installed';
129167
case 'Error':
130168
return 'error';

src/daemon-commander.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,18 @@ import got from 'got';
2121
import { isWindows } from './util';
2222
import type { ConfigKeys, Configuration, StartInfo, Status } from './types';
2323

24+
export function getCrcApiUrl(): string {
25+
if(isWindows()) {
26+
return 'http://unix://?/pipe/crc-http:';
27+
}
28+
return `http://unix:${process.env.HOME}/.crc/crc-http.sock:`;
29+
}
30+
2431
export class DaemonCommander {
2532
private apiPath: string;
2633

2734
constructor() {
28-
this.apiPath = `http://unix:${process.env.HOME}/.crc/crc-http.sock:/api`;
29-
30-
if (isWindows()) {
31-
this.apiPath = 'http://unix://?/pipe/crc-http:/api';
32-
}
35+
this.apiPath = getCrcApiUrl() + '/api';
3336
}
3437

3538
async status(): Promise<Status> {
@@ -41,7 +44,7 @@ export class DaemonCommander {
4144
} catch (error) {
4245
// ignore status error, as it may happen when no cluster created
4346
return {
44-
CrcStatus: 'No Cluster',
47+
CrcStatus: 'NoVm',
4548
};
4649
}
4750
}

0 commit comments

Comments
 (0)