tangled
alpha
login
or
join now
stream.place
/
streamplace
79
fork
atom
Live video on the AT Protocol
79
fork
atom
overview
issues
pulls
pipelines
app: prevent concurrent sqlite3 access
Eli Mallon
11 months ago
9839024d
4afc87bf
+76
-5
3 changed files
expand all
collapse all
unified
split
js
app
app.config.ts
storage
lock.tsx
storage.native.tsx
+9
-1
js/app/app.config.ts
reviewed
···
12
12
return config;
13
13
};
14
14
15
15
+
export const withoutNotificationsIOS: ConfigPlugin = (config) => {
16
16
+
config = withEntitlementsPlist(config, (config) => {
17
17
+
delete config.modResults["aps-environment"];
18
18
+
return config;
19
19
+
});
20
20
+
return config;
21
21
+
};
22
22
+
15
23
const withConsistentVersionNumber = (
16
24
config,
17
25
{ version }: { version: string },
···
170
178
"@react-native-firebase/messaging",
171
179
[withNotificationsIOS, {}],
172
180
]
173
173
-
: ["expo-dev-launcher"]),
181
181
+
: ["expo-dev-launcher", withoutNotificationsIOS]),
174
182
],
175
183
experiments: {
176
184
typedRoutes: true,
+38
js/app/storage/lock.tsx
reviewed
···
1
1
+
type Cont = () => void;
2
2
+
3
3
+
export class Lock {
4
4
+
private readonly queue: Cont[] = [];
5
5
+
private acquired = false;
6
6
+
7
7
+
public async acquire(): Promise<void> {
8
8
+
if (!this.acquired) {
9
9
+
this.acquired = true;
10
10
+
} else {
11
11
+
return new Promise<void>((resolve, _) => {
12
12
+
this.queue.push(resolve);
13
13
+
});
14
14
+
}
15
15
+
}
16
16
+
17
17
+
public async release(): Promise<void> {
18
18
+
if (this.queue.length === 0 && this.acquired) {
19
19
+
this.acquired = false;
20
20
+
return;
21
21
+
}
22
22
+
23
23
+
const continuation = this.queue.shift();
24
24
+
return new Promise((res: Cont) => {
25
25
+
continuation!();
26
26
+
res();
27
27
+
});
28
28
+
}
29
29
+
30
30
+
public async critical<T>(task: () => Promise<T>) {
31
31
+
await this.acquire();
32
32
+
try {
33
33
+
return await task();
34
34
+
} finally {
35
35
+
await this.release();
36
36
+
}
37
37
+
}
38
38
+
}
+29
-4
js/app/storage/storage.native.tsx
reviewed
···
1
1
import Storage from "expo-sqlite/kv-store";
2
2
import { AQStorage } from "./storage.shared";
3
3
+
import { Lock } from "./lock";
4
4
+
5
5
+
// Needed because concurrent calls seem to return with a locked database
6
6
+
const lock = new Lock();
3
7
4
8
export default class NativeStorage implements AQStorage {
5
9
async getItem(key: string): Promise<string | null> {
6
6
-
const value = await Storage.getItem(key);
7
7
-
return value ?? null;
10
10
+
return lock.critical(async () => {
11
11
+
try {
12
12
+
const value = await Storage.getItem(key);
13
13
+
return value ?? null;
14
14
+
} catch (e) {
15
15
+
console.error(`error in NativeStorage.getItem: ${e}`);
16
16
+
throw e;
17
17
+
}
18
18
+
});
8
19
}
9
20
10
21
async setItem(key: string, value: string): Promise<void> {
11
11
-
await Storage.setItem(key, value);
22
22
+
return lock.critical(async () => {
23
23
+
try {
24
24
+
await Storage.setItem(key, value);
25
25
+
} catch (e) {
26
26
+
console.error(`error in NativeStorage.setItem: ${e}`);
27
27
+
throw e;
28
28
+
}
29
29
+
});
12
30
}
13
31
14
32
async removeItem(key: string): Promise<void> {
15
15
-
await Storage.removeItem(key);
33
33
+
return lock.critical(async () => {
34
34
+
try {
35
35
+
await Storage.removeItem(key);
36
36
+
} catch (e) {
37
37
+
console.error(`error in NativeStorage.removeItem: ${e}`);
38
38
+
throw e;
39
39
+
}
40
40
+
});
16
41
}
17
42
}