2
0
mirror of https://github.com/frappe/books.git synced 2024-09-20 11:29:00 +00:00

incr: flatten locale

- simplify telemetry calls
- add platform
This commit is contained in:
18alantom 2022-03-18 15:39:17 +05:30 committed by Alan
parent 88f44692d6
commit 3d4275ef34
6 changed files with 137 additions and 53 deletions

View File

@ -84,6 +84,7 @@ export default {
TelemetryModal, TelemetryModal,
}, },
async mounted() { async mounted() {
telemetry.platform = this.platform;
const lastSelectedFilePath = config.get('lastSelectedFilePath', null); const lastSelectedFilePath = config.get('lastSelectedFilePath', null);
const { connectionSuccess, reason } = await connectToLocalDatabase( const { connectionSuccess, reason } = await connectToLocalDatabase(
lastSelectedFilePath lastSelectedFilePath
@ -132,7 +133,7 @@ export default {
}, },
changeDbFile() { changeDbFile() {
config.set('lastSelectedFilePath', null); config.set('lastSelectedFilePath', null);
telemetry.stop() telemetry.stop();
purgeCache(true); purgeCache(true);
this.activeScreen = 'DatabaseSelector'; this.activeScreen = 'DatabaseSelector';
}, },

View File

@ -1,11 +1,10 @@
import config from '@/config'; import config from '@/config';
import { ipcRenderer } from 'electron';
import SQLiteDatabase from 'frappe/backends/sqlite'; import SQLiteDatabase from 'frappe/backends/sqlite';
import fs from 'fs'; import fs from 'fs';
import models from '../models'; import models from '../models';
import regionalModelUpdates from '../models/regionalModelUpdates'; import regionalModelUpdates from '../models/regionalModelUpdates';
import postStart, { setCurrencySymbols } from '../server/postStart'; import postStart, { setCurrencySymbols } from '../server/postStart';
import { DB_CONN_FAILURE, IPC_ACTIONS } from './messages'; import { DB_CONN_FAILURE } from './messages';
import runMigrate from './migrate'; import runMigrate from './migrate';
import { getId } from './telemetry/helpers'; import { getId } from './telemetry/helpers';
import telemetry from './telemetry/telemetry'; import telemetry from './telemetry/telemetry';
@ -97,10 +96,7 @@ export async function connectToLocalDatabase(filePath) {
// second init with currency, normal usage // second init with currency, normal usage
await callInitializeMoneyMaker(); await callInitializeMoneyMaker();
const creds = await ipcRenderer.invoke(IPC_ACTIONS.GET_CREDS); await telemetry.start();
telemetry.setCreds(creds?.telemetryUrl ?? '', creds?.tokenString ?? '');
telemetry.start();
await telemetry.setCount();
if (frappe.store.isDevelopment) { if (frappe.store.isDevelopment) {
// @ts-ignore // @ts-ignore

View File

@ -154,7 +154,12 @@ function registerIpcRendererListeners() {
}); });
document.addEventListener('visibilitychange', function () { document.addEventListener('visibilitychange', function () {
if (document.visibilityState !== 'hidden') { const { visibilityState } = document;
if (visibilityState === 'visible' && !telemetry.started) {
telemetry.start();
}
if (visibilityState !== 'hidden') {
return; return;
} }

View File

@ -1,6 +1,8 @@
import config, { ConfigFile, ConfigKeys } from '@/config'; import config, { ConfigFile, ConfigKeys } from '@/config';
import { IPC_ACTIONS } from '@/messages';
import { ipcRenderer } from 'electron';
import { DoctypeName } from '../../models/types'; import { DoctypeName } from '../../models/types';
import { Count, Locale, UniqueId } from './types'; import { Count, UniqueId } from './types';
export function getId(): string { export function getId(): string {
let id: string = ''; let id: string = '';
@ -12,12 +14,13 @@ export function getId(): string {
return id; return id;
} }
export function getLocale(): Locale { export function getCountry(): string {
// @ts-ignore // @ts-ignore
const country: string = frappe.AccountingSettings?.country ?? ''; return frappe.AccountingSettings?.country ?? '';
const language: string = config.get('language') as string; }
return { country, language }; export function getLanguage(): string {
return config.get('language') as string;
} }
export async function getCounts(): Promise<Count> { export async function getCounts(): Promise<Count> {
@ -122,3 +125,10 @@ function setInstanceId(companyName: string, files: ConfigFile[]): UniqueId {
config.set(ConfigKeys.Files, files); config.set(ConfigKeys.Files, files);
return id; return id;
} }
export async function getCreds() {
const creds = await ipcRenderer.invoke(IPC_ACTIONS.GET_CREDS);
const url: string = creds?.telemetryUrl ?? '';
const token: string = creds?.tokenString ?? '';
return { url, token };
}

View File

@ -1,8 +1,48 @@
import config, { ConfigKeys, TelemetrySetting } from '@/config'; import config, { ConfigKeys, TelemetrySetting } from '@/config';
import frappe from 'frappe'; import frappe from 'frappe';
import { cloneDeep } from 'lodash'; import { cloneDeep } from 'lodash';
import { getCounts, getDeviceId, getInstanceId, getLocale } from './helpers'; import {
import { Noun, NounEnum, Telemetry, Verb } from './types'; getCountry,
getCounts,
getCreds,
getDeviceId,
getInstanceId,
getLanguage,
} from './helpers';
import { Noun, NounEnum, Platform, Telemetry, Verb } from './types';
/**
* # Telemetry
*
* ## `start`
* Used to initialize state. It should be called before interaction.
* It is called on three events:
* 1. On db initialization which happens everytime a db is loaded or changed.
* 2. On visibility change if not started, eg: when user minimizeds Books and
* then comes back later.
* 3. When `log` is called if not initialized.
*
* ## `log`
* Used to make entries in the `timeline` which happens only if telmetry
* is set to 'Allow Telemetry`
*
* ## `error`
* Called in errorHandling.ts and maintains a count of errors that were
* thrown during usage.
*
* ## `stop`
* This is to be called when a session is being stopped. It's called on two events
* 1. When the db is being changed.
* 2. When the visiblity has changed which happens when either the app is being shut or
* the app is hidden.
*
* This function can't be async as it's called when visibility changes to 'hidden'
* at which point async doesn't seem to work and hence count is captured on `start()`
*
* ## `finalLogAndStop`
* Called when telemetry is set to "Don't Log Anything" so as to indicate cessation of
* telemetry and not app usage.
*/
class TelemetryManager { class TelemetryManager {
#url: string = ''; #url: string = '';
@ -10,32 +50,42 @@ class TelemetryManager {
#started = false; #started = false;
#telemetryObject: Partial<Telemetry> = {}; #telemetryObject: Partial<Telemetry> = {};
start() { set platform(value: Platform) {
this.#telemetryObject.locale = getLocale(); this.#telemetryObject.platform ||= value;
}
get hasCreds() {
return !!this.#url && !!this.#token;
}
get started() {
return this.#started;
}
get telemetryObject(): Readonly<Partial<Telemetry>> {
return cloneDeep(this.#telemetryObject);
}
async start() {
this.#telemetryObject.country ||= getCountry();
this.#telemetryObject.language ??= getLanguage();
this.#telemetryObject.deviceId ||= getDeviceId(); this.#telemetryObject.deviceId ||= getDeviceId();
this.#telemetryObject.instanceId ||= getInstanceId(); this.#telemetryObject.instanceId ||= getInstanceId();
this.#telemetryObject.openTime ||= new Date().valueOf(); this.#telemetryObject.openTime ||= new Date().valueOf();
this.#telemetryObject.timeline ??= []; this.#telemetryObject.timeline ??= [];
this.#telemetryObject.errors ??= {}; this.#telemetryObject.errors ??= {};
this.#telemetryObject.counts ??= {};
this.#started = true; this.#started = true;
await this.#postStart();
} }
getCanLog(): boolean { async log(verb: Verb, noun: Noun, more?: Record<string, unknown>) {
const telemetrySetting = config.get(ConfigKeys.Telemetry) as string;
return telemetrySetting === TelemetrySetting.allow;
}
setCreds(url: string, token: string) {
this.#url ||= url;
this.#token ||= token;
}
log(verb: Verb, noun: Noun, more?: Record<string, unknown>) {
if (!this.#started) { if (!this.#started) {
this.start(); await this.start();
} }
if (!this.getCanLog()) { if (!this.#getCanLog()) {
return; return;
} }
@ -56,32 +106,23 @@ class TelemetryManager {
this.#telemetryObject.errors[name] += 1; this.#telemetryObject.errors[name] += 1;
} }
async setCount() {
this.#telemetryObject.counts = this.getCanLog() ? await getCounts() : {};
}
stop() { stop() {
// Will set ids if not set. this.#started = false;
this.start();
//@ts-ignore //@ts-ignore
this.#telemetryObject.version = frappe.store.appVersion ?? ''; this.#telemetryObject.version = frappe.store.appVersion ?? '';
this.#telemetryObject.closeTime = new Date().valueOf(); this.#telemetryObject.closeTime = new Date().valueOf();
const telemetryObject = this.#telemetryObject; const data = JSON.stringify({
token: this.#token,
telemetryData: this.#telemetryObject,
});
this.#started = false; this.#clear();
this.#telemetryObject = {};
if (config.get(ConfigKeys.Telemetry) === TelemetrySetting.dontLogAnything) { if (config.get(ConfigKeys.Telemetry) === TelemetrySetting.dontLogAnything) {
return; return;
} }
const data = JSON.stringify({
token: this.#token,
telemetryData: telemetryObject,
});
navigator.sendBeacon(this.#url, data); navigator.sendBeacon(this.#url, data);
} }
@ -90,8 +131,43 @@ class TelemetryManager {
this.stop(); this.stop();
} }
get telemetryObject(): Readonly<Partial<Telemetry>> { async #postStart() {
return cloneDeep(this.#telemetryObject); await this.#setCount();
await this.#setCreds();
}
async #setCount() {
if (!this.#getCanLog()) {
return;
}
this.#telemetryObject.counts = await getCounts();
}
async #setCreds() {
if (this.hasCreds) {
return;
}
const { url, token } = await getCreds();
this.#url = url;
this.#token = token;
}
#getCanLog(): boolean {
const telemetrySetting = config.get(ConfigKeys.Telemetry) as string;
return telemetrySetting === TelemetrySetting.allow;
}
#clear() {
// Delete only what varies
delete this.#telemetryObject.openTime;
delete this.#telemetryObject.closeTime;
delete this.#telemetryObject.errors;
delete this.#telemetryObject.counts;
delete this.#telemetryObject.timeline;
delete this.#telemetryObject.instanceId;
delete this.#telemetryObject.country;
} }
} }

View File

@ -11,11 +11,6 @@ export interface InteractionEvent {
more?: Record<string, unknown>; more?: Record<string, unknown>;
} }
export interface Locale {
country: string;
language: string;
}
export type Count = Partial<{ export type Count = Partial<{
[key in DoctypeName]: number; [key in DoctypeName]: number;
}>; }>;
@ -30,7 +25,8 @@ export interface Telemetry {
timeline?: InteractionEvent[]; timeline?: InteractionEvent[];
counts?: Count; counts?: Count;
errors: Record<string, number>; errors: Record<string, number>;
locale: Locale; country: string;
language: string;
version: AppVersion; version: AppVersion;
} }