mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-16 19:57:52 +01:00
add debug logging
This commit is contained in:
@@ -17,7 +17,7 @@ import { useNoteStore } from '../../stores/use-notes-store';
|
|||||||
import { useSettingStore } from '../../stores/use-setting-store';
|
import { useSettingStore } from '../../stores/use-setting-store';
|
||||||
import { useThemeStore } from '../../stores/use-theme-store';
|
import { useThemeStore } from '../../stores/use-theme-store';
|
||||||
import { useUserStore } from '../../stores/use-user-store';
|
import { useUserStore } from '../../stores/use-user-store';
|
||||||
import { db, loadDatabase } from '../../utils/database';
|
import { DatabaseLogger, db, loadDatabase } from '../../utils/database';
|
||||||
import { MMKV } from '../../utils/database/mmkv';
|
import { MMKV } from '../../utils/database/mmkv';
|
||||||
import { eCloseProgressDialog, eOpenAnnouncementDialog } from '../../utils/events';
|
import { eCloseProgressDialog, eOpenAnnouncementDialog } from '../../utils/events';
|
||||||
import { tabBarRef } from '../../utils/global-refs';
|
import { tabBarRef } from '../../utils/global-refs';
|
||||||
@@ -85,6 +85,7 @@ const Launcher = React.memo(
|
|||||||
await loadDatabase();
|
await loadDatabase();
|
||||||
db?.eventManager?.subscribe(EVENTS.databaseMigrating, onDatabaseMigratingProgess);
|
db?.eventManager?.subscribe(EVENTS.databaseMigrating, onDatabaseMigratingProgess);
|
||||||
db?.eventManager?.subscribe(EVENTS.databaseMigrated, onMigrationCompleted);
|
db?.eventManager?.subscribe(EVENTS.databaseMigrated, onMigrationCompleted);
|
||||||
|
DatabaseLogger.info('Initializing database');
|
||||||
await db.init();
|
await db.init();
|
||||||
dbInitCompleted.current = true;
|
dbInitCompleted.current = true;
|
||||||
}
|
}
|
||||||
@@ -139,6 +140,7 @@ const Launcher = React.memo(
|
|||||||
};
|
};
|
||||||
|
|
||||||
const checkAppUpdateAvailable = async () => {
|
const checkAppUpdateAvailable = async () => {
|
||||||
|
if (__DEV__) return;
|
||||||
try {
|
try {
|
||||||
const version = await checkVersion();
|
const version = await checkVersion();
|
||||||
if (!version.needsUpdate) return false;
|
if (!version.needsUpdate) return false;
|
||||||
|
|||||||
@@ -6,18 +6,28 @@ import { Header } from '../components/header';
|
|||||||
import { Toast } from '../components/toast';
|
import { Toast } from '../components/toast';
|
||||||
import { useNoteStore } from '../stores/use-notes-store';
|
import { useNoteStore } from '../stores/use-notes-store';
|
||||||
import { useSettingStore } from '../stores/use-setting-store';
|
import { useSettingStore } from '../stores/use-setting-store';
|
||||||
|
import { useThemeStore } from '../stores/use-theme-store';
|
||||||
import { TabsHolder } from './tabs-holder';
|
import { TabsHolder } from './tabs-holder';
|
||||||
|
|
||||||
export const ApplicationHolder = React.memo(
|
export const ApplicationHolder = React.memo(
|
||||||
() => {
|
() => {
|
||||||
const loading = useNoteStore(state => state.loading);
|
const loading = useNoteStore(state => state.loading);
|
||||||
const introCompleted = useSettingStore(state => state.settings.introCompleted);
|
const introCompleted = useSettingStore(state => state.settings.introCompleted);
|
||||||
|
const colors = useThemeStore(state => state.colors);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{loading && introCompleted ? (
|
{loading && introCompleted ? (
|
||||||
<>
|
<>
|
||||||
<Header />
|
<SafeAreaView
|
||||||
<DelayLayout animated={false} wait={loading} />
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: colors.bg
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Header />
|
||||||
|
<DelayLayout animated={false} wait={loading} />
|
||||||
|
</SafeAreaView>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ const Editor = React.memo(
|
|||||||
allowUniversalAccessFromFileURLs={true}
|
allowUniversalAccessFromFileURLs={true}
|
||||||
originWhitelist={['*']}
|
originWhitelist={['*']}
|
||||||
source={{
|
source={{
|
||||||
uri: __DEV__ ? 'http://localhost:3000/index.html' : EDITOR_URI
|
uri: __DEV__ ? 'http://192.168.10.6:3000/index.html' : EDITOR_URI
|
||||||
}}
|
}}
|
||||||
style={style}
|
style={style}
|
||||||
autoManageStatusBarEnabled={false}
|
autoManageStatusBarEnabled={false}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import Clipboard from '@react-native-clipboard/clipboard';
|
import Clipboard from '@react-native-clipboard/clipboard';
|
||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import { FlatList, Platform, TouchableOpacity, View } from 'react-native';
|
import { FlatList, Platform, TouchableOpacity, View } from 'react-native';
|
||||||
import * as ScopedStorage from 'react-native-scoped-storage';
|
import * as ScopedStorage from 'react-native-scoped-storage';
|
||||||
import RNFetchBlob from 'rn-fetch-blob';
|
import RNFetchBlob from 'rn-fetch-blob';
|
||||||
@@ -12,28 +12,71 @@ import { useThemeStore } from '../../stores/use-theme-store';
|
|||||||
import { hexToRGBA } from '../../utils/color-scheme/utils';
|
import { hexToRGBA } from '../../utils/color-scheme/utils';
|
||||||
import Storage from '../../utils/database/storage';
|
import Storage from '../../utils/database/storage';
|
||||||
import { sanitizeFilename } from '../../utils/sanitizer';
|
import { sanitizeFilename } from '../../utils/sanitizer';
|
||||||
|
import { DatabaseLogger } from '../../utils/database/index';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import useTimer from '../../utils/hooks/use-timer';
|
||||||
|
import { LogLevel } from '@streetwriters/notesnook-core/logger';
|
||||||
|
|
||||||
|
function getLevelString(level: number) {
|
||||||
|
switch (level) {
|
||||||
|
case LogLevel.Debug:
|
||||||
|
return 'DEBUG';
|
||||||
|
case LogLevel.Info:
|
||||||
|
return 'INFO';
|
||||||
|
case LogLevel.Log:
|
||||||
|
return 'LOG';
|
||||||
|
case LogLevel.Error:
|
||||||
|
return 'ERROR';
|
||||||
|
case LogLevel.Warn:
|
||||||
|
return 'WARN';
|
||||||
|
case LogLevel.Fatal:
|
||||||
|
return 'FATAL';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default function DebugLogs() {
|
export default function DebugLogs() {
|
||||||
const colors = useThemeStore(state => state.colors);
|
const colors = useThemeStore(state => state.colors);
|
||||||
|
const { seconds, start } = useTimer('debug_logs_timer');
|
||||||
|
const [logs, setLogs] = useState<
|
||||||
|
{
|
||||||
|
key: string;
|
||||||
|
logs: any[];
|
||||||
|
}[]
|
||||||
|
>([]);
|
||||||
|
const [currentLog, setCurrentLog] = useState<{
|
||||||
|
key: string;
|
||||||
|
logs: any[];
|
||||||
|
}>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
if (seconds === 0) {
|
||||||
|
start(5, 'debug_logs_timer');
|
||||||
|
let logs = await DatabaseLogger.get();
|
||||||
|
if (logs.length > 0 && !currentLog) {
|
||||||
|
setCurrentLog(logs[0]);
|
||||||
|
} else {
|
||||||
|
setCurrentLog(logs[logs.findIndex(l => l.key === currentLog?.key)]);
|
||||||
|
}
|
||||||
|
setLogs(logs);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}, [seconds]);
|
||||||
|
|
||||||
const renderItem = ({ item, index }) => {
|
const renderItem = ({ item, index }) => {
|
||||||
const background =
|
const background =
|
||||||
item.type === 'error'
|
item.level === LogLevel.Error || item.level === LogLevel.Fatal
|
||||||
? hexToRGBA(colors.red, 0.2)
|
? hexToRGBA(colors.red, 0.2)
|
||||||
: item.type === 'success'
|
: item.level === LogLevel.Warn
|
||||||
? hexToRGBA(colors.green, 0.2)
|
|
||||||
: item.type === 'warn'
|
|
||||||
? hexToRGBA(colors.orange, 0.2)
|
? hexToRGBA(colors.orange, 0.2)
|
||||||
: 'transparent';
|
: 'transparent';
|
||||||
|
|
||||||
const color =
|
const color =
|
||||||
item.type === 'error'
|
item.level === LogLevel.Error || item.level === LogLevel.Fatal
|
||||||
? colors.red
|
? colors.red
|
||||||
: item.type === 'success'
|
: item.level === LogLevel.Warn
|
||||||
? colors.green
|
|
||||||
: item.type === 'warn'
|
|
||||||
? colors.orange
|
? colors.orange
|
||||||
: 'transparent';
|
: colors.pri;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
@@ -50,24 +93,31 @@ export default function DebugLogs() {
|
|||||||
paddingHorizontal: 12,
|
paddingHorizontal: 12,
|
||||||
paddingVertical: 12,
|
paddingVertical: 12,
|
||||||
backgroundColor: background,
|
backgroundColor: background,
|
||||||
flexShrink: 1
|
flexShrink: 1,
|
||||||
|
borderBottomWidth: 1,
|
||||||
|
borderBottomColor: colors.nav
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Paragraph
|
<Paragraph
|
||||||
style={{
|
style={{
|
||||||
flexShrink: 1,
|
flexShrink: 1,
|
||||||
flexWrap: 'wrap',
|
flexWrap: 'wrap',
|
||||||
fontFamily: 'monospace'
|
fontFamily: Platform.OS === 'ios' ? 'Menlo' : 'monospace'
|
||||||
}}
|
}}
|
||||||
|
size={12}
|
||||||
color={color}
|
color={color}
|
||||||
>
|
>
|
||||||
{item.error}
|
[{getLevelString(item.level)}] {item.message}
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<View>
|
<View
|
||||||
|
style={{
|
||||||
|
flex: 1
|
||||||
|
}}
|
||||||
|
>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
padding: 12
|
padding: 12
|
||||||
@@ -77,104 +127,154 @@ export default function DebugLogs() {
|
|||||||
text="If you are facing an issue in the app. You can send us the logs from here to help us investigate the issue."
|
text="If you are facing an issue in the app. You can send us the logs from here to help us investigate the issue."
|
||||||
type="information"
|
type="information"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
flexDirection: 'row',
|
|
||||||
width: '100%',
|
|
||||||
alignItems: 'flex-end',
|
|
||||||
justifyContent: 'flex-end',
|
|
||||||
marginTop: 12
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<IconButton
|
|
||||||
onPress={() => {
|
|
||||||
Clipboard.setString('All logs copied');
|
|
||||||
ToastEvent.show({
|
|
||||||
heading: 'Debug log copied!',
|
|
||||||
context: 'global',
|
|
||||||
type: 'success'
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
size={20}
|
|
||||||
name="clipboard"
|
|
||||||
color={colors.gray}
|
|
||||||
/>
|
|
||||||
<IconButton
|
|
||||||
onPress={async () => {
|
|
||||||
try {
|
|
||||||
let path = null;
|
|
||||||
const fileName = sanitizeFilename(`notesnook_logs_${Date.now()}`);
|
|
||||||
if (Platform.OS === 'android') {
|
|
||||||
let file = await ScopedStorage.createDocument(
|
|
||||||
fileName,
|
|
||||||
'text/plain',
|
|
||||||
'save data',
|
|
||||||
'utf8'
|
|
||||||
);
|
|
||||||
if (!file) return;
|
|
||||||
path = file.uri;
|
|
||||||
} else {
|
|
||||||
path = await Storage.checkAndCreateDir('/');
|
|
||||||
await RNFetchBlob.fs.writeFile(path + fileName, 'save data', 'utf8');
|
|
||||||
path = path + fileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path) {
|
|
||||||
ToastEvent.show({
|
|
||||||
heading: 'Debug logs downloaded',
|
|
||||||
context: 'global',
|
|
||||||
type: 'success'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
size={20}
|
|
||||||
name="download"
|
|
||||||
color={colors.gray}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<IconButton
|
|
||||||
onPress={() => {
|
|
||||||
presentDialog({
|
|
||||||
title: 'Clear all logs',
|
|
||||||
paragraph: 'Are you sure you want to delete alll logs?',
|
|
||||||
negativeText: 'Cancel',
|
|
||||||
positiveText: 'Clear',
|
|
||||||
positivePress: () => {}
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
size={20}
|
|
||||||
name="delete"
|
|
||||||
color={colors.gray}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<FlatList
|
{currentLog && (
|
||||||
inverted
|
<FlatList
|
||||||
data={[
|
ListHeaderComponent={
|
||||||
{
|
<View
|
||||||
type: 'error',
|
style={{
|
||||||
error: 'Error: file not found and jt aksdj adksj kdajkd jsakdjs kjda kdjsak djaks dkas.'
|
paddingHorizontal: 12,
|
||||||
},
|
marginBottom: 10,
|
||||||
{
|
flexDirection: 'row',
|
||||||
type: 'warn',
|
alignItems: 'center',
|
||||||
error: 'Warning: file found with invalid name'
|
backgroundColor: colors.bg,
|
||||||
},
|
justifyContent: 'space-between'
|
||||||
{
|
}}
|
||||||
type: 'success',
|
>
|
||||||
error: 'Success: file found'
|
<View
|
||||||
},
|
style={{
|
||||||
{
|
flexDirection: 'row',
|
||||||
type: 'error',
|
alignItems: 'center'
|
||||||
error: 'Error: file not found'
|
}}
|
||||||
|
>
|
||||||
|
<Paragraph>{currentLog.key}</Paragraph>
|
||||||
|
|
||||||
|
<IconButton
|
||||||
|
customStyle={{
|
||||||
|
width: 30,
|
||||||
|
height: 30,
|
||||||
|
marginHorizontal: 5
|
||||||
|
}}
|
||||||
|
onPress={() => {
|
||||||
|
let index = logs.findIndex(l => l.key === currentLog.key);
|
||||||
|
if (index === 0) return;
|
||||||
|
setCurrentLog(logs[index - 1]);
|
||||||
|
}}
|
||||||
|
size={20}
|
||||||
|
name="chevron-left"
|
||||||
|
color={colors.icon}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<IconButton
|
||||||
|
customStyle={{
|
||||||
|
width: 30,
|
||||||
|
height: 30
|
||||||
|
}}
|
||||||
|
onPress={() => {
|
||||||
|
let index = logs.findIndex(l => l.key === currentLog.key);
|
||||||
|
if (index === logs.length - 1) return;
|
||||||
|
setCurrentLog(logs[index + 1]);
|
||||||
|
}}
|
||||||
|
size={20}
|
||||||
|
name="chevron-right"
|
||||||
|
color={colors.icon}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
flexDirection: 'row'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IconButton
|
||||||
|
onPress={() => {
|
||||||
|
Clipboard.setString('All logs copied');
|
||||||
|
ToastEvent.show({
|
||||||
|
heading: 'Debug log copied!',
|
||||||
|
context: 'global',
|
||||||
|
type: 'success'
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
size={20}
|
||||||
|
customStyle={{
|
||||||
|
width: 30,
|
||||||
|
height: 30,
|
||||||
|
marginRight: 5
|
||||||
|
}}
|
||||||
|
name="content-copy"
|
||||||
|
color={colors.gray}
|
||||||
|
/>
|
||||||
|
<IconButton
|
||||||
|
onPress={async () => {
|
||||||
|
try {
|
||||||
|
let path = null;
|
||||||
|
const fileName = sanitizeFilename(`notesnook_logs_${Date.now()}`);
|
||||||
|
const data = currentLog?.logs
|
||||||
|
.map(
|
||||||
|
log =>
|
||||||
|
`${new Date(log.timestamp).toUTCString()}: [${getLevelString(
|
||||||
|
log.level
|
||||||
|
)}] ${log.message || log.error?.message}${
|
||||||
|
log.error?.stack ? '\n' + log.error?.stack : ''
|
||||||
|
}`
|
||||||
|
)
|
||||||
|
.join(`\n`);
|
||||||
|
if (!data) return;
|
||||||
|
if (Platform.OS === 'android') {
|
||||||
|
let file = await ScopedStorage.createDocument(
|
||||||
|
fileName + '.txt',
|
||||||
|
'text/plain',
|
||||||
|
data,
|
||||||
|
'utf8'
|
||||||
|
);
|
||||||
|
if (!file) return;
|
||||||
|
path = file.uri;
|
||||||
|
} else {
|
||||||
|
path = await Storage.checkAndCreateDir('/');
|
||||||
|
await RNFetchBlob.fs.writeFile(path + fileName + '.txt', data, 'utf8');
|
||||||
|
path = path + fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path) {
|
||||||
|
ToastEvent.show({
|
||||||
|
heading: 'Debug logs downloaded',
|
||||||
|
context: 'global',
|
||||||
|
type: 'success'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
customStyle={{
|
||||||
|
width: 30,
|
||||||
|
height: 30,
|
||||||
|
marginRight: 5
|
||||||
|
}}
|
||||||
|
size={20}
|
||||||
|
name="download"
|
||||||
|
color={colors.gray}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
}
|
}
|
||||||
]}
|
style={{
|
||||||
renderItem={renderItem}
|
flex: 1,
|
||||||
/>
|
width: '100%'
|
||||||
|
}}
|
||||||
|
stickyHeaderIndices={[0]}
|
||||||
|
ListFooterComponent={
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
height: 200
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
data={currentLog.logs}
|
||||||
|
renderItem={renderItem}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -749,14 +749,14 @@ export const settingsGroups: SettingSection[] = [
|
|||||||
name: 'Debug mode',
|
name: 'Debug mode',
|
||||||
description: 'Show debug options on items',
|
description: 'Show debug options on items',
|
||||||
property: 'devMode'
|
property: 'devMode'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'debug-logs',
|
||||||
|
type: 'screen',
|
||||||
|
name: 'Debug logs',
|
||||||
|
description: 'View debug logs from the app',
|
||||||
|
component: 'debug-logs'
|
||||||
}
|
}
|
||||||
// {
|
|
||||||
// id: 'debug-logs',
|
|
||||||
// type: 'screen',
|
|
||||||
// name: 'Debug logs',
|
|
||||||
// description: 'View debug logs from the app',
|
|
||||||
// component: 'debug-logs'
|
|
||||||
// }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,53 +12,71 @@ import {
|
|||||||
} from './encryption';
|
} from './encryption';
|
||||||
import { MMKV } from './mmkv';
|
import { MMKV } from './mmkv';
|
||||||
|
|
||||||
async function read(key) {
|
export class KV {
|
||||||
if (!key) return null;
|
storage = null;
|
||||||
let data = MMKV.getString(key);
|
constructor(storage) {
|
||||||
if (!data) return null;
|
this.storage = storage;
|
||||||
try {
|
}
|
||||||
let parse = JSON.parse(data);
|
async read(key) {
|
||||||
return parse;
|
if (!key) return null;
|
||||||
} catch (e) {
|
let data = this.storage.getString(key);
|
||||||
return data;
|
if (!data) return null;
|
||||||
|
try {
|
||||||
|
let parse = JSON.parse(data);
|
||||||
|
return parse;
|
||||||
|
} catch (e) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async write(key, data) {
|
||||||
|
this.storage.setString(key, typeof data === 'string' ? data : JSON.stringify(data));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async readMulti(keys) {
|
||||||
|
if (keys.length <= 0) {
|
||||||
|
return [];
|
||||||
|
} else {
|
||||||
|
let data = await this.storage.getMultipleItemsAsync(keys.slice());
|
||||||
|
|
||||||
|
return data.map(([key, value]) => {
|
||||||
|
let obj;
|
||||||
|
try {
|
||||||
|
obj = JSON.parse(value);
|
||||||
|
} catch (e) {
|
||||||
|
obj = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [key, obj];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async remove(key) {
|
||||||
|
return await this.storage.removeItem(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
async clear() {
|
||||||
|
return await this.storage.clearStore();
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllKeys() {
|
||||||
|
let keys = (await this.storage.indexer.getKeys()) || [];
|
||||||
|
keys = keys.filter(
|
||||||
|
k =>
|
||||||
|
k !== 'stringIndex' &&
|
||||||
|
k !== 'boolIndex' &&
|
||||||
|
k !== 'mapIndex' &&
|
||||||
|
k !== 'arrayIndex' &&
|
||||||
|
k !== 'numberIndex' &&
|
||||||
|
k !== this.storage.instanceID
|
||||||
|
);
|
||||||
|
return keys;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function write(key, data) {
|
const DefaultStorage = new KV(MMKV);
|
||||||
MMKV.setString(key, typeof data === 'string' ? data : JSON.stringify(data));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function readMulti(keys) {
|
|
||||||
if (keys.length <= 0) {
|
|
||||||
return [];
|
|
||||||
} else {
|
|
||||||
let data = await MMKV.getMultipleItemsAsync(keys.slice());
|
|
||||||
|
|
||||||
return data.map(([key, value]) => {
|
|
||||||
let obj;
|
|
||||||
try {
|
|
||||||
obj = JSON.parse(value);
|
|
||||||
} catch (e) {
|
|
||||||
obj = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [key, obj];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function remove(key) {
|
|
||||||
return await MMKV.removeItem(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function clear() {
|
|
||||||
return await MMKV.clearStore();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getAllKeys() {
|
|
||||||
return await MMKV.indexer.getKeys();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function requestPermission() {
|
async function requestPermission() {
|
||||||
if (Platform.OS === 'ios') return true;
|
if (Platform.OS === 'ios') return true;
|
||||||
@@ -84,14 +102,14 @@ async function checkAndCreateDir(path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
read,
|
read: key => DefaultStorage.read(key),
|
||||||
write,
|
write: (key, value) => DefaultStorage.write(key, value),
|
||||||
readMulti,
|
readMulti: keys => DefaultStorage.readMulti(keys),
|
||||||
remove,
|
remove: key => DefaultStorage.remove(key),
|
||||||
clear,
|
clear: () => DefaultStorage.clear(),
|
||||||
|
getAllKeys: () => DefaultStorage.getAllKeys(),
|
||||||
encrypt,
|
encrypt,
|
||||||
decrypt,
|
decrypt,
|
||||||
getAllKeys,
|
|
||||||
getRandomBytes,
|
getRandomBytes,
|
||||||
checkAndCreateDir,
|
checkAndCreateDir,
|
||||||
requestPermission,
|
requestPermission,
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
|
import Database from '@streetwriters/notesnook-core/api/index';
|
||||||
|
import { initalize, logger as dbLogger } from '@streetwriters/notesnook-core/logger';
|
||||||
import { Platform } from 'react-native';
|
import { Platform } from 'react-native';
|
||||||
|
import { MMKVLoader } from 'react-native-mmkv-storage';
|
||||||
import filesystem from '../filesystem';
|
import filesystem from '../filesystem';
|
||||||
import EventSource from '../sse/even-source-ios';
|
import EventSource from '../sse/even-source-ios';
|
||||||
import AndroidEventSource from '../sse/event-source';
|
import AndroidEventSource from '../sse/event-source';
|
||||||
import Storage from './storage';
|
import Storage, { KV } from './storage';
|
||||||
import Database from '@streetwriters/notesnook-core/api/index';
|
const LoggerStorage = new MMKVLoader().withInstanceID('notesnook_logs').initialize();
|
||||||
|
initalize(new KV(LoggerStorage));
|
||||||
|
export const DatabaseLogger = dbLogger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {import("@streetwriters/notesnook-core/api/index").default}
|
* @type {import("@streetwriters/notesnook-core/api/index").default}
|
||||||
|
|||||||
Reference in New Issue
Block a user