add and start using indexeddb via emscripten APIs

Replace a couple of load/store actions with new APIs that do so
asynchronously (using indexeddb underneath, via emscripten APIs.)
Required restructuring how app starts. More changes to come. The idea is
to replace wordlist storage: this'll keep 'em smaller and not require
conversion to string.
This commit is contained in:
Eric House 2021-03-02 21:10:59 -08:00
parent 55f590ca0b
commit 2a6931fdcf
4 changed files with 164 additions and 44 deletions

View file

@ -36,6 +36,9 @@ typedef enum { UNPAUSED,
typedef XP_Bool (*OnOneProc)(void* closure, const XP_UCHAR* indx);
typedef void (*OnStoreProc)( void* closure, bool success );
typedef void (*OnLoadProc)( void* closure, const char* key, void* data, int len );
typedef struct _DUtilVtable {
XP_U32 (*m_dutil_getCurSeconds)( XW_DUtilCtxt* duc, XWEnv xwe );
const XP_UCHAR* (*m_dutil_getUserString)( XW_DUtilCtxt* duc, XWEnv xwe,
@ -56,6 +59,11 @@ typedef struct _DUtilVtable {
const XP_UCHAR* fallbackKey, // PENDING() remove this after a few months.
void* data, XP_U32* lenp );
void (*m_dutil_startStore)( XW_DUtilCtxt* duc, XWEnv xwe, const XP_UCHAR* key,
const void* data, XP_U32 len, OnStoreProc proc, void* closure );
void (*m_dutil_startLoad)( XW_DUtilCtxt* duc, XWEnv xwe, const XP_UCHAR* key,
OnLoadProc proc, void* closure );
#ifdef XWFEATURE_INDEXSTORE
void (*m_dutil_storeIndxStream)( XW_DUtilCtxt* duc, XWEnv xwe, const XP_UCHAR* key,
const XP_UCHAR* indx, XWStreamCtxt* data );
@ -153,6 +161,11 @@ void dutil_super_init( MPFORMAL XW_DUtilCtxt* dutil );
#define dutil_removeAllIndx(duc, indx) \
(duc)->vtable.m_dutil_removeAllIndx((duc), (indx));
#define dutil_startStore( duc, xwe, key, data, len, proc, closure ) \
(duc)->vtable.m_dutil_startStore((duc), (xwe), (key), (data), (len), (proc), (closure) )
#define dutil_startLoad( duc, xwe, key, proc, closure ) \
(duc)->vtable.m_dutil_startLoad((duc), (xwe), (key), (proc), (closure) )
#ifdef XWFEATURE_SMS
# define dutil_phoneNumbersSame(duc,e,p1,p2) \
(duc)->vtable.m_dutil_phoneNumbersSame( (duc), (e), (p1), (p2) )

View file

@ -611,25 +611,14 @@ onDeleteConfirmed( void* closure, bool confirmed )
}
}
static void
getPlayerName( Globals* globals, char* playerName, size_t buflen )
{
XP_U32 len = buflen;
dutil_loadPtr( globals->dutil, NULL, KEY_PLAYER_NAME, NULL,
playerName, &len );
XP_LOGFF( "after: len: %d", len );
if ( 0 == len ) { /* not found? */
strcpy( playerName, "Player 1" );
}
}
static void
onPlayerNamed( void* closure, const char* name )
{
CAST_GLOB(Globals*, globals, closure);
if ( !!name ) {
dutil_storePtr( globals->dutil, NULL, KEY_PLAYER_NAME,
name, 1 + strlen(name) );
strncpy( globals->playerName, name, VSIZE(globals->playerName) );
dutil_startStore( globals->dutil, NULL, KEY_PLAYER_NAME,
name, 1 + strlen(name), NULL, NULL );
}
}
@ -655,9 +644,7 @@ onDeviceButton( void* closure, const char* button )
curGS->gameName );
call_confirm( globals, msg, onDeleteConfirmed, curGS );
} else if ( 0 == strcmp(button, BUTTON_NAME ) ) {
char playerName[32];
getPlayerName( globals, playerName, sizeof(playerName)-1 );
call_get_string( "Set your (local) player name", playerName,
call_get_string( "Set your (local) player name", globals->playerName,
onPlayerNamed, globals );
}
}
@ -783,8 +770,9 @@ initDeviceGlobals( Globals* globals )
static void
storeCurOpen( GameState* gs )
{
dutil_storePtr( gs->globals->dutil, NULL, KEY_LAST_GID,
&gs->gi.gameID, sizeof(gs->gi.gameID) );
dutil_startStore( gs->globals->dutil, NULL, KEY_LAST_GID,
&gs->gi.gameID, sizeof(gs->gi.gameID),
NULL, NULL );
}
static void
@ -830,11 +818,8 @@ newFromInvite( Globals* globals, const NetLaunchInfo* invite )
gs->util = wasm_util_make( MPPARM(globals->mpool) &gs->gi,
globals->dutil, gs );
char playerName[32];
getPlayerName( globals, playerName, sizeof(playerName) );
game_makeFromInvite( MPPARM(globals->mpool) NULL, invite,
&gs->game, &gs->gi, playerName,
&gs->game, &gs->gi, globals->playerName,
gs->util, globals->draw,
&globals->cp, &globals->procs );
if ( invite->gameName[0] ) {
@ -1052,9 +1037,6 @@ loadAndDraw( Globals* globals, const NetLaunchInfo* invite,
if ( !gs ) {
DictionaryCtxt* dict = loadAnyDict( globals );
if ( !!dict ) {
char playerName[32];
getPlayerName( globals, playerName, sizeof(playerName) );
gs = newGameState( globals );
gs->gi.serverRole = !!params && !params->isRobotNotRemote
? SERVER_ISSERVER : SERVER_STANDALONE;
@ -1067,7 +1049,7 @@ loadAndDraw( Globals* globals, const NetLaunchInfo* invite,
dict_getShortName(dict) );
gs->gi.nPlayers = 2;
gs->gi.boardSize = 15;
gs->gi.players[0].name = copyString( globals->mpool, playerName );
gs->gi.players[0].name = copyString( globals->mpool, globals->playerName );
gs->gi.players[0].isLocal = XP_TRUE;
gs->gi.players[0].robotIQ = 0;
@ -1562,6 +1544,44 @@ inviteFromArgv( Globals* globals, NetLaunchInfo* nlip,
return success;
}
typedef struct _GameStartState {
Globals* globals;
NetLaunchInfo nli;
NetLaunchInfo* nlip;
char lastKey[16];
int nWanted;
} GameStartState;
/* Will get called twice, once with KEY_PLAYER_NAME and once with KEY_LAST_GID */
static void
onReqsLoaded(void* closure, const char* key, void* data, int dataLen)
{
GameStartState* gss = (GameStartState*)closure;
Globals* globals = gss->globals;
XP_LOGFF( "(key: %s, len: %d)", key, dataLen );
if ( 0 == strcmp( key, KEY_LAST_GID ) ) {
int gameID = 0;
if ( !!data && dataLen == sizeof(gameID) ) {
gameID = *(int*)data;
formatGameID( gss->lastKey, sizeof(gss->lastKey), gameID );
}
XP_LOGFF( "loaded KEY_LAST_GID: %s", gss->lastKey );
} else if ( 0 == strcmp( key, KEY_PLAYER_NAME ) ) {
if ( !!data && 0 < dataLen && dataLen < VSIZE(globals->playerName) ) {
XP_MEMCPY( globals->playerName, data, dataLen );
} else {
strcat( globals->playerName, "Player 1" );
}
}
if ( 0 == --gss->nWanted ) {
loadAndDraw( globals, gss->nlip, gss->lastKey, NULL );
updateDeviceButtons( globals );
XP_FREE( globals->mpool, gss );
}
}
static void
initNoReturn( int argc, const char** argv )
{
@ -1574,10 +1594,12 @@ initNoReturn( int argc, const char** argv )
globals._GUARD = GUARD_GLOB;
#endif
NetLaunchInfo nli = {0};
NetLaunchInfo* nlip = NULL;
if ( inviteFromArgv( &globals, &nli, argc, argv ) ) {
nlip = &nli;
/* I don't think this ever gets popped off stack, but to be safe.... */
GameStartState* gss = XP_CALLOC( globals.mpool, sizeof(*gss) );
gss->globals = &globals;
if ( inviteFromArgv( &globals, &gss->nli, argc, argv ) ) {
gss->nlip = &gss->nli;
}
SDL_Init( SDL_INIT_EVENTS );
@ -1586,24 +1608,16 @@ initNoReturn( int argc, const char** argv )
SDL_CreateWindowAndRenderer( WINDOW_WIDTH, WINDOW_HEIGHT, 0,
&globals.window, &globals.renderer );
/* whip the canvas to background */
/* wipe the canvas to background */
SDL_SetRenderDrawColor( globals.renderer, 155, 155, 155, 255 );
SDL_RenderClear( globals.renderer );
initDeviceGlobals( &globals );
char lastKey[16] = {0};
int gameID = 0;
XP_U32 len = sizeof(gameID);
dutil_loadPtr( globals.dutil, NULL, KEY_LAST_GID, NULL,
(XP_U8*)&gameID, &len );
if ( len == sizeof(gameID) ) {
formatGameID( lastKey, sizeof(lastKey), gameID );
}
XP_LOGFF( "loaded KEY_LAST_GID: %s", lastKey );
loadAndDraw( &globals, nlip, lastKey, NULL );
updateDeviceButtons( &globals );
/* Load the two bits we need from storage before starting */
dutil_startLoad( globals.dutil, NULL, KEY_PLAYER_NAME, onReqsLoaded, gss );
dutil_startLoad( globals.dutil, NULL, KEY_LAST_GID, onReqsLoaded, gss );
gss->nWanted = 2;
emscripten_set_main_loop_arg( looper, &globals, -1, 1 );
}

View file

@ -64,6 +64,8 @@ typedef struct Globals {
CommonPrefs cp;
DictMgrCtxt* dictMgr;
char playerName[32];
#ifdef MEM_DEBUG
MemPoolCtx* mpool;
#endif

View file

@ -30,6 +30,8 @@
#include "wasmasm.h"
#include "wasmdict.h"
#define DB_NAME "kvstore0.1"
typedef struct _WasmDUtilCtxt {
XW_DUtilCtxt super;
} WasmDUtilCtxt;
@ -283,6 +285,93 @@ wasm_dutil_storePtr( XW_DUtilCtxt* duc, XWEnv xwe, const XP_UCHAR* key,
XP_FREE( duc->mpool, out );
}
typedef struct _StoreState {
XW_DUtilCtxt* duc;
OnStoreProc proc;
void* closure;
} StoreState;
static void
callStoredAndFree( void* closure, bool success )
{
if ( !!closure ) {
StoreState* ss = (StoreState*)closure;
(*ss->proc)(ss->closure, success);
XP_FREE( ss->duc->mpool, ss );
}
}
static void
onStoreSuccess( void* closure )
{
callStoredAndFree( closure, true );
}
static void
onStoreError( void* closure )
{
callStoredAndFree( closure, false );
}
static void
wasm_dutil_startStore( XW_DUtilCtxt* duc, XWEnv xwe, const XP_UCHAR* key,
const void* data, XP_U32 len, OnStoreProc proc, void* closure )
{
XP_LOGFF("(key: %s)", key);
StoreState* ss = NULL;
if ( !!proc ) {
ss = XP_MALLOC( duc->mpool, sizeof(*ss) );
ss->duc = duc;
ss->proc = proc;
ss->closure = closure;
}
emscripten_idb_async_store( DB_NAME, key, (void*)data, len,
ss, onStoreSuccess, onStoreError );
}
typedef struct _LoadState {
XW_DUtilCtxt* duc;
OnLoadProc proc;
void* closure;
char* key;
} LoadState;
static void
callLoadedAndFree(void* closure, void* data, int len )
{
LoadState* ls = (LoadState*)closure;
(*ls->proc)(ls->closure, ls->key, data, len );
XP_FREE( ls->duc->mpool, (void*)ls->key );
XP_FREE( ls->duc->mpool, ls );
}
static void
onLoadSuccess( void* closure, void* data, int len )
{
callLoadedAndFree( closure, data, len );
}
static void
onLoadError( void *closure )
{
callLoadedAndFree( closure, NULL, 0 );
}
static void
wasm_dutil_startLoad( XW_DUtilCtxt* duc, XWEnv xwe, const XP_UCHAR* key,
OnLoadProc proc, void* closure )
{
LoadState* ls = XP_MALLOC( duc->mpool, sizeof(*ls) );
ls->duc = duc;
ls->proc = proc;
ls->closure = closure;
ls->key = NULL;
replaceStringIfDifferent( duc->mpool, &ls->key, key );
emscripten_idb_async_load(DB_NAME, key, ls, onLoadSuccess, onLoadError);
}
static void
wasm_dutil_storeIndxStream( XW_DUtilCtxt* duc, XWEnv xwe, const XP_UCHAR* key,
const XP_UCHAR* indx, XWStreamCtxt* data )
@ -533,6 +622,8 @@ wasm_dutil_make( MPFORMAL VTableMgr* vtMgr, void* closure )
SET_PROC(getUserQuantityString);
SET_PROC(storePtr);
SET_PROC(loadPtr);
SET_PROC(startStore);
SET_PROC(startLoad);
#ifdef XWFEATURE_SMS
SET_PROC(phoneNumbersSame);