mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2024-12-28 09:58:30 +01:00
add mqtt as a new transport
This is meant to replace the relay eventually, but for now it's a new option, like BT or SMS, to be chosen. Protocol is handled in common/ code for the first time, meaning that linux and android interact without the need to keep two platforms in sync. Linux uses lib-mosquitto, and Android uses eclipse's Paho client (the generic java version, not the one that uses four-year-old Service patterns and so crashes for SDK >= 26.)
This commit is contained in:
parent
996e0d62c7
commit
f6d7eed84d
72 changed files with 2766 additions and 1098 deletions
|
@ -37,6 +37,9 @@ if ( FABRIC_API_KEY && hasProperty('useCrashlytics') ) { // rm-for-fdroid
|
|||
repositories {
|
||||
google()
|
||||
maven { url 'https://maven.fabric.io/public' } // rm-for-fdroid
|
||||
maven {
|
||||
url "https://repo.eclipse.org/content/repositories/paho-releases/"
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
|
@ -87,6 +90,7 @@ android {
|
|||
buildConfigField "boolean", "LOG_LIFECYLE", "false"
|
||||
buildConfigField "String", "KEY_FCMID", "\"FBMService_fcmid\""
|
||||
buildConfigField "boolean", "ATTACH_SUPPORTED", "false"
|
||||
buildConfigField "boolean", "OFFER_MQTT", "false"
|
||||
}
|
||||
|
||||
xw4NoSMS {
|
||||
|
@ -119,6 +123,7 @@ android {
|
|||
externalNativeBuild.ndkBuild.cFlags += ['-DVARIANT_xw4fdroid']
|
||||
externalNativeBuild.ndkBuild.arguments += ['XW_BT_UUID=' + XW_UUID]
|
||||
}
|
||||
|
||||
xw4d {
|
||||
dimension "variant"
|
||||
buildConfigField "String", "DB_NAME", "\"xwddb\""
|
||||
|
@ -133,6 +138,7 @@ android {
|
|||
buildConfigField "String", "KEY_FCMID", "\"FBMService_fcmid1\""
|
||||
buildConfigField "String", "NFC_AID", "\"${NFC_AID_XW4d}\""
|
||||
resValue "string", "nfc_aid", "$NFC_AID_XW4d"
|
||||
buildConfigField "boolean", "OFFER_MQTT", "true"
|
||||
externalNativeBuild.ndkBuild.cFlags += ['-DVARIANT_xw4d']
|
||||
externalNativeBuild.ndkBuild.arguments += ['XW_BT_UUID=' + XWD_UUID]
|
||||
}
|
||||
|
@ -150,6 +156,7 @@ android {
|
|||
buildConfigField "boolean", "REPORT_LOCKS", "true"
|
||||
buildConfigField "String", "NFC_AID", "\"${NFC_AID_XW4d}\""
|
||||
resValue "string", "nfc_aid", "$NFC_AID_XW4d"
|
||||
buildConfigField "boolean", "OFFER_MQTT", "true"
|
||||
externalNativeBuild.ndkBuild.cFlags += ['-DVARIANT_xw4dNoSMS']
|
||||
externalNativeBuild.ndkBuild.arguments += ['XW_BT_UUID=' + XWD_UUID]
|
||||
}
|
||||
|
@ -331,6 +338,8 @@ dependencies {
|
|||
implementation 'com.google.firebase:firebase-core:16.0.6' // rm-for-fdroid
|
||||
|
||||
implementation 'com.github.eehouse:nbsproxy:v0.2.2'
|
||||
|
||||
implementation "org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.+"
|
||||
}
|
||||
|
||||
task mkImages(type: Exec) {
|
||||
|
|
|
@ -106,6 +106,9 @@
|
|||
<activity android:name="RelayInviteActivity"
|
||||
android:label="@string/relay_invite_title"
|
||||
/>
|
||||
<activity android:name="MQTTInviteActivity"
|
||||
android:label="@string/mqtt_invite_title"
|
||||
/>
|
||||
|
||||
<activity android:name="GameConfigActivity"
|
||||
android:screenOrientation="sensor"
|
||||
|
|
|
@ -749,6 +749,9 @@ public class BoardDelegate extends DelegateBase
|
|||
case RELAY_INVITE_RESULT:
|
||||
missingMeans = InviteMeans.RELAY;
|
||||
break;
|
||||
case MQTT_INVITE_RESULT:
|
||||
missingMeans = InviteMeans.MQTT;
|
||||
break;
|
||||
case P2P_INVITE_RESULT:
|
||||
missingMeans = InviteMeans.WIFIDIRECT;
|
||||
break;
|
||||
|
@ -1351,6 +1354,10 @@ public class BoardDelegate extends DelegateBase
|
|||
RelayInviteDelegate.launchForResult( m_activity, m_mySIS.nMissing, info,
|
||||
RequestCode.RELAY_INVITE_RESULT );
|
||||
break;
|
||||
case MQTT:
|
||||
MQTTInviteDelegate.launchForResult( m_activity, m_mySIS.nMissing, info,
|
||||
RequestCode.MQTT_INVITE_RESULT );
|
||||
break;
|
||||
case WIFIDIRECT:
|
||||
WiDirInviteDelegate.launchForResult( m_activity,
|
||||
m_mySIS.nMissing, info,
|
||||
|
@ -1631,6 +1638,9 @@ public class BoardDelegate extends DelegateBase
|
|||
case COMMS_CONN_NFC:
|
||||
nli.addNFCInfo();
|
||||
break;
|
||||
case COMMS_CONN_MQTT:
|
||||
nli.addMQTTInfo();
|
||||
break;
|
||||
default:
|
||||
Log.w( TAG, "Not doing NFC join for conn type %s",
|
||||
typ.toString() );
|
||||
|
@ -2512,6 +2522,7 @@ public class BoardDelegate extends DelegateBase
|
|||
case COMMS_CONN_SMS:
|
||||
case COMMS_CONN_P2P:
|
||||
case COMMS_CONN_NFC:
|
||||
case COMMS_CONN_MQTT:
|
||||
break;
|
||||
default:
|
||||
Log.w( TAG, "tickle: unexpected type %s", typ.toString() );
|
||||
|
@ -2808,6 +2819,9 @@ public class BoardDelegate extends DelegateBase
|
|||
case WIFIDIRECT:
|
||||
WiDirService.inviteRemote( m_activity, dev, nli );
|
||||
break;
|
||||
case MQTT:
|
||||
MQTTUtils.inviteRemote( m_activity, dev, nli );
|
||||
break;
|
||||
}
|
||||
|
||||
if ( null != dev ) {
|
||||
|
@ -2993,6 +3007,7 @@ public class BoardDelegate extends DelegateBase
|
|||
supported = connTypes.contains( CommsConnType.COMMS_CONN_BT )
|
||||
|| connTypes.contains( CommsConnType.COMMS_CONN_SMS )
|
||||
|| connTypes.contains( CommsConnType.COMMS_CONN_RELAY )
|
||||
|| connTypes.contains( CommsConnType.COMMS_CONN_MQTT )
|
||||
|| connTypes.contains( CommsConnType.COMMS_CONN_P2P );
|
||||
}
|
||||
} else if ( null != context ) {
|
||||
|
@ -3027,6 +3042,7 @@ public class BoardDelegate extends DelegateBase
|
|||
String btAddr = null;
|
||||
String relayID = null;
|
||||
String p2pMacAddress = null;
|
||||
String mqttDevID = null;
|
||||
if ( DeviceRole.SERVER_STANDALONE == gi.serverRole ) {
|
||||
// nothing to do??
|
||||
} else if ( 2 != gi.nPlayers ) {
|
||||
|
@ -3057,6 +3073,10 @@ public class BoardDelegate extends DelegateBase
|
|||
Assert.assertNull( p2pMacAddress );
|
||||
p2pMacAddress = addr.p2p_addr;
|
||||
}
|
||||
if ( addr.contains( CommsConnType.COMMS_CONN_MQTT ) ) {
|
||||
Assert.assertNull( mqttDevID );
|
||||
mqttDevID = addr.mqtt_devID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3065,7 +3085,8 @@ public class BoardDelegate extends DelegateBase
|
|||
String newName = summary.getRematchName( activity );
|
||||
Intent intent = GamesListDelegate
|
||||
.makeRematchIntent( activity, rowid, groupID, gi, connTypes,
|
||||
btAddr, phone, relayID, p2pMacAddress, newName );
|
||||
btAddr, phone, relayID, p2pMacAddress,
|
||||
mqttDevID, newName );
|
||||
if ( null != intent ) {
|
||||
activity.startActivity( intent );
|
||||
}
|
||||
|
@ -3150,6 +3171,11 @@ public class BoardDelegate extends DelegateBase
|
|||
WiDirService.inviteRemote( m_activity, value, nli );
|
||||
recordInviteSent( InviteMeans.WIFIDIRECT, value );
|
||||
}
|
||||
value = m_summary.getStringExtra( GameSummary.EXTRA_REMATCH_MQTT );
|
||||
if ( null != value ) {
|
||||
MQTTUtils.inviteRemote( m_activity, value, nli );
|
||||
recordInviteSent( InviteMeans.MQTT, value );
|
||||
}
|
||||
|
||||
showToast( R.string.rematch_sent_toast );
|
||||
}
|
||||
|
|
|
@ -446,6 +446,9 @@ public class CommsTransport implements TransportProcs,
|
|||
case COMMS_CONN_NFC:
|
||||
nSent = NFCUtils.addMsgFor( buf, gameID );
|
||||
break;
|
||||
case COMMS_CONN_MQTT:
|
||||
nSent = MQTTUtils.send( context, addr.mqtt_devID, gameID, buf );
|
||||
break;
|
||||
default:
|
||||
Assert.failDbg();
|
||||
break;
|
||||
|
|
|
@ -168,6 +168,7 @@ public class ConnStatusHandler {
|
|||
|
||||
private static final CommsConnType[] sDisplayOrder = {
|
||||
CommsConnType.COMMS_CONN_RELAY,
|
||||
CommsConnType.COMMS_CONN_MQTT,
|
||||
CommsConnType.COMMS_CONN_BT,
|
||||
CommsConnType.COMMS_CONN_IR,
|
||||
CommsConnType.COMMS_CONN_IP_DIRECT,
|
||||
|
@ -688,6 +689,9 @@ public class ConnStatusHandler {
|
|||
case COMMS_CONN_NFC:
|
||||
result = NFCUtils.nfcAvail( context )[1];
|
||||
break;
|
||||
case COMMS_CONN_MQTT:
|
||||
result = BuildConfig.OFFER_MQTT;
|
||||
break;
|
||||
default:
|
||||
Log.w( TAG, "connTypeEnabled: %s not handled", connType.toString() );
|
||||
break;
|
||||
|
@ -717,6 +721,9 @@ public class ConnStatusHandler {
|
|||
XWPrefs.getDefaultRelayHost(context),
|
||||
fcmMsg );
|
||||
break;
|
||||
case COMMS_CONN_MQTT:
|
||||
result = String.format("DevID: %s", XwJNI.dvc_getMQTTDevID(null));
|
||||
break;
|
||||
case COMMS_CONN_P2P:
|
||||
result = WiDirService.formatNetStateInfo();
|
||||
break;
|
||||
|
|
|
@ -130,6 +130,9 @@ public class ConnViaViewLayout extends LinearLayout {
|
|||
case COMMS_CONN_P2P:
|
||||
enabled = WiDirWrapper.enabled();
|
||||
break;
|
||||
case COMMS_CONN_MQTT:
|
||||
enabled = BuildConfig.OFFER_MQTT;
|
||||
break;
|
||||
default:
|
||||
Assert.failDbg();
|
||||
break;
|
||||
|
@ -169,6 +172,10 @@ public class ConnViaViewLayout extends LinearLayout {
|
|||
msgID = R.string.not_again_comms_p2p;
|
||||
keyID = R.string.key_na_comms_p2p;
|
||||
break;
|
||||
case COMMS_CONN_MQTT:
|
||||
msgID = R.string.not_again_comms_mqtt;
|
||||
keyID = R.string.key_na_comms_mqtt;
|
||||
break;
|
||||
default:
|
||||
Assert.failDbg();
|
||||
break;
|
||||
|
|
|
@ -377,23 +377,18 @@ public class DBUtils {
|
|||
} // saveSummary
|
||||
|
||||
public static void addRematchInfo( Context context, long rowid, String btAddr,
|
||||
String phone, String relayID, String p2pAddr )
|
||||
String phone, String relayID, String p2pAddr,
|
||||
String mqttDevID )
|
||||
{
|
||||
try ( GameLock lock = GameLock.tryLock(rowid) ) {
|
||||
if ( null != lock ) {
|
||||
GameSummary summary = getSummary( context, lock );
|
||||
if ( null != btAddr ) {
|
||||
summary.putStringExtra( GameSummary.EXTRA_REMATCH_BTADDR, btAddr );
|
||||
}
|
||||
if ( null != phone ) {
|
||||
summary.putStringExtra( GameSummary.EXTRA_REMATCH_PHONE, phone );
|
||||
}
|
||||
if ( null != relayID ) {
|
||||
summary.putStringExtra( GameSummary.EXTRA_REMATCH_RELAY, relayID );
|
||||
}
|
||||
if ( null != p2pAddr ) {
|
||||
summary.putStringExtra( GameSummary.EXTRA_REMATCH_P2P, p2pAddr );
|
||||
}
|
||||
GameSummary summary = getSummary( context, lock )
|
||||
.putStringExtra( GameSummary.EXTRA_REMATCH_BTADDR, btAddr )
|
||||
.putStringExtra( GameSummary.EXTRA_REMATCH_PHONE, phone )
|
||||
.putStringExtra( GameSummary.EXTRA_REMATCH_RELAY, relayID )
|
||||
.putStringExtra( GameSummary.EXTRA_REMATCH_P2P, p2pAddr )
|
||||
.putStringExtra( GameSummary.EXTRA_REMATCH_MQTT, mqttDevID )
|
||||
;
|
||||
saveSummary( context, lock, summary );
|
||||
} else {
|
||||
Assert.failDbg();
|
||||
|
|
|
@ -0,0 +1,298 @@
|
|||
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */
|
||||
/*
|
||||
* Copyright 2012 - 2020 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 android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Button;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.eehouse.android.xw4.DlgDelegate.Action;
|
||||
|
||||
abstract class DevIDInviteDelegate extends InviteDelegate {
|
||||
private static final String TAG = DevIDInviteDelegate.class.getSimpleName();
|
||||
|
||||
private static int[] BUTTONIDS = {
|
||||
R.id.button_relay_add,
|
||||
R.id.manual_add_button,
|
||||
R.id.button_clear,
|
||||
R.id.button_edit,
|
||||
};
|
||||
|
||||
protected ArrayList<DevIDRec> m_devIDRecs;
|
||||
private Activity m_activity;
|
||||
private boolean m_immobileConfirmed; // WTF is this?
|
||||
|
||||
abstract String getRecsKey();
|
||||
abstract String getMeDevID();
|
||||
|
||||
public DevIDInviteDelegate( Delegator delegator, Bundle savedInstanceState )
|
||||
{
|
||||
super( delegator, savedInstanceState );
|
||||
m_activity = delegator.getActivity();
|
||||
}
|
||||
|
||||
static class DevIDRec implements InviterItem, Serializable {
|
||||
public String m_devID;
|
||||
public String m_opponent;
|
||||
public int m_nPlayers;
|
||||
|
||||
public DevIDRec( String opponent, String devID )
|
||||
{
|
||||
m_devID = devID;
|
||||
m_nPlayers = 1;
|
||||
m_opponent = opponent;
|
||||
}
|
||||
|
||||
public String getDev() { return m_devID; }
|
||||
|
||||
public boolean equals( InviterItem item )
|
||||
{
|
||||
return item != null
|
||||
&& ((DevIDRec)item).m_devID == m_devID;
|
||||
}
|
||||
}
|
||||
|
||||
void saveAndRebuild()
|
||||
{
|
||||
DBUtils.setSerializableFor( m_activity, getRecsKey(), m_devIDRecs );
|
||||
rebuildList( false );
|
||||
}
|
||||
|
||||
void rebuildList( boolean checkIfAll )
|
||||
{
|
||||
Collections.sort( m_devIDRecs, new Comparator<DevIDRec>() {
|
||||
public int compare( DevIDRec rec1, DevIDRec rec2 ) {
|
||||
return rec1.m_opponent.compareTo(rec2.m_opponent);
|
||||
}
|
||||
});
|
||||
|
||||
addSelf();
|
||||
updateList( m_devIDRecs );
|
||||
tryEnable();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init( Bundle savedInstanceState )
|
||||
{
|
||||
super.init( savedInstanceState );
|
||||
|
||||
String msg = getString( R.string.button_invite );
|
||||
msg = getQuantityString( R.plurals.invite_relay_desc_fmt, m_nMissing,
|
||||
m_nMissing, msg );
|
||||
super.init( msg, R.string.empty_relay_inviter );
|
||||
addButtonBar( R.layout.relay_buttons, BUTTONIDS );
|
||||
|
||||
getSavedState();
|
||||
rebuildList( true );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBarButtonClicked( int id )
|
||||
{
|
||||
switch( id ) {
|
||||
case R.id.button_relay_add:
|
||||
Utils.notImpl( getActivity() );
|
||||
break;
|
||||
case R.id.manual_add_button:
|
||||
showDialogFragment( DlgID.GET_NUMBER );
|
||||
break;
|
||||
case R.id.button_clear:
|
||||
int count = getChecked().size();
|
||||
String msg = getQuantityString( R.plurals.confirm_clear_relay_fmt,
|
||||
count, count );
|
||||
makeConfirmThenBuilder( msg, Action.CLEAR_ACTION ).show();
|
||||
break;
|
||||
case R.id.button_edit:
|
||||
Object obj = getChecked().iterator().next();
|
||||
Log.d( TAG, "passing %s", obj );
|
||||
showDialogFragment( DlgID.GET_NUMBER, obj );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dialog makeDialog( DBAlert alert, Object[] params )
|
||||
{
|
||||
Dialog dialog = null;
|
||||
DialogInterface.OnClickListener lstnr;
|
||||
switch( alert.getDlgID() ) {
|
||||
case GET_NUMBER: {
|
||||
final DevIDRec curRec =
|
||||
1 <= params.length && params[0] instanceof String
|
||||
? getHasID((String)params[0]) : null;
|
||||
Log.d( TAG, "curRec: %s", curRec );
|
||||
final View getNumView = inflate( R.layout.get_relay );
|
||||
final EditText numField = (EditText)
|
||||
getNumView.findViewById( R.id.num_field );
|
||||
final EditText nameField = (EditText)
|
||||
getNumView.findViewById( R.id.name_field );
|
||||
if ( null != curRec ) {
|
||||
numField.setText( curRec.m_devID );
|
||||
nameField.setText( curRec.m_opponent );
|
||||
}
|
||||
lstnr = new DialogInterface.OnClickListener() {
|
||||
public void onClick( DialogInterface dlg, int item ) {
|
||||
String number = numField.getText().toString();
|
||||
if ( null != number && 0 < number.length() ) {
|
||||
String name = nameField.getText().toString();
|
||||
if ( curRec != null ) {
|
||||
curRec.m_opponent = name;
|
||||
curRec.m_devID = number;
|
||||
} else {
|
||||
DevIDRec rec = new DevIDRec( name, number );
|
||||
m_devIDRecs.add( rec );
|
||||
clearChecked();
|
||||
onItemChecked( rec, true );
|
||||
}
|
||||
saveAndRebuild();
|
||||
}
|
||||
}
|
||||
};
|
||||
dialog = makeAlertBuilder()
|
||||
.setTitle( R.string.get_sms_title )
|
||||
.setView( getNumView )
|
||||
.setPositiveButton( android.R.string.ok, lstnr )
|
||||
.setNegativeButton( android.R.string.cancel, null )
|
||||
.create();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dialog = super.makeDialog( alert, params );
|
||||
break;
|
||||
}
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onChildAdded( View child, InviterItem data )
|
||||
{
|
||||
DevIDRec rec = (DevIDRec)data;
|
||||
((TwoStrsItem)child).setStrings( rec.m_opponent, rec.m_devID );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tryEnable()
|
||||
{
|
||||
super.tryEnable();
|
||||
|
||||
Button button = (Button)findViewById( R.id.button_clear );
|
||||
if ( null != button ) { // may not be there yet
|
||||
button.setEnabled( 0 < getChecked().size() );
|
||||
}
|
||||
button = (Button)findViewById( R.id.button_edit );
|
||||
if ( null != button ) {
|
||||
button.setEnabled( 1 == getChecked().size() );
|
||||
}
|
||||
}
|
||||
|
||||
// DlgDelegate.DlgClickNotify interface
|
||||
@Override
|
||||
public boolean onPosButton( Action action, Object[] params )
|
||||
{
|
||||
boolean handled = true;
|
||||
switch( action ) {
|
||||
case CLEAR_ACTION:
|
||||
clearSelectedImpl();
|
||||
break;
|
||||
case USE_IMMOBILE_ACTION:
|
||||
m_immobileConfirmed = true;
|
||||
break;
|
||||
default:
|
||||
handled = super.onPosButton( action, params );
|
||||
break;
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDismissed( Action action, Object[] params )
|
||||
{
|
||||
boolean handled = true;
|
||||
if ( Action.USE_IMMOBILE_ACTION == action && m_immobileConfirmed ) {
|
||||
makeConfirmThenBuilder( R.string.warn_unlimited,
|
||||
Action.POST_WARNING_ACTION )
|
||||
.setPosButton( R.string.button_yes )
|
||||
.show();
|
||||
} else {
|
||||
handled = false;
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
void addSelf()
|
||||
{
|
||||
boolean hasSelf = false;
|
||||
String me = getMeDevID();
|
||||
for ( DevIDRec rec : m_devIDRecs ) {
|
||||
if ( rec.m_devID.equals( me ) ) {
|
||||
hasSelf = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !hasSelf ) {
|
||||
DevIDRec rec = new DevIDRec( "self", me );
|
||||
m_devIDRecs.add( rec );
|
||||
}
|
||||
}
|
||||
|
||||
void getSavedState()
|
||||
{
|
||||
m_devIDRecs = (ArrayList<DevIDRec>)DBUtils.getSerializableFor( m_activity, getRecsKey() );
|
||||
if ( null == m_devIDRecs ) {
|
||||
m_devIDRecs = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
void clearSelectedImpl()
|
||||
{
|
||||
Set<String> checked = getChecked();
|
||||
for ( Iterator<DevIDRec> iter = m_devIDRecs.iterator(); iter.hasNext(); ) {
|
||||
if ( checked.contains( iter.next().getDev() ) ) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
clearChecked();
|
||||
saveAndRebuild();
|
||||
}
|
||||
|
||||
DevIDRec getHasID( String id )
|
||||
{
|
||||
DevIDRec result = null;
|
||||
for ( DevIDRec rec : m_devIDRecs ) {
|
||||
if ( rec.m_devID.equals(id) ) {
|
||||
result = rec;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -300,6 +300,7 @@ public class DlgDelegate {
|
|||
SMS_DATA, // classic NBS-based data sms
|
||||
EMAIL, NFC, BLUETOOTH, CLIPBOARD, RELAY, WIFIDIRECT,
|
||||
SMS_USER, // just launch the SMS app, as with email
|
||||
MQTT,
|
||||
};
|
||||
boolean onPosButton( Action action, Object... params );
|
||||
boolean onNegButton( Action action, Object... params );
|
||||
|
|
|
@ -735,9 +735,10 @@ public class GameUtils {
|
|||
if ( null != message ) {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction( Intent.ACTION_SEND );
|
||||
String subject =
|
||||
String subject = null != nli.room ?
|
||||
LocUtils.getString( activity, R.string.invite_subject_fmt,
|
||||
nli.room );
|
||||
nli.room )
|
||||
: LocUtils.getString( activity, R.string.invite_subject );
|
||||
intent.putExtra( Intent.EXTRA_SUBJECT, subject );
|
||||
intent.putExtra( Intent.EXTRA_TEXT, Html.fromHtml(message) );
|
||||
|
||||
|
@ -1323,6 +1324,9 @@ public class GameUtils {
|
|||
case COMMS_CONN_P2P:
|
||||
WiDirService.gameDied( addr.p2p_addr, gameID );
|
||||
break;
|
||||
case COMMS_CONN_MQTT:
|
||||
MQTTUtils.gameDied( addr.mqtt_devID, gameID );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,6 +100,9 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
private static final String REMATCH_RELAYID_EXTRA = "rm_relayid";
|
||||
private static final String REMATCH_P2PADDR_EXTRA = "rm_p2pma";
|
||||
|
||||
private static final String INVITE_ACTION = "org.eehouse.action_invite";
|
||||
private static final String INVITE_DATA = "data_invite";
|
||||
|
||||
private static final String ALERT_MSG = "alert_msg";
|
||||
private static final String WITH_EMAIL = "with_email";
|
||||
|
||||
|
@ -2417,12 +2420,13 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
String p2pMacAddress = extras.getString( REMATCH_P2PADDR_EXTRA );
|
||||
String dict = extras.getString( REMATCH_DICT_EXTRA );
|
||||
int lang = extras.getInt( REMATCH_LANG_EXTRA, -1 );
|
||||
String mqttDevID = extras.getString( GameSummary.EXTRA_REMATCH_MQTT );
|
||||
String json = extras.getString( REMATCH_PREFS_EXTRA );
|
||||
|
||||
newid = GameUtils.makeNewMultiGame( m_activity, groupID, dict,
|
||||
lang, json, addrs, gameName );
|
||||
DBUtils.addRematchInfo( m_activity, newid, btAddr, phone,
|
||||
relayID, p2pMacAddress );
|
||||
relayID, p2pMacAddress, mqttDevID );
|
||||
}
|
||||
launchGame( newid );
|
||||
}
|
||||
|
@ -2446,10 +2450,10 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
return handled;
|
||||
}
|
||||
|
||||
private boolean tryNFCIntent( Intent intent )
|
||||
private boolean tryInviteIntent( Intent intent )
|
||||
{
|
||||
boolean result = false;
|
||||
byte[] data = NFCUtils.getFromIntent( intent );
|
||||
byte[] data = getFromIntent( intent );
|
||||
if ( null != data ) {
|
||||
NetLaunchInfo nli = NetLaunchInfo.makeFrom( m_activity, data );
|
||||
if ( null != nli && nli.isValid() ) {
|
||||
|
@ -2681,7 +2685,7 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
|| startHasGameID( intent )
|
||||
|| startRematch( intent )
|
||||
|| tryAlert( intent )
|
||||
|| tryNFCIntent( intent )
|
||||
|| tryInviteIntent( intent )
|
||||
;
|
||||
Log.d( TAG, "tryStartsFromIntent() => handled: %b", handled );
|
||||
}
|
||||
|
@ -2895,7 +2899,7 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
CommsConnTypeSet addrTypes,
|
||||
String btAddr, String phone,
|
||||
String relayID, String p2pMacAddress,
|
||||
String newName )
|
||||
String mqttDevID, String newName )
|
||||
{
|
||||
Intent intent = null;
|
||||
boolean isSolo = gi.serverRole == CurGameInfo.DeviceRole.SERVER_STANDALONE;
|
||||
|
@ -2926,6 +2930,9 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
Assert.assertTrue( addrTypes.contains( CommsConnType.COMMS_CONN_P2P ) );
|
||||
intent.putExtra( REMATCH_P2PADDR_EXTRA, p2pMacAddress );
|
||||
}
|
||||
if ( null != mqttDevID ) {
|
||||
intent.putExtra( GameSummary.EXTRA_REMATCH_MQTT, mqttDevID );
|
||||
}
|
||||
}
|
||||
return intent;
|
||||
}
|
||||
|
@ -2944,15 +2951,40 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
;
|
||||
}
|
||||
|
||||
public static void postNFCInvite( Context context, byte[] data )
|
||||
public static void postReceivedInvite( Context context, byte[] data )
|
||||
{
|
||||
Intent intent = makeSelfIntent( context )
|
||||
.addFlags( Intent.FLAG_ACTIVITY_NEW_TASK )
|
||||
;
|
||||
NFCUtils.populateIntent( context, intent, data );
|
||||
populateInviteIntent( context, intent, data );
|
||||
context.startActivity( intent );
|
||||
}
|
||||
|
||||
private static void populateInviteIntent( Context context, Intent intent,
|
||||
byte[] data )
|
||||
{
|
||||
NetLaunchInfo nli = NetLaunchInfo.makeFrom( context, data );
|
||||
if ( null != nli ) {
|
||||
intent.setAction( INVITE_ACTION )
|
||||
.putExtra( INVITE_DATA, data );
|
||||
} else {
|
||||
Assert.failDbg();
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] getFromIntent( Intent intent )
|
||||
{
|
||||
byte[] result = null;
|
||||
|
||||
String action = intent.getAction();
|
||||
if ( INVITE_ACTION.equals( action ) ) {
|
||||
result = intent.getByteArrayExtra( INVITE_DATA );
|
||||
}
|
||||
|
||||
// Log.d( TAG, "getFromIntent() => %s", result );
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void openGame( Context context, Uri data )
|
||||
{
|
||||
Intent intent = makeSelfIntent( context )
|
||||
|
|
|
@ -68,6 +68,9 @@ public class InviteChoicesAlert extends DlgDelegateAlert {
|
|||
if ( BuildConfig.DEBUG || !BuildConfig.IS_TAGGED_BUILD ) {
|
||||
add( items, means, R.string.invite_choice_relay, InviteMeans.RELAY );
|
||||
}
|
||||
if ( BuildConfig.OFFER_MQTT ) {
|
||||
add( items, means, R.string.invite_choice_mqtt, InviteMeans.MQTT );
|
||||
}
|
||||
if ( WiDirWrapper.enabled() ) {
|
||||
add( items, means, R.string.invite_choice_p2p, InviteMeans.WIFIDIRECT );
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */
|
||||
/*
|
||||
* Copyright 2015 - 2020 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 android.os.Bundle;
|
||||
|
||||
public class MQTTInviteActivity extends InviteActivity {
|
||||
private MQTTInviteDelegate m_dlgt;
|
||||
|
||||
@Override
|
||||
protected void onCreate( Bundle savedInstanceState )
|
||||
{
|
||||
m_dlgt = new MQTTInviteDelegate( this, savedInstanceState );
|
||||
super.onCreate( savedInstanceState, m_dlgt );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */
|
||||
/*
|
||||
* Copyright 2012 - 2020 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 android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import org.eehouse.android.xw4.DBUtils.SentInvitesInfo;
|
||||
import org.eehouse.android.xw4.jni.XwJNI;
|
||||
|
||||
public class MQTTInviteDelegate extends DevIDInviteDelegate {
|
||||
private static final String TAG = MQTTInviteDelegate.class.getSimpleName();
|
||||
private static final String RECS_KEY = TAG + "/recs";
|
||||
private static final boolean MQTTINVITE_SUPPORTED
|
||||
= BuildConfig.DEBUG || !BuildConfig.IS_TAGGED_BUILD;
|
||||
|
||||
private String m_devIDStr;
|
||||
|
||||
public static void launchForResult( Activity activity, int nMissing,
|
||||
SentInvitesInfo info,
|
||||
RequestCode requestCode )
|
||||
{
|
||||
if ( MQTTINVITE_SUPPORTED ) {
|
||||
Intent intent =
|
||||
InviteDelegate.makeIntent( activity, MQTTInviteActivity.class,
|
||||
nMissing, info );
|
||||
activity.startActivityForResult( intent, requestCode.ordinal() );
|
||||
}
|
||||
}
|
||||
|
||||
public MQTTInviteDelegate( Delegator delegator, Bundle savedInstanceState )
|
||||
{
|
||||
super( delegator, savedInstanceState );
|
||||
}
|
||||
|
||||
@Override
|
||||
String getRecsKey()
|
||||
{
|
||||
return RECS_KEY;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getMeDevID()
|
||||
{
|
||||
if ( null == m_devIDStr ) {
|
||||
m_devIDStr = XwJNI.dvc_getMQTTDevID(null);
|
||||
}
|
||||
return m_devIDStr;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,432 @@
|
|||
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */
|
||||
/*
|
||||
* Copyright 2009 - 2020 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 android.content.Context;
|
||||
|
||||
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
|
||||
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
|
||||
import org.eclipse.paho.client.mqttv3.IMqttToken;
|
||||
import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
|
||||
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
|
||||
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
|
||||
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||
import org.eclipse.paho.client.mqttv3.MqttMessage;
|
||||
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
|
||||
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eehouse.android.xw4.jni.CommsAddrRec;
|
||||
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
|
||||
import org.eehouse.android.xw4.jni.XwJNI;
|
||||
import org.eehouse.android.xw4.loc.LocUtils;
|
||||
|
||||
public class MQTTUtils extends Thread implements IMqttActionListener, MqttCallbackExtended {
|
||||
private static final String TAG = MQTTUtils.class.getSimpleName();
|
||||
private static AtomicReference<MQTTUtils> sInstance = new AtomicReference<>();
|
||||
|
||||
private MqttAsyncClient mClient;
|
||||
private long mPauseTime = 0L;
|
||||
private String mDevID;
|
||||
private String mTopic;
|
||||
private Context mContext;
|
||||
private MsgThread mMsgThread;
|
||||
private LinkedBlockingQueue<MessagePair> mOutboundQueue = new LinkedBlockingQueue<>();
|
||||
private boolean mShouldExit = false;
|
||||
|
||||
public static void init( Context context )
|
||||
{
|
||||
Log.d( TAG, "init(OFFER_MQTT:%b)", BuildConfig.OFFER_MQTT );
|
||||
getOrStart( context );
|
||||
}
|
||||
|
||||
public static void onResume( Context context )
|
||||
{
|
||||
Log.d( TAG, "onResume()" );
|
||||
getOrStart( context );
|
||||
}
|
||||
|
||||
static void onConfigChanged( Context context )
|
||||
{
|
||||
MQTTUtils instance = sInstance.get();
|
||||
if ( null != instance ) {
|
||||
clearInstance( instance );
|
||||
}
|
||||
}
|
||||
|
||||
private static MQTTUtils getOrStart( Context context )
|
||||
{
|
||||
MQTTUtils result = null;
|
||||
if ( BuildConfig.OFFER_MQTT ) {
|
||||
result = sInstance.get();
|
||||
if ( null == result ) {
|
||||
try {
|
||||
result = new MQTTUtils(context);
|
||||
setInstance( result );
|
||||
result.start();
|
||||
} catch ( MqttException me ) {
|
||||
result = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static class MessagePair {
|
||||
byte[] mPacket;
|
||||
String mTopic;
|
||||
MessagePair( String topic, byte[] packet ) {
|
||||
mPacket = packet;
|
||||
mTopic = topic;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
setup();
|
||||
while ( !mShouldExit ) {
|
||||
try {
|
||||
// this thread can be fed before the connection is
|
||||
// established. Wait for that before removing packets from the
|
||||
// queue.
|
||||
if ( !mClient.isConnected() ) {
|
||||
Log.d( TAG, "not connected; sleeping..." );
|
||||
Thread.sleep(500);
|
||||
continue;
|
||||
}
|
||||
MessagePair pair = mOutboundQueue.take();
|
||||
MqttMessage message = new MqttMessage( pair.mPacket );
|
||||
mClient.publish( pair.mTopic, message );
|
||||
} catch ( MqttException me ) {
|
||||
me.printStackTrace();
|
||||
break;
|
||||
} catch ( InterruptedException ie ) {
|
||||
ie.printStackTrace();
|
||||
break;
|
||||
}
|
||||
}
|
||||
clearInstance();
|
||||
}
|
||||
|
||||
private void enqueue( String topic, byte[] packet )
|
||||
{
|
||||
mOutboundQueue.add( new MessagePair( topic, packet ) );
|
||||
}
|
||||
|
||||
private static void setInstance( MQTTUtils instance )
|
||||
{
|
||||
MQTTUtils oldInstance = sInstance.getAndSet(instance);
|
||||
if ( null != oldInstance ) {
|
||||
oldInstance.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
private static void clearInstance( MQTTUtils curInstance )
|
||||
{
|
||||
MQTTUtils oldInstance = sInstance.getAndSet(null);
|
||||
if ( curInstance == oldInstance ) {
|
||||
oldInstance.disconnect();
|
||||
}
|
||||
// if ( sResumed ) {
|
||||
// Log.d( TAG, "clearInstance(); looks like I could start another!!" );
|
||||
// }
|
||||
}
|
||||
|
||||
public static void onPause()
|
||||
{
|
||||
// Log.d( TAG, "onPause()" );
|
||||
// MQTTUtils instance = sInstance.get();
|
||||
// if ( null != instance ) {
|
||||
// instance.setPaused(true);
|
||||
// }
|
||||
// DbgUtils.assertOnUIThread();
|
||||
// // sResumed = false;
|
||||
}
|
||||
|
||||
private MQTTUtils( Context context ) throws MqttException
|
||||
{
|
||||
Log.d( TAG, "%H.<init>()", this );
|
||||
mContext = context;
|
||||
String[] topic = {null};
|
||||
mDevID = XwJNI.dvc_getMQTTDevID( topic );
|
||||
mTopic = topic[0];
|
||||
mMsgThread = new MsgThread();
|
||||
|
||||
String host = XWPrefs.getPrefsString( context, R.string.key_mqtt_host );
|
||||
Log.d( TAG, "host: %s", host );
|
||||
int port = XWPrefs.getPrefsInt( context, R.string.key_mqtt_port, 1883 );
|
||||
String url = String.format( java.util.Locale.US, "tcp://%s:%d", host, port );
|
||||
Log.d( TAG, "using url: %s", url );
|
||||
mClient = new MqttAsyncClient( url, mDevID, new MemoryPersistence() );
|
||||
mClient.setCallback( this );
|
||||
}
|
||||
|
||||
private void setup()
|
||||
{
|
||||
Log.d( TAG, "setup()" );
|
||||
MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
|
||||
mqttConnectOptions.setAutomaticReconnect(true);
|
||||
mqttConnectOptions.setCleanSession(false);
|
||||
final int qos = XWPrefs.getPrefsInt( mContext, R.string.key_mqtt_qos, 2 );
|
||||
|
||||
try {
|
||||
mClient.connect( mqttConnectOptions, null, new IMqttActionListener() {
|
||||
@Override
|
||||
public void onSuccess( IMqttToken asyncActionToken ) {
|
||||
Log.d( TAG, "onSuccess()" );
|
||||
try {
|
||||
mClient.subscribe( mTopic, qos, null, MQTTUtils.this );
|
||||
Log.d( TAG, "subscribed to %s", mTopic );
|
||||
mMsgThread.start();
|
||||
} catch ( MqttException ex ) {
|
||||
ex.printStackTrace();
|
||||
} catch ( Exception ex ) {
|
||||
ex.printStackTrace();
|
||||
clearInstance();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
|
||||
Log.d( TAG, "onFailure(%s, %s)", asyncActionToken, exception );
|
||||
ConnStatusHandler.updateStatus( mContext, null,
|
||||
CommsConnType.COMMS_CONN_MQTT,
|
||||
false );
|
||||
clearInstance();
|
||||
}
|
||||
} );
|
||||
} catch ( MqttException ex ) {
|
||||
ex.printStackTrace();
|
||||
} catch ( java.lang.IllegalStateException ise ) {
|
||||
ise.printStackTrace();
|
||||
} catch ( Exception ise ) {
|
||||
ise.printStackTrace();
|
||||
clearInstance();
|
||||
}
|
||||
}
|
||||
|
||||
// private void setPaused( boolean paused )
|
||||
// {
|
||||
// if ( paused ) {
|
||||
// if ( 0 == mPauseTime ) {
|
||||
// mPauseTime = System.currentTimeMillis();
|
||||
// Log.d( TAG, "setPaused() called for first time" );
|
||||
// }
|
||||
// } else {
|
||||
// long diff = System.currentTimeMillis() - mPauseTime;
|
||||
// Log.d( TAG, "unpausing after %d seconds", diff/1000);
|
||||
// mPauseTime = 0;
|
||||
// }
|
||||
// }
|
||||
|
||||
private void disconnect()
|
||||
{
|
||||
if ( 0 == mPauseTime ) {
|
||||
Log.d( TAG, "disconnect()" );
|
||||
} else {
|
||||
long diff = System.currentTimeMillis() - mPauseTime;
|
||||
Log.d( TAG, "disconnect() called %d seconds after app paused", diff/1000 );
|
||||
}
|
||||
try {
|
||||
mShouldExit = true;
|
||||
mClient.unsubscribe( mDevID );
|
||||
mClient.disconnect();
|
||||
Log.d( TAG, "disconnect() succeeded" );
|
||||
mMsgThread.interrupt();
|
||||
} catch (MqttException ex){
|
||||
ex.printStackTrace();
|
||||
} catch (Exception ex){
|
||||
ex.printStackTrace();
|
||||
clearInstance();
|
||||
}
|
||||
}
|
||||
|
||||
private void clearInstance() { clearInstance( this ); }
|
||||
|
||||
public static void inviteRemote( Context context, String invitee, NetLaunchInfo nli )
|
||||
{
|
||||
String[] topic = {invitee};
|
||||
byte[] packet = XwJNI.dvc_makeMQTTInvite( nli, topic );
|
||||
addToSendQueue( context, topic[0], packet );
|
||||
}
|
||||
|
||||
private static void notifyNotHere( Context context, String addressee, int gameID )
|
||||
{
|
||||
String[] topic = {addressee};
|
||||
byte[] packet = XwJNI.dvc_makeMQTTNoSuchGame( gameID, topic );
|
||||
addToSendQueue( context, topic[0], packet );
|
||||
}
|
||||
|
||||
public static int send( Context context, String addressee, int gameID, byte[] buf )
|
||||
{
|
||||
Log.d( TAG, "send(to:%s, len: %d)", addressee, buf.length );
|
||||
String[] topic = {addressee};
|
||||
byte[] packet = XwJNI.dvc_makeMQTTMessage( gameID, buf, topic );
|
||||
addToSendQueue( context, topic[0], packet );
|
||||
return buf.length;
|
||||
}
|
||||
|
||||
private static void addToSendQueue( Context context, String topic, byte[] packet )
|
||||
{
|
||||
MQTTUtils instance = getOrStart( context );
|
||||
if ( null != instance ) {
|
||||
instance.enqueue( topic, packet );
|
||||
}
|
||||
}
|
||||
|
||||
public static void gameDied( String devID, int gameID )
|
||||
{
|
||||
Log.e( TAG, "gameDied() not handled" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectComplete(boolean reconnect, String serverURI)
|
||||
{
|
||||
Log.d( TAG, "%H.connectComplete(reconnect=%b, serverURI=%s)", this,
|
||||
reconnect, serverURI );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionLost( Throwable cause )
|
||||
{
|
||||
Log.d( TAG, "%H.connectionLost(%s)", this, cause );
|
||||
clearInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageArrived( String topic, MqttMessage message) throws Exception
|
||||
{
|
||||
Log.d( TAG, "messageArrived(topic=%s, message=%s)", topic, message );
|
||||
Assert.assertTrueNR( topic.equals(mTopic) );
|
||||
mMsgThread.add( message.getPayload() );
|
||||
ConnStatusHandler
|
||||
.updateStatusIn( mContext, CommsConnType.COMMS_CONN_MQTT, true );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deliveryComplete(IMqttDeliveryToken token)
|
||||
{
|
||||
Log.d( TAG, "deliveryComplete(token=%s)", token );
|
||||
ConnStatusHandler
|
||||
.updateStatusOut( mContext, CommsConnType.COMMS_CONN_MQTT, true );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(IMqttToken asyncActionToken)
|
||||
{
|
||||
Log.d( TAG, "onSuccess(%s)", asyncActionToken );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(IMqttToken asyncActionToken, Throwable exception)
|
||||
{
|
||||
Log.d( TAG, "onFailure(%s, %s)", asyncActionToken, exception );
|
||||
}
|
||||
|
||||
private class MsgThread extends Thread {
|
||||
private LinkedBlockingQueue<byte[]> mQueue = new LinkedBlockingQueue<>();
|
||||
|
||||
void add( byte[] msg ) {
|
||||
mQueue.add( msg );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
for ( ; ; ) {
|
||||
try {
|
||||
byte[] packet = mQueue.take();
|
||||
XwJNI.dvc_parseMQTTPacket( packet );
|
||||
} catch ( InterruptedException ie ) {
|
||||
// Assert.failDbg();
|
||||
break;
|
||||
}
|
||||
}
|
||||
Log.d( TAG, "%H.run() exiting", this );
|
||||
}
|
||||
}
|
||||
|
||||
public static void handleMessage( Context context, CommsAddrRec from,
|
||||
int gameID, byte[] data )
|
||||
{
|
||||
Log.d( TAG, "handleMessage(gameID=%d): got message", gameID );
|
||||
MQTTServiceHelper helper = new MQTTServiceHelper( context, from );
|
||||
long[] rowids = DBUtils.getRowIDsFor( context, gameID );
|
||||
Log.d( TAG, "got %d rows for gameID %d", rowids == null ? 0 : rowids.length, gameID );
|
||||
if ( 0 == rowids.length ) {
|
||||
notifyNotHere( context, from.mqtt_devID, gameID );
|
||||
} else {
|
||||
for ( long rowid : rowids ) {
|
||||
MQTTMsgSink sink = new MQTTMsgSink( context, rowid );
|
||||
helper.receiveMessage( rowid, sink, data );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void handleGameGone( Context context, CommsAddrRec from, int gameID )
|
||||
{
|
||||
new MQTTServiceHelper( context, from )
|
||||
.postEvent( MultiService.MultiEvent.MESSAGE_NOGAME, gameID );
|
||||
}
|
||||
|
||||
private static class MQTTServiceHelper extends XWServiceHelper {
|
||||
private CommsAddrRec mReturnAddr;
|
||||
private Context mContext;
|
||||
|
||||
MQTTServiceHelper( Context context, CommsAddrRec from )
|
||||
{
|
||||
super( context );
|
||||
mContext = context;
|
||||
mReturnAddr = from;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MultiMsgSink getSink( long rowid )
|
||||
{
|
||||
Context context = getContext();
|
||||
return new MQTTMsgSink( context, rowid );
|
||||
}
|
||||
|
||||
@Override
|
||||
void postNotification( String device, int gameID, long rowid )
|
||||
{
|
||||
Assert.failDbg();
|
||||
// Context context = getContext();
|
||||
// String body = LocUtils.getString( mContext, R.string.new_relay_body );
|
||||
// GameUtils.postInvitedNotification( mContext, gameID, body, rowid );
|
||||
}
|
||||
|
||||
private void receiveMessage( long rowid, MQTTMsgSink sink, byte[] msg )
|
||||
{
|
||||
Log.d( TAG, "receiveMessage(rowid=%d, len=%d)", rowid, msg.length );
|
||||
receiveMessage( rowid, sink, msg, mReturnAddr );
|
||||
}
|
||||
}
|
||||
|
||||
private static class MQTTMsgSink extends MultiMsgSink {
|
||||
MQTTMsgSink( Context context, long rowid )
|
||||
{
|
||||
super( context, rowid );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -84,6 +84,11 @@ public class MultiMsgSink implements TransportProcs {
|
|||
return NFCUtils.addMsgFor( buf, gameID );
|
||||
}
|
||||
|
||||
int sendViaMQTT( String addressee, byte[] buf, int gameID )
|
||||
{
|
||||
return MQTTUtils.send( m_context, addressee, gameID, buf );
|
||||
}
|
||||
|
||||
public int numSent()
|
||||
{
|
||||
return m_sentSet.size();
|
||||
|
@ -114,6 +119,9 @@ public class MultiMsgSink implements TransportProcs {
|
|||
case COMMS_CONN_NFC:
|
||||
nSent = sendViaNFC( buf, gameID );
|
||||
break;
|
||||
case COMMS_CONN_MQTT:
|
||||
nSent = sendViaMQTT( addr.mqtt_devID, buf, gameID );
|
||||
break;
|
||||
default:
|
||||
Assert.failDbg();
|
||||
break;
|
||||
|
|
|
@ -50,6 +50,7 @@ public class MultiService {
|
|||
public static final String BT_NAME = "BT_NAME";
|
||||
public static final String BT_ADDRESS = "BT_ADDRESS";
|
||||
public static final String P2P_MAC_ADDRESS = "P2P_MAC_ADDRESS";
|
||||
public static final String MQTT_DEVID = "MQTT_DEVID";
|
||||
private static final String NLI_DATA = "nli";
|
||||
public static final String DUPEMODE = "du";
|
||||
|
||||
|
|
|
@ -59,9 +59,6 @@ public class NFCUtils {
|
|||
private static final String TAG = NFCUtils.class.getSimpleName();
|
||||
private static final boolean USE_BIGINTEGER = true;
|
||||
|
||||
private static final String NFC_TO_SELF_ACTION = "org.eehouse.nfc_to_self";
|
||||
private static final String NFC_TO_SELF_DATA = "nfc_data";
|
||||
|
||||
static final byte VERSION_1 = (byte)0x01;
|
||||
|
||||
private static final byte MESSAGE = 0x01;
|
||||
|
@ -91,31 +88,6 @@ public class NFCUtils {
|
|||
return s_nfcAvail;
|
||||
}
|
||||
|
||||
public static byte[] getFromIntent( Intent intent )
|
||||
{
|
||||
byte[] result = null;
|
||||
|
||||
String action = intent.getAction();
|
||||
if ( NFC_TO_SELF_ACTION.equals( action ) ) {
|
||||
result = intent.getByteArrayExtra( NFC_TO_SELF_DATA );
|
||||
}
|
||||
|
||||
// Log.d( TAG, "getFromIntent() => %s", result );
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void populateIntent( Context context, Intent intent,
|
||||
byte[] data )
|
||||
{
|
||||
NetLaunchInfo nli = NetLaunchInfo.makeFrom( context, data );
|
||||
if ( null != nli ) {
|
||||
intent.setAction( NFC_TO_SELF_ACTION )
|
||||
.putExtra( NFC_TO_SELF_DATA, data );
|
||||
} else {
|
||||
Assert.failDbg();
|
||||
}
|
||||
}
|
||||
|
||||
public static Dialog makeEnableNFCDialog( final Activity activity )
|
||||
{
|
||||
DialogInterface.OnClickListener lstnr
|
||||
|
@ -415,7 +387,7 @@ public class NFCUtils {
|
|||
}
|
||||
break;
|
||||
case INVITE:
|
||||
GamesListDelegate.postNFCInvite( context, body );
|
||||
GamesListDelegate.postReceivedInvite( context, body );
|
||||
break;
|
||||
case REPLY:
|
||||
switch( body[0] ) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* -*- compile-command: "find-and-gradle.sh inXw4Deb"; -*- */
|
||||
/*
|
||||
* Copyright 2009 - 2018 by Eric House (xwords@eehouse.org). All rights
|
||||
* Copyright 2009 - 2020 by Eric House (xwords@eehouse.org). All rights
|
||||
* reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -45,6 +45,7 @@ import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnTypeSet;
|
|||
import org.eehouse.android.xw4.jni.CommsAddrRec;
|
||||
import org.eehouse.android.xw4.jni.CurGameInfo;
|
||||
import org.eehouse.android.xw4.jni.GameSummary;
|
||||
import org.eehouse.android.xw4.jni.XwJNI;
|
||||
import org.eehouse.android.xw4.loc.LocUtils;
|
||||
|
||||
public class NetLaunchInfo implements Serializable {
|
||||
|
@ -65,8 +66,11 @@ public class NetLaunchInfo implements Serializable {
|
|||
private static final String FORCECHANNEL_KEY = "fc";
|
||||
private static final String NAME_KEY = "nm";
|
||||
private static final String P2P_MAC_KEY = "p2";
|
||||
private static final String MQTT_DEVID_KEY = "r2id";
|
||||
private static final String DUPMODE_KEY = "du";
|
||||
|
||||
private static final int EMPTY_SET = new CommsConnTypeSet().toInt();
|
||||
|
||||
protected String gameName;
|
||||
protected String dict;
|
||||
protected int lang;
|
||||
|
@ -83,17 +87,18 @@ public class NetLaunchInfo implements Serializable {
|
|||
protected boolean isGSM;
|
||||
protected int osVers;
|
||||
|
||||
private int _conTypes; // for syncing with the c version only!!
|
||||
// MQTT
|
||||
protected String mqttDevID;
|
||||
|
||||
private int _conTypes;
|
||||
private int gameID = 0;
|
||||
private CommsConnTypeSet m_addrs;
|
||||
private boolean m_valid;
|
||||
private String inviteID;
|
||||
private boolean dupeMode;
|
||||
|
||||
public NetLaunchInfo()
|
||||
{
|
||||
m_addrs = new CommsConnTypeSet();
|
||||
// Give it a random number. It may be overwritten, but so what.
|
||||
_conTypes = EMPTY_SET;
|
||||
inviteID = GameUtils.formatGameID( Utils.nextRandomInt() );
|
||||
}
|
||||
|
||||
|
@ -117,8 +122,9 @@ public class NetLaunchInfo implements Serializable {
|
|||
btName = bundle.getString( MultiService.BT_NAME );
|
||||
btAddress = bundle.getString( MultiService.BT_ADDRESS );
|
||||
p2pMacAddress = bundle.getString( MultiService.P2P_MAC_ADDRESS );
|
||||
mqttDevID = bundle.getString( MultiService.MQTT_DEVID );
|
||||
|
||||
m_addrs = new CommsConnTypeSet( bundle.getInt( ADDRS_KEY ) );
|
||||
_conTypes = bundle.getInt( ADDRS_KEY );
|
||||
|
||||
Utils.testSerialization( this );
|
||||
}
|
||||
|
@ -183,14 +189,15 @@ public class NetLaunchInfo implements Serializable {
|
|||
String val = data.getQueryParameter( ADDRS_KEY );
|
||||
boolean hasAddrs = null != val;
|
||||
if ( hasAddrs ) {
|
||||
m_addrs = new CommsConnTypeSet( Integer.decode( val ) );
|
||||
_conTypes = Integer.decode( val );
|
||||
} else {
|
||||
m_addrs = new CommsConnTypeSet();
|
||||
_conTypes = EMPTY_SET;
|
||||
}
|
||||
|
||||
List<CommsConnType> supported = CommsConnTypeSet.getSupported( context );
|
||||
CommsConnTypeSet addrs = new CommsConnTypeSet( _conTypes );
|
||||
for ( CommsConnType typ : supported ) {
|
||||
if ( hasAddrs && !m_addrs.contains( typ ) ) {
|
||||
if ( hasAddrs && !addrs.contains( typ ) ) {
|
||||
continue;
|
||||
}
|
||||
boolean doAdd;
|
||||
|
@ -222,15 +229,20 @@ public class NetLaunchInfo implements Serializable {
|
|||
case COMMS_CONN_NFC:
|
||||
doAdd = true;
|
||||
break;
|
||||
case COMMS_CONN_MQTT:
|
||||
mqttDevID = data.getQueryParameter( MQTT_DEVID_KEY );
|
||||
doAdd = !hasAddrs && null != mqttDevID;
|
||||
break;
|
||||
default:
|
||||
doAdd = false;
|
||||
Log.d( TAG, "unexpected type: %s", typ );
|
||||
Assert.failDbg();
|
||||
}
|
||||
if ( doAdd ) {
|
||||
m_addrs.add( typ );
|
||||
addrs.add( typ );
|
||||
}
|
||||
}
|
||||
_conTypes = addrs.toInt();
|
||||
|
||||
removeUnsupported( supported );
|
||||
|
||||
|
@ -307,6 +319,9 @@ public class NetLaunchInfo implements Serializable {
|
|||
case COMMS_CONN_NFC:
|
||||
addNFCInfo();
|
||||
break;
|
||||
case COMMS_CONN_MQTT:
|
||||
addMQTTInfo();
|
||||
break;
|
||||
default:
|
||||
Assert.failDbg();
|
||||
break;
|
||||
|
@ -316,12 +331,14 @@ public class NetLaunchInfo implements Serializable {
|
|||
|
||||
public boolean contains( CommsConnType typ )
|
||||
{
|
||||
return m_addrs.contains( typ );
|
||||
return new CommsConnTypeSet( _conTypes ).contains( typ );
|
||||
}
|
||||
|
||||
public void removeAddress( CommsConnType typ )
|
||||
{
|
||||
m_addrs.remove( typ );
|
||||
CommsConnTypeSet addrs = new CommsConnTypeSet( _conTypes );
|
||||
addrs.remove( typ );
|
||||
_conTypes = addrs.toInt();
|
||||
}
|
||||
|
||||
public String inviteID()
|
||||
|
@ -365,12 +382,12 @@ public class NetLaunchInfo implements Serializable {
|
|||
bundle.putString( MultiService.BT_ADDRESS, btAddress );
|
||||
bundle.putString( MultiService.P2P_MAC_ADDRESS, p2pMacAddress );
|
||||
bundle.putInt( MultiService.FORCECHANNEL, forceChannel );
|
||||
bundle.putString( MultiService.MQTT_DEVID, mqttDevID );
|
||||
if ( dupeMode ) {
|
||||
bundle.putBoolean( MultiService.DUPEMODE, true );
|
||||
}
|
||||
|
||||
int flags = m_addrs.toInt();
|
||||
bundle.putInt( ADDRS_KEY, flags );
|
||||
bundle.putInt( ADDRS_KEY, _conTypes );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -391,14 +408,14 @@ public class NetLaunchInfo implements Serializable {
|
|||
&& TextUtils.equals( room, other.room )
|
||||
&& TextUtils.equals( btName, other.btName )
|
||||
&& TextUtils.equals( btAddress, other.btAddress )
|
||||
&& TextUtils.equals( mqttDevID, other.mqttDevID )
|
||||
&& TextUtils.equals( p2pMacAddress, other.p2pMacAddress )
|
||||
&& TextUtils.equals( phone, other.phone )
|
||||
&& isGSM == other. isGSM
|
||||
&& osVers == other.osVers
|
||||
&& _conTypes == other._conTypes
|
||||
&& gameID == other.gameID
|
||||
&& ((null == m_addrs ? (null == other.m_addrs)
|
||||
: m_addrs.equals(other.m_addrs)))
|
||||
&& _conTypes == other._conTypes
|
||||
&& m_valid == other.m_valid
|
||||
&& TextUtils.equals( inviteID, other.inviteID )
|
||||
;
|
||||
|
@ -411,7 +428,7 @@ public class NetLaunchInfo implements Serializable {
|
|||
String result = null;
|
||||
try {
|
||||
JSONObject obj = new JSONObject()
|
||||
.put( ADDRS_KEY, m_addrs.toInt() )
|
||||
.put( ADDRS_KEY, _conTypes )
|
||||
.put( MultiService.LANG, lang )
|
||||
.put( MultiService.DICT, dict )
|
||||
.put( MultiService.GAMENAME, gameName )
|
||||
|
@ -426,23 +443,28 @@ public class NetLaunchInfo implements Serializable {
|
|||
obj.put( MultiService.DUPEMODE, dupeMode );
|
||||
}
|
||||
|
||||
if ( m_addrs.contains( CommsConnType.COMMS_CONN_RELAY ) ) {
|
||||
CommsConnTypeSet addrs = new CommsConnTypeSet( _conTypes );
|
||||
if ( addrs.contains( CommsConnType.COMMS_CONN_RELAY ) ) {
|
||||
obj.put( MultiService.ROOM, room )
|
||||
.put( MultiService.INVITEID, inviteID );
|
||||
}
|
||||
|
||||
if ( m_addrs.contains( CommsConnType.COMMS_CONN_BT ) ) {
|
||||
if ( addrs.contains( CommsConnType.COMMS_CONN_BT ) ) {
|
||||
obj.put( MultiService.BT_NAME, btName )
|
||||
.put( MultiService.BT_ADDRESS, btAddress );
|
||||
}
|
||||
if ( m_addrs.contains( CommsConnType.COMMS_CONN_SMS ) ) {
|
||||
if ( addrs.contains( CommsConnType.COMMS_CONN_SMS ) ) {
|
||||
obj.put( PHONE_KEY, phone )
|
||||
.put( GSM_KEY, isGSM )
|
||||
.put( OSVERS_KEY, osVers );
|
||||
}
|
||||
if ( m_addrs.contains( CommsConnType.COMMS_CONN_P2P ) ) {
|
||||
if ( addrs.contains( CommsConnType.COMMS_CONN_P2P ) ) {
|
||||
obj.put( P2P_MAC_KEY, p2pMacAddress );
|
||||
}
|
||||
|
||||
if ( addrs.contains( CommsConnType.COMMS_CONN_MQTT ) ) {
|
||||
obj.put( MQTT_DEVID_KEY, mqttDevID );
|
||||
}
|
||||
result = obj.toString();
|
||||
|
||||
} catch ( org.json.JSONException jse ) {
|
||||
|
@ -455,7 +477,8 @@ public class NetLaunchInfo implements Serializable {
|
|||
public CommsAddrRec makeAddrRec( Context context )
|
||||
{
|
||||
CommsAddrRec result = new CommsAddrRec();
|
||||
for ( CommsConnType typ : m_addrs.getTypes() ) {
|
||||
CommsConnTypeSet addrs = new CommsConnTypeSet( _conTypes );
|
||||
for ( CommsConnType typ : addrs.getTypes() ) {
|
||||
result.conTypes.add( typ );
|
||||
switch( typ ) {
|
||||
case COMMS_CONN_RELAY:
|
||||
|
@ -474,6 +497,9 @@ public class NetLaunchInfo implements Serializable {
|
|||
break;
|
||||
case COMMS_CONN_NFC:
|
||||
break;
|
||||
case COMMS_CONN_MQTT:
|
||||
result.setMQTTParams( mqttDevID );
|
||||
break;
|
||||
default:
|
||||
Assert.failDbg();
|
||||
break;
|
||||
|
@ -490,8 +516,7 @@ public class NetLaunchInfo implements Serializable {
|
|||
|
||||
int flags = json.optInt(ADDRS_KEY, -1);
|
||||
boolean hasAddrs = -1 != flags;
|
||||
m_addrs = hasAddrs ?
|
||||
new CommsConnTypeSet( flags ) : new CommsConnTypeSet();
|
||||
_conTypes = hasAddrs ? flags : EMPTY_SET;
|
||||
|
||||
lang = json.optInt( MultiService.LANG, -1 );
|
||||
forceChannel = json.optInt( MultiService.FORCECHANNEL, 0 );
|
||||
|
@ -504,8 +529,9 @@ public class NetLaunchInfo implements Serializable {
|
|||
gameID = json.optInt( MultiService.GAMEID, 0 );
|
||||
|
||||
// Try each type
|
||||
CommsConnTypeSet addrs = new CommsConnTypeSet( _conTypes );
|
||||
for ( CommsConnType typ : supported ) {
|
||||
if ( hasAddrs && !m_addrs.contains( typ ) ) {
|
||||
if ( hasAddrs && !addrs.contains( typ ) ) {
|
||||
continue;
|
||||
}
|
||||
boolean doAdd;
|
||||
|
@ -533,16 +559,21 @@ public class NetLaunchInfo implements Serializable {
|
|||
case COMMS_CONN_NFC:
|
||||
doAdd = NFCUtils.nfcAvail( context )[0];
|
||||
break;
|
||||
case COMMS_CONN_MQTT:
|
||||
mqttDevID = json.optString( MQTT_DEVID_KEY );
|
||||
doAdd = BuildConfig.OFFER_MQTT && null != mqttDevID;
|
||||
break;
|
||||
default:
|
||||
doAdd = false;
|
||||
Assert.failDbg();
|
||||
}
|
||||
if ( doAdd ) {
|
||||
m_addrs.add( typ );
|
||||
addrs.add( typ );
|
||||
}
|
||||
}
|
||||
|
||||
removeUnsupported( supported );
|
||||
_conTypes = addrs.toInt();
|
||||
|
||||
calcValid();
|
||||
}
|
||||
|
@ -554,7 +585,6 @@ public class NetLaunchInfo implements Serializable {
|
|||
|
||||
public Uri makeLaunchUri( Context context )
|
||||
{
|
||||
int addrs = m_addrs.toInt();
|
||||
String host = LocUtils.getString( context, R.string.invite_host );
|
||||
host = NetUtils.forceHost( host );
|
||||
Uri.Builder ub = new Uri.Builder()
|
||||
|
@ -566,7 +596,7 @@ public class NetLaunchInfo implements Serializable {
|
|||
appendInt( ub, HEREPLAYERS_KEY, nPlayersH );
|
||||
appendInt( ub, GID_KEY, gameID() );
|
||||
appendInt( ub, FORCECHANNEL_KEY, forceChannel );
|
||||
appendInt( ub, ADDRS_KEY, addrs );
|
||||
appendInt( ub, ADDRS_KEY, _conTypes );
|
||||
ub.appendQueryParameter( NAME_KEY, gameName );
|
||||
if ( dupeMode ) {
|
||||
appendInt( ub, DUPMODE_KEY, 1 );
|
||||
|
@ -576,22 +606,26 @@ public class NetLaunchInfo implements Serializable {
|
|||
ub.appendQueryParameter( WORDLIST_KEY, dict );
|
||||
}
|
||||
|
||||
if ( m_addrs.contains( CommsConnType.COMMS_CONN_RELAY ) ) {
|
||||
CommsConnTypeSet addrs = new CommsConnTypeSet( _conTypes );
|
||||
if ( addrs.contains( CommsConnType.COMMS_CONN_RELAY ) ) {
|
||||
ub.appendQueryParameter( ROOM_KEY, room );
|
||||
ub.appendQueryParameter( ID_KEY, inviteID );
|
||||
}
|
||||
if ( m_addrs.contains( CommsConnType.COMMS_CONN_BT ) ) {
|
||||
if ( addrs.contains( CommsConnType.COMMS_CONN_BT ) ) {
|
||||
ub.appendQueryParameter( BTADDR_KEY, btAddress );
|
||||
ub.appendQueryParameter( BTNAME_KEY, btName );
|
||||
}
|
||||
if ( m_addrs.contains( CommsConnType.COMMS_CONN_SMS ) ) {
|
||||
if ( addrs.contains( CommsConnType.COMMS_CONN_SMS ) ) {
|
||||
ub.appendQueryParameter( PHONE_KEY, phone );
|
||||
appendInt( ub, GSM_KEY, (isGSM? 1 : 0) );
|
||||
appendInt( ub, OSVERS_KEY, osVers );
|
||||
}
|
||||
if ( m_addrs.contains( CommsConnType.COMMS_CONN_P2P ) ) {
|
||||
if ( addrs.contains( CommsConnType.COMMS_CONN_P2P ) ) {
|
||||
ub.appendQueryParameter( P2P_MAC_KEY, p2pMacAddress );
|
||||
}
|
||||
if ( addrs.contains( CommsConnType.COMMS_CONN_MQTT ) ) {
|
||||
ub.appendQueryParameter( MQTT_DEVID_KEY, mqttDevID );
|
||||
}
|
||||
Uri result = ub.build();
|
||||
|
||||
if ( BuildConfig.DEBUG ) { // Test...
|
||||
|
@ -603,11 +637,18 @@ public class NetLaunchInfo implements Serializable {
|
|||
return result;
|
||||
}
|
||||
|
||||
private void add( CommsConnType typ )
|
||||
{
|
||||
CommsConnTypeSet addrs = new CommsConnTypeSet( _conTypes );
|
||||
addrs.add( typ );
|
||||
_conTypes = addrs.toInt();
|
||||
}
|
||||
|
||||
public void addRelayInfo( String aRoom, String inviteID )
|
||||
{
|
||||
room = aRoom;
|
||||
inviteID = inviteID;
|
||||
m_addrs.add( CommsConnType.COMMS_CONN_RELAY );
|
||||
add( CommsConnType.COMMS_CONN_RELAY );
|
||||
}
|
||||
|
||||
public void addBTInfo()
|
||||
|
@ -616,7 +657,7 @@ public class NetLaunchInfo implements Serializable {
|
|||
if ( null != got ) {
|
||||
btName = got[0];
|
||||
btAddress = got[1];
|
||||
m_addrs.add( CommsConnType.COMMS_CONN_BT );
|
||||
add( CommsConnType.COMMS_CONN_BT );
|
||||
} else {
|
||||
Log.w( TAG, "addBTInfo(): no BT info available" );
|
||||
}
|
||||
|
@ -631,19 +672,25 @@ public class NetLaunchInfo implements Serializable {
|
|||
|
||||
osVers = Integer.valueOf( android.os.Build.VERSION.SDK );
|
||||
|
||||
m_addrs.add( CommsConnType.COMMS_CONN_SMS );
|
||||
add( CommsConnType.COMMS_CONN_SMS );
|
||||
}
|
||||
}
|
||||
|
||||
public void addP2PInfo( Context context )
|
||||
{
|
||||
p2pMacAddress = WiDirService.getMyMacAddress( context );
|
||||
m_addrs.add( CommsConnType.COMMS_CONN_P2P );
|
||||
add( CommsConnType.COMMS_CONN_P2P );
|
||||
}
|
||||
|
||||
public void addNFCInfo()
|
||||
{
|
||||
m_addrs.add( CommsConnType.COMMS_CONN_NFC );
|
||||
add( CommsConnType.COMMS_CONN_NFC );
|
||||
}
|
||||
|
||||
public void addMQTTInfo()
|
||||
{
|
||||
add( CommsConnType.COMMS_CONN_MQTT );
|
||||
mqttDevID = XwJNI.dvc_getMQTTDevID( null );
|
||||
}
|
||||
|
||||
public boolean isValid()
|
||||
|
@ -686,16 +733,6 @@ public class NetLaunchInfo implements Serializable {
|
|||
Assert.failDbg();
|
||||
}
|
||||
|
||||
public void freezeAddrs()
|
||||
{
|
||||
_conTypes = m_addrs.toInt();
|
||||
}
|
||||
|
||||
public void unfreezeAddrs()
|
||||
{
|
||||
m_addrs = new CommsConnTypeSet( _conTypes, true );
|
||||
}
|
||||
|
||||
private boolean hasCommon()
|
||||
{
|
||||
return null != dict
|
||||
|
@ -706,20 +743,25 @@ public class NetLaunchInfo implements Serializable {
|
|||
|
||||
private void removeUnsupported( List<CommsConnType> supported )
|
||||
{
|
||||
for ( Iterator<CommsConnType> iter = m_addrs.iterator();
|
||||
CommsConnTypeSet addrs = new CommsConnTypeSet( _conTypes );// , true );
|
||||
for ( Iterator<CommsConnType> iter = addrs.iterator();
|
||||
iter.hasNext(); ) {
|
||||
if ( !supported.contains( iter.next() ) ) {
|
||||
CommsConnType typ = iter.next();
|
||||
if ( !supported.contains( typ ) ) {
|
||||
Log.d( TAG, "removing %s", typ );
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
_conTypes = addrs.toInt();
|
||||
}
|
||||
|
||||
private void calcValid()
|
||||
{
|
||||
boolean valid = hasCommon() && null != m_addrs;
|
||||
boolean valid = hasCommon();
|
||||
// Log.d( TAG, "calcValid(%s); valid (so far): %b", this, valid );
|
||||
if ( valid ) {
|
||||
for ( Iterator<CommsConnType> iter = m_addrs.iterator();
|
||||
for ( Iterator<CommsConnType> iter
|
||||
= new CommsConnTypeSet( _conTypes ).iterator();
|
||||
valid && iter.hasNext(); ) {
|
||||
CommsConnType typ = iter.next();
|
||||
switch ( typ ) {
|
||||
|
@ -732,6 +774,9 @@ public class NetLaunchInfo implements Serializable {
|
|||
case COMMS_CONN_SMS:
|
||||
valid = null != phone && 0 < osVers;
|
||||
break;
|
||||
case COMMS_CONN_MQTT:
|
||||
valid = null != mqttDevID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,9 @@ public class PrefsDelegate extends DelegateBase
|
|||
R.string.key_disable_nag_solo,
|
||||
R.string.key_disable_relay,
|
||||
R.string.key_force_tablet,
|
||||
R.string.key_mqtt_host,
|
||||
R.string.key_mqtt_port,
|
||||
R.string.key_mqtt_qos,
|
||||
};
|
||||
private static Map<String, Integer> s_keysHash = null;
|
||||
|
||||
|
@ -236,6 +239,11 @@ public class PrefsDelegate extends DelegateBase
|
|||
case R.string.key_force_tablet:
|
||||
makeOkOnlyBuilder( R.string.after_restart ).show();
|
||||
break;
|
||||
case R.string.key_mqtt_host:
|
||||
case R.string.key_mqtt_port:
|
||||
case R.string.key_mqtt_qos:
|
||||
MQTTUtils.onConfigChanged( m_activity );
|
||||
break;
|
||||
default:
|
||||
Assert.failDbg();
|
||||
break;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */
|
||||
/*
|
||||
* Copyright 2012 - 2015 by Eric House (xwords@eehouse.org). All rights
|
||||
* Copyright 2012 - 2020 by Eric House (xwords@eehouse.org). All rights
|
||||
* reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -21,59 +21,19 @@
|
|||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.text.method.DigitsKeyListener;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView.OnItemSelectedListener;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.EditText;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.Spinner;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import org.eehouse.android.xw4.DBUtils.SentInvitesInfo;
|
||||
import org.eehouse.android.xw4.DlgDelegate.Action;
|
||||
|
||||
public class RelayInviteDelegate extends InviteDelegate {
|
||||
public class RelayInviteDelegate extends DevIDInviteDelegate {
|
||||
private static final String TAG = RelayInviteDelegate.class.getSimpleName();
|
||||
private static final String RECS_KEY = "TAG" + "/recs";
|
||||
private static final String RECS_KEY = TAG + "/recs";
|
||||
private static final boolean RELAYINVITE_SUPPORTED
|
||||
= BuildConfig.DEBUG || !BuildConfig.IS_TAGGED_BUILD;
|
||||
|
||||
private static int[] BUTTONIDS = {
|
||||
R.id.button_relay_add,
|
||||
R.id.manual_add_button,
|
||||
R.id.button_clear,
|
||||
R.id.button_edit,
|
||||
};
|
||||
|
||||
private static final String SAVE_NAME = "SAVE_NAME";
|
||||
private static final String SAVE_NUMBER = "SAVE_NUMBER";
|
||||
|
||||
private ArrayList<DevIDRec> m_devIDRecs;
|
||||
private boolean m_immobileConfirmed;
|
||||
private Activity m_activity;
|
||||
private String m_devIDStr;
|
||||
private String mRelayDevIDStr;
|
||||
|
||||
public static void launchForResult( Activity activity, int nMissing,
|
||||
SentInvitesInfo info,
|
||||
|
@ -90,633 +50,20 @@ public class RelayInviteDelegate extends InviteDelegate {
|
|||
public RelayInviteDelegate( Delegator delegator, Bundle savedInstanceState )
|
||||
{
|
||||
super( delegator, savedInstanceState );
|
||||
m_activity = delegator.getActivity();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init( Bundle savedInstanceState )
|
||||
String getRecsKey()
|
||||
{
|
||||
if ( RELAYINVITE_SUPPORTED ) {
|
||||
super.init( savedInstanceState );
|
||||
|
||||
String msg = getString( R.string.button_invite );
|
||||
msg = getQuantityString( R.plurals.invite_relay_desc_fmt, m_nMissing,
|
||||
m_nMissing, msg );
|
||||
super.init( msg, R.string.empty_relay_inviter );
|
||||
addButtonBar( R.layout.relay_buttons, BUTTONIDS );
|
||||
|
||||
m_devIDStr = String.format( "%d", DevID.getRelayDevIDInt(m_activity) );
|
||||
|
||||
// getBundledData( savedInstanceState );
|
||||
|
||||
// m_addButton = (ImageButton)findViewById( R.id.manual_add_button );
|
||||
// m_addButton.setOnClickListener( new View.OnClickListener() {
|
||||
// public void onClick( View view )
|
||||
// {
|
||||
// showDialog( DlgID.GET_NUMBER );
|
||||
// }
|
||||
// } );
|
||||
|
||||
// if ( XWPrefs.getRelayInviteToSelfEnabled( m_activity ) ) {
|
||||
// ImageButton addMe = (ImageButton)findViewById( R.id.add_self_button );
|
||||
// addMe.setVisibility( View.VISIBLE );
|
||||
// addMe.setOnClickListener( new View.OnClickListener() {
|
||||
// public void onClick( View view ) {
|
||||
// int devIDInt = DevID.getRelayDevIDInt( m_activity );
|
||||
// String devID = String.format( "%d", devIDInt );
|
||||
// DevIDRec rec = new DevIDRec( "self", devID );
|
||||
// addChecked( rec );
|
||||
// saveAndRebuild();
|
||||
// }
|
||||
// } );
|
||||
// }
|
||||
|
||||
getSavedState();
|
||||
rebuildList( true );
|
||||
}
|
||||
return RECS_KEY;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBarButtonClicked( int id )
|
||||
String getMeDevID()
|
||||
{
|
||||
if ( RELAYINVITE_SUPPORTED ) {
|
||||
switch( id ) {
|
||||
case R.id.button_relay_add:
|
||||
Utils.notImpl( m_activity );
|
||||
break;
|
||||
case R.id.manual_add_button:
|
||||
showDialogFragment( DlgID.GET_NUMBER );
|
||||
break;
|
||||
case R.id.button_clear:
|
||||
int count = getChecked().size();
|
||||
String msg = getQuantityString( R.plurals.confirm_clear_relay_fmt,
|
||||
count, count );
|
||||
makeConfirmThenBuilder( msg, Action.CLEAR_ACTION ).show();
|
||||
break;
|
||||
case R.id.button_edit:
|
||||
showDialogFragment( DlgID.GET_NUMBER, getChecked().iterator().next() );
|
||||
break;
|
||||
}
|
||||
if ( null == mRelayDevIDStr ) {
|
||||
mRelayDevIDStr = String.format( "%d", DevID.getRelayDevIDInt(getActivity()) );
|
||||
}
|
||||
return mRelayDevIDStr;
|
||||
}
|
||||
|
||||
// protected void onSaveInstanceState( Bundle outState )
|
||||
// {
|
||||
// outState.putString( SAVE_NAME, m_pendingName );
|
||||
// outState.putString( SAVE_NUMBER, m_pendingNumber );
|
||||
// }
|
||||
|
||||
// private void getBundledData( Bundle bundle )
|
||||
// {
|
||||
// if ( null != bundle ) {
|
||||
// m_pendingName = bundle.getString( SAVE_NAME );
|
||||
// m_pendingNumber = bundle.getString( SAVE_NUMBER );
|
||||
// }
|
||||
// }
|
||||
|
||||
// protected void onActivityResult( int requestCode, int resultCode,
|
||||
// Intent data )
|
||||
// {
|
||||
// // super.onActivityResult( requestCode, resultCode, data );
|
||||
// if ( Activity.RESULT_CANCELED != resultCode && data != null ) {
|
||||
// switch (requestCode) {
|
||||
// case GET_CONTACT:
|
||||
// addPhoneNumbers( data );
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
@Override
|
||||
protected Dialog makeDialog( DBAlert alert, Object[] params )
|
||||
{
|
||||
Dialog dialog = null;
|
||||
if ( RELAYINVITE_SUPPORTED ) {
|
||||
DialogInterface.OnClickListener lstnr;
|
||||
switch( alert.getDlgID() ) {
|
||||
case GET_NUMBER: {
|
||||
final DevIDRec curRec =
|
||||
1 <= params.length && params[0] instanceof DevIDRec
|
||||
? (DevIDRec)params[0] : null;
|
||||
final View getNumView = inflate( R.layout.get_relay );
|
||||
final EditText numField = (EditText)
|
||||
getNumView.findViewById( R.id.num_field );
|
||||
numField.setKeyListener(DigitsKeyListener.getInstance());
|
||||
final EditText nameField = (EditText)
|
||||
getNumView.findViewById( R.id.name_field );
|
||||
if ( null != curRec ) {
|
||||
numField.setText( curRec.m_devID );
|
||||
nameField.setText( curRec.m_opponent );
|
||||
}
|
||||
lstnr = new DialogInterface.OnClickListener() {
|
||||
public void onClick( DialogInterface dlg, int item ) {
|
||||
String number = numField.getText().toString();
|
||||
if ( null != number && 0 < number.length() ) {
|
||||
String name = nameField.getText().toString();
|
||||
if ( curRec != null ) {
|
||||
curRec.m_opponent = name;
|
||||
curRec.m_devID = number;
|
||||
} else {
|
||||
DevIDRec rec = new DevIDRec( name, number );
|
||||
m_devIDRecs.add( rec );
|
||||
clearChecked();
|
||||
onItemChecked( rec, true );
|
||||
}
|
||||
saveAndRebuild();
|
||||
}
|
||||
}
|
||||
};
|
||||
dialog = makeAlertBuilder()
|
||||
.setTitle( R.string.get_sms_title )
|
||||
.setView( getNumView )
|
||||
.setPositiveButton( android.R.string.ok, lstnr )
|
||||
.setNegativeButton( android.R.string.cancel, null )
|
||||
.create();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dialog = super.makeDialog( alert, params );
|
||||
break;
|
||||
}
|
||||
}
|
||||
return dialog;
|
||||
}
|
||||
|
||||
// protected Dialog onCreateDialog( int id )
|
||||
// {
|
||||
// Dialog dialog = super.onCreateDialog( id );
|
||||
// if ( null == dialog ) {
|
||||
// DialogInterface.OnClickListener lstnr;
|
||||
// DlgID dlgID = DlgID.values()[id];
|
||||
// switch( dlgID ) {
|
||||
// case GET_NUMBER:
|
||||
// final GameNamer namerView =
|
||||
// (GameNamer)inflate( R.layout.rename_game );
|
||||
// namerView.setLabel( R.string.get_relay_number );
|
||||
// namerView.setKeyListener(DialerKeyListener.getInstance());
|
||||
// lstnr = new DialogInterface.OnClickListener() {
|
||||
// public void onClick( DialogInterface dlg, int item ) {
|
||||
// String devID = namerView.getName();
|
||||
// if ( 0 < devID.length() ) {
|
||||
// DevIDRec rec = new DevIDRec( devID );
|
||||
// addChecked( new DevIDRec( devID ) );
|
||||
// saveAndRebuild();
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// dialog = makeAlertBuilder()
|
||||
// .setNegativeButton( android.R.string.cancel, null )
|
||||
// .setPositiveButton( android.R.string.ok, lstnr )
|
||||
// .setView( namerView )
|
||||
// .create();
|
||||
// break;
|
||||
// }
|
||||
// setRemoveOnDismiss( dialog, dlgID );
|
||||
// }
|
||||
// return dialog;
|
||||
// }
|
||||
|
||||
@Override
|
||||
protected void onChildAdded( View child, InviterItem data )
|
||||
{
|
||||
DevIDRec rec = (DevIDRec)data;
|
||||
((TwoStrsItem)child).setStrings( rec.m_opponent, rec.m_devID );
|
||||
}
|
||||
|
||||
// We want to present user with list of previous opponents and devices. We
|
||||
// can easily get list of relayIDs. The relay, if reachable, can convert
|
||||
// that to a (likely shorter) list of devices. Then for each deviceID,
|
||||
// open the newest game with a relayID mapping to it and get the name of
|
||||
// the opponent?
|
||||
|
||||
// protected void scan()
|
||||
// {
|
||||
// long[][] rowIDss = new long[1][];
|
||||
// String[] relayIDs = DBUtils.getRelayIDs( m_activity, rowIDss );
|
||||
|
||||
// if ( null != relayIDs && 0 < relayIDs.length ) {
|
||||
// new ListOpponentsTask( m_activity, relayIDs, rowIDss[0] ).execute();
|
||||
// }
|
||||
|
||||
// // Intent intent = new Intent( Intent.ACTION_PICK,
|
||||
// // ContactsContract.Contacts.CONTENT_URI );
|
||||
// // intent.setType( Phone.CONTENT_TYPE );
|
||||
// // startActivityForResult( intent, GET_CONTACT );
|
||||
// }
|
||||
|
||||
// @Override
|
||||
// protected void clearSelected( Integer[] selected )
|
||||
// {
|
||||
// makeConfirmThenBuilder( R.string.confirm_clear_relay, Action.CLEAR_ACTION )
|
||||
// .show();
|
||||
// }
|
||||
|
||||
// protected void listSelected( String[][] devsP, int[][] countsP )
|
||||
// {
|
||||
// // int count = m_adapter.getCount();
|
||||
// // String[] result = new String[countChecks()];
|
||||
// // int[] counts = new int[result.length];
|
||||
|
||||
// // int index = 0;
|
||||
// // Iterator<DevIDRec> iter = m_devIDRecs.iterator();
|
||||
// // for ( int ii = 0; iter.hasNext(); ++ii ) {
|
||||
// // DevIDRec rec = iter.next();
|
||||
// // if ( rec.m_isChecked ) {
|
||||
// // counts[index] = rec.m_nPlayers;
|
||||
// // result[index] = ((SMSListItem)m_adapter.getItem(ii)).getNumber();
|
||||
// // index++;
|
||||
// // }
|
||||
// // }
|
||||
// // devsP[0] = result;
|
||||
// // if ( null != countsP ) {
|
||||
// // countsP[0] = counts;
|
||||
// // }
|
||||
// }
|
||||
|
||||
@Override
|
||||
protected void tryEnable()
|
||||
{
|
||||
if ( RELAYINVITE_SUPPORTED ) {
|
||||
super.tryEnable();
|
||||
|
||||
Button button = (Button)findViewById( R.id.button_clear );
|
||||
if ( null != button ) { // may not be there yet
|
||||
button.setEnabled( 0 < getChecked().size() );
|
||||
}
|
||||
button = (Button)findViewById( R.id.button_edit );
|
||||
if ( null != button ) {
|
||||
button.setEnabled( 1 == getChecked().size() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DlgDelegate.DlgClickNotify interface
|
||||
@Override
|
||||
public boolean onPosButton( Action action, Object[] params )
|
||||
{
|
||||
boolean handled = true;
|
||||
if ( RELAYINVITE_SUPPORTED ) {
|
||||
switch( action ) {
|
||||
case CLEAR_ACTION:
|
||||
clearSelectedImpl();
|
||||
break;
|
||||
case USE_IMMOBILE_ACTION:
|
||||
m_immobileConfirmed = true;
|
||||
break;
|
||||
default:
|
||||
handled = super.onPosButton( action, params );
|
||||
break;
|
||||
}
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDismissed( Action action, Object[] params )
|
||||
{
|
||||
boolean handled = true;
|
||||
if ( RELAYINVITE_SUPPORTED ) {
|
||||
if ( Action.USE_IMMOBILE_ACTION == action && m_immobileConfirmed ) {
|
||||
makeConfirmThenBuilder( R.string.warn_unlimited,
|
||||
Action.POST_WARNING_ACTION )
|
||||
.setPosButton( R.string.button_yes )
|
||||
.show();
|
||||
} else {
|
||||
handled = false;
|
||||
}
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
// private int countChecks()
|
||||
// {
|
||||
// int count = 0;
|
||||
// if ( null != m_devIDRecs ) {
|
||||
// Iterator<DevIDRec> iter = m_devIDRecs.iterator();
|
||||
// while ( iter.hasNext() ) {
|
||||
// if ( iter.next().m_isChecked ) {
|
||||
// ++count;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return count;
|
||||
// }
|
||||
|
||||
// private void addPhoneNumbers( Intent intent )
|
||||
// {
|
||||
// Uri data = intent.getData();
|
||||
// Cursor cursor = m_activity
|
||||
// .managedQuery( data,
|
||||
// new String[] { Phone.DISPLAY_NAME,
|
||||
// Phone.NUMBER,
|
||||
// Phone.TYPE },
|
||||
// null, null, null );
|
||||
// // Have seen a crash reporting
|
||||
// // "android.database.StaleDataException: Attempted to access a
|
||||
// // cursor after it has been closed." when the query takes a
|
||||
// // long time to return. Be safe.
|
||||
// if ( null != cursor && !cursor.isClosed() ) {
|
||||
// if ( cursor.moveToFirst() ) {
|
||||
// String name =
|
||||
// cursor.getString( cursor.
|
||||
// getColumnIndex( Phone.DISPLAY_NAME));
|
||||
// String number =
|
||||
// cursor.getString( cursor.
|
||||
// getColumnIndex( Phone.NUMBER ) );
|
||||
|
||||
// int type = cursor.getInt( cursor.
|
||||
// getColumnIndex( Phone.TYPE ) );
|
||||
// // m_pendingName = name;
|
||||
// // m_pendingNumber = number;
|
||||
// if ( Phone.TYPE_MOBILE == type ) {
|
||||
// showConfirmThen( R.string.warn_unlimited,
|
||||
// R.string.button_yes,
|
||||
// Action.POST_WARNING_ACTION );
|
||||
// } else {
|
||||
// m_immobileConfirmed = false;
|
||||
// String msg = getString( R.string.warn_nomobile_fmt,
|
||||
// number, name );
|
||||
// showConfirmThen( msg, R.string.button_yes,
|
||||
// Action.USE_IMMOBILE_ACTION );
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } // addPhoneNumbers
|
||||
|
||||
private void addSelf()
|
||||
{
|
||||
boolean hasSelf = false;
|
||||
for ( DevIDRec rec : m_devIDRecs ) {
|
||||
if ( rec.m_devID.equals( m_devIDStr ) ) {
|
||||
hasSelf = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !hasSelf ) {
|
||||
DevIDRec rec = new DevIDRec( "me", m_devIDStr );
|
||||
m_devIDRecs.add( rec );
|
||||
}
|
||||
}
|
||||
|
||||
private void rebuildList( boolean checkIfAll )
|
||||
{
|
||||
Collections.sort( m_devIDRecs, new Comparator<DevIDRec>() {
|
||||
public int compare( DevIDRec rec1, DevIDRec rec2 ) {
|
||||
return rec1.m_opponent.compareTo(rec2.m_opponent);
|
||||
}
|
||||
});
|
||||
|
||||
addSelf();
|
||||
updateList( m_devIDRecs );
|
||||
tryEnable();
|
||||
}
|
||||
|
||||
private void getSavedState()
|
||||
{
|
||||
m_devIDRecs = (ArrayList<DevIDRec>)DBUtils.getSerializableFor( m_activity, RECS_KEY );
|
||||
if ( null == m_devIDRecs ) {
|
||||
m_devIDRecs = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
private void saveAndRebuild()
|
||||
{
|
||||
DBUtils.setSerializableFor( m_activity, RECS_KEY, m_devIDRecs );
|
||||
rebuildList( false );
|
||||
}
|
||||
|
||||
// private void addChecked( DevIDRec rec )
|
||||
// {
|
||||
// if ( m_nMissing <= countChecks() ) {
|
||||
// Iterator<DevIDRec> iter = m_devIDRecs.iterator();
|
||||
// while ( iter.hasNext() ) {
|
||||
// iter.next().m_isChecked = false;
|
||||
// }
|
||||
// }
|
||||
|
||||
// rec.m_isChecked = true;
|
||||
// m_devIDRecs.add( rec );
|
||||
// }
|
||||
|
||||
private void clearSelectedImpl()
|
||||
{
|
||||
Set<String> checked = getChecked();
|
||||
for ( Iterator<DevIDRec> iter = m_devIDRecs.iterator(); iter.hasNext(); ) {
|
||||
if ( checked.contains( iter.next().getDev() ) ) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
clearChecked();
|
||||
saveAndRebuild();
|
||||
}
|
||||
|
||||
private static class DevIDRec implements InviterItem, Serializable {
|
||||
public String m_devID;
|
||||
public String m_opponent;
|
||||
public int m_nPlayers;
|
||||
// public DevIDRec( String name, String devID )
|
||||
// {
|
||||
// this( name, devID, false );
|
||||
// }
|
||||
// public DevIDRec( String devID )
|
||||
// {
|
||||
// this( null, devID, false );
|
||||
// }
|
||||
|
||||
public DevIDRec( String opponent, String devID )
|
||||
{
|
||||
m_devID = devID;
|
||||
m_nPlayers = 1;
|
||||
m_opponent = opponent;
|
||||
}
|
||||
|
||||
public String getDev() { return m_devID; }
|
||||
|
||||
public boolean equals( InviterItem item )
|
||||
{
|
||||
return item != null
|
||||
&& ((DevIDRec)item).m_devID == m_devID;
|
||||
}
|
||||
}
|
||||
|
||||
// private class RelayDevsAdapter extends XWListAdapter {
|
||||
// private SMSListItem[] m_items;
|
||||
|
||||
// public RelayDevsAdapter()
|
||||
// {
|
||||
// super( m_devIDRecs.size() );
|
||||
// m_items = new SMSListItem[m_devIDRecs.size()];
|
||||
// }
|
||||
|
||||
// public Object getItem( final int position )
|
||||
// {
|
||||
// // For some reason I can't cache items to be returned.
|
||||
// // Checking/unchecking breaks for some but not all items,
|
||||
// // with some relation to whether they were scrolled into
|
||||
// // view. So build them anew each time (but still cache
|
||||
// // for by-index access.)
|
||||
|
||||
// SMSListItem item =
|
||||
// (SMSListItem)inflate( R.layout.smsinviter_item );
|
||||
// // item.setChecked( m_devIDRecs.get(position).m_isChecked );
|
||||
|
||||
// CompoundButton.OnCheckedChangeListener lstnr =
|
||||
// new CompoundButton.OnCheckedChangeListener() {
|
||||
// public void onCheckedChanged( CompoundButton bv,
|
||||
// boolean isChecked ) {
|
||||
// m_devIDRecs.get(position).m_isChecked = isChecked;
|
||||
// tryEnable();
|
||||
// }
|
||||
// };
|
||||
// item.setOnCheckedChangeListener( lstnr );
|
||||
// final DevIDRec rec = m_devIDRecs.get( position );
|
||||
// item.setContents( rec.m_opponent, rec.m_devID );
|
||||
// m_items[position] = item;
|
||||
|
||||
// // Set up spinner
|
||||
// Assert.assertTrue( 1 == rec.m_nPlayers );
|
||||
// if ( XWPrefs.getCanInviteMulti( m_activity ) && 1 < m_nMissing ) {
|
||||
// Spinner spinner = (Spinner)
|
||||
// item.findViewById(R.id.nperdev_spinner);
|
||||
// ArrayAdapter<String> adapter =
|
||||
// new ArrayAdapter<>( m_activity, android.R.layout
|
||||
// .simple_spinner_item );
|
||||
// for ( int ii = 1; ii <= m_nMissing; ++ii ) {
|
||||
// String str = getQuantityString( R.plurals.nplayers_fmt, ii, ii );
|
||||
// adapter.add( str );
|
||||
// }
|
||||
// spinner.setAdapter( adapter );
|
||||
// spinner.setVisibility( View.VISIBLE );
|
||||
// spinner.setOnItemSelectedListener( new OnItemSelectedListener() {
|
||||
// public void onItemSelected( AdapterView<?> parent,
|
||||
// View view, int pos,
|
||||
// long id )
|
||||
// {
|
||||
// rec.m_nPlayers = 1 + pos;
|
||||
// tryEnable();
|
||||
// }
|
||||
|
||||
// public void onNothingSelected( AdapterView<?> parent ) {}
|
||||
// } );
|
||||
// }
|
||||
|
||||
// return item;
|
||||
// }
|
||||
|
||||
// public View getView( final int position, View convertView,
|
||||
// ViewGroup parent ) {
|
||||
// return (View)getItem( position );
|
||||
// }
|
||||
// }
|
||||
|
||||
// private class ListOpponentsTask extends AsyncTask<Void, Void, Set<String>> {
|
||||
// private Context m_context;
|
||||
// private String[] m_relayIDs;
|
||||
// private long[] m_rowIDs;
|
||||
|
||||
// public ListOpponentsTask( Context context, String[] relayIDs, long[] rowIDs ) {
|
||||
// m_context = context;
|
||||
// m_relayIDs = relayIDs;
|
||||
// m_rowIDs = rowIDs;
|
||||
// }
|
||||
|
||||
// @Override protected Set<String> doInBackground( Void... unused )
|
||||
// {
|
||||
// Set<String> result = null;
|
||||
// JSONObject reply = null;
|
||||
// try {
|
||||
// startProgress( R.string.fetching_from_relay );
|
||||
|
||||
// JSONArray ids = new JSONArray();
|
||||
// for ( String id : m_relayIDs ) {
|
||||
// ids.put( id );
|
||||
// }
|
||||
// JSONObject params = new JSONObject();
|
||||
// params.put( "relayIDs", ids );
|
||||
// params.put( "me", DevID.getRelayDevIDInt( m_activity ) );
|
||||
// Log.i( TAG, "sending to server: %s", params.toString() );
|
||||
|
||||
// HttpURLConnection conn = NetUtils.makeHttpConn( m_context, "opponentIDsFor" );
|
||||
// if ( null != conn ) {
|
||||
// String str = NetUtils.runConn( conn, params );
|
||||
// Log.i( TAG, "got json from server: %s", str );
|
||||
// reply = new JSONObject( str );
|
||||
// }
|
||||
|
||||
// if ( null != reply ) {
|
||||
// result = new HashSet<>();
|
||||
|
||||
// setProgressMsg( R.string.processing_games );
|
||||
|
||||
// JSONArray objs = reply.getJSONArray("devIDs");
|
||||
// for ( int ii = 0; ii < objs.length(); ++ii ) {
|
||||
// JSONObject obj = objs.getJSONObject( ii );
|
||||
// Iterator<String> keys = obj.keys();
|
||||
// Assert.assertTrue( keys.hasNext() );
|
||||
// String key = keys.next();
|
||||
// Assert.assertFalse( keys.hasNext() );
|
||||
// JSONArray devIDs2 = obj.getJSONArray( key );
|
||||
// for ( int jj = 0; jj < devIDs2.length(); ++jj ) {
|
||||
// result.add( devIDs2.getString(jj) );
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// } catch ( org.json.JSONException je ) {
|
||||
// Log.ex( TAG, je );
|
||||
// }
|
||||
|
||||
// stopProgress();
|
||||
// return result;
|
||||
// }
|
||||
|
||||
// @Override protected void onPostExecute( Set<String> devIDs )
|
||||
// {
|
||||
// if ( null == devIDs ) {
|
||||
// Log.w( TAG, "onPostExecute: no results from server?" );
|
||||
// } else {
|
||||
// m_devIDRecs = new ArrayList<>(devIDs.size());
|
||||
// Iterator<String> iter = devIDs.iterator();
|
||||
// while ( iter.hasNext() ) {
|
||||
// String devID = iter.next();
|
||||
// DevIDRec rec = new DevIDRec( "name", devID );
|
||||
// m_devIDRecs.add( rec );
|
||||
// }
|
||||
|
||||
// // m_adapter = new RelayDevsAdapter();
|
||||
// // setListAdapter( m_adapter );
|
||||
// // // m_checked.clear();
|
||||
// // tryEnable();
|
||||
// }
|
||||
// }
|
||||
|
||||
// private void startProgress( final int msgID )
|
||||
// {
|
||||
// runOnUiThread( new Runnable() {
|
||||
// public void run() {
|
||||
// RelayInviteDelegate.this
|
||||
// .startProgress( R.string.rel_invite_title, msgID );
|
||||
// }
|
||||
// } );
|
||||
// }
|
||||
|
||||
// private void setProgressMsg( final int id )
|
||||
// {
|
||||
// runOnUiThread( new Runnable() {
|
||||
// public void run() {
|
||||
// RelayInviteDelegate.this.setProgressMsg( id );
|
||||
// }
|
||||
// } );
|
||||
// }
|
||||
|
||||
// private void stopProgress()
|
||||
// {
|
||||
// runOnUiThread( new Runnable() {
|
||||
// public void run() {
|
||||
// RelayInviteDelegate.this.stopProgress();
|
||||
// }
|
||||
// } );
|
||||
// }
|
||||
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ public enum RequestCode {
|
|||
SMS_DATA_INVITE_RESULT,
|
||||
RELAY_INVITE_RESULT,
|
||||
P2P_INVITE_RESULT,
|
||||
MQTT_INVITE_RESULT,
|
||||
|
||||
// PermUtils
|
||||
PERM_REQUEST,
|
||||
|
|
|
@ -101,6 +101,8 @@ public class XWApp extends Application
|
|||
NBSProxy.register( this, mPort, BuildConfig.APPLICATION_ID, this );
|
||||
|
||||
DupeModeTimer.init( this );
|
||||
|
||||
MQTTUtils.init( this );
|
||||
}
|
||||
|
||||
@OnLifecycleEvent(ON_ANY)
|
||||
|
@ -109,12 +111,16 @@ public class XWApp extends Application
|
|||
Log.d( TAG, "onAny(%s)", event );
|
||||
switch( event ) {
|
||||
case ON_RESUME:
|
||||
MQTTUtils.onResume( this );
|
||||
// Do here what checkForMoves does
|
||||
if ( null != DBUtils.getRelayIDs( this, null ) ) {
|
||||
RelayService.timerFired( this );
|
||||
}
|
||||
GameUtils.resendAllIf( this, null );
|
||||
break;
|
||||
case ON_PAUSE:
|
||||
MQTTUtils.onPause();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -205,7 +205,19 @@ public class XWPrefs {
|
|||
String key = context.getString( keyID );
|
||||
SharedPreferences sp = PreferenceManager
|
||||
.getDefaultSharedPreferences( context );
|
||||
return sp.getInt( key, defaultValue );
|
||||
int result;
|
||||
try {
|
||||
result = sp.getInt( key, defaultValue );
|
||||
// If it's in a pref, it'll be a string (editable) So will get CCE
|
||||
} catch ( ClassCastException cce ) {
|
||||
String asStr = sp.getString( key, String.format( "%d", defaultValue ) );
|
||||
try {
|
||||
result = Integer.parseInt( asStr );
|
||||
} catch ( Exception ex ) {
|
||||
result = defaultValue;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void setPrefsInt( Context context, int keyID, int newValue )
|
||||
|
@ -521,6 +533,9 @@ public class XWPrefs {
|
|||
if ( RelayService.relayEnabled( context ) ) {
|
||||
result.add( CommsConnType.COMMS_CONN_RELAY );
|
||||
}
|
||||
if ( BuildConfig.OFFER_MQTT ) {
|
||||
result.add( CommsConnType.COMMS_CONN_MQTT );
|
||||
}
|
||||
if ( BTService.BTEnabled() ) {
|
||||
result.add( CommsConnType.COMMS_CONN_BT );
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */
|
||||
/*
|
||||
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
|
||||
* Copyright 2009-2020 by Eric House (xwords@eehouse.org). All
|
||||
* rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -54,7 +54,8 @@ public class CommsAddrRec {
|
|||
COMMS_CONN_BT,
|
||||
COMMS_CONN_SMS,
|
||||
COMMS_CONN_P2P,
|
||||
COMMS_CONN_NFC(false);
|
||||
COMMS_CONN_NFC(false),
|
||||
COMMS_CONN_MQTT;
|
||||
|
||||
private boolean mIsSelectable = true;
|
||||
|
||||
|
@ -82,6 +83,8 @@ public class CommsAddrRec {
|
|||
id = R.string.invite_choice_p2p; break;
|
||||
case COMMS_CONN_NFC:
|
||||
id = R.string.invite_choice_nfc; break;
|
||||
case COMMS_CONN_MQTT:
|
||||
id = R.string.invite_choice_mqtt; break;
|
||||
default:
|
||||
Assert.failDbg();
|
||||
}
|
||||
|
@ -101,17 +104,16 @@ public class CommsAddrRec {
|
|||
|
||||
public CommsConnTypeSet() { this(BIT_VECTOR_MASK); }
|
||||
|
||||
public CommsConnTypeSet( int bits, boolean isVector )
|
||||
public CommsConnTypeSet( final int inBits )
|
||||
{
|
||||
this( bits | BIT_VECTOR_MASK );
|
||||
Assert.assertTrue( isVector );
|
||||
}
|
||||
|
||||
public CommsConnTypeSet( int bits )
|
||||
{
|
||||
boolean isVector = 0 != (BIT_VECTOR_MASK & bits);
|
||||
bits &= ~BIT_VECTOR_MASK;
|
||||
boolean isVector = 0 != (BIT_VECTOR_MASK & inBits);
|
||||
int bits = inBits & ~BIT_VECTOR_MASK;
|
||||
CommsConnType[] values = CommsConnType.values();
|
||||
// Deal with games saved before I added the BIT_VECTOR_MASK back
|
||||
// in. This should be removable before ship. Or later of course.
|
||||
if ( !isVector && bits >= values.length ) {
|
||||
isVector = true;
|
||||
}
|
||||
if ( isVector ) {
|
||||
for ( CommsConnType value : values ) {
|
||||
int ord = value.ordinal();
|
||||
|
@ -119,8 +121,10 @@ public class CommsAddrRec {
|
|||
add( value );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if ( bits < values.length ) { // don't crash
|
||||
add( values[bits] );
|
||||
} else {
|
||||
Log.e( TAG, "<init>: bad bits value: 0x%x", inBits );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,6 +151,9 @@ public class CommsAddrRec {
|
|||
{
|
||||
List<CommsConnType> supported = new ArrayList<>();
|
||||
supported.add( CommsConnType.COMMS_CONN_RELAY );
|
||||
if ( BuildConfig.OFFER_MQTT ) {
|
||||
supported.add( CommsConnType.COMMS_CONN_MQTT );
|
||||
}
|
||||
if ( BTService.BTAvailable() ) {
|
||||
supported.add( CommsConnType.COMMS_CONN_BT );
|
||||
}
|
||||
|
@ -216,9 +223,6 @@ public class CommsAddrRec {
|
|||
private static final CommsConnType[] s_hint = new CommsConnType[0];
|
||||
}
|
||||
|
||||
// The C equivalent of this struct uses a union for the various
|
||||
// data sets below. So don't assume that any fields will be valid
|
||||
// except those for the current conType.
|
||||
public CommsConnTypeSet conTypes;
|
||||
|
||||
// relay case
|
||||
|
@ -240,6 +244,9 @@ public class CommsAddrRec {
|
|||
// wifi-direct
|
||||
public String p2p_addr;
|
||||
|
||||
// mqtt
|
||||
public String mqtt_devID;
|
||||
|
||||
public CommsAddrRec( CommsConnType cTyp )
|
||||
{
|
||||
this();
|
||||
|
@ -318,6 +325,12 @@ public class CommsAddrRec {
|
|||
return this;
|
||||
}
|
||||
|
||||
public CommsAddrRec setMQTTParams( String devID )
|
||||
{
|
||||
mqtt_devID = devID;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void populate( Context context, CommsConnTypeSet newTypes )
|
||||
{
|
||||
for ( CommsConnType typ : newTypes.getTypes() ) {
|
||||
|
@ -405,6 +418,9 @@ public class CommsAddrRec {
|
|||
case COMMS_CONN_P2P:
|
||||
p2p_addr = WiDirService.getMyMacAddress( context );
|
||||
break;
|
||||
case COMMS_CONN_MQTT:
|
||||
mqtt_devID = XwJNI.dvc_getMQTTDevID( null );
|
||||
break;
|
||||
case COMMS_CONN_NFC:
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -24,7 +24,10 @@ import android.content.Context;
|
|||
import android.content.Intent;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eehouse.android.xw4.Assert;
|
||||
import org.eehouse.android.xw4.BuildConfig;
|
||||
import org.eehouse.android.xw4.Channels;
|
||||
import org.eehouse.android.xw4.DBUtils;
|
||||
import org.eehouse.android.xw4.DevID;
|
||||
|
@ -33,6 +36,8 @@ import org.eehouse.android.xw4.FBMService;
|
|||
import org.eehouse.android.xw4.GameUtils;
|
||||
import org.eehouse.android.xw4.GamesListDelegate;
|
||||
import org.eehouse.android.xw4.Log;
|
||||
import org.eehouse.android.xw4.MQTTUtils;
|
||||
import org.eehouse.android.xw4.NetLaunchInfo;
|
||||
import org.eehouse.android.xw4.R;
|
||||
import org.eehouse.android.xw4.Utils;
|
||||
import org.eehouse.android.xw4.XWApp;
|
||||
|
@ -253,21 +258,19 @@ public class DUtilCtxt {
|
|||
// Log.d( TAG, "store(key=%s)", key );
|
||||
if ( null != data ) {
|
||||
DBUtils.setBytesFor( m_context, key, data );
|
||||
if ( BuildConfig.DEBUG ) {
|
||||
byte[] tmp = load( key );
|
||||
Assert.assertTrue( Arrays.equals( tmp, data ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] load( String key )
|
||||
{
|
||||
byte[] result = null;
|
||||
int resultLen = 0;
|
||||
Log.d( TAG, "load(key=%s)", key );
|
||||
byte[] result = DBUtils.getBytesFor( m_context, key );
|
||||
|
||||
result = DBUtils.getBytesFor( m_context, key );
|
||||
if ( result != null ) {
|
||||
resultLen = result.length;
|
||||
}
|
||||
|
||||
Log.d( TAG, "load(%s) returning %d bytes", key, resultLen );
|
||||
// Log.d( TAG, "load(%s) returning %d bytes", key,
|
||||
// null == result ? 0 : result.length );
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -337,4 +340,23 @@ public class DUtilCtxt {
|
|||
{
|
||||
DupeModeTimer.timerChanged( m_context, gameID, newVal );
|
||||
}
|
||||
|
||||
public void onInviteReceived( NetLaunchInfo nli )
|
||||
{
|
||||
Log.d( TAG, "onInviteReceived(%s)", nli );
|
||||
GamesListDelegate.postReceivedInvite( m_context, nli.asByteArray() );
|
||||
}
|
||||
|
||||
public void onMessageReceived( int gameID, CommsAddrRec from, byte[] msg )
|
||||
{
|
||||
Log.d( TAG, "onMessageReceived()" );
|
||||
Assert.assertTrueNR( from.contains( CommsAddrRec.CommsConnType.COMMS_CONN_MQTT ) );
|
||||
MQTTUtils.handleMessage( m_context, from, gameID, msg );
|
||||
}
|
||||
|
||||
public void onGameGoneReceived( int gameID, CommsAddrRec from )
|
||||
{
|
||||
Assert.assertTrueNR( from.contains( CommsAddrRec.CommsConnType.COMMS_CONN_MQTT ) );
|
||||
MQTTUtils.handleGameGone( m_context, from, gameID );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ public class GameSummary implements Serializable {
|
|||
public static final String EXTRA_REMATCH_PHONE = "rm_phone";
|
||||
public static final String EXTRA_REMATCH_RELAY = "rm_relay";
|
||||
public static final String EXTRA_REMATCH_P2P = "rm_p2p";
|
||||
public static final String EXTRA_REMATCH_MQTT = "rm_mqtt";
|
||||
|
||||
public static final int MSG_FLAGS_NONE = 0;
|
||||
public static final int MSG_FLAGS_TURN = 1;
|
||||
|
@ -279,7 +280,8 @@ public class GameSummary implements Serializable {
|
|||
// Otherwise, use BT or SMS
|
||||
if ( null == result ) {
|
||||
if ( conTypes.contains( CommsConnType.COMMS_CONN_BT )
|
||||
|| ( conTypes.contains( CommsConnType.COMMS_CONN_SMS))){
|
||||
|| conTypes.contains( CommsConnType.COMMS_CONN_SMS)
|
||||
|| conTypes.contains( CommsConnType.COMMS_CONN_MQTT )) {
|
||||
if ( 0 < missing ) {
|
||||
if ( DeviceRole.SERVER_ISSERVER == serverRole ) {
|
||||
fmtID = R.string.summary_wait_host;
|
||||
|
@ -469,21 +471,24 @@ public class GameSummary implements Serializable {
|
|||
m_extras = data;
|
||||
}
|
||||
|
||||
public void putStringExtra( String key, String value )
|
||||
public GameSummary putStringExtra( String key, String value )
|
||||
{
|
||||
String extras = (null == m_extras) ? "{}" : m_extras;
|
||||
try {
|
||||
JSONObject asObj = new JSONObject( extras );
|
||||
if ( null == value ) {
|
||||
asObj.remove( key );
|
||||
} else {
|
||||
asObj.put( key, value );
|
||||
if ( null != value ) {
|
||||
String extras = (null == m_extras) ? "{}" : m_extras;
|
||||
try {
|
||||
JSONObject asObj = new JSONObject( extras );
|
||||
if ( null == value ) {
|
||||
asObj.remove( key );
|
||||
} else {
|
||||
asObj.put( key, value );
|
||||
}
|
||||
m_extras = asObj.toString();
|
||||
} catch( org.json.JSONException ex ) {
|
||||
Log.ex( TAG, ex );
|
||||
}
|
||||
m_extras = asObj.toString();
|
||||
} catch( org.json.JSONException ex ) {
|
||||
Log.ex( TAG, ex );
|
||||
Log.i( TAG, "putStringExtra(%s,%s) => %s", key, value, m_extras );
|
||||
}
|
||||
Log.i( TAG, "putStringExtra(%s,%s) => %s", key, value, m_extras );
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getStringExtra( String key )
|
||||
|
@ -511,6 +516,7 @@ public class GameSummary implements Serializable {
|
|||
EXTRA_REMATCH_PHONE,
|
||||
EXTRA_REMATCH_RELAY,
|
||||
EXTRA_REMATCH_P2P,
|
||||
EXTRA_REMATCH_MQTT,
|
||||
};
|
||||
for ( String key : keys ) {
|
||||
found = null != getStringExtra( key );
|
||||
|
|
|
@ -127,6 +127,32 @@ public class XwJNI {
|
|||
cleanGlobals();
|
||||
}
|
||||
|
||||
public static String dvc_getMQTTDevID( String[] topic )
|
||||
{
|
||||
return dvc_getMQTTDevID( getJNI().m_ptrGlobals, topic );
|
||||
}
|
||||
|
||||
public static byte[] dvc_makeMQTTInvite( NetLaunchInfo nli, String[] addrToTopic )
|
||||
{
|
||||
return dvc_makeMQTTInvite( getJNI().m_ptrGlobals, nli, addrToTopic );
|
||||
}
|
||||
|
||||
public static byte[] dvc_makeMQTTMessage( int gameID, byte[] buf,
|
||||
String[] addrToTopic )
|
||||
{
|
||||
return dvc_makeMQTTMessage( getJNI().m_ptrGlobals, gameID, buf, addrToTopic );
|
||||
}
|
||||
|
||||
public static byte[] dvc_makeMQTTNoSuchGame( int gameID, String[] addrToTopic )
|
||||
{
|
||||
return dvc_makeMQTTNoSuchGame( getJNI().m_ptrGlobals, gameID, addrToTopic );
|
||||
}
|
||||
|
||||
public static void dvc_parseMQTTPacket( byte[] buf )
|
||||
{
|
||||
dvc_parseMQTTPacket( getJNI().m_ptrGlobals, buf );
|
||||
}
|
||||
|
||||
private static void cleanGlobals()
|
||||
{
|
||||
synchronized( XwJNI.class ) { // let's be safe here
|
||||
|
@ -174,7 +200,6 @@ public class XwJNI {
|
|||
|
||||
public static byte[] nliToStream( NetLaunchInfo nli )
|
||||
{
|
||||
nli.freezeAddrs();
|
||||
return nli_to_stream( getJNI().m_ptrGlobals, nli );
|
||||
}
|
||||
|
||||
|
@ -182,7 +207,6 @@ public class XwJNI {
|
|||
{
|
||||
NetLaunchInfo nli = new NetLaunchInfo();
|
||||
nli_from_stream( getJNI().m_ptrGlobals, nli, stream );
|
||||
nli.unfreezeAddrs();
|
||||
return nli;
|
||||
}
|
||||
|
||||
|
@ -533,6 +557,15 @@ public class XwJNI {
|
|||
|
||||
// Private methods -- called only here
|
||||
private static native long initGlobals( DUtilCtxt dutil, JNIUtils jniu );
|
||||
private static native String dvc_getMQTTDevID( long jniState, String[] topic );
|
||||
private static native byte[] dvc_makeMQTTInvite( long jniState, NetLaunchInfo nli,
|
||||
String[] addrToTopic );
|
||||
private static native byte[] dvc_makeMQTTMessage( long jniState, int gameID, byte[] buf,
|
||||
String[] addrToTopic );
|
||||
private static native byte[] dvc_makeMQTTNoSuchGame( long jniState, int gameID,
|
||||
String[] addrToTopic );
|
||||
|
||||
private static native void dvc_parseMQTTPacket( long jniState, byte[] buf );
|
||||
private static native void cleanGlobals( long jniState );
|
||||
private static native byte[] gi_to_stream( long jniState, CurGameInfo gi );
|
||||
private static native void gi_from_stream( long jniState, CurGameInfo gi,
|
||||
|
|
|
@ -39,6 +39,9 @@
|
|||
<string name="key_relay_via_http_first">key_relay_via_http_first</string>
|
||||
<string name="key_update_url">key_update_url2</string>
|
||||
<string name="key_relay_url">key_relay_url2</string>
|
||||
<string name="key_mqtt_host">key_mqtt_host</string>
|
||||
<string name="key_mqtt_port">key_mqtt_port</string>
|
||||
<string name="key_mqtt_qos">key_mqtt_qos</string>
|
||||
<string name="key_update_prerel">key_update_prerel</string>
|
||||
<string name="key_proxy_port">key_proxy_port</string>
|
||||
<string name="key_sms_port">key_sms_port</string>
|
||||
|
@ -143,6 +146,7 @@
|
|||
<string name="key_notagain_nbsGamesOnUpgrade">key_notagain_nbsGamesOnUpgrade</string>
|
||||
<string name="key_na_comms_bt">key_na_comms_bt</string>
|
||||
<string name="key_na_comms_p2p">key_na_comms_p2p</string>
|
||||
<string name="key_na_comms_mqtt">key_na_comms_mqtt</string>
|
||||
<string name="key_na_comms_sms">key_na_comms_sms</string>
|
||||
<string name="key_na_comms_relay">key_na_comms_relay</string>
|
||||
<string name="key_na_bt_badproto">key_na_bt_badproto</string>
|
||||
|
@ -339,6 +343,12 @@
|
|||
<item>@string/relay_poll_name_both</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="mqtt_qos_values">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="force_tablet_names">
|
||||
<item>@string/force_tablet_default</item>
|
||||
<item>@string/force_tablet_phone</item>
|
||||
|
|
|
@ -1048,6 +1048,7 @@
|
|||
<!-- <string name="button_nfc">NFC</string> -->
|
||||
<!-- This is the subject line of the email/text sent to invite
|
||||
someone to join a game. -->
|
||||
<string name="invite_subject">Let\'s play CrossWords</string>
|
||||
<string name="invite_subject_fmt">Let\'s play CrossWords (room %1$s)</string>
|
||||
<!-- This is the body of the html version of the invitation. A URL
|
||||
is created with parameters describing the game and
|
||||
|
@ -1602,7 +1603,7 @@
|
|||
<string name="invite_progress_title">Connecting…</string>
|
||||
<string name="invite_progress_fmt">Sending invitation to CrossWords on %1$s</string>
|
||||
<!-- -->
|
||||
<string name="summary_wait_host">Waiting for connection[s]</string>
|
||||
<string name="summary_wait_host">Waiting for guest[s]</string>
|
||||
<!-- -->
|
||||
<string name="summary_wait_guest">Unconnected</string>
|
||||
<!-- -->
|
||||
|
@ -2195,6 +2196,7 @@
|
|||
<string name="advanced">For debugging</string>
|
||||
<string name="advanced_summary">You should never need these…</string>
|
||||
<string name="relay_host">Relay host</string>
|
||||
<string name="mqtt_host">MQTT host</string>
|
||||
<string name="relay_via_http_first">Use Web APIs first</string>
|
||||
<string name="relay_via_http_first_summary">(instead of as fallback for custom protocol)</string>
|
||||
<string name="dict_host">Wordlist download URL</string>
|
||||
|
@ -2207,6 +2209,8 @@
|
|||
<string name="git_rev_title">Source version id</string>
|
||||
<string name="devid_title">Device ID (on relay)</string>
|
||||
<string name="relay_port">Relay game port</string>
|
||||
<string name="mqtt_port">MQTT port</string>
|
||||
<string name="mqtt_qos">MQTT QOS</string>
|
||||
<string name="proxy_port">Relay device port</string>
|
||||
<string name="name_dict_fmt">%1$s/%2$s</string>
|
||||
<string name="gamel_menu_storedb">Write games to SD card</string>
|
||||
|
@ -2551,4 +2555,10 @@
|
|||
|
||||
<string name="pick_tiles_title">Pick a tile \"spelling\"</string>
|
||||
<string name="no_tiles_exist">\"%1$s\" cannot be spelled with tiles in %2$s.</string>
|
||||
|
||||
<!-- MQTT stuff. May not see the light of day -->
|
||||
<string name="invite_choice_mqtt">Internet/MQTT</string>
|
||||
<string name="mqtt_invite_title">MQTT Invitation</string>
|
||||
<string name="not_again_comms_mqtt">I\'m experimenting with this
|
||||
as a replacement for the relay.</string>
|
||||
</resources>
|
||||
|
|
|
@ -456,6 +456,26 @@
|
|||
android:defaultValue="10998"
|
||||
android:numeric="decimal"
|
||||
/>
|
||||
|
||||
<org.eehouse.android.xw4.XWEditTextPreference
|
||||
android:key="@string/key_mqtt_host"
|
||||
android:title="@string/mqtt_host"
|
||||
android:defaultValue="@string/default_host"
|
||||
/>
|
||||
<org.eehouse.android.xw4.XWEditTextPreference
|
||||
android:key="@string/key_mqtt_port"
|
||||
android:title="@string/mqtt_port"
|
||||
android:defaultValue="1883"
|
||||
android:numeric="decimal"
|
||||
/>
|
||||
<org.eehouse.android.xw4.XWListPreference
|
||||
android:key="@string/key_mqtt_qos"
|
||||
android:title="@string/mqtt_qos"
|
||||
android:entries="@array/mqtt_qos_values"
|
||||
android:entryValues="@array/mqtt_qos_values"
|
||||
android:defaultValue="2"
|
||||
/>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
<PreferenceScreen android:title="@string/pref_group_sms_title"
|
||||
|
|
|
@ -86,6 +86,7 @@ COMMON_SRC_FILES += \
|
|||
$(COMMON_PATH)/dbgutil.c \
|
||||
$(COMMON_PATH)/nli.c \
|
||||
$(COMMON_PATH)/smsproto.c \
|
||||
$(COMMON_PATH)/device.c \
|
||||
|
||||
LOCAL_CFLAGS+=$(LOCAL_C_INCLUDES) $(LOCAL_DEFINES) -Wall -std=c99
|
||||
LOCAL_SRC_FILES := $(linux_SRC_FILES) $(LOCAL_SRC_FILES) $(COMMON_SRC_FILES)
|
||||
|
|
|
@ -150,8 +150,8 @@ setInts( JNIEnv* env, jobject jobj, void* cobj, const SetInfo* sis, XP_U16 nSis
|
|||
XP_ASSERT(0);
|
||||
}
|
||||
setInt( env, jobj, si->name, val );
|
||||
/* XP_LOGF( "%s: read int %s of size %d with val %d from offset %d", */
|
||||
/* __func__, si->name, si->siz, val, si->offset ); */
|
||||
/* XP_LOGFF( "read int %s of size %d with val %d/0x%x from offset %d", */
|
||||
/* si->name, si->siz, val, val, si->offset ); */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -185,7 +185,7 @@ setBools( JNIEnv* env, jobject jobj, void* cobj, const SetInfo* sis, XP_U16 nSis
|
|||
bool
|
||||
setString( JNIEnv* env, jobject obj, const char* name, const XP_UCHAR* value )
|
||||
{
|
||||
// XP_LOGF( "%s(%s)", __func__, name );
|
||||
/* XP_LOGFF( "(name=%s, val=%s)", name, value ); */
|
||||
bool success = false;
|
||||
jclass cls = (*env)->GetObjectClass( env, obj );
|
||||
jfieldID fid = (*env)->GetFieldID( env, cls, name, "Ljava/lang/String;" );
|
||||
|
@ -226,7 +226,7 @@ void
|
|||
getString( JNIEnv* env, jobject obj, const char* name, XP_UCHAR* buf,
|
||||
int bufLen )
|
||||
{
|
||||
// XP_LOGF( "%s(%s)", __func__, name );
|
||||
/* XP_LOGFF( "(name=%s, bufLen=%d)", name, bufLen ); */
|
||||
jclass cls = (*env)->GetObjectClass( env, obj );
|
||||
XP_ASSERT( !!cls );
|
||||
jfieldID fid = (*env)->GetFieldID( env, cls, name, "Ljava/lang/String;" );
|
||||
|
@ -509,8 +509,27 @@ setTypeSetFieldIn( JNIEnv* env, const CommsAddrRec* addr, jobject jTarget,
|
|||
deleteLocalRef( env, jtypset );
|
||||
}
|
||||
|
||||
jobject
|
||||
makeJAddr( JNIEnv* env, const CommsAddrRec* addr )
|
||||
{
|
||||
jobject jaddr = NULL;
|
||||
if ( NULL != addr ) {
|
||||
jclass clazz
|
||||
= (*env)->FindClass(env, PKG_PATH("jni/CommsAddrRec") );
|
||||
XP_ASSERT( !!clazz );
|
||||
jmethodID mid = getMethodID( env, clazz, "<init>", "()V" );
|
||||
XP_ASSERT( !!mid );
|
||||
|
||||
jaddr = (*env)->NewObject( env, clazz, mid );
|
||||
setJAddrRec( env, jaddr, addr );
|
||||
|
||||
deleteLocalRef( env, clazz );
|
||||
}
|
||||
return jaddr;
|
||||
}
|
||||
|
||||
/* Copy C object data into Java object */
|
||||
void
|
||||
jobject
|
||||
setJAddrRec( JNIEnv* env, jobject jaddr, const CommsAddrRec* addr )
|
||||
{
|
||||
XP_ASSERT( !!addr );
|
||||
|
@ -543,10 +562,17 @@ setJAddrRec( JNIEnv* env, jobject jaddr, const CommsAddrRec* addr )
|
|||
break;
|
||||
case COMMS_CONN_NFC:
|
||||
break;
|
||||
case COMMS_CONN_MQTT: {
|
||||
XP_UCHAR buf[32];
|
||||
formatMQTTDevID( &addr->u.mqtt.devID, buf, VSIZE(buf) );
|
||||
setString( env, jaddr, "mqtt_devID", buf );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
XP_ASSERT(0);
|
||||
}
|
||||
}
|
||||
return jaddr;
|
||||
}
|
||||
|
||||
jobject
|
||||
|
@ -636,6 +662,12 @@ getJAddrRec( JNIEnv* env, CommsAddrRec* addr, jobject jaddr )
|
|||
break;
|
||||
case COMMS_CONN_NFC:
|
||||
break;
|
||||
case COMMS_CONN_MQTT: {
|
||||
XP_UCHAR buf[32];
|
||||
getString( env, jaddr, "mqtt_devID", buf, VSIZE(buf) );
|
||||
sscanf( buf, MQTTDevID_FMT, &addr->u.mqtt.devID );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
XP_ASSERT(0);
|
||||
}
|
||||
|
@ -723,6 +755,48 @@ jEnumToInt( JNIEnv* env, jobject jenum )
|
|||
return (*env)->CallIntMethod( env, jenum, mid );
|
||||
}
|
||||
|
||||
static const SetInfo nli_ints[] = {
|
||||
ARR_MEMBER( NetLaunchInfo, _conTypes ),
|
||||
ARR_MEMBER( NetLaunchInfo, lang ),
|
||||
ARR_MEMBER( NetLaunchInfo, forceChannel ),
|
||||
ARR_MEMBER( NetLaunchInfo, nPlayersT ),
|
||||
ARR_MEMBER( NetLaunchInfo, nPlayersH ),
|
||||
ARR_MEMBER( NetLaunchInfo, gameID ),
|
||||
ARR_MEMBER( NetLaunchInfo, osVers ),
|
||||
};
|
||||
|
||||
static const SetInfo nli_bools[] = {
|
||||
ARR_MEMBER( NetLaunchInfo, isGSM ),
|
||||
ARR_MEMBER( NetLaunchInfo, remotesAreRobots ),
|
||||
};
|
||||
|
||||
static const SetInfo nli_strs[] = {
|
||||
ARR_MEMBER( NetLaunchInfo, dict ),
|
||||
ARR_MEMBER( NetLaunchInfo, gameName ),
|
||||
ARR_MEMBER( NetLaunchInfo, room ),
|
||||
ARR_MEMBER( NetLaunchInfo, btName ),
|
||||
ARR_MEMBER( NetLaunchInfo, btAddress ),
|
||||
ARR_MEMBER( NetLaunchInfo, phone ),
|
||||
ARR_MEMBER( NetLaunchInfo, inviteID ),
|
||||
ARR_MEMBER( NetLaunchInfo, mqttDevID ),
|
||||
};
|
||||
|
||||
void
|
||||
loadNLI( JNIEnv* env, NetLaunchInfo* nli, jobject jnli )
|
||||
{
|
||||
getInts( env, (void*)nli, jnli, AANDS(nli_ints) );
|
||||
getBools( env, (void*)nli, jnli, AANDS(nli_bools) );
|
||||
getStrings( env, (void*)nli, jnli, AANDS(nli_strs) );
|
||||
}
|
||||
|
||||
void
|
||||
setNLI( JNIEnv* env, jobject jnli, const NetLaunchInfo* nli )
|
||||
{
|
||||
setInts( env, jnli, (void*)nli, AANDS(nli_ints) );
|
||||
setBools( env, jnli, (void*)nli, AANDS(nli_bools) );
|
||||
setStrings( env, jnli, (void*)nli, AANDS(nli_strs) );
|
||||
}
|
||||
|
||||
XWStreamCtxt*
|
||||
and_empty_stream( MPFORMAL AndGameGlobals* globals )
|
||||
{
|
||||
|
@ -785,7 +859,7 @@ passToJava( const char* tag, const char* msg )
|
|||
|
||||
releaseEnvFromGlobals( env );
|
||||
} else {
|
||||
RAW_LOG( "env is NULL; dropping" );
|
||||
// RAW_LOG( "env is NULL; dropping" );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,8 @@ jbyteArray streamToBArray( JNIEnv *env, XWStreamCtxt* stream );
|
|||
jmethodID getMethodID( JNIEnv* env, jobject obj, const char* proc,
|
||||
const char* sig );
|
||||
|
||||
void setJAddrRec( JNIEnv* env, jobject jaddr, const CommsAddrRec* addr );
|
||||
jobject makeJAddr( JNIEnv* env, const CommsAddrRec* addr );
|
||||
jobject setJAddrRec( JNIEnv* env, jobject jaddr, const CommsAddrRec* addr );
|
||||
void getJAddrRec( JNIEnv* env, CommsAddrRec* addr, jobject jaddr );
|
||||
void setTypeSetFieldIn( JNIEnv* env, const CommsAddrRec* addr, jobject jTarget,
|
||||
const char* fldName );
|
||||
|
@ -104,6 +105,10 @@ void intToJenumField( JNIEnv* env, jobject jobj, int val, const char* field,
|
|||
jobject intToJEnum( JNIEnv* env, int val, const char* enumSig );
|
||||
jint jEnumToInt( JNIEnv* env, jobject jenum );
|
||||
|
||||
#define AANDS(a) (a), VSIZE(a)
|
||||
void loadNLI( JNIEnv* env, NetLaunchInfo* nli, jobject jnli );
|
||||
void setNLI( JNIEnv* env, jobject jnli, const NetLaunchInfo* nli );
|
||||
|
||||
XP_U32 getCurSeconds( JNIEnv* env );
|
||||
|
||||
void deleteLocalRef( JNIEnv* env, jobject jobj );
|
||||
|
|
|
@ -210,12 +210,14 @@ makeDSI( AndDraw* draw, XWEnv xwe, int indx, const DrawScoreInfo* dsi )
|
|||
}
|
||||
#endif
|
||||
|
||||
#define DRAW_CBK_HEADER(nam,sig) \
|
||||
#define DRAW_CBK_HEADER(nam,sig) { \
|
||||
JNIEnv* env = xwe; \
|
||||
AndDraw* draw = (AndDraw*)dctx; \
|
||||
ASSERT_ENV( draw->ti, env ); \
|
||||
XP_ASSERT( !!draw->jdraw ); \
|
||||
jmethodID mid = getMethodID( xwe, draw->jdraw, nam, sig );
|
||||
jmethodID mid = getMethodID( xwe, draw->jdraw, nam, sig ) \
|
||||
|
||||
#define DRAW_CBK_HEADER_END() }
|
||||
|
||||
static XP_Bool
|
||||
and_draw_scoreBegin( DrawCtx* dctx, XWEnv xwe, const XP_Rect* rect,
|
||||
|
@ -238,6 +240,7 @@ and_draw_scoreBegin( DrawCtx* dctx, XWEnv xwe, const XP_Rect* rect,
|
|||
|
||||
returnJRect( draw, JCACHE_RECT0, jrect );
|
||||
deleteLocalRef( env, jscores );
|
||||
DRAW_CBK_HEADER_END();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -255,6 +258,7 @@ and_draw_drawRemText( DrawCtx* dctx, XP_S16 nTilesLeft,
|
|||
readJRect( env, rect, jrect );
|
||||
}
|
||||
returnJRect( draw, JCACHE_RECT0, jrect );
|
||||
DRAW_CBK_HEADER_END();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -277,6 +281,7 @@ and_draw_score_drawPlayers( DrawCtx* dctx, XWEnv xwe, const XP_Rect* scoreRect,
|
|||
readJRect( env, &playerRects[ii], jrect );
|
||||
}
|
||||
returnJRect( draw, JCACHE_RECT0, jrect );
|
||||
DRAW_CBK_HEADER_END();
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -286,15 +291,16 @@ and_draw_measureRemText( DrawCtx* dctx, XWEnv xwe, const XP_Rect* rect,
|
|||
XP_S16 nTilesLeft,
|
||||
XP_U16* width, XP_U16* height )
|
||||
{
|
||||
jboolean result;
|
||||
DRAW_CBK_HEADER("measureRemText", "(Landroid/graphics/Rect;I[I[I)Z" );
|
||||
|
||||
jintArray widthArray = (*env)->NewIntArray( env, 1 );
|
||||
jintArray heightArray = (*env)->NewIntArray( env, 1 );
|
||||
jobject jrect = makeJRect( draw, xwe, JCACHE_RECT0, rect );
|
||||
|
||||
jboolean result = (*env)->CallBooleanMethod( env, draw->jdraw, mid, jrect,
|
||||
nTilesLeft, widthArray,
|
||||
heightArray );
|
||||
result = (*env)->CallBooleanMethod( env, draw->jdraw, mid, jrect,
|
||||
nTilesLeft, widthArray,
|
||||
heightArray );
|
||||
if ( result ) {
|
||||
int tmp;
|
||||
getIntsFromArray( env, &tmp, widthArray, 1, true );
|
||||
|
@ -303,6 +309,7 @@ and_draw_measureRemText( DrawCtx* dctx, XWEnv xwe, const XP_Rect* rect,
|
|||
*height = tmp;
|
||||
}
|
||||
returnJRect( draw, JCACHE_RECT0, jrect );
|
||||
DRAW_CBK_HEADER_END();
|
||||
return result;
|
||||
} /* and_draw_measureRemText */
|
||||
|
||||
|
@ -321,6 +328,7 @@ and_draw_drawRemText( DrawCtx* dctx, XWEnv xwe, const XP_Rect* rInner,
|
|||
nTilesLeft, focussed );
|
||||
returnJRect( draw, JCACHE_RECT0, jrinner );
|
||||
returnJRect( draw, JCACHE_RECT1, jrouter );
|
||||
DRAW_CBK_HEADER_END();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -347,6 +355,7 @@ and_draw_measureScoreText( DrawCtx* dctx, XWEnv xwe, const XP_Rect* r,
|
|||
*width = tmp;
|
||||
getIntsFromArray( env, &tmp, heightArray, 1, true );
|
||||
*height = tmp;
|
||||
DRAW_CBK_HEADER_END();
|
||||
} /* and_draw_measureScoreText */
|
||||
|
||||
static void
|
||||
|
@ -366,6 +375,7 @@ and_draw_score_drawPlayer( DrawCtx* dctx, XWEnv xwe, const XP_Rect* rInner,
|
|||
jdsi );
|
||||
returnJRect( draw, JCACHE_RECT0, jrinner );
|
||||
returnJRect( draw, JCACHE_RECT1, jrouter );
|
||||
DRAW_CBK_HEADER_END();
|
||||
} /* and_draw_score_drawPlayer */
|
||||
#endif
|
||||
|
||||
|
@ -382,6 +392,7 @@ and_draw_drawTimer( DrawCtx* dctx, XWEnv xwe, const XP_Rect* rect, XP_U16 player
|
|||
(*env)->CallVoidMethod( env, draw->jdraw, mid,
|
||||
jrect, player, secondsLeft, inDuplicateMode );
|
||||
returnJRect( draw, JCACHE_RECT0, jrect );
|
||||
DRAW_CBK_HEADER_END();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -408,6 +419,7 @@ and_draw_drawCell( DrawCtx* dctx, XWEnv xwe, const XP_Rect* rect,
|
|||
XP_S16 owner, XWBonusType bonus, HintAtts hintAtts,
|
||||
CellFlags flags )
|
||||
{
|
||||
jboolean result;
|
||||
DRAW_CBK_HEADER("drawCell",
|
||||
"(Landroid/graphics/Rect;Ljava/lang/String;IIIIII)Z" );
|
||||
jobject jrect = makeJRect( draw, xwe, JCACHE_RECT0, rect );
|
||||
|
@ -419,13 +431,14 @@ and_draw_drawCell( DrawCtx* dctx, XWEnv xwe, const XP_Rect* rect,
|
|||
jtext = (*env)->NewStringUTF( env, text );
|
||||
}
|
||||
|
||||
jboolean result = (*env)->CallBooleanMethod( env, draw->jdraw, mid,
|
||||
jrect, jtext, tile, value,
|
||||
owner, bonus, hintAtts,
|
||||
flags );
|
||||
result = (*env)->CallBooleanMethod( env, draw->jdraw, mid,
|
||||
jrect, jtext, tile, value,
|
||||
owner, bonus, hintAtts,
|
||||
flags );
|
||||
returnJRect( draw, JCACHE_RECT0, jrect );
|
||||
deleteLocalRef( env, jtext );
|
||||
|
||||
DRAW_CBK_HEADER_END();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -440,6 +453,7 @@ and_draw_drawBoardArrow( DrawCtx* dctx, XWEnv xwe, const XP_Rect* rect,
|
|||
(*env)->CallVoidMethod( env, draw->jdraw, mid,
|
||||
jrect, bonus, vert, hintAtts, flags );
|
||||
returnJRect( draw, JCACHE_RECT0, jrect );
|
||||
DRAW_CBK_HEADER_END();
|
||||
}
|
||||
|
||||
static XP_Bool
|
||||
|
@ -456,13 +470,14 @@ static XP_Bool
|
|||
and_draw_trayBegin( DrawCtx* dctx, XWEnv xwe, const XP_Rect* rect, XP_U16 owner,
|
||||
XP_S16 score, DrawFocusState XP_UNUSED(dfs) )
|
||||
{
|
||||
jboolean result;
|
||||
DRAW_CBK_HEADER( "trayBegin", "(Landroid/graphics/Rect;II)Z" );
|
||||
|
||||
jobject jrect = makeJRect( draw, xwe, JCACHE_RECT0, rect );
|
||||
|
||||
jboolean result = (*env)->CallBooleanMethod( env, draw->jdraw, mid,
|
||||
jrect, owner, score );
|
||||
result = (*env)->CallBooleanMethod( env, draw->jdraw, mid, jrect, owner, score );
|
||||
returnJRect( draw, JCACHE_RECT0, jrect );
|
||||
DRAW_CBK_HEADER_END();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -484,6 +499,7 @@ and_draw_drawTile( DrawCtx* dctx, XWEnv xwe, const XP_Rect* rect,
|
|||
jrect, jtext, val, flags );
|
||||
returnJRect( draw, JCACHE_RECT0, jrect );
|
||||
deleteLocalRef( env, jtext );
|
||||
DRAW_CBK_HEADER_END();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -506,18 +522,21 @@ and_draw_drawTileMidDrag( DrawCtx* dctx, XWEnv xwe, const XP_Rect* rect,
|
|||
jrect, jtext, val, owner, flags );
|
||||
returnJRect( draw, JCACHE_RECT0, jrect );
|
||||
deleteLocalRef( env, jtext );
|
||||
DRAW_CBK_HEADER_END();
|
||||
return result;
|
||||
}
|
||||
|
||||
static XP_Bool
|
||||
and_draw_drawTileBack( DrawCtx* dctx, XWEnv xwe, const XP_Rect* rect, CellFlags flags )
|
||||
{
|
||||
XP_Bool result;
|
||||
DRAW_CBK_HEADER( "drawTileBack", "(Landroid/graphics/Rect;I)Z" );
|
||||
|
||||
jobject jrect = makeJRect( draw, xwe, JCACHE_RECT0, rect );
|
||||
|
||||
XP_Bool result = (*env)->CallBooleanMethod( env, draw->jdraw, mid, jrect, flags );
|
||||
result = (*env)->CallBooleanMethod( env, draw->jdraw, mid, jrect, flags );
|
||||
returnJRect( draw, JCACHE_RECT0, jrect );
|
||||
DRAW_CBK_HEADER_END();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -531,6 +550,7 @@ and_draw_drawTrayDivider( DrawCtx* dctx, XWEnv xwe, const XP_Rect* rect, CellFla
|
|||
(*env)->CallVoidMethod( env, draw->jdraw, mid,
|
||||
jrect, flags );
|
||||
returnJRect( draw, JCACHE_RECT0, jrect );
|
||||
DRAW_CBK_HEADER_END();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -545,6 +565,7 @@ and_draw_score_pendingScore( DrawCtx* dctx, XWEnv xwe, const XP_Rect* rect,
|
|||
(*env)->CallVoidMethod( env, draw->jdraw, mid,
|
||||
jrect, score, playerNum, curTurn, flags );
|
||||
returnJRect( draw, JCACHE_RECT0, jrect );
|
||||
DRAW_CBK_HEADER_END();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -559,6 +580,7 @@ and_draw_objFinished( DrawCtx* dctx, XWEnv xwe, BoardObjectType typ,
|
|||
(*env)->CallVoidMethod( env, draw->jdraw, mid,
|
||||
(jint)typ, jrect );
|
||||
returnJRect( draw, JCACHE_RECT0, jrect );
|
||||
DRAW_CBK_HEADER_END();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -568,7 +590,7 @@ and_draw_dictChanged( DrawCtx* dctx, XWEnv xwe, XP_S16 playerNum,
|
|||
{
|
||||
AndDraw* draw = (AndDraw*)dctx;
|
||||
if ( !!dict && !!draw->jdraw ) {
|
||||
XP_LOGF( "%s(dict=%p); code=%x", __func__, dict, andDictID(dict) );
|
||||
XP_LOGFF( "(dict=%p/%s); code=%x", dict, dict_getName(dict), andDictID(dict) );
|
||||
XP_LangCode code = 0; /* A null dict means no-lang */
|
||||
if ( NULL != dict ) {
|
||||
code = dict_getLangCode( dict );
|
||||
|
@ -587,6 +609,7 @@ and_draw_dictChanged( DrawCtx* dctx, XWEnv xwe, XP_S16 playerNum,
|
|||
/* jobject jdict = (*env)->NewObject( env, rclass, initId, (int)dict ); */
|
||||
|
||||
(*env)->CallVoidMethod( env, draw->jdraw, mid, (jlong)dict );
|
||||
DRAW_CBK_HEADER_END();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -602,6 +625,7 @@ and_draw_getMiniWText( DrawCtx* dctx, XWEnv xwe, XWMiniTextType textHint )
|
|||
snprintf( draw->miniTextBuf, VSIZE(draw->miniTextBuf), "%s", str );
|
||||
(*env)->ReleaseStringUTFChars( env, jstr, str );
|
||||
deleteLocalRef( env, jstr );
|
||||
DRAW_CBK_HEADER_END();
|
||||
return draw->miniTextBuf;
|
||||
}
|
||||
|
||||
|
@ -625,6 +649,7 @@ and_draw_measureMiniWText( DrawCtx* dctx, XWEnv xwe, const XP_UCHAR* textP,
|
|||
*width = tmp;
|
||||
getIntsFromArray( env, &tmp, heightArray, 1, true );
|
||||
*height = tmp;
|
||||
DRAW_CBK_HEADER_END();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -641,6 +666,7 @@ and_draw_drawMiniWindow( DrawCtx* dctx, XWEnv xwe, const XP_UCHAR* text,
|
|||
jstr, jrect );
|
||||
returnJRect( draw, JCACHE_RECT0, jrect );
|
||||
deleteLocalRef( env, jstr );
|
||||
DRAW_CBK_HEADER_END();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "paths.h"
|
||||
#include "LocalizedStrIncludes.h"
|
||||
#include "dbgutil.h"
|
||||
#include "nli.h"
|
||||
|
||||
#define MAX_QUANTITY_STRS 4
|
||||
|
||||
|
@ -523,16 +524,17 @@ and_dutil_loadPtr( XW_DUtilCtxt* duc, XWEnv xwe, const XP_UCHAR* key,
|
|||
{
|
||||
JNIEnv* env = xwe;
|
||||
jbyteArray jvalue = loadToByteArray( duc, env, key );
|
||||
jsize len = 0;
|
||||
if ( jvalue != NULL ) {
|
||||
jsize len = (*env)->GetArrayLength( env, jvalue );
|
||||
len = (*env)->GetArrayLength( env, jvalue );
|
||||
if ( len <= *lenp ) {
|
||||
jbyte* jelems = (*env)->GetByteArrayElements( env, jvalue, NULL );
|
||||
XP_MEMCPY( data, jelems, len );
|
||||
(*env)->ReleaseByteArrayElements( env, jvalue, jelems, 0 );
|
||||
}
|
||||
*lenp = len;
|
||||
deleteLocalRef( env, jvalue );
|
||||
}
|
||||
*lenp = len;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -847,6 +849,64 @@ and_dutil_onDupTimerChanged( XW_DUtilCtxt* duc, XWEnv xwe, XP_U32 gameID,
|
|||
DUTIL_CBK_TAIL();
|
||||
}
|
||||
|
||||
static void
|
||||
and_dutil_onInviteReceived( XW_DUtilCtxt* duc, XWEnv xwe, const NetLaunchInfo* nli )
|
||||
{
|
||||
LOGNLI( nli );
|
||||
DUTIL_CBK_HEADER( "onInviteReceived", "(L" PKG_PATH("NetLaunchInfo") ";)V" );
|
||||
|
||||
/* Allocate a new NetLaunchInfo */
|
||||
jclass cls = (*env)->FindClass( env, PKG_PATH("NetLaunchInfo") );
|
||||
XP_ASSERT( !!cls );
|
||||
jmethodID initId = (*env)->GetMethodID( env, cls, "<init>", "()V" );
|
||||
XP_ASSERT( !!initId );
|
||||
jobject jnli = (*env)->NewObject( env, cls, initId );
|
||||
XP_ASSERT( !!jnli );
|
||||
setNLI( env, jnli, nli );
|
||||
|
||||
(*env)->CallVoidMethod( env, dutil->jdutil, mid, jnli );
|
||||
|
||||
deleteLocalRefs( env, jnli, cls, DELETE_NO_REF );
|
||||
DUTIL_CBK_TAIL();
|
||||
}
|
||||
|
||||
static void
|
||||
and_dutil_onMessageReceived( XW_DUtilCtxt* duc, XWEnv xwe, XP_U32 gameID,
|
||||
const CommsAddrRec* from, XWStreamCtxt* stream )
|
||||
{
|
||||
LOG_FUNC();
|
||||
DUTIL_CBK_HEADER( "onMessageReceived",
|
||||
"(IL" PKG_PATH("jni/CommsAddrRec") ";[B)V" );
|
||||
|
||||
XP_U16 len = stream_getSize( stream );
|
||||
XP_U8 data[len];
|
||||
stream_getBytes( stream, data, len );
|
||||
|
||||
jbyteArray jmsg = makeByteArray( env, len, (jbyte*)data );
|
||||
|
||||
jobject jaddr = makeJAddr( env, from );
|
||||
|
||||
(*env)->CallVoidMethod( env, dutil->jdutil, mid, gameID, jaddr, jmsg );
|
||||
|
||||
deleteLocalRefs( env, jmsg, jaddr, DELETE_NO_REF );
|
||||
|
||||
DUTIL_CBK_TAIL();
|
||||
LOG_RETURN_VOID();
|
||||
}
|
||||
|
||||
static void
|
||||
and_dutil_onGameGoneReceived( XW_DUtilCtxt* duc, XWEnv xwe, XP_U32 gameID,
|
||||
const CommsAddrRec* from )
|
||||
{
|
||||
DUTIL_CBK_HEADER( "onGameGoneReceived",
|
||||
"(IL" PKG_PATH("jni/CommsAddrRec") ";)V" );
|
||||
jobject jaddr = makeJAddr( env, from );
|
||||
(*env)->CallVoidMethod( env, dutil->jdutil, mid, gameID, jaddr );
|
||||
|
||||
deleteLocalRefs( env, jaddr, DELETE_NO_REF );
|
||||
DUTIL_CBK_TAIL();
|
||||
}
|
||||
|
||||
XW_UtilCtxt*
|
||||
makeUtil( MPFORMAL JNIEnv* env,
|
||||
#ifdef MAP_THREAD_TO_ENV
|
||||
|
@ -994,6 +1054,10 @@ makeDUtil( MPFORMAL JNIEnv* env,
|
|||
SET_DPROC(notifyPause);
|
||||
SET_DPROC(onDupTimerChanged);
|
||||
|
||||
SET_DPROC(onInviteReceived);
|
||||
SET_DPROC(onMessageReceived);
|
||||
SET_DPROC(onGameGoneReceived);
|
||||
|
||||
#undef SET_DPROC
|
||||
|
||||
assertTableFull( vtable, sizeof(*vtable), "dutil" );
|
||||
|
|
|
@ -32,27 +32,6 @@ typedef struct _AndTransportProcs {
|
|||
MPSLOT
|
||||
} AndTransportProcs;
|
||||
|
||||
static jobject
|
||||
makeJAddr( JNIEnv* env, const CommsAddrRec* addr )
|
||||
{
|
||||
jobject jaddr = NULL;
|
||||
if ( NULL != addr ) {
|
||||
jclass clazz
|
||||
= (*env)->FindClass(env, PKG_PATH("jni/CommsAddrRec") );
|
||||
XP_ASSERT( !!clazz );
|
||||
jmethodID mid = getMethodID( env, clazz, "<init>", "()V" );
|
||||
XP_ASSERT( !!mid );
|
||||
|
||||
jaddr = (*env)->NewObject( env, clazz, mid );
|
||||
XP_ASSERT( !!jaddr );
|
||||
|
||||
setJAddrRec( env, jaddr, addr );
|
||||
|
||||
deleteLocalRef( env, clazz );
|
||||
}
|
||||
return jaddr;
|
||||
}
|
||||
|
||||
static XP_U32
|
||||
and_xport_getFlags( XWEnv xwe, void* closure )
|
||||
{
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "dictmgr.h"
|
||||
#include "nli.h"
|
||||
#include "smsproto.h"
|
||||
#include "device.h"
|
||||
|
||||
#include "utilwrapper.h"
|
||||
#include "drawwrapper.h"
|
||||
|
@ -434,9 +435,6 @@ static const SetInfo pl_ints[] = {
|
|||
,ARR_MEMBER( LocalPlayer, secondsUsed )
|
||||
};
|
||||
|
||||
#define AANDS(a) \
|
||||
(a), VSIZE(a)
|
||||
|
||||
static CurGameInfo*
|
||||
makeGI( MPFORMAL JNIEnv* env, jobject jgi )
|
||||
{
|
||||
|
@ -498,47 +496,6 @@ makeGI( MPFORMAL JNIEnv* env, jobject jgi )
|
|||
return gi;
|
||||
} /* makeGI */
|
||||
|
||||
static const SetInfo nli_ints[] = {
|
||||
ARR_MEMBER( NetLaunchInfo, _conTypes ),
|
||||
ARR_MEMBER( NetLaunchInfo, lang ),
|
||||
ARR_MEMBER( NetLaunchInfo, forceChannel ),
|
||||
ARR_MEMBER( NetLaunchInfo, nPlayersT ),
|
||||
ARR_MEMBER( NetLaunchInfo, nPlayersH ),
|
||||
ARR_MEMBER( NetLaunchInfo, gameID ),
|
||||
ARR_MEMBER( NetLaunchInfo, osVers ),
|
||||
};
|
||||
|
||||
static const SetInfo nli_bools[] = {
|
||||
ARR_MEMBER( NetLaunchInfo, isGSM ),
|
||||
ARR_MEMBER( NetLaunchInfo, remotesAreRobots ),
|
||||
};
|
||||
|
||||
static const SetInfo nli_strs[] = {
|
||||
ARR_MEMBER( NetLaunchInfo, dict ),
|
||||
ARR_MEMBER( NetLaunchInfo, gameName ),
|
||||
ARR_MEMBER( NetLaunchInfo, room ),
|
||||
ARR_MEMBER( NetLaunchInfo, btName ),
|
||||
ARR_MEMBER( NetLaunchInfo, btAddress ),
|
||||
ARR_MEMBER( NetLaunchInfo, phone ),
|
||||
ARR_MEMBER( NetLaunchInfo, inviteID ),
|
||||
};
|
||||
|
||||
static void
|
||||
loadNLI( JNIEnv* env, NetLaunchInfo* nli, jobject jnli )
|
||||
{
|
||||
getInts( env, (void*)nli, jnli, AANDS(nli_ints) );
|
||||
getBools( env, (void*)nli, jnli, AANDS(nli_bools) );
|
||||
getStrings( env, (void*)nli, jnli, AANDS(nli_strs) );
|
||||
}
|
||||
|
||||
static void
|
||||
setNLI( JNIEnv* env, jobject jnli, const NetLaunchInfo* nli )
|
||||
{
|
||||
setInts( env, jnli, (void*)nli, AANDS(nli_ints) );
|
||||
setBools( env, jnli, (void*)nli, AANDS(nli_bools) );
|
||||
setStrings( env, jnli, (void*)nli, AANDS(nli_strs) );
|
||||
}
|
||||
|
||||
static void
|
||||
setJGI( JNIEnv* env, jobject jgi, const CurGameInfo* gi )
|
||||
{
|
||||
|
@ -653,8 +610,153 @@ streamFromJStream( MPFORMAL JNIEnv* env, VTableMgr* vtMgr, jbyteArray jstream )
|
|||
} /* streamFromJStream */
|
||||
|
||||
/****************************************************
|
||||
* These three methods are stateless: no gamePtr
|
||||
* These methods are stateless: no gamePtr
|
||||
****************************************************/
|
||||
|
||||
#define DVC_HEADER(PTR) { \
|
||||
JNIGlobalState* globalState = (JNIGlobalState*)(PTR); \
|
||||
|
||||
#define DVC_HEADER_END() } \
|
||||
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_dvc_1getMQTTDevID
|
||||
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jobjectArray jTopicOut )
|
||||
{
|
||||
jstring result;
|
||||
DVC_HEADER(jniGlobalPtr);
|
||||
MQTTDevID devID;
|
||||
dvc_getMQTTDevID( globalState->dutil, env, &devID );
|
||||
|
||||
XP_UCHAR buf[64];
|
||||
|
||||
if ( !!jTopicOut ) {
|
||||
formatMQTTTopic( &devID, buf, VSIZE(buf) );
|
||||
jstring jtopic = (*env)->NewStringUTF( env, buf );
|
||||
XP_ASSERT( 1 == (*env)->GetArrayLength( env, jTopicOut ) ); /* fired */
|
||||
(*env)->SetObjectArrayElement( env, jTopicOut, 0, jtopic );
|
||||
deleteLocalRef( env, jtopic );
|
||||
}
|
||||
|
||||
formatMQTTDevID( &devID, buf, VSIZE(buf) );
|
||||
result = (*env)->NewStringUTF( env, buf );
|
||||
DVC_HEADER_END();
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
addrToTopic( JNIEnv* env, jobjectArray jAddrToTopic )
|
||||
{
|
||||
XP_ASSERT( 1 == (*env)->GetArrayLength( env, jAddrToTopic ) );
|
||||
jstring jaddr = (*env)->GetObjectArrayElement( env, jAddrToTopic, 0 );
|
||||
const char* addr = (*env)->GetStringUTFChars( env, jaddr, NULL );
|
||||
|
||||
MQTTDevID devID;
|
||||
#ifdef DEBUG
|
||||
XP_Bool success =
|
||||
#endif
|
||||
strToMQTTCDevID( addr, &devID );
|
||||
XP_ASSERT( success );
|
||||
|
||||
XP_UCHAR buf[64];
|
||||
formatMQTTTopic( &devID, buf, VSIZE(buf) );
|
||||
jstring jTopic = (*env)->NewStringUTF( env, buf );
|
||||
(*env)->SetObjectArrayElement( env, jAddrToTopic, 0, jTopic );
|
||||
|
||||
(*env)->ReleaseStringUTFChars( env, jaddr, addr );
|
||||
deleteLocalRefs( env, jaddr, jTopic, DELETE_NO_REF );
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_dvc_1makeMQTTInvite
|
||||
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jobject jnli,
|
||||
jobjectArray jAddrToTopic )
|
||||
{
|
||||
jbyteArray result;
|
||||
DVC_HEADER(jniGlobalPtr);
|
||||
NetLaunchInfo nli = {0};
|
||||
loadNLI( env, &nli, jnli );
|
||||
LOGNLI( &nli );
|
||||
|
||||
XWStreamCtxt* stream = mem_stream_make( MPPARM(globalState->mpool)
|
||||
globalState->vtMgr,
|
||||
NULL, 0, NULL );
|
||||
dvc_makeMQTTInvite( stream, &nli );
|
||||
|
||||
result = streamToBArray( env, stream );
|
||||
stream_destroy( stream, env );
|
||||
|
||||
addrToTopic( env, jAddrToTopic );
|
||||
|
||||
DVC_HEADER_END();
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_dvc_1makeMQTTMessage
|
||||
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jint jGameID,
|
||||
jbyteArray jmsg, jobjectArray jAddrToTopic )
|
||||
{
|
||||
jbyteArray result;
|
||||
LOG_FUNC();
|
||||
DVC_HEADER(jniGlobalPtr);
|
||||
|
||||
XWStreamCtxt* stream = mem_stream_make( MPPARM(globalState->mpool)
|
||||
globalState->vtMgr,
|
||||
NULL, 0, NULL );
|
||||
|
||||
XP_U16 len = (*env)->GetArrayLength( env, jmsg );
|
||||
jbyte* buf = (*env)->GetByteArrayElements( env, jmsg, NULL );
|
||||
dvc_makeMQTTMessage( globalState->dutil, env, stream, jGameID,
|
||||
(const XP_U8*)buf, len );
|
||||
(*env)->ReleaseByteArrayElements( env, jmsg, buf, 0 );
|
||||
|
||||
result = streamToBArray( env, stream );
|
||||
stream_destroy( stream, env );
|
||||
|
||||
addrToTopic( env, jAddrToTopic );
|
||||
|
||||
DVC_HEADER_END();
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_dvc_1makeMQTTNoSuchGame
|
||||
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jint jgameid, jobjectArray jAddrToTopic )
|
||||
{
|
||||
jbyteArray result;
|
||||
DVC_HEADER(jniGlobalPtr);
|
||||
|
||||
XWStreamCtxt* stream = mem_stream_make( MPPARM(globalState->mpool)
|
||||
globalState->vtMgr,
|
||||
NULL, 0, NULL );
|
||||
dvc_makeMQTTNoSuchGame( globalState->dutil, env, stream, jgameid );
|
||||
|
||||
result = streamToBArray( env, stream );
|
||||
stream_destroy( stream, env );
|
||||
|
||||
addrToTopic( env, jAddrToTopic );
|
||||
|
||||
DVC_HEADER_END();
|
||||
LOG_RETURN_VOID();
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_dvc_1parseMQTTPacket
|
||||
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jbyteArray jmsg )
|
||||
{
|
||||
DVC_HEADER(jniGlobalPtr);
|
||||
|
||||
XP_U16 len = (*env)->GetArrayLength( env, jmsg );
|
||||
jbyte* buf = (*env)->GetByteArrayElements( env, jmsg, NULL );
|
||||
|
||||
dvc_parseMQTTPacket( globalState->dutil, env, (XP_U8*)buf, len );
|
||||
|
||||
(*env)->ReleaseByteArrayElements( env, jmsg, buf, 0 );
|
||||
DVC_HEADER_END();
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_gi_1to_1stream
|
||||
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jobject jgi )
|
||||
|
@ -705,7 +807,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_gi_1from_1stream
|
|||
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_nli_1to_1stream
|
||||
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jobject njli )
|
||||
( JNIEnv* env, jclass C, jlong jniGlobalPtr, jobject jnli )
|
||||
{
|
||||
LOG_FUNC();
|
||||
JNIGlobalState* globalState = (JNIGlobalState*)jniGlobalPtr;
|
||||
|
@ -715,7 +817,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_nli_1to_1stream
|
|||
|
||||
jbyteArray result;
|
||||
NetLaunchInfo nli = {0};
|
||||
loadNLI( env, &nli, njli );
|
||||
loadNLI( env, &nli, jnli );
|
||||
/* CurGameInfo* gi = makeGI( MPPARM(mpool) env, jgi ); */
|
||||
XWStreamCtxt* stream = mem_stream_make( MPPARM(mpool) globalState->vtMgr,
|
||||
NULL, 0, NULL );
|
||||
|
@ -1877,10 +1979,8 @@ Java_org_eehouse_android_xw4_jni_XwJNI_comms_1getAddrs
|
|||
jclass clas = (*env)->FindClass( env, PKG_PATH("jni/CommsAddrRec") );
|
||||
result = (*env)->NewObjectArray( env, count, clas, NULL );
|
||||
|
||||
jmethodID initId = (*env)->GetMethodID( env, clas, "<init>", "()V" );
|
||||
for ( int ii = 0; ii < count; ++ii ) {
|
||||
jobject jaddr = (*env)->NewObject( env, clas, initId );
|
||||
setJAddrRec( env, jaddr, &addrs[ii] );
|
||||
jobject jaddr = makeJAddr( env, &addrs[ii] );
|
||||
(*env)->SetObjectArrayElement( env, result, ii, jaddr );
|
||||
deleteLocalRef( env, jaddr );
|
||||
}
|
||||
|
@ -1976,6 +2076,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1summarize
|
|||
}
|
||||
break;
|
||||
case COMMS_CONN_NFC:
|
||||
case COMMS_CONN_MQTT:
|
||||
break;
|
||||
#if defined XWFEATURE_BLUETOOTH || defined XWFEATURE_SMS || defined XWFEATURE_P2P
|
||||
case COMMS_CONN_BT:
|
||||
|
|
|
@ -27,9 +27,6 @@
|
|||
#include "draw.h"
|
||||
#include "xwstream.h"
|
||||
|
||||
/* typedef struct BoardVTable { */
|
||||
/* } BoardVTable; */
|
||||
|
||||
#ifdef CPLUS
|
||||
extern "C" {
|
||||
#endif
|
||||
|
|
|
@ -622,6 +622,9 @@ addrFromStreamOne( CommsAddrRec* addrP, XWStreamCtxt* stream, CommsConnType typ
|
|||
break;
|
||||
case COMMS_CONN_NFC:
|
||||
break;
|
||||
case COMMS_CONN_MQTT:
|
||||
stream_getBytes( stream, &addrP->u.mqtt.devID, sizeof(addrP->u.mqtt.devID) );
|
||||
break;
|
||||
default:
|
||||
/* shut up, compiler */
|
||||
break;
|
||||
|
@ -872,6 +875,9 @@ addrToStreamOne( XWStreamCtxt* stream, CommsConnType typ, const CommsAddrRec* ad
|
|||
break;
|
||||
case COMMS_CONN_NFC:
|
||||
break;
|
||||
case COMMS_CONN_MQTT:
|
||||
stream_putBytes( stream, &addrP->u.mqtt.devID, sizeof(addrP->u.mqtt.devID) );
|
||||
break;
|
||||
default:
|
||||
XP_ASSERT(0);
|
||||
break;
|
||||
|
@ -2021,6 +2027,7 @@ preProcess( CommsCtxt* comms, XWEnv xwe, const CommsAddrRec* useAddr,
|
|||
case COMMS_CONN_P2P:
|
||||
break; /* nothing to grab?? */
|
||||
case COMMS_CONN_NFC:
|
||||
case COMMS_CONN_MQTT:
|
||||
break; /* nothing to grab?? */
|
||||
default:
|
||||
XP_ASSERT(0);
|
||||
|
@ -2109,8 +2116,8 @@ getRecordFor( CommsCtxt* comms, XWEnv xwe, const CommsAddrRec* addr,
|
|||
}
|
||||
}
|
||||
|
||||
XP_LOGF( "%s(%s, maskChannel=%s) => %p", __func__,
|
||||
cbuf, maskChannel? "true":"false", rec );
|
||||
XP_LOGFF( "(%s, maskChannel=%s) => %p", cbuf,
|
||||
maskChannel? "true":"false", rec );
|
||||
return rec;
|
||||
} /* getRecordFor */
|
||||
|
||||
|
@ -2503,17 +2510,24 @@ comms_isConnected( const CommsCtxt* const comms )
|
|||
XP_Bool result = XP_FALSE;
|
||||
CommsConnType typ;
|
||||
for ( XP_U32 st = 0; !result && addr_iter( &comms->addr, &typ, &st ); ) {
|
||||
XP_Bool expected = XP_FALSE;
|
||||
switch ( typ ) {
|
||||
case COMMS_CONN_RELAY:
|
||||
result = 0 != comms->rr.connName[0];
|
||||
expected = XP_TRUE;
|
||||
break;
|
||||
case COMMS_CONN_SMS:
|
||||
case COMMS_CONN_BT:
|
||||
case COMMS_CONN_P2P:
|
||||
result = comms->connID != CONN_ID_NONE;
|
||||
case COMMS_CONN_MQTT:
|
||||
expected = XP_TRUE;
|
||||
default:
|
||||
result = comms->connID != CONN_ID_NONE;
|
||||
break;
|
||||
}
|
||||
if ( ! expected ) {
|
||||
XP_LOGFF( "unexpected type %s", ConnType2Str(typ) );
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -2666,6 +2680,7 @@ ConnType2Str( CommsConnType typ )
|
|||
CASESTR( COMMS_CONN_P2P );
|
||||
CASESTR( COMMS_CONN_NTYPES );
|
||||
CASESTR( COMMS_CONN_NFC );
|
||||
CASESTR( COMMS_CONN_MQTT );
|
||||
default:
|
||||
XP_ASSERT(0);
|
||||
}
|
||||
|
@ -2819,6 +2834,13 @@ logAddr( const CommsCtxt* comms, XWEnv xwe,
|
|||
break;
|
||||
case COMMS_CONN_NFC:
|
||||
break;
|
||||
case COMMS_CONN_MQTT: {
|
||||
stream_catString( stream, "mqtt devID: " );
|
||||
XP_UCHAR buf[32];
|
||||
XP_SNPRINTF( buf, VSIZE(buf), MQTTDevID_FMT, addr->u.mqtt.devID );
|
||||
stream_catString( stream, buf );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
XP_ASSERT(0);
|
||||
}
|
||||
|
@ -2899,6 +2921,11 @@ augmentAddr( CommsAddrRec* destAddr, const CommsAddrRec* srcAddr )
|
|||
#endif
|
||||
case COMMS_CONN_NFC:
|
||||
break;
|
||||
case COMMS_CONN_MQTT:
|
||||
dest = &destAddr->u.mqtt;
|
||||
src = &srcAddr->u.mqtt;
|
||||
siz = sizeof(destAddr->u.mqtt);
|
||||
break;
|
||||
default:
|
||||
XP_ASSERT(0);
|
||||
break;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#define _COMMS_H_
|
||||
|
||||
#include "comtypes.h"
|
||||
#include "commstyp.h"
|
||||
#include "mempool.h"
|
||||
#include "xwrelay.h"
|
||||
#include "server.h"
|
||||
|
@ -43,6 +44,7 @@ typedef enum {
|
|||
,COMMS_CONN_SMS
|
||||
,COMMS_CONN_P2P /* a.k.a. Wifi direct */
|
||||
,COMMS_CONN_NFC
|
||||
,COMMS_CONN_MQTT
|
||||
|
||||
,COMMS_CONN_NTYPES
|
||||
} CommsConnType;
|
||||
|
@ -66,57 +68,12 @@ typedef enum {
|
|||
# define XW_BT_NAME "CrossWords"
|
||||
#endif
|
||||
|
||||
/* on Palm BtLibDeviceAddressType is a 48-bit quantity. Linux's typeis the
|
||||
same size. Goal is something all platforms support */
|
||||
typedef struct XP_BtAddr { XP_U8 bits[6]; } XP_BtAddr;
|
||||
typedef struct XP_BtAddrStr { XP_UCHAR chars[18]; } XP_BtAddrStr;
|
||||
|
||||
#ifdef COMMS_HEARTBEAT
|
||||
# define IF_CH(a) a,
|
||||
#else
|
||||
# define IF_CH(a)
|
||||
#endif
|
||||
|
||||
#define MAX_HOSTNAME_LEN 63
|
||||
#define MAX_PHONE_LEN 31
|
||||
#define MAX_P2P_MAC_LEN 17
|
||||
|
||||
typedef struct _CommsAddrRec {
|
||||
XP_U16 _conTypes;
|
||||
|
||||
struct {
|
||||
struct {
|
||||
XP_UCHAR hostName_ip[MAX_HOSTNAME_LEN + 1];
|
||||
XP_U32 ipAddr_ip; /* looked up from above */
|
||||
XP_U16 port_ip;
|
||||
} ip;
|
||||
struct {
|
||||
XP_UCHAR invite[MAX_INVITE_LEN + 1]; /* room!!!! */
|
||||
XP_UCHAR hostName[MAX_HOSTNAME_LEN + 1];
|
||||
XP_U32 ipAddr; /* looked up from above */
|
||||
XP_U16 port;
|
||||
XP_Bool seeksPublicRoom;
|
||||
XP_Bool advertiseRoom;
|
||||
} ip_relay;
|
||||
struct {
|
||||
/* nothing? */
|
||||
XP_UCHAR foo; /* wince doesn't like nothing here */
|
||||
} ir;
|
||||
struct {
|
||||
/* guests can browse for the host to connect to */
|
||||
XP_UCHAR hostName[MAX_HOSTNAME_LEN + 1];
|
||||
XP_BtAddrStr btAddr;
|
||||
} bt;
|
||||
struct {
|
||||
XP_UCHAR phone[MAX_PHONE_LEN + 1];
|
||||
XP_U16 port;
|
||||
} sms;
|
||||
struct {
|
||||
XP_UCHAR mac_addr[MAX_P2P_MAC_LEN + 1];
|
||||
} p2p;
|
||||
} u;
|
||||
} CommsAddrRec;
|
||||
|
||||
typedef XP_S16 (*TransportSend)( XWEnv xwe, const XP_U8* buf, XP_U16 len,
|
||||
const XP_UCHAR* msgNo,
|
||||
const CommsAddrRec* addr,
|
||||
|
|
75
xwords4/common/commstyp.h
Normal file
75
xwords4/common/commstyp.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
/* -*- compile-command: "cd ../linux && make MEMDEBUG=TRUE -j3"; -*- */
|
||||
/*
|
||||
* Copyright 2001 - 2020 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.
|
||||
*/
|
||||
|
||||
#ifndef _COMMSTYP_H_
|
||||
#define _COMMSTYP_H_
|
||||
|
||||
#include "comtypes.h"
|
||||
#include "xwrelay.h"
|
||||
|
||||
#define MAX_HOSTNAME_LEN 63
|
||||
#define MAX_PHONE_LEN 31
|
||||
#define MAX_P2P_MAC_LEN 17
|
||||
|
||||
/* on Palm BtLibDeviceAddressType is a 48-bit quantity. Linux's typeis the
|
||||
same size. Goal is something all platforms support */
|
||||
typedef struct XP_BtAddr { XP_U8 bits[6]; } XP_BtAddr;
|
||||
typedef struct XP_BtAddrStr { XP_UCHAR chars[18]; } XP_BtAddrStr;
|
||||
|
||||
typedef struct _CommsAddrRec {
|
||||
XP_U16 _conTypes;
|
||||
|
||||
struct {
|
||||
struct {
|
||||
XP_UCHAR hostName_ip[MAX_HOSTNAME_LEN + 1];
|
||||
XP_U32 ipAddr_ip; /* looked up from above */
|
||||
XP_U16 port_ip;
|
||||
} ip;
|
||||
struct {
|
||||
XP_UCHAR invite[MAX_INVITE_LEN + 1]; /* room!!!! */
|
||||
XP_UCHAR hostName[MAX_HOSTNAME_LEN + 1];
|
||||
XP_U32 ipAddr; /* looked up from above */
|
||||
XP_U16 port;
|
||||
XP_Bool seeksPublicRoom;
|
||||
XP_Bool advertiseRoom;
|
||||
} ip_relay;
|
||||
struct {
|
||||
/* nothing? */
|
||||
XP_UCHAR foo; /* wince doesn't like nothing here */
|
||||
} ir;
|
||||
struct {
|
||||
/* guests can browse for the host to connect to */
|
||||
XP_UCHAR hostName[MAX_HOSTNAME_LEN + 1];
|
||||
XP_BtAddrStr btAddr;
|
||||
} bt;
|
||||
struct {
|
||||
XP_UCHAR phone[MAX_PHONE_LEN + 1];
|
||||
XP_U16 port;
|
||||
} sms;
|
||||
struct {
|
||||
MQTTDevID devID;
|
||||
} mqtt;
|
||||
struct {
|
||||
XP_UCHAR mac_addr[MAX_P2P_MAC_LEN + 1];
|
||||
} p2p;
|
||||
} u;
|
||||
} CommsAddrRec;
|
||||
|
||||
#endif
|
|
@ -246,6 +246,47 @@ typedef struct _PlayerDicts {
|
|||
DictionaryCtxt* dicts[MAX_NUM_PLAYERS];
|
||||
} PlayerDicts;
|
||||
|
||||
typedef uint64_t MQTTDevID;
|
||||
|
||||
#if __WORDSIZE == 64
|
||||
# define MQTTDevID_FMT "%lX"
|
||||
#elif __WORDSIZE == 32
|
||||
# define MQTTDevID_FMT "%llX"
|
||||
#endif
|
||||
# define MQTTTopic_FMT "xw4/device/" MQTTDevID_FMT
|
||||
|
||||
/* Used by scoring code and engine as fast representation of moves. */
|
||||
typedef struct _MoveInfoTile {
|
||||
XP_U8 varCoord; /* 5 bits ok (0-16 for 17x17 board) */
|
||||
Tile tile; /* 6 bits will do */
|
||||
} MoveInfoTile;
|
||||
|
||||
typedef struct MoveInfo {
|
||||
XP_U8 nTiles; /* 4 bits: 0-7 */
|
||||
XP_U8 commonCoord; /* 5 bits: 0-16 if 17x17 possible */
|
||||
XP_Bool isHorizontal; /* 1 bit */
|
||||
/* If this is to go on an undo stack, we need player num here, or the code
|
||||
has to keep track of it *and* there must be exactly one entry per
|
||||
player per turn. */
|
||||
MoveInfoTile tiles[MAX_TRAY_TILES];
|
||||
} MoveInfo;
|
||||
|
||||
typedef struct _LastMoveInfo {
|
||||
const XP_UCHAR* names[MAX_NUM_PLAYERS];
|
||||
XP_U16 nWinners; /* >1 possible in duplicate case only */
|
||||
XP_U16 score;
|
||||
XP_U16 nTiles;
|
||||
XP_UCHAR word[MAX_COLS * 2]; /* be safe */
|
||||
XP_U8 moveType;
|
||||
XP_Bool inDuplicateMode;
|
||||
} LastMoveInfo;
|
||||
|
||||
typedef XP_U8 TrayTile;
|
||||
typedef struct _TrayTileSet {
|
||||
XP_U8 nTiles;
|
||||
TrayTile tiles[MAX_TRAY_TILES];
|
||||
} TrayTileSet;
|
||||
|
||||
#ifdef XWFEATURE_BLUETOOTH
|
||||
/* temporary debugging hack */
|
||||
|
||||
|
|
|
@ -21,14 +21,8 @@
|
|||
#include "comtypes.h"
|
||||
#include "memstream.h"
|
||||
#include "xwstream.h"
|
||||
|
||||
#ifdef XWFEATURE_DEVICE
|
||||
|
||||
# define KEY_DEVSTATE PERSIST_KEY("devState")
|
||||
|
||||
typedef struct _DevCtxt {
|
||||
XP_U16 devCount;
|
||||
} DevCtxt;
|
||||
#include "strutils.h"
|
||||
#include "nli.h"
|
||||
|
||||
static XWStreamCtxt*
|
||||
mkStream( XW_DUtilCtxt* dutil )
|
||||
|
@ -38,6 +32,13 @@ mkStream( XW_DUtilCtxt* dutil )
|
|||
return stream;
|
||||
}
|
||||
|
||||
#ifdef XWFEATURE_DEVICE
|
||||
# define KEY_DEVSTATE PERSIST_KEY("devState")
|
||||
|
||||
typedef struct _DevCtxt {
|
||||
XP_U16 devCount;
|
||||
} DevCtxt;
|
||||
|
||||
static DevCtxt*
|
||||
load( XW_DUtilCtxt* dutil, XWEnv xwe )
|
||||
{
|
||||
|
@ -64,7 +65,7 @@ load( XW_DUtilCtxt* dutil, XWEnv xwe )
|
|||
}
|
||||
|
||||
void
|
||||
device_store( XW_DUtilCtxt* dutil, XWEnv xwe )
|
||||
dvc_store( XW_DUtilCtxt* dutil, XWEnv xwe )
|
||||
{
|
||||
LOG_FUNC();
|
||||
DevCtxt* state = load( dutil, xwe );
|
||||
|
@ -77,3 +78,100 @@ device_store( XW_DUtilCtxt* dutil, XWEnv xwe )
|
|||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define MQTT_DEVID_KEY "mqtt_devid_key"
|
||||
|
||||
void
|
||||
dvc_getMQTTDevID( XW_DUtilCtxt* dutil, XWEnv xwe, MQTTDevID* devID )
|
||||
{
|
||||
MQTTDevID tmp = 0;
|
||||
XP_U16 len = sizeof(tmp);
|
||||
dutil_loadPtr( dutil, xwe, MQTT_DEVID_KEY, &tmp, &len );
|
||||
// XP_LOGFF( "len: %d; sizeof(tmp): %d", len, sizeof(tmp) );
|
||||
if ( len != sizeof(tmp) ) { /* we have it!!! */
|
||||
tmp = XP_RANDOM();
|
||||
tmp <<= 32;
|
||||
tmp |= XP_RANDOM();
|
||||
dutil_storePtr( dutil, xwe, MQTT_DEVID_KEY, &tmp, sizeof(tmp) );
|
||||
#ifdef DEBUG
|
||||
XP_UCHAR buf[32];
|
||||
formatMQTTDevID( &tmp, buf, VSIZE(buf) );
|
||||
/* This log statement is required by discon_ok2.py!!! (keep in sync) */
|
||||
XP_LOGFF( "generated id: %s", buf );
|
||||
#endif
|
||||
}
|
||||
*devID = tmp;
|
||||
// LOG_RETURNF( MQTTDevID_FMT, *devID );
|
||||
}
|
||||
|
||||
typedef enum { CMD_INVITE, CMD_MSG, CMD_DEVGONE, } MQTTCmd;
|
||||
|
||||
void
|
||||
dvc_makeMQTTInvite( XWStreamCtxt* stream, const NetLaunchInfo* nli )
|
||||
{
|
||||
stream_putU8( stream, CMD_INVITE );
|
||||
nli_saveToStream( nli, stream );
|
||||
}
|
||||
|
||||
static void
|
||||
addCmdAddrAndGameID( XW_DUtilCtxt* dutil, XWEnv xwe, MQTTCmd cmd, XP_U32 gameID,
|
||||
XWStreamCtxt* stream)
|
||||
{
|
||||
stream_putU8( stream, cmd );
|
||||
|
||||
MQTTDevID myID;
|
||||
dvc_getMQTTDevID( dutil, xwe, &myID );
|
||||
stream_putBytes( stream, &myID, sizeof(myID) );
|
||||
|
||||
stream_putU32( stream, gameID );
|
||||
}
|
||||
|
||||
void
|
||||
dvc_makeMQTTMessage( XW_DUtilCtxt* dutil, XWEnv xwe, XWStreamCtxt* stream,
|
||||
XP_U32 gameID, const XP_U8* buf, XP_U16 len )
|
||||
{
|
||||
addCmdAddrAndGameID( dutil, xwe, CMD_MSG, gameID, stream);
|
||||
stream_putBytes( stream, buf, len );
|
||||
}
|
||||
|
||||
void
|
||||
dvc_makeMQTTNoSuchGame( XW_DUtilCtxt* dutil, XWEnv xwe,
|
||||
XWStreamCtxt* stream, XP_U32 gameID )
|
||||
{
|
||||
addCmdAddrAndGameID( dutil, xwe, CMD_DEVGONE, gameID, stream);
|
||||
}
|
||||
|
||||
void
|
||||
dvc_parseMQTTPacket( XW_DUtilCtxt* dutil, XWEnv xwe, const XP_U8* buf, XP_U16 len )
|
||||
{
|
||||
XWStreamCtxt* stream = mkStream( dutil );
|
||||
stream_putBytes( stream, buf, len );
|
||||
|
||||
MQTTCmd cmd = stream_getU8( stream );
|
||||
switch ( cmd ) {
|
||||
case CMD_INVITE: {
|
||||
NetLaunchInfo nli = {0};
|
||||
if ( nli_makeFromStream( &nli, stream ) ) {
|
||||
dutil_onInviteReceived( dutil, xwe, &nli );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CMD_DEVGONE:
|
||||
case CMD_MSG: {
|
||||
CommsAddrRec from = {0};
|
||||
addr_addType( &from, COMMS_CONN_MQTT );
|
||||
stream_getBytes( stream, &from.u.mqtt.devID, sizeof(from.u.mqtt.devID) );
|
||||
XP_U32 gameID = stream_getU32( stream );
|
||||
if ( CMD_MSG == cmd ) {
|
||||
dutil_onMessageReceived( dutil, xwe, gameID, &from, stream );
|
||||
} else if ( CMD_DEVGONE == cmd ) {
|
||||
dutil_onGameGoneReceived( dutil, xwe, gameID, &from );
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
XP_LOGFF( "unknown command %d; dropping message", cmd );
|
||||
XP_ASSERT(0);
|
||||
}
|
||||
stream_destroy( stream, xwe );
|
||||
}
|
||||
|
|
|
@ -25,9 +25,17 @@
|
|||
|
||||
// void device_load( XW_DUtilCtxt dctxt );
|
||||
# ifdef XWFEATURE_DEVICE
|
||||
void device_store( XW_DUtilCtxt* dctxt, XWEnv xwe );
|
||||
void dvc_store( XW_DUtilCtxt* dctxt, XWEnv xwe );
|
||||
# else
|
||||
# define device_store(dctxt, xwe)
|
||||
# define dvc_store(dctxt, xwe)
|
||||
# endif
|
||||
|
||||
void dvc_getMQTTDevID( XW_DUtilCtxt* dutil, XWEnv xwe, MQTTDevID* devID );
|
||||
|
||||
void dvc_makeMQTTInvite( XWStreamCtxt* stream, const NetLaunchInfo* nli);
|
||||
void dvc_makeMQTTMessage( XW_DUtilCtxt* dutil, XWEnv xwe, XWStreamCtxt* stream,
|
||||
XP_U32 gameID, const XP_U8* buf, XP_U16 len );
|
||||
void dvc_makeMQTTNoSuchGame( XW_DUtilCtxt* dutil, XWEnv xwe,
|
||||
XWStreamCtxt* stream, XP_U32 gameID );
|
||||
void dvc_parseMQTTPacket( XW_DUtilCtxt* dutil, XWEnv xwe, const XP_U8* buf, XP_U16 len );
|
||||
#endif
|
||||
|
|
|
@ -21,10 +21,12 @@
|
|||
#ifndef _DEVUTIL_H_
|
||||
#define _DEVUTIL_H_
|
||||
|
||||
#include "mempool.h"
|
||||
#include "comtypes.h"
|
||||
#include "mempool.h"
|
||||
#include "xwrelay.h"
|
||||
#include "vtabmgr.h"
|
||||
#include "commstyp.h"
|
||||
#include "nlityp.h"
|
||||
|
||||
typedef enum { UNPAUSED,
|
||||
PAUSED,
|
||||
|
@ -68,6 +70,13 @@ typedef struct _DUtilVtable {
|
|||
const XP_UCHAR* name, const XP_UCHAR* msg );
|
||||
void (*m_dutil_onDupTimerChanged)( XW_DUtilCtxt* duc, XWEnv xwe, XP_U32 gameID,
|
||||
XP_U32 oldVal, XP_U32 newVal );
|
||||
|
||||
void (*m_dutil_onInviteReceived)( XW_DUtilCtxt* duc, XWEnv xwe,
|
||||
const NetLaunchInfo* nli );
|
||||
void (*m_dutil_onMessageReceived)( XW_DUtilCtxt* duc, XWEnv xwe, XP_U32 gameID,
|
||||
const CommsAddrRec* from, XWStreamCtxt* stream );
|
||||
void (*m_dutil_onGameGoneReceived)( XW_DUtilCtxt* duc, XWEnv xwe, XP_U32 gameID,
|
||||
const CommsAddrRec* from );
|
||||
} DUtilVtable;
|
||||
|
||||
struct XW_DUtilCtxt {
|
||||
|
@ -119,4 +128,13 @@ struct XW_DUtilCtxt {
|
|||
|
||||
#define dutil_onDupTimerChanged(duc, e, id, ov, nv) \
|
||||
(duc)->vtable.m_dutil_onDupTimerChanged( (duc), (e), (id), (ov), (nv))
|
||||
|
||||
|
||||
#define dutil_onInviteReceived(duc, xwe, nli) \
|
||||
(duc)->vtable.m_dutil_onInviteReceived( (duc), (xwe), (nli) )
|
||||
#define dutil_onMessageReceived(duc, xwe, gameID, from, stream) \
|
||||
(duc)->vtable.m_dutil_onMessageReceived((duc),(xwe),(gameID),(from),(stream))
|
||||
#define dutil_onGameGoneReceived(duc, xwe, gameID, from) \
|
||||
(duc)->vtable.m_dutil_onGameGoneReceived((duc),(xwe),(gameID),(from))
|
||||
|
||||
#endif
|
||||
|
|
|
@ -56,37 +56,6 @@ extern "C" {
|
|||
#define MAX_UNIQUE_TILES 64 /* max tile non-blank faces */
|
||||
#define MAX_NUM_BLANKS 4
|
||||
|
||||
/* Used by scoring code and engine as fast representation of moves. */
|
||||
typedef struct _MoveInfoTile {
|
||||
XP_U8 varCoord; /* 5 bits ok (0-16 for 17x17 board) */
|
||||
Tile tile; /* 6 bits will do */
|
||||
} MoveInfoTile;
|
||||
|
||||
typedef struct MoveInfo {
|
||||
XP_U8 nTiles; /* 4 bits: 0-7 */
|
||||
XP_U8 commonCoord; /* 5 bits: 0-16 if 17x17 possible */
|
||||
XP_Bool isHorizontal; /* 1 bit */
|
||||
/* If this is to go on an undo stack, we need player num here, or the code
|
||||
has to keep track of it *and* there must be exactly one entry per
|
||||
player per turn. */
|
||||
MoveInfoTile tiles[MAX_TRAY_TILES];
|
||||
} MoveInfo;
|
||||
|
||||
typedef struct _LastMoveInfo {
|
||||
const XP_UCHAR* names[MAX_NUM_PLAYERS];
|
||||
XP_U16 nWinners; /* >1 possible in duplicate case only */
|
||||
XP_U16 score;
|
||||
XP_U16 nTiles;
|
||||
XP_UCHAR word[MAX_COLS * 2]; /* be safe */
|
||||
XP_U8 moveType;
|
||||
XP_Bool inDuplicateMode;
|
||||
} LastMoveInfo;
|
||||
|
||||
typedef XP_U8 TrayTile;
|
||||
typedef struct _TrayTileSet {
|
||||
XP_U8 nTiles;
|
||||
TrayTile tiles[MAX_TRAY_TILES];
|
||||
} TrayTileSet;
|
||||
|
||||
typedef struct BlankQueue {
|
||||
XP_U16 nBlanks;
|
||||
|
|
|
@ -55,6 +55,9 @@ nli_init( NetLaunchInfo* nli, const CurGameInfo* gi, const CommsAddrRec* addr,
|
|||
XP_STRCAT( nli->phone, addr->u.sms.phone );
|
||||
// nli->port = addr->u.sms.port; <-- I wish
|
||||
break;
|
||||
case COMMS_CONN_MQTT:
|
||||
nli_setMQTTDevID( nli, &addr->u.mqtt.devID );
|
||||
break;
|
||||
default:
|
||||
XP_ASSERT(0);
|
||||
break;
|
||||
|
@ -86,6 +89,13 @@ nli_setInviteID( NetLaunchInfo* nli, const XP_UCHAR* inviteID )
|
|||
XP_STRCAT( nli->inviteID, inviteID );
|
||||
}
|
||||
|
||||
void
|
||||
nli_setMQTTDevID( NetLaunchInfo* nli, const MQTTDevID* mqttDevID )
|
||||
{
|
||||
types_addType( &nli->_conTypes, COMMS_CONN_MQTT );
|
||||
formatMQTTDevID( mqttDevID, nli->mqttDevID, VSIZE(nli->mqttDevID) );
|
||||
}
|
||||
|
||||
void
|
||||
nli_saveToStream( const NetLaunchInfo* nli, XWStreamCtxt* stream )
|
||||
{
|
||||
|
@ -118,6 +128,9 @@ nli_saveToStream( const NetLaunchInfo* nli, XWStreamCtxt* stream )
|
|||
stream_putU8( stream, nli->osType );
|
||||
stream_putU32( stream, nli->osVers );
|
||||
}
|
||||
if ( types_hasType( nli->_conTypes, COMMS_CONN_MQTT ) ) {
|
||||
stringToStream( stream, nli->mqttDevID );
|
||||
}
|
||||
|
||||
if ( NLI_VERSION > 0 ) {
|
||||
stream_putBits( stream, 1, nli->remotesAreRobots ? 1 : 0 );
|
||||
|
@ -160,6 +173,9 @@ nli_makeFromStream( NetLaunchInfo* nli, XWStreamCtxt* stream )
|
|||
nli->osType= stream_getU8( stream );
|
||||
nli->osVers = stream_getU32( stream );
|
||||
}
|
||||
if ( types_hasType( nli->_conTypes, COMMS_CONN_MQTT ) ) {
|
||||
stringFromStreamHere( stream, nli->mqttDevID, sizeof(nli->mqttDevID) );
|
||||
}
|
||||
|
||||
if ( version > 0 && 0 < stream_getSize( stream ) ) {
|
||||
nli->remotesAreRobots = 0 != stream_getBits( stream, 1 );
|
||||
|
@ -198,6 +214,16 @@ nli_makeAddrRec( const NetLaunchInfo* nli, CommsAddrRec* addr )
|
|||
XP_STRCAT( addr->u.sms.phone, nli->phone );
|
||||
addr->u.sms.port = 1; /* BAD, but 0 is worse */
|
||||
break;
|
||||
case COMMS_CONN_MQTT: {
|
||||
#ifdef DEBUG
|
||||
XP_Bool success =
|
||||
#endif
|
||||
strToMQTTCDevID( nli->mqttDevID, &addr->u.mqtt.devID );
|
||||
XP_ASSERT( success );
|
||||
}
|
||||
break;
|
||||
case COMMS_CONN_NFC:
|
||||
break;
|
||||
default:
|
||||
XP_ASSERT(0);
|
||||
break;
|
||||
|
@ -212,9 +238,10 @@ logNLI( const NetLaunchInfo* nli, const char* callerFunc, const int callerLine )
|
|||
XP_LOGFF( "called by %s(), line %d", callerFunc, callerLine );
|
||||
|
||||
XP_UCHAR buf[256];
|
||||
XP_SNPRINTF( buf, VSIZE(buf), "{nPlayersT: %d; nPlayersH: %d; "
|
||||
"gameID: %d; inviteID: %s}",
|
||||
nli->nPlayersT, nli->nPlayersH, nli->gameID, nli->inviteID );
|
||||
XP_SNPRINTF( buf, VSIZE(buf), "{ctyps: %x, nPlayersT: %d; nPlayersH: %d; "
|
||||
"gameID: %d; inviteID: %s, mqttid: %s}", nli->_conTypes,
|
||||
nli->nPlayersT, nli->nPlayersH, nli->gameID, nli->inviteID,
|
||||
nli->mqttDevID );
|
||||
XP_LOGF( "%s", buf );
|
||||
}
|
||||
# endif
|
||||
|
|
|
@ -22,63 +22,30 @@
|
|||
#define _INVIT_H_
|
||||
|
||||
// #include "comms.h"
|
||||
#include "nlityp.h"
|
||||
#include "xwstream.h"
|
||||
#include "game.h"
|
||||
|
||||
#define MAX_GAME_NAME_LEN 64
|
||||
#define MAX_DICT_NAME_LEN 32
|
||||
|
||||
typedef enum {OSType_NONE, OSType_LINUX, OSType_ANDROID, } XP_OSType;
|
||||
|
||||
/* InviteInfo
|
||||
*
|
||||
* A representation of return addresses sent with an invitation so that the
|
||||
* recipient has all it needs to create a game and connect back.
|
||||
*/
|
||||
|
||||
typedef struct _InviteInfo {
|
||||
XP_U16 _conTypes;
|
||||
|
||||
XP_UCHAR gameName[MAX_GAME_NAME_LEN];
|
||||
XP_UCHAR dict[MAX_DICT_NAME_LEN];
|
||||
XP_LangCode lang;
|
||||
XP_U8 forceChannel;
|
||||
XP_U8 nPlayersT;
|
||||
XP_U8 nPlayersH;
|
||||
XP_Bool remotesAreRobots;
|
||||
XP_Bool inDuplicateMode;
|
||||
|
||||
/* Relay */
|
||||
XP_UCHAR room[MAX_INVITE_LEN + 1];
|
||||
XP_U32 devID; /* not used on android; remove?? */
|
||||
|
||||
/* BT */
|
||||
XP_UCHAR btName[32];
|
||||
XP_UCHAR btAddress[32];
|
||||
|
||||
// SMS
|
||||
XP_UCHAR phone[32];
|
||||
XP_Bool isGSM;
|
||||
XP_OSType osType;
|
||||
XP_U32 osVers;
|
||||
|
||||
XP_U32 gameID;
|
||||
XP_UCHAR inviteID[32];
|
||||
} NetLaunchInfo;
|
||||
|
||||
void
|
||||
nli_init( NetLaunchInfo* invit, const CurGameInfo* gi, const CommsAddrRec* addr,
|
||||
nli_init( NetLaunchInfo* nli, const CurGameInfo* gi, const CommsAddrRec* addr,
|
||||
XP_U16 nPlayers, XP_U16 forceChannel );
|
||||
|
||||
|
||||
XP_Bool nli_makeFromStream( NetLaunchInfo* invit, XWStreamCtxt* stream );
|
||||
void nli_saveToStream( const NetLaunchInfo* invit, XWStreamCtxt* stream );
|
||||
XP_Bool nli_makeFromStream( NetLaunchInfo* nli, XWStreamCtxt* stream );
|
||||
void nli_saveToStream( const NetLaunchInfo* nli, XWStreamCtxt* stream );
|
||||
|
||||
void nli_makeAddrRec( const NetLaunchInfo* invit, CommsAddrRec* addr );
|
||||
void nli_makeAddrRec( const NetLaunchInfo* nli, CommsAddrRec* addr );
|
||||
|
||||
void nli_setDevID( NetLaunchInfo* invit, XP_U32 devID );
|
||||
void nli_setInviteID( NetLaunchInfo* invit, const XP_UCHAR* inviteID );
|
||||
void nli_setGameName( NetLaunchInfo* invit, const XP_UCHAR* gameName );
|
||||
void nli_setDevID( NetLaunchInfo* nli, XP_U32 devID );
|
||||
void nli_setInviteID( NetLaunchInfo* nli, const XP_UCHAR* inviteID );
|
||||
void nli_setGameName( NetLaunchInfo* nli, const XP_UCHAR* gameName );
|
||||
void nli_setMQTTDevID( NetLaunchInfo* nli, const MQTTDevID* mqttDevID );
|
||||
|
||||
# ifdef DEBUG
|
||||
void logNLI( const NetLaunchInfo* nli, const char* callerFunc, const int callerLine );
|
||||
|
|
65
xwords4/common/nlityp.h
Normal file
65
xwords4/common/nlityp.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
|
||||
/*
|
||||
* Copyright 2018 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.
|
||||
*/
|
||||
|
||||
#ifndef _NLITYP_H_
|
||||
#define _NLITYP_H_
|
||||
|
||||
#include "comtypes.h"
|
||||
#include "xwrelay.h"
|
||||
|
||||
#define MAX_GAME_NAME_LEN 64
|
||||
#define MAX_DICT_NAME_LEN 32
|
||||
|
||||
typedef enum {OSType_NONE, OSType_LINUX, OSType_ANDROID, } XP_OSType;
|
||||
|
||||
typedef struct _NetLaunchInfo {
|
||||
XP_U16 _conTypes;
|
||||
|
||||
XP_UCHAR gameName[MAX_GAME_NAME_LEN];
|
||||
XP_UCHAR dict[MAX_DICT_NAME_LEN];
|
||||
XP_LangCode lang;
|
||||
XP_U8 forceChannel;
|
||||
XP_U8 nPlayersT;
|
||||
XP_U8 nPlayersH;
|
||||
XP_Bool remotesAreRobots;
|
||||
XP_Bool inDuplicateMode;
|
||||
|
||||
/* Relay */
|
||||
XP_UCHAR room[MAX_INVITE_LEN + 1];
|
||||
XP_U32 devID; /* not used on android; remove?? */
|
||||
|
||||
/* BT */
|
||||
XP_UCHAR btName[32];
|
||||
XP_UCHAR btAddress[32];
|
||||
|
||||
// SMS
|
||||
XP_UCHAR phone[32];
|
||||
XP_Bool isGSM;
|
||||
XP_OSType osType;
|
||||
XP_U32 osVers;
|
||||
|
||||
XP_U32 gameID;
|
||||
XP_UCHAR inviteID[32];
|
||||
/* MQTT */
|
||||
|
||||
XP_UCHAR mqttDevID[17];
|
||||
} NetLaunchInfo;
|
||||
|
||||
#endif
|
|
@ -555,6 +555,33 @@ smsToBin( XP_U8* out, XP_U16* outlenp, const XP_UCHAR* sms, XP_U16 smslen )
|
|||
|
||||
#endif
|
||||
|
||||
const XP_UCHAR*
|
||||
formatMQTTDevID( const MQTTDevID* devid, XP_UCHAR* buf, XP_U16 bufLen )
|
||||
{
|
||||
XP_SNPRINTF( buf, bufLen, MQTTDevID_FMT, *devid );
|
||||
return buf;
|
||||
}
|
||||
|
||||
const XP_UCHAR*
|
||||
formatMQTTTopic( const MQTTDevID* devid, XP_UCHAR* buf, XP_U16 bufLen )
|
||||
{
|
||||
XP_SNPRINTF( buf, bufLen, MQTTTopic_FMT, *devid );
|
||||
// LOG_RETURNF( "%s", buf );
|
||||
return buf;
|
||||
}
|
||||
|
||||
XP_Bool
|
||||
strToMQTTCDevID( const XP_UCHAR* str, MQTTDevID* result )
|
||||
{
|
||||
MQTTDevID tmp;
|
||||
int nMatched = sscanf( str, MQTTDevID_FMT, &tmp );
|
||||
XP_Bool success = nMatched == 1;
|
||||
if ( success ) {
|
||||
*result = tmp;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
#define NUM_PER_LINE 8
|
||||
void
|
||||
|
|
|
@ -108,6 +108,10 @@ void binToSms( XP_UCHAR* out, XP_U16* outlen, const XP_U8* in, XP_U16 inlen );
|
|||
XP_Bool smsToBin( XP_U8* out, XP_U16* outlen, const XP_UCHAR* in, XP_U16 inlen );
|
||||
#endif
|
||||
|
||||
const XP_UCHAR* formatMQTTTopic( const MQTTDevID* devid, XP_UCHAR* buf, XP_U16 bufLen );
|
||||
const XP_UCHAR* formatMQTTDevID( const MQTTDevID* devid, XP_UCHAR* buf, XP_U16 bufLen );
|
||||
XP_Bool strToMQTTCDevID( const XP_UCHAR* str, MQTTDevID* result );
|
||||
|
||||
#ifdef DEBUG
|
||||
void assertSorted( const MoveInfo* mi );
|
||||
void log_hex( const XP_U8* memp, XP_U16 len, const char* tag );
|
||||
|
|
|
@ -234,12 +234,14 @@ OBJ = \
|
|||
$(BUILD_PLAT_DIR)/linuxutl.o \
|
||||
$(BUILD_PLAT_DIR)/gamesdb.o \
|
||||
$(BUILD_PLAT_DIR)/relaycon.o \
|
||||
$(BUILD_PLAT_DIR)/mqttcon.o \
|
||||
$(BUILD_PLAT_DIR)/lindutil.o \
|
||||
$(CURSES_OBJS) $(GTK_OBJS) $(MAIN_OBJS)
|
||||
|
||||
LIBS = -lm -lpthread -luuid -lcurl -ljson-c $(GPROFFLAG)
|
||||
ifdef USE_SQLITE
|
||||
LIBS += -lsqlite3
|
||||
LIBS += -lmosquitto
|
||||
DEFINES += -DUSE_SQLITE
|
||||
endif
|
||||
# Turn this off for now. I apparently have a memory problem, but it
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
|
||||
#include "curgamlistwin.h"
|
||||
#include "linuxmain.h"
|
||||
#include "device.h"
|
||||
#include "strutils.h"
|
||||
|
||||
struct CursGameList {
|
||||
WINDOW* window;
|
||||
|
@ -295,8 +297,12 @@ cgl_draw( CursGameList* cgl )
|
|||
|
||||
XP_U32 relayID = linux_getDevIDRelay( cgl->params );
|
||||
char buf[cgl->width + 1];
|
||||
snprintf( buf, VSIZE(buf), "pid: %d; nGames: %d, relayid: %d",
|
||||
cgl->pid, nGames, relayID );
|
||||
|
||||
MQTTDevID devID;
|
||||
dvc_getMQTTDevID( cgl->params->dutil, NULL_XWE, &devID );
|
||||
XP_UCHAR didBuf[32];
|
||||
snprintf( buf, VSIZE(buf), "pid: %d; nGames: %d, relayid: %d, mqttid: %s",
|
||||
cgl->pid, nGames, relayID, formatMQTTDevID( &devID, didBuf, VSIZE(didBuf) ) );
|
||||
mvwaddstr( win, 0, 0, buf );
|
||||
|
||||
wrefresh( win );
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "linuxmain.h"
|
||||
#include "linuxutl.h"
|
||||
#include "relaycon.h"
|
||||
#include "mqttcon.h"
|
||||
#include "cursesask.h"
|
||||
#include "cursesmenu.h"
|
||||
#include "cursesletterask.h"
|
||||
|
@ -161,7 +162,8 @@ inviteIdle( gpointer data )
|
|||
CursesBoardGlobals* bGlobals = (CursesBoardGlobals*)data;
|
||||
LaunchParams* params = bGlobals->cGlobals.params;
|
||||
if ( !!params->connInfo.relay.inviteeRelayIDs
|
||||
|| !!params->connInfo.sms.inviteePhones ) {
|
||||
|| !!params->connInfo.sms.inviteePhones
|
||||
|| !!params->connInfo.mqtt.inviteeDevIDs ) {
|
||||
handleInvite( bGlobals, 0 );
|
||||
}
|
||||
return FALSE;
|
||||
|
@ -1223,7 +1225,7 @@ handleReplace( void* closure, int XP_UNUSED(key) )
|
|||
|
||||
static bool
|
||||
inviteList( CommonGlobals* cGlobals, CommsAddrRec* addr, GSList* invitees,
|
||||
bool useRelay )
|
||||
CommsConnType typ )
|
||||
{
|
||||
bool haveAddressees = !!invitees;
|
||||
if ( haveAddressees ) {
|
||||
|
@ -1235,14 +1237,31 @@ inviteList( CommonGlobals* cGlobals, CommsAddrRec* addr, GSList* invitees,
|
|||
nPlayersH, forceChannel, ii );
|
||||
NetLaunchInfo nli = {0};
|
||||
nli_init( &nli, cGlobals->gi, addr, nPlayersH, forceChannel );
|
||||
if ( useRelay ) {
|
||||
switch ( typ ) {
|
||||
case COMMS_CONN_RELAY: {
|
||||
uint64_t inviteeRelayID = (uint64_t)g_slist_nth_data( invitees, ii );
|
||||
relaycon_invite( params, (XP_U32)inviteeRelayID, NULL, &nli );
|
||||
} else {
|
||||
}
|
||||
break;
|
||||
case COMMS_CONN_SMS: {
|
||||
const gchar* inviteePhone = (const gchar*)g_slist_nth_data( invitees, ii );
|
||||
linux_sms_invite( params, &nli, inviteePhone,
|
||||
params->connInfo.sms.port );
|
||||
}
|
||||
break;
|
||||
case COMMS_CONN_MQTT: {
|
||||
MQTTDevID devID;
|
||||
const gchar* str = g_slist_nth_data( invitees, ii );
|
||||
if ( strToMQTTCDevID( str, &devID ) ) {
|
||||
mqttc_invite( params, &nli, &devID );
|
||||
} else {
|
||||
XP_LOGFF( "unable to convert devid %s", str );
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
XP_ASSERT(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return haveAddressees;
|
||||
|
@ -1270,20 +1289,24 @@ handleInvite( void* closure, int XP_UNUSED(key) )
|
|||
/* Invite first based on an invitee provided. Otherwise, fall back to
|
||||
doing a send-to-self. Let the recipient code reject a duplicate if
|
||||
the user so desires. */
|
||||
} else if ( inviteList( cGlobals, &addr, params->connInfo.sms.inviteePhones, false ) ) {
|
||||
} else if ( inviteList( cGlobals, &addr, params->connInfo.sms.inviteePhones, COMMS_CONN_SMS ) ) {
|
||||
/* do nothing */
|
||||
} else if ( inviteList( cGlobals, &addr, params->connInfo.relay.inviteeRelayIDs, true ) ) {
|
||||
} else if ( inviteList( cGlobals, &addr, params->connInfo.relay.inviteeRelayIDs, COMMS_CONN_RELAY ) ) {
|
||||
/* do nothing */
|
||||
} else if ( inviteList( cGlobals, &addr, params->connInfo.mqtt.inviteeDevIDs, COMMS_CONN_MQTT ) ) {
|
||||
/* do nothing */
|
||||
/* Try sending to self, using the phone number or relayID of this device */
|
||||
} else if ( addr_hasType( &addr, COMMS_CONN_SMS ) ) {
|
||||
linux_sms_invite( params, &nli, addr.u.sms.phone, addr.u.sms.port );
|
||||
} else if ( addr_hasType( &addr, COMMS_CONN_MQTT ) ) {
|
||||
mqttc_invite( params, &nli, mqttc_getDevID( params ) );
|
||||
} else if ( addr_hasType( &addr, COMMS_CONN_RELAY ) ) {
|
||||
XP_U32 relayID = linux_getDevIDRelay( params );
|
||||
if ( 0 != relayID ) {
|
||||
relaycon_invite( params, relayID, NULL, &nli );
|
||||
}
|
||||
} else {
|
||||
ca_inform( bGlobals->boardWin, "Cannot invite via relayID or by \"sms phone\"." );
|
||||
ca_inform( bGlobals->boardWin, "Cannot invite via relayID, MQTT or by \"sms phone\"." );
|
||||
}
|
||||
LOG_RETURNF( "%s", "TRUE" );
|
||||
return XP_TRUE;
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
#include "linuxudp.h"
|
||||
#include "gamesdb.h"
|
||||
#include "relaycon.h"
|
||||
#include "mqttcon.h"
|
||||
#include "smsproto.h"
|
||||
#include "device.h"
|
||||
#include "cursesmenu.h"
|
||||
|
@ -1152,10 +1153,11 @@ onJoined( void* closure, const XP_UCHAR* connname, XWHostID hid )
|
|||
/* } */
|
||||
#endif
|
||||
|
||||
static void
|
||||
inviteReceivedCurses( CursesAppGlobals* aGlobals, const NetLaunchInfo* invite,
|
||||
void
|
||||
inviteReceivedCurses( void* closure, const NetLaunchInfo* invite,
|
||||
const CommsAddrRec* returnAddr )
|
||||
{
|
||||
CursesAppGlobals* aGlobals = (CursesAppGlobals*)closure;
|
||||
sqlite3_int64 rowids[1];
|
||||
int nRowIDs = VSIZE(rowids);
|
||||
getRowsForGameID( aGlobals->cag.params->pDb, invite->gameID, rowids, &nRowIDs );
|
||||
|
@ -1176,7 +1178,7 @@ inviteReceivedCurses( CursesAppGlobals* aGlobals, const NetLaunchInfo* invite,
|
|||
}
|
||||
|
||||
static void
|
||||
relayInviteReceivedCurses( void* closure, NetLaunchInfo* invite )
|
||||
relayInviteReceivedCurses( void* closure, const NetLaunchInfo* invite )
|
||||
{
|
||||
CursesAppGlobals* aGlobals = (CursesAppGlobals*)closure;
|
||||
CommsAddrRec addr = {0};
|
||||
|
@ -1228,6 +1230,21 @@ smsMsgReceivedCurses( void* closure, const CommsAddrRec* from, XP_U32 gameID,
|
|||
cb_feedGame( aGlobals->cbState, gameID, buf, len, from );
|
||||
}
|
||||
|
||||
void
|
||||
mqttMsgReceivedCurses( void* closure, const CommsAddrRec* from,
|
||||
XP_U32 gameID, const XP_U8* buf, XP_U16 len )
|
||||
{
|
||||
CursesAppGlobals* aGlobals = (CursesAppGlobals*)closure;
|
||||
cb_feedGame( aGlobals->cbState, gameID, buf, len, from );
|
||||
}
|
||||
|
||||
void
|
||||
gameGoneCurses( void* XP_UNUSED(closure), const CommsAddrRec* XP_UNUSED(from),
|
||||
XP_U32 XP_UNUSED_DBG(gameID) )
|
||||
{
|
||||
XP_LOGFF( "(gameID=%d)", gameID );
|
||||
}
|
||||
|
||||
static void
|
||||
cursesGotForRow( void* XP_UNUSED(closure), const CommsAddrRec* XP_UNUSED(from),
|
||||
sqlite3_int64 XP_UNUSED(rowid), const XP_U8* XP_UNUSED(buf),
|
||||
|
@ -1401,6 +1418,7 @@ cursesmain( XP_Bool XP_UNUSED(isServer), LaunchParams* params )
|
|||
{
|
||||
memset( &g_globals, 0, sizeof(g_globals) );
|
||||
g_globals.cag.params = params;
|
||||
params->appGlobals = &g_globals;
|
||||
|
||||
initCurses( &g_globals );
|
||||
if ( !params->closeStdin ) {
|
||||
|
@ -1494,6 +1512,8 @@ cursesmain( XP_Bool XP_UNUSED(isServer), LaunchParams* params )
|
|||
linux_doInitialReg( params, idIsNew );
|
||||
}
|
||||
|
||||
mqttc_init( params );
|
||||
|
||||
#ifdef XWFEATURE_SMS
|
||||
gchar* myPhone = NULL;
|
||||
XP_U16 myPort = 0;
|
||||
|
@ -1535,12 +1555,13 @@ cursesmain( XP_Bool XP_UNUSED(isServer), LaunchParams* params )
|
|||
|
||||
endwin();
|
||||
|
||||
device_store( params->dutil, NULL_XWE );
|
||||
dvc_store( params->dutil, NULL_XWE );
|
||||
|
||||
if ( params->useUdp ) {
|
||||
relaycon_cleanup( params );
|
||||
}
|
||||
|
||||
linux_sms_cleanup( params );
|
||||
mqttc_cleanup( params );
|
||||
} /* cursesmain */
|
||||
#endif /* PLATFORM_NCURSES */
|
||||
|
|
|
@ -75,5 +75,10 @@ void cursesDrawCtxtFree( DrawCtx* dctx );
|
|||
|
||||
void cursesmain( XP_Bool isServer, LaunchParams* params );
|
||||
bool handleQuit( void* closure, int unused_key );
|
||||
void inviteReceivedCurses( void* aGlobals, const NetLaunchInfo* invite,
|
||||
const CommsAddrRec* returnAddr );
|
||||
void mqttMsgReceivedCurses( void* closure, const CommsAddrRec* from,
|
||||
XP_U32 gameID, const XP_U8* buf, XP_U16 len );
|
||||
void gameGoneCurses( void* closure, const CommsAddrRec* from, XP_U32 gameID );
|
||||
|
||||
#endif
|
||||
|
|
|
@ -372,6 +372,12 @@ summarize( CommonGlobals* cGlobals )
|
|||
case COMMS_CONN_IP_DIRECT:
|
||||
strcat( connvia, "IP" );
|
||||
break;
|
||||
case COMMS_CONN_MQTT:
|
||||
strcat( connvia, "MQTT" );
|
||||
break;
|
||||
case COMMS_CONN_NFC: /* this should be filtered out!!! */
|
||||
strcat( connvia, "NFC" );
|
||||
break;
|
||||
default:
|
||||
XP_ASSERT(0);
|
||||
break;
|
||||
|
@ -703,7 +709,7 @@ FetchResult
|
|||
db_fetch( sqlite3* pDb, const gchar* key, gchar* buf, gint* buflen )
|
||||
{
|
||||
XP_ASSERT( !!pDb );
|
||||
FetchResult result = NOT_THERE;
|
||||
FetchResult fetchRes = NOT_THERE;
|
||||
char query[256];
|
||||
#ifdef DEBUG
|
||||
int len =
|
||||
|
@ -715,20 +721,20 @@ db_fetch( sqlite3* pDb, const gchar* key, gchar* buf, gint* buflen )
|
|||
int sqlResult = sqlite3_prepare_v2( pDb, query, -1, &ppStmt, NULL );
|
||||
XP_Bool found = SQLITE_OK == sqlResult;
|
||||
if ( found ) {
|
||||
result = sqlite3_step( ppStmt );
|
||||
found = SQLITE_ROW == result;
|
||||
sqlResult = sqlite3_step( ppStmt );
|
||||
found = SQLITE_ROW == sqlResult;
|
||||
if ( found ) {
|
||||
if ( getColumnText( ppStmt, 0, buf, buflen ) ) {
|
||||
result = SUCCESS;
|
||||
fetchRes = SUCCESS;
|
||||
} else {
|
||||
result = BUFFER_TOO_SMALL;
|
||||
fetchRes = BUFFER_TOO_SMALL;
|
||||
}
|
||||
} else if ( !!buf ) {
|
||||
buf[0] = '\0';
|
||||
}
|
||||
}
|
||||
sqlite3_finalize( ppStmt );
|
||||
return result;
|
||||
return fetchRes;
|
||||
}
|
||||
|
||||
XP_Bool
|
||||
|
|
|
@ -72,6 +72,7 @@
|
|||
#include "filestream.h"
|
||||
#include "gamesdb.h"
|
||||
#include "relaycon.h"
|
||||
#include "mqttcon.h"
|
||||
|
||||
/* static guint gtkSetupClientSocket( GtkGameGlobals* globals, int sock ); */
|
||||
static void setCtrlsForTray( GtkGameGlobals* globals );
|
||||
|
@ -86,6 +87,7 @@ static void gtkShowFinalScores( const GtkGameGlobals* globals,
|
|||
XP_Bool ignoreTimeout );
|
||||
static void send_invites( CommonGlobals* cGlobals, XP_U16 nPlayers,
|
||||
XP_U32 relayDevID, const XP_UCHAR* relayID,
|
||||
MQTTDevID* mqttInviteeID,
|
||||
const CommsAddrRec* addrs );
|
||||
|
||||
#define GTK_TRAY_HT_ROWS 3
|
||||
|
@ -677,7 +679,7 @@ on_board_window_shown( GtkWidget* XP_UNUSED(widget), GtkGameGlobals* globals )
|
|||
CommsAddrRec addr = {0};
|
||||
addrFromStream( &addr, stream );
|
||||
|
||||
send_invites( cGlobals, 1, 0, relayID, NULL );
|
||||
send_invites( cGlobals, 1, 0, relayID, &addr.u.mqtt.devID, &addr );
|
||||
}
|
||||
}
|
||||
stream_destroy( stream, NULL_XWE );
|
||||
|
@ -1403,18 +1405,20 @@ handle_invite_button( GtkWidget* XP_UNUSED(widget), GtkGameGlobals* globals )
|
|||
CommsAddrRec inviteAddr = {0};
|
||||
gint nPlayers = nMissing;
|
||||
XP_U32 relayDevID = 0;
|
||||
MQTTDevID mqttInviteeID;
|
||||
XP_Bool confirmed = gtkInviteDlg( globals, &inviteAddr, &nPlayers,
|
||||
&relayDevID );
|
||||
&relayDevID, &mqttInviteeID );
|
||||
XP_LOGF( "%s: inviteDlg => %d", __func__, confirmed );
|
||||
|
||||
if ( confirmed ) {
|
||||
send_invites( cGlobals, nPlayers, relayDevID, NULL, &inviteAddr );
|
||||
send_invites( cGlobals, nPlayers, relayDevID, NULL, &mqttInviteeID, &inviteAddr );
|
||||
}
|
||||
} /* handle_invite_button */
|
||||
|
||||
static void
|
||||
send_invites( CommonGlobals* cGlobals, XP_U16 nPlayers,
|
||||
XP_U32 relayDevID, const XP_UCHAR* relayID,
|
||||
MQTTDevID* mqttInviteeID,
|
||||
const CommsAddrRec* addrs )
|
||||
{
|
||||
CommsAddrRec addr = {0};
|
||||
|
@ -1433,6 +1437,11 @@ send_invites( CommonGlobals* cGlobals, XP_U16 nPlayers,
|
|||
}
|
||||
// nli_setDevID( &nli, linux_getDevIDRelay( cGlobals->params ) );
|
||||
|
||||
if ( addr_hasType( &addr, COMMS_CONN_MQTT ) ) {
|
||||
const MQTTDevID* devid = mqttc_getDevID( cGlobals->params );
|
||||
nli_setMQTTDevID( &nli, devid );
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(cGlobals->util->mpool)
|
||||
|
@ -1458,6 +1467,10 @@ send_invites( CommonGlobals* cGlobals, XP_U16 nPlayers,
|
|||
relaycon_invite( cGlobals->params, relayDevID, relayID, &nli );
|
||||
}
|
||||
|
||||
if ( addr_hasType( addrs, COMMS_CONN_MQTT ) ) {
|
||||
mqttc_invite( cGlobals->params, &nli, mqttInviteeID );
|
||||
}
|
||||
|
||||
/* while ( gtkaskm( "Invite how many and how?", infos, VSIZE(infos) ) ) { */
|
||||
/* int nPlayers = atoi( countStr ); */
|
||||
/* if ( 0 >= nPlayers || nPlayers > nMissing ) { */
|
||||
|
@ -1955,7 +1968,7 @@ gtk_util_makeStreamFromAddr(XW_UtilCtxt* uc, XWEnv XP_UNUSED(xwe), XP_PlayerAddr
|
|||
static void
|
||||
gtk_util_showChat( XW_UtilCtxt* uc, XWEnv XP_UNUSED(xwe),
|
||||
const XP_UCHAR* const msg, XP_S16 from,
|
||||
XP_U32 timestamp )
|
||||
XP_U32 tsSecs )
|
||||
{
|
||||
GtkGameGlobals* globals = (GtkGameGlobals*)uc->closure;
|
||||
XP_UCHAR buf[1024];
|
||||
|
@ -1963,7 +1976,13 @@ gtk_util_showChat( XW_UtilCtxt* uc, XWEnv XP_UNUSED(xwe),
|
|||
if ( 0 <= from ) {
|
||||
name = globals->cGlobals.gi->players[from].name;
|
||||
}
|
||||
XP_SNPRINTF( buf, VSIZE(buf), "quoth %s at %d: %s", name, timestamp, msg );
|
||||
|
||||
GDateTime* dt = g_date_time_new_from_unix_utc( tsSecs );
|
||||
gchar* tsStr = g_date_time_format( dt, "%T" );
|
||||
XP_SNPRINTF( buf, VSIZE(buf), "Quoth %s at %s: \"%s\"", name, tsStr, msg );
|
||||
g_free( tsStr );
|
||||
g_date_time_unref (dt);
|
||||
|
||||
(void)gtkask( globals->window, buf, GTK_BUTTONS_OK, NULL );
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -125,6 +125,8 @@ handle_ok( GtkWidget* XP_UNUSED(widget), gpointer closure )
|
|||
txt = gtk_entry_get_text( GTK_ENTRY(state->smsport) );
|
||||
state->addr->u.sms.port = atoi( txt );
|
||||
break;
|
||||
case COMMS_CONN_MQTT:
|
||||
break;
|
||||
default:
|
||||
XP_ASSERT( 0 ); /* keep compiler happy */
|
||||
break;
|
||||
|
@ -321,7 +323,14 @@ makeSMSPage( GtkConnsState* state, PageData* data )
|
|||
gtk_widget_show( vbox );
|
||||
|
||||
return vbox;
|
||||
} /* makeBTPage */
|
||||
} /* makeSMSPage */
|
||||
|
||||
static GtkWidget*
|
||||
makeMQTTPage( GtkConnsState* state, PageData* data )
|
||||
{
|
||||
GtkWidget* vbox = boxWithUseCheck( state, data );
|
||||
return vbox;
|
||||
} /* makeMQTTPage */
|
||||
|
||||
static PageData*
|
||||
getNextData( GtkConnsState* state, CommsConnType typ, gchar* label )
|
||||
|
@ -352,6 +361,10 @@ gtkConnsDlg( GtkGameGlobals* globals, CommsAddrRec* addr, DeviceRole role,
|
|||
state.notebook = gtk_notebook_new();
|
||||
PageData* data;
|
||||
|
||||
data = getNextData( &state, COMMS_CONN_MQTT, "MQTT" );
|
||||
(void)gtk_notebook_append_page( GTK_NOTEBOOK(state.notebook),
|
||||
makeMQTTPage( &state, data ),
|
||||
data->label );
|
||||
#ifdef XWFEATURE_RELAY
|
||||
data = getNextData( &state, COMMS_CONN_RELAY, "Relay" );
|
||||
(void)gtk_notebook_append_page( GTK_NOTEBOOK(state.notebook),
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include "gtkutils.h"
|
||||
#include "linuxbt.h"
|
||||
#include "comtypes.h"
|
||||
#include "mqttcon.h"
|
||||
#include "strutils.h"
|
||||
|
||||
typedef struct _PageData {
|
||||
CommsConnType pageType;
|
||||
|
@ -39,6 +41,7 @@ typedef struct _GtkInviteState {
|
|||
CommsAddrRec* addr;
|
||||
gint* nPlayersP;
|
||||
XP_U32* relayDevIDp;
|
||||
MQTTDevID* mqttDevIDp;
|
||||
gint maxPlayers;
|
||||
|
||||
GtkWidget* nPlayersCombo;
|
||||
|
@ -50,6 +53,8 @@ typedef struct _GtkInviteState {
|
|||
GtkWidget* smsphone;
|
||||
GtkWidget* smsport;
|
||||
|
||||
GtkWidget* mqttDevID;
|
||||
|
||||
GtkWidget* bgScanButton;
|
||||
GtkWidget* okButton;
|
||||
|
||||
|
@ -107,12 +112,17 @@ handle_ok( GtkWidget* XP_UNUSED(widget), gpointer closure )
|
|||
break;
|
||||
#endif
|
||||
case COMMS_CONN_SMS:
|
||||
txt = gtk_entry_get_text( GTK_ENTRY(state->smsphone) );
|
||||
XP_STRNCPY( state->addr->u.sms.phone, txt,
|
||||
sizeof(state->addr->u.sms.phone) );
|
||||
txt = gtk_entry_get_text( GTK_ENTRY(state->smsport) );
|
||||
state->addr->u.sms.port = atoi( txt );
|
||||
break;
|
||||
case COMMS_CONN_MQTT:
|
||||
txt = gtk_entry_get_text( GTK_ENTRY(state->mqttDevID) );
|
||||
if ( strToMQTTCDevID( txt, &state->addr->u.mqtt.devID ) ) {
|
||||
*state->mqttDevIDp = state->addr->u.mqtt.devID;
|
||||
} else {
|
||||
XP_ASSERT(0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
XP_ASSERT( 0 ); /* keep compiler happy */
|
||||
break;
|
||||
|
@ -253,6 +263,23 @@ makeSMSPage( GtkInviteState* state, PageData* data )
|
|||
return vbox;
|
||||
} /* makeBTPage */
|
||||
|
||||
static GtkWidget*
|
||||
makeMQTTPage( GtkInviteState* state, PageData* data )
|
||||
{
|
||||
data->okButtonTxt = "Invite via MQTT";
|
||||
|
||||
GtkWidget* vbox = gtk_box_new( GTK_ORIENTATION_VERTICAL, 0 );
|
||||
GtkWidget* hbox;
|
||||
|
||||
hbox = makeLabeledField( "Invitee MQTT DevID", &state->mqttDevID, NULL );
|
||||
// gtk_entry_set_text( GTK_ENTRY(state->mqttDevID), s_mqttIDBuf );
|
||||
gtk_box_pack_start( GTK_BOX(vbox), hbox, FALSE, TRUE, 0 );
|
||||
|
||||
gtk_widget_show( vbox );
|
||||
|
||||
return vbox;
|
||||
}
|
||||
|
||||
static PageData*
|
||||
getNextData( GtkInviteState* state, CommsConnType typ, gchar* label )
|
||||
{
|
||||
|
@ -275,7 +302,8 @@ onPageChanged( GtkNotebook* XP_UNUSED(notebook), gpointer XP_UNUSED(arg1),
|
|||
|
||||
XP_Bool
|
||||
gtkInviteDlg( GtkGameGlobals* globals, CommsAddrRec* addr,
|
||||
gint* nPlayersP, XP_U32* relayDevIDp )
|
||||
gint* nPlayersP, XP_U32* relayDevIDp,
|
||||
MQTTDevID* mqttDevIDp )
|
||||
{
|
||||
GtkInviteState state = {
|
||||
.globals = globals,
|
||||
|
@ -283,6 +311,7 @@ gtkInviteDlg( GtkGameGlobals* globals, CommsAddrRec* addr,
|
|||
.nPlayersP = nPlayersP,
|
||||
.relayDevIDp = relayDevIDp,
|
||||
.maxPlayers = *nPlayersP,
|
||||
.mqttDevIDp = mqttDevIDp,
|
||||
};
|
||||
|
||||
GtkWidget* dialog;
|
||||
|
@ -310,6 +339,10 @@ gtkInviteDlg( GtkGameGlobals* globals, CommsAddrRec* addr,
|
|||
|
||||
PageData* data;
|
||||
|
||||
data = getNextData( &state, COMMS_CONN_MQTT, "MQTT" );
|
||||
(void)gtk_notebook_append_page( GTK_NOTEBOOK(state.notebook),
|
||||
makeMQTTPage( &state, data ),
|
||||
data->label );
|
||||
#ifdef XWFEATURE_RELAY
|
||||
data = getNextData( &state, COMMS_CONN_RELAY, "Relay" );
|
||||
(void)gtk_notebook_append_page( GTK_NOTEBOOK(state.notebook),
|
||||
|
|
|
@ -24,7 +24,8 @@
|
|||
|
||||
/* return true if not cancelled */
|
||||
XP_Bool gtkInviteDlg( GtkGameGlobals* globals, CommsAddrRec* addr,
|
||||
/*inout*/ gint* nPlayers, /* out */ XP_U32* relayDevID );
|
||||
/*inout*/ gint* nPlayers, /* out */ XP_U32* relayDevID,
|
||||
MQTTDevID* mqttInviteeID );
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "linuxmain.h"
|
||||
#include "linuxutl.h"
|
||||
#include "relaycon.h"
|
||||
#include "mqttcon.h"
|
||||
#include "linuxsms.h"
|
||||
#include "gtkask.h"
|
||||
#include "device.h"
|
||||
|
@ -502,6 +503,13 @@ setWindowTitle( GtkAppGlobals* apg )
|
|||
len = strlen( title );
|
||||
snprintf( &title[len], VSIZE(title) - len, " (relayid: %d)", relayID );
|
||||
#endif
|
||||
len = strlen( title );
|
||||
MQTTDevID devID;
|
||||
dvc_getMQTTDevID( params->dutil, NULL_XWE, &devID );
|
||||
XP_UCHAR didBuf[32];
|
||||
snprintf( &title[len], VSIZE(title) - len, " (mqtt: %s)",
|
||||
formatMQTTDevID( &devID, didBuf, VSIZE(didBuf) ) );
|
||||
|
||||
gtk_window_set_title( GTK_WINDOW(window), title );
|
||||
}
|
||||
|
||||
|
@ -536,10 +544,19 @@ handle_relayid_to_clip( GtkWidget* XP_UNUSED(widget), GtkAppGlobals* apg )
|
|||
XP_U32 relayID = linux_getDevIDRelay( params );
|
||||
gchar str[32];
|
||||
snprintf( &str[0], VSIZE(str), "%d", relayID );
|
||||
GtkClipboard *clipboard = gtk_clipboard_get( GDK_SELECTION_CLIPBOARD );
|
||||
GtkClipboard* clipboard = gtk_clipboard_get( GDK_SELECTION_CLIPBOARD );
|
||||
gtk_clipboard_set_text( clipboard, str, strlen(str) );
|
||||
}
|
||||
|
||||
static void
|
||||
handle_mqttid_to_clip( GtkWidget* XP_UNUSED(widget), GtkAppGlobals* apg )
|
||||
{
|
||||
LaunchParams* params = apg->cag.params;
|
||||
const gchar* devIDStr = mqttc_getDevIDStr( params );
|
||||
GtkClipboard* clipboard = gtk_clipboard_get( GDK_SELECTION_CLIPBOARD );
|
||||
gtk_clipboard_set_text( clipboard, devIDStr, strlen(devIDStr) );
|
||||
}
|
||||
|
||||
static void
|
||||
makeGamesWindow( GtkAppGlobals* apg )
|
||||
{
|
||||
|
@ -573,6 +590,8 @@ makeGamesWindow( GtkAppGlobals* apg )
|
|||
}
|
||||
(void)createAddItem( netMenu, "copy relayid",
|
||||
(GCallback)handle_relayid_to_clip, apg );
|
||||
(void)createAddItem( netMenu, "copy mqtt devid",
|
||||
(GCallback)handle_mqttid_to_clip, apg );
|
||||
gtk_widget_show( menubar );
|
||||
gtk_box_pack_start( GTK_BOX(vbox), menubar, FALSE, TRUE, 0 );
|
||||
|
||||
|
@ -707,8 +726,8 @@ gameFromInvite( GtkAppGlobals* apg, const NetLaunchInfo* invite,
|
|||
gi_disposePlayerInfo( MPPARM(params->mpool) &gi );
|
||||
}
|
||||
|
||||
static void
|
||||
relayInviteReceived( void* closure, NetLaunchInfo* invite )
|
||||
void
|
||||
relayInviteReceivedGTK( void* closure, const NetLaunchInfo* invite )
|
||||
{
|
||||
GtkAppGlobals* apg = (GtkAppGlobals*)closure;
|
||||
|
||||
|
@ -795,9 +814,9 @@ smsInviteReceived( void* closure, const NetLaunchInfo* nli,
|
|||
gameFromInvite( apg, nli, returnAddr );
|
||||
}
|
||||
|
||||
static void
|
||||
smsMsgReceivedGTK( void* closure, const CommsAddrRec* from, XP_U32 gameID,
|
||||
const XP_U8* buf, XP_U16 len )
|
||||
void
|
||||
msgReceivedGTK( void* closure, const CommsAddrRec* from, XP_U32 gameID,
|
||||
const XP_U8* buf, XP_U16 len )
|
||||
{
|
||||
LOG_FUNC();
|
||||
GtkAppGlobals* apg = (GtkAppGlobals*)closure;
|
||||
|
@ -807,11 +826,24 @@ smsMsgReceivedGTK( void* closure, const CommsAddrRec* from, XP_U32 gameID,
|
|||
int nRowIDs = VSIZE(rowids);
|
||||
getRowsForGameID( params->pDb, gameID, rowids, &nRowIDs );
|
||||
XP_LOGF( "%s: found %d rows for gameID %d", __func__, nRowIDs, gameID );
|
||||
for ( int ii = 0; ii < nRowIDs; ++ii ) {
|
||||
feedBufferGTK( apg, rowids[ii], buf, len, from );
|
||||
if ( 0 == nRowIDs ) {
|
||||
mqttc_notifyGameGone( params, &from->u.mqtt.devID, gameID );
|
||||
} else {
|
||||
for ( int ii = 0; ii < nRowIDs; ++ii ) {
|
||||
feedBufferGTK( apg, rowids[ii], buf, len, from );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gameGoneGTK( void* closure, const CommsAddrRec* XP_UNUSED(from), XP_U32 gameID )
|
||||
{
|
||||
GtkAppGlobals* apg = (GtkAppGlobals*)closure;
|
||||
gchar buf[64];
|
||||
snprintf( buf, VSIZE(buf), "game %d has been deleted on a remote device", gameID );
|
||||
gtktell( apg->window, buf );
|
||||
}
|
||||
|
||||
static gboolean
|
||||
keepalive_timer( gpointer data )
|
||||
{
|
||||
|
@ -872,6 +904,7 @@ int
|
|||
gtkmain( LaunchParams* params )
|
||||
{
|
||||
GtkAppGlobals apg = {0};
|
||||
params->appGlobals = &apg;
|
||||
|
||||
g_globals_for_signal = &apg;
|
||||
|
||||
|
@ -896,7 +929,7 @@ gtkmain( LaunchParams* params )
|
|||
.msgNoticeReceived = gtkNoticeRcvd,
|
||||
.devIDReceived = gtkDevIDReceived,
|
||||
.msgErrorMsg = gtkErrorMsgRcvd,
|
||||
.inviteReceived = relayInviteReceived,
|
||||
.inviteReceived = relayInviteReceivedGTK,
|
||||
};
|
||||
|
||||
relaycon_init( params, &procs, &apg,
|
||||
|
@ -904,6 +937,8 @@ gtkmain( LaunchParams* params )
|
|||
params->connInfo.relay.defaultSendPort );
|
||||
|
||||
linux_doInitialReg( params, idIsNew );
|
||||
|
||||
mqttc_init( params );
|
||||
}
|
||||
|
||||
#ifdef XWFEATURE_SMS
|
||||
|
@ -912,7 +947,7 @@ gtkmain( LaunchParams* params )
|
|||
if ( parseSMSParams( params, &myPhone, &myPort ) ) {
|
||||
SMSProcs smsProcs = {
|
||||
.inviteReceived = smsInviteReceived,
|
||||
.msgReceived = smsMsgReceivedGTK,
|
||||
.msgReceived = msgReceivedGTK,
|
||||
};
|
||||
linux_sms_init( params, myPhone, myPort, &smsProcs, &apg );
|
||||
} else {
|
||||
|
@ -933,13 +968,14 @@ gtkmain( LaunchParams* params )
|
|||
}
|
||||
|
||||
gtk_main();
|
||||
device_store( params->dutil, NULL_XWE );
|
||||
dvc_store( params->dutil, NULL_XWE );
|
||||
/* closeGamesDB( params->pDb ); */
|
||||
/* params->pDb = NULL; */
|
||||
relaycon_cleanup( params );
|
||||
#ifdef XWFEATURE_SMS
|
||||
linux_sms_cleanup( params );
|
||||
#endif
|
||||
mqttc_cleanup( params );
|
||||
return 0;
|
||||
} /* gtkmain */
|
||||
|
||||
|
|
|
@ -27,5 +27,8 @@ int gtkmain( LaunchParams* params );
|
|||
void windowDestroyed( GtkGameGlobals* globals );
|
||||
void gtkOnGameSaved( void* closure, sqlite3_int64 rowid, XP_Bool firstTime );
|
||||
void make_rematch( GtkAppGlobals* apg, const CommonGlobals* cGlobals );
|
||||
|
||||
void relayInviteReceivedGTK( void* closure, const NetLaunchInfo* invite );
|
||||
void msgReceivedGTK( void* closure, const CommsAddrRec* from, XP_U32 gameID,
|
||||
const XP_U8* buf, XP_U16 len );
|
||||
void gameGoneGTK( void* closure, const CommsAddrRec* from, XP_U32 gameID );
|
||||
#endif
|
||||
|
|
|
@ -23,7 +23,11 @@
|
|||
#include "linuxutl.h"
|
||||
#include "linuxmain.h"
|
||||
#include "gamesdb.h"
|
||||
#include "dbgutil.h"
|
||||
#include "LocalizedStrIncludes.h"
|
||||
#include "nli.h"
|
||||
#include "cursesmain.h"
|
||||
#include "gtkmain.h"
|
||||
|
||||
static XP_U32 linux_dutil_getCurSeconds( XW_DUtilCtxt* duc, XWEnv xwe );
|
||||
static const XP_UCHAR* linux_dutil_getUserString( XW_DUtilCtxt* duc, XWEnv xwe, XP_U16 code );
|
||||
|
@ -78,6 +82,52 @@ linux_dutil_onDupTimerChanged( XW_DUtilCtxt* XP_UNUSED(duc), XWEnv XP_UNUSED(xwe
|
|||
XP_LOGF( "%s(id=%d, oldVal=%d, newVal=%d)", __func__, gameID, oldVal, newVal );
|
||||
}
|
||||
|
||||
static void
|
||||
linux_dutil_onInviteReceived( XW_DUtilCtxt* duc, XWEnv XP_UNUSED(xwe),
|
||||
const NetLaunchInfo* nli )
|
||||
{
|
||||
LaunchParams* params = (LaunchParams*)duc->closure;
|
||||
|
||||
if ( params->useCurses ) {
|
||||
CommsAddrRec addr = {0};
|
||||
nli_makeAddrRec( nli, &addr );
|
||||
inviteReceivedCurses( params->appGlobals, nli, &addr );
|
||||
} else {
|
||||
relayInviteReceivedGTK( params->appGlobals, nli );
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
linux_dutil_onMessageReceived( XW_DUtilCtxt* duc, XWEnv XP_UNUSED(xwe),
|
||||
XP_U32 gameID, const CommsAddrRec* from,
|
||||
XWStreamCtxt* stream )
|
||||
{
|
||||
XP_LOGFF( "(gameID=%d)", gameID );
|
||||
LaunchParams* params = (LaunchParams*)duc->closure;
|
||||
|
||||
XP_U16 len = stream_getSize( stream );
|
||||
XP_U8 buf[len];
|
||||
stream_getBytes( stream, buf, len );
|
||||
|
||||
if ( params->useCurses ) {
|
||||
mqttMsgReceivedCurses( params->appGlobals, from, gameID, buf, len );
|
||||
} else {
|
||||
msgReceivedGTK( params->appGlobals, from, gameID, buf, len );
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
linux_dutil_onGameGoneReceived( XW_DUtilCtxt* duc, XWEnv XP_UNUSED(xwe),
|
||||
XP_U32 gameID, const CommsAddrRec* from )
|
||||
{
|
||||
LaunchParams* params = (LaunchParams*)duc->closure;
|
||||
if ( params->useCurses ) {
|
||||
gameGoneCurses( params->appGlobals, from, gameID );
|
||||
} else {
|
||||
gameGoneGTK( params->appGlobals, from, gameID );
|
||||
}
|
||||
}
|
||||
|
||||
XW_DUtilCtxt*
|
||||
dutils_init( MPFORMAL VTableMgr* vtMgr, void* closure )
|
||||
{
|
||||
|
@ -111,9 +161,14 @@ dutils_init( MPFORMAL VTableMgr* vtMgr, void* closure )
|
|||
|
||||
SET_PROC(notifyPause);
|
||||
SET_PROC(onDupTimerChanged);
|
||||
SET_PROC(onInviteReceived);
|
||||
SET_PROC(onMessageReceived);
|
||||
SET_PROC(onGameGoneReceived);
|
||||
|
||||
# undef SET_PROC
|
||||
|
||||
assertTableFull( &result->vtable, sizeof(result->vtable), "lindutil" );
|
||||
|
||||
MPASSIGN( result->mpool, mpool );
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
#include "linuxdict.h"
|
||||
#include "lindutil.h"
|
||||
#include "relaycon.h"
|
||||
#include "mqttcon.h"
|
||||
#include "smsproto.h"
|
||||
#ifdef PLATFORM_NCURSES
|
||||
# include "cursesmain.h"
|
||||
|
@ -299,21 +300,37 @@ linuxOpenGame( CommonGlobals* cGlobals, const TransportProcs* procs,
|
|||
/* If this is to be a relay connected game, tell it so. Otherwise
|
||||
let the invitation process and receipt of messages populate
|
||||
comms' addressbook */
|
||||
if ( cGlobals->gi->serverRole != SERVER_STANDALONE
|
||||
&& addr_hasType( ¶ms->addr, COMMS_CONN_RELAY ) ) {
|
||||
if ( cGlobals->gi->serverRole != SERVER_STANDALONE ) {
|
||||
if ( addr_hasType( ¶ms->addr, COMMS_CONN_RELAY ) ) {
|
||||
|
||||
if ( ! savedGame ) {
|
||||
linuxSaveGame( cGlobals );
|
||||
savedGame = true;
|
||||
if ( ! savedGame ) {
|
||||
linuxSaveGame( cGlobals );
|
||||
savedGame = true;
|
||||
}
|
||||
CommsAddrRec addr = {0};
|
||||
comms_getInitialAddr( &addr, params->connInfo.relay.relayName,
|
||||
params->connInfo.relay.defaultSendPort );
|
||||
XP_MEMCPY( addr.u.ip_relay.invite, params->connInfo.relay.invite,
|
||||
1 + XP_STRLEN(params->connInfo.relay.invite) );
|
||||
addr.u.ip_relay.seeksPublicRoom = params->connInfo.relay.seeksPublicRoom;
|
||||
addr.u.ip_relay.advertiseRoom = params->connInfo.relay.advertiseRoom;
|
||||
comms_augmentHostAddr( cGlobals->game.comms, NULL_XWE, &addr ); /* sends stuff */
|
||||
}
|
||||
|
||||
if ( addr_hasType( ¶ms->addr, COMMS_CONN_SMS ) ) {
|
||||
CommsAddrRec addr = {0};
|
||||
addr_addType( &addr, COMMS_CONN_SMS );
|
||||
XP_STRCAT( addr.u.sms.phone, params->connInfo.sms.myPhone );
|
||||
addr.u.sms.port = params->connInfo.sms.port;
|
||||
comms_augmentHostAddr( cGlobals->game.comms, NULL_XWE, &addr );
|
||||
}
|
||||
|
||||
if ( addr_hasType( ¶ms->addr, COMMS_CONN_MQTT ) ) {
|
||||
CommsAddrRec addr = {0};
|
||||
addr_addType( &addr, COMMS_CONN_MQTT );
|
||||
addr.u.mqtt.devID = *mqttc_getDevID( params );
|
||||
comms_augmentHostAddr( cGlobals->game.comms, NULL_XWE, &addr );
|
||||
}
|
||||
CommsAddrRec addr = {0};
|
||||
comms_getInitialAddr( &addr, params->connInfo.relay.relayName,
|
||||
params->connInfo.relay.defaultSendPort );
|
||||
XP_MEMCPY( addr.u.ip_relay.invite, params->connInfo.relay.invite,
|
||||
1 + XP_STRLEN(params->connInfo.relay.invite) );
|
||||
addr.u.ip_relay.seeksPublicRoom = params->connInfo.relay.seeksPublicRoom;
|
||||
addr.u.ip_relay.advertiseRoom = params->connInfo.relay.advertiseRoom;
|
||||
comms_augmentHostAddr( cGlobals->game.comms, NULL_XWE, &addr ); /* sends stuff */
|
||||
}
|
||||
|
||||
if ( !!returnAddrP ) {
|
||||
|
@ -882,6 +899,11 @@ typedef enum {
|
|||
,CMD_INVITEE_SMSNUMBER
|
||||
,CMD_SMSPORT
|
||||
#endif
|
||||
,CMD_WITHMQTT
|
||||
,CMD_MQTTHOST
|
||||
,CMD_MQTTPORT
|
||||
|
||||
,CMD_INVITEE_MQTTDEVID
|
||||
,CMD_INVITEE_COUNTS
|
||||
#ifdef XWFEATURE_RELAY
|
||||
,CMD_ROOMNAME
|
||||
|
@ -1018,6 +1040,10 @@ static CmdInfoRec CmdInfoRecs[] = {
|
|||
,{ CMD_INVITEE_SMSNUMBER, true, "invitee-sms-number", "number to send any invitation to" }
|
||||
,{ CMD_SMSPORT, true, "sms-port", "this devices's sms port" }
|
||||
#endif
|
||||
,{ CMD_WITHMQTT, false, "with-mqtt", "enable connecting via mqtt" }
|
||||
,{ CMD_MQTTHOST, true, "mqtt-host", "server mosquitto is running on" }
|
||||
,{ CMD_MQTTPORT, true, "mqtt-port", "port mosquitto is listening on" }
|
||||
,{ CMD_INVITEE_MQTTDEVID, true, "invitee-mqtt-devid", "upper-case hex devID to send any invitation to" }
|
||||
,{ CMD_INVITEE_COUNTS, true, "invitee-counts",
|
||||
"When invitations sent, how many on each device? e.g. \"1:2\" for a "
|
||||
"three-dev game with two players on second guest" }
|
||||
|
@ -1586,6 +1612,15 @@ linux_send( XWEnv XP_UNUSED(xwe), const XP_U8* buf, XP_U16 buflen,
|
|||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case COMMS_CONN_MQTT:
|
||||
nSent = mqttc_send( cGlobals->params, gameID, buf, buflen, &addrRec->u.mqtt.devID );
|
||||
break;
|
||||
|
||||
case COMMS_CONN_NFC:
|
||||
XP_LOGFF( "I don't do nfc! Should be filtering it on invitation receipt" );
|
||||
break;
|
||||
|
||||
default:
|
||||
XP_ASSERT(0);
|
||||
}
|
||||
|
@ -2587,6 +2622,8 @@ main( int argc, char** argv )
|
|||
mainParams.connInfo.ip.port = DEFAULT_PORT;
|
||||
mainParams.connInfo.ip.hostName = "localhost";
|
||||
#endif
|
||||
mainParams.connInfo.mqtt.hostName = "localhost";
|
||||
mainParams.connInfo.mqtt.port = 1883;
|
||||
#ifdef XWFEATURE_SMS
|
||||
mainParams.connInfo.sms.port = 1;
|
||||
#endif
|
||||
|
@ -2795,6 +2832,22 @@ main( int argc, char** argv )
|
|||
addr_addType( &mainParams.addr, COMMS_CONN_SMS );
|
||||
break;
|
||||
#endif
|
||||
case CMD_WITHMQTT:
|
||||
addr_addType( &mainParams.addr, COMMS_CONN_MQTT );
|
||||
break;
|
||||
case CMD_MQTTHOST:
|
||||
addr_addType( &mainParams.addr, COMMS_CONN_MQTT );
|
||||
mainParams.connInfo.mqtt.hostName = optarg;
|
||||
break;
|
||||
case CMD_MQTTPORT:
|
||||
addr_addType( &mainParams.addr, COMMS_CONN_MQTT );
|
||||
mainParams.connInfo.mqtt.port = atoi(optarg);
|
||||
break;
|
||||
case CMD_INVITEE_MQTTDEVID:
|
||||
mainParams.connInfo.mqtt.inviteeDevIDs =
|
||||
g_slist_append( mainParams.connInfo.mqtt.inviteeDevIDs, optarg );
|
||||
addr_addType( &mainParams.addr, COMMS_CONN_MQTT );
|
||||
break;
|
||||
case CMD_DUPPACKETS:
|
||||
mainParams.duplicatePackets = XP_TRUE;
|
||||
break;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
|
||||
/*
|
||||
* Copyright 2001-2013 by Eric House (xwords@eehouse.org). All rights
|
||||
* Copyright 2001 - 2020 by Eric House (xwords@eehouse.org). All rights
|
||||
* reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -51,7 +51,7 @@ typedef void (*SockReceiver)( void* closure, int socket );
|
|||
typedef void (*NewSocketProc)( void* closure, int newSock, int oldSock,
|
||||
SockReceiver proc, void* procClosure );
|
||||
|
||||
typedef struct LaunchParams {
|
||||
typedef struct _LaunchParams {
|
||||
/* CommPipeCtxt* pipe; */
|
||||
CurGameInfo pgi;
|
||||
|
||||
|
@ -67,6 +67,7 @@ typedef struct LaunchParams {
|
|||
XP_U32 dbFileID;
|
||||
#endif
|
||||
void* relayConStorage; /* opaque outside of relaycon.c */
|
||||
void* mqttConStorage;
|
||||
#ifdef XWFEATURE_SMS
|
||||
void* smsStorage;
|
||||
#endif
|
||||
|
@ -107,7 +108,10 @@ typedef struct LaunchParams {
|
|||
XP_Bool skipGameOver;
|
||||
XP_Bool useMmap;
|
||||
XP_Bool closeStdin;
|
||||
|
||||
XP_Bool useCurses;
|
||||
void* appGlobals; /* cursesmain or gtkmain sets this */
|
||||
|
||||
XP_Bool useUdp;
|
||||
XP_Bool useHTTP;
|
||||
XP_Bool runSMSTest;
|
||||
|
@ -168,6 +172,12 @@ typedef struct LaunchParams {
|
|||
int port;
|
||||
} sms;
|
||||
#endif
|
||||
struct {
|
||||
MQTTDevID devID;
|
||||
GSList* inviteeDevIDs;
|
||||
const char* hostName;
|
||||
int port;
|
||||
} mqtt;
|
||||
} connInfo;
|
||||
|
||||
union {
|
||||
|
|
275
xwords4/linux/mqttcon.c
Normal file
275
xwords4/linux/mqttcon.c
Normal file
|
@ -0,0 +1,275 @@
|
|||
/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
|
||||
/*
|
||||
* Copyright 2020 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.
|
||||
*/
|
||||
|
||||
#include <mosquitto.h>
|
||||
|
||||
#include "mqttcon.h"
|
||||
#include "gsrcwrap.h"
|
||||
#include "device.h"
|
||||
#include "strutils.h"
|
||||
|
||||
typedef struct _MQTTConStorage {
|
||||
LaunchParams* params;
|
||||
struct mosquitto* mosq;
|
||||
MQTTDevID clientID;
|
||||
gchar clientIDStr[32];
|
||||
gchar topic[64];
|
||||
int msgPipe[2];
|
||||
} MQTTConStorage;
|
||||
|
||||
#define DEFAULT_QOS 2
|
||||
|
||||
static MQTTConStorage*
|
||||
getStorage( LaunchParams* params )
|
||||
{
|
||||
MQTTConStorage* storage = (MQTTConStorage*)params->mqttConStorage;
|
||||
if ( NULL == storage ) {
|
||||
storage = XP_CALLOC( params->mpool, sizeof(*storage) );
|
||||
params->mqttConStorage = storage;
|
||||
}
|
||||
return storage;
|
||||
}
|
||||
|
||||
static void
|
||||
loadClientID( LaunchParams* params, MQTTConStorage* storage )
|
||||
{
|
||||
dvc_getMQTTDevID( params->dutil, NULL_XWE, &storage->clientID );
|
||||
formatMQTTDevID( &storage->clientID, storage->clientIDStr,
|
||||
VSIZE(storage->clientIDStr) );
|
||||
formatMQTTTopic( &storage->clientID, storage->topic, VSIZE(storage->topic) );
|
||||
}
|
||||
|
||||
static void
|
||||
onMessageReceived( struct mosquitto *mosq, void *userdata,
|
||||
const struct mosquitto_message* message )
|
||||
{
|
||||
XP_LOGFF( "(len=%d)", message->payloadlen );
|
||||
MQTTConStorage* storage = (MQTTConStorage*)userdata;
|
||||
XP_ASSERT( storage->mosq == mosq );
|
||||
// XP_ASSERT( 0 == XP_STRCMP( message->topic, storage->clientID ) );
|
||||
|
||||
XP_ASSERT( message->payloadlen < 0x7FFF );
|
||||
short len = (short)message->payloadlen;
|
||||
len = htons( len );
|
||||
|
||||
write( storage->msgPipe[1], &len, sizeof(len) );
|
||||
write( storage->msgPipe[1], message->payload, message->payloadlen );
|
||||
}
|
||||
|
||||
static void
|
||||
connect_callback( struct mosquitto *mosq, void *userdata, int result )
|
||||
{
|
||||
LOG_FUNC();
|
||||
XP_USE(mosq);
|
||||
XP_USE(userdata);
|
||||
XP_USE(result);
|
||||
/* int i; */
|
||||
/* if(!result){ */
|
||||
/* /\* Subscribe to broker information topics on successful connect. *\/ */
|
||||
/* mosquitto_subscribe(mosq, NULL, "$SYS/#", 2); */
|
||||
/* }else{ */
|
||||
/* fprintf(stderr, "Connect failed\n"); */
|
||||
/* } */
|
||||
}
|
||||
|
||||
static void
|
||||
subscribe_callback( struct mosquitto *mosq, void *userdata, int mid,
|
||||
int qos_count, const int *granted_qos)
|
||||
{
|
||||
XP_USE(mosq);
|
||||
XP_USE(userdata);
|
||||
XP_USE(mid);
|
||||
XP_USE(qos_count);
|
||||
XP_USE(granted_qos);
|
||||
XP_LOGFF ("Subscribed (mid: %d): %d", mid, granted_qos[0]);
|
||||
for( int ii=1; ii < qos_count; ii++ ) {
|
||||
XP_LOGFF(", %d", granted_qos[ii]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
log_callback(struct mosquitto *mosq, void *userdata, int level, const char *str )
|
||||
{
|
||||
XP_USE(mosq);
|
||||
XP_USE(userdata);
|
||||
XP_USE(level);
|
||||
XP_LOGFF( "msg: %s", str );
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_gotmsg( GIOChannel* source, GIOCondition XP_UNUSED(condition), gpointer data )
|
||||
{
|
||||
// XP_LOGFF( "(len=%d)", message->payloadlen );
|
||||
LOG_FUNC();
|
||||
MQTTConStorage* storage = (MQTTConStorage*)data;
|
||||
|
||||
int pipe = g_io_channel_unix_get_fd( source );
|
||||
XP_ASSERT( pipe == storage->msgPipe[0] );
|
||||
short len;
|
||||
ssize_t nRead = read( pipe, &len, sizeof(len) );
|
||||
XP_ASSERT( nRead == sizeof(len) );
|
||||
len = ntohs(len);
|
||||
XP_U8 buf[len];
|
||||
nRead = read( pipe, buf, len );
|
||||
XP_ASSERT( nRead == len );
|
||||
|
||||
dvc_parseMQTTPacket( storage->params->dutil, NULL_XWE, buf, len );
|
||||
|
||||
return TRUE;
|
||||
} /* handle_gotmsg */
|
||||
|
||||
static bool
|
||||
postMsg( MQTTConStorage* storage, XWStreamCtxt* stream, const MQTTDevID* invitee )
|
||||
{
|
||||
const XP_U8* bytes = stream_getPtr( stream );
|
||||
XP_U16 len = stream_getSize( stream );
|
||||
|
||||
int mid;
|
||||
|
||||
#ifdef DEBUG
|
||||
XP_UCHAR* sum = dutil_md5sum( storage->params->dutil, NULL_XWE, bytes, len );
|
||||
XP_LOGFF( "sending %d bytes with sum %s", len, sum );
|
||||
XP_FREEP( storage->params->mpool, &sum );
|
||||
#endif
|
||||
|
||||
gchar buf[32];
|
||||
int err = mosquitto_publish( storage->mosq, &mid,
|
||||
formatMQTTTopic( invitee, buf, sizeof(buf) ),
|
||||
len, bytes, DEFAULT_QOS, false );
|
||||
XP_LOGFF( "mosquitto_publish(topic=%s) => %s; mid=%d", buf, mosquitto_strerror(err), mid );
|
||||
|
||||
stream_destroy( stream, NULL_XWE );
|
||||
return err == 0;
|
||||
}
|
||||
|
||||
void
|
||||
mqttc_init( LaunchParams* params )
|
||||
{
|
||||
|
||||
XP_ASSERT( !params->mqttConStorage );
|
||||
MQTTConStorage* storage = getStorage( params );
|
||||
storage->params = params;
|
||||
|
||||
loadClientID( params, storage );
|
||||
|
||||
int res = pipe( storage->msgPipe );
|
||||
XP_ASSERT( !res );
|
||||
ADD_SOCKET( storage, storage->msgPipe[0], handle_gotmsg );
|
||||
|
||||
int err = mosquitto_lib_init();
|
||||
XP_LOGFF( "mosquitto_lib_init() => %d", err );
|
||||
XP_ASSERT( 0 == err );
|
||||
|
||||
bool cleanSession = false;
|
||||
struct mosquitto* mosq = storage->mosq =
|
||||
mosquitto_new( storage->clientIDStr, cleanSession, storage );
|
||||
|
||||
mosquitto_log_callback_set( mosq, log_callback );
|
||||
mosquitto_connect_callback_set( mosq, connect_callback );
|
||||
mosquitto_message_callback_set( mosq, onMessageReceived );
|
||||
mosquitto_subscribe_callback_set( mosq, subscribe_callback );
|
||||
|
||||
int keepalive = 60;
|
||||
err = mosquitto_connect( mosq, params->connInfo.mqtt.hostName,
|
||||
params->connInfo.mqtt.port, keepalive );
|
||||
XP_LOGFF( "mosquitto_connect() => %s", mosquitto_strerror(err) );
|
||||
if ( MOSQ_ERR_SUCCESS == err ) {
|
||||
int mid;
|
||||
err = mosquitto_subscribe( mosq, &mid, storage->topic, DEFAULT_QOS );
|
||||
XP_LOGFF( "mosquitto_subscribe(topic=%s) => %s, mid=%d", storage->topic,
|
||||
mosquitto_strerror(err), mid );
|
||||
|
||||
err = mosquitto_loop_start( mosq );
|
||||
XP_ASSERT( !err );
|
||||
} else {
|
||||
XP_LOGFF( "failed to connect so not proceeding" );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mqttc_cleanup( LaunchParams* params )
|
||||
{
|
||||
MQTTConStorage* storage = getStorage( params );
|
||||
|
||||
int err = mosquitto_loop_stop( storage->mosq, true ); /* blocks until thread dies */
|
||||
XP_LOGFF( "mosquitto_loop_stop() => %s", mosquitto_strerror(err) );
|
||||
mosquitto_destroy( storage->mosq );
|
||||
storage->mosq = NULL;
|
||||
mosquitto_lib_cleanup();
|
||||
|
||||
XP_ASSERT( params->mqttConStorage == storage ); /* cheat */
|
||||
XP_FREEP( params->mpool, &storage );
|
||||
params->mqttConStorage = NULL;
|
||||
}
|
||||
|
||||
const MQTTDevID*
|
||||
mqttc_getDevID( LaunchParams* params )
|
||||
{
|
||||
MQTTConStorage* storage = getStorage( params );
|
||||
return &storage->clientID;
|
||||
}
|
||||
|
||||
const gchar*
|
||||
mqttc_getDevIDStr( LaunchParams* params )
|
||||
{
|
||||
MQTTConStorage* storage = getStorage( params );
|
||||
return storage->clientIDStr;
|
||||
}
|
||||
|
||||
void
|
||||
mqttc_invite( LaunchParams* params, NetLaunchInfo* nli, const MQTTDevID* invitee )
|
||||
{
|
||||
MQTTConStorage* storage = getStorage( params );
|
||||
gchar buf[32];
|
||||
XP_LOGFF( "need to send to %s", formatMQTTDevID(invitee, buf, sizeof(buf) ) );
|
||||
|
||||
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(params->mpool)
|
||||
params->vtMgr );
|
||||
|
||||
dvc_makeMQTTInvite( stream, nli );
|
||||
|
||||
postMsg( storage, stream, invitee );
|
||||
}
|
||||
|
||||
XP_S16
|
||||
mqttc_send( LaunchParams* params, XP_U32 gameID, const XP_U8* buf,
|
||||
XP_U16 len, const MQTTDevID* addressee )
|
||||
{
|
||||
XP_S16 result = -1;
|
||||
MQTTConStorage* storage = getStorage( params );
|
||||
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(params->mpool)
|
||||
params->vtMgr );
|
||||
|
||||
dvc_makeMQTTMessage( params->dutil, NULL_XWE, stream,
|
||||
gameID, buf, len );
|
||||
if ( postMsg( storage, stream, addressee ) ) {
|
||||
result = len;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
mqttc_notifyGameGone( LaunchParams* params, const MQTTDevID* addressee, XP_U32 gameID )
|
||||
{
|
||||
MQTTConStorage* storage = getStorage( params );
|
||||
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(params->mpool)
|
||||
params->vtMgr );
|
||||
dvc_makeMQTTNoSuchGame( params->dutil, NULL_XWE, stream, gameID );
|
||||
postMsg( storage, stream, addressee );
|
||||
}
|
38
xwords4/linux/mqttcon.h
Normal file
38
xwords4/linux/mqttcon.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
|
||||
/*
|
||||
* Copyright 2020 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.
|
||||
*/
|
||||
|
||||
#ifndef _MQTTCON_H_
|
||||
#define _MQTTCON_H_
|
||||
|
||||
#include "main.h"
|
||||
#include "nli.h"
|
||||
|
||||
void mqttc_init( LaunchParams* params );
|
||||
void mqttc_cleanup( LaunchParams* params );
|
||||
|
||||
const MQTTDevID* mqttc_getDevID( LaunchParams* params );
|
||||
const gchar* mqttc_getDevIDStr( LaunchParams* params );
|
||||
void mqttc_invite( LaunchParams* params, NetLaunchInfo* nli, const MQTTDevID* mqttInvitee );
|
||||
XP_S16 mqttc_send( LaunchParams* params, XP_U32 gameID, const XP_U8* buf, XP_U16 len,
|
||||
const MQTTDevID* addressee );
|
||||
void mqttc_notifyGameGone( LaunchParams* params, const MQTTDevID* addressee, XP_U32 gameID );
|
||||
|
||||
bool mqttc_strToDevID( const gchar* str, MQTTDevID* result );
|
||||
|
||||
#endif
|
|
@ -33,7 +33,7 @@ typedef struct _Procs {
|
|||
void (*devIDReceived)( void* closure, const XP_UCHAR* devID,
|
||||
XP_U16 maxInterval );
|
||||
void (*msgErrorMsg)( void* closure, const XP_UCHAR* msg );
|
||||
void (*inviteReceived)( void* closure, NetLaunchInfo* invit );
|
||||
void (*inviteReceived)( void* closure, const NetLaunchInfo* invit );
|
||||
} RelayConnProcs;
|
||||
|
||||
void relaycon_init( LaunchParams* params, const RelayConnProcs* procs,
|
||||
|
|
|
@ -165,6 +165,7 @@ class Device():
|
|||
sTilesLeftTrayPat = re.compile('.*player \d+ now has (\d+) tiles')
|
||||
sRelayIDPat = re.compile('.*UPDATE games.*seed=(\d+),.*relayid=\'([^\']+)\'.*')
|
||||
sDevIDPat = re.compile('.*storing new devid: ([\da-fA-F]+).*')
|
||||
sMQTTDevIDPat = re.compile('.*dvc_getMQTTDevID.*: generated id: ([\d[A-F]+).*')
|
||||
sConnPat = re.compile('.*linux_util_informMissing\(isServer.*nMissing=0\).*')
|
||||
|
||||
sScoresDup = []
|
||||
|
@ -198,6 +199,8 @@ class Device():
|
|||
self.relayID = None
|
||||
self.inviteeDevID = None
|
||||
self.inviteeDevIDs = [] # only servers use this
|
||||
self.inviteeMQTTDevID = None
|
||||
self.inviteeMQTTDevIDs = []
|
||||
self.connected = False
|
||||
self.relaySeed = 0
|
||||
self.locked = False
|
||||
|
@ -261,6 +264,12 @@ class Device():
|
|||
match = Device.sDevIDPat.match(line)
|
||||
if match: self.inviteeDevID = int(match.group(1), 16)
|
||||
|
||||
if self.args.ADD_MQTT and not self.inviteeMQTTDevID:
|
||||
match = Device.sMQTTDevIDPat.match(line)
|
||||
if match:
|
||||
self.inviteeMQTTDevID = int(match.group(1), 16)
|
||||
# print('read mqtt devid: {:16X}'.format(self.inviteeMQTTDevID))
|
||||
|
||||
if not self.connected:
|
||||
match = Device.sConnPat.match(line)
|
||||
if match: self.connected = True
|
||||
|
@ -308,6 +317,18 @@ class Device():
|
|||
for inviteeDevID in self.inviteeDevIDs:
|
||||
args += ['--invitee-relayid', str(inviteeDevID)]
|
||||
|
||||
if self.args.ADD_MQTT:
|
||||
if self.order == 1 and not self.connected:
|
||||
for peer in self.peers:
|
||||
if peer.inviteeMQTTDevID and not peer == self:
|
||||
if not peer.inviteeMQTTDevID in self.inviteeMQTTDevIDs:
|
||||
self.inviteeMQTTDevIDs.append(peer.inviteeMQTTDevID)
|
||||
if self.inviteeMQTTDevIDs:
|
||||
args += [ '--force-invite' ]
|
||||
for idid in self.inviteeMQTTDevIDs:
|
||||
asHexStr = '{:16X}'.format(idid)
|
||||
args += ['--invitee-mqtt-devid', asHexStr]
|
||||
|
||||
self.proc = subprocess.Popen(args, stdout = subprocess.DEVNULL,
|
||||
stderr = subprocess.PIPE, universal_newlines = True)
|
||||
self.pid = self.proc.pid
|
||||
|
@ -450,6 +471,11 @@ def build_cmds(args):
|
|||
for dev in range(2, NDEVS + 1):
|
||||
PARAMS += [ '--invitee-sms-number', makeSMSPhoneNo(GAME, dev) ]
|
||||
|
||||
if args.ADD_MQTT:
|
||||
PARAMS += [ '--mqtt-port', args.MQTT_PORT, '--mqtt-host', args.MQTT_HOST ]
|
||||
if DEV == 1:
|
||||
PARAMS += [ '--force-invite' ]
|
||||
|
||||
if args.UNDO_PCT > 0:
|
||||
PARAMS += ['--undo-pct', args.UNDO_PCT]
|
||||
PARAMS += [ '--game-dict', DICT]
|
||||
|
@ -755,6 +781,11 @@ def mkParser():
|
|||
|
||||
parser.add_argument('--add-sms', dest = 'ADD_SMS', default = False, action = 'store_true')
|
||||
parser.add_argument('--sms-fail-pct', dest = 'SMS_FAIL_PCT', default = 0, type = int)
|
||||
|
||||
parser.add_argument('--add-mqtt', dest = 'ADD_MQTT', default = False, action = 'store_true')
|
||||
parser.add_argument('--mqtt-port', dest = 'MQTT_PORT', default = 1883 )
|
||||
parser.add_argument('--mqtt-host', dest = 'MQTT_HOST', default = 'localhost' )
|
||||
|
||||
parser.add_argument('--remove-relay', dest = 'ADD_RELAY', default = True, action = 'store_false')
|
||||
|
||||
parser.add_argument('--core-pat', dest = 'CORE_PAT', default = os.environ.get('DISCON_COREPAT'),
|
||||
|
|
65
xwords4/relay/scripts/mqtt-showinplay.py
Executable file
65
xwords4/relay/scripts/mqtt-showinplay.py
Executable file
|
@ -0,0 +1,65 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import argparse, re
|
||||
import paho.mqtt.client as mqtt
|
||||
|
||||
g_topics = [
|
||||
'$SYS/broker/clients/disconnected',
|
||||
# '$SYS/broker/+/+',
|
||||
'xw4/device/#',
|
||||
]
|
||||
|
||||
sDevIDPat = re.compile('xw4/device/([\dA-F]+)')
|
||||
|
||||
# Define event callbacks
|
||||
def on_connect(client, userdata, flags, rc):
|
||||
print("rc: " + str(rc))
|
||||
|
||||
def on_message(client, obj, msg):
|
||||
match = sDevIDPat.match(msg.topic)
|
||||
if match:
|
||||
print('for: {}, len: {}'.format(match.group(1), len(msg.payload)))
|
||||
|
||||
def on_publish(client, obj, mid):
|
||||
print("mid: " + str(mid))
|
||||
|
||||
def on_subscribe(client, obj, mid, granted_qos):
|
||||
print("Subscribed: " + str(mid) + " " + str(granted_qos))
|
||||
|
||||
def on_log(client, obj, level, string):
|
||||
print(string)
|
||||
|
||||
def makeClient():
|
||||
mqttc = mqtt.Client()
|
||||
# Assign event callbacks
|
||||
mqttc.on_message = on_message
|
||||
mqttc.on_connect = on_connect
|
||||
mqttc.on_publish = on_publish
|
||||
mqttc.on_subscribe = on_subscribe
|
||||
return mqttc
|
||||
|
||||
def mkParser():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--host', dest = 'HOST', default = 'liquidsugar.net',
|
||||
help = 'the host mosquitto is on')
|
||||
parser.add_argument('--port', dest = 'PORT', default = 1883,
|
||||
help = 'the port mosquitto is on')
|
||||
return parser
|
||||
|
||||
def main():
|
||||
args = mkParser().parse_args()
|
||||
|
||||
mqttc = makeClient()
|
||||
mqttc.connect(args.HOST, args.PORT)
|
||||
# Start subscribe, with QoS level 2
|
||||
for topic in g_topics:
|
||||
mqttc.subscribe(topic, 2)
|
||||
while True:
|
||||
err = mqttc.loop()
|
||||
if 0 != err:
|
||||
print('got {} from loop()'.format(err))
|
||||
break
|
||||
|
||||
##############################################################################
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Reference in a new issue