Moving Bitmessage context into a foreground service (work in progress)

This commit is contained in:
2015-10-23 22:40:09 +02:00
parent 9b1bf6bdb3
commit f5bf5c8bca
14 changed files with 441 additions and 143 deletions

View File

@ -0,0 +1,186 @@
package ch.dissem.apps.abit.synchronization;
import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetAddress;
import java.net.UnknownHostException;
import ch.dissem.apps.abit.listener.MessageListener;
import ch.dissem.apps.abit.notification.NetworkNotification;
import ch.dissem.apps.abit.repository.AndroidInventory;
import ch.dissem.apps.abit.repository.SqlHelper;
import ch.dissem.apps.abit.service.Singleton;
import ch.dissem.bitmessage.BitmessageContext;
import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.networking.DefaultNetworkHandler;
import ch.dissem.bitmessage.ports.MemoryNodeRegistry;
import ch.dissem.bitmessage.security.sc.SpongySecurity;
import static ch.dissem.apps.abit.notification.NetworkNotification.ONGOING_NOTIFICATION_ID;
/**
* Define a Service that returns an IBinder for the
* sync adapter class, allowing the sync adapter framework to call
* onPerformSync().
*/
public class BitmessageService extends Service {
public static final Logger LOG = LoggerFactory.getLogger(BitmessageService.class);
public static final int MSG_SYNC = 2;
public static final int MSG_CREATE_IDENTITY = 10;
public static final int MSG_SUBSCRIBE = 20;
public static final int MSG_ADD_CONTACT = 21;
public static final int MSG_SUBSCRIBE_AND_ADD_CONTACT = 23;
public static final int MSG_START_NODE = 100;
public static final int MSG_STOP_NODE = 101;
public static final String DATA_FIELD_ADDRESS = "address";
// Object to use as a thread-safe lock
private static final Object lock = new Object();
private static MessageListener messageListener = null;
private static NetworkNotification notification = null;
private static BitmessageContext bmc = null;
private static volatile boolean running = false;
private static Messenger messenger;
public static boolean isRunning() {
return running;
}
@Override
public void onCreate() {
synchronized (lock) {
if (bmc == null) {
messageListener = Singleton.getMessageListener(this);
SqlHelper sqlHelper = Singleton.getSqlHelper(this);
bmc = new BitmessageContext.Builder()
.security(new SpongySecurity())
.nodeRegistry(new MemoryNodeRegistry())
.inventory(new AndroidInventory(sqlHelper))
.addressRepo(Singleton.getAddressRepository(this))
.messageRepo(Singleton.getMessageRepository(this))
.networkHandler(new DefaultNetworkHandler())
.listener(messageListener)
.build();
notification = new NetworkNotification(this, bmc);
messenger = new Messenger(new IncomingHandler());
}
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
@Override
public void onDestroy() {
bmc.shutdown();
running = false;
}
/**
* Return an object that allows the system to invoke
* the sync adapter.
*/
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
private class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_CREATE_IDENTITY:
BitmessageAddress identity = bmc.createIdentity(false);
if (msg.replyTo != null) {
try {
Message message = Message.obtain(this, MSG_CREATE_IDENTITY);
Bundle bundle = new Bundle();
bundle.putSerializable(DATA_FIELD_ADDRESS, identity);
message.setData(bundle);
msg.replyTo.send(message);
} catch (RemoteException e) {
LOG.debug(e.getMessage(), e);
}
}
break;
case MSG_SUBSCRIBE:
BitmessageAddress address = (BitmessageAddress) msg.getData().getSerializable(DATA_FIELD_ADDRESS);
bmc.addSubscribtion(address);
break;
case MSG_SYNC:
LOG.info("Synchronizing Bitmessage");
// If the Bitmessage context acts as a full node, synchronization isn't necessary
if (bmc.isRunning()) break;
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(
BitmessageService.this);
String trustedNode = preferences.getString("trusted_node", null);
if (trustedNode == null) break;
trustedNode = trustedNode.trim();
if (trustedNode.isEmpty()) break;
int port;
if (trustedNode.matches("^(?![0-9a-fA-F]*:[0-9a-fA-F]*:).*(:[0-9]+)$")) {
int index = trustedNode.lastIndexOf(':');
String portString = trustedNode.substring(index + 1);
trustedNode = trustedNode.substring(0, index);
try {
port = Integer.parseInt(portString);
} catch (NumberFormatException e) {
LOG.error("Invalid port " + portString);
// TODO: show error as notification
return;
}
} else {
port = 8444;
}
long timeoutInSeconds = preferences.getInt("sync_timeout", 120);
try {
LOG.info("Synchronization started");
bmc.synchronize(InetAddress.getByName(trustedNode), port, timeoutInSeconds, true);
LOG.info("Synchronization finished");
} catch (UnknownHostException e) {
LOG.error("Couldn't synchronize", e);
// TODO: show error as notification
}
break;
case MSG_START_NODE:
startService(new Intent(BitmessageService.this, BitmessageService.class));
// TODO: warn user, option to restrict to WiFi
running = true;
startForeground(ONGOING_NOTIFICATION_ID, notification.getNotification());
bmc.startup();
notification.show();
break;
case MSG_STOP_NODE:
bmc.shutdown();
running = false;
stopForeground(false);
stopService(new Intent(BitmessageService.this, BitmessageService.class));
break;
default:
super.handleMessage(msg);
}
}
}
}

