101 lines
2.8 KiB
TypeScript
101 lines
2.8 KiB
TypeScript
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
import NetInfo from '@react-native-community/netinfo';
|
|
import Constants from 'expo-constants';
|
|
import * as Device from 'expo-device';
|
|
import { Platform } from 'react-native';
|
|
import { ConstEnv } from '@/constants/ConstEnv';
|
|
|
|
const QUEUE_KEY = 'error_log_queue';
|
|
const APP_NAME = 'desa-plus';
|
|
|
|
type ErrorPayload = {
|
|
affectedVersion: string;
|
|
device: string;
|
|
os: string;
|
|
description: string;
|
|
app: string;
|
|
source: 'SYSTEM';
|
|
stackTrace: string;
|
|
};
|
|
|
|
function buildPayload(description: string, stackTrace?: string): ErrorPayload {
|
|
const platformName = Platform.OS === 'ios' ? 'iOS' : 'Android';
|
|
return {
|
|
affectedVersion: Constants.expoConfig?.version ?? 'unknown',
|
|
device: Device.modelName ?? 'unknown',
|
|
os: `${platformName} ${Device.osVersion ?? ''}`.trim(),
|
|
description,
|
|
app: APP_NAME,
|
|
source: 'SYSTEM',
|
|
stackTrace: stackTrace ?? '',
|
|
};
|
|
}
|
|
|
|
async function sendToMonitoring(payload: ErrorPayload): Promise<boolean> {
|
|
try {
|
|
const res = await fetch(`${ConstEnv.url_monitoring}/api/bugs`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-API-Key': ConstEnv.key_api_monitoring ?? '',
|
|
},
|
|
body: JSON.stringify(payload),
|
|
});
|
|
return res.ok;
|
|
} catch (error) {
|
|
console.log(error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async function enqueue(payload: ErrorPayload): Promise<void> {
|
|
try {
|
|
const raw = await AsyncStorage.getItem(QUEUE_KEY);
|
|
const queue: ErrorPayload[] = raw ? JSON.parse(raw) : [];
|
|
queue.push(payload);
|
|
await AsyncStorage.setItem(QUEUE_KEY, JSON.stringify(queue));
|
|
} catch {}
|
|
}
|
|
|
|
export async function flushErrorQueue(): Promise<void> {
|
|
try {
|
|
const state = await NetInfo.fetch();
|
|
if (!state.isConnected) return;
|
|
|
|
const raw = await AsyncStorage.getItem(QUEUE_KEY);
|
|
if (!raw) return;
|
|
|
|
const queue: ErrorPayload[] = JSON.parse(raw);
|
|
if (queue.length === 0) return;
|
|
|
|
const failed: ErrorPayload[] = [];
|
|
for (const payload of queue) {
|
|
const ok = await sendToMonitoring(payload);
|
|
if (!ok) failed.push(payload);
|
|
}
|
|
|
|
if (failed.length > 0) {
|
|
await AsyncStorage.setItem(QUEUE_KEY, JSON.stringify(failed));
|
|
} else {
|
|
await AsyncStorage.removeItem(QUEUE_KEY);
|
|
}
|
|
} catch {}
|
|
}
|
|
|
|
export async function logError(description: string, error?: Error | unknown): Promise<void> {
|
|
const stackTrace = error instanceof Error ? (error.stack ?? error.message) : String(error ?? '');
|
|
const payload = buildPayload(description, stackTrace);
|
|
|
|
try {
|
|
const state = await NetInfo.fetch();
|
|
if (state.isConnected) {
|
|
const ok = await sendToMonitoring(payload);
|
|
if (!ok) await enqueue(payload);
|
|
} else {
|
|
await enqueue(payload);
|
|
}
|
|
} catch {
|
|
await enqueue(payload);
|
|
}
|
|
}
|