diff --git a/.env b/.env
index e0f07e34..5a610e11 100644
--- a/.env
+++ b/.env
@@ -8,6 +8,8 @@ ESIGNET_HOST=https://api.qa-inji.mosip.net
GOOGLE_NEARBY_MESSAGES_API_KEY=
+OBSRV_HOST = https://dataset-api.obsrv.mosip.net
+
#Application Theme can be ( orange | purple )
APPLICATION_THEME=orange
diff --git a/App.tsx b/App.tsx
index 8f9f5799..57ec58b8 100644
--- a/App.tsx
+++ b/App.tsx
@@ -15,6 +15,12 @@ import {
import { DualMessageOverlay } from './components/DualMessageOverlay';
import { useApp } from './screens/AppController';
import { Alert } from 'react-native';
+import {
+ getAppInfoData,
+ getTelemetryConfigData,
+ initializeTelemetry,
+ sendAppInfoEvent,
+} from './shared/telemetry/TelemetryUtils';
import { ErrorMessageOverlay } from './components/MessageOverlay';
import SecureKeystore from 'react-native-secure-keystore';
import { isCustomSecureKeystore } from './shared/cryptoutil/cryptoUtil';
@@ -35,6 +41,11 @@ const DecryptErrorAlert = (controller, t) => {
},
]);
};
+function configureTelemetry() {
+ const config = getTelemetryConfigData();
+ initializeTelemetry(config);
+ sendAppInfoEvent(getAppInfoData());
+}
const AppLayoutWrapper: React.FC = () => {
const { appService } = useContext(GlobalContext);
@@ -44,6 +55,7 @@ const AppLayoutWrapper: React.FC = () => {
if (isDecryptError) {
DecryptErrorAlert(controller, t);
}
+ configureTelemetry();
return ;
};
diff --git a/components/LanguageSelector.tsx b/components/LanguageSelector.tsx
index 49d66d56..ce3f5249 100644
--- a/components/LanguageSelector.tsx
+++ b/components/LanguageSelector.tsx
@@ -6,6 +6,7 @@ import Storage from '../shared/storage';
import {useTranslation} from 'react-i18next';
import i18next from 'i18next';
import RNRestart from 'react-native-restart';
+import { __SelectedLanguage } from '../shared/GlobalVariables';
export const LanguageSelector: React.FC = props => {
const {i18n} = useTranslation();
@@ -16,6 +17,7 @@ export const LanguageSelector: React.FC = props => {
const changeLanguage = async (language: string) => {
if (language !== i18n.language) {
await i18n.changeLanguage(language).then(async () => {
+ __SelectedLanguage.setValue(language);
await Storage.setItem('language', i18n.language);
const isRTL = i18next.dir(language) === 'rtl' ? true : false;
if (isRTL !== I18nManager.isRTL) {
diff --git a/machines/QrLoginMachine.ts b/machines/QrLoginMachine.ts
index d020b82b..2d8de3b1 100644
--- a/machines/QrLoginMachine.ts
+++ b/machines/QrLoginMachine.ts
@@ -21,6 +21,7 @@ import {
getPrivateKey,
} from '../shared/keystore/SecureKeystore';
import i18n from '../i18n';
+import { getEndData, sendEndEvent } from '../shared/telemetry/TelemetryUtils';
const model = createModel(
{
@@ -225,6 +226,7 @@ export const qrLoginMachine =
},
},
success: {
+ entry: [() => sendEndEvent(getEndData('QR login'))],
on: {
CONFIRM: {
target: 'done',
diff --git a/machines/bleShare/scan/scanMachine.ts b/machines/bleShare/scan/scanMachine.ts
index 20b9a576..724928b9 100644
--- a/machines/bleShare/scan/scanMachine.ts
+++ b/machines/bleShare/scan/scanMachine.ts
@@ -39,6 +39,12 @@ import {WalletDataEvent} from 'react-native-tuvali/lib/typescript/types/events';
import {BLEError} from '../types';
import Storage from '../../../shared/storage';
import {logState} from '../../app';
+import {
+ getData,
+ getEndData,
+ sendStartEvent,
+ sendEndEvent,
+} from '../../../shared/telemetry/TelemetryUtils';
const {wallet, EventTypes, VerificationStatus} = tuvali;
@@ -425,7 +431,7 @@ export const scanMachine =
},
navigatingToHistory: {},
},
- entry: 'sendScanData',
+ entry: ['sendScanData', () => sendStartEvent(getData('QR login'))],
},
connecting: {
invoke: {
@@ -552,7 +558,7 @@ export const scanMachine =
},
},
accepted: {
- entry: 'logShared',
+ entry: ['logShared', () => sendEndEvent(getEndData('VC share'))],
on: {
DISMISS: {
target: 'navigatingToHome',
@@ -983,6 +989,7 @@ export const scanMachine =
},
startConnection: context => callback => {
+ sendStartEvent(getData('VC share'));
wallet.startConnection(context.openId4VpUri);
const statusCallback = (event: WalletDataEvent) => {
if (event.type === EventTypes.onSecureChannelEstablished) {
diff --git a/machines/settings.ts b/machines/settings.ts
index 4a0e822b..a070d926 100644
--- a/machines/settings.ts
+++ b/machines/settings.ts
@@ -16,7 +16,7 @@ import getAllConfigurations, {
} from '../shared/commonprops/commonProps';
import Storage from '../shared/storage';
import ShortUniqueId from 'short-unique-id';
-import { AppId } from '../shared/request';
+import { __AppId } from '../shared/GlobalVariables';
import { isCustomSecureKeystore } from '../shared/cryptoutil/cryptoUtil';
const model = createModel(
@@ -171,7 +171,7 @@ export const settingsMachine = model.createMachine(
updateDefaults: model.assign({
appId: () => {
const appId = generateAppId();
- AppId.setValue(appId);
+ __AppId.setValue(appId);
return appId;
},
@@ -192,7 +192,7 @@ export const settingsMachine = model.createMachine(
setContext: model.assign((context, event) => {
const newContext = event.response as ContextFrom;
- AppId.setValue(newContext.appId);
+ __AppId.setValue(newContext.appId);
return {
...context,
...newContext,
diff --git a/machines/vcItem.ts b/machines/vcItem.ts
index b120defd..879cf573 100644
--- a/machines/vcItem.ts
+++ b/machines/vcItem.ts
@@ -34,6 +34,12 @@ import getAllConfigurations, {
import { VcEvents } from './vc';
import i18n from '../i18n';
import SecureKeystore from 'react-native-secure-keystore';
+import {
+ sendStartEvent,
+ getData,
+ getEndData,
+ sendEndEvent,
+} from '../shared/telemetry/TelemetryUtils';
const model = createModel(
{
@@ -301,6 +307,7 @@ export const vcItemMachine =
showBindingWarning: {
on: {
CONFIRM: {
+ actions: [() => sendStartEvent(getData('VC activation'))],
target: '#vc-item.kebabPopUp.requestingBindingOtp',
},
CANCEL: {
@@ -413,6 +420,7 @@ export const vcItemMachine =
'updateVc',
'setWalletBindingErrorEmpty',
'logWalletBindingSuccess',
+ () => sendEndEvent(getEndData('VC activation')),
],
target: '#vc-item.kebabPopUp',
},
@@ -632,6 +640,7 @@ export const vcItemMachine =
showBindingWarning: {
on: {
CONFIRM: {
+ actions: () => sendStartEvent(getData('VC activation')),
target: 'requestingBindingOtp',
},
CANCEL: {
@@ -740,6 +749,7 @@ export const vcItemMachine =
'updateVc',
'setWalletBindingErrorEmpty',
'logWalletBindingSuccess',
+ () => sendEndEvent(getEndData('VC activation')),
],
target: 'idle',
},
diff --git a/package-lock.json b/package-lock.json
index ea9a7df3..8147e330 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -62,6 +62,7 @@
"react-native-gesture-handler": "~2.9.0",
"react-native-keychain": "^8.0.0",
"react-native-linear-gradient": "^2.8.0",
+ "react-native-localize": "^3.0.2",
"react-native-location": "^2.5.0",
"react-native-mmkv-storage": "^0.9.1",
"react-native-permissions": "^3.8.0",
@@ -24095,6 +24096,21 @@
"react-native": "*"
}
},
+ "node_modules/react-native-localize": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/react-native-localize/-/react-native-localize-3.0.2.tgz",
+ "integrity": "sha512-/l/oE1LVNgIRRhLbhmfFMHiWV0xhUn0A0iz1ytLVRYywL7FTp8Rx2vkJS/q/RpExDvV7yLw2493XZBYIM1dnLQ==",
+ "peerDependencies": {
+ "react": ">=18.1.0",
+ "react-native": ">=0.70.0",
+ "react-native-macos": ">=0.70.0"
+ },
+ "peerDependenciesMeta": {
+ "react-native-macos": {
+ "optional": true
+ }
+ }
+ },
"node_modules/react-native-location": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/react-native-location/-/react-native-location-2.5.0.tgz",
@@ -45551,6 +45567,12 @@
"integrity": "sha512-hgmCsgzd58WNcDCyPtKrvxsaoETjb/jLGxis/dmU3Aqm2u4ICIduj4ECjbil7B7pm9OnuTkmpwXu08XV2mpg8g==",
"requires": {}
},
+ "react-native-localize": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/react-native-localize/-/react-native-localize-3.0.2.tgz",
+ "integrity": "sha512-/l/oE1LVNgIRRhLbhmfFMHiWV0xhUn0A0iz1ytLVRYywL7FTp8Rx2vkJS/q/RpExDvV7yLw2493XZBYIM1dnLQ==",
+ "requires": {}
+ },
"react-native-location": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/react-native-location/-/react-native-location-2.5.0.tgz",
diff --git a/package.json b/package.json
index 4f9b5b74..7540eab9 100644
--- a/package.json
+++ b/package.json
@@ -64,6 +64,7 @@
"react-native-gesture-handler": "~2.9.0",
"react-native-keychain": "^8.0.0",
"react-native-linear-gradient": "^2.8.0",
+ "react-native-localize": "^3.0.2",
"react-native-location": "^2.5.0",
"react-native-mmkv-storage": "^0.9.1",
"react-native-permissions": "^3.8.0",
diff --git a/screens/Settings/AboutInji.tsx b/screens/Settings/AboutInji.tsx
index 7bff8f1e..9de78356 100644
--- a/screens/Settings/AboutInji.tsx
+++ b/screens/Settings/AboutInji.tsx
@@ -10,6 +10,8 @@ import getAllConfigurations from '../../shared/commonprops/commonProps';
import {getVersion} from 'react-native-device-info';
import {CopyButton} from '../../components/CopyButton';
import testIDProps from '../../shared/commonUtil';
+import { __InjiVersion, __TuvaliVersion } from '../../shared/GlobalVariables';
+
export const AboutInji: React.FC = ({appId}) => {
const {t} = useTranslation('AboutInji');
@@ -23,22 +25,6 @@ export const AboutInji: React.FC = ({appId}) => {
});
}, []);
- const dependencies = require('../../package-lock.json').dependencies;
- let packageVersion, packageCommitId;
-
- Object.keys(dependencies).forEach(dependencyName => {
- const dependencyData = dependencies[dependencyName];
-
- if (dependencyName == 'react-native-tuvali') {
- packageVersion = dependencyData.from
- ? dependencyData.from.split('#')[1]
- : 'unknown';
- if (packageVersion != 'unknown') {
- packageCommitId = dependencyData.version.split('#')[1].substring(0, 7);
- }
- }
- });
-
return (
= ({appId}) => {
- {t('version')}: {getVersion()}
+ {t('version')}: {__InjiVersion.getValue()}
- {packageVersion != 'unknown' && (
+ {__TuvaliVersion.getpackageVersion() != 'unknown' && (
- {t('tuvaliVersion')}: {packageVersion + '-' + packageCommitId}
+ {t('tuvaliVersion')}: {__TuvaliVersion.getValue()}
)}
diff --git a/screens/Settings/AppMetaData.tsx b/screens/Settings/AppMetaData.tsx
index 15bcf82b..7ad34639 100644
--- a/screens/Settings/AppMetaData.tsx
+++ b/screens/Settings/AppMetaData.tsx
@@ -7,28 +7,12 @@ import { Divider, Icon, ListItem, Overlay } from 'react-native-elements';
import { Button, Text, Row } from '../../components/ui';
import { Theme } from '../../components/ui/styleUtils';
import appMetaData from '../../AppMetaData.md';
-import { getVersion } from 'react-native-device-info';
+import { __InjiVersion, __TuvaliVersion } from '../../shared/GlobalVariables';
export const AppMetaData: React.FC = (props) => {
const { t } = useTranslation('AppMetaData');
const [isViewing, setIsViewing] = useState(false);
- const dependencies = require('../../package-lock.json').dependencies;
- let packageVersion, packageCommitId;
-
- Object.keys(dependencies).forEach((dependencyName) => {
- const dependencyData = dependencies[dependencyName];
-
- if (dependencyName == 'react-native-tuvali') {
- packageVersion = dependencyData.from
- ? dependencyData.from.split('#')[1]
- : 'unknown';
- if (packageVersion != 'unknown') {
- packageCommitId = dependencyData.version.split('#')[1].substring(0, 7);
- }
- }
- });
-
const markdownStyles = {
text: {
fontSize: 18,
@@ -88,17 +72,16 @@ export const AppMetaData: React.FC = (props) => {
align="center"
size="small"
color={Theme.Colors.version}>
- {t('version')}: {getVersion()}
+ {t('version')}: {__InjiVersion.getValue()}
- {packageVersion != 'unknown' && (
+ {__TuvaliVersion.getpackageVersion() != 'unknown' && (
- {t('Tuvali-version')}:{' '}
- {packageVersion + '-' + packageCommitId}
+ {t('Tuvali-version')}: {__TuvaliVersion.getValue()}
)}
diff --git a/screens/SetupLanguageScreen.tsx b/screens/SetupLanguageScreen.tsx
index ab2fb500..3e26983e 100644
--- a/screens/SetupLanguageScreen.tsx
+++ b/screens/SetupLanguageScreen.tsx
@@ -11,6 +11,7 @@ import {Theme} from '../components/ui/styleUtils';
import {Icon} from 'react-native-elements';
import {RootRouteProps} from '../routes';
import {useWelcomeScreen} from './WelcomeScreenController';
+import { __SelectedLanguage } from '../shared/GlobalVariables';
export const SetupLanguageScreen: React.FC = props => {
const {t} = useTranslation('SetupLanguage');
@@ -22,6 +23,7 @@ export const SetupLanguageScreen: React.FC = props => {
const changeLanguage = async (language: string) => {
if (language !== i18n.language) {
await i18n.changeLanguage(language).then(async () => {
+ __SelectedLanguage.setValue(language);
await Storage.setItem('language', i18n.language);
const isRTL = i18next.dir(language) === 'rtl' ? true : false;
if (isRTL !== I18nManager.isRTL) {
diff --git a/shared/GlobalVariables.ts b/shared/GlobalVariables.ts
new file mode 100644
index 00000000..778d03ef
--- /dev/null
+++ b/shared/GlobalVariables.ts
@@ -0,0 +1,83 @@
+import { getVersion } from 'react-native-device-info';
+import ShortUniqueId from 'short-unique-id';
+import { APP_ID_LENGTH } from './constants';
+/* eslint-disable @typescript-eslint/no-var-requires */
+const dependencies = require('../package-lock.json').dependencies;
+
+function getTuvaliPackageDetails() {
+ let packageVersion, packageCommitId;
+
+ Object.keys(dependencies).forEach((dependencyName) => {
+ const dependencyData = dependencies[dependencyName];
+
+ if (dependencyName == 'react-native-tuvali') {
+ packageVersion = dependencyData.from
+ ? dependencyData.from.split('#')[1]
+ : 'unknown';
+
+ if (packageVersion != 'unknown') {
+ packageCommitId = dependencyData.version.split('#')[1].substring(0, 7);
+ }
+ }
+ });
+ return { packageVersion, packageCommitId };
+}
+export class __AppId {
+ private static value: string;
+
+ public static getValue(): string {
+ return __AppId.value;
+ }
+
+ public static setValue(value: string) {
+ this.value = value;
+ }
+}
+export class __TuvaliVersion {
+ private static packageDetails = getTuvaliPackageDetails();
+
+ public static getPackageCommitId(): string {
+ return __TuvaliVersion.packageDetails.packageCommitId;
+ }
+
+ public static getpackageVersion(): string {
+ return __TuvaliVersion.packageDetails.packageVersion;
+ }
+
+ public static getValue(): string {
+ return this.getpackageVersion() + '-' + this.getPackageCommitId();
+ }
+}
+export class __InjiVersion {
+ private static value = getVersion();
+
+ public static getValue(): string {
+ return __InjiVersion.value;
+ }
+}
+export class __SessionId {
+ private static value = generateSessionId();
+
+ public static getValue(): string {
+ return __SessionId.value;
+ }
+}
+
+export class __SelectedLanguage {
+ private static language = '';
+
+ public static getValue(): string {
+ return __SelectedLanguage.language;
+ }
+
+ public static setValue(currentLangauge: string) {
+ this.language = currentLangauge;
+ }
+}
+
+function generateSessionId() {
+ const shortUUID = new ShortUniqueId({
+ length: APP_ID_LENGTH,
+ });
+ return shortUUID.randomUUID() + Date.now();
+}
diff --git a/shared/request.ts b/shared/request.ts
index 9cfa8da8..a043dbe9 100644
--- a/shared/request.ts
+++ b/shared/request.ts
@@ -1,5 +1,6 @@
import { DecodedCredential, VerifiableCredential } from '../types/vc';
-import { MIMOTO_BASE_URL } from './constants';
+import { __AppId } from './GlobalVariables';
+import { HOST, MIMOTO_BASE_URL } from './constants';
export class BackendResponseError extends Error {
constructor(name: string, message: string) {
@@ -8,18 +9,6 @@ export class BackendResponseError extends Error {
}
}
-export class AppId {
- private static value: string;
-
- public static getValue(): string {
- return AppId.value;
- }
-
- public static setValue(value: string) {
- this.value = value;
- }
-}
-
export async function request(
method: 'GET' | 'POST' | 'PATCH',
path: `/${string}`,
@@ -29,7 +18,8 @@ export async function request(
const headers = {
'Content-Type': 'application/json',
};
- if (path.includes('residentmobileapp')) headers['X-AppId'] = AppId.getValue();
+ if (path.includes('residentmobileapp'))
+ headers['X-AppId'] = __AppId.getValue();
const response = await fetch(host + path, {
method,
diff --git a/shared/telemetry/TelemetryUtils.js b/shared/telemetry/TelemetryUtils.js
new file mode 100644
index 00000000..9dbb8716
--- /dev/null
+++ b/shared/telemetry/TelemetryUtils.js
@@ -0,0 +1,80 @@
+import telemetry from '@project-sunbird/telemetry-sdk';
+import {Platform} from 'react-native';
+import {HOST} from '../constants';
+import {
+ __AppId,
+ __InjiVersion,
+ __SelectedLanguage,
+ __SessionId,
+ __TuvaliVersion,
+} from '../GlobalVariables';
+import {OBSRV_HOST} from 'react-native-dotenv';
+import DeviceInfo from 'react-native-device-info';
+import {isCustomSecureKeystore} from '../cryptoutil/cryptoUtil';
+import * as RNLocalize from 'react-native-localize';
+
+export function sendImpressionEvent(data) {
+ telemetry.impression(data, {});
+}
+
+export function sendEndEvent(data) {
+ telemetry.end(data, {});
+}
+
+export function initializeTelemetry(config) {
+ telemetry.initialize(config);
+}
+
+export function sendStartEvent(data) {
+ telemetry.start({}, '', '', data, {});
+}
+
+export function sendAppInfoEvent(data) {
+ telemetry.appinfo(data);
+}
+
+export function getTelemetryConfigData() {
+ return {
+ authtoken: '',
+ appid: __AppId.getValue(),
+ sid: __SessionId.getValue(),
+ batchsize: 5,
+ host: OBSRV_HOST,
+ endpoint: '/obsrv/v1/data/mosip-dataset',
+ telemetryDebugEnabled: true,
+ enableValidation: true,
+ schemaBaseUrl: 'http://mosip.io/telemetry/',
+ };
+}
+
+export function getData(type) {
+ return {
+ type: type,
+ };
+}
+
+export function getEndData(type) {
+ return {
+ type: type,
+ status: 'SUCCESS',
+ };
+}
+
+export function getAppInfoData() {
+ return {
+ env: HOST,
+ brandName: DeviceInfo.getBrand(),
+ modelName: DeviceInfo.getModel(),
+ osName: DeviceInfo.getSystemName(),
+ osVersion: DeviceInfo.getSystemVersion(),
+ osApiLevel: Platform.Version.toString(),
+ isHardwareKeystoreSupported: isCustomSecureKeystore(),
+ dateTime: new Date().getTime(),
+ zone: RNLocalize.getTimeZone(),
+ offset: new Date().getTimezoneOffset() * 60 * 1000,
+ preferredLanguage: __SelectedLanguage.getValue(),
+ buildNumber: DeviceInfo.getBuildNumber(),
+ injiVersion: __InjiVersion.getValue(),
+ tuvaliVersion: __TuvaliVersion.getValue(),
+ };
+}
diff --git a/types/react-native-dotenv/index.d.ts b/types/react-native-dotenv/index.d.ts
index 6b452f34..3aed7591 100644
--- a/types/react-native-dotenv/index.d.ts
+++ b/types/react-native-dotenv/index.d.ts
@@ -9,6 +9,11 @@ declare module 'react-native-dotenv' {
*/
export const ESIGNET_HOST: string;
+ /**
+ * URL for the obsrv server for telemetry
+ */
+ export const OBSRV_HOST: string;
+
/**
* API key to use Google Nearby Messages API
*/