download wordlists when needed for invitation

This commit is contained in:
Eric House 2021-03-05 18:21:13 -08:00
parent 3c0edb3531
commit 4f524d0bb0
7 changed files with 153 additions and 33 deletions

View file

@ -110,8 +110,21 @@ static void saveName( GameState* gs );
static bool isVisible( GameState* gs );
static int countDicts( Globals* globals );
EM_JS(void, call_get_dict, (void* closure), {
getDict(closure);
typedef void (*GotDictProc)(void* closure, const char* lc, const char* name,
uint8_t* data, int len);
EM_JS(void, call_get_dict, (const char* lc, GotDictProc proc,
void* closure), {
let langs;
if (lc) {
langs = [UTF8ToString(lc)];
} else {
langs = [navigator.language.split('-')[0]];
if (langs[0] != 'en') {
langs.push('en');
}
}
getDict(langs, proc, closure);
});
EM_JS(void, show_name, (const char* name), {
@ -315,7 +328,6 @@ sendInviteTo(GameState* gs, const MQTTDevID* remoteDevID)
nli_init( &nli, &gs->gi, &myAddr, 1, 1 );
nli_setGameName( &nli, gs->gameName );
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(globals->mpool)
globals->vtMgr );
dvc_makeMQTTInvite( globals->dutil, NULL, stream, &nli );
@ -691,6 +703,15 @@ countDicts( Globals* globals )
return count;
}
static bool
haveDictFor(Globals* globals, const char* lc)
{
int count = 0;
const XP_UCHAR* keys[] = {KEY_DICTS, lc, NULL};
dutil_forEach( globals->dutil, NULL, keys, upCounter, &count );
return 0 < count;
}
static void
updateDeviceButtons( Globals* globals )
{
@ -740,6 +761,31 @@ onMqttMsg(void* closure, const uint8_t* data, int len )
dvc_parseMQTTPacket( globals->dutil, NULL, data, len );
}
static void
storeAsDict(Globals* globals, const char* lc, const char* name,
uint8_t* data, int len )
{
char shortName[32];
sprintf( shortName, "%s", name );
char* dot = strstr(shortName, ".xwd");
if ( !!dot ) {
*dot = '\0';
}
XP_LOGFF("shortName: %s", shortName);
const XP_UCHAR* keys[] = {KEY_DICTS, lc, shortName, NULL};
dutil_storePtr( globals->dutil, NULL, keys, data, len );
}
static void
onGotDict( void* closure, const char* lc, const char* name,
uint8_t* data, int len)
{
CAST_GLOB(Globals*, globals, closure);
storeAsDict( globals, lc, name, data, len );
updateDeviceButtons( globals );
}
static void
initDeviceGlobals( Globals* globals )
{
@ -771,7 +817,7 @@ initDeviceGlobals( Globals* globals )
call_setup( globals, buf, GITREV, now, onConflict, onFocussed, onMqttMsg );
if ( 0 == countDicts( globals ) ) {
call_get_dict( globals );
call_get_dict( NULL, onGotDict, globals );
}
}
@ -840,6 +886,40 @@ newFromInvite( Globals* globals, const NetLaunchInfo* invite )
return gs;
}
typedef struct _DictDownState {
Globals* globals;
NetLaunchInfo invite;
const char* lc;
} DictDownState;
static void
onDictForInvite( void* closure, const char* lc, const char* name,
uint8_t* data, int len )
{
DictDownState* dds = (DictDownState*)closure;
if ( !!data && 0 < len ) {
storeAsDict( dds->globals, lc, name, data, len );
loadAndDraw( dds->globals, &dds->invite, NULL, NULL );
} else {
char msg[128];
sprintf( msg, "Unable to download %s worldlist for invitation", dds->lc );
call_alert( msg );
}
XP_FREE( dds->globals->mpool, dds );
}
static void
onDictConfirmed( void* closure, bool confirmed )
{
DictDownState* dds = (DictDownState*)closure;
if ( confirmed ) {
call_get_dict( dds->lc, onDictForInvite, dds );
} else {
XP_FREE( dds->globals->mpool, dds );
}
}
/* If you launch a URL that encodes an invitation, you'll get here. If it's
* the first time (the game hasn't been created yet) you'll get a new game
* that connects to the host. If you've already created the game, you'll be
@ -853,10 +933,19 @@ gameFromInvite( Globals* globals, const NetLaunchInfo* invite )
bool needsLoad = true;
GameState* gs = getSavedGame( globals, invite->gameID );
if ( !gs ) {
if ( invite->lang == 1 ) {
const char* lc = lcToLocale( invite->lang );
if ( haveDictFor(globals, lc) ) {
gs = newFromInvite( globals, invite );
} else {
call_alert( "Invitations are only supported for play in English right now." );
char msg[128];
sprintf( msg, "Invitation requires a wordlist %s for "
"language %s; download now?", invite->dict, lc );
DictDownState* dds = XP_MALLOC( globals->mpool, sizeof(*dds) );
dds->globals = globals;
dds->invite = *invite;
dds->lc = lc;
call_confirm(globals, msg, onDictConfirmed, dds);
}
}
return gs;
@ -1674,16 +1763,11 @@ cbckString( StringProc proc, void* closure, const char* str )
}
void
gotDictBinary( void* closure, const char* xwd, const char* lang,
const char* lc, int len, uint8_t* data )
gotDictBinary( GotDictProc proc, void* closure, const char* xwd,
const char* lc, uint8_t* data, int len )
{
XP_LOGFF( "xwd: %s; lang: %s, lc: %s, len: %d", xwd, lang, lc, len );
CAST_GLOB(Globals*, globals, closure);
const XP_UCHAR* keys[] = {KEY_DICTS, lc, xwd, NULL};
dutil_storePtr( globals->dutil, NULL, keys, data, len );
updateDeviceButtons( globals );
XP_LOGFF( "lc: %s, xwd: %s; len: %d", lc, xwd, len );
(*proc)(closure, lc, xwd, data, len);
}
void

View file

@ -81,7 +81,7 @@ typedef struct Globals {
#define CAST_GS(typ, var, ptr) XP_ASSERT(((typ)(ptr))->_GUARD == GUARD_GS); typ var = (typ)(ptr)
#define KEY_DICTS "dicts"
#define ROOT_PATH "/persisted"
#define ROOT_PATH "/persisted0.3"
void main_set_timer( GameState* gs, XWTimerReason why, XP_U16 when,
XWTimerProc proc, void* closure );

View file

@ -163,6 +163,16 @@ wasm_dictionary_destroy( DictionaryCtxt* dict, XWEnv xwe )
XP_FREE( dict->mpool, ctxt );
}
DictionaryCtxt*
wasm_dictionary_make_empty( Globals* globals )
{
WasmDictionaryCtxt* wdict = XP_CALLOC( globals->mpool, sizeof( *wdict ) );
dict_super_init( MPPARM(globals->mpool) (DictionaryCtxt*)wdict );
LOG_RETURNF( "%p", wdict );
return (DictionaryCtxt*)wdict;
}
DictionaryCtxt*
wasm_dictionary_make( Globals* globals, XWEnv xwe,
const char* name, uint8_t* base, size_t len )

View file

@ -26,6 +26,7 @@
DictionaryCtxt* wasm_dictionary_make( Globals* globals, XWEnv xwe,
const char* name, uint8_t* base, size_t len );
DictionaryCtxt* wasm_dictionary_make_empty( Globals* globals );
void formatDictIndx( char buf[], size_t len, const char* lang, const char* name );
#endif

View file

@ -410,6 +410,28 @@ wasm_dutil_md5sum( XW_DUtilCtxt* duc, XWEnv xwe, const XP_U8* ptr,
return NULL;
}
typedef struct _ForLangState {
XW_DUtilCtxt* duc;
XWEnv xwe;
uint8_t* ptr;
XP_U32 len;
} ForLangState;
static XP_Bool
gotForLang( void* closure, const XP_UCHAR* keys[] )
{
XP_LOGFF("name: %s", keys[2]);
ForLangState* fls = (ForLangState*)closure;
dutil_loadPtr( fls->duc, fls->xwe, keys, NULL, &fls->len );
if ( 0 < fls->len ) {
fls->ptr = XP_MALLOC( fls->duc->mpool, fls->len );
dutil_loadPtr( fls->duc, fls->xwe, keys, fls->ptr, &fls->len );
} else {
XP_LOGFF( "nothing for %s/%s", keys[1], keys[2] );
}
return NULL != fls->ptr;
}
static const DictionaryCtxt*
wasm_dutil_getDict( XW_DUtilCtxt* duc, XWEnv xwe,
XP_LangCode lang, const XP_UCHAR* dictName )
@ -429,10 +451,22 @@ wasm_dutil_getDict( XW_DUtilCtxt* duc, XWEnv xwe,
dutil_loadPtr( duc, xwe, keys, ptr, &len );
result = wasm_dictionary_make( globals, xwe, dictName, ptr, len );
dmgr_put( globals->dictMgr, xwe, dictName, result );
} else {
/* Try another dict in same language */
XP_LOGFF( "trying for another %s dict", lc );
ForLangState fls = { .duc = duc,
.xwe = xwe,
};
const char* langKeys[] = {KEY_DICTS, lc, KEY_WILDCARD, NULL};
dutil_forEach( duc, xwe, langKeys, gotForLang, &fls );
if ( !!fls.ptr ) {
result = wasm_dictionary_make( globals, xwe, dictName, fls.ptr, fls.len );
dmgr_put( globals->dictMgr, xwe, dictName, result );
}
}
}
LOG_RETURNF( "%p", result );
XP_LOGFF("(%s, %s)=>%p", lc, dictName, result );
return result;
}

