add to test ability to invite using known players

This commit is contained in:
Eric House 2024-09-12 18:17:48 -07:00
parent 31d0547a60
commit 2d9cb93ae6
9 changed files with 144 additions and 71 deletions

View file

@ -1666,8 +1666,8 @@ pickChannel( const CommsCtxt* comms, const NetLaunchInfo* nli,
/* First, do we already have an invitation for this address */
for ( AddressRecord* rec = comms->recs; !!rec; rec = rec->next ) {
if ( addrsAreSame( destAddr, &rec->addr ) ) {
result = rec->channelNo;
XP_LOGFF( "addrs match; reusing channel" );
result = rec->channelNo & CHANNEL_MASK;
XP_LOGFF( "addrs match; reusing channel %d", result );
break;
}
}
@ -1685,7 +1685,7 @@ pickChannel( const CommsCtxt* comms, const NetLaunchInfo* nli,
for ( XP_PlayerAddr chan = 1; chan <= CHANNEL_MASK; ++chan ) {
if ( 0 == (gicd.hasInvitesMask & (1 << chan)) ) {
result = chan;
XP_LOGFF( "using unused channel" );
XP_LOGFF( "using unused channel %d", result );
break;
}
}
@ -1696,14 +1696,14 @@ pickChannel( const CommsCtxt* comms, const NetLaunchInfo* nli,
for ( XP_PlayerAddr chan = 1; chan <= CHANNEL_MASK; ++chan ) {
if ( 0 == (gicd.hasNonInvitesMask & (1 << chan)) ) {
result = chan;
XP_LOGFF( "recycling channel" );
XP_LOGFF( "recycling channel: %d", result );
break;
}
}
}
}
LOG_RETURNF( "%d", result );
COMMS_LOGFF( "=> 0X%X", result );
return result;
}
@ -1714,9 +1714,9 @@ comms_invite( CommsCtxt* comms, XWEnv xwe, const NetLaunchInfo* nli,
COMMS_LOGFF("(sendNow=%s)", boolToStr(sendNow));
LOGNLI(nli);
WITH_MUTEX(&comms->mutex);
XP_PlayerAddr forceChannel = pickChannel(comms, nli, destAddr);
XP_PlayerAddr forceChannel = pickChannel( comms, nli, destAddr );
XP_LOGFF( "forceChannel: %d", forceChannel );
XP_ASSERT( 0 < forceChannel && (forceChannel & CHANNEL_MASK) == forceChannel );
XP_ASSERT( 0 < forceChannel );
if ( 0 < forceChannel ) {
XP_ASSERT( (forceChannel & CHANNEL_MASK) == forceChannel );
if ( !haveRealChannel( comms, forceChannel ) ) {
@ -2779,7 +2779,7 @@ getChannelFromInvite( const CommsCtxt* comms, const CommsAddrRec* retAddr,
COMMS_LOGFF( "channelNo after: %x", *channelNoP );
}
}
COMMS_LOGFF( "=>%s", boolToStr(found) );
COMMS_LOGFF( "=> %s", boolToStr(found) );
return found;
}
@ -2872,7 +2872,7 @@ checkChannelNo( CommsCtxt* comms, const CommsAddrRec* retAddr, XP_PlayerAddr* ch
comms->nextChannelNo = channelNo;
}
*channelNoP = channelNo;
LOG_RETURNF( "%s", boolToStr(success) );
COMMS_LOGFF( "=> %s", boolToStr(success) );
return success;
}

View file

@ -367,7 +367,7 @@ kplr_getAddr( XW_DUtilCtxt* dutil, XWEnv xwe, const XP_UCHAR* name,
}
releaseStateLocked( dutil, xwe, state );
END_WITH_MUTEX();
LOG_RETURNF( "%s", boolToStr(found) );
XP_LOGFF( "(%s) => %s", name, boolToStr(found) );
return found;
}

View file

@ -149,6 +149,13 @@ nli_setMQTTDevID( NetLaunchInfo* nli, const MQTTDevID* mqttDevID )
formatMQTTDevID( mqttDevID, nli->mqttDevID, VSIZE(nli->mqttDevID) );
}
void
nli_setPhone( NetLaunchInfo* nli, const XP_UCHAR* phone )
{
types_addType( &nli->_conTypes, COMMS_CONN_SMS );
XP_STRNCPY( nli->phone, phone, VSIZE(nli->phone) );
}
void
nli_saveToStream( const NetLaunchInfo* nli, XWStreamCtxt* stream )
{

View file

@ -49,6 +49,7 @@ void nli_setDevID( NetLaunchInfo* nli, XP_U32 devID );
void nli_setInviteID( NetLaunchInfo* nli, const XP_UCHAR* inviteID );
void nli_setGameName( NetLaunchInfo* nli, const XP_UCHAR* gameName );
void nli_setMQTTDevID( NetLaunchInfo* nli, const MQTTDevID* mqttDevID );
void nli_setPhone( NetLaunchInfo* nli, const XP_UCHAR* phone );
#ifdef XWFEATURE_NLI_FROM_ARGV
XP_Bool nli_fromArgv( MPFORMAL NetLaunchInfo* nlip, int argc, const char** argv );

View file

@ -1069,7 +1069,7 @@ server_initClientConnection( ServerCtxt* server, XWEnv xwe )
SRVR_LOGFF( "wierd state: %s (expected XWSTATE_NONE); dropping message",
getStateStr(server->nv.gameState) );
}
SRVR_LOGFF( "=>%s", boolToStr(result) );
SRVR_LOGFF( "=> %s", boolToStr(result) );
return result;
} /* server_initClientConnection */
@ -2145,6 +2145,7 @@ findOrderedSlot( ServerCtxt* server, XWStreamCtxt* stream,
for ( int ii = 0; !success && ii < gi->nPlayers; ++ii ) {
ServerPlayer* sp = &server->srvPlyrs[ii];
SRVR_LOGFFV( "ii: %d; deviceIndex: %d", ii, sp->deviceIndex );
if ( UNKNOWN_DEVICE == sp->deviceIndex ) {
int addrIndx = rip->addrIndices[ii];
if ( addrsAreSame( &guestAddr, &rip->addrs[addrIndx] ) ) {
@ -2156,7 +2157,7 @@ findOrderedSlot( ServerCtxt* server, XWStreamCtxt* stream,
}
}
LOG_RETURNF( "%s", boolToStr(success) );
SRVR_LOGFFV( "()=>%s", boolToStr(success) );
return success;
}

View file

@ -28,6 +28,7 @@
#include "gamesdb.h"
#include "dbgutil.h"
#include "stats.h"
#include "knownplyr.h"
static XP_U32
castGid( cJSON* obj )
@ -82,45 +83,61 @@ gidFromObject( const cJSON* obj )
return castGid( tmp );
}
/* Invite can be via a known player or via */
static XP_Bool
inviteFromArgs( CmdWrapper* wr, cJSON* args )
{
XW_DUtilCtxt* dutil = wr->params->dutil;
XP_U32 gameID = gidFromObject( args );
XP_Bool viaKnowns = XP_FALSE;
cJSON* remotes = cJSON_GetObjectItem( args, "remotes" );
if ( !remotes ) {
remotes = cJSON_GetObjectItem( args, "kps" );
viaKnowns = !!remotes;
}
int nRemotes = cJSON_GetArraySize(remotes);
CommsAddrRec destAddrs[nRemotes];
XP_MEMSET( destAddrs, 0, sizeof(destAddrs) );
for ( int ii = 0; ii < nRemotes; ++ii ) {
XP_Bool success = XP_TRUE;
for ( int ii = 0; success && ii < nRemotes; ++ii ) {
cJSON* item = cJSON_GetArrayItem( remotes, ii );
cJSON* addr = cJSON_GetObjectItem( item, "addr" );
XP_ASSERT( !!addr );
cJSON* tmp = cJSON_GetObjectItem( addr, "mqtt" );
if ( !!tmp ) {
XP_LOGFF( "parsing mqtt: %s", tmp->valuestring );
addr_addType( &destAddrs[ii], COMMS_CONN_MQTT );
#ifdef DEBUG
XP_Bool success =
#endif
strToMQTTCDevID( tmp->valuestring, &destAddrs[ii].u.mqtt.devID );
XP_ASSERT( success );
}
tmp = cJSON_GetObjectItem( addr, "sms" );
if ( !!tmp ) {
XP_LOGFF( "parsing sms: %s", tmp->valuestring );
addr_addType( &destAddrs[ii], COMMS_CONN_SMS );
XP_STRCAT( destAddrs[ii].u.sms.phone, tmp->valuestring );
destAddrs[ii].u.sms.port = 1;
if ( viaKnowns ) {
/* item is just a name */
XP_LOGFF( "found kplyr name: %s", item->valuestring );
success = kplr_getAddr( dutil, NULL_XWE, item->valuestring,
&destAddrs[ii], NULL );
} else {
cJSON* addr = cJSON_GetObjectItem( item, "addr" );
XP_ASSERT( !!addr );
cJSON* tmp = cJSON_GetObjectItem( addr, "mqtt" );
if ( !!tmp ) {
XP_LOGFF( "parsing mqtt: %s", tmp->valuestring );
addr_addType( &destAddrs[ii], COMMS_CONN_MQTT );
success =
strToMQTTCDevID( tmp->valuestring, &destAddrs[ii].u.mqtt.devID );
XP_ASSERT( success );
}
tmp = cJSON_GetObjectItem( addr, "sms" );
if ( !!tmp ) {
XP_LOGFF( "parsing sms: %s", tmp->valuestring );
addr_addType( &destAddrs[ii], COMMS_CONN_SMS );
XP_STRCAT( destAddrs[ii].u.sms.phone, tmp->valuestring );
destAddrs[ii].u.sms.port = 1;
}
}
}
(*wr->procs.addInvites)( wr->closure, gameID, nRemotes, destAddrs );
if ( success ) {
(*wr->procs.addInvites)( wr->closure, gameID, nRemotes, destAddrs );
}
LOG_RETURN_VOID();
return XP_TRUE;
LOG_RETURNF( "%s", boolToStr(success) );
return success;
}
static XP_Bool

View file

@ -1406,6 +1406,9 @@ send_invites( CommonGlobals* cGlobals, XP_U16 nPlayers,
const MQTTDevID* devid = mqttc_getDevID( cGlobals->params );
nli_setMQTTDevID( &nli, devid );
}
if ( addr_hasType( &myAddr, COMMS_CONN_SMS ) ) {
nli_setPhone( &nli, myAddr.u.sms.phone );
}
#ifdef DEBUG
{

View file

@ -179,11 +179,10 @@ linux_addInvites( CommonGlobals* cGlobals, XP_U16 nRemotes,
CommsAddrRec selfAddr;
comms_getSelfAddr( comms, &selfAddr );
NetLaunchInfo nli;
nli_init( &nli, cGlobals->gi, &selfAddr, 1, 0 );
for ( int ii = 0; ii < nRemotes; ++ii ) {
NetLaunchInfo nli;
nli_init( &nli, cGlobals->gi, &selfAddr, 1, 0 );
comms_invite( comms, NULL_XWE, &nli, &destAddrs[ii], XP_TRUE );
}
}

View file

@ -4,6 +4,7 @@ import argparse, datetime, glob, json, os, random, shutil, signal, \
socket, struct, subprocess, sys, threading, time
g_ROOT_NAMES = ['Brynn', 'Ariela', 'Kati', 'Eric']
g_INVITE_HOWS = ['Out-of-App', 'Internal', 'KnownPlayer']
# These must correspond to what the linux app is looking for in roFromStr()
g_ROS = ['same', 'low_score_first', 'high_score_first', 'juggle',]
gDone = False
@ -472,15 +473,45 @@ class Device():
Device.getForPlayer(guest) \
.expectInvite(newGid, rematchLevel, gid, rematchOrder)
# Randomly choose from g_INVITE_HOWS based on the ratio expressed
# in INVITE_PCTS, without requiring e.g. that they sum to 100%
def _inviteHow(self):
count = len(g_INVITE_HOWS)
# multiply by len to ensure the ratios work without errors
asInts = [count * int(one) for one in self.args.INVITE_PCTS.split(':')]
assert count == len(asInts)
total = sum(asInts)
assert 0 == total % count
choice = random.randrange(0, total)
for indx in range(count):
target = asInts[indx]
if choice < target:
result = g_INVITE_HOWS[indx]
break
choice -= target
return result
# inviting means either causing host to send an in-game invitation
# (the way rematch works) or causing guest to register (as happens
# when email or SMS is used for invitations.)
def invite(self, game):
doOOB = random.randint(0, 99) < self.args.OOB_PCT
if doOOB: self.inviteOutOfBand(game)
else: self.inviteInBand(game)
test = { key: 0 for key in g_INVITE_HOWS }
def inviteOutOfBand(self, game):
how = self._inviteHow()
if how == 'Out-of-App':
success = self.inviteOutOfApp(game)
elif how == 'Internal':
success = self.inviteInApp(game)
elif how == 'KnownPlayer':
success = self.inviteKP(game)
else: assert False
return success
# doOOB = random.randint(0, 99) < self.args.OOB_PCT
# if doOOB: self.inviteOutOfBand(game)
# else: self.inviteInBand(game)
def inviteOutOfApp(self, game):
# For each invitee, we need to make sure it exists, launch it,
# and then send it the equivalent of an emailed invitation.
@ -499,8 +530,7 @@ class Device():
game.needsInvite = False
def inviteInBand(self, game):
def inviteInApp(self, game):
remotes = []
guestDevs = []
useRandomDevID = random.randint(0, 100) < self.args.BAD_INVITE_PCT
@ -519,6 +549,14 @@ class Device():
guestDev.expectInvite(game.gid, game.rematchLevel)
game.needsInvite = useRandomDevID
def inviteKP(self, game):
response = self._sendWaitReply('invite', gid=game.gid,
kps=game.guestNames)
if response['success']:
for name in game.guestNames:
Device.getForPlayer(name).expectInvite(game.gid, game.rematchLevel)
game.needsInvite = False
def _mkAddr(self, dev, useRandomDevID=False):
addr = {}
if self.args.WITH_MQTT:
@ -644,38 +682,38 @@ class Device():
def _checkScript(self):
assert os.path.exists(self.args.APP_NEW)
if not os.path.exists(self.script):
scriptArgs = ['exec'] # without exec means terminate() won't work
if self.args.VALGRIND:
scriptArgs += ['valgrind']
# args += ['--leak-check=full']
# args += ['--track-origins=yes']
scriptArgs.append('"${APP}"')
scriptArgs = ['exec'] # without exec means terminate() won't work
if self.args.VALGRIND:
scriptArgs += ['valgrind']
# args += ['--leak-check=full']
# args += ['--track-origins=yes']
scriptArgs += '--db', self.dbName, '--skip-confirm'
scriptArgs += '--localName', self.hostName
scriptArgs += '--cmd-socket-name', self.cmdSocketName
scriptArgs.append('"${APP}"')
if self.args.WITH_MQTT:
scriptArgs += [ '--mqtt-port', self.args.MQTT_PORT, '--mqtt-host', self.args.MQTT_HOST ]
scriptArgs += '--db', self.dbName, '--skip-confirm'
scriptArgs += '--localName', self.hostName
scriptArgs += '--cmd-socket-name', self.cmdSocketName
if self.args.WITH_SMS:
scriptArgs += [ '--sms-number', self.smsNumber ]
if self.args.WITH_MQTT:
scriptArgs += [ '--mqtt-port', self.args.MQTT_PORT, '--mqtt-host', self.args.MQTT_HOST ]
scriptArgs += ['--board-size', '15', '--sort-tiles']
if self.args.WITH_SMS:
scriptArgs += [ '--sms-number', self.smsNumber ]
# useDupeMode = random.randint(0, 100) < self.args.DUP_PCT
# if not useDupeMode: scriptArgs += ['--trade-pct', self.args.TRADE_PCT]
scriptArgs += ['--board-size', '15', '--sort-tiles']
# useDupeMode = random.randint(0, 100) < self.args.DUP_PCT
# if not useDupeMode: scriptArgs += ['--trade-pct', self.args.TRADE_PCT]
# if self.devID: args.extend( ' '.split(self.devID))
scriptArgs += [ '$*' ]
# if self.devID: args.extend( ' '.split(self.devID))
scriptArgs += [ '$*' ]
with open( self.script, 'w' ) as fil:
fil.write('#!/bin/bash\n' )
fil.write('APP="${{APP:-{}}}"\n'.format(self.args.APP_NEW))
fil.write(' '.join([str(arg) for arg in scriptArgs]) + '\n')
os.chmod(self.script, 0o755)
with open( self.script, 'w' ) as fil:
fil.write('#!/bin/bash\n' )
fil.write('APP="${{APP:-{}}}"\n'.format(self.args.APP_NEW))
fil.write(' '.join([str(arg) for arg in scriptArgs]) + '\n')
os.chmod(self.script, 0o755)
@staticmethod
def printStatus(statusSteps, noPrint):
@ -954,16 +992,23 @@ def mkParser():
parser.add_argument('--bad-invite-pct', dest = 'BAD_INVITE_PCT', default = 0, type=int,
help='What pct (0..99) of MQTT invitations will be to non-existant devices')
parser.add_argument('--oob-invite-pct', dest = 'OOB_PCT', default = 50, type=int,
help='What pct (0..99) of guests will "emailed" rather than comms-invited')
# Inviting to new games is done in one of three ways. New games
# with new players involve an out-of-app process like sending an
# email with a URL. After that, once a remote player is "known",
# known-player invitation uses info in the KnownPlayer
# data. Finally, rematches work with the information in the
# current game's addressing.
parser.add_argument('--invite-pcts', dest = 'INVITE_PCTS', default = '33:33:33',
help='Odds of inviting each of 3 ways: {}'.format(':'.join(g_INVITE_HOWS)))
parser.add_argument('--timer-seconds', dest='TIMER_SECS', default=10, type=int,
help='Enable game timer with game this many seconds long')
parser.add_argument('--min-app-life', dest='MIN_APP_LIFE', default=15, type=int,
help='Minimum number of seconds app will run after each launch')
parser.add_argument('--with-sms', dest = 'WITH_SMS', action = 'store_true')
parser.add_argument('--without-sms', dest = 'WITH_SMS', default = False, action = 'store_false')
parser.add_argument('--with-sms', dest = 'WITH_SMS', action = 'store_true', default=False)
parser.add_argument('--without-sms', dest = 'WITH_SMS', default=False, action='store_false')
# parser.add_argument('--sms-fail-pct', dest = 'SMS_FAIL_PCT', default = 0, type = int)
parser.add_argument('--with-mqtt', dest = 'WITH_MQTT', default = True, action = 'store_true')