Fix a few things: ready to work on basic live games
[vchess.git] / client / src / utils / storage.js
CommitLineData
6d01bb17 1import { extractTime } from "@/utils/timeControl";
ce87ac6a 2
8f5780d8
BA
3// TODO: show game structure
4//const newItem = [
5// { gameId: "", players: [], timeControl: "", clocks: [] }
6//];
7
8function dbOperation(callback)
9{
10 let db = null;
11 let DBOpenRequest = window.indexedDB.open("vchess", 4);
12
13 DBOpenRequest.onerror = function(event) {
14 alert("Database error: " + event.target.errorCode);
15 };
16
17 DBOpenRequest.onsuccess = function(event) {
18 db = DBOpenRequest.result;
19 callback(db);
20 db.close();
21 };
22
23 DBOpenRequest.onupgradeneeded = function(event) {
24 let db = event.target.result;
25 db.onerror = function(event) {
26 alert("Error while loading database: " + event.target.errorCode);
27 };
28 // Create objectStore for vchess->games
29 db.createObjectStore("games", { keyPath: "gameId" });
30 }
31}
32
33// Optional callback to get error status
34function addGame(game, callback)
35{
36 dbOperation((db) => {
37 let transaction = db.transaction(["games"], "readwrite");
38 if (callback)
39 {
40 transaction.oncomplete = function() {
41 callback({}); //everything's fine
42 }
43 transaction.onerror = function() {
44 callback({errmsg: "addGame failed: " + transaction.error});
45 };
46 }
47 let objectStore = transaction.objectStore("games");
48 objectStore.add(game);
49 });
50}
51
52// Clear current live game from localStorage
53function clear() {
54 localStorage.deleteItem("gameInfo");
55 localStorage.deleteItem("gameState");
56}
57
58// Current live game:
59function getCurrent()
60{
61 return Object.assign({},
62 JSON.parse(localStorage.getItem("gameInfo")),
63 JSON.parse(localStorage.getItem("gameState")));
64}
65
66// Only called internally after a score update
67function transferToDb()
68{
69 addGame(getCurrent(), (err) => {
70 if (!!err.errmsg)
71 return err;
72 clear();
73 });
74}
75
d2634386 76export const GameStorage =
59d58d7d 77{
8f5780d8 78 // localStorage:
6d01bb17 79 init: function(o)
d2634386 80 {
6d01bb17
BA
81 // Extract times (in [milli]seconds), set clocks, store in localStorage
82 const tc = extractTime(o.timeControl);
8f5780d8
BA
83
84 // game infos: constant
85 const gameInfo =
86 {
87 gameId: o.gameId,
88 vname: o.vname,
8f5780d8 89 fenStart: o.fenStart,
4b0384fa 90 players: o.players,
8f5780d8
BA
91 timeControl: o.timeControl,
92 increment: tc.increment,
93 mode: "live", //function for live games only
94 };
95
96 // game state: will be updated
97 const gameState =
98 {
99 fen: o.fenStart,
100 moves: [],
101 clocks: [...Array(o.players.length)].fill(tc.mainTime),
102 started: [...Array(o.players.length)].fill(false),
103 score: "*",
104 };
105
106 localStorage.setItem("gameInfo", JSON.stringify(gameInfo));
107 localStorage.setItem("gameState", JSON.stringify(gameState));
d2634386 108 },
59d58d7d 109
8f5780d8
BA
110 // localStorage:
111 // TODO: also option to takeback a move ? Is fen included in move ?
4c177b7f 112 // NOTE: for live games only (all on server for corr)
8f5780d8 113 update: function(fen, moves, clocks, started, score)
4c177b7f 114 {
8f5780d8
BA
115 let gameState = JSON.parse(localStorage.getItem("gameState"));
116 if (!!fen)
4c177b7f 117 {
8f5780d8
BA
118 gameState.moves = moves;
119 gameState.fen = fen;
120 gameState.clocks = clocks;
4c177b7f 121 }
8f5780d8
BA
122 if (!!started)
123 gameState.started = started;
4c177b7f 124 if (!!score)
8f5780d8
BA
125 gameState.score = score;
126 localStorage.setItem("gameState", JSON.stringify(gameState));
127 if (!!score && score != "*")
128 transferToDb(); //game is over
4c177b7f
BA
129 },
130
8f5780d8
BA
131 // indexedDB:
132 // Since DB requests are asynchronous, require a callback using the result
133 // TODO: option for remote retrieval (third arg, or just "gameRef")
d6c1bf37 134 getLocal: function(gameId, callback)
d2634386 135 {
8f5780d8
BA
136 let games = [];
137 dbOperation((db) => {
138 // TODO: if gameId is provided, limit search to gameId (just .get(gameId). ...)
139 let objectStore = db.transaction('games').objectStore('games');
140 objectStore.openCursor().onsuccess = function(event) {
141 var cursor = event.target.result;
142 // if there is still another cursor to go, keep runing this code
143 if (cursor)
144 {
145 games.push(cursor.value);
146 cursor.continue();
147 }
148 else
149 callback(games);
150 }
151 });
d2634386 152 },
59d58d7d 153
8f5780d8
BA
154 // Delete a game in indexedDB
155 remove: function(gameId, callback)
d2634386 156 {
8f5780d8
BA
157 dbOperation((db) => {
158 let transaction = db.transaction(["games"], "readwrite");
159 if (callback)
160 {
161 transaction.oncomplete = function() {
162 callback({}); //everything's fine
163 }
164 transaction.onerror = function() {
165 callback({errmsg: "deleteGame failed: " + transaction.error});
166 };
167 }
168 transaction.objectStore("games").delete(gameId);
169 });
d2634386 170 },
59d58d7d 171
8f5780d8
BA
172 // Retrieve any live game from its identifiers (remote or not, running or not)
173 // NOTE: need callback because result might be obtained asynchronously
174 get: function(gameRef, callback)
d2634386
BA
175 {
176 const gid = gameRef.id;
177 const rid = gameRef.rid; //may be blank
8f5780d8 178 if (!!rid)
d2634386 179 {
8f5780d8
BA
180 // TODO: send request to server which forward to user sid == rid,
181 // need to listen to "remote game" event in main hall ?
182 return callback({}); //means "the game will arrive later" (TODO...)
d2634386 183 }
8f5780d8
BA
184
185 const gameInfoStr = localStorage.getItem("gameInfo");
186 if (gameInfoStr)
d2634386 187 {
8f5780d8
BA
188 const gameInfo = JSON.parse(gameInfoStr);
189 if (gameInfo.gameId == gid)
190 {
191 const gameState = JSON.parse(localStorage.getItem("gameState"));
192 return callback(Object.assign({}, gameInfo, gameState));
193 }
d2634386 194 }
8f5780d8
BA
195
196 // Game is local and not running
d6c1bf37 197 GameStorage.getLocal(gid, callback);
d2634386
BA
198 },
199};