Commit | Line | Data |
---|---|---|
6d01bb17 | 1 | import { extractTime } from "@/utils/timeControl"; |
ce87ac6a | 2 | |
8f5780d8 BA |
3 | // TODO: show game structure |
4 | //const newItem = [ | |
5 | // { gameId: "", players: [], timeControl: "", clocks: [] } | |
6 | //]; | |
7 | ||
8 | function 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 | |
34 | function 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 | |
53 | function clear() { | |
54 | localStorage.deleteItem("gameInfo"); | |
55 | localStorage.deleteItem("gameState"); | |
56 | } | |
57 | ||
58 | // Current live game: | |
59 | function 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 | |
67 | function transferToDb() | |
68 | { | |
69 | addGame(getCurrent(), (err) => { | |
70 | if (!!err.errmsg) | |
71 | return err; | |
72 | clear(); | |
73 | }); | |
74 | } | |
75 | ||
d2634386 | 76 | export 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 | }; |