mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-22 07:28:16 +01:00
use a single queue for all nbsproto threads
No point in worrying about whether a thread exists without emptying its queue. Instead have a thread start when something's added to the queue and exit when it's been empty for a while. Only trick is the need to remember the phone number[s] on behalf of which a retry's necessary because jni code is waiting to see if combining can be done.
This commit is contained in:
parent
8c2582b9a2
commit
993fff8e13
3 changed files with 202 additions and 174 deletions
|
@ -428,7 +428,7 @@ public class CommsTransport implements TransportProcs,
|
||||||
break;
|
break;
|
||||||
case COMMS_CONN_SMS:
|
case COMMS_CONN_SMS:
|
||||||
nSent = NBSProto.sendPacket( context, addr.sms_phone,
|
nSent = NBSProto.sendPacket( context, addr.sms_phone,
|
||||||
gameID, buf );
|
gameID, buf, msgID );
|
||||||
break;
|
break;
|
||||||
case COMMS_CONN_BT:
|
case COMMS_CONN_BT:
|
||||||
nSent = BTService.sendPacket( context, buf, msgID, addr, gameID );
|
nSent = BTService.sendPacket( context, buf, msgID, addr, gameID );
|
||||||
|
|
|
@ -68,9 +68,9 @@ public class MultiMsgSink implements TransportProcs {
|
||||||
return BTService.sendPacket( m_context, buf, msgID, addr, gameID );
|
return BTService.sendPacket( m_context, buf, msgID, addr, gameID );
|
||||||
}
|
}
|
||||||
|
|
||||||
public int sendViaSMS( byte[] buf, int gameID, CommsAddrRec addr )
|
public int sendViaSMS( byte[] buf, String msgID, int gameID, CommsAddrRec addr )
|
||||||
{
|
{
|
||||||
return NBSProto.sendPacket( m_context, addr.sms_phone, gameID, buf );
|
return NBSProto.sendPacket( m_context, addr.sms_phone, gameID, buf, msgID );
|
||||||
}
|
}
|
||||||
|
|
||||||
public int sendViaP2P( byte[] buf, int gameID, CommsAddrRec addr )
|
public int sendViaP2P( byte[] buf, int gameID, CommsAddrRec addr )
|
||||||
|
@ -101,7 +101,7 @@ public class MultiMsgSink implements TransportProcs {
|
||||||
nSent = sendViaBluetooth( buf, msgID, gameID, addr );
|
nSent = sendViaBluetooth( buf, msgID, gameID, addr );
|
||||||
break;
|
break;
|
||||||
case COMMS_CONN_SMS:
|
case COMMS_CONN_SMS:
|
||||||
nSent = sendViaSMS( buf, gameID, addr );
|
nSent = sendViaSMS( buf, msgID, gameID, addr );
|
||||||
break;
|
break;
|
||||||
case COMMS_CONN_P2P:
|
case COMMS_CONN_P2P:
|
||||||
nSent = sendViaP2P( buf, gameID, addr );
|
nSent = sendViaP2P( buf, gameID, addr );
|
||||||
|
|
|
@ -28,6 +28,7 @@ import android.telephony.SmsManager;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
@ -60,7 +61,7 @@ public class NBSProto {
|
||||||
public static void handleFrom( Context context, byte[] buffer,
|
public static void handleFrom( Context context, byte[] buffer,
|
||||||
String phone, short port )
|
String phone, short port )
|
||||||
{
|
{
|
||||||
getCurThread( phone, port ).addPacketFrom( context, buffer );
|
addPacketFrom( context, phone, port, buffer );
|
||||||
if ( (0 == (++s_nReceived % TOAST_FREQ)) && showToasts( context ) ) {
|
if ( (0 == (++s_nReceived % TOAST_FREQ)) && showToasts( context ) ) {
|
||||||
DbgUtils.showf( context, "Got msg %d", s_nReceived );
|
DbgUtils.showf( context, "Got msg %d", s_nReceived );
|
||||||
}
|
}
|
||||||
|
@ -69,25 +70,27 @@ public class NBSProto {
|
||||||
public static void inviteRemote( Context context, String phone,
|
public static void inviteRemote( Context context, String phone,
|
||||||
NetLaunchInfo nli )
|
NetLaunchInfo nli )
|
||||||
{
|
{
|
||||||
getCurThread( phone ).addInviteTo( context, nli );
|
addInviteTo( context, phone, nli );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int sendPacket( Context context, String phone,
|
public static int sendPacket( Context context, String phone,
|
||||||
int gameID, byte[] binmsg )
|
int gameID, byte[] binmsg, String msgID )
|
||||||
{
|
{
|
||||||
getCurThread( phone ).addPacketTo( context, gameID, binmsg );
|
Log.d( TAG, "sendPacket(phone=%s, gameID=%d, len=%d, msgID=%s)",
|
||||||
|
phone, gameID, binmsg.length, msgID );
|
||||||
|
addPacketTo( context, phone, gameID, binmsg );
|
||||||
return binmsg.length;
|
return binmsg.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void gameDied( Context context, int gameID, String phone )
|
public static void gameDied( Context context, int gameID, String phone )
|
||||||
{
|
{
|
||||||
getCurThread( phone ).addGameDied( context, gameID );
|
addGameDied( context, phone, gameID );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void onGameDictDownload( Context context, Intent oldIntent )
|
public static void onGameDictDownload( Context context, Intent oldIntent )
|
||||||
{
|
{
|
||||||
NetLaunchInfo nli = MultiService.getMissingDictData( context, oldIntent );
|
NetLaunchInfo nli = MultiService.getMissingDictData( context, oldIntent );
|
||||||
getCurThread( nli.phone ).addInviteFrom( context, nli );
|
addInviteFrom( context, nli );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void stopThreads()
|
public static void stopThreads()
|
||||||
|
@ -100,57 +103,61 @@ public class NBSProto {
|
||||||
s_showToasts = newVal;
|
s_showToasts = newVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void addPacketFrom( Context context, String phone,
|
||||||
|
short port, byte[] data )
|
||||||
|
{
|
||||||
|
add( new ReceiveElem( context, phone, port, data ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addInviteFrom( Context context, NetLaunchInfo nli )
|
||||||
|
{
|
||||||
|
add( new ReceiveElem( context, nli ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addPacketTo( Context context, String phone,
|
||||||
|
int gameID, byte[] binmsg )
|
||||||
|
{
|
||||||
|
add( new SendElem( context, phone, SMS_CMD.DATA, gameID, binmsg ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addInviteTo( Context context, String phone, NetLaunchInfo nli )
|
||||||
|
{
|
||||||
|
add( new SendElem( context, phone, SMS_CMD.INVITE, nli ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addGameDied( Context context, String phone, int gameID )
|
||||||
|
{
|
||||||
|
add( new SendElem( context, phone, SMS_CMD.DEATH, gameID, null ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addAck( Context context, String phone, int gameID )
|
||||||
|
{
|
||||||
|
add( new SendElem( context, phone, SMS_CMD.ACK_INVITE, gameID, null ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void add( QueueElem elem ) {
|
||||||
|
if ( XWPrefs.getNBSEnabled( elem.context ) ) {
|
||||||
|
sQueue.add( elem );
|
||||||
|
startThreadOnce();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static LinkedBlockingQueue<QueueElem> sQueue = new LinkedBlockingQueue<>();
|
||||||
|
|
||||||
static class NBSProtoThread extends Thread {
|
static class NBSProtoThread extends Thread {
|
||||||
private String mPhone;
|
|
||||||
private short mPort;
|
|
||||||
private LinkedBlockingQueue<QueueElem> mQueue = new LinkedBlockingQueue<>();
|
|
||||||
private boolean mForceNow;
|
private boolean mForceNow;
|
||||||
private int[] mWaitSecs = { 0 };
|
private int[] mWaitSecs = { 0 };
|
||||||
|
private Set<String> mCachedDests = new HashSet<>();
|
||||||
|
|
||||||
NBSProtoThread( String phone, short port )
|
NBSProtoThread()
|
||||||
{
|
{
|
||||||
super( "NBSProtoThread" );
|
super( "NBSProtoThread" );
|
||||||
mPhone = phone;
|
|
||||||
mPort = port;
|
|
||||||
mForceNow = !XWPrefs.getSMSProtoEnabled( XWApp.getContext() );
|
mForceNow = !XWPrefs.getSMSProtoEnabled( XWApp.getContext() );
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getPhone() { return mPhone; }
|
|
||||||
private short getPort() { return mPort; }
|
|
||||||
|
|
||||||
void addPacketFrom( Context context, byte[] data )
|
|
||||||
{
|
|
||||||
add( new ReceiveElem( context, data ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
void addInviteFrom( Context context, NetLaunchInfo nli )
|
|
||||||
{
|
|
||||||
add( new ReceiveElem( context, nli ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
void addPacketTo( Context context, int gameID, byte[] binmsg )
|
|
||||||
{
|
|
||||||
add( new SendElem( context, SMS_CMD.DATA, gameID, binmsg ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
void addInviteTo( Context context, NetLaunchInfo nli )
|
|
||||||
{
|
|
||||||
add( new SendElem( context, SMS_CMD.INVITE, nli ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
void addGameDied( Context context, int gameID )
|
|
||||||
{
|
|
||||||
add( new SendElem( context, SMS_CMD.DEATH, gameID, null ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
void addAck( Context context, int gameID )
|
|
||||||
{
|
|
||||||
add( new SendElem( context, SMS_CMD.ACK_INVITE, gameID, null ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Log.d( TAG, "%s.run() starting for %s", this, mPhone );
|
Log.d( TAG, "%s.run() starting", this );
|
||||||
|
|
||||||
while ( !isInterrupted() ) {
|
while ( !isInterrupted() ) {
|
||||||
try {
|
try {
|
||||||
|
@ -159,8 +166,8 @@ public class NBSProto {
|
||||||
// set by smsproto_prepOutbound(). Otherwise sleep until
|
// set by smsproto_prepOutbound(). Otherwise sleep until
|
||||||
// there's something in the queue.
|
// there's something in the queue.
|
||||||
long waitSecs = mWaitSecs[0] <= 0 ? 10 * 60 : mWaitSecs[0];
|
long waitSecs = mWaitSecs[0] <= 0 ? 10 * 60 : mWaitSecs[0];
|
||||||
QueueElem elem = mQueue.poll( waitSecs, TimeUnit.SECONDS );
|
QueueElem elem = sQueue.poll( waitSecs, TimeUnit.SECONDS );
|
||||||
if ( !process( elem, false ) ) {
|
if ( !process( elem ) ) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch ( InterruptedException iex ) {
|
} catch ( InterruptedException iex ) {
|
||||||
|
@ -169,76 +176,89 @@ public class NBSProto {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeSelf( this ); // should stop additions to the queue
|
removeSelf( this );
|
||||||
|
|
||||||
// Now just empty out the queue, in case anything was added
|
|
||||||
// late. Note that if we're abandoning a half-assembled
|
|
||||||
// multi-message buffer that data's lost until a higher level
|
|
||||||
// resends. So don't let that happen.
|
|
||||||
for ( ; ; ) {
|
|
||||||
QueueElem elem = mQueue.poll();
|
|
||||||
process( elem, true );
|
|
||||||
if ( null == elem ) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Better not be leaving anything behind!
|
|
||||||
Assert.assertTrue( 0 == mQueue.size() || !BuildConfig.DEBUG );
|
|
||||||
Log.d( TAG, "%s.run() DONE", this );
|
Log.d( TAG, "%s.run() DONE", this );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void add( QueueElem elem ) {
|
private boolean processReceive( ReceiveElem elem )
|
||||||
if ( XWPrefs.getNBSEnabled( elem.context ) ) {
|
|
||||||
mQueue.add( elem );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean processReceive( ReceiveElem elem, boolean exiting )
|
|
||||||
{
|
{
|
||||||
if ( null != elem.data ) {
|
if ( null != elem.data ) {
|
||||||
SMSProtoMsg[] msgs = XwJNI.smsproto_prepInbound( elem.data, mPhone, mPort );
|
SMSProtoMsg[] msgs = XwJNI.smsproto_prepInbound( elem.data, elem.phone, elem.port );
|
||||||
if ( null != msgs ) {
|
if ( null != msgs ) {
|
||||||
Log.d( TAG, "got %d msgs combined!", msgs.length );
|
Log.d( TAG, "got %d msgs combined!", msgs.length );
|
||||||
for ( int ii = 0; ii < msgs.length; ++ii ) {
|
for ( int ii = 0; ii < msgs.length; ++ii ) {
|
||||||
Log.d( TAG, "%d: type: %s; len: %d", ii, msgs[ii].cmd, msgs[ii].data.length );
|
Log.d( TAG, "%d: type: %s; len: %d", ii, msgs[ii].cmd, msgs[ii].data.length );
|
||||||
}
|
}
|
||||||
for ( SMSProtoMsg msg : msgs ) {
|
for ( SMSProtoMsg msg : msgs ) {
|
||||||
receive( elem.context, msg );
|
receive( elem.context, elem.phone, msg );
|
||||||
}
|
}
|
||||||
getHelper().postEvent( MultiEvent.SMS_RECEIVE_OK );
|
getHelper().postEvent( MultiEvent.SMS_RECEIVE_OK );
|
||||||
} else {
|
} else {
|
||||||
Log.d( TAG, "receiveBuffer(): bogus or incomplete message from %s",
|
Log.d( TAG, "receiveBuffer(): bogus or incomplete message from %s",
|
||||||
getPhone() );
|
elem.phone );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( null != elem.nli ) {
|
if ( null != elem.nli ) {
|
||||||
makeForInvite( elem.context, elem.nli );
|
makeForInvite( elem.context, elem.phone, elem.nli );
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean processSend( SendElem elem, boolean exiting )
|
// Called when we have nothing to add, but might be sending what's
|
||||||
|
// already waiting for possible combination with other messages.
|
||||||
|
private boolean processRetry()
|
||||||
{
|
{
|
||||||
boolean forceNow = mForceNow || exiting;
|
Assert.assertTrue( !mForceNow || !BuildConfig.DEBUG );
|
||||||
byte[][] msgs = null != elem
|
boolean handled = false;
|
||||||
? XwJNI.smsproto_prepOutbound( elem.cmd, elem.gameID, elem.data,
|
|
||||||
mPhone, mPort, forceNow, mWaitSecs )
|
|
||||||
: XwJNI.smsproto_prepOutbound( mPhone, mPort, forceNow, mWaitSecs );
|
|
||||||
|
|
||||||
if ( null != msgs ) {
|
for ( Iterator<String> iter = mCachedDests.iterator();
|
||||||
sendBuffers( msgs );
|
iter.hasNext(); ) {
|
||||||
|
String[] portAndPhone = iter.next().split( "\0", 2 );
|
||||||
|
short port = Short.valueOf(portAndPhone[0]);
|
||||||
|
byte[][] msgs = XwJNI
|
||||||
|
.smsproto_prepOutbound( portAndPhone[1], port,
|
||||||
|
mForceNow, mWaitSecs );
|
||||||
|
if ( null != msgs ) {
|
||||||
|
sendBuffers( msgs, portAndPhone[1], port );
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
boolean needsRetry = mWaitSecs[0] > 0;
|
||||||
|
if ( !needsRetry ) {
|
||||||
|
iter.remove();
|
||||||
|
}
|
||||||
|
handled = handled || needsRetry;
|
||||||
}
|
}
|
||||||
return null != msgs || mWaitSecs[0] > 0;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean process( QueueElem qelm, boolean exiting )
|
private boolean processSend( SendElem elem )
|
||||||
|
{
|
||||||
|
boolean forceNow = mForceNow;
|
||||||
|
byte[][] msgs = XwJNI
|
||||||
|
.smsproto_prepOutbound( elem.cmd, elem.gameID, elem.data,
|
||||||
|
elem.phone, elem.port, forceNow, mWaitSecs );
|
||||||
|
if ( null != msgs ) {
|
||||||
|
sendBuffers( msgs, elem.phone, elem.port );
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean needsRetry = mWaitSecs[0] > 0;
|
||||||
|
if ( needsRetry ) {
|
||||||
|
cacheForRetry( elem );
|
||||||
|
}
|
||||||
|
|
||||||
|
return null != msgs || needsRetry;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean process( QueueElem qelm )
|
||||||
{
|
{
|
||||||
boolean handled;
|
boolean handled;
|
||||||
if ( null == qelm || qelm instanceof SendElem ) {
|
if ( null == qelm ) {
|
||||||
handled = processSend( (SendElem)qelm, exiting );
|
handled = processRetry();
|
||||||
|
} else if ( qelm instanceof SendElem ) {
|
||||||
|
handled = processSend( (SendElem)qelm );
|
||||||
} else {
|
} else {
|
||||||
handled = processReceive( (ReceiveElem)qelm, exiting );
|
handled = processReceive( (ReceiveElem)qelm );
|
||||||
}
|
}
|
||||||
Log.d( TAG, "%s.process(%s) => %b", this, qelm, handled );
|
Log.d( TAG, "%s.process(%s) => %b", this, qelm, handled );
|
||||||
return handled;
|
return handled;
|
||||||
|
@ -253,15 +273,17 @@ public class NBSProto {
|
||||||
return mHelper;
|
return mHelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void receive( Context context, SMSProtoMsg msg )
|
private void receive( Context context, String phone, SMSProtoMsg msg )
|
||||||
{
|
{
|
||||||
Log.i( TAG, "receive(cmd=%s)", msg.cmd );
|
Log.i( TAG, "receive(cmd=%s)", msg.cmd );
|
||||||
switch( msg.cmd ) {
|
switch( msg.cmd ) {
|
||||||
case INVITE:
|
case INVITE:
|
||||||
makeForInvite( context, NetLaunchInfo.makeFrom( context, msg.data ) );
|
makeForInvite( context, phone,
|
||||||
|
NetLaunchInfo.makeFrom( context, msg.data ) );
|
||||||
break;
|
break;
|
||||||
case DATA:
|
case DATA:
|
||||||
if ( feedMessage( context, msg.gameID, msg.data, new CommsAddrRec( getPhone() ) ) ) {
|
if ( feedMessage( context, msg.gameID, msg.data,
|
||||||
|
new CommsAddrRec( phone ) ) ) {
|
||||||
SMSResendReceiver.resetTimer( context );
|
SMSResendReceiver.resetTimer( context );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -292,28 +314,25 @@ public class NBSProto {
|
||||||
private void sendDiedPacket( Context context, String phone, int gameID )
|
private void sendDiedPacket( Context context, String phone, int gameID )
|
||||||
{
|
{
|
||||||
if ( !s_sentDied.contains( gameID ) ) {
|
if ( !s_sentDied.contains( gameID ) ) {
|
||||||
getCurThread( phone ).addGameDied( context, gameID );
|
addGameDied( context, phone, gameID );
|
||||||
s_sentDied.add( gameID );
|
s_sentDied.add( gameID );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void makeForInvite( Context context, NetLaunchInfo nli )
|
private void makeForInvite( Context context, String phone, NetLaunchInfo nli )
|
||||||
{
|
{
|
||||||
if ( nli != null ) {
|
if ( nli != null ) {
|
||||||
getHelper().handleInvitation( nli, mPhone, DictFetchOwner.OWNER_SMS );
|
getHelper().handleInvitation( nli, phone, DictFetchOwner.OWNER_SMS );
|
||||||
getCurThread(mPhone).addAck( context, nli.gameID() );
|
addAck( context, phone, nli.gameID() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendBuffers( byte[][] fragments )
|
private void sendBuffers( byte[][] fragments, String phone, short port )
|
||||||
{
|
{
|
||||||
Context context = XWApp.getContext();
|
Context context = XWApp.getContext();
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
if ( XWPrefs.getNBSEnabled( context ) ) {
|
if ( XWPrefs.getNBSEnabled( context ) ) {
|
||||||
|
|
||||||
String phone = getPhone();
|
|
||||||
short port = getPort();
|
|
||||||
|
|
||||||
// Try send-to-self
|
// Try send-to-self
|
||||||
if ( XWPrefs.getSMSToSelfEnabled( context ) ) {
|
if ( XWPrefs.getSMSToSelfEnabled( context ) ) {
|
||||||
String myPhone = SMSPhoneInfo.get( context ).number;
|
String myPhone = SMSPhoneInfo.get( context ).number;
|
||||||
|
@ -373,85 +392,94 @@ public class NBSProto {
|
||||||
return PendingIntent.getBroadcast( context, 0, intent, 0 );
|
return PendingIntent.getBroadcast( context, 0, intent, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void cacheForRetry( QueueElem elem )
|
||||||
static class QueueElem {
|
{
|
||||||
Context context;
|
String dest = elem.port + "\0" + elem.phone;
|
||||||
QueueElem( Context context ) { this.context = context; }
|
mCachedDests.add( dest );
|
||||||
}
|
|
||||||
|
|
||||||
private static class SendElem extends QueueElem {
|
|
||||||
SMS_CMD cmd;
|
|
||||||
int gameID;
|
|
||||||
byte[] data;
|
|
||||||
SendElem( Context context, SMS_CMD cmd, int gameID, byte[] data ) {
|
|
||||||
super( context );
|
|
||||||
this.cmd = cmd;
|
|
||||||
this.gameID = gameID;
|
|
||||||
this.data = data;
|
|
||||||
}
|
|
||||||
SendElem( Context context, SMS_CMD cmd, NetLaunchInfo nli ) {
|
|
||||||
this( context, cmd, 0, nli.asByteArray() );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return String.format( "SendElem: {cmd: %s, dataLen: %d}", cmd,
|
|
||||||
data == null ? 0 : data.length );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ReceiveElem extends QueueElem {
|
|
||||||
// One of these two will be set
|
|
||||||
byte[] data;
|
|
||||||
NetLaunchInfo nli;
|
|
||||||
ReceiveElem( Context context, byte[] data )
|
|
||||||
{
|
|
||||||
super( context );
|
|
||||||
this.data = data;
|
|
||||||
}
|
|
||||||
ReceiveElem( Context context, NetLaunchInfo nli )
|
|
||||||
{
|
|
||||||
super( context );
|
|
||||||
this.nli = nli;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return String.format( "ReceiveElem: {nli: %s, data: %s}", nli, data );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, NBSProtoThread> sThreadMap = new HashMap<>();
|
private static class QueueElem {
|
||||||
|
Context context;
|
||||||
|
String phone;
|
||||||
|
short port;
|
||||||
|
QueueElem( Context context, String phone, short port )
|
||||||
|
{
|
||||||
|
this.context = context;
|
||||||
|
this.phone = phone;
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
private static NBSProtoThread getCurThread( String phone )
|
QueueElem( Context context, String phone )
|
||||||
{
|
{
|
||||||
return getCurThread( phone, getNBSPort() );
|
this( context, phone, getNBSPort() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static NBSProtoThread getCurThread( String phone, short port )
|
private static class SendElem extends QueueElem {
|
||||||
|
SMS_CMD cmd;
|
||||||
|
int gameID;
|
||||||
|
byte[] data;
|
||||||
|
SendElem( Context context, String phone, SMS_CMD cmd, int gameID,
|
||||||
|
byte[] data ) {
|
||||||
|
super( context, phone );
|
||||||
|
this.cmd = cmd;
|
||||||
|
this.gameID = gameID;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
SendElem( Context context, String phone, SMS_CMD cmd, NetLaunchInfo nli ) {
|
||||||
|
this( context, phone, cmd, 0, nli.asByteArray() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return String.format( "SendElem: {cmd: %s, dataLen: %d}", cmd,
|
||||||
|
data == null ? 0 : data.length );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ReceiveElem extends QueueElem {
|
||||||
|
// One of these two will be set
|
||||||
|
byte[] data;
|
||||||
|
NetLaunchInfo nli;
|
||||||
|
|
||||||
|
ReceiveElem( Context context, String phone, short port, byte[] data )
|
||||||
|
{
|
||||||
|
super( context, phone, port );
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReceiveElem( Context context, NetLaunchInfo nli )
|
||||||
|
{
|
||||||
|
super( context, nli.phone );
|
||||||
|
this.nli = nli;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return String.format( "ReceiveElem: {nli: %s, data: %s}", nli, data );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static NBSProtoThread[] sThreadHolder = { null };
|
||||||
|
|
||||||
|
private static void startThreadOnce()
|
||||||
{
|
{
|
||||||
NBSProtoThread result = null;
|
synchronized ( sThreadHolder ) {
|
||||||
synchronized ( sThreadMap ) {
|
if ( sThreadHolder[0] == null ) {
|
||||||
result = sThreadMap.get( phone );
|
sThreadHolder[0] = new NBSProtoThread();
|
||||||
if ( result == null ) {
|
sThreadHolder[0].start();
|
||||||
result = new NBSProtoThread( phone, port );
|
|
||||||
result.start();
|
|
||||||
sThreadMap.put( phone, result );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Assert.assertTrue( result.getPort() == port || !BuildConfig.DEBUG );
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void removeSelf( NBSProtoThread self )
|
private static void removeSelf( NBSProtoThread self )
|
||||||
{
|
{
|
||||||
synchronized ( sThreadMap ) {
|
synchronized ( sThreadHolder ) {
|
||||||
String phone = self.getPhone();
|
if ( sThreadHolder[0] == self ) {
|
||||||
if ( sThreadMap.get(phone) == self ) {
|
sThreadHolder[0] = null;
|
||||||
sThreadMap.remove( phone );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -464,9 +492,9 @@ public class NBSProto {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int sendViaSMS( byte[] buf, int gameID, CommsAddrRec addr )
|
public int sendViaSMS( byte[] buf, String msgID, int gameID, CommsAddrRec addr )
|
||||||
{
|
{
|
||||||
return sendPacket( mContext, addr.sms_phone, gameID, buf );
|
return sendPacket( mContext, addr.sms_phone, gameID, buf, msgID );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -496,10 +524,10 @@ public class NBSProto {
|
||||||
|
|
||||||
private static void stopCurThreads()
|
private static void stopCurThreads()
|
||||||
{
|
{
|
||||||
synchronized( sThreadMap ) {
|
synchronized( sThreadHolder ) {
|
||||||
for ( String phone : sThreadMap.keySet() ) {
|
NBSProtoThread self = sThreadHolder[0];
|
||||||
// should cause them all to call removeSelf() soon
|
if ( null != self ) {
|
||||||
sThreadMap.get( phone ).interrupt();
|
self.interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue