make a common superclass

This commit is contained in:
Eric House 2019-04-02 13:49:17 -07:00
parent 1c2a0ed994
commit 266c61f84b

View file

@ -167,67 +167,36 @@ public class NBSProto {
s_phoneInfo = null; s_phoneInfo = null;
} }
static abstract class NBSProtoThread extends Thread {
private static class SendThread extends Thread {
private String mPhone; private String mPhone;
private short mPort; private short mPort;
private LinkedBlockingQueue<SendElem> mQueue = new LinkedBlockingQueue<>(); private LinkedBlockingQueue<QueueElem> mQueue = new LinkedBlockingQueue<>();
SendThread( String phone ) { NBSProtoThread( String name, String phone, short port )
{
super( name );
mPhone = phone; mPhone = phone;
mPort = getNBSPort(); mPort = port;
} }
String getPhone() { return mPhone; } String getPhone() { return mPhone; }
short getPort() { return mPort; }
void addPacket( Context context, int gameID, byte[] binmsg ) abstract void removeSelf();
{ abstract void process( QueueElem elem, boolean exiting );
mQueue.add( new SendElem( context, SMS_CMD.DATA, gameID, binmsg ) );
}
void addInvite( Context context, NetLaunchInfo nli ) void add( QueueElem elem ) { mQueue.add( elem ); }
{
mQueue.add( new SendElem( context, SMS_CMD.INVITE, nli ) );
}
void addDeathNotice( Context context, int gameID )
{
mQueue.add( new SendElem( context, SMS_CMD.DEATH, gameID, null ) );
}
void addAck( Context context, int gameID )
{
mQueue.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 for %s", this, mPhone );
int[] waitSecs = { 5 };
while ( !isInterrupted() ) { while ( !isInterrupted() ) {
SendElem elem;
try { try {
elem = mQueue.poll( waitSecs[0], TimeUnit.SECONDS ); QueueElem elem = mQueue.poll( 5, TimeUnit.MINUTES );
process( elem, false );
byte[][] msgs; if ( null == elem ) {
if ( null == elem ) { // timed out? break;
// removeSelf( this );
msgs = XwJNI.smsproto_prepOutbound( SMS_CMD.NONE, 0, null, mPhone,
mPort, true, waitSecs );
} else {
boolean newSMSEnabled = XWPrefs.getSMSProtoEnabled( elem.context );
boolean forceNow = !newSMSEnabled; // || cmd == SMS_CMD.INVITE;
msgs = XwJNI.smsproto_prepOutbound( elem.cmd, elem.gameID, elem.data, mPhone,
mPort, forceNow, waitSecs );
}
if ( null != msgs ) {
sendBuffers( msgs, mPhone, mPort );
}
if ( waitSecs[0] <= 0 ) {
waitSecs[0] = 5;
} }
} catch ( InterruptedException iex ) { } catch ( InterruptedException iex ) {
Log.d( TAG, "poll() threw: %s", iex.getMessage() ); Log.d( TAG, "poll() threw: %s", iex.getMessage() );
@ -235,27 +204,112 @@ public class NBSProto {
} }
} }
// To be safe, call again removeSelf();
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! // Better not be leaving anything behind!
Assert.assertTrue( 0 == mQueue.size() || !BuildConfig.DEBUG ); Assert.assertTrue( 0 == mQueue.size() || !BuildConfig.DEBUG );
Log.d( TAG, "%s.run() DONE", this ); Log.d( TAG, "%s.run() DONE", this );
} }
private void sendBuffers( byte[][] fragments, String phone, short nbsPort ) private SMSServiceHelper mHelper = null;
protected SMSServiceHelper getHelper( Context context )
{
if ( null == mHelper ) {
mHelper = new SMSServiceHelper( context );
}
return mHelper;
}
static class QueueElem {
Context context;
QueueElem( Context context ) { this.context = context; }
}
}
private static class SendThread extends NBSProtoThread {
private int[] mWaitSecs = { 0 };
private boolean mForceNow;
SendThread( String phone ) {
super( "SendThread", phone, getNBSPort() );
boolean newSMSEnabled = XWPrefs.getSMSProtoEnabled( XWApp.getContext() );
mForceNow = !newSMSEnabled;
}
void addPacket( Context context, int gameID, byte[] binmsg )
{
add( new SendElem( context, SMS_CMD.DATA, gameID, binmsg ) );
}
void addInvite( Context context, NetLaunchInfo nli )
{
add( new SendElem( context, SMS_CMD.INVITE, nli ) );
}
void addDeathNotice( 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
protected void removeSelf() { NBSProto.removeSelf( this ); }
@Override
protected void process( QueueElem qelm, boolean exiting )
{
SendElem elem = (SendElem)qelm;
byte[][] msgs;
boolean forceNow = mForceNow || exiting;
if ( null != elem ) {
msgs = XwJNI.smsproto_prepOutbound( elem.cmd, elem.gameID, elem.data,
getPhone(), getPort(), forceNow, mWaitSecs );
} else { // timed out
msgs = XwJNI.smsproto_prepOutbound( SMS_CMD.NONE, 0, null, getPhone(),
getPort(), forceNow, mWaitSecs );
}
if ( null != msgs ) {
sendBuffers( msgs );
}
// if ( mWaitSecs[0] <= 0 ) {
// mWaitSecs[0] = 5;
// }
}
private void sendBuffers( byte[][] fragments )
{ {
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 = getPhoneInfo( context ).number; String myPhone = getPhoneInfo( context ).number;
if ( null != myPhone if ( null != myPhone
&& PhoneNumberUtils.compare( phone, myPhone ) ) { && PhoneNumberUtils.compare( phone, myPhone ) ) {
for ( byte[] fragment : fragments ) { for ( byte[] fragment : fragments ) {
handleFrom( context, fragment, phone, nbsPort ); handleFrom( context, fragment, phone, port );
} }
success = true; success = true;
} }
@ -272,9 +326,9 @@ public class NBSProto {
: makeStatusIntent( context, MSG_DELIVERED ); : makeStatusIntent( context, MSG_DELIVERED );
for ( byte[] fragment : fragments ) { for ( byte[] fragment : fragments ) {
if ( useProxy ) { if ( useProxy ) {
NBSProxy.send( context, phone, nbsPort, fragment ); NBSProxy.send( context, phone, port, fragment );
} else { } else {
mgr.sendDataMessage( phone, null, nbsPort, fragment, mgr.sendDataMessage( phone, null, port, fragment,
sent, delivery ); sent, delivery );
} }
} }
@ -284,8 +338,7 @@ public class NBSProto {
} catch ( NullPointerException npe ) { } catch ( NullPointerException npe ) {
Assert.assertFalse( BuildConfig.DEBUG ); // shouldn't be trying to do this!!! Assert.assertFalse( BuildConfig.DEBUG ); // shouldn't be trying to do this!!!
} catch ( java.lang.SecurityException se ) { } catch ( java.lang.SecurityException se ) {
// getHelper(context).postEvent( MultiEvent.SMS_SEND_FAILED_NOPERMISSION ); getHelper(context).postEvent( MultiEvent.SMS_SEND_FAILED_NOPERMISSION );
Assert.assertFalse( BuildConfig.DEBUG );
} catch ( Exception ee ) { } catch ( Exception ee ) {
Log.ex( TAG, ee ); Log.ex( TAG, ee );
} }
@ -309,13 +362,12 @@ public class NBSProto {
return PendingIntent.getBroadcast( context, 0, intent, 0 ); return PendingIntent.getBroadcast( context, 0, intent, 0 );
} }
private static class SendElem { private static class SendElem extends QueueElem {
Context context;
SMS_CMD cmd; SMS_CMD cmd;
int gameID; int gameID;
byte[] data; byte[] data;
SendElem( Context context, SMS_CMD cmd, int gameID, byte[] data ) { SendElem( Context context, SMS_CMD cmd, int gameID, byte[] data ) {
this.context = context; super( context );
this.cmd = cmd; this.cmd = cmd;
this.gameID = gameID; this.gameID = gameID;
this.data = data; this.data = data;
@ -352,54 +404,39 @@ public class NBSProto {
} }
} }
private static class ReceiveThread extends Thread { private static class ReceiveThread extends NBSProtoThread {
private String mPhone;
private short mPort; private short mPort;
private LinkedBlockingQueue<ReceiveElem> mQueue = new LinkedBlockingQueue<>();
ReceiveThread( String fromPhone, short port ) { ReceiveThread( String fromPhone, short port ) {
mPhone = fromPhone; super( "ReceiveThread", fromPhone, port );
mPort = port;
} }
short getPort() { return mPort; }
void addPacket( Context context, byte[] data ) void addPacket( Context context, byte[] data )
{ {
mQueue.add( new ReceiveElem( context, data ) ); add( new ReceiveElem( context, data ) );
} }
@Override @Override
public void run() { protected void removeSelf() { NBSProto.removeSelf( this ); }
Log.d( TAG, "%s.run() starting", this );
while ( ! isInterrupted() ) {
ReceiveElem elem;
try {
elem = mQueue.poll( 10, TimeUnit.SECONDS );
if ( null != elem ) { @Override
SMSProtoMsg[] msgs = XwJNI.smsproto_prepInbound( elem.data, mPhone, mPort ); protected void process( QueueElem qelem, boolean exiting )
if ( null != msgs ) { {
Log.d( TAG, "got %d msgs combined!", msgs.length ); ReceiveElem elem = (ReceiveElem)qelem;
for ( int ii = 0; ii < msgs.length; ++ii ) { SMSProtoMsg[] msgs = XwJNI.smsproto_prepInbound( elem.data, getPhone(), getPort() );
Log.d( TAG, "%d: type: %s; len: %d", ii, msgs[ii].cmd, msgs[ii].data.length ); if ( null != msgs ) {
} Log.d( TAG, "got %d msgs combined!", msgs.length );
for ( SMSProtoMsg msg : msgs ) { for ( int ii = 0; ii < msgs.length; ++ii ) {
receive( elem.context, msg ); Log.d( TAG, "%d: type: %s; len: %d", ii, msgs[ii].cmd, msgs[ii].data.length );
}
getHelper(elem.context).postEvent( MultiEvent.SMS_RECEIVE_OK );
} else {
Log.d( TAG, "receiveBuffer(): bogus or incomplete message from %s",
mPhone );
}
}
} catch (InterruptedException iex) {
Log.d( TAG, "%s.poll() threw: %s", this, iex.getMessage() );
break;
} }
for ( SMSProtoMsg msg : msgs ) {
receive( elem.context, msg );
}
getHelper(elem.context).postEvent( MultiEvent.SMS_RECEIVE_OK );
} else {
Log.d( TAG, "receiveBuffer(): bogus or incomplete message from %s",
getPhone() );
} }
Log.d( TAG, "%s.run() DONE", this );
} }
private void receive( Context context, SMSProtoMsg msg ) private void receive( Context context, SMSProtoMsg msg )
@ -410,7 +447,7 @@ public class NBSProto {
makeForInvite( context, NetLaunchInfo.makeFrom( context, msg.data ) ); makeForInvite( context, NetLaunchInfo.makeFrom( context, msg.data ) );
break; break;
case DATA: case DATA:
if ( feedMessage( context, msg.gameID, msg.data, new CommsAddrRec( mPhone ) ) ) { if ( feedMessage( context, msg.gameID, msg.data, new CommsAddrRec( getPhone() ) ) ) {
SMSResendReceiver.resetTimer( context ); SMSResendReceiver.resetTimer( context );
} }
break; break;
@ -450,26 +487,17 @@ public class NBSProto {
private void makeForInvite( Context context, NetLaunchInfo nli ) private void makeForInvite( Context context, NetLaunchInfo nli )
{ {
if ( nli != null ) { if ( nli != null ) {
getHelper(context).handleInvitation( nli, mPhone, DictFetchOwner.OWNER_SMS ); String phone = getPhone();
getCurSender( mPhone ).addAck( context, nli.gameID() ); getHelper(context).handleInvitation( nli, phone, DictFetchOwner.OWNER_SMS );
getCurSender( phone ).addAck( context, nli.gameID() );
} }
} }
private SMSServiceHelper mHelper = null; private static class ReceiveElem extends QueueElem {
private SMSServiceHelper getHelper( Context context )
{
if ( null == mHelper ) {
mHelper = new SMSServiceHelper( context );
}
return mHelper;
}
private static class ReceiveElem {
Context context;
byte[] data; byte[] data;
ReceiveElem( Context context, byte[] data ) ReceiveElem( Context context, byte[] data )
{ {
this.context = context; super( context );
this.data = data; this.data = data;
} }
} }
@ -492,6 +520,16 @@ public class NBSProto {
return result; return result;
} }
private static void removeSelf( ReceiveThread self )
{
synchronized ( sReceiversMap ) {
String phone = self.getPhone();
if ( sReceiversMap.get(phone) == self ) {
sReceiversMap.remove( phone );
}
}
}
private static class SMSMsgSink extends MultiMsgSink { private static class SMSMsgSink extends MultiMsgSink {
private Context mContext; private Context mContext;
public SMSMsgSink( Context context ) { public SMSMsgSink( Context context ) {