mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-15 15:41:24 +01:00
Merge branch 'android_branch' into gtk_multigame
Conflicts: xwords4/android/XWords4/src/org/eehouse/android/xw4/GCMIntentService.java xwords4/android/XWords4/src/org/eehouse/android/xw4/RelayService.java
This commit is contained in:
commit
31c443e4b1
7 changed files with 221 additions and 74 deletions
|
@ -36,7 +36,7 @@ local_DEFINES += \
|
|||
-DHASH_STREAM \
|
||||
-DXWFEATURE_BASE64 \
|
||||
-DXWFEATURE_DEVID \
|
||||
-DINITIAL_CLIENT_VERS=2 \
|
||||
-DINITIAL_CLIENT_VERS=3 \
|
||||
-DRELAY_ROOM_DEFAULT=\"\" \
|
||||
-D__LITTLE_ENDIAN \
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import android.content.Context;
|
|||
import android.content.Intent;
|
||||
import com.google.android.gcm.GCMBaseIntentService;
|
||||
import com.google.android.gcm.GCMRegistrar;
|
||||
import org.json.JSONArray;
|
||||
|
||||
public class GCMIntentService extends GCMBaseIntentService {
|
||||
|
||||
|
@ -61,13 +62,31 @@ public class GCMIntentService extends GCMBaseIntentService {
|
|||
if ( ignoreIt ) {
|
||||
DbgUtils.logf( "received GCM but ignoring it" );
|
||||
} else {
|
||||
value = intent.getStringExtra( "checkUpdates" );
|
||||
if ( null != value && Boolean.parseBoolean( value ) ) {
|
||||
UpdateCheckReceiver.checkVersions( context, true );
|
||||
}
|
||||
|
||||
value = intent.getStringExtra( "getMoves" );
|
||||
if ( null != value && Boolean.parseBoolean( value ) ) {
|
||||
RelayReceiver.RestartTimer( context, true );
|
||||
}
|
||||
value = intent.getStringExtra( "checkUpdates" );
|
||||
if ( null != value && Boolean.parseBoolean( value ) ) {
|
||||
UpdateCheckReceiver.checkVersions( context, true );
|
||||
|
||||
value = intent.getStringExtra( "msgs64" );
|
||||
if ( null != value ) {
|
||||
String connname = intent.getStringExtra( "connname" );
|
||||
if ( null != connname ) {
|
||||
try {
|
||||
JSONArray msgs64 = new JSONArray( value );
|
||||
String[] strs64 = new String[msgs64.length()];
|
||||
for ( int ii = 0; ii < strs64.length; ++ii ) {
|
||||
strs64[ii] = msgs64.optString(ii);
|
||||
}
|
||||
RelayService.processMsgs( context, connname, strs64 );
|
||||
} catch (org.json.JSONException jse ) {
|
||||
DbgUtils.loge( jse );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
value = intent.getStringExtra( "msg" );
|
||||
|
@ -76,6 +95,7 @@ public class GCMIntentService extends GCMBaseIntentService {
|
|||
if ( null != title ) {
|
||||
int code = value.hashCode() ^ title.hashCode();
|
||||
Utils.postNotification( context, null, title, value, code );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,12 @@ package org.eehouse.android.xw4;
|
|||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
<<<<<<< HEAD
|
||||
import java.io.ByteArrayInputStream;
|
||||
=======
|
||||
import android.os.AsyncTask;
|
||||
import android.os.IBinder;
|
||||
>>>>>>> android_branch
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
|
@ -43,16 +48,21 @@ import org.eehouse.android.xw4.MultiService.MultiEvent;
|
|||
import org.eehouse.android.xw4.jni.CommsAddrRec;
|
||||
import org.eehouse.android.xw4.jni.GameSummary;
|
||||
import org.eehouse.android.xw4.jni.UtilCtxt;
|
||||
import org.eehouse.android.xw4.jni.XwJNI;
|
||||
|
||||
public class RelayService extends XWService {
|
||||
private static final int MAX_SEND = 1024;
|
||||
private static final int MAX_BUF = MAX_SEND - 2;
|
||||
|
||||
private static final String CMD_STR = "CMD";
|
||||
private static final int UDP_CHANGED = 1;
|
||||
private static final int SEND = 2;
|
||||
private static final int RECEIVE = 3;
|
||||
|
||||
|
||||
private static final int PROCESS_MSGS = 1;
|
||||
private static final int UDP_CHANGED = 2;
|
||||
private static final int SEND = 3;
|
||||
private static final int RECEIVE = 4;
|
||||
|
||||
private static final String MSGS = "MSGS";
|
||||
private static final String RELAY_ID = "RELAY_ID";
|
||||
private static final String ROWID = "ROWID";
|
||||
private static final String BINBUFFER = "BINBUFFER";
|
||||
|
||||
|
@ -103,9 +113,9 @@ public class RelayService extends XWService {
|
|||
|
||||
public static int sendPacket( Context context, long rowid, byte[] buf )
|
||||
{
|
||||
Intent intent = getIntentTo( context, SEND );
|
||||
intent.putExtra( ROWID, rowid );
|
||||
intent.putExtra( BINBUFFER, buf );
|
||||
Intent intent = getIntentTo( context, SEND )
|
||||
.putExtra( ROWID, rowid )
|
||||
.putExtra( BINBUFFER, buf );
|
||||
context.startService( intent );
|
||||
return buf.length;
|
||||
}
|
||||
|
@ -115,9 +125,9 @@ public class RelayService extends XWService {
|
|||
{
|
||||
DbgUtils.logf( "RelayService::postData: packet of length %d for token %d",
|
||||
msg.length, rowid );
|
||||
Intent intent = getIntentTo( context, RECEIVE );
|
||||
intent.putExtra( ROWID, rowid );
|
||||
intent.putExtra( BINBUFFER, msg );
|
||||
Intent intent = getIntentTo( context, RECEIVE )
|
||||
.putExtra( ROWID, rowid )
|
||||
.putExtra( BINBUFFER, msg );
|
||||
context.startService( intent );
|
||||
}
|
||||
|
||||
|
@ -126,6 +136,15 @@ public class RelayService extends XWService {
|
|||
startService( context );
|
||||
}
|
||||
|
||||
public static void processMsgs( Context context, String relayId,
|
||||
String[] msgs64 )
|
||||
{
|
||||
Intent intent = getIntentTo( context, PROCESS_MSGS )
|
||||
.putExtra( MSGS, msgs64 )
|
||||
.putExtra( RELAY_ID, relayId );
|
||||
context.startService( intent );
|
||||
}
|
||||
|
||||
private static Intent getIntentTo( Context context, int cmd )
|
||||
{
|
||||
Intent intent = new Intent( context, RelayService.class );
|
||||
|
@ -183,6 +202,31 @@ public class RelayService extends XWService {
|
|||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand( Intent intent, int flags, int startId )
|
||||
{
|
||||
int cmd = intent.getIntExtra( CMD_STR, -1 );
|
||||
switch( cmd ) {
|
||||
case PROCESS_MSGS:
|
||||
String[] relayIDs = new String[1];
|
||||
relayIDs[0] = intent.getStringExtra( RELAY_ID );
|
||||
long[] rowIDs = DBUtils.getRowIDsFor( this, relayIDs[0] );
|
||||
if ( 0 < rowIDs.length ) {
|
||||
String[] msgs64 = intent.getStringArrayExtra( MSGS );
|
||||
int count = msgs64.length;
|
||||
|
||||
byte[][][] msgs = new byte[1][count][];
|
||||
for ( int ii = 0; ii < count; ++ii ) {
|
||||
msgs[0][ii] = XwJNI.base64Decode( msgs64[ii] );
|
||||
}
|
||||
process( msgs, rowIDs, relayIDs );
|
||||
}
|
||||
break;
|
||||
}
|
||||
stopSelf( startId );
|
||||
return Service.START_NOT_STICKY;
|
||||
}
|
||||
|
||||
private void setupNotification( String[] relayIDs )
|
||||
{
|
||||
for ( String relayID : relayIDs ) {
|
||||
|
@ -568,67 +612,80 @@ public class RelayService extends XWService {
|
|||
long[][] rowIDss = new long[1][];
|
||||
String[] relayIDs = DBUtils.getRelayIDs( this, rowIDss );
|
||||
if ( null != relayIDs && 0 < relayIDs.length ) {
|
||||
long[] rowIDs = rowIDss[0];
|
||||
byte[][][] msgs = NetUtils.queryRelay( this, relayIDs );
|
||||
|
||||
if ( null != msgs ) {
|
||||
RelayMsgSink sink = new RelayMsgSink();
|
||||
int nameCount = relayIDs.length;
|
||||
ArrayList<String> idsWMsgs =
|
||||
new ArrayList<String>( nameCount );
|
||||
for ( int ii = 0; ii < nameCount; ++ii ) {
|
||||
byte[][] forOne = msgs[ii];
|
||||
// if game has messages, open it and feed 'em
|
||||
// to it.
|
||||
if ( null == forOne ) {
|
||||
// Nothing for this relayID
|
||||
} else if ( BoardActivity.feedMessages( rowIDs[ii], forOne )
|
||||
|| GameUtils.feedMessages( this, rowIDs[ii],
|
||||
forOne, null,
|
||||
sink ) ) {
|
||||
idsWMsgs.add( relayIDs[ii] );
|
||||
} else {
|
||||
DbgUtils.logf( "dropping message for %s (rowid %d)",
|
||||
relayIDs[ii], rowIDs[ii] );
|
||||
}
|
||||
}
|
||||
if ( 0 < idsWMsgs.size() ) {
|
||||
String[] tmp = new String[idsWMsgs.size()];
|
||||
idsWMsgs.toArray( tmp );
|
||||
setupNotification( tmp );
|
||||
}
|
||||
sink.send( this );
|
||||
}
|
||||
process( msgs, rowIDss[0], relayIDs );
|
||||
}
|
||||
}
|
||||
|
||||
private static void sendToRelay( Context context,
|
||||
HashMap<String,ArrayList<byte[]>> msgHash )
|
||||
private void process( byte[][][] msgs, long[] rowIDs, String[] relayIDs )
|
||||
{
|
||||
// format: total msg lenth: 2
|
||||
// number-of-relayIDs: 2
|
||||
// for-each-relayid: relayid + '\n': varies
|
||||
// message count: 1
|
||||
// for-each-message: length: 2
|
||||
// message: varies
|
||||
if ( null != msgs ) {
|
||||
RelayMsgSink sink = new RelayMsgSink();
|
||||
int nameCount = relayIDs.length;
|
||||
ArrayList<String> idsWMsgs = new ArrayList<String>( nameCount );
|
||||
|
||||
if ( null != msgHash ) {
|
||||
for ( int ii = 0; ii < nameCount; ++ii ) {
|
||||
byte[][] forOne = msgs[ii];
|
||||
|
||||
// if game has messages, open it and feed 'em to it.
|
||||
if ( null == forOne ) {
|
||||
// Nothing for this relayID
|
||||
} else if ( BoardActivity.feedMessages( rowIDs[ii], forOne )
|
||||
|| GameUtils.feedMessages( this, rowIDs[ii],
|
||||
forOne, null,
|
||||
sink ) ) {
|
||||
idsWMsgs.add( relayIDs[ii] );
|
||||
} else {
|
||||
DbgUtils.logf( "message for %s (rowid %d) not consumed",
|
||||
relayIDs[ii], rowIDs[ii] );
|
||||
}
|
||||
}
|
||||
if ( 0 < idsWMsgs.size() ) {
|
||||
String[] tmp = new String[idsWMsgs.size()];
|
||||
idsWMsgs.toArray( tmp );
|
||||
setupNotification( tmp );
|
||||
}
|
||||
sink.send( this );
|
||||
}
|
||||
}
|
||||
|
||||
private static class AsyncSender extends AsyncTask<Void, Void, Void> {
|
||||
private Context m_context;
|
||||
private HashMap<String,ArrayList<byte[]>> m_msgHash;
|
||||
|
||||
public AsyncSender( Context context,
|
||||
HashMap<String,ArrayList<byte[]>> msgHash )
|
||||
{
|
||||
m_context = context;
|
||||
m_msgHash = msgHash;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground( Void... ignored )
|
||||
{
|
||||
// format: total msg lenth: 2
|
||||
// number-of-relayIDs: 2
|
||||
// for-each-relayid: relayid + '\n': varies
|
||||
// message count: 1
|
||||
// for-each-message: length: 2
|
||||
// message: varies
|
||||
|
||||
// Build up a buffer containing everything but the total
|
||||
// message length and number of relayIDs in the message.
|
||||
try {
|
||||
// Build up a buffer containing everything but the total
|
||||
// message length and number of relayIDs in the message.
|
||||
ByteArrayOutputStream store =
|
||||
new ByteArrayOutputStream( MAX_BUF ); // mem
|
||||
DataOutputStream outBuf = new DataOutputStream( store );
|
||||
int msgLen = 4; // relayID count + protocol stuff
|
||||
int nRelayIDs = 0;
|
||||
|
||||
Iterator<String> iter = msgHash.keySet().iterator();
|
||||
Iterator<String> iter = m_msgHash.keySet().iterator();
|
||||
while ( iter.hasNext() ) {
|
||||
String relayID = iter.next();
|
||||
int thisLen = 1 + relayID.length(); // string and '\n'
|
||||
thisLen += 2; // message count
|
||||
|
||||
ArrayList<byte[]> msgs = msgHash.get( relayID );
|
||||
ArrayList<byte[]> msgs = m_msgHash.get( relayID );
|
||||
for ( byte[] msg : msgs ) {
|
||||
thisLen += 2 + msg.length;
|
||||
}
|
||||
|
@ -649,10 +706,9 @@ public class RelayService extends XWService {
|
|||
}
|
||||
msgLen += thisLen;
|
||||
}
|
||||
|
||||
// Now open a real socket, write size and proto, and
|
||||
// copy in the formatted buffer
|
||||
Socket socket = NetUtils.makeProxySocket( context, 8000 );
|
||||
Socket socket = NetUtils.makeProxySocket( m_context, 8000 );
|
||||
if ( null != socket ) {
|
||||
DataOutputStream outStream =
|
||||
new DataOutputStream( socket.getOutputStream() );
|
||||
|
@ -667,6 +723,15 @@ public class RelayService extends XWService {
|
|||
} catch ( java.io.IOException ioe ) {
|
||||
DbgUtils.loge( ioe );
|
||||
}
|
||||
return null;
|
||||
} // doInBackground
|
||||
}
|
||||
|
||||
private static void sendToRelay( Context context,
|
||||
HashMap<String,ArrayList<byte[]>> msgHash )
|
||||
{
|
||||
if ( null != msgHash ) {
|
||||
new AsyncSender( context, msgHash ).execute();
|
||||
} else {
|
||||
DbgUtils.logf( "sendToRelay: null msgs" );
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@ dict_getNextTileString( const DictionaryCtxt* dict, Tile tile,
|
|||
} else {
|
||||
cur += XP_STRLEN( cur ) + 1;
|
||||
XP_Bool isSpecial = dict_faceIsBitmap( dict, tile );
|
||||
if ( isSpecial ) {
|
||||
if ( isSpecial || tile == dict->blankTile ) {
|
||||
const XP_UCHAR* facep = dict_getTileStringRaw( dict, tile );
|
||||
if ( cur < dict->charEnds[(XP_U16)*facep] ) {
|
||||
result = cur;
|
||||
|
|
|
@ -2856,17 +2856,27 @@ server_formatDictCounts( ServerCtxt* server, XWStreamCtxt* stream,
|
|||
nChars = dict_numTileFaces( dict );
|
||||
|
||||
for ( tile = 0, nPrinted = 0; ; ) {
|
||||
XP_UCHAR buf[24];
|
||||
XP_UCHAR buf[128];
|
||||
XP_U16 count, value;
|
||||
|
||||
count = dict_numTiles( dict, tile );
|
||||
|
||||
if ( count > 0 ) {
|
||||
const XP_UCHAR* face = dict_getTileString( dict, tile );
|
||||
const XP_UCHAR* face = NULL;
|
||||
XP_UCHAR faces[48] = {0};
|
||||
XP_U16 len = 0;
|
||||
for ( ; ; ) {
|
||||
face = dict_getNextTileString( dict, tile, face );
|
||||
if ( !face ) {
|
||||
break;
|
||||
}
|
||||
const XP_UCHAR* fmt = len == 0? "%s" : ",%s";
|
||||
len += XP_SNPRINTF( faces + len, sizeof(faces) - len, fmt, face );
|
||||
}
|
||||
value = dict_getTileValue( dict, tile );
|
||||
|
||||
XP_SNPRINTF( buf, sizeof(buf), (XP_UCHAR*)"%s: %d/%d",
|
||||
face, count, value );
|
||||
faces, count, value );
|
||||
stream_catString( stream, buf );
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
XWLANG = PTBR4422
|
||||
LANGCODE = pt_PT
|
||||
ENC = UTF-8
|
||||
DICTNOTE = "Lista com as 4422 palavras mais frequentes nas legendas em português brasileiro do site www.opensubtitles.org."
|
||||
|
||||
TARGET_TYPE ?= WINCE
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ g_con = None
|
|||
g_sent = None
|
||||
g_debug = False
|
||||
g_skipSend = False # for debugging
|
||||
g_columns = [ 'id', 'devid', 'connname', 'hid', 'msg64' ]
|
||||
DEVTYPE_GCM = 3 # 3 == GCM
|
||||
LINE_LEN = 76
|
||||
|
||||
|
@ -55,19 +56,51 @@ def init():
|
|||
|
||||
def getPendingMsgs( con, typ ):
|
||||
cur = con.cursor()
|
||||
query = """SELECT id, devid FROM msgs
|
||||
query = """SELECT %s FROM msgs
|
||||
WHERE devid IN (SELECT id FROM devices WHERE devtype=%d and NOT unreg)
|
||||
AND NOT connname IN (SELECT connname FROM games WHERE dead); """
|
||||
cur.execute(query % typ)
|
||||
result = cur.fetchall()
|
||||
cur.execute(query % (",".join( g_columns ), typ))
|
||||
|
||||
result = []
|
||||
for row in cur:
|
||||
rowObj = {}
|
||||
for ii in range( len( g_columns ) ):
|
||||
rowObj[g_columns[ii]] = row[ii]
|
||||
result.append( rowObj )
|
||||
if g_debug: print "getPendingMsgs=>", result
|
||||
return result
|
||||
|
||||
def addClntVers( con, rows ):
|
||||
query = """select clntVers[%s] from games where connname = '%s';"""
|
||||
cur = con.cursor()
|
||||
for row in rows:
|
||||
cur.execute( query % (row['hid'], row['connname']))
|
||||
if cur.rowcount == 1: row['clntVers'] = cur.fetchone()[0]
|
||||
else: print "bad row count: ", cur.rowcount
|
||||
con.commit()
|
||||
return rows
|
||||
|
||||
def deleteMsgs( con, msgIDs ):
|
||||
if 0 < len( msgIDs ):
|
||||
query = "DELETE from msgs where id in (%s);" % ",".join(msgIDs)
|
||||
try:
|
||||
cur = con.cursor()
|
||||
cur.execute(query)
|
||||
con.commit()
|
||||
except psycopg2.DatabaseError, e:
|
||||
print 'Error %s' % e
|
||||
except Exception as inst:
|
||||
print "failed to execute", query
|
||||
print type(inst)
|
||||
print inst.args
|
||||
print inst
|
||||
|
||||
def unregister( gcmid ):
|
||||
global g_con
|
||||
print "unregister(", gcmid, ")"
|
||||
query = "UPDATE devices SET unreg=TRUE WHERE devid = '%s' and devtype = 3" % gcmid
|
||||
g_con.cursor().execute( query )
|
||||
g_con.commit()
|
||||
|
||||
def asGCMIds(con, devids, typ):
|
||||
cur = con.cursor()
|
||||
|
@ -76,13 +109,22 @@ def asGCMIds(con, devids, typ):
|
|||
cur.execute( query )
|
||||
return [elem[0] for elem in cur.fetchall()]
|
||||
|
||||
def notifyGCM( devids, typ ):
|
||||
def notifyGCM( devids, typ, target ):
|
||||
success = False
|
||||
if typ == DEVTYPE_GCM:
|
||||
if 3 <= target['clntVers']:
|
||||
connname = "%s/%d" % (target['connname'], target['hid'])
|
||||
data = { 'msgs64': [ target['msg64'] ],
|
||||
'connname': connname,
|
||||
}
|
||||
else:
|
||||
data = { 'getMoves': True, }
|
||||
values = {
|
||||
'data' : { 'getMoves': True, },
|
||||
'data' : data,
|
||||
'registration_ids': devids,
|
||||
}
|
||||
params = json.dumps( values )
|
||||
|
||||
req = urllib2.Request("https://android.googleapis.com/gcm/send", params )
|
||||
req.add_header( 'Content-Type' , 'application/x-www-form-urlencoded;charset=UTF-8' )
|
||||
req.add_header( 'Authorization' , 'key=' + mykey.myKey )
|
||||
|
@ -92,11 +134,13 @@ def notifyGCM( devids, typ ):
|
|||
|
||||
if 'success' in asJson and 'failure' in asJson and len(devids) == asJson['success'] and 0 == asJson['failure']:
|
||||
print "OK"
|
||||
success = True
|
||||
else:
|
||||
print "Errors: "
|
||||
print response
|
||||
else:
|
||||
print "not sending to", len(devids), "devices because typ ==", typ
|
||||
return success
|
||||
|
||||
def shouldSend(val):
|
||||
return val == 1
|
||||
|
@ -113,14 +157,14 @@ def targetsAfterBackoff( msgs ):
|
|||
global g_sent
|
||||
targets = {}
|
||||
for row in msgs:
|
||||
msgid = row[0]
|
||||
devid = row[1]
|
||||
msgid = row['id']
|
||||
devid = row['devid']
|
||||
if not msgid in g_sent:
|
||||
g_sent[msgid] = 0
|
||||
g_sent[msgid] += 1
|
||||
if shouldSend( g_sent[msgid] ):
|
||||
targets[devid] = True
|
||||
return targets.keys()
|
||||
targets[devid] = row
|
||||
return targets
|
||||
|
||||
# devids is an array of (msgid, devid) tuples
|
||||
def pruneSent( devids ):
|
||||
|
@ -129,7 +173,7 @@ def pruneSent( devids ):
|
|||
lenBefore = len(g_sent)
|
||||
msgids = []
|
||||
for row in devids:
|
||||
msgids.append(row[0])
|
||||
msgids.append(row['id'])
|
||||
for msgid in g_sent.keys():
|
||||
if not msgid in msgids:
|
||||
del g_sent[msgid]
|
||||
|
@ -181,14 +225,21 @@ def main():
|
|||
if g_debug: print
|
||||
devids = getPendingMsgs( g_con, typ )
|
||||
if 0 < len(devids):
|
||||
devids = addClntVers( g_con, devids )
|
||||
targets = targetsAfterBackoff( devids )
|
||||
if 0 < len(targets):
|
||||
if 0 < emptyCount: print ""
|
||||
emptyCount = 0
|
||||
print strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
|
||||
print "devices needing notification:", targets, '=>',
|
||||
notifyGCM( asGCMIds( g_con, targets, typ ), typ )
|
||||
toDelete = []
|
||||
for devid in targets.keys():
|
||||
target = targets[devid]
|
||||
if notifyGCM( asGCMIds(g_con, [devid], typ), typ, target )\
|
||||
and 3 <= target['clntVers']:
|
||||
toDelete.append( str(target['id']) )
|
||||
pruneSent( devids )
|
||||
deleteMsgs( g_con, toDelete )
|
||||
elif g_debug: print "no targets after backoff"
|
||||
else:
|
||||
emptyCount += 1
|
||||
|
|
Loading…
Reference in a new issue