Skip to content

Commit 3a622f1

Browse files
jabzajabza
andauthored
Use Promise chaining to enforce read/write queue (#699)
* Use Promise chaining to enforce read/write queue * Wrap flatfile request chaining in function Co-authored-by: Thomas Kilsby <[email protected]>
1 parent de002e1 commit 3a622f1

1 file changed

Lines changed: 41 additions & 18 deletions

File tree

src/server/db/flatfile.ts

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,17 @@ import { State, Server, LogEntry } from '../../types';
1414
*/
1515
export class FlatFile extends StorageAPI.Async {
1616
private games: {
17-
init: (opts: object) => void;
18-
setItem: (id: string, value: any) => void;
19-
getItem: (id: string) => State | Server.GameMetadata | LogEntry[];
20-
removeItem: (id: string) => void;
17+
init: (opts: object) => Promise<void>;
18+
setItem: (id: string, value: any) => Promise<any>;
19+
getItem: (id: string) => Promise<State | Server.GameMetadata | LogEntry[]>;
20+
removeItem: (id: string) => Promise<void>;
2121
clear: () => {};
22-
keys: () => string[];
22+
keys: () => Promise<string[]>;
2323
};
2424
private dir: string;
2525
private logging?: boolean;
2626
private ttl?: boolean;
27+
private requests: Promise<any>;
2728

2829
constructor({
2930
dir,
@@ -39,6 +40,14 @@ export class FlatFile extends StorageAPI.Async {
3940
this.dir = dir;
4041
this.logging = logging || false;
4142
this.ttl = ttl || false;
43+
this.requests = Promise.resolve();
44+
}
45+
46+
private async request<T extends any = any>(
47+
action: () => Promise<T>
48+
): Promise<T> {
49+
this.requests = this.requests.then(action, action);
50+
return this.requests;
4251
}
4352

4453
async connect() {
@@ -56,7 +65,8 @@ export class FlatFile extends StorageAPI.Async {
5665
): Promise<void> {
5766
// Store initial state separately for easy retrieval later.
5867
const key = InitialStateKey(gameID);
59-
await this.games.setItem(key, opts.initialState);
68+
69+
await this.request(() => this.games.setItem(key, opts.initialState));
6070

6171
await this.setState(gameID, opts.initialState);
6272
await this.setMetadata(gameID, opts.metadata);
@@ -69,22 +79,30 @@ export class FlatFile extends StorageAPI.Async {
6979
let result = {} as StorageAPI.FetchFields;
7080

7181
if (opts.state) {
72-
result.state = (await this.games.getItem(gameID)) as State;
82+
result.state = (await this.request(() =>
83+
this.games.getItem(gameID)
84+
)) as State;
7385
}
7486

7587
if (opts.metadata) {
7688
const key = MetadataKey(gameID);
77-
result.metadata = (await this.games.getItem(key)) as Server.GameMetadata;
89+
result.metadata = (await this.request(() =>
90+
this.games.getItem(key)
91+
)) as Server.GameMetadata;
7892
}
7993

8094
if (opts.log) {
8195
const key = LogKey(gameID);
82-
result.log = (await this.games.getItem(key)) as LogEntry[];
96+
result.log = (await this.request(() =>
97+
this.games.getItem(key)
98+
)) as LogEntry[];
8399
}
84100

85101
if (opts.initialState) {
86102
const key = InitialStateKey(gameID);
87-
result.initialState = (await this.games.getItem(key)) as State;
103+
result.initialState = (await this.request(() =>
104+
this.games.getItem(key)
105+
)) as State;
88106
}
89107

90108
return result as StorageAPI.FetchResult<O>;
@@ -98,27 +116,32 @@ export class FlatFile extends StorageAPI.Async {
98116
if (deltalog && deltalog.length > 0) {
99117
const key = LogKey(id);
100118
const log: LogEntry[] =
101-
((await this.games.getItem(key)) as LogEntry[]) || [];
102-
await this.games.setItem(key, log.concat(deltalog));
119+
((await this.request(() => this.games.getItem(key))) as LogEntry[]) ||
120+
[];
121+
122+
await this.request(() => this.games.setItem(key, log.concat(deltalog)));
103123
}
104-
return await this.games.setItem(id, state);
124+
125+
return await this.request(() => this.games.setItem(id, state));
105126
}
106127

107128
async setMetadata(id: string, metadata: Server.GameMetadata): Promise<void> {
108129
const key = MetadataKey(id);
109-
return await this.games.setItem(key, metadata);
130+
131+
return await this.request(() => this.games.setItem(key, metadata));
110132
}
111133

112134
async wipe(id: string) {
113135
var keys = await this.games.keys();
114136
if (!(keys.indexOf(id) > -1)) return;
115-
await this.games.removeItem(id);
116-
await this.games.removeItem(LogKey(id));
117-
await this.games.removeItem(MetadataKey(id));
137+
138+
await this.request(() => this.games.removeItem(id));
139+
await this.request(() => this.games.removeItem(LogKey(id)));
140+
await this.request(() => this.games.removeItem(MetadataKey(id)));
118141
}
119142

120143
async listGames(): Promise<string[]> {
121-
const keys = await this.games.keys();
144+
const keys = await this.request(() => this.games.keys());
122145
const suffix = ':metadata';
123146
return keys
124147
.filter(k => k.endsWith(suffix))

0 commit comments

Comments
 (0)