|
1 |
| -import { AnalyticsServiceBase } from "../../common/services/analytics-service-base"; |
2 | 1 | import { ChildProcess } from "child_process";
|
3 | 2 | import * as path from "path";
|
4 | 3 | import { cache } from "../../common/decorators";
|
5 |
| -import { isInteractive } from '../../common/helpers'; |
| 4 | +import { isInteractive, toBoolean } from '../../common/helpers'; |
6 | 5 | import { DeviceTypes, AnalyticsClients } from "../../common/constants";
|
7 | 6 |
|
8 |
| -export class AnalyticsService extends AnalyticsServiceBase { |
| 7 | +export class AnalyticsService implements IAnalyticsService, IDisposable { |
9 | 8 | private static ANALYTICS_BROKER_START_TIMEOUT = 10 * 1000;
|
10 | 9 | private brokerProcess: ChildProcess;
|
11 |
| - |
12 |
| - constructor(protected $logger: ILogger, |
13 |
| - protected $options: IOptions, |
14 |
| - protected $processService: IProcessService, |
15 |
| - $staticConfig: Config.IStaticConfig, |
16 |
| - $prompter: IPrompter, |
17 |
| - $userSettingsService: UserSettings.IUserSettingsService, |
18 |
| - $analyticsSettingsService: IAnalyticsSettingsService, |
| 10 | + private shouldDisposeInstance: boolean = true; |
| 11 | + private analyticsStatuses: IDictionary<AnalyticsStatus> = {}; |
| 12 | + |
| 13 | + constructor(private $logger: ILogger, |
| 14 | + private $options: IOptions, |
| 15 | + private $processService: IProcessService, |
| 16 | + private $staticConfig: Config.IStaticConfig, |
| 17 | + private $prompter: IPrompter, |
| 18 | + private $userSettingsService: UserSettings.IUserSettingsService, |
| 19 | + private $analyticsSettingsService: IAnalyticsSettingsService, |
19 | 20 | private $childProcess: IChildProcess,
|
20 | 21 | private $projectDataService: IProjectDataService,
|
21 | 22 | private $mobileHelper: Mobile.IMobileHelper) {
|
22 |
| - super($logger, $options, $staticConfig, $processService, $prompter, $userSettingsService, $analyticsSettingsService); |
23 | 23 | }
|
24 | 24 |
|
25 |
| - public trackException(exception: any, message: string): Promise<void> { |
26 |
| - const data: IExceptionsTrackingInformation = { |
27 |
| - type: TrackingTypes.Exception, |
28 |
| - exception, |
29 |
| - message |
30 |
| - }; |
| 25 | + public setShouldDispose(shouldDispose: boolean): void { |
| 26 | + this.shouldDisposeInstance = shouldDispose; |
| 27 | + } |
31 | 28 |
|
32 |
| - return this.sendInfoForTracking(data, this.$staticConfig.ERROR_REPORT_SETTING_NAME); |
| 29 | + public async checkConsent(): Promise<void> { |
| 30 | + if (await this.$analyticsSettingsService.canDoRequest()) { |
| 31 | + const initialTrackFeatureUsageStatus = await this.getStatus(this.$staticConfig.TRACK_FEATURE_USAGE_SETTING_NAME); |
| 32 | + let trackFeatureUsage = initialTrackFeatureUsageStatus === AnalyticsStatus.enabled; |
| 33 | + |
| 34 | + if (await this.isNotConfirmed(this.$staticConfig.TRACK_FEATURE_USAGE_SETTING_NAME) && isInteractive()) { |
| 35 | + this.$logger.out("Do you want to help us improve " |
| 36 | + + this.$analyticsSettingsService.getClientName() |
| 37 | + + " by automatically sending anonymous usage statistics? We will not use this information to identify or contact you." |
| 38 | + + " You can read our official Privacy Policy at"); |
| 39 | + |
| 40 | + const message = this.$analyticsSettingsService.getPrivacyPolicyLink(); |
| 41 | + trackFeatureUsage = await this.$prompter.confirm(message, () => true); |
| 42 | + await this.setStatus(this.$staticConfig.TRACK_FEATURE_USAGE_SETTING_NAME, trackFeatureUsage); |
| 43 | + |
| 44 | + await this.trackAcceptFeatureUsage({ acceptTrackFeatureUsage: trackFeatureUsage }); |
| 45 | + } |
| 46 | + |
| 47 | + const isErrorReportingUnset = await this.isNotConfirmed(this.$staticConfig.ERROR_REPORT_SETTING_NAME); |
| 48 | + const isUsageReportingConfirmed = !await this.isNotConfirmed(this.$staticConfig.TRACK_FEATURE_USAGE_SETTING_NAME); |
| 49 | + if (isErrorReportingUnset && isUsageReportingConfirmed) { |
| 50 | + await this.setStatus(this.$staticConfig.ERROR_REPORT_SETTING_NAME, trackFeatureUsage); |
| 51 | + } |
| 52 | + } |
| 53 | + } |
| 54 | + |
| 55 | + public async setStatus(settingName: string, enabled: boolean): Promise<void> { |
| 56 | + this.analyticsStatuses[settingName] = enabled ? AnalyticsStatus.enabled : AnalyticsStatus.disabled; |
| 57 | + await this.$userSettingsService.saveSetting(settingName, enabled.toString()); |
| 58 | + } |
| 59 | + |
| 60 | + public async isEnabled(settingName: string): Promise<boolean> { |
| 61 | + const analyticsStatus = await this.getStatus(settingName); |
| 62 | + return analyticsStatus === AnalyticsStatus.enabled; |
| 63 | + } |
| 64 | + |
| 65 | + public getStatusMessage(settingName: string, jsonFormat: boolean, readableSettingName: string): Promise<string> { |
| 66 | + if (jsonFormat) { |
| 67 | + return this.getJsonStatusMessage(settingName); |
| 68 | + } |
| 69 | + |
| 70 | + return this.getHumanReadableStatusMessage(settingName, readableSettingName); |
33 | 71 | }
|
34 | 72 |
|
35 | 73 | public async trackAcceptFeatureUsage(settings: { acceptTrackFeatureUsage: boolean }): Promise<void> {
|
@@ -192,6 +230,72 @@ export class AnalyticsService extends AnalyticsServiceBase {
|
192 | 230 | }
|
193 | 231 | });
|
194 | 232 | }
|
| 233 | + |
| 234 | + @cache() |
| 235 | + private async initAnalyticsStatuses(): Promise<void> { |
| 236 | + if (await this.$analyticsSettingsService.canDoRequest()) { |
| 237 | + this.$logger.trace("Initializing analytics statuses."); |
| 238 | + const settingsNames = [this.$staticConfig.TRACK_FEATURE_USAGE_SETTING_NAME, this.$staticConfig.ERROR_REPORT_SETTING_NAME]; |
| 239 | + |
| 240 | + for (const settingName of settingsNames) { |
| 241 | + await this.getStatus(settingName); |
| 242 | + } |
| 243 | + |
| 244 | + this.$logger.trace("Analytics statuses: ", this.analyticsStatuses); |
| 245 | + } |
| 246 | + } |
| 247 | + |
| 248 | + private async getStatus(settingName: string): Promise<AnalyticsStatus> { |
| 249 | + if (!_.has(this.analyticsStatuses, settingName)) { |
| 250 | + const settingValue = await this.$userSettingsService.getSettingValue<string>(settingName); |
| 251 | + |
| 252 | + if (settingValue) { |
| 253 | + const isEnabled = toBoolean(settingValue); |
| 254 | + if (isEnabled) { |
| 255 | + this.analyticsStatuses[settingName] = AnalyticsStatus.enabled; |
| 256 | + } else { |
| 257 | + this.analyticsStatuses[settingName] = AnalyticsStatus.disabled; |
| 258 | + } |
| 259 | + } else { |
| 260 | + this.analyticsStatuses[settingName] = AnalyticsStatus.notConfirmed; |
| 261 | + } |
| 262 | + } |
| 263 | + |
| 264 | + return this.analyticsStatuses[settingName]; |
| 265 | + } |
| 266 | + |
| 267 | + private async isNotConfirmed(settingName: string): Promise<boolean> { |
| 268 | + const analyticsStatus = await this.getStatus(settingName); |
| 269 | + return analyticsStatus === AnalyticsStatus.notConfirmed; |
| 270 | + } |
| 271 | + |
| 272 | + private async getHumanReadableStatusMessage(settingName: string, readableSettingName: string): Promise<string> { |
| 273 | + let status: string = null; |
| 274 | + |
| 275 | + if (await this.isNotConfirmed(settingName)) { |
| 276 | + status = "disabled until confirmed"; |
| 277 | + } else { |
| 278 | + status = await this.getStatus(settingName); |
| 279 | + } |
| 280 | + |
| 281 | + return `${readableSettingName} is ${status}.`; |
| 282 | + } |
| 283 | + |
| 284 | + private async getJsonStatusMessage(settingName: string): Promise<string> { |
| 285 | + const status = await this.getStatus(settingName); |
| 286 | + const enabled = status === AnalyticsStatus.notConfirmed ? null : status === AnalyticsStatus.enabled; |
| 287 | + return JSON.stringify({ enabled }); |
| 288 | + } |
| 289 | + |
| 290 | + public trackException(exception: any, message: string): Promise<void> { |
| 291 | + const data: IExceptionsTrackingInformation = { |
| 292 | + type: TrackingTypes.Exception, |
| 293 | + exception, |
| 294 | + message |
| 295 | + }; |
| 296 | + |
| 297 | + return this.sendInfoForTracking(data, this.$staticConfig.ERROR_REPORT_SETTING_NAME); |
| 298 | + } |
195 | 299 | }
|
196 | 300 |
|
197 | 301 | $injector.register("analyticsService", AnalyticsService);
|
0 commit comments