From cd5ba362c2d7cffce1d0ddd10497bdee8e6c6668 Mon Sep 17 00:00:00 2001 From: DC* Date: Sat, 1 May 2021 00:54:46 +0100 Subject: [PATCH 1/3] Upgrade to node-wrapper 1.1 Signed-off-by: DC* --- app/build.gradle | 4 +- .../mobile/services/node/Manager.java | 169 +++++++----------- .../mobile/ui/main/activity/MainFragment.java | 24 +-- 3 files changed, 85 insertions(+), 112 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 3196e78..bc05ea1 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,7 +9,7 @@ android { } defaultConfig { applicationId "org.freenetproject.mobile" - minSdkVersion 22 + minSdkVersion 26 targetSdkVersion 30 versionCode 303 versionName '0.3.2-beta' @@ -55,7 +55,7 @@ dependencies { implementation 'com.google.guava:guava:24.1-jre' // Freenet dependencies - implementation ('com.github.freenet-mobile:node-wrapper:0.6') { + implementation ('com.github.freenet-mobile:node-wrapper:1.1') { exclude group: 'org.freenetproject', module: 'freenet-ext' exclude group: 'net.java.dev.jna', module: 'jna' exclude group: 'net.java.dev.jna', module: 'jna-platform' diff --git a/app/src/main/java/org/freenetproject/mobile/services/node/Manager.java b/app/src/main/java/org/freenetproject/mobile/services/node/Manager.java index cf065b7..19e1085 100644 --- a/app/src/main/java/org/freenetproject/mobile/services/node/Manager.java +++ b/app/src/main/java/org/freenetproject/mobile/services/node/Manager.java @@ -2,8 +2,8 @@ import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.content.res.Resources; -import android.os.Build; import android.util.Log; import androidx.lifecycle.LiveData; @@ -11,48 +11,46 @@ import com.jakewharton.processphoenix.ProcessPhoenix; +import org.freenetproject.mobile.NodeController; +import org.freenetproject.mobile.NodeControllerImpl; import org.freenetproject.mobile.R; import org.freenetproject.mobile.ui.main.activity.MainActivity; -import java.io.FileNotFoundException; +import java.io.File; +import java.io.IOException; import java.util.HashMap; import java.util.Map; -import org.freenetproject.mobile.Runner; -import org.freenetproject.mobile.Installer; - /** * Class responsible for exposing data to the UI. It also exposes methods for the UI to interact with, * such as startService and stopService. */ public class Manager { - + public static final String CONTEXT_NETWORK = "network"; + public static final String CONTEXT_BATTERY = "battery"; private static Manager instance = null; - private final Runner runner = Runner.getInstance(); + private final Map contextRunFlag = new HashMap() {{ + put(CONTEXT_NETWORK, true); + put(CONTEXT_BATTERY, true); + }}; + // when adding a new state that has transitions be sure to update isTransitioning method public enum Status { STARTING_UP, STARTED, STOPPING, STOPPED, ERROR, - INSTALLING, PAUSED, - PAUSING // when adding a new state that has transitions be sure to update isTransitioning method + PAUSING } - public static final String CONTEXT_NETWORK = "network"; - public static final String CONTEXT_BATTERY = "battery"; + private NodeController nc; + private final MutableLiveData status = new MutableLiveData(); - private Map contextRunFlag = new HashMap() {{ - put(CONTEXT_NETWORK, true); - put(CONTEXT_BATTERY, true); - }}; - - private MutableLiveData status = new MutableLiveData(); private Manager() { status.postValue( - runner.isStarted() ? Status.STARTED : Status.STOPPED + nc != null && nc.isRunning() ? Status.STARTED : Status.STOPPED ); } @@ -77,92 +75,73 @@ public LiveData getStatus() { * Checks if the node is installed and install it otherwise. * * @param context Application context. - * @return */ - public int startService(Context context) { - if (!Installer.getInstance().isInstalled()) { - status.postValue(Status.INSTALLING); - try { - Resources res = context.getResources(); - Installer.getInstance().install( - context.getDir("data", Context.MODE_PRIVATE).getAbsolutePath(), - res.openRawResource(R.raw.seednodes), - res.openRawResource(R.raw.freenet), - res.openRawResource(R.raw.bookmarks), - res.getConfiguration().locale.getDisplayLanguage() - ); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - } + public void startService(Context context) throws IOException { + File path = context.getDir("data", Context.MODE_PRIVATE); - int ret = startNode(); - if (ret == 0) { - Intent serviceIntent = new Intent(context, Service.class); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - context.startForegroundService(serviceIntent); - } else { - context.startService(serviceIntent); - } - } else { - Log.e("Freenet", "Error starting freenet (" + ret + ")"); - status.postValue(Status.ERROR); + status.postValue(Status.STARTING_UP); + + nc = new NodeControllerImpl(path.toPath()); + + SharedPreferences prefs = context.getSharedPreferences( + context.getPackageName(), Context.MODE_PRIVATE + ); + + Resources res = context.getResources(); + // Setup first-run configuration + if (prefs.getBoolean("first-run", true)) { + nc.setConfig("seednodes.fref", res.openRawResource(R.raw.seednodes)); + nc.setConfig("bookmarks.dat", res.openRawResource(R.raw.bookmarks)); } - return 0; - } + nc.start(); - private int startNode() { - status.postValue(Status.STARTING_UP); - int ret = -1; - try { - ret = runner.start(new String[]{Installer.getInstance().getFreenetIniPath()}); - if (ret == 0) { - status.postValue(Status.STARTED); - } else if (ret == -1) { - // Already running - status.postValue(Status.STARTED); - } else { - status.postValue(Status.ERROR); + if (nc.isRunning()) { + + if (prefs.getBoolean("first-run", true)) { + // Setup first-run runtime configuration + nc.setConfig("node.l10n", res.getConfiguration().getLocales().get(0).toLanguageTag()); } - } catch (Exception e) { + + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean("first-run", false); + editor.apply(); + + Intent serviceIntent = new Intent(context, Service.class); + context.startForegroundService(serviceIntent); + status.postValue(Status.STARTED); + + } else { status.postValue(Status.ERROR); } - return ret; + } /** * Stops the service through the Runner class. Also stops the Services.Node.Service. * * @param context Application context. - * @return */ - public int stopService(Context context) { + public void stopService(Context context) { Intent serviceIntent = new Intent(context, Service.class); context.stopService(serviceIntent); try { - if (runner.stop() != 0) { - status.postValue(Status.ERROR); - } - + nc.shutdown(); status.postValue(Status.STOPPED); - } catch (Exception e) { status.postValue(Status.ERROR); } - return 0; } /** * Stop the node and restart the application. * - * @param context - * @return + * @param context Application context */ - public int restartService(Context context) { + public void restartService(Context context) { stopService(context); Log.i("Freenet", "Calling rebirth"); @@ -174,73 +153,64 @@ public int restartService(Context context) { ) ); - return 0; } /** * Pauses the node running on the device while maintaining the service running on foreground. * - * @param context - * @return + * @param context Application context + * @param serviceContext String description for the calling context */ - public int pauseService(Context context, String serviceContext) { + public void pauseService(Context context, String serviceContext) { if (isPaused()) { - return -1; + return; } contextRunFlag.put(serviceContext, false); status.postValue(Status.PAUSING); try { - if (runner.pause() == 0) { - status.postValue(Status.PAUSED); - } else { - status.postValue(Status.ERROR); - - } + nc.pause(); + status.postValue(Status.PAUSED); } catch (Exception e) { status.postValue(Status.ERROR); } - return 0; } /** * Starts up or resume a service. * - * @param context - * @return + * @param context Application context + * @param serviceContext String description for the calling context */ - public int resumeService(Context context, String serviceContext) { + public void resumeService(Context context, String serviceContext) { if (!isPaused()) { - return -2; + return; } contextRunFlag.put(serviceContext, true); for (Boolean value : contextRunFlag.values()) { - if (!value) - return -3; // a given context has flagged not to run + if (!value) { + return; // a given context has flagged not to run + } } status.postValue(Status.STARTING_UP); try { - if (runner.resume() == 0) { - status.postValue(Status.STARTED); - } else { - status.postValue(Status.ERROR); - } + nc.resume(); + status.postValue(Status.STARTED); } catch (Exception e) { status.postValue(Status.ERROR); } - return 0; } - public Boolean resetService(Context context) { + public void resetService(Context context) { Intent serviceIntent = new Intent(context, Service.class); context.stopService(serviceIntent); try { - runner.stop(); + nc.shutdown(); } catch (Exception e) { Log.e("Freenet", "Error stopping node: " + e.getMessage()); } @@ -253,7 +223,6 @@ public Boolean resetService(Context context) { MainActivity.class ) ); - return true; } public Boolean isStopped() { diff --git a/app/src/main/java/org/freenetproject/mobile/ui/main/activity/MainFragment.java b/app/src/main/java/org/freenetproject/mobile/ui/main/activity/MainFragment.java index 5a41f44..775dc10 100644 --- a/app/src/main/java/org/freenetproject/mobile/ui/main/activity/MainFragment.java +++ b/app/src/main/java/org/freenetproject/mobile/ui/main/activity/MainFragment.java @@ -14,8 +14,6 @@ import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; -import com.google.common.collect.ImmutableMap; - import org.freenetproject.mobile.BuildConfig; import org.freenetproject.mobile.R; import org.freenetproject.mobile.services.node.Manager; @@ -24,18 +22,20 @@ import org.freenetproject.mobile.ui.acknowledgement.activity.AcknowledgementActivity; import org.freenetproject.mobile.ui.acknowledgement.activity.AcknowledgementFragment; import org.freenetproject.mobile.ui.main.viewmodel.MainViewModel; -import org.freenetproject.mobile.ui.notification.Notification; import org.freenetproject.mobile.ui.settings.activity.SettingsActivity; +import java.util.HashMap; +import java.io.IOException; import java.util.Map; public class MainFragment extends Fragment { - static final Map STATUS_ACTION_MAP = ImmutableMap.builder() - .put(Manager.Status.STARTED.ordinal(), R.drawable.ic_baseline_power_settings_new_24) - .put(Manager.Status.PAUSED.ordinal(), R.drawable.ic_baseline_power_settings_new_24) - .put(Manager.Status.STOPPED.ordinal(), R.drawable.ic_baseline_play_circle_outline_24) - .put(Manager.Status.ERROR.ordinal(), R.drawable.ic_baseline_replay_24) - .build(); + static final Map STATUS_ACTION_MAP = new HashMap() {{ + put(Manager.Status.STOPPED.ordinal(), R.drawable.ic_baseline_info_24); + put(Manager.Status.STARTED.ordinal(), R.drawable.ic_baseline_power_settings_new_24); + put(Manager.Status.PAUSED.ordinal(), R.drawable.ic_baseline_power_settings_new_24); + put(Manager.Status.STOPPED.ordinal(), R.drawable.ic_baseline_play_circle_outline_24); + put(Manager.Status.ERROR.ordinal(), R.drawable.ic_baseline_replay_24); + }}; @Override public View onCreateView( @@ -80,7 +80,11 @@ private void updateControls(Manager m, View view) { // When running or paused the node can be shutdown,but it can not // be paused or started. if (m.isStopped()) { - m.startService(view.getContext()); + try { + m.startService(view.getContext()); + } catch (IOException e) { + // Should set an error message + } } else if (m.isRunning() || m.isPaused()) { m.restartService(view.getContext()); } else if (m.hasError()) { From 2f6edbf929bd1987f1e2fd7865ee30f9b464ca7a Mon Sep 17 00:00:00 2001 From: DC* Date: Sun, 2 May 2021 02:27:52 +0100 Subject: [PATCH 2/3] Upgrade to node-wrapper 2 Signed-off-by: DC* --- app/build.gradle | 2 +- .../freenetproject/mobile/services/node/Manager.java | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index bc05ea1..57c64e0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -55,7 +55,7 @@ dependencies { implementation 'com.google.guava:guava:24.1-jre' // Freenet dependencies - implementation ('com.github.freenet-mobile:node-wrapper:1.1') { + implementation ('com.github.freenet-mobile:node-wrapper:2.0') { exclude group: 'org.freenetproject', module: 'freenet-ext' exclude group: 'net.java.dev.jna', module: 'jna' exclude group: 'net.java.dev.jna', module: 'jna-platform' diff --git a/app/src/main/java/org/freenetproject/mobile/services/node/Manager.java b/app/src/main/java/org/freenetproject/mobile/services/node/Manager.java index 19e1085..3f4da4e 100644 --- a/app/src/main/java/org/freenetproject/mobile/services/node/Manager.java +++ b/app/src/main/java/org/freenetproject/mobile/services/node/Manager.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.util.HashMap; import java.util.Map; +import java.util.Objects; /** * Class responsible for exposing data to the UI. It also exposes methods for the UI to interact with, @@ -226,22 +227,23 @@ public void resetService(Context context) { } public Boolean isStopped() { - return status.getValue().equals(Status.STOPPED); + return Objects.equals(status.getValue(), Status.STOPPED); } public Boolean isPaused() { - return status.getValue().equals(Status.PAUSED); + return Objects.equals(status.getValue(), Status.PAUSED); } public Boolean isRunning() { - return status.getValue().equals(Status.STARTED); + return Objects.equals(status.getValue(), Status.STARTED); } public Boolean hasError() { - return status.getValue().equals(Status.ERROR); + return Objects.equals(status.getValue(), Status.ERROR); } public Boolean isTransitioning() { Status value = status.getValue(); + assert value != null; return !value.equals(Status.STARTED) && !value.equals(Status.STOPPED) && !value.equals(Status.PAUSED); From a8e651777e0c55ac749bcc573f6378328d4e63e8 Mon Sep 17 00:00:00 2001 From: DC* Date: Sat, 14 Aug 2021 20:44:33 +0100 Subject: [PATCH 3/3] Randomize fproxy and fcp ports --- .../freenetproject/mobile/proxy/Simple.java | 10 ++- .../mobile/services/node/Manager.java | 64 +++++++++++++++---- 2 files changed, 58 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/org/freenetproject/mobile/proxy/Simple.java b/app/src/main/java/org/freenetproject/mobile/proxy/Simple.java index 6be5ed9..007ace5 100644 --- a/app/src/main/java/org/freenetproject/mobile/proxy/Simple.java +++ b/app/src/main/java/org/freenetproject/mobile/proxy/Simple.java @@ -107,13 +107,17 @@ public void run() { } } - @Override - public void run() { + public void run(String address, int port) { Log.d("Freenet", "Proxy thread started"); try { - run("127.0.0.1", 8888, defaultLocalPort); + run(address, port, defaultLocalPort); } catch (IOException e) { e.printStackTrace(); } } + + @Override + public void run() { + run("127.0.0.1", 8888); + } } diff --git a/app/src/main/java/org/freenetproject/mobile/services/node/Manager.java b/app/src/main/java/org/freenetproject/mobile/services/node/Manager.java index 3f4da4e..5dfdd87 100644 --- a/app/src/main/java/org/freenetproject/mobile/services/node/Manager.java +++ b/app/src/main/java/org/freenetproject/mobile/services/node/Manager.java @@ -11,6 +11,8 @@ import com.jakewharton.processphoenix.ProcessPhoenix; +import org.freenetproject.mobile.Config; +import org.freenetproject.mobile.Connector; import org.freenetproject.mobile.NodeController; import org.freenetproject.mobile.NodeControllerImpl; import org.freenetproject.mobile.R; @@ -21,6 +23,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Objects; +import java.util.Random; /** * Class responsible for exposing data to the UI. It also exposes methods for the UI to interact with, @@ -78,19 +81,29 @@ public LiveData getStatus() { * @param context Application context. */ public void startService(Context context) throws IOException { + SharedPreferences prefs = context.getSharedPreferences( + context.getPackageName(), Context.MODE_PRIVATE + ); + + Resources res = context.getResources(); + File path = context.getDir("data", Context.MODE_PRIVATE); status.postValue(Status.STARTING_UP); - nc = new NodeControllerImpl(path.toPath()); + final boolean isFirstRun = prefs.getBoolean("first-run", true); - SharedPreferences prefs = context.getSharedPreferences( - context.getPackageName(), Context.MODE_PRIVATE - ); + // on first install + if (isFirstRun) { + initializeConfiguration(path, context); + } + + // instantiate connector with given port + Connector connector = new Connector("127.0.0.1", prefs.getInt("fcp.port", 9481)); + nc = new NodeControllerImpl(path.toPath(), new Config(), connector); - Resources res = context.getResources(); // Setup first-run configuration - if (prefs.getBoolean("first-run", true)) { + if (isFirstRun) { nc.setConfig("seednodes.fref", res.openRawResource(R.raw.seednodes)); nc.setConfig("bookmarks.dat", res.openRawResource(R.raw.bookmarks)); } @@ -98,12 +111,6 @@ public void startService(Context context) throws IOException { nc.start(); if (nc.isRunning()) { - - if (prefs.getBoolean("first-run", true)) { - // Setup first-run runtime configuration - nc.setConfig("node.l10n", res.getConfiguration().getLocales().get(0).toLanguageTag()); - } - SharedPreferences.Editor editor = prefs.edit(); editor.putBoolean("first-run", false); editor.apply(); @@ -111,13 +118,44 @@ public void startService(Context context) throws IOException { Intent serviceIntent = new Intent(context, Service.class); context.startForegroundService(serviceIntent); status.postValue(Status.STARTED); - } else { status.postValue(Status.ERROR); } } + /** + * + * @param path + * @param context + * @throws IOException + */ + private void initializeConfiguration(File path, Context context) throws IOException { + SharedPreferences prefs = context.getSharedPreferences( + context.getPackageName(), Context.MODE_PRIVATE + ); + + // generate random port + final int TOP_RANGE = 32767, BOTTOM_RANGE = 5001; + + // store in shared preferences + SharedPreferences.Editor editor = prefs.edit(); + editor.putInt("fproxy.port", new Random().nextInt(TOP_RANGE - BOTTOM_RANGE) + BOTTOM_RANGE); + editor.putInt("fcp.port", new Random().nextInt(TOP_RANGE - BOTTOM_RANGE) + BOTTOM_RANGE); + editor.apply(); + + // update config with given ports + Config config = new Config(); + config.loadOrDefault(path.toPath()); + config.set("fproxy.port", String.valueOf(prefs.getInt("fproxy.port", 8888))); + config.set("fcp.port", String.valueOf(prefs.getInt("fcp.port", 9481))); + + Resources res = context.getResources(); + config.set("node.l10n", res.getConfiguration().getLocales().get(0).toLanguageTag()); + + config.persist(); + } + /** * Stops the service through the Runner class. Also stops the Services.Node.Service. *