signal-desktop/ts/state/ducks/crashReports.ts

155 lines
3.4 KiB
TypeScript
Raw Normal View History

2022-01-11 20:02:46 +00:00
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { ReadonlyDeep } from 'type-fest';
import type { ThunkAction } from 'redux-thunk';
2022-01-11 20:02:46 +00:00
import * as log from '../../logging/log';
import * as Errors from '../../types/errors';
import { ToastType } from '../../types/Toast';
import type { StateType as RootStateType } from '../reducer';
import { showToast } from './toast';
import type { ShowToastActionType } from './toast';
2022-10-18 17:12:02 +00:00
import type { PromiseAction } from '../util';
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
import { useBoundActions } from '../../hooks/useBoundActions';
2022-01-11 20:02:46 +00:00
// State
export type CrashReportsStateType = ReadonlyDeep<{
2022-01-11 20:02:46 +00:00
count: number;
isPending: boolean;
}>;
2022-01-11 20:02:46 +00:00
// Actions
const SET_COUNT = 'crashReports/SET_COUNT';
const WRITE_TO_LOG = 'crashReports/WRITE_TO_LOG';
2022-01-11 20:02:46 +00:00
const ERASE = 'crashReports/ERASE';
type SetCrashReportCountActionType = ReadonlyDeep<{
2022-01-11 20:02:46 +00:00
type: typeof SET_COUNT;
payload: number;
}>;
2022-01-11 20:02:46 +00:00
type CrashReportsActionType = ReadonlyDeep<
2022-01-11 20:02:46 +00:00
| SetCrashReportCountActionType
| PromiseAction<typeof WRITE_TO_LOG>
| PromiseAction<typeof ERASE>
>;
2022-01-11 20:02:46 +00:00
// Action Creators
export const actions = {
setCrashReportCount,
writeCrashReportsToLog,
2022-01-11 20:02:46 +00:00
eraseCrashReports,
};
export const useCrashReportsActions = (): BoundActionCreatorsMapObject<
typeof actions
> => useBoundActions(actions);
2022-01-11 20:02:46 +00:00
function setCrashReportCount(count: number): SetCrashReportCountActionType {
return { type: SET_COUNT, payload: count };
}
function writeCrashReportsToLog(): ThunkAction<
void,
RootStateType,
unknown,
PromiseAction<typeof WRITE_TO_LOG> | ShowToastActionType
> {
return dispatch => {
async function run() {
try {
await window.IPC.crashReports.writeToLog();
} catch (error) {
dispatch(showToast({ toastType: ToastType.DebugLogError }));
throw error;
}
}
dispatch({ type: WRITE_TO_LOG, payload: run() });
};
2022-01-11 20:02:46 +00:00
}
function eraseCrashReports(): ThunkAction<
void,
RootStateType,
unknown,
PromiseAction<typeof ERASE> | ShowToastActionType
> {
return dispatch => {
async function run() {
try {
await window.IPC.crashReports.erase();
} catch (error) {
dispatch(showToast({ toastType: ToastType.DebugLogError }));
throw error;
}
}
dispatch({ type: ERASE, payload: run() });
};
2022-01-11 20:02:46 +00:00
}
// Reducer
export function getEmptyState(): CrashReportsStateType {
return {
count: 0,
isPending: false,
};
}
export function reducer(
state: Readonly<CrashReportsStateType> = getEmptyState(),
action: Readonly<CrashReportsActionType>
): CrashReportsStateType {
if (action.type === SET_COUNT) {
return {
...state,
count: action.payload,
};
}
if (
action.type === `${WRITE_TO_LOG}_PENDING` ||
2022-01-11 20:02:46 +00:00
action.type === `${ERASE}_PENDING`
) {
return {
...state,
isPending: true,
};
}
if (
action.type === `${WRITE_TO_LOG}_FULFILLED` ||
2022-01-11 20:02:46 +00:00
action.type === `${ERASE}_FULFILLED`
) {
return {
...state,
count: 0,
isPending: false,
};
}
if (
action.type === (`${WRITE_TO_LOG}_REJECTED` as const) ||
2022-01-11 20:02:46 +00:00
action.type === (`${ERASE}_REJECTED` as const)
) {
const { error } = action;
log.error(
`Failed to write crash report due to error ${Errors.toLogFormat(error)}`
2022-01-11 20:02:46 +00:00
);
return {
...state,
count: 0,
isPending: false,
};
}
return state;
}