react-native-mosquito-transport 0.0.22 → 0.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -2
- package/src/helpers/fs_manager.js +46 -0
- package/src/helpers/peripherals.js +2 -2
- package/src/helpers/purger.js +20 -9
- package/src/helpers/sqlite_manager.js +16 -10
- package/src/helpers/utils.js +25 -11
- package/src/helpers/variables.js +1 -1
- package/src/products/database/accessor.js +47 -26
- package/src/products/database/index.js +5 -2
- package/src/products/http_callable/accessor.js +21 -16
- package/src/products/http_callable/index.js +5 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-mosquito-transport",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.24",
|
|
4
4
|
"description": "React native javascript sdk for mosquito-transport (https://github.com/brainbehindx/mosquito-transport)",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -33,8 +33,9 @@
|
|
|
33
33
|
"entity-serializer": "^1.0.2",
|
|
34
34
|
"guard-object": "^1.1.4",
|
|
35
35
|
"lodash": "^4.17.21",
|
|
36
|
+
"react-native-file-access": "^3.1.1",
|
|
36
37
|
"react-native-get-random-values": "^1.9.0",
|
|
37
|
-
"react-native-
|
|
38
|
+
"react-native-sha256": "^1.4.10",
|
|
38
39
|
"simplify-error": "^1.0.1",
|
|
39
40
|
"socket.io-client": "^4.6.2",
|
|
40
41
|
"subscription-listener": "^1.1.2",
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Platform } from "react-native";
|
|
2
|
+
import { Buffer } from 'buffer';
|
|
3
|
+
import { deserialize, serialize } from 'entity-serializer';
|
|
4
|
+
import { Dirs, FileSystem } from 'react-native-file-access';
|
|
5
|
+
|
|
6
|
+
const MAX_INLINE_BLOB = 1024;
|
|
7
|
+
|
|
8
|
+
const DIR_PATH = `${Platform.OS === 'android' ? Dirs.DatabaseDir : Dirs.MainBundleDir}/MOSQUITO`;
|
|
9
|
+
const resolvePath = (path = '') => `${DIR_PATH}/${path.startsWith('/') ? path : '/' + path}`;
|
|
10
|
+
|
|
11
|
+
const DIR_CREATION_PROMISE = FileSystem.mkdir(DIR_PATH);
|
|
12
|
+
|
|
13
|
+
const fsWrite = async (path, data) => {
|
|
14
|
+
await DIR_CREATION_PROMISE;
|
|
15
|
+
return FileSystem.writeFile(resolvePath(path), data instanceof Buffer ? data.toString('base64') : data, 'base64');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const fsRead = async (path) => {
|
|
19
|
+
await DIR_CREATION_PROMISE;
|
|
20
|
+
return Buffer.from(await FileSystem.readFile(resolvePath(path), 'base64'), 'base64');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const getStoreID = (db_filename, table, primary_key) => `${table}_${primary_key}_${db_filename}.blob`;
|
|
24
|
+
|
|
25
|
+
export const deleteBigData = (store_id) => FileSystem.unlink(resolvePath(store_id));
|
|
26
|
+
|
|
27
|
+
export const handleBigData = async (store_id, data) => {
|
|
28
|
+
const bufData = serialize(data);
|
|
29
|
+
if (bufData.byteLength <= MAX_INLINE_BLOB) {
|
|
30
|
+
return serialize([bufData]).toString('base64');
|
|
31
|
+
}
|
|
32
|
+
await fsWrite(store_id, bufData);
|
|
33
|
+
return serialize([undefined, store_id]).toString('base64');
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const parseBigData = async (result) => {
|
|
37
|
+
const [inline, store_id] = deserialize(Buffer.from(result, 'base64'));
|
|
38
|
+
if (store_id) {
|
|
39
|
+
try {
|
|
40
|
+
return deserialize(await fsRead(store_id));
|
|
41
|
+
} catch (error) {
|
|
42
|
+
throw `Referenced local file is either corrupted or deleted, Error: ${error}`;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return deserialize(inline);
|
|
46
|
+
};
|
|
@@ -3,7 +3,7 @@ import { ServerReachableListener } from "./listeners";
|
|
|
3
3
|
import naclPkg from 'tweetnacl';
|
|
4
4
|
import getLodash from "lodash/get";
|
|
5
5
|
import { deserialize, serialize } from "entity-serializer";
|
|
6
|
-
import {
|
|
6
|
+
import { sha256 } from 'react-native-sha256';
|
|
7
7
|
|
|
8
8
|
const { box, randomBytes } = naclPkg;
|
|
9
9
|
|
|
@@ -65,7 +65,7 @@ export function sortArrayByObjectKey(arr = [], key) {
|
|
|
65
65
|
};
|
|
66
66
|
|
|
67
67
|
export async function niceHash(str = '') {
|
|
68
|
-
const hash = await
|
|
68
|
+
const hash = await sha256(str);
|
|
69
69
|
if (hash.length > str.length) return encodeBinary(str);
|
|
70
70
|
return hash;
|
|
71
71
|
};
|
package/src/helpers/purger.js
CHANGED
|
@@ -3,6 +3,7 @@ import { Validator } from "guard-object";
|
|
|
3
3
|
import { incrementDatabaseSizeCore } from "../products/database/counter";
|
|
4
4
|
import { incrementFetcherSizeCore } from "../products/http_callable/counter";
|
|
5
5
|
import unsetLodash from 'lodash/unset';
|
|
6
|
+
import { deleteBigData, getStoreID } from "./fs_manager";
|
|
6
7
|
|
|
7
8
|
const { LIMITER_DATA, LIMITER_RESULT, DB_COUNT_QUERY, FETCH_RESOURCES } = SQLITE_PATH;
|
|
8
9
|
|
|
@@ -156,7 +157,7 @@ export const purgeRedundantRecords = async (data, builder) => {
|
|
|
156
157
|
|
|
157
158
|
const [instanceData, resultData] = await Promise.all([
|
|
158
159
|
sqlite.executeSql(`SELECT access_id, touched, size FROM ${LIMITER_DATA(path)}`),
|
|
159
|
-
sqlite.executeSql(`SELECT
|
|
160
|
+
sqlite.executeSql(`SELECT access_id_limiter, touched, size FROM ${LIMITER_RESULT(path)}`)
|
|
160
161
|
]).then(r =>
|
|
161
162
|
r.map(v => v[0].rows.raw())
|
|
162
163
|
);
|
|
@@ -178,19 +179,24 @@ export const purgeRedundantRecords = async (data, builder) => {
|
|
|
178
179
|
let cuts = 0;
|
|
179
180
|
|
|
180
181
|
for (let i = 0; i < redundantDbRanking.length; i++) {
|
|
181
|
-
sizer -= redundantDbRanking[i][0].size || 0;
|
|
182
|
+
sizer -= (redundantDbRanking[i][0].size || 0);
|
|
182
183
|
++cuts;
|
|
183
184
|
if (sizer < newSize) break;
|
|
184
185
|
}
|
|
185
186
|
|
|
186
187
|
console.warn(`purging ${cuts} of ${redundantDbRanking.length} db entities`);
|
|
187
188
|
await Promise.all(redundantDbRanking.slice(0, cuts).map(async ([v, { builder, isCounter, path }]) => {
|
|
188
|
-
|
|
189
|
+
let db_filename;
|
|
190
|
+
const sqlite = await openDB(builder, n => db_filename = n);
|
|
189
191
|
try {
|
|
190
|
-
const table = (isCounter ? DB_COUNT_QUERY : '
|
|
191
|
-
const id_field = '
|
|
192
|
+
const table = (isCounter ? DB_COUNT_QUERY : 'access_id_limiter' in v ? LIMITER_RESULT : LIMITER_DATA)(path);
|
|
193
|
+
const id_field = 'access_id_limiter' in v ? 'access_id_limiter' : 'access_id';
|
|
194
|
+
const primary_key = v[id_field];
|
|
192
195
|
|
|
193
|
-
await
|
|
196
|
+
await Promise.all([
|
|
197
|
+
sqlite.executeSql(SQLITE_COMMANDS.DELETE_ROW(table, `${id_field} = ?`), [primary_key]),
|
|
198
|
+
deleteBigData(getStoreID(db_filename, table, primary_key)).catch(() => null)
|
|
199
|
+
]);
|
|
194
200
|
if (!isCounter) incrementDatabaseSizeCore(data.DatabaseStats, builder, path, -v.size);
|
|
195
201
|
} catch (error) {
|
|
196
202
|
console.log('db redundantClearing err:', error);
|
|
@@ -223,16 +229,21 @@ export const purgeRedundantRecords = async (data, builder) => {
|
|
|
223
229
|
let cuts = 0;
|
|
224
230
|
|
|
225
231
|
for (let i = 0; i < redundantFetchRanking.length; i++) {
|
|
226
|
-
sizer -= redundantFetchRanking[i][0].size || 0;
|
|
232
|
+
sizer -= (redundantFetchRanking[i][0].size || 0);
|
|
227
233
|
++cuts;
|
|
228
234
|
if (sizer < newSize) break;
|
|
229
235
|
}
|
|
230
236
|
|
|
231
237
|
console.warn(`purging ${cuts} of ${redundantFetchRanking.length} fetcher entities`);
|
|
232
238
|
await Promise.all(redundantFetchRanking.slice(0, cuts).map(async ([v, projectUrl]) => {
|
|
233
|
-
|
|
239
|
+
let db_filename;
|
|
240
|
+
const sqlite = await openDB(FETCH_RESOURCES(projectUrl), n => db_filename = n);
|
|
241
|
+
|
|
234
242
|
try {
|
|
235
|
-
await
|
|
243
|
+
await Promise.all([
|
|
244
|
+
sqlite.executeSql(SQLITE_COMMANDS.DELETE_ROW('main', 'access_id = ?'), [v.access_id]),
|
|
245
|
+
deleteBigData(getStoreID(db_filename, 'main', v.access_id)).catch(() => null)
|
|
246
|
+
]);
|
|
236
247
|
incrementFetcherSizeCore(data.DatabaseStats, projectUrl, -v.size);
|
|
237
248
|
} catch (error) {
|
|
238
249
|
console.log('fetcher redundantClearing err:', error);
|
|
@@ -3,6 +3,7 @@ import { Scoped, SqliteCollective } from './variables';
|
|
|
3
3
|
import { niceHash } from './peripherals';
|
|
4
4
|
|
|
5
5
|
enablePromise(true);
|
|
6
|
+
let sqliteKeyHash;
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* this method implement a centralize approach for opening and closing of sqlite database to ensure consistency across multiple task opening and closing the database in diferent order
|
|
@@ -10,7 +11,7 @@ enablePromise(true);
|
|
|
10
11
|
* @param {string} name
|
|
11
12
|
* @returns {Promise<import('react-native-sqlite-storage').SQLiteDatabase>}
|
|
12
13
|
*/
|
|
13
|
-
export const openDB = async (name) => {
|
|
14
|
+
export const openDB = async (name, onName) => {
|
|
14
15
|
|
|
15
16
|
if (name?.projectUrl) {
|
|
16
17
|
const { projectUrl, dbUrl, dbName } = name;
|
|
@@ -19,11 +20,15 @@ export const openDB = async (name) => {
|
|
|
19
20
|
|
|
20
21
|
const { sqliteKey } = Scoped.ReleaseCacheData;
|
|
21
22
|
|
|
22
|
-
if (sqliteKey)
|
|
23
|
+
if (sqliteKey) {
|
|
24
|
+
const thisHash = await (sqliteKeyHash || (sqliteKeyHash = niceHash(sqliteKey)));
|
|
25
|
+
name = `${thisHash}__${name}`;
|
|
26
|
+
}
|
|
27
|
+
onName?.(name);
|
|
23
28
|
|
|
24
29
|
if (!SqliteCollective.openedDb[name]) {
|
|
25
30
|
SqliteCollective.openedDbProcess[name] = 0;
|
|
26
|
-
SqliteCollective.openedDb[name] = (SqliteCollective.closeDbPromises[name] || Promise.resolve()).
|
|
31
|
+
SqliteCollective.openedDb[name] = Promise.allSettled([SqliteCollective.closeDbPromises[name] || Promise.resolve()]).then(() =>
|
|
27
32
|
openDatabase({
|
|
28
33
|
location: 'default',
|
|
29
34
|
name,
|
|
@@ -91,13 +96,14 @@ export const openDB = async (name) => {
|
|
|
91
96
|
* @param {any} builder
|
|
92
97
|
* @param {string} access_id
|
|
93
98
|
* @param {'database' | 'dbQueryCount' | 'httpFetch'} node
|
|
94
|
-
* @returns {(task: (sqlite: import("react-native-sqlite-storage").SQLiteDatabase) => Promise<{any}> )=> Promise<{any}>}
|
|
99
|
+
* @returns {(task: (sqlite: import("react-native-sqlite-storage").SQLiteDatabase, db_filename: string) => Promise<{any}> )=> Promise<{any}>}
|
|
95
100
|
*/
|
|
96
101
|
export const useSqliteLinearAccessId = (builder, access_id, node) => async (task) => {
|
|
97
102
|
const { projectUrl, dbUrl, dbName } = builder;
|
|
98
103
|
const nodeId = typeof builder === 'string' ? `${builder}_${access_id}` : `${projectUrl}_${dbUrl}_${dbName}_${access_id}`;
|
|
104
|
+
let db_filename;
|
|
99
105
|
|
|
100
|
-
const sqlite = await openDB(builder);
|
|
106
|
+
const sqlite = await openDB(builder, n => db_filename = n);
|
|
101
107
|
|
|
102
108
|
const thatProcess = Scoped.linearSqliteProcess[node][nodeId];
|
|
103
109
|
|
|
@@ -106,7 +112,7 @@ export const useSqliteLinearAccessId = (builder, access_id, node) => async (task
|
|
|
106
112
|
if (thatProcess !== undefined) await thatProcess;
|
|
107
113
|
} catch (_) { }
|
|
108
114
|
try {
|
|
109
|
-
resolve(await task(sqlite));
|
|
115
|
+
resolve(await task(sqlite, db_filename));
|
|
110
116
|
} catch (error) {
|
|
111
117
|
console.error('useSqliteLinearAccessId err:', error);
|
|
112
118
|
reject(error);
|
|
@@ -124,10 +130,10 @@ export const useSqliteLinearAccessId = (builder, access_id, node) => async (task
|
|
|
124
130
|
export const SQLITE_PATH = {
|
|
125
131
|
FILE_NAME: 'MOSQUITO_TRANSPORT.db',
|
|
126
132
|
TABLE_NAME: 'MT_MAIN',
|
|
127
|
-
LIMITER_RESULT: path => `"${encodeURIComponent(path)}
|
|
128
|
-
LIMITER_DATA: path => `"${encodeURIComponent(path)}
|
|
129
|
-
DB_COUNT_QUERY: path => `"${encodeURIComponent(path)}
|
|
130
|
-
FETCH_RESOURCES: projectUrl => `
|
|
133
|
+
LIMITER_RESULT: path => `"${encodeURIComponent(path)}_LIMITER_RESULT"`,
|
|
134
|
+
LIMITER_DATA: path => `"${encodeURIComponent(path)}_LIMITER_DATA"`,
|
|
135
|
+
DB_COUNT_QUERY: path => `"${encodeURIComponent(path)}_DB_COUNT_QUERY"`,
|
|
136
|
+
FETCH_RESOURCES: projectUrl => `FETCH_RESOURCES_${encodeURIComponent(projectUrl)}.db`
|
|
131
137
|
};
|
|
132
138
|
|
|
133
139
|
export const SQLITE_COMMANDS = {
|
package/src/helpers/utils.js
CHANGED
|
@@ -6,6 +6,7 @@ import { trySendPendingWrite } from "../products/database";
|
|
|
6
6
|
import { deserialize } from "entity-serializer";
|
|
7
7
|
import { openDB, SQLITE_COMMANDS, SQLITE_PATH } from "./sqlite_manager";
|
|
8
8
|
import { purgeRedundantRecords } from "./purger";
|
|
9
|
+
import { getStoreID, handleBigData, parseBigData } from "./fs_manager";
|
|
9
10
|
|
|
10
11
|
const { FILE_NAME, TABLE_NAME } = SQLITE_PATH;
|
|
11
12
|
|
|
@@ -44,14 +45,18 @@ export const updateCacheStore = (timer = 300, node) => {
|
|
|
44
45
|
|
|
45
46
|
if (!updationKey.length) return;
|
|
46
47
|
const sqlite = await openDB(FILE_NAME);
|
|
47
|
-
await Promise.
|
|
48
|
+
await Promise.all(
|
|
48
49
|
updationKey
|
|
49
50
|
.map(v => [v, v === 'PendingWrites' ? serializeToBase64(CacheStore[v]) : CacheStore[v]])
|
|
50
|
-
.map(([ref, value]) =>
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
.map(async ([ref, value]) => {
|
|
52
|
+
const blobData = await handleBigData(getStoreID(FILE_NAME, TABLE_NAME, ref), value);
|
|
53
|
+
return sqlite.executeSql(SQLITE_COMMANDS.MERGE(TABLE_NAME, ['ref', 'value']), [ref, blobData]);
|
|
54
|
+
})
|
|
55
|
+
).catch(err => {
|
|
56
|
+
console.error('updateCacheStore err:', err);
|
|
57
|
+
}).finally(() => {
|
|
58
|
+
sqlite.close();
|
|
59
|
+
});
|
|
55
60
|
}
|
|
56
61
|
};
|
|
57
62
|
|
|
@@ -71,14 +76,23 @@ export const releaseCacheStore = async (builder) => {
|
|
|
71
76
|
data = JSON.parse((await io.input()) || '{}');
|
|
72
77
|
} else {
|
|
73
78
|
const sqlite = await openDB(FILE_NAME);
|
|
74
|
-
await sqlite.executeSql(`CREATE TABLE IF NOT EXISTS ${TABLE_NAME} ( ref TEXT PRIMARY KEY, value
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
79
|
+
await sqlite.executeSql(`CREATE TABLE IF NOT EXISTS ${TABLE_NAME} ( ref TEXT PRIMARY KEY, value BLOB )`).catch(() => null);
|
|
80
|
+
try {
|
|
81
|
+
const [query] = await sqlite.executeSql(`SELECT * FROM ${TABLE_NAME}`);
|
|
82
|
+
data = Object.fromEntries(
|
|
83
|
+
await Promise.all(query.rows.raw().map(async v =>
|
|
84
|
+
[v.ref, await parseBigData(v.value)]
|
|
85
|
+
))
|
|
86
|
+
);
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.error('initializeCache sqlite data release err:', error);
|
|
89
|
+
} finally {
|
|
90
|
+
sqlite.close();
|
|
91
|
+
}
|
|
78
92
|
}
|
|
79
93
|
await purgeRedundantRecords(data, builder);
|
|
80
94
|
} catch (e) {
|
|
81
|
-
console.error('
|
|
95
|
+
console.error('initializeCache data err:', e);
|
|
82
96
|
}
|
|
83
97
|
|
|
84
98
|
Object.entries(data).forEach(([k, v]) => {
|
package/src/helpers/variables.js
CHANGED
|
@@ -13,6 +13,7 @@ import { TIMESTAMP } from "../..";
|
|
|
13
13
|
import { docSize, incrementDatabaseSize } from "./counter";
|
|
14
14
|
import { deserializeBSON, serializeToBase64 } from "./bson";
|
|
15
15
|
import { openDB, SQLITE_COMMANDS, SQLITE_PATH, useSqliteLinearAccessId } from "../../helpers/sqlite_manager";
|
|
16
|
+
import { getStoreID, handleBigData, parseBigData } from "../../helpers/fs_manager";
|
|
16
17
|
|
|
17
18
|
const { LIMITER_DATA, LIMITER_RESULT, DB_COUNT_QUERY } = SQLITE_PATH;
|
|
18
19
|
|
|
@@ -105,20 +106,20 @@ export const insertRecord = async (builder, config, accessIdWithoutLimit, value,
|
|
|
105
106
|
const thisSize = docSize(value);
|
|
106
107
|
|
|
107
108
|
if (!io) {
|
|
108
|
-
await useSqliteLinearAccessId(builder, accessIdWithoutLimit, 'database')(async (sqlite) => {
|
|
109
|
+
await useSqliteLinearAccessId(builder, accessIdWithoutLimit, 'database')(async (sqlite, db_filename) => {
|
|
109
110
|
const initNode = `${projectUrl}_${dbUrl}_${dbName}_${path}`;
|
|
110
111
|
|
|
111
112
|
if (!Scoped.initedSqliteInstances.database[initNode]) {
|
|
112
113
|
Scoped.initedSqliteInstances.database[initNode] = (async () => {
|
|
113
114
|
await Promise.allSettled([
|
|
114
|
-
sqlite.executeSql(`CREATE TABLE IF NOT EXISTS ${LIMITER_DATA(path)} ( access_id TEXT PRIMARY KEY, value
|
|
115
|
-
sqlite.executeSql(`CREATE TABLE IF NOT EXISTS ${LIMITER_RESULT(path)} (
|
|
115
|
+
sqlite.executeSql(`CREATE TABLE IF NOT EXISTS ${LIMITER_DATA(path)} ( access_id TEXT PRIMARY KEY, value BLOB, touched INTEGER, size INTEGER )`),
|
|
116
|
+
sqlite.executeSql(`CREATE TABLE IF NOT EXISTS ${LIMITER_RESULT(path)} ( access_id_limiter TEXT PRIMARY KEY, access_id TEXT, value BLOB, touched INTEGER, size INTEGER )`)
|
|
116
117
|
]);
|
|
117
118
|
|
|
118
119
|
await Promise.allSettled([
|
|
119
120
|
sqlite.executeSql(SQLITE_COMMANDS.CREATE_INDEX(LIMITER_DATA(path), ['access_id'])),
|
|
120
121
|
// sqlite.executeSql(SQLITE_COMMANDS.CREATE_INDEX(LIMITER_DATA(path), ['touched'])),
|
|
121
|
-
sqlite.executeSql(SQLITE_COMMANDS.CREATE_INDEX(LIMITER_RESULT(path), ['
|
|
122
|
+
sqlite.executeSql(SQLITE_COMMANDS.CREATE_INDEX(LIMITER_RESULT(path), ['access_id_limiter'])),
|
|
122
123
|
// sqlite.executeSql(SQLITE_COMMANDS.CREATE_INDEX(LIMITER_RESULT(path), ['touched']))
|
|
123
124
|
]);
|
|
124
125
|
})();
|
|
@@ -130,7 +131,7 @@ export const insertRecord = async (builder, config, accessIdWithoutLimit, value,
|
|
|
130
131
|
|
|
131
132
|
const [instanceData, resultData] = await Promise.all([
|
|
132
133
|
sqlite.executeSql(`SELECT access_id, size FROM ${LIMITER_DATA(path)} WHERE access_id = ?`, [accessIdWithoutLimit]),
|
|
133
|
-
sqlite.executeSql(`SELECT
|
|
134
|
+
sqlite.executeSql(`SELECT access_id_limiter, size FROM ${LIMITER_RESULT(path)} WHERE access_id_limiter = ?`, [resultAccessId])
|
|
134
135
|
]).then(r =>
|
|
135
136
|
r.map(v => v[0].rows.item(0))
|
|
136
137
|
);
|
|
@@ -150,16 +151,22 @@ export const insertRecord = async (builder, config, accessIdWithoutLimit, value,
|
|
|
150
151
|
data: value,
|
|
151
152
|
size: thisSize
|
|
152
153
|
});
|
|
154
|
+
const [blobData, episodeBlobData] = await Promise.all([
|
|
155
|
+
handleBigData(getStoreID(db_filename, LIMITER_DATA(path), accessIdWithoutLimit), newData),
|
|
156
|
+
isEpisode ?
|
|
157
|
+
handleBigData(getStoreID(db_filename, LIMITER_RESULT(path), resultAccessId), newResultData)
|
|
158
|
+
: Promise.resolve()
|
|
159
|
+
]);
|
|
153
160
|
|
|
154
161
|
await Promise.all([
|
|
155
162
|
sqlite.executeSql(
|
|
156
163
|
SQLITE_COMMANDS.MERGE(LIMITER_DATA(path), ['access_id', 'value', 'touched', 'size']),
|
|
157
|
-
[accessIdWithoutLimit,
|
|
164
|
+
[accessIdWithoutLimit, blobData, Date.now(), thisSize]
|
|
158
165
|
),
|
|
159
166
|
isEpisode ?
|
|
160
167
|
sqlite.executeSql(
|
|
161
|
-
SQLITE_COMMANDS.MERGE(LIMITER_RESULT(path), ['
|
|
162
|
-
[resultAccessId, accessIdWithoutLimit,
|
|
168
|
+
SQLITE_COMMANDS.MERGE(LIMITER_RESULT(path), ['access_id_limiter', 'access_id', 'value', 'touched', 'size']),
|
|
169
|
+
[resultAccessId, accessIdWithoutLimit, episodeBlobData, Date.now(), thisSize]
|
|
163
170
|
) : Promise.resolve()
|
|
164
171
|
]);
|
|
165
172
|
incrementDatabaseSize(builder, path, editionSizeOffset + resultSizeOffset);
|
|
@@ -227,18 +234,16 @@ export const getRecord = async (builder, accessIdWithoutLimit, episode = 0) => {
|
|
|
227
234
|
const record = await useSqliteLinearAccessId(builder, accessIdWithoutLimit, 'database')(async sqlite => {
|
|
228
235
|
const resultAccessId = `${accessIdWithoutLimit}-${limit}`;
|
|
229
236
|
|
|
230
|
-
const
|
|
231
|
-
isEpisode ? sqlite.executeSql(`SELECT * FROM ${LIMITER_RESULT(path)} WHERE
|
|
237
|
+
const qData = await (
|
|
238
|
+
isEpisode ? sqlite.executeSql(`SELECT * FROM ${LIMITER_RESULT(path)} WHERE access_id_limiter = ?`, [resultAccessId]) :
|
|
232
239
|
sqlite.executeSql(`SELECT * FROM ${LIMITER_DATA(path)} WHERE access_id = ?`, [accessIdWithoutLimit])
|
|
233
|
-
).then(v =>
|
|
234
|
-
|
|
235
|
-
if (d) return deserializeBSON(d.value, true);
|
|
236
|
-
}).catch(() => null);
|
|
240
|
+
).then(v => v[0].rows.item(0)).catch(() => null);
|
|
241
|
+
const thisData = qData && deserializeBSON(await parseBigData(qData.value), true);
|
|
237
242
|
|
|
238
243
|
if (!thisData) return null;
|
|
239
244
|
|
|
240
245
|
if (isEpisode) {
|
|
241
|
-
await sqlite.executeSql(SQLITE_COMMANDS.UPDATE_COLUMNS(LIMITER_RESULT(path), ['touched'], '
|
|
246
|
+
await sqlite.executeSql(SQLITE_COMMANDS.UPDATE_COLUMNS(LIMITER_RESULT(path), ['touched'], 'access_id_limiter = ?'), [Date.now(), resultAccessId]);
|
|
242
247
|
return [thisData.data];
|
|
243
248
|
}
|
|
244
249
|
|
|
@@ -460,20 +465,30 @@ export const addPendingWrites = async (builder, writeId, result) => {
|
|
|
460
465
|
const pathFinder = {};
|
|
461
466
|
|
|
462
467
|
await Promise.all(colListing.map(async access_id =>
|
|
463
|
-
useSqliteLinearAccessId(builder, access_id, 'database')(async sqlite => {
|
|
464
|
-
const data = await sqlite.executeSql(`SELECT * FROM ${LIMITER_DATA(path)} WHERE access_id = ?`, [access_id]).then(v =>
|
|
465
|
-
v[0].rows.
|
|
466
|
-
|
|
468
|
+
useSqliteLinearAccessId(builder, access_id, 'database')(async (sqlite, db_filename) => {
|
|
469
|
+
const data = await sqlite.executeSql(`SELECT * FROM ${LIMITER_DATA(path)} WHERE access_id = ?`, [access_id]).then(async v => {
|
|
470
|
+
const d = v[0].rows.item(0);
|
|
471
|
+
return [d.access_id, deserializeBSON(await parseBigData(d.value), true)];
|
|
472
|
+
});
|
|
467
473
|
await MutateDataInstance(data, path =>
|
|
468
474
|
pathFinder[path] || (
|
|
469
475
|
pathFinder[path] = sqlite.executeSql(`SELECT value FROM ${LIMITER_DATA(path)}`).then(v =>
|
|
470
|
-
|
|
476
|
+
Promise.all(
|
|
477
|
+
v[0].rows.raw().map(async d =>
|
|
478
|
+
deserializeBSON(await parseBigData(d.value), true).data
|
|
479
|
+
)
|
|
480
|
+
).then(r => r.flat())
|
|
471
481
|
).catch(() => [])
|
|
472
482
|
)
|
|
473
483
|
);
|
|
484
|
+
const editedBlobData = await handleBigData(
|
|
485
|
+
getStoreID(db_filename, LIMITER_DATA(path), access_id),
|
|
486
|
+
serializeToBase64(data[1])
|
|
487
|
+
);
|
|
488
|
+
|
|
474
489
|
await sqlite.executeSql(
|
|
475
490
|
SQLITE_COMMANDS.MERGE(LIMITER_DATA(path), ['access_id', 'value', 'touched', 'size']),
|
|
476
|
-
[access_id,
|
|
491
|
+
[access_id, editedBlobData, Date.now(), data[1].size]
|
|
477
492
|
);
|
|
478
493
|
})
|
|
479
494
|
));
|
|
@@ -709,15 +724,21 @@ export const removePendingWrite = async (builder, writeId, revert) => {
|
|
|
709
724
|
if (io) {
|
|
710
725
|
RevertMutation(getLodash(CacheStore.DatabaseStore, [projectUrl, dbUrl, dbName, path, 'instance', access_id]));
|
|
711
726
|
} else {
|
|
712
|
-
await useSqliteLinearAccessId(builder, access_id, 'database')(async sqlite => {
|
|
713
|
-
const colObj = await sqlite.executeSql(`SELECT * FROM ${LIMITER_DATA(path)} WHERE access_id = ?`, [access_id]).then(v =>
|
|
714
|
-
v[0].rows.
|
|
715
|
-
|
|
727
|
+
await useSqliteLinearAccessId(builder, access_id, 'database')(async (sqlite, db_filename) => {
|
|
728
|
+
const colObj = await sqlite.executeSql(`SELECT * FROM ${LIMITER_DATA(path)} WHERE access_id = ?`, [access_id]).then(async v => {
|
|
729
|
+
const d = v[0].rows.item(0);
|
|
730
|
+
return deserializeBSON(await parseBigData(d.value));
|
|
731
|
+
}).catch(() => null);
|
|
716
732
|
if (!colObj) return;
|
|
717
733
|
RevertMutation(colObj);
|
|
734
|
+
const revertedBlobData = await handleBigData(
|
|
735
|
+
getStoreID(db_filename, LIMITER_DATA(path), access_id),
|
|
736
|
+
serializeToBase64(colObj)
|
|
737
|
+
);
|
|
738
|
+
|
|
718
739
|
await sqlite.executeSql(
|
|
719
740
|
SQLITE_COMMANDS.MERGE(LIMITER_DATA(path), ['access_id', 'value', 'touched', 'size']),
|
|
720
|
-
[access_id,
|
|
741
|
+
[access_id, revertedBlobData, Date.now(), colObj.size]
|
|
721
742
|
);
|
|
722
743
|
});
|
|
723
744
|
}
|
|
@@ -505,8 +505,11 @@ const findObject = async (builder, config) => {
|
|
|
505
505
|
Scoped.PendingDbReadCollective[processAccessId] = [];
|
|
506
506
|
}
|
|
507
507
|
|
|
508
|
-
|
|
509
|
-
if (
|
|
508
|
+
let staleData;
|
|
509
|
+
if (
|
|
510
|
+
retrieval.startsWith('sticky') &&
|
|
511
|
+
(staleData = await getRecordData())
|
|
512
|
+
) {
|
|
510
513
|
finalize(staleData);
|
|
511
514
|
if (retrieval !== RETRIEVAL.STICKY_RELOAD) return;
|
|
512
515
|
}
|
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
import { Buffer } from "buffer";
|
|
2
1
|
import { updateCacheStore } from "../../helpers/utils";
|
|
3
2
|
import { CacheStore, Scoped } from "../../helpers/variables";
|
|
4
3
|
import cloneDeep from "lodash/cloneDeep";
|
|
5
|
-
import {
|
|
4
|
+
import { serialize } from "entity-serializer";
|
|
6
5
|
import { SQLITE_COMMANDS, SQLITE_PATH, useSqliteLinearAccessId } from "../../helpers/sqlite_manager";
|
|
7
6
|
import { incrementFetcherSize } from "./counter";
|
|
7
|
+
import { getStoreID, handleBigData, parseBigData } from "../../helpers/fs_manager";
|
|
8
8
|
|
|
9
9
|
const { FETCH_RESOURCES } = SQLITE_PATH;
|
|
10
10
|
|
|
11
11
|
export const insertFetchResources = async (projectUrl, access_id, value) => {
|
|
12
12
|
value = cloneDeep(value);
|
|
13
|
-
const
|
|
13
|
+
const dataSize = serialize(value).byteLength;
|
|
14
14
|
|
|
15
15
|
const { io } = Scoped.ReleaseCacheData;
|
|
16
16
|
if (io) {
|
|
17
17
|
if (!CacheStore.FetchedStore[projectUrl])
|
|
18
18
|
CacheStore.FetchedStore[projectUrl] = {};
|
|
19
19
|
const b4 = CacheStore.FetchedStore[projectUrl][access_id];
|
|
20
|
-
incrementFetcherSize(projectUrl,
|
|
20
|
+
incrementFetcherSize(projectUrl, dataSize - (b4?.size || 0));
|
|
21
21
|
CacheStore.FetchedStore[projectUrl][access_id] = {
|
|
22
22
|
touched: Date.now(),
|
|
23
23
|
data: value,
|
|
24
|
-
size:
|
|
24
|
+
size: dataSize
|
|
25
25
|
};
|
|
26
26
|
} else {
|
|
27
27
|
const initNode = projectUrl;
|
|
28
28
|
|
|
29
|
-
await useSqliteLinearAccessId(FETCH_RESOURCES(projectUrl), access_id, 'httpFetch')(async sqlite => {
|
|
29
|
+
await useSqliteLinearAccessId(FETCH_RESOURCES(projectUrl), access_id, 'httpFetch')(async (sqlite, db_filename) => {
|
|
30
30
|
if (!Scoped.initedSqliteInstances.httpFetch[initNode]) {
|
|
31
31
|
Scoped.initedSqliteInstances.httpFetch[initNode] = (async () => {
|
|
32
|
-
await sqlite.executeSql(`CREATE TABLE IF NOT EXISTS main ( access_id TEXT PRIMARY KEY, value
|
|
32
|
+
await sqlite.executeSql(`CREATE TABLE IF NOT EXISTS main ( access_id TEXT PRIMARY KEY, value BLOB, touched INTEGER, size INTEGER )`).catch(() => null);
|
|
33
33
|
await Promise.allSettled([
|
|
34
34
|
sqlite.executeSql(SQLITE_COMMANDS.CREATE_INDEX('main', ['access_id'])),
|
|
35
35
|
sqlite.executeSql(SQLITE_COMMANDS.CREATE_INDEX('main', ['touched']))
|
|
@@ -41,11 +41,13 @@ export const insertFetchResources = async (projectUrl, access_id, value) => {
|
|
|
41
41
|
const b4Data = await sqlite.executeSql(`SELECT access_id, size FROM main WHERE access_id = ?`, [access_id]).then(r =>
|
|
42
42
|
r[0].rows.item(0)
|
|
43
43
|
);
|
|
44
|
+
const blobData = await handleBigData(getStoreID(db_filename, 'main', access_id), value);
|
|
45
|
+
|
|
44
46
|
await sqlite.executeSql(
|
|
45
47
|
SQLITE_COMMANDS.MERGE('main', ['access_id', 'value', 'touched', 'size']),
|
|
46
|
-
[access_id,
|
|
48
|
+
[access_id, blobData, Date.now(), dataSize]
|
|
47
49
|
);
|
|
48
|
-
incrementFetcherSize(projectUrl,
|
|
50
|
+
incrementFetcherSize(projectUrl, dataSize - (b4Data?.size || 0));
|
|
49
51
|
});
|
|
50
52
|
}
|
|
51
53
|
|
|
@@ -61,12 +63,15 @@ export const getFetchResources = async (projectUrl, access_id) => {
|
|
|
61
63
|
return record && cloneDeep(record?.data);
|
|
62
64
|
}
|
|
63
65
|
|
|
64
|
-
const res = await useSqliteLinearAccessId(FETCH_RESOURCES(projectUrl), access_id, 'httpFetch')(sqlite =>
|
|
65
|
-
sqlite.executeSql('SELECT * FROM main WHERE access_id = ?', [access_id]).
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
const res = await useSqliteLinearAccessId(FETCH_RESOURCES(projectUrl), access_id, 'httpFetch')(async sqlite => {
|
|
67
|
+
const query = await sqlite.executeSql('SELECT * FROM main WHERE access_id = ?', [access_id]).catch(() => null);
|
|
68
|
+
|
|
69
|
+
const rawData = query && query[0].rows.item(0).value;
|
|
70
|
+
if (!rawData) return null;
|
|
71
|
+
|
|
72
|
+
const data = await parseBigData(rawData);
|
|
73
|
+
await sqlite.executeSql(SQLITE_COMMANDS.UPDATE_COLUMNS('main', ['touched'], 'access_id = ?'), [Date.now(), access_id]);
|
|
74
|
+
return data;
|
|
75
|
+
});
|
|
71
76
|
return res;
|
|
72
77
|
}
|
|
@@ -122,8 +122,11 @@ export const mfetch = async (input = '', init, config) => {
|
|
|
122
122
|
Scoped.PendingFetchCollective[processReqId] = [];
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
|
|
126
|
-
if (
|
|
125
|
+
let reqData;
|
|
126
|
+
if (
|
|
127
|
+
retrieval.startsWith('sticky') &&
|
|
128
|
+
(reqData = await getFetchResources(projectUrl, reqId))
|
|
129
|
+
) {
|
|
127
130
|
resolveCache(reqData);
|
|
128
131
|
if (retrieval !== RETRIEVAL.STICKY_RELOAD) return;
|
|
129
132
|
}
|