05aaef7404fc4bb90e6ba72c0552804efb01802a
[vchess.git] / client / src / utils / gameStorage.js
1 // Game object: {
2 // // Static informations:
3 // id: string
4 // vname: string,
5 // fenStart: string,
6 // players: array of sid+id+name,
7 // timeControl: string,
8 // increment: integer (seconds),
9 // mode: string ("live" or "corr")
10 // imported: boolean (optional, default false)
11 // // Game (dynamic) state:
12 // fen: string,
13 // moves: array of Move objects,
14 // clocks: array of integers,
15 // initime: array of integers (when clock start running),
16 // score: string (several options; '*' == running),
17 // }
18
19 import { ajax } from "@/utils/ajax";
20 import { store } from "@/store";
21
22 function dbOperation(callback)
23 {
24 let db = null;
25 let DBOpenRequest = window.indexedDB.open("vchess", 4);
26
27 DBOpenRequest.onerror = function(event) {
28 alert(store.state.tr["Database error:"] + " " + event.target.errorCode);
29 };
30
31 DBOpenRequest.onsuccess = function(event) {
32 db = DBOpenRequest.result;
33 callback(db);
34 db.close();
35 };
36
37 DBOpenRequest.onupgradeneeded = function(event) {
38 let db = event.target.result;
39 db.onerror = function(event) {
40 alert(store.state.tr["Error while loading database:"] + " " + event.target.errorCode);
41 };
42 // Create objectStore for vchess->games
43 let objectStore = db.createObjectStore("games", { keyPath: "id" });
44 objectStore.createIndex("score", "score"); //to search by game result
45 }
46 }
47
48 export const GameStorage =
49 {
50 // Optional callback to get error status
51 add: function(game, callback)
52 {
53 dbOperation((db) => {
54 let transaction = db.transaction("games", "readwrite");
55 if (callback)
56 {
57 transaction.oncomplete = function() {
58 callback({}); //everything's fine
59 }
60 transaction.onerror = function() {
61 callback({errmsg: store.state.tr["Game retrieval failed:"] + " " + transaction.error});
62 };
63 }
64 let objectStore = transaction.objectStore("games");
65 objectStore.add(game);
66 });
67 },
68
69 // TODO: also option to takeback a move ?
70 // obj: chat, move, fen, clocks, score[Msg], initime, ...
71 update: function(gameId, obj)
72 {
73 if (Number.isInteger(gameId) || !isNaN(parseInt(gameId)))
74 {
75 // corr: only move, fen and score
76 ajax(
77 "/games",
78 "PUT",
79 {
80 gid: gameId,
81 newObj:
82 {
83 // Some fields may be undefined:
84 chat: obj.chat,
85 move: obj.move,
86 fen: obj.fen,
87 score: obj.score,
88 scoreMsg: obj.scoreMsg,
89 drawOffer: obj.drawOffer,
90 }
91 }
92 );
93 }
94 else
95 {
96 // live
97 dbOperation((db) => {
98 let objectStore = db.transaction("games", "readwrite").objectStore("games");
99 objectStore.get(gameId).onsuccess = function(event) {
100 const game = event.target.result;
101 Object.keys(obj).forEach(k => {
102 if (k == "move")
103 game.moves.push(obj[k]);
104 else
105 game[k] = obj[k];
106 });
107 objectStore.put(game); //save updated data
108 }
109 });
110 }
111 },
112
113 // Retrieve all local games (running, completed, imported...)
114 getAll: function(callback)
115 {
116 dbOperation((db) => {
117 let objectStore = db.transaction('games').objectStore('games');
118 let games = [];
119 objectStore.openCursor().onsuccess = function(event) {
120 let cursor = event.target.result;
121 // if there is still another cursor to go, keep running this code
122 if (cursor)
123 {
124 games.push(cursor.value);
125 cursor.continue();
126 }
127 else
128 callback(games);
129 }
130 });
131 },
132
133 // Retrieve any game from its identifiers (locally or on server)
134 // NOTE: need callback because result is obtained asynchronously
135 get: function(gameId, callback)
136 {
137 // corr games identifiers are integers
138 if (Number.isInteger(gameId) || !isNaN(parseInt(gameId)))
139 {
140 ajax("/games", "GET", {gid:gameId}, res => {
141 let game = res.game;
142 game.moves.forEach(m => {
143 m.squares = JSON.parse(m.squares);
144 });
145 callback(game);
146 });
147 }
148 else //local game
149 {
150 dbOperation((db) => {
151 let objectStore = db.transaction('games').objectStore('games');
152 objectStore.get(gameId).onsuccess = function(event) {
153 callback(event.target.result);
154 }
155 });
156 }
157 },
158
159 getCurrent: function(callback)
160 {
161 dbOperation((db) => {
162 let objectStore = db.transaction('games').objectStore('games');
163 objectStore.get("*").onsuccess = function(event) {
164 callback(event.target.result);
165 };
166 });
167 },
168
169 // Delete a game in indexedDB
170 remove: function(gameId, callback)
171 {
172 dbOperation((db) => {
173 let transaction = db.transaction(["games"], "readwrite");
174 if (callback)
175 {
176 transaction.oncomplete = function() {
177 callback({}); //everything's fine
178 }
179 transaction.onerror = function() {
180 callback({errmsg: store.state.tr["Game removal failed:"] + " " + transaction.error});
181 };
182 }
183 transaction.objectStore("games").delete(gameId);
184 });
185 },
186 };