View file

@ -410,11 +410,9 @@ wasm_util_altKeyDown( XW_UtilCtxt* uc, XWEnv xwe )
static DictionaryCtxt*
wasm_util_makeEmptyDict( XW_UtilCtxt* uc, XWEnv xwe )
{
LOG_FUNC(); /* firing */
XP_ASSERT(0);
/* return wasm_dictionary_make( MPPARM(uc->mpool) NULL, uc->closure, */
/* NULL, false, NULL ); */
return NULL;
WasmUtilCtx* wuctxt = (WasmUtilCtx*)uc;
GameState* gs = wuctxt->closure;
return wasm_dictionary_make_empty( gs->globals );
}
static void

View file

@ -45,18 +45,11 @@ function registerOnce(devid, gitrev, now) {
}
}
function getDict(closure) {
function getDict(langs, proc, closure) {
// set these later
let gots = {};
let langs = 'en'; // navigator.language;
if (langs) {
langs = [langs.split('-')[0]];
}
console.log('langs: ' + langs + '; langs[0]: ' + langs[0]);
if (langs[0] != 'en' ) {
langs.push('en');
}
let args = '?lc=' + langs.join('|');
console.log('args: ' + args);
fetch('/xw4/info.py/listDicts' + args, {
@ -97,8 +90,8 @@ function getDict(closure) {
dataHeap.set( new Uint8Array(data) );
// console.log('made array?: ' + dataHeap);
Module.ccall('gotDictBinary', null,
['number', 'string', 'string', 'string', 'number', 'array'],
[closure, gots.xwd, gots.langName, gots.lc, len, dataHeap]);
['number', 'number', 'string', 'string', 'array', 'number'],
[proc, closure, gots.xwd, gots.lc, dataHeap, len]);
Module._free(dataPtr);
});
console.log('getDict() done');