Avoid the same node being added multiple times (fixes #65).

When trying to add a node that already exists, the existing node is edited
instead.
This commit is contained in:
Felix Ableitner 2014-08-17 22:26:20 +02:00
parent 6a85fae8ca
commit 64bad6d0fe
9 changed files with 112 additions and 47 deletions

View File

@ -11,13 +11,11 @@ import android.os.Bundle;
import android.os.Environment;
import android.os.IBinder;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
@ -31,9 +29,7 @@ import com.nutomic.syncthingandroid.syncthing.SyncthingServiceBinder;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Stack;
/**
* Activity that allows selecting a directory in the local file system.

View File

@ -1,10 +1,6 @@
package com.nutomic.syncthingandroid.gui;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.app.Fragment;
@ -15,7 +11,6 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import com.nutomic.syncthingandroid.R;
import com.nutomic.syncthingandroid.syncthing.RestApi;

View File

@ -1,7 +1,6 @@
package com.nutomic.syncthingandroid.gui;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
@ -34,7 +33,8 @@ import java.util.Map;
*/
public class NodeSettingsActivity extends PreferenceActivity implements
Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener,
RestApi.OnReceiveConnectionsListener, SyncthingService.OnApiChangeListener {
RestApi.OnReceiveConnectionsListener, SyncthingService.OnApiChangeListener,
RestApi.OnNodeIdNormalizedListener {
public static final String ACTION_CREATE = "create";
@ -161,15 +161,16 @@ public class NodeSettingsActivity extends PreferenceActivity implements
switch (item.getItemId()) {
case R.id.create:
if (mNode.NodeID.equals("")) {
Toast.makeText(this, R.string.node_id_required, Toast.LENGTH_LONG).show();
Toast.makeText(this, R.string.node_id_required, Toast.LENGTH_LONG)
.show();
return true;
}
if (mNode.Name.equals("")) {
Toast.makeText(this, R.string.node_name_required, Toast.LENGTH_LONG).show();
Toast.makeText(this, R.string.node_name_required, Toast.LENGTH_LONG)
.show();
return true;
}
mSyncthingService.getApi().editNode(mNode, true, this);
finish();
mSyncthingService.getApi().editNode(mNode, this);
return true;
case R.id.share_node_id:
RestApi.shareNodeId(this, mNode.NodeID);
@ -255,7 +256,7 @@ public class NodeSettingsActivity extends PreferenceActivity implements
*/
private void nodeUpdated() {
if (getIntent().getAction().equals(ACTION_EDIT)) {
mSyncthingService.getApi().editNode(mNode, false, this);
mSyncthingService.getApi().editNode(mNode, this);
}
}
@ -287,4 +288,22 @@ public class NodeSettingsActivity extends PreferenceActivity implements
}
}
/**
* Callback for {@link RestApi#editNode(RestApi.Node, RestApi.OnNodeIdNormalizedListener)}.
* Displays an error message if present, or finishes the Activity on success in edit mode.
*
* @param normalizedId The normalized node ID, or null on error.
* @param error An error message, or null on success.
*/
@Override
public void onNodeIdNormalized(String normalizedId, String error) {
if (error != null) {
Toast.makeText(NodeSettingsActivity.this, error,
Toast.LENGTH_LONG).show();
}
else if (getIntent().getAction().equals(ACTION_CREATE)) {
finish();
}
}
}

View File

@ -3,9 +3,7 @@ package com.nutomic.syncthingandroid.gui;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;

View File

@ -3,9 +3,7 @@ package com.nutomic.syncthingandroid.gui;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import com.nutomic.syncthingandroid.R;

View File

@ -12,7 +12,6 @@ import android.view.View;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.nutomic.syncthingandroid.R;
import com.nutomic.syncthingandroid.syncthing.SyncthingService;

View File

@ -37,6 +37,8 @@ public class GetTask extends AsyncTask<String, Void, String> {
public static final String URI_MODEL = "/rest/model";
public static final String URI_NODEID = "/rest/nodeid";
/**
* params[0] Syncthing hostname
* params[1] URI to call

View File

@ -647,33 +647,56 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener {
}
/**
* Updates or creates the given node.
* Updates or creates the given node, depending on whether it already exists.
*
* @param node Settings of the node to edit. To create a node, pass a non-existant node ID.
* @param listener {@link OnNodeIdNormalizedListener} for the normalized node ID.
*/
public void editNode(Node node, boolean create, Activity activity) {
try {
JSONArray nodes = mConfig.getJSONArray("Nodes");
JSONObject n = null;
if (create) {
n = new JSONObject();
nodes.put(n);
}
else {
for (int i = 0; i < nodes.length(); i++) {
JSONObject json = nodes.getJSONObject(i);
if (node.NodeID.equals(json.getString("NodeID"))) {
n = nodes.getJSONObject(i);
break;
public void editNode(final Node node,
final OnNodeIdNormalizedListener listener) {
mSyncthingService.getApi().normalizeNodeId(node.NodeID,
new RestApi.OnNodeIdNormalizedListener() {
@Override
public void onNodeIdNormalized(String normalizedId, String error) {
listener.onNodeIdNormalized(normalizedId, error);
if (normalizedId == null)
return;
node.NodeID = normalizedId;
// If the node already exists, just update it.
boolean create = true;
for (RestApi.Node n : getNodes()) {
if (n.NodeID.equals(node.NodeID)) {
create = false;
}
}
try {
JSONArray nodes = mConfig.getJSONArray("Nodes");
JSONObject n = null;
if (create) {
n = new JSONObject();
nodes.put(n);
}
else {
for (int i = 0; i < nodes.length(); i++) {
JSONObject json = nodes.getJSONObject(i);
if (node.NodeID.equals(json.getString("NodeID"))) {
n = nodes.getJSONObject(i);
break;
}
}
}
n.put("NodeID", node.NodeID);
n.put("Name", node.Name);
n.put("Addresses", listToJson(node.Addresses.split(" ")));
configUpdated(mSyncthingService);
}
catch (JSONException e) {
Log.w(TAG, "Failed to read nodes", e);
}
}
}
}
n.put("NodeID", node.NodeID);
n.put("Name", node.Name);
n.put("Addresses", listToJson(node.Addresses.split(" ")));
configUpdated(activity);
}
catch (JSONException e) {
Log.w(TAG, "Failed to read nodes", e);
}
});
}
/**
@ -781,6 +804,42 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener {
return newArray;
}
/**
* Result listener for {@link #normalizeNodeId(String, OnNodeIdNormalizedListener)}.
*/
public interface OnNodeIdNormalizedListener {
/**
* On any call, exactly one parameter will be null.
*
* @param normalizedId The normalized node ID, or null on error.
* @param error An error message, or null on success.
*/
public void onNodeIdNormalized(String normalizedId, String error);
}
/**
* Normalizes a given node ID.
*/
public void normalizeNodeId(String id, final OnNodeIdNormalizedListener listener) {
new GetTask() {
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
String normalized = null;
String error = null;
try {
JSONObject json = new JSONObject(s);
normalized = json.optString("id", null);
error = json.optString("error", null);
}
catch (JSONException e) {
Log.d(TAG, "Failed to parse normalized node ID JSON", e);
}
listener.onNodeIdNormalized(normalized, error);
}
}.execute(mUrl, GetTask.URI_NODEID, mApiKey, "id", id);
}
public boolean isApiAvailable() {
return mAvailableCount.get() == TOTAL_STARTUP_CALLS;
}

View File

@ -36,7 +36,6 @@ import java.io.InputStreamReader;
import java.lang.ref.WeakReference;
import java.util.HashSet;
import java.util.Iterator;
import java.util.concurrent.locks.ReentrantLock;
/**
* Holds the native syncthing instance and provides an API to access it.