From 54ed32740655f3228c5382a7f4929a288c4707e8 Mon Sep 17 00:00:00 2001 From: Eric House Date: Thu, 1 Dec 2016 07:48:03 -0800 Subject: [PATCH] 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. --- .../src/org/eehouse/android/xw4dbg/.gitignore | 1 + .../org/eehouse/android/xw4/BiDiSockWrap.java | 5 + .../org/eehouse/android/xw4/WiDirService.java | 184 ++++++++++-------- .../src/org/eehouse/android/xw4/XWPacket.java | 119 +++++++++++ 4 files changed, 228 insertions(+), 81 deletions(-) create mode 100644 xwords4/android/XWords4/src/org/eehouse/android/xw4/XWPacket.java diff --git a/xwords4/android/XWords4-dbg/src/org/eehouse/android/xw4dbg/.gitignore b/xwords4/android/XWords4-dbg/src/org/eehouse/android/xw4dbg/.gitignore index 4d82c30ed..2877127b4 100644 --- a/xwords4/android/XWords4-dbg/src/org/eehouse/android/xw4dbg/.gitignore +++ b/xwords4/android/XWords4-dbg/src/org/eehouse/android/xw4dbg/.gitignore @@ -144,3 +144,4 @@ BiDiSockWrap.java WiDirService.java WiDirInviteActivity.java WiDirInviteDelegate.java +XWPacket.java diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BiDiSockWrap.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BiDiSockWrap.java index 56aafd774..48ac9a62f 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BiDiSockWrap.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BiDiSockWrap.java @@ -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 ); diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/WiDirService.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/WiDirService.java index 1c4a9b713..3e5571d2c 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/WiDirService.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/WiDirService.java @@ -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; diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWPacket.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWPacket.java new file mode 100644 index 000000000..8b2da1582 --- /dev/null +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWPacket.java @@ -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(); } +}