View File

@ -1,16 +1,12 @@
package ch.dissem.apps.abit.synchronization;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import ch.dissem.apps.abit.MessageListActivity;
import ch.dissem.apps.abit.listener.MessageListener;
import ch.dissem.apps.abit.notification.NetworkNotification;
import ch.dissem.apps.abit.repository.AndroidAddressRepository;
import ch.dissem.apps.abit.repository.AndroidInventory;
import ch.dissem.apps.abit.repository.AndroidMessageRepository;
import ch.dissem.apps.abit.repository.SqlHelper;
import ch.dissem.apps.abit.service.Singleton;
import ch.dissem.bitmessage.BitmessageContext;
@ -26,20 +22,12 @@ import static ch.dissem.apps.abit.notification.NetworkNotification.ONGOING_NOTIF
* onPerformSync().
*/
public class SyncService extends Service {
private static MessageListener messageListener = null;
private static BitmessageContext bmc = null;
// Storage for an instance of the sync adapter
private static SyncAdapter syncAdapter = null;
// Object to use as a thread-safe lock
private static final Object syncAdapterLock = new Object();
private static volatile boolean running = false;
public static boolean isRunning() {
return running;
}
/*
/**
* Instantiate the sync adapter object.
*/
@Override
@ -50,46 +38,12 @@ public class SyncService extends Service {
* Disallow parallel syncs
*/
synchronized (syncAdapterLock) {
final Context ctx = getApplicationContext();
if (bmc == null) {
// messageListener = new MessageListener(ctx);
// SqlHelper sqlHelper = new SqlHelper(ctx);
// bmc = new BitmessageContext.Builder()
// .security(new SpongySecurity())
// .nodeRegistry(new MemoryNodeRegistry())
// .inventory(new AndroidInventory(sqlHelper))
// .addressRepo(new AndroidAddressRepository(sqlHelper))
// .messageRepo(new AndroidMessageRepository(sqlHelper, ctx))
// .networkHandler(new DefaultNetworkHandler())
// .listener(messageListener)
// .build();
// FIXME: this needs to change once I figured out how to get rid of those singletons
messageListener = Singleton.getMessageListener(ctx);
bmc = Singleton.getBitmessageContext(ctx);
}
if (syncAdapter == null) {
syncAdapter = new SyncAdapter(ctx, bmc);
syncAdapter = new SyncAdapter(this, null); // FIXME
}
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO: warn user, option to restrict to WiFi
running = true;
NetworkNotification networkNotification = new NetworkNotification(this);
startForeground(ONGOING_NOTIFICATION_ID, networkNotification.getNotification());
bmc.startup();
networkNotification.show();
return Service.START_STICKY;
}
@Override
public void onDestroy() {
bmc.shutdown();
running = false;
}
/**
* Return an object that allows the system to invoke
* the sync adapter.