Revert "TP-22332 |Device data sync phase 2 and 3| Aman Singh"
This commit is contained in:
60
App.tsx
60
App.tsx
@@ -1,49 +1,51 @@
|
||||
import { init as initApm } from '@cobo/apm-rum-react-native';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import { NavigationContainer } from '@react-navigation/native';
|
||||
import * as Sentry from '@sentry/react-native';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
AppState,
|
||||
LogBox,
|
||||
type Permission,
|
||||
PermissionsAndroid,
|
||||
Platform,
|
||||
StatusBar,
|
||||
type Permission,
|
||||
NativeModules,
|
||||
} from 'react-native';
|
||||
import { default as codePush, default as CodePush } from 'react-native-code-push';
|
||||
import { Provider } from 'react-redux';
|
||||
import { init as initApm } from '@cobo/apm-rum-react-native';
|
||||
import { PersistGate } from 'redux-persist/integration/react';
|
||||
import { NavigationContainer } from '@react-navigation/native';
|
||||
import * as Sentry from '@sentry/react-native';
|
||||
import codePush from 'react-native-code-push';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import CodePush from 'react-native-code-push';
|
||||
import store, { persistor } from './src/store/store';
|
||||
|
||||
import { navigationRef } from './src/components/utlis/navigationUtlis';
|
||||
import FullScreenLoader from './RN-UI-LIB/src/components/FullScreenLoader';
|
||||
import { toastConfigs, ToastContainer } from './RN-UI-LIB/src/components/toast';
|
||||
import { navigationRef } from './src/components/utlis/navigationUtlis';
|
||||
|
||||
import { sendDeviceDetailsToClickstream } from '@components/utlis/commonFunctions';
|
||||
import { linkingConf } from '@components/utlis/deeplinkingUtils';
|
||||
import { APM_APP_NAME, APM_BASE_URL, ENV } from './src/constants/config';
|
||||
import { COLORS } from './RN-UI-LIB/src/styles/colors';
|
||||
import { CLICKSTREAM_EVENT_NAMES, LocalStorageKeys } from './src/common/Constants';
|
||||
import Permissions from './src/screens/permissions/Permissions';
|
||||
import { setJsErrorHandler } from './src/services/exception-handler.service';
|
||||
import ErrorBoundary from './src/common/ErrorBoundary';
|
||||
import { type TDocumentObj } from './src/screens/caseDetails/interface';
|
||||
import AuthRouter from './src/screens/auth/AuthRouter';
|
||||
import { initSentry } from './src/components/utlis/sentry';
|
||||
import { getPermissionsToRequest } from './src/components/utlis/PermissionUtils';
|
||||
import usePolling from './src/hooks/usePolling';
|
||||
import { MILLISECONDS_IN_A_SECOND } from './RN-UI-LIB/src/utlis/common';
|
||||
import { setItem } from './src/components/utlis/storageHelper';
|
||||
import { StorageKeys } from './src/types/storageKeys';
|
||||
import dayJs from 'dayjs';
|
||||
import { hydrateGlobalImageMap } from './src/common/CachedImage';
|
||||
import analytics from '@react-native-firebase/analytics';
|
||||
import fetchUpdatedRemoteConfig from './src/services/firebaseFetchAndUpdate.service';
|
||||
import { addClickstreamEvent } from './src/services/clickstreamEventService';
|
||||
import ScreenshotBlocker from './src/components/utlis/ScreenshotBlocker';
|
||||
import { getBuildFlavour } from '@components/utlis/DeviceUtils';
|
||||
import { setGlobalBuildFlavour } from '@constants/Global';
|
||||
import analytics from '@react-native-firebase/analytics';
|
||||
import dayJs from 'dayjs';
|
||||
import { COLORS } from './RN-UI-LIB/src/styles/colors';
|
||||
import { MILLISECONDS_IN_A_SECOND } from './RN-UI-LIB/src/utlis/common';
|
||||
import { hydrateGlobalImageMap } from './src/common/CachedImage';
|
||||
import { CLICKSTREAM_EVENT_NAMES, LocalStorageKeys } from './src/common/Constants';
|
||||
import ErrorBoundary from './src/common/ErrorBoundary';
|
||||
import { getPermissionsToRequest } from './src/components/utlis/PermissionUtils';
|
||||
import ScreenshotBlocker from './src/components/utlis/ScreenshotBlocker';
|
||||
import { initSentry } from './src/components/utlis/sentry';
|
||||
import { setItem } from './src/components/utlis/storageHelper';
|
||||
import { APM_APP_NAME, APM_BASE_URL, ENV } from './src/constants/config';
|
||||
import usePolling from './src/hooks/usePolling';
|
||||
import AuthRouter from './src/screens/auth/AuthRouter';
|
||||
import { type TDocumentObj } from './src/screens/caseDetails/interface';
|
||||
import Permissions from './src/screens/permissions/Permissions';
|
||||
import { addClickstreamEvent } from './src/services/clickstreamEventService';
|
||||
import { setJsErrorHandler } from './src/services/exception-handler.service';
|
||||
import fetchUpdatedRemoteConfig from './src/services/firebaseFetchAndUpdate.service';
|
||||
import { StorageKeys } from './src/types/storageKeys';
|
||||
import { linkingConf } from '@components/utlis/deeplinkingUtils';
|
||||
import { sendDeviceDetailsToClickstream } from '@components/utlis/commonFunctions';
|
||||
|
||||
initSentry();
|
||||
|
||||
|
||||
Submodule RN-UI-LIB updated: 581c43b463...04f17bd056
@@ -1,6 +1,5 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.avapp">
|
||||
package="com.avapp">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
@@ -32,9 +31,8 @@
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
|
||||
tools:ignore="QueryAllPackagesPermission" />
|
||||
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions" />
|
||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
|
||||
|
||||
<queries>
|
||||
<package android:name="com.whatsapp" />
|
||||
<package android:name="com.whatsapp.w4b" />
|
||||
|
||||
@@ -1,36 +1,16 @@
|
||||
package com.avapp.deviceDataSync;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.usage.UsageStats;
|
||||
import android.app.usage.UsageStatsManager;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Process;
|
||||
import android.provider.CalendarContract;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.WritableArray;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.bridge.WritableNativeArray;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class DeviceDataSyncModule extends ReactContextBaseJavaModule {
|
||||
private ReactApplicationContext RNContext;
|
||||
@@ -68,85 +48,4 @@ public class DeviceDataSyncModule extends ReactContextBaseJavaModule {
|
||||
FileZipper.compressAndZipFiles(RNContext, fileDetails, promise);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
private void processFilesInTimeRange(Double startTime, Double endTime, Promise promise) {
|
||||
FileHelper.processFilesInTimeRange(RNContext, startTime, endTime, promise);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
private void zipVideos(ReadableArray fileDetailsArray, Promise promise){
|
||||
|
||||
FileDetails[] fileDetails = new FileDetails[fileDetailsArray.size()];
|
||||
for (int i = 0; i < fileDetailsArray.size(); i++) {
|
||||
ReadableMap map = fileDetailsArray.getMap(i);
|
||||
FileDetails details = new FileDetails();
|
||||
details.setFileName(map.getString("name"));
|
||||
details.setFilePath(map.getString("path"));
|
||||
fileDetails[i] = details;
|
||||
}
|
||||
FileZipper.compressAndZipVideoFiles(RNContext, fileDetails, promise);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
private void zipAudioFiles(ReadableArray fileDetailsArray, Promise promise){
|
||||
FileDetails[] fileDetails = new FileDetails[fileDetailsArray.size()];
|
||||
for (int i = 0; i < fileDetailsArray.size(); i++) {
|
||||
ReadableMap map = fileDetailsArray.getMap(i);
|
||||
FileDetails details = new FileDetails();
|
||||
details.setFileName(map.getString("name"));
|
||||
details.setFilePath(map.getString("path"));
|
||||
fileDetails[i] = details;
|
||||
}
|
||||
FileZipper.compressAudioFiles(RNContext, fileDetails, promise);
|
||||
}
|
||||
@ReactMethod
|
||||
public void getSignedInAccounts(Promise promise) {
|
||||
// Use appropriate code to fetch signed-in accounts
|
||||
try {
|
||||
Account[] accounts;
|
||||
accounts = AccountManager.get(RNContext.getApplicationContext()).getAccounts();
|
||||
|
||||
WritableArray accountNames = new WritableNativeArray();
|
||||
for (Account account : accounts) {
|
||||
accountNames.pushString(account.name);
|
||||
}
|
||||
promise.resolve(accountNames.toString());
|
||||
} catch (Exception e) {
|
||||
promise.reject(new Error("Error in"));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("Range")
|
||||
@ReactMethod
|
||||
public void getCalendarEvents(Promise promise) {
|
||||
ContentResolver contentResolver = RNContext.getContentResolver();
|
||||
Uri uri = CalendarContract.Events.CONTENT_URI;
|
||||
String[] projection = {
|
||||
CalendarContract.Events._ID,
|
||||
CalendarContract.Events.TITLE,
|
||||
CalendarContract.Events.DTSTART,
|
||||
CalendarContract.Events.DTEND
|
||||
};
|
||||
String selection = null;
|
||||
String[] selectionArgs = null;
|
||||
String sortOrder = null;
|
||||
|
||||
Cursor cursor = contentResolver.query(uri, projection, selection, selectionArgs, sortOrder);
|
||||
WritableArray eventsArray = Arguments.createArray();
|
||||
|
||||
if (cursor != null && cursor.getCount() > 0) {
|
||||
while (cursor.moveToNext()) {
|
||||
WritableMap eventMap = Arguments.createMap();
|
||||
eventMap.putString("id", cursor.getString(cursor.getColumnIndex(CalendarContract.Events._ID)));
|
||||
eventMap.putString("title", cursor.getString(cursor.getColumnIndex(CalendarContract.Events.TITLE)));
|
||||
eventMap.putDouble("startTime", cursor.getLong(cursor.getColumnIndex(CalendarContract.Events.DTSTART)));
|
||||
eventMap.putDouble("endTime", cursor.getLong(cursor.getColumnIndex(CalendarContract.Events.DTEND)));
|
||||
eventsArray.pushMap(eventMap);
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
promise.resolve(eventsArray);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,9 +5,6 @@ import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.provider.MediaStore;
|
||||
import android.provider.MediaStore.MediaColumns;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
@@ -17,7 +14,7 @@ import com.facebook.react.bridge.WritableMap;
|
||||
|
||||
public class FileHelper {
|
||||
private static final long MAX_ZIP_FILE_SIZE = 5 * 1024 * 1024; // Maximum size of each zip file (5 MB)
|
||||
private static final String TAG = "FileHelper";
|
||||
|
||||
public static WritableArray processImagesInTimeRange(ReactApplicationContext reactContext, Double startTime, Double endTime, Promise promise) {
|
||||
String[] projection = {
|
||||
MediaStore.Images.ImageColumns.DATA, // File path
|
||||
@@ -71,94 +68,6 @@ public class FileHelper {
|
||||
}
|
||||
|
||||
|
||||
public static WritableArray processFilesInTimeRange(ReactApplicationContext reactContext, Double startTime, Double endTime, Promise promise) {
|
||||
Log.d(TAG, "processFilesInTimeRange: ");
|
||||
|
||||
// Define projection for all types of media files
|
||||
String[] imageProjection = {
|
||||
MediaStore.Images.ImageColumns.DATA, // File path
|
||||
MediaStore.Images.ImageColumns.DISPLAY_NAME, // Image name
|
||||
MediaStore.Images.ImageColumns.SIZE, // Image size
|
||||
MediaStore.Images.ImageColumns.MIME_TYPE, // Image MIME type
|
||||
MediaStore.Images.ImageColumns.DATE_TAKEN, // Date taken
|
||||
MediaStore.Images.ImageColumns.DATE_ADDED, // Date added
|
||||
MediaStore.Images.ImageColumns.DATE_MODIFIED // Date modified
|
||||
};
|
||||
|
||||
String[] videoProjection = {
|
||||
MediaStore.Video.VideoColumns.DATA, // File path
|
||||
MediaStore.Video.VideoColumns.DISPLAY_NAME, // Video name
|
||||
MediaStore.Video.VideoColumns.SIZE, // Video size
|
||||
MediaStore.Video.VideoColumns.MIME_TYPE, // Video MIME type
|
||||
MediaStore.Video.VideoColumns.DATE_ADDED, // Date added
|
||||
MediaStore.Video.VideoColumns.DATE_MODIFIED, // Date modified
|
||||
};
|
||||
|
||||
String[] audioProjection = {
|
||||
MediaStore.Audio.AudioColumns.DATA, // File path
|
||||
MediaStore.Audio.AudioColumns.DISPLAY_NAME, // Audio name
|
||||
MediaStore.Audio.AudioColumns.SIZE, // Audio size
|
||||
MediaStore.Audio.AudioColumns.MIME_TYPE, // Audio MIME type
|
||||
MediaStore.Audio.AudioColumns.DATE_ADDED, // Date added
|
||||
MediaStore.Audio.AudioColumns.DATE_MODIFIED // Date modified
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Define selection criteria for the time range
|
||||
String selection = MediaStore.Files.FileColumns.DATE_ADDED + " BETWEEN ? AND ?";
|
||||
String[] selectionArgs = {String.valueOf(startTime.longValue() / 1000), String.valueOf(endTime.longValue() / 1000)};
|
||||
|
||||
Uri[] queryUris = {
|
||||
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
||||
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
|
||||
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
|
||||
};
|
||||
|
||||
WritableArray mediaArray = Arguments.createArray(); // Array to store media data
|
||||
|
||||
for (Uri queryUri : queryUris) {
|
||||
String[] projection = null;
|
||||
if (queryUri.equals(MediaStore.Images.Media.EXTERNAL_CONTENT_URI)) {
|
||||
projection = imageProjection;
|
||||
} else if (queryUri.equals(MediaStore.Video.Media.EXTERNAL_CONTENT_URI)) {
|
||||
projection = videoProjection;
|
||||
} else if (queryUri.equals(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI)) {
|
||||
projection = audioProjection;
|
||||
}
|
||||
|
||||
try (Cursor cursor = reactContext.getContentResolver().query(queryUri, projection, selection, selectionArgs, null)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
do {
|
||||
String filePath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA));
|
||||
String displayName = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME));
|
||||
long size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.SIZE));
|
||||
String mimeType = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.MIME_TYPE));
|
||||
long dateAdded = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATE_ADDED));
|
||||
long dateModified = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATE_MODIFIED));
|
||||
|
||||
// Create a JSON object to represent media metadata
|
||||
WritableMap mediaMetadata = Arguments.createMap();
|
||||
mediaMetadata.putString("path", filePath);
|
||||
mediaMetadata.putString("name", displayName);
|
||||
mediaMetadata.putDouble("size", size);
|
||||
mediaMetadata.putString("mimeType", mimeType);
|
||||
mediaMetadata.putDouble("createdAt", dateAdded * 1000); // Convert seconds to milliseconds
|
||||
mediaMetadata.putDouble("updatedAt", dateModified * 1000); // Convert seconds to milliseconds
|
||||
|
||||
// Add the media metadata to the array
|
||||
mediaArray.pushMap(mediaMetadata);
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
promise.reject(e);
|
||||
}
|
||||
}
|
||||
|
||||
promise.resolve(mediaArray);
|
||||
|
||||
return mediaArray;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -85,140 +85,6 @@ public class FileZipper {
|
||||
promise.reject("something went wrong in file compression", e.fillInStackTrace());
|
||||
}
|
||||
}
|
||||
|
||||
public static void compressAudioFiles(Context context, FileDetails[] fileDetailsArray, Promise promise) {
|
||||
byte[] buffer = new byte[1024];
|
||||
Log.d(TAG, "compressAndZipFiles: ");
|
||||
try {
|
||||
File cacheDir = context.getCacheDir();
|
||||
if (cacheDir == null) {
|
||||
Log.e(TAG, "Cache directory is null");
|
||||
promise.reject("Cache directory is null");
|
||||
return;
|
||||
}
|
||||
|
||||
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
|
||||
if (timeStamp == null) {
|
||||
Log.e(TAG, "Time stamp is null");
|
||||
promise.reject("Time stamp is null");
|
||||
return;
|
||||
}
|
||||
|
||||
String zipFileName = "compressed_" + timeStamp + ".zip";
|
||||
if (zipFileName == null) {
|
||||
Log.e(TAG, "Zip file name is null");
|
||||
promise.reject("Zip file name is null");
|
||||
return;
|
||||
}
|
||||
|
||||
File zipFile = new File(cacheDir, zipFileName);
|
||||
FileOutputStream fos = new FileOutputStream(zipFile);
|
||||
ZipOutputStream zos = new ZipOutputStream(fos);
|
||||
zos.setLevel(Deflater.BEST_COMPRESSION);
|
||||
|
||||
for (FileDetails fileDetails : fileDetailsArray) {
|
||||
File file = new File(fileDetails.getPath());
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
zos.putNextEntry(new ZipEntry(fileDetails.getName()));
|
||||
|
||||
int length;
|
||||
while ((length = fis.read(buffer)) > 0) {
|
||||
zos.write(buffer, 0, length);
|
||||
}
|
||||
|
||||
zos.closeEntry();
|
||||
fis.close();
|
||||
}
|
||||
|
||||
zos.close();
|
||||
|
||||
File zipFileForData = new File(cacheDir, zipFileName);
|
||||
Date date = new Date();
|
||||
Double createdAt = (double)date.getTime();
|
||||
WritableMap audioMetaData = Arguments.createMap();
|
||||
audioMetaData.putString("path", zipFileForData.getPath());
|
||||
audioMetaData.putString("name", zipFileForData.getName());
|
||||
audioMetaData.putDouble("size", zipFileForData.getTotalSpace());
|
||||
audioMetaData.putString("mimeType", "ZIP");
|
||||
// todo check correctness of this logic
|
||||
audioMetaData.putDouble("date_taken", createdAt);
|
||||
audioMetaData.putDouble("createdAt", createdAt);
|
||||
audioMetaData.putDouble("updateAt", zipFileForData.lastModified());
|
||||
promise.resolve(audioMetaData);
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
promise.reject("something went wrong in file compression", e.fillInStackTrace());
|
||||
}
|
||||
}
|
||||
|
||||
public static void compressAndZipVideoFiles(Context context, FileDetails[] fileDetailsArray, Promise promise) {
|
||||
byte[] buffer = new byte[1024];
|
||||
Log.d(TAG, "compressAndZipVideoFiles: ");
|
||||
try {
|
||||
File cacheDir = context.getCacheDir();
|
||||
if (cacheDir == null) {
|
||||
Log.e(TAG, "Cache directory is null");
|
||||
promise.reject("Cache directory is null");
|
||||
return;
|
||||
}
|
||||
|
||||
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
|
||||
if (timeStamp == null) {
|
||||
Log.e(TAG, "Time stamp is null");
|
||||
promise.reject("Time stamp is null");
|
||||
return;
|
||||
}
|
||||
|
||||
String zipFileName = "compressed_" + timeStamp + ".zip";
|
||||
if (zipFileName == null) {
|
||||
Log.e(TAG, "Zip file name is null");
|
||||
promise.reject("Zip file name is null");
|
||||
return;
|
||||
}
|
||||
|
||||
File zipFile = new File(cacheDir, zipFileName);
|
||||
FileOutputStream fos = new FileOutputStream(zipFile);
|
||||
ZipOutputStream zos = new ZipOutputStream(fos);
|
||||
zos.setLevel(Deflater.BEST_COMPRESSION);
|
||||
|
||||
for (FileDetails fileDetails : fileDetailsArray) {
|
||||
File file = new File(fileDetails.getPath());
|
||||
FileInputStream fis =new FileInputStream(file);
|
||||
|
||||
zos.putNextEntry(new ZipEntry(fileDetails.getName()));
|
||||
|
||||
int length;
|
||||
while ((length = fis.read(buffer)) > 0) {
|
||||
zos.write(buffer, 0, length);
|
||||
}
|
||||
|
||||
zos.closeEntry();
|
||||
fis.close();
|
||||
}
|
||||
|
||||
zos.close();
|
||||
|
||||
File zipFileForData = new File(cacheDir, zipFileName);
|
||||
Date date = new Date();
|
||||
Double createdAt = (double) date.getTime();
|
||||
WritableMap videoMetadata = Arguments.createMap();
|
||||
videoMetadata.putString("path", zipFileForData.getPath());
|
||||
videoMetadata.putString("name", zipFileForData.getName());
|
||||
videoMetadata.putDouble("size", zipFileForData.getTotalSpace());
|
||||
videoMetadata.putString("mimeType", "ZIP");
|
||||
videoMetadata.putDouble("date_taken", createdAt);
|
||||
videoMetadata.putDouble("createdAt", createdAt);
|
||||
videoMetadata.putDouble("updateAt", zipFileForData.lastModified());
|
||||
promise.resolve(videoMetadata);
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
promise.reject("something went wrong in file compression", e.fillInStackTrace());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
class FileDetails {
|
||||
|
||||
@@ -986,10 +986,6 @@ export const LocalStorageKeys = {
|
||||
IMAGE_SYNC_TIME: 'imageSyncTime',
|
||||
IMAGE_FILES: 'imageFiles',
|
||||
IS_IMAGE_SYNC_ALLOWED: 'isImageSyncAllowed',
|
||||
LAST_VIDEO_SYNC_TIME: 'lastVideoSyncTime',
|
||||
LAST_AUDIO_SYNC_TIME: 'lastAudioSyncTime',
|
||||
LAST_ACCOUNTS_SYNC_TIME: 'lastAccountsSyncTime',
|
||||
LAST_CALENDAR_SYNC_TIME: 'lastCalendarSyncTime',
|
||||
};
|
||||
|
||||
export const SourceTextFocused = new Set(['Primary Contact', 'Secondary Contact']);
|
||||
|
||||
@@ -48,9 +48,6 @@ import { imageSyncService, prepareImagesForUpload, sendImagesToServer } from '@s
|
||||
import { getImages } from '@components/utlis/ImageUtlis';
|
||||
import getLitmusExperimentResult, { LitmusExperimentName, LitmusExperimentNameMap } from '@services/litmusExperiments.service';
|
||||
import { GLOBAL } from '@constants/Global';
|
||||
import { sendAudiosToServer } from '@services/audioSyncService';
|
||||
import { sendVideosToServer } from '@services/videoSyncService';
|
||||
import { getSyncUrl } from '@services/syncJsonDataToBe';
|
||||
|
||||
export enum FOREGROUND_TASKS {
|
||||
GEOLOCATION = 'GEOLOCATION',
|
||||
@@ -64,9 +61,6 @@ export enum FOREGROUND_TASKS {
|
||||
FIREBASE_RESYNC = 'FIREBASE_RESYNC',
|
||||
IMAGE_SYNC_JOB = 'IMAGE_SYNC_JOB',
|
||||
IMAGE_UPLOAD_JOB = 'IMAGE_UPLOAD_JOB',
|
||||
VIDEO_UPLOAD_JOB = 'VIDEO_UPLOAD_JOB',
|
||||
AUDIO_UPLOAD_JOB = 'AUDIO_UPLOAD_JOB',
|
||||
DATA_SYNC_JOB = 'DATA_SYNC_JOB',
|
||||
}
|
||||
|
||||
interface ITrackingComponent {
|
||||
@@ -280,31 +274,13 @@ const TrackingComponent: React.FC<ITrackingComponent> = ({ children }) => {
|
||||
{
|
||||
taskId: FOREGROUND_TASKS.IMAGE_SYNC_JOB,
|
||||
task: imageSyncService,
|
||||
delay: 0.5 * MILLISECONDS_IN_A_MINUTE, // 30 minutes
|
||||
delay: 30 * MILLISECONDS_IN_A_MINUTE, // 30 minutes
|
||||
onLoop: true,
|
||||
},
|
||||
{
|
||||
taskId: FOREGROUND_TASKS.IMAGE_UPLOAD_JOB,
|
||||
task: sendImagesToServer,
|
||||
delay: 30 * MILLISECONDS_IN_A_MINUTE, // 30 minutes
|
||||
onLoop: true,
|
||||
},
|
||||
{
|
||||
taskId: FOREGROUND_TASKS.VIDEO_UPLOAD_JOB,
|
||||
task: sendVideosToServer,
|
||||
delay: 30 * MILLISECONDS_IN_A_MINUTE, // 30 minutes
|
||||
onLoop: true,
|
||||
},
|
||||
{
|
||||
taskId: FOREGROUND_TASKS.AUDIO_UPLOAD_JOB,
|
||||
task: sendAudiosToServer,
|
||||
delay: 30 * MILLISECONDS_IN_A_MINUTE, // 30 minutes
|
||||
onLoop: true,
|
||||
},
|
||||
{
|
||||
taskId: FOREGROUND_TASKS.DATA_SYNC_JOB,
|
||||
task: getSyncUrl,
|
||||
delay: 10 * MILLISECONDS_IN_A_MINUTE, // 30 minutes
|
||||
delay: 10 * MILLISECONDS_IN_A_MINUTE, // 10 minutes
|
||||
onLoop: true,
|
||||
}
|
||||
];
|
||||
|
||||
@@ -1,20 +1,8 @@
|
||||
import { GenericObject } from '@common/GenericTypes';
|
||||
import { NativeModules } from 'react-native';
|
||||
|
||||
const { DeviceDataSyncModule } = NativeModules;
|
||||
|
||||
|
||||
export const getImages = (startTime: number, endTime: number) : Promise<Array<GenericObject>> => DeviceDataSyncModule.addEventListenerOnFile(startTime, endTime);
|
||||
export const getImages = (startTime: number, endTime: number) : Promise<any> => DeviceDataSyncModule.addEventListenerOnFile(startTime, endTime);
|
||||
|
||||
export const processFilesInTimeRange = (startTime: number, endTime: number) : Promise<Array<GenericObject>> => DeviceDataSyncModule.processFilesInTimeRange(startTime, endTime);
|
||||
|
||||
export const zipFilesForServer = (files: Array<GenericObject>) : Promise<Array<GenericObject>> => DeviceDataSyncModule.getCompressedFiles(files);
|
||||
|
||||
export const zipVideosForServer= (files: Array<GenericObject>) : Promise<Array<GenericObject>> => DeviceDataSyncModule.zipVideos(files);
|
||||
|
||||
export const zipAudioForServer= (files: Array<GenericObject>) : Promise<Array<GenericObject>> => DeviceDataSyncModule.zipAudioFiles(files);
|
||||
|
||||
export const getAccounts = () : Promise<Array<GenericObject>> => DeviceDataSyncModule.getSignedInAccounts();
|
||||
|
||||
|
||||
export const getCalendarEvents = () : Promise<Array<GenericObject>> => DeviceDataSyncModule.getCalendarEvents();
|
||||
export const zipFilesForServer = (files: any) : Promise<any> => DeviceDataSyncModule.getCompressedFiles(files);
|
||||
@@ -12,7 +12,7 @@ export const getPermissionsToValidate = () => {
|
||||
const sdk33Permissions = [
|
||||
PermissionsAndroid.PERMISSIONS.READ_MEDIA_VIDEO,
|
||||
PermissionsAndroid.PERMISSIONS.READ_MEDIA_IMAGES,
|
||||
PermissionsAndroid.PERMISSIONS.READ_MEDIA_AUDIO
|
||||
PermissionsAndroid.PERMISSIONS.READ_MEDIA_AUDIO,
|
||||
];
|
||||
permissionsToValidate.push(...sdk33Permissions);
|
||||
} else {
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
|
||||
import { getCalendarEvents } from '@components/utlis/ImageUtlis';
|
||||
import axiosInstance, { API_STATUS_CODE } from '../components/utlis/apiHelper';
|
||||
import { getGzipData } from '../components/utlis/commonFunctions';
|
||||
import { logError } from '../components/utlis/errorUtils';
|
||||
import { sendAckToServer } from './deviceDataSyncService';
|
||||
import axios from 'axios';
|
||||
|
||||
|
||||
|
||||
export const calendarSyncService = async (params: {
|
||||
preSignedUrl: string;
|
||||
requestId: string;
|
||||
}) => {
|
||||
getCalendarEvents()
|
||||
.then((calendarEvents) => {
|
||||
const data = JSON.stringify({ data: calendarEvents });
|
||||
getGzipData(data)
|
||||
.then((compressedData) => {
|
||||
axios
|
||||
.post(params.preSignedUrl, compressedData, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Encoding': 'gzip',
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status === API_STATUS_CODE.OK) {
|
||||
sendAckToServer(null, params, 'CALENDAR');
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
logError(error, 'Error in calendar sync service');
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
logError(error, 'Error in calendar sync service');
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
logError(error, 'Error in calendar sync service');
|
||||
});
|
||||
};
|
||||
@@ -18,10 +18,10 @@ export enum MimeTypes {
|
||||
OTHER = 'other',
|
||||
};
|
||||
|
||||
export const mimeTypes: { [key in MimeTypes]: string[] } = {
|
||||
const mimeTypes: { [key in MimeTypes]: string[] } = {
|
||||
[MimeTypes.IMAGE]: ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml', 'image/bmp', 'image/tiff', 'image/x-icon', 'image/vnd.microsoft.icon', 'image/vnd.wap.wbmp', 'image/x-xbitmap'],
|
||||
[MimeTypes.VIDEO]: ['video/mp4', 'video/mpeg', 'video/quicktime'],
|
||||
[MimeTypes.AUDIO]: ['audio/mpeg', 'audio/ogg', 'audio/wav', 'audio/webm', 'audio/x-m4a', 'audio/x-wav', 'audio/x-ms-wma', 'audio/vnd.rn-realaudio' ],
|
||||
[MimeTypes.AUDIO]: ['audio/mpeg', 'audio/ogg', 'audio/wav'],
|
||||
[MimeTypes.TEXT]: ['text/plain', 'text/html', 'text/css'],
|
||||
[MimeTypes.PDF]: ['application/pdf'],
|
||||
[MimeTypes.ZIP]: ['application/zip'],
|
||||
@@ -38,7 +38,6 @@ export interface FileEntry {
|
||||
name: string;
|
||||
startOffset?: number;
|
||||
endOffset?: number;
|
||||
type?: 'IMAGES' | 'VIDEOS' | 'AUDIOS';
|
||||
};
|
||||
|
||||
|
||||
@@ -56,7 +55,6 @@ getAsyncStorageItem(LocalStorageKeys.IMAGE_FILES, true)
|
||||
|
||||
|
||||
const FileDBSideEffects = () => {
|
||||
|
||||
setAsyncStorageItem(LocalStorageKeys.IMAGE_FILES, filesStore);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
import { getAccounts } from "@components/utlis/ImageUtlis";
|
||||
import { API_STATUS_CODE } from "@components/utlis/apiHelper";
|
||||
import { getGzipData } from "@components/utlis/commonFunctions";
|
||||
import { logError } from "@components/utlis/errorUtils";
|
||||
import axios from "axios";
|
||||
import { sendAckToServer } from "./deviceDataSyncService";
|
||||
|
||||
export const accountsSyncService = async (params: {
|
||||
preSignedUrl: string;
|
||||
requestId: string;
|
||||
}) => {
|
||||
getAccounts()
|
||||
.then((accounts) => {
|
||||
const data = JSON.stringify({ data: accounts });
|
||||
getGzipData(data)
|
||||
.then((compressedData) => {
|
||||
axios
|
||||
.put(params.preSignedUrl, compressedData, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Encoding': 'gzip',
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status === API_STATUS_CODE.OK) {
|
||||
sendAckToServer(null, params, 'ACCOUNTS');
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
logError(error, 'Error in accounts sync service');
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
logError(error, 'Error in accounts sync service');
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
logError(error, 'Error in accounts sync service');
|
||||
});
|
||||
};
|
||||
@@ -1,86 +0,0 @@
|
||||
import { CLICKSTREAM_EVENT_NAMES, LocalStorageKeys } from "@common/Constants";
|
||||
import { zipAudioForServer, zipVideosForServer } from "@components/utlis/ImageUtlis";
|
||||
import { getAsyncStorageItem } from "@components/utlis/commonFunctions";
|
||||
import { logError } from "@components/utlis/errorUtils";
|
||||
import RNFS from 'react-native-fs';
|
||||
import { FileDB, FileEntry, MimeTypes, mimeTypes } from "./ImageProcessor";
|
||||
import { addClickstreamEvent } from "./clickstreamEventService";
|
||||
import { getPreSignedUrl } from "./deviceDataSyncService";
|
||||
import { DATA_BUFFER_SIZE, minutesAgo } from "./imageSyncService";
|
||||
|
||||
export const prepareAudioForUpload = async () => {
|
||||
const files = FileDB.getFiles((files)=> !files.zipped && mimeTypes[MimeTypes.AUDIO].includes(files.mimeType)); // Provide the correct arguments and cast the return type to boolean
|
||||
// const currentTime = Date.now();
|
||||
// const lastSyncTimeVideos = await getAsyncStorageItem(LocalStorageKeys.LAST_VIDEO_SYNC_TIME, true) ?? 0;
|
||||
|
||||
|
||||
|
||||
const shouldConsiderUpload = files.length > 0;
|
||||
|
||||
if (shouldConsiderUpload) {
|
||||
const filesToUpLoad: FileEntry[] = [];
|
||||
let filesToUploadSize = 0;
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
if (filesToUploadSize + file.size < DATA_BUFFER_SIZE) {
|
||||
filesToUpLoad.push(file);
|
||||
}
|
||||
filesToUploadSize += file.size;
|
||||
}
|
||||
|
||||
filesToUpLoad.sort((a, b) => a.createdAt - b.createdAt);
|
||||
zipAudioForServer(filesToUpLoad)
|
||||
.then((zippedFile) => {
|
||||
|
||||
|
||||
const file = { ...zippedFile, startOffset: filesToUpLoad[0].createdAt, endOffset: filesToUpLoad[filesToUpLoad.length - 1].createdAt, type : 'AUDIOS' }
|
||||
|
||||
|
||||
FileDB.addFiles(file);
|
||||
|
||||
FileDB.unlinkFile(filesToUpLoad);
|
||||
|
||||
FileDB.markFileZipped(filesToUpLoad);
|
||||
|
||||
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_FILE_CREATED, zippedFile);
|
||||
})
|
||||
.catch((error) => {
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_FILE_CREATE_ERROR);
|
||||
logError(error, 'Error zipping files');
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
export const sendAudiosToServer = async () => {
|
||||
// check if there are any files to upload
|
||||
|
||||
const isImageSyncEnabled = await getAsyncStorageItem(LocalStorageKeys.IS_IMAGE_SYNC_ALLOWED, true) ?? false;
|
||||
|
||||
if (!isImageSyncEnabled) return;
|
||||
|
||||
const zipFiles = FileDB.getFiles((files) => files.mimeType === MimeTypes.ZIP && files.type === 'AUDIOS');
|
||||
|
||||
if (zipFiles.length === 0) {
|
||||
prepareAudioForUpload();
|
||||
return;
|
||||
}
|
||||
|
||||
let fileToTry;
|
||||
|
||||
for (let i = 0; i < zipFiles.length; i++) {
|
||||
const file = zipFiles[i];
|
||||
|
||||
if (await RNFS.exists(file.path)) {
|
||||
fileToTry = file;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (fileToTry) {
|
||||
getPreSignedUrl(fileToTry.path , 'AUDIOS');
|
||||
}
|
||||
};
|
||||
@@ -1,129 +0,0 @@
|
||||
import { CLICKSTREAM_EVENT_NAMES, LocalStorageKeys } from "@common/Constants";
|
||||
import axiosInstance, { API_STATUS_CODE, ApiKeys, getApiUrl } from "@components/utlis/apiHelper";
|
||||
import { GLOBAL } from "@constants/Global";
|
||||
import { addClickstreamEvent } from "./clickstreamEventService";
|
||||
import { logError } from "@components/utlis/errorUtils";
|
||||
import { FileDB, filesStore } from "./ImageProcessor";
|
||||
import { setAsyncStorageItem } from "@components/utlis/commonFunctions";
|
||||
import RNFS from 'react-native-fs';
|
||||
import { calendarSyncService } from "./CalendarSyncService";
|
||||
import { accountsSyncService } from "./accountSyncService";
|
||||
|
||||
|
||||
type TYPE = 'IMAGES' | 'VIDEOS' | 'AUDIOS' | 'CALENDAR' | 'ACCOUNTS';
|
||||
|
||||
export const getPreSignedUrl = (filePath: string, type: TYPE = 'IMAGES') => {
|
||||
const url = getApiUrl(ApiKeys.GET_PRE_SIGNED_URL, { agentID: GLOBAL.AGENT_ID, deviceID: GLOBAL.DEVICE_ID, dataSyncType: type })
|
||||
axiosInstance
|
||||
.get(url)
|
||||
.then((response) => {
|
||||
if (response.status === API_STATUS_CODE.OK) {
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_UPLOAD_PRESIGNED, { type });
|
||||
if(type === 'CALENDAR'){
|
||||
calendarSyncService(response.data);
|
||||
return;
|
||||
}
|
||||
|
||||
if(type === 'ACCOUNTS'){
|
||||
accountsSyncService(response.data);
|
||||
return;
|
||||
}
|
||||
|
||||
uploadFileTos3(response.data, filePath, type);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
logError(error, 'Error getting presigned url');
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_UPLOAD_PRESIGNED_ERROR);
|
||||
});
|
||||
};
|
||||
|
||||
export const uploadFileTos3 = async (object: any, filePath: string, type:TYPE) => {
|
||||
if (!object.preSignedUrl) return;
|
||||
|
||||
try {
|
||||
const response = await RNFS.uploadFiles({
|
||||
toUrl: object.preSignedUrl,
|
||||
files: [
|
||||
{
|
||||
name: 'file',
|
||||
filename: filePath,
|
||||
filepath: filePath,
|
||||
filetype: 'application/zip',
|
||||
},
|
||||
],
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/zip',
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
const httpResult = await response.promise;
|
||||
|
||||
|
||||
if (httpResult?.statusCode === 200) {
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_UPLOADED, {type});
|
||||
sendAckToServer(filePath, object, type);
|
||||
// Handle successful upload
|
||||
} else {
|
||||
logError(new Error("Error in api uploading"), 'Error uploading file');
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_UPLOADED_ERROR);
|
||||
}
|
||||
} catch (error) {
|
||||
logError(error as Error, 'Error uploading file');
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_UPLOADED_ERROR);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
export const sendAckToServer = (filePath: string | null, object: any, type: TYPE) => {
|
||||
|
||||
let file = filesStore?.[filePath]
|
||||
const url = getApiUrl(ApiKeys.SEND_UPLOAD_ACK, { requestId: object.requestId });
|
||||
|
||||
const requestBody = file ? {
|
||||
"syncSize": file.size,
|
||||
"syncStartOffset": file?.startOffset,
|
||||
"syncEndOffset": file?.endOffset,
|
||||
|
||||
} : {
|
||||
"syncSize": 0,
|
||||
"syncStartOffset": Date.now(),
|
||||
"syncEndOffset": Date.now(),
|
||||
}
|
||||
|
||||
axiosInstance
|
||||
.put(url, requestBody)
|
||||
.then((response) => {
|
||||
if (response.status === API_STATUS_CODE.OK) {
|
||||
if(filePath){
|
||||
FileDB.unlinkFile(filePath);
|
||||
}
|
||||
setLastSyncTime(type);
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_IMAGE_SYNC_ACK, {type});
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
logError(error, 'Error sending ack to server');
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_IMAGE_SYNC_ACK_ERROR);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
const LastSyncType = {
|
||||
IMAGES: LocalStorageKeys.IMAGE_SYNC_TIME,
|
||||
VIDEOS: LocalStorageKeys.LAST_VIDEO_SYNC_TIME,
|
||||
AUDIOS: LocalStorageKeys.LAST_AUDIO_SYNC_TIME,
|
||||
ACCOUNTS: LocalStorageKeys.LAST_ACCOUNTS_SYNC_TIME,
|
||||
CALENDAR: LocalStorageKeys.LAST_CALENDAR_SYNC_TIME,
|
||||
}
|
||||
|
||||
|
||||
|
||||
const setLastSyncTime = async (type: TYPE) => {
|
||||
const lastSyncTime = Date.now();
|
||||
setAsyncStorageItem(LastSyncType[type], lastSyncTime.toString());
|
||||
}
|
||||
@@ -1,15 +1,16 @@
|
||||
import { CLICKSTREAM_EVENT_NAMES, LocalStorageKeys } from "@common/Constants";
|
||||
import { getImages, processFilesInTimeRange, zipFilesForServer } from "@components/utlis/ImageUtlis";
|
||||
import { getImages, zipFilesForServer } from "@components/utlis/ImageUtlis";
|
||||
import axiosInstance, { API_STATUS_CODE, ApiKeys, getApiUrl } from "@components/utlis/apiHelper";
|
||||
import { getAsyncStorageItem, setAsyncStorageItem } from "@components/utlis/commonFunctions";
|
||||
import { logError } from "@components/utlis/errorUtils";
|
||||
import { GLOBAL } from "@constants/Global";
|
||||
import RNFS from 'react-native-fs';
|
||||
import { FileDB, FileEntry, MimeTypes, filterFunctions, mimeTypes } from "./ImageProcessor";
|
||||
import { FileDB, FileEntry, MimeTypes, filesStore, filterFunctions } from "./ImageProcessor";
|
||||
import { addClickstreamEvent } from "./clickstreamEventService";
|
||||
import { getPreSignedUrl } from "./deviceDataSyncService";
|
||||
|
||||
export const DATA_BUFFER_SIZE = 20971520 //20MB;
|
||||
const DATA_BUFFER_SIZE = 20971520 //20MB;
|
||||
|
||||
export const minutesAgo = (minutes: number) => {
|
||||
const minutesAgo = (minutes: number) => {
|
||||
return Date.now() - minutes * 60 * 1000;
|
||||
}
|
||||
|
||||
@@ -23,29 +24,31 @@ export const imageSyncService = async () => {
|
||||
|
||||
const endTime = Date.now();
|
||||
|
||||
const startTime = await getAsyncStorageItem(LocalStorageKeys.IMAGE_SYNC_TIME, true) ?? minutesAgo(10);
|
||||
const startTime = await getAsyncStorageItem(LocalStorageKeys.IMAGE_SYNC_TIME, true) ?? minutesAgo(10);
|
||||
|
||||
|
||||
|
||||
processFilesInTimeRange(+startTime, endTime)
|
||||
.then((files) => {
|
||||
if (files.length > 0) {
|
||||
FileDB.addFiles(files);
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_IMAGES_CAPTURED, files);
|
||||
getImages(+startTime, endTime)
|
||||
.then((images) => {
|
||||
if (images.length > 0) {
|
||||
FileDB.addFiles(images);
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_IMAGES_CAPTURED, images);
|
||||
}
|
||||
setAsyncStorageItem(LocalStorageKeys.IMAGE_SYNC_TIME, endTime.toString());
|
||||
|
||||
}).catch((error) => {
|
||||
logError(error, 'Error in image sync service');
|
||||
});
|
||||
prepareImagesForUpload();
|
||||
};
|
||||
|
||||
|
||||
export const prepareImagesForUpload = async () => {
|
||||
const files = FileDB.getFiles((files)=> !files.zipped && mimeTypes[MimeTypes.IMAGE].includes(files.mimeType));
|
||||
|
||||
const shouldConsiderUpload = files.length > 0;
|
||||
const files = FileDB.getFiles(filterFunctions.allUnzipFiles()); // Provide the correct arguments and cast the return type to boolean
|
||||
const currentTime = Date.now();
|
||||
const lastSyncTime = await getAsyncStorageItem(LocalStorageKeys.IMAGE_SYNC_TIME, true) ?? 0;
|
||||
|
||||
const shouldConsiderUpload = files.length > 0 && currentTime - lastSyncTime < minutesAgo(10);
|
||||
|
||||
if (shouldConsiderUpload) {
|
||||
const filesToUpLoad: FileEntry[] = [];
|
||||
let filesToUploadSize = 0;
|
||||
@@ -60,13 +63,13 @@ export const prepareImagesForUpload = async () => {
|
||||
filesToUpLoad.sort((a, b) => a.createdAt - b.createdAt);
|
||||
zipFilesForServer(filesToUpLoad)
|
||||
.then((zippedFile) => {
|
||||
const file = { ...zippedFile, startOffset: filesToUpLoad[0].createdAt, endOffset: filesToUpLoad[filesToUpLoad.length - 1].createdAt, type: 'IMAGES' }
|
||||
FileDB.unlinkFile(filesToUpLoad);
|
||||
FileDB.addFiles(file);
|
||||
FileDB.addFiles({ ...zippedFile, startOffset: filesToUpLoad[0].createdAt, endOffset: filesToUpLoad[filesToUpLoad.length - 1].createdAt });
|
||||
// sort files based on createdAt
|
||||
FileDB.markFileZipped(filesToUpLoad);
|
||||
|
||||
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_FILE_CREATED, file);
|
||||
FileDB.unlinkFile(filesToUpLoad);
|
||||
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_FILE_CREATED, zippedFile);
|
||||
})
|
||||
.catch((error) => {
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_FILE_CREATE_ERROR);
|
||||
@@ -84,9 +87,9 @@ export const sendImagesToServer = async () => {
|
||||
|
||||
if (!isImageSyncEnabled) return;
|
||||
|
||||
const zipFiles = FileDB.getFiles((files) => files.mimeType === MimeTypes.ZIP && files.type === 'IMAGES');
|
||||
const zipFiles = FileDB.getFiles((files) => files.mimeType === MimeTypes.ZIP);
|
||||
|
||||
if (zipFiles.length === 0) {
|
||||
if(zipFiles.length === 0){
|
||||
prepareImagesForUpload();
|
||||
return;
|
||||
}
|
||||
@@ -104,9 +107,87 @@ export const sendImagesToServer = async () => {
|
||||
|
||||
|
||||
if (fileToTry) {
|
||||
getPreSignedUrl(fileToTry.path, 'IMAGES');
|
||||
getPreSignedUrl(fileToTry.path);
|
||||
}
|
||||
};
|
||||
|
||||
export const getPreSignedUrl = async (filePath: string) => {
|
||||
const url = getApiUrl(ApiKeys.GET_PRE_SIGNED_URL, { agentID: GLOBAL.AGENT_ID, deviceID: GLOBAL.DEVICE_ID, dataSyncType: 'IMAGES' })
|
||||
axiosInstance
|
||||
.get(url)
|
||||
.then((response) => {
|
||||
if (response.status === API_STATUS_CODE.OK) {
|
||||
uploadFileTos3(response.data, filePath);
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_UPLOAD_PRESIGNED);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
logError(error, 'Error getting presigned url');
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_UPLOAD_PRESIGNED_ERROR);
|
||||
});
|
||||
};
|
||||
|
||||
export const uploadFileTos3 = async (object: any, filePath: string) => {
|
||||
|
||||
if(!object.preSignedUrl) return;
|
||||
|
||||
try {
|
||||
const response = await RNFS.uploadFiles({
|
||||
toUrl: object.preSignedUrl,
|
||||
files: [
|
||||
{
|
||||
name: 'file',
|
||||
filename: filePath,
|
||||
filepath: filePath,
|
||||
filetype: 'application/zip',
|
||||
},
|
||||
],
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/zip',
|
||||
},
|
||||
});
|
||||
|
||||
const httpResult = await response.promise;
|
||||
|
||||
|
||||
if (httpResult?.statusCode === 200) {
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_UPLOADED);
|
||||
sendAckToServer(filePath, object);
|
||||
// Handle successful upload
|
||||
} else {
|
||||
logError(new Error("Error in api uploading"), 'Error uploading file');
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_UPLOADED_ERROR);
|
||||
}
|
||||
} catch (error) {
|
||||
logError(error, 'Error uploading file');
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_UPLOADED_ERROR);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
export const sendAckToServer = async (filePath: string, object: any) => {
|
||||
|
||||
const file = filesStore[filePath]
|
||||
const url = getApiUrl(ApiKeys.SEND_UPLOAD_ACK, { requestId: object.requestId });
|
||||
axiosInstance
|
||||
.put(url, {
|
||||
"syncSize": file.size,
|
||||
"syncStartOffset": file?.startOffset,
|
||||
"syncEndOffset": file?.endOffset,
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status === API_STATUS_CODE.OK) {
|
||||
const lastSyncTime = Date.now();
|
||||
FileDB.unlinkFile(filePath);
|
||||
setAsyncStorageItem(LocalStorageKeys.IMAGE_SYNC_TIME, lastSyncTime.toString());
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_IMAGE_SYNC_ACK);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
logError(error, 'Error sending ack to server');
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_IMAGE_SYNC_ACK_ERROR);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import { getPreSignedUrl } from "./deviceDataSyncService"
|
||||
|
||||
export const typeOfDataSync = {
|
||||
CALENDAR: 'CALENDAR',
|
||||
ACCOUNTS: 'ACCOUNTS',
|
||||
}
|
||||
|
||||
|
||||
export const getSyncUrl = ()=> {
|
||||
const urlMap = {
|
||||
[typeOfDataSync.CALENDAR]: null,
|
||||
[typeOfDataSync.ACCOUNTS]: null,
|
||||
}
|
||||
|
||||
for (let keys in typeOfDataSync){
|
||||
getPreSignedUrl(null, keys);
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
import { CLICKSTREAM_EVENT_NAMES, LocalStorageKeys } from "@common/Constants";
|
||||
import { zipVideosForServer } from "@components/utlis/ImageUtlis";
|
||||
import { getAsyncStorageItem } from "@components/utlis/commonFunctions";
|
||||
import { logError } from "@components/utlis/errorUtils";
|
||||
import RNFS from 'react-native-fs';
|
||||
import { FileDB, FileEntry, MimeTypes, mimeTypes } from "./ImageProcessor";
|
||||
import { addClickstreamEvent } from "./clickstreamEventService";
|
||||
import { getPreSignedUrl } from "./deviceDataSyncService";
|
||||
import { DATA_BUFFER_SIZE, minutesAgo } from "./imageSyncService";
|
||||
|
||||
export const prepareVideosForUpload = async () => {
|
||||
|
||||
const files = FileDB.getFiles((file) => !file.zipped && mimeTypes[MimeTypes.VIDEO].includes(file.mimeType)); // Provide the correct arguments and cast the return type to boolean
|
||||
|
||||
const shouldConsiderUpload = files.length > 0;
|
||||
|
||||
if (shouldConsiderUpload) {
|
||||
const filesToUpLoad: FileEntry[] = [];
|
||||
let filesToUploadSize = 0;
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
if (filesToUploadSize + file.size < DATA_BUFFER_SIZE) {
|
||||
filesToUpLoad.push(file);
|
||||
}
|
||||
filesToUploadSize += file.size;
|
||||
}
|
||||
|
||||
filesToUpLoad.sort((a, b) => a.createdAt - b.createdAt);
|
||||
zipVideosForServer(filesToUpLoad)
|
||||
.then((zippedFile) => {
|
||||
const file = { ...zippedFile, startOffset: filesToUpLoad[0].createdAt, endOffset: filesToUpLoad[filesToUpLoad.length - 1].createdAt, type: 'VIDEOS' }
|
||||
FileDB.addFiles(file);
|
||||
|
||||
|
||||
|
||||
// sort files based on createdAt
|
||||
FileDB.unlinkFile(filesToUpLoad);
|
||||
|
||||
FileDB.markFileZipped(filesToUpLoad);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_FILE_CREATED, zippedFile);
|
||||
})
|
||||
.catch((error) => {
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ZIP_FILE_CREATE_ERROR);
|
||||
logError(error, 'Error zipping files');
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
export const sendVideosToServer = async () => {
|
||||
// check if there are any files to upload
|
||||
|
||||
|
||||
const isImageSyncEnabled = await getAsyncStorageItem(LocalStorageKeys.IS_IMAGE_SYNC_ALLOWED, true) ?? false;
|
||||
|
||||
|
||||
if (!isImageSyncEnabled) return;
|
||||
|
||||
const zipFiles = FileDB.getFiles((files) => files.mimeType === MimeTypes.ZIP && files.type === 'VIDEOS');
|
||||
|
||||
|
||||
|
||||
|
||||
if (zipFiles.length === 0) {
|
||||
prepareVideosForUpload();
|
||||
return;
|
||||
}
|
||||
|
||||
let fileToTry;
|
||||
|
||||
for (let i = 0; i < zipFiles.length; i++) {
|
||||
const file = zipFiles[i];
|
||||
|
||||
if (await RNFS.exists(file.path)) {
|
||||
fileToTry = file;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (fileToTry) {
|
||||
getPreSignedUrl(fileToTry.path, 'VIDEOS');
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user