wifi: notify when game missing

Rewrite to use new XWPacket class that wraps JSONObject but could later
support a binary format, and reply with new message when packet arrives
for a game that does not exist. Code already present turns that into an
invitation to delete the game.
This commit is contained in:
Eric House 2016-12-01 07:48:03 -08:00
parent 54d02e0fb2
commit 54ed327406
4 changed files with 228 additions and 81 deletions

View file

@ -144,3 +144,4 @@ BiDiSockWrap.java
WiDirService.java
WiDirInviteActivity.java
WiDirInviteDelegate.java
XWPacket.java

View file

@ -111,6 +111,11 @@ public class BiDiSockWrap {
send( obj.toString() );
}
public void send( XWPacket packet )
{
send( packet.toString() );
}
public void send( byte[] packet )
{
Assert.assertNotNull( packet );

View file

@ -62,6 +62,7 @@ import org.json.JSONException;
import org.json.JSONObject;
import org.eehouse.android.xw4.MultiService.DictFetchOwner;
import org.eehouse.android.xw4.MultiService.MultiEvent;
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
import org.eehouse.android.xw4.jni.CommsAddrRec;
import org.eehouse.android.xw4.jni.XwJNI;
@ -81,6 +82,7 @@ public class WiDirService extends XWService {
private enum P2PAction { _NONE,
GOT_MSG,
GOT_INVITE,
GAME_GONE,
}
private static final String KEY_CMD = "cmd";
@ -95,11 +97,6 @@ public class WiDirService extends XWService {
private static final String KEY_MAP = "map";
private static final String KEY_RETADDR = "raddr";
private static final String CMD_PING = "ping";
private static final String CMD_PONG = "pong";
private static final String CMD_MSG = "msg";
private static final String CMD_INVITE = "invite";
private static Channel sChannel;
private static ServiceDiscoverer s_discoverer;
private static IntentFilter sIntentFilter;
@ -153,6 +150,9 @@ public class WiDirService extends XWService {
case GOT_INVITE:
handleGotInvite( intent );
break;
case GAME_GONE:
handleGameGone( intent );
break;
}
}
} else {
@ -254,19 +254,14 @@ public class WiDirService extends XWService {
if ( null == wrap ) {
DbgUtils.loge( TAG, "inviteRemote: no socket for %s", macAddr );
} else {
try {
JSONObject packet = new JSONObject()
.put( KEY_CMD, CMD_INVITE )
.put( KEY_SRC, getMyMacAddress() )
.put( KEY_NLI, nliString )
;
if ( forwarding[0] ) {
packet.put( KEY_DEST, macAddr );
}
wrap.send( packet );
} catch ( JSONException jse ) {
DbgUtils.logex( jse );
XWPacket packet = new XWPacket( XWPacket.CMD.INVITE )
.put( KEY_SRC, getMyMacAddress() )
.put( KEY_NLI, nliString )
;
if ( forwarding[0] ) {
packet.put( KEY_DEST, macAddr );
}
wrap.send( packet );
}
}
@ -280,21 +275,16 @@ public class WiDirService extends XWService {
BiDiSockWrap wrap = getForSend( macAddr, forwarding );
if ( null != wrap ) {
try {
JSONObject packet = new JSONObject()
.put( KEY_CMD, CMD_MSG )
.put( KEY_SRC, getMyMacAddress() )
.put( KEY_DATA, XwJNI.base64Encode( buf ) )
.put( KEY_GAMEID, gameID )
;
if ( forwarding[0] ) {
packet.put( KEY_DEST, macAddr );
}
wrap.send( packet );
nSent = buf.length;
} catch ( JSONException jse ) {
DbgUtils.logex( jse );
XWPacket packet = new XWPacket( XWPacket.CMD.MSG )
.put( KEY_SRC, getMyMacAddress() )
.put( KEY_DATA, XwJNI.base64Encode( buf ) )
.put( KEY_GAMEID, gameID )
;
if ( forwarding[0] ) {
packet.put( KEY_DEST, macAddr );
}
wrap.send( packet );
nSent = buf.length;
} else {
DbgUtils.logd( TAG, "sendPacket: no socket for %s", macAddr );
}
@ -352,14 +342,9 @@ public class WiDirService extends XWService {
DbgUtils.logd( TAG, "connectStateChanged(connected=%b)",
nowConnected );
if ( nowConnected ) {
try {
wrap.send( new JSONObject()
.put( KEY_CMD, CMD_PING )
wrap.send( new XWPacket( XWPacket.CMD.PING )
.put( KEY_NAME, sDeviceName )
.put( KEY_MAC, getMyMacAddress( context ) ) );
} catch ( JSONException jse ) {
DbgUtils.logex( jse );
}
} else {
int sizeBefore = sSocketWrapMap.size();
sSocketWrapMap.values().remove( wrap );
@ -652,9 +637,9 @@ public class WiDirService extends XWService {
wrap.connect();
}
private static void storeByAddress( BiDiSockWrap wrap, JSONObject packet )
private static void storeByAddress( BiDiSockWrap wrap, XWPacket packet )
{
String macAddress = packet.optString( KEY_MAC, null );
String macAddress = packet.getString( KEY_MAC );
// Assert.assertNotNull( macAddress );
if ( null != macAddress ) {
// this has fired. Sockets close and re-open?
@ -676,6 +661,9 @@ public class WiDirService extends XWService {
.setP2PParams( macAddress );
ReceiveResult rslt = receiveMessage( this, gameID, m_sink, data, addr );
if ( ReceiveResult.GAME_GONE == rslt ) {
sendNoGame( null, macAddress, gameID );
}
}
private void handleGotInvite( Intent intent )
@ -697,6 +685,12 @@ public class WiDirService extends XWService {
}
}
private void handleGameGone( Intent intent )
{
int gameID = intent.getIntExtra( KEY_GAMEID, 0 );
sendResult( MultiEvent.MESSAGE_NOGAME, gameID );
}
private void makeGame( NetLaunchInfo nli, String senderMac )
{
long[] rowids = DBUtils.getRowIDsFor( this, nli.gameID() );
@ -719,53 +713,81 @@ public class WiDirService extends XWService {
private static void processPacket( BiDiSockWrap wrap, byte[] bytes )
{
Context context = XWApp.getContext();
Intent intent = null;
String asStr = new String(bytes);
DbgUtils.logd( TAG, "got string: %s", asStr );
try {
JSONObject asObj = new JSONObject( asStr );
DbgUtils.logd( TAG, "got json: %s", asObj.toString() );
final String cmd = asObj.optString( KEY_CMD, "" );
if ( cmd.equals( CMD_PING ) ) {
storeByAddress( wrap, asObj );
try {
JSONObject packet = new JSONObject()
.put( KEY_CMD, CMD_PONG )
.put( KEY_MAC, getMyMacAddress() );
addMappings( packet );
wrap.send( packet );
} catch ( JSONException jse ) {
DbgUtils.logex( jse );
}
} else if ( cmd.equals( CMD_PONG ) ) {
storeByAddress( wrap, asObj );
readMappings( asObj );
} else if ( cmd.equals( CMD_INVITE ) ) {
if ( ! forwardedPacket( asObj, bytes ) ) {
Intent intent = getIntentTo( P2PAction.GOT_INVITE );
intent.putExtra( KEY_NLI, asObj.getString( KEY_NLI ) );
intent.putExtra( KEY_SRC, asObj.getString( KEY_SRC ) );
XWApp.getContext().startService( intent );
}
} else if ( cmd.equals( CMD_MSG ) ) {
if ( ! forwardedPacket( asObj, bytes ) ) {
int gameID = asObj.optInt( KEY_GAMEID, 0 );
if ( 0 != gameID ) {
Intent intent = getIntentTo( P2PAction.GOT_MSG );
XWPacket packet = new XWPacket( asStr );
// JSONObject asObj = new JSONObject( asStr );
DbgUtils.logd( TAG, "got packet: %s", packet.toString() );
final XWPacket.CMD cmd = packet.getCommand();
switch ( cmd ) {
case PING:
storeByAddress( wrap, packet );
XWPacket reply = new XWPacket( XWPacket.CMD.PONG )
.put( KEY_MAC, getMyMacAddress() );
addMappings( reply );
wrap.send( reply );
break;
case PONG:
storeByAddress( wrap, packet );
readMappings( packet );
break;
case INVITE:
if ( ! forwardedPacket( packet, bytes ) ) {
intent = getIntentTo( P2PAction.GOT_INVITE );
intent.putExtra( KEY_NLI, packet.getString( KEY_NLI ) );
intent.putExtra( KEY_SRC, packet.getString( KEY_SRC ) );
}
break;
case MSG:
if ( ! forwardedPacket( packet, bytes ) ) {
int gameID = packet.getInt( KEY_GAMEID, 0 );
if ( 0 != gameID ) {
if ( DBUtils.haveGame( context, gameID ) ) {
intent = getIntentTo( P2PAction.GOT_MSG );
intent.putExtra( KEY_GAMEID, gameID );
intent.putExtra( KEY_DATA, asObj.getString( KEY_DATA ) );
intent.putExtra( KEY_RETADDR, asObj.getString( KEY_SRC ) );
XWApp.getContext().startService( intent );
intent.putExtra( KEY_DATA, packet.getString( KEY_DATA ) );
intent.putExtra( KEY_RETADDR, packet.getString( KEY_SRC ) );
} else {
Assert.fail(); // don't ship with this!!!
sendNoGame( wrap, null, gameID );
}
}
}
} catch ( JSONException jse ) {
DbgUtils.logex( jse );
break;
case NOGAME:
if ( ! forwardedPacket( packet, bytes ) ) {
int gameID = packet.getInt( KEY_GAMEID, 0 );
intent = getIntentTo( P2PAction.GAME_GONE );
intent.putExtra( KEY_GAMEID, gameID );
}
break;
}
if ( null != intent ) {
context.startService( intent );
}
}
private static void addMappings( JSONObject packet )
private static void sendNoGame( BiDiSockWrap wrap, String macAddress,
int gameID )
{
boolean[] forwarding = { false };
if ( null == wrap ) {
wrap = getForSend( macAddress, forwarding );
}
if ( null != wrap ) {
XWPacket packet = new XWPacket( XWPacket.CMD.NOGAME )
.put( KEY_GAMEID, gameID );
if ( forwarding[0] ) {
packet.put( KEY_DEST, macAddress );
}
wrap.send( packet );
}
}
private static void addMappings( XWPacket packet )
{
synchronized( sUserMap ) {
try {
@ -783,11 +805,11 @@ public class WiDirService extends XWService {
}
}
private static void readMappings( JSONObject asObj )
private static void readMappings( XWPacket packet )
{
synchronized( sUserMap ) {
try {
JSONArray array = asObj.getJSONArray( KEY_MAP );
JSONArray array = packet.getJSONArray( KEY_MAP );
for ( int ii = 0; ii < array.length(); ++ii ) {
JSONObject map = array.getJSONObject( ii );
String name = map.getString( KEY_NAME );
@ -845,11 +867,11 @@ public class WiDirService extends XWService {
return result;
}
private static boolean forwardedPacket( JSONObject asObj, byte[] bytes )
private static boolean forwardedPacket( XWPacket packet, byte[] bytes )
{
boolean forwarded = false;
String destAddr = asObj.optString( KEY_DEST );
if ( 0 < destAddr.length() ) {
String destAddr = packet.getString( KEY_DEST );
if ( null != destAddr && 0 < destAddr.length() ) {
Assert.assertFalse( destAddr.equals( sMacAddress ) );
forwardPacket( bytes, destAddr );
forwarded = true;

View file

@ -0,0 +1,119 @@
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/*
* Copyright 2016 by Eric House (xwords@eehouse.org). All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.eehouse.android.xw4;
import org.json.JSONObject;
import org.json.JSONException;
import org.json.JSONArray;
public class XWPacket {
private static final String TAG = XWPacket.class.getSimpleName();
private static final String KEY_CMD = "cmd";
private JSONObject m_obj;
public enum CMD {
PING,
PONG,
MSG,
INVITE,
NOGAME,
}
public XWPacket( CMD cmd ) {
try {
m_obj = new JSONObject();
m_obj.put( KEY_CMD, cmd.ordinal() );
} catch ( JSONException ex ) {
DbgUtils.logd( TAG, ex.toString() );
}
}
public XWPacket( String str )
{
try {
m_obj = new JSONObject( str );
} catch ( JSONException ex ) {
DbgUtils.logd( TAG, ex.toString() );
}
}
public CMD getCommand()
{
int cmd = m_obj.optInt( KEY_CMD, -1 ); // let's blow up :-)
return CMD.values()[cmd];
}
public XWPacket put( String key, String value )
{
try {
m_obj.put( key, value );
} catch ( JSONException ex ) {
DbgUtils.logd( TAG, ex.toString() );
}
return this;
}
public XWPacket put( String key, int value )
{
try {
m_obj.put( key, value );
} catch ( JSONException ex ) {
DbgUtils.logd( TAG, ex.toString() );
}
return this;
}
public XWPacket put( String key, JSONArray value )
{
try {
m_obj.put( key, value );
} catch ( JSONException ex ) {
DbgUtils.logd( TAG, ex.toString() );
}
return this;
}
public String getString( String key )
{
String str = m_obj.optString( key );
return str;
}
public int getInt( String key, int dflt )
{
int ii = m_obj.optInt( key, dflt );
return ii;
}
public JSONArray getJSONArray( String key )
{
JSONArray array = null;
try {
array = m_obj.getJSONArray( key );
} catch ( JSONException ex ) {
}
return array;
}
@Override
public String toString() { return m_obj.toString(); }
}