From abaab3b26bbbee5251ea0cfb974464cfb0e0704f Mon Sep 17 00:00:00 2001 From: Adrian Tiberius Date: Mon, 27 Jun 2016 18:35:25 +0300 Subject: [PATCH 01/10] added Geth react-native module --- android/app/build.gradle | 2 +- android/app/src/main/AndroidManifest.xml | 2 +- .../main/java/com/statusim/GethService.java | 140 ----------- .../main/java/com/statusim/MainActivity.java | 81 +------ .../com/statusim/geth/module/GethModule.java | 209 ++++++++++++++++ .../com/statusim/geth/module/GethPackage.java | 33 +++ .../geth/service/ConnectorHandler.java | 12 + .../statusim/geth/service/GethConnector.java | 107 +++++++++ .../statusim/geth/service/GethMessages.java | 56 +++++ .../statusim/geth/service/GethService.java | 227 ++++++++++++++++++ .../geth/service/ServiceConnector.java | 149 ++++++++++++ src/status_im/components/react.cljs | 3 + 12 files changed, 801 insertions(+), 220 deletions(-) delete mode 100644 android/app/src/main/java/com/statusim/GethService.java create mode 100644 android/app/src/main/java/com/statusim/geth/module/GethModule.java create mode 100644 android/app/src/main/java/com/statusim/geth/module/GethPackage.java create mode 100644 android/app/src/main/java/com/statusim/geth/service/ConnectorHandler.java create mode 100644 android/app/src/main/java/com/statusim/geth/service/GethConnector.java create mode 100644 android/app/src/main/java/com/statusim/geth/service/GethMessages.java create mode 100644 android/app/src/main/java/com/statusim/geth/service/GethService.java create mode 100644 android/app/src/main/java/com/statusim/geth/service/ServiceConnector.java diff --git a/android/app/build.gradle b/android/app/build.gradle index 7202b12494..301a07656c 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -133,7 +133,7 @@ dependencies { compile project(':react-native-camera') compile project(':react-native-orientation') // compile(name:'geth', ext:'aar') - compile(group: 'status-im', name: 'android-geth', version: '1.4.0-201604110816-a97a114', ext: 'aar') + compile(group: 'status-im', name: 'status-go', version: '0.1.0-test-callback', ext: 'aar') compile fileTree(dir: "node_modules/realm/android/libs", include: ["*.jar"]) } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 42b5ee2517..a7b7a31725 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -23,7 +23,7 @@ diff --git a/android/app/src/main/java/com/statusim/GethService.java b/android/app/src/main/java/com/statusim/GethService.java deleted file mode 100644 index 84ec5daaa2..0000000000 --- a/android/app/src/main/java/com/statusim/GethService.java +++ /dev/null @@ -1,140 +0,0 @@ -package com.statusim; - -import android.app.Service; -import android.content.Intent; -import android.os.Handler; -import android.os.AsyncTask; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.Messenger; -import android.support.annotation.Nullable; -import android.util.Log; -import android.os.Environment; - -import java.lang.ref.WeakReference; - -import com.github.ethereum.go_ethereum.cmd.Geth; - -import java.io.File; - -public class GethService extends Service { - - private static final String TAG = "GethService"; - - private static boolean isGethStarted = false; - private static boolean isGethInitialized = false; - private final Handler handler = new Handler(); - - static class IncomingHandler extends Handler { - - private final WeakReference service; - - IncomingHandler(GethService service) { - - this.service = new WeakReference(service); - } - - @Override - public void handleMessage(Message message) { - - GethService service = this.service.get(); - if (service != null) { - if (!service.handleMessage(message)) { - super.handleMessage(message); - } - } - } - } - - final Messenger serviceMessenger = new Messenger(new IncomingHandler(this)); - - protected class StartTask extends AsyncTask { - - public StartTask() { - } - - protected Void doInBackground(Void... args) { - startGeth(); - return null; - } - - protected void onPostExecute(Void results) { - onGethStarted(); - } - } - - protected void onGethStarted() { - Log.d(TAG, "Geth Service started"); - isGethStarted = true; - } - - protected void startGeth() { - Log.d(TAG, "Starting background Geth Service"); - - File extStore = Environment.getExternalStorageDirectory(); - - final String dataFolder = extStore.exists() ? - extStore.getAbsolutePath() : - getApplicationInfo().dataDir; - - final Runnable addPeer = new Runnable() { - public void run() { - Log.w("Geth", "adding peer"); - Geth.run("--exec admin.addPeer(\"enode://e2f28126720452aa82f7d3083e49e6b3945502cb94d9750a15e27ee310eed6991618199f878e5fbc7dfa0e20f0af9554b41f491dc8f1dbae8f0f2d37a3a613aa@139.162.13.89:55555\") attach http://localhost:8545"); - } - }; - - new Thread(new Runnable() { - public void run() { - Geth.run("--shh --ipcdisable --nodiscover --rpc --rpcapi db,eth,net,web3,shh,admin --fast --datadir=" + dataFolder); - } - }).start(); - - handler.postDelayed(addPeer, 5000); - } - - public void signalEvent(String jsonEvent) { - - } - - @Nullable - @Override - public IBinder onBind(Intent intent) { - return serviceMessenger.getBinder(); - } - - @Override - public void onCreate() { - super.onCreate(); - System.loadLibrary("gethraw"); - System.loadLibrary("geth"); - - if (!isGethInitialized) { - isGethInitialized = true; - new StartTask().execute(); - } - } - - @Override - public void onDestroy() { - super.onDestroy(); - //TODO: stop geth - isGethStarted = false; - isGethInitialized = false; - Log.d(TAG, "Geth Service stopped !"); - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - return Service.START_STICKY; - } - - protected boolean handleMessage(Message message) { - return false; - } - - public static boolean isRunning() { - return isGethInitialized; - } -} diff --git a/android/app/src/main/java/com/statusim/MainActivity.java b/android/app/src/main/java/com/statusim/MainActivity.java index ee5ff65fd1..f5c2afe69d 100644 --- a/android/app/src/main/java/com/statusim/MainActivity.java +++ b/android/app/src/main/java/com/statusim/MainActivity.java @@ -1,98 +1,36 @@ package com.statusim; import com.facebook.react.ReactActivity; +import com.statusim.geth.module.GethPackage; import io.realm.react.RealmReactPackage; import com.oblador.vectoricons.VectorIconsPackage; import com.facebook.react.ReactPackage; import com.facebook.react.shell.MainReactPackage; import com.rt2zz.reactnativecontacts.ReactNativeContacts; import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.Message; -import android.os.Messenger; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.DialogInterface.OnCancelListener; -import android.content.ComponentName; -import android.content.ServiceConnection; import android.content.Intent; -import android.content.Context; import com.bitgo.randombytes.RandomBytesPackage; import com.BV.LinearGradient.LinearGradientPackage; import com.centaurwarchief.smslistener.SmsListener; import com.github.yamill.orientation.OrientationPackage; - -import android.util.Log; - import java.util.Arrays; import java.util.List; import java.util.Properties; -import java.io.File; import com.lwansbrough.RCTCamera.*; import com.i18n.reactnativei18n.ReactNativeI18n; -import io.realm.react.RealmReactPackage; -import android.content.Intent; import android.content.res.Configuration; public class MainActivity extends ReactActivity { private static final String TAG = "MainActivity"; - /** - * Incoming message handler. Calls to its binder are sequential! - */ - protected final IncomingHandler handler = new IncomingHandler(); - - /** Flag indicating if the service is bound. */ - protected boolean isBound; - - /** Sends messages to the service. */ - protected Messenger serviceMessenger = null; - - /** Receives messages from the service. */ - protected Messenger clientMessenger = new Messenger(handler); - - class IncomingHandler extends Handler { - - @Override - public void handleMessage(Message message) { - boolean isClaimed = false; - Log.d(TAG, "!!!!!!!!!!!!!! Received Service Message !!!!!!!!!!!!!!"); - super.handleMessage(message); - } - } - - protected ServiceConnection serviceConnection = new ServiceConnection() { - - public void onServiceConnected(ComponentName className, IBinder service) { - // This is called when the connection with the service has been - // established, giving us the object we can use to - // interact with the service. We are communicating with the - // service using a Messenger, so here we get a client-side - // representation of that from the raw IBinder object. - serviceMessenger = new Messenger(service); - isBound = true; - onConnected(); - } - - public void onServiceDisconnected(ComponentName className) { - // This is called when the connection with the service has been - // unexpectedly disconnected -- that is, its process crashed. - serviceMessenger = null; - isBound = false; - Log.d(TAG, "!!!!!!!!!!!!!! Geth Service Disconnected !!!!!!!!!!!!!!"); - } - }; - - protected void onConnected() { - Log.d(TAG, "!!!!!!!!!!!!!! Geth Service Connected !!!!!!!!!!!!!!"); - } - protected void startStatus() { // Required because of crazy APN settings redirecting localhost (found in GB) Properties properties = System.getProperties(); @@ -129,25 +67,11 @@ public class MainActivity extends ReactActivity { }).create(); dialog.show(); } - Intent intent = new Intent(this, GethService.class); - if (!GethService.isRunning()) { - startService(intent); - } - if (serviceConnection != null && GethService.isRunning()) { - bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); - } - } @Override protected void onDestroy() { super.onDestroy(); - try { - unbindService(serviceConnection); - } - catch (Throwable t) { - Log.e(TAG, "Failed to unbind from the geth service", t); - } } /** @@ -184,7 +108,8 @@ public class MainActivity extends ReactActivity { new LinearGradientPackage(), new RCTCameraPackage(), new SmsListener(this), - new OrientationPackage(this) + new OrientationPackage(this), + new GethPackage() ); } diff --git a/android/app/src/main/java/com/statusim/geth/module/GethModule.java b/android/app/src/main/java/com/statusim/geth/module/GethModule.java new file mode 100644 index 0000000000..a4bb3e12d0 --- /dev/null +++ b/android/app/src/main/java/com/statusim/geth/module/GethModule.java @@ -0,0 +1,209 @@ +package com.statusim.geth.module; + +import android.app.Activity; +import android.os.Bundle; +import android.os.Message; +import com.facebook.react.bridge.*; +import com.statusim.geth.service.ConnectorHandler; +import com.statusim.geth.service.GethConnector; +import com.statusim.geth.service.GethMessages; +import com.statusim.geth.service.GethService; + +import java.util.HashMap; +import java.util.UUID; + +public class GethModule extends ReactContextBaseJavaModule implements LifecycleEventListener, ConnectorHandler { + + protected GethConnector geth = null; + protected String handlerIdentifier = createIdentifier(); + + protected HashMap startNodeCallbacks = new HashMap<>(); + protected HashMap createAccountCallbacks = new HashMap<>(); + protected HashMap addAccountCallbacks = new HashMap<>(); + protected HashMap unlockAccountCallbacks = new HashMap<>(); + + + public GethModule(ReactApplicationContext reactContext) { + super(reactContext); + reactContext.addLifecycleEventListener(this); + } + + @Override + public String getName() { + return "Geth"; + } + + @Override + public void onHostResume() { // Actvity `onResume` + + Activity currentActivity = getCurrentActivity(); + + if (currentActivity == null) { + return; + } + if (geth == null) { + geth = new GethConnector(currentActivity, GethService.class); + geth.registerHandler(this); + } + geth.bindService(); + } + + @Override + public void onHostPause() { // Actvity `onPause` + + if (geth != null) { + geth.unbindService(); + } + } + + @Override + public void onHostDestroy() { // Actvity `onDestroy` + + if (geth != null) { + geth.stopNode(null); + } + } + + @Override + public String getID() { + + return handlerIdentifier; + } + + @Override + public void onConnectorConnected() { + } + + @Override + public void onConnectorDisconnected() { + } + + @Override + public boolean handleMessage(Message message) { + + boolean isClaimed = true; + Bundle data = message.getData(); + String callbackIdentifier = data.getString(GethConnector.CALLBACK_IDENTIFIER); + Callback callback = null; + switch (message.what) { + case GethMessages.MSG_NODE_STARTED: + callback = startNodeCallbacks.remove(callbackIdentifier); + if (callback != null) { + callback.invoke(null); + } + break; + case GethMessages.MSG_NODE_STOPPED: + break; + case GethMessages.MSG_ACCOUNT_CREATED: + callback = createAccountCallbacks.remove(callbackIdentifier); + if (callback != null) { + callback.invoke(null, "{ \"address\": \"" + data.getString("address") + "\"}"); + } + break; + case GethMessages.MSG_ACCOUNT_ADDED: + callback = addAccountCallbacks.remove(callbackIdentifier); + if (callback != null) { + callback.invoke(null, "{ \"address\": \"" + data.getString("address") + "\"}"); + } + break; + case GethMessages.MSG_ACCOUNT_UNLOCKED: + callback = unlockAccountCallbacks.remove(callbackIdentifier); + if (callback != null) { + callback.invoke(null, "{ \"result\": \"" + data.getString("result") + "\"}"); + } + break; + default: + isClaimed = false; + } + + return isClaimed; + } + + @ReactMethod + public void startNode(Callback callback) { + + Activity currentActivity = getCurrentActivity(); + + if (currentActivity == null) { + callback.invoke("Activity doesn't exist"); + return; + } + + if (geth == null) { + callback.invoke("Geth connector is null"); + return; + } + + String callbackIdentifier = createIdentifier(); + startNodeCallbacks.put(callbackIdentifier, callback); + + geth.startNode(callbackIdentifier); + } + + @ReactMethod + public void unlockAccount(String address, String password, Callback callback) { + + Activity currentActivity = getCurrentActivity(); + + if (currentActivity == null) { + callback.invoke("Activity doesn't exist"); + return; + } + + if (geth == null) { + callback.invoke("Geth connector is null"); + return; + } + + String callbackIdentifier = createIdentifier(); + unlockAccountCallbacks.put(callbackIdentifier, callback); + + geth.unlockAccount(callbackIdentifier, address, password); + } + + @ReactMethod + public void createAccount(Callback callback) { + + Activity currentActivity = getCurrentActivity(); + + if (currentActivity == null) { + callback.invoke("Activity doesn't exist"); + return; + } + + if (geth == null) { + callback.invoke("Geth connector is null"); + return; + } + + String callbackIdentifier = createIdentifier(); + createAccountCallbacks.put(callbackIdentifier, callback); + + geth.createAccount(callbackIdentifier); + } + + @ReactMethod + public void addAccount(String privateKey, Callback callback) { + + Activity currentActivity = getCurrentActivity(); + + if (currentActivity == null) { + callback.invoke("Activity doesn't exist"); + return; + } + + if (geth == null) { + callback.invoke("Geth connector is null"); + return; + } + + String callbackIdentifier = createIdentifier(); + addAccountCallbacks.put(callbackIdentifier, callback); + geth.addAccount(callbackIdentifier, privateKey); + } + + protected String createIdentifier() { + return UUID.randomUUID().toString(); + } + +} \ No newline at end of file diff --git a/android/app/src/main/java/com/statusim/geth/module/GethPackage.java b/android/app/src/main/java/com/statusim/geth/module/GethPackage.java new file mode 100644 index 0000000000..d7dc02df6f --- /dev/null +++ b/android/app/src/main/java/com/statusim/geth/module/GethPackage.java @@ -0,0 +1,33 @@ +package com.statusim.geth.module; + +import com.facebook.react.ReactPackage; +import com.facebook.react.bridge.JavaScriptModule; +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.uimanager.ViewManager; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class GethPackage implements ReactPackage { + + @Override + public List createNativeModules(ReactApplicationContext reactContext) { + List modules = new ArrayList<>(); + + modules.add(new GethModule(reactContext)); + + return modules; + } + + @Override + public List> createJSModules() { + return Collections.emptyList(); + } + + @Override + public List createViewManagers(ReactApplicationContext reactContext) { + return Collections.emptyList(); + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/statusim/geth/service/ConnectorHandler.java b/android/app/src/main/java/com/statusim/geth/service/ConnectorHandler.java new file mode 100644 index 0000000000..0df2737a97 --- /dev/null +++ b/android/app/src/main/java/com/statusim/geth/service/ConnectorHandler.java @@ -0,0 +1,12 @@ +package com.statusim.geth.service; + + +import android.os.Message; + +public interface ConnectorHandler { + + boolean handleMessage(Message message); + void onConnectorConnected(); + void onConnectorDisconnected(); + String getID(); +} \ No newline at end of file diff --git a/android/app/src/main/java/com/statusim/geth/service/GethConnector.java b/android/app/src/main/java/com/statusim/geth/service/GethConnector.java new file mode 100644 index 0000000000..73a1fd74d4 --- /dev/null +++ b/android/app/src/main/java/com/statusim/geth/service/GethConnector.java @@ -0,0 +1,107 @@ +package com.statusim.geth.service; + + +import android.content.Context; +import android.os.Bundle; +import android.os.Message; +import android.os.RemoteException; +import android.util.Log; + +public class GethConnector extends ServiceConnector { + + private static final String TAG = "GethConnector"; + + public static final String CALLBACK_IDENTIFIER = "callbackIdentifier"; + + public GethConnector(Context context, Class serviceClass) { + + super(context, serviceClass); + } + + public void startNode(String callbackIdentifier) { + + if (checkBound()) { + Message msg = createMessage(callbackIdentifier, GethMessages.MSG_START_NODE, null); + try { + serviceMessenger.send(msg); + } catch (RemoteException e) { + Log.e(TAG, "Exception sending message(startNode) to service: ", e); + } + } + } + + public void stopNode(String callbackIdentifier) { + + if (checkBound()) { + Message msg = createMessage(callbackIdentifier, GethMessages.MSG_STOP_NODE, null); + try { + serviceMessenger.send(msg); + } catch (RemoteException e) { + Log.e(TAG, "Exception sending message(stopNode) to service: ", e); + } + } + } + + public void unlockAccount(String callbackIdentifier, String address, String password) { + + if (checkBound()) { + Bundle data = new Bundle(); + data.putString("address", address); + data.putString("password", password); + Message msg = createMessage(callbackIdentifier, GethMessages.MSG_UNLOCK_ACCOUNT, data); + try { + serviceMessenger.send(msg); + } catch (RemoteException e) { + Log.e(TAG, "Exception sending message(unlockAccount) to service: ", e); + } + } + } + + public void createAccount(String callbackIdentifier) { + + if (checkBound()) { + Message msg = createMessage(callbackIdentifier, GethMessages.MSG_CREATE_ACCOUNT, null); + try { + serviceMessenger.send(msg); + } catch (RemoteException e) { + Log.e(TAG, "Exception sending message(createAccount) to service: ", e); + } + } + } + + public void addAccount(String callbackIdentifier, String privateKey) { + + if (checkBound()) { + Bundle data = new Bundle(); + data.putString("privateKey", privateKey); + Message msg = createMessage(callbackIdentifier, GethMessages.MSG_ADD_ACCOUNT, data); + try { + serviceMessenger.send(msg); + } catch (RemoteException e) { + Log.e(TAG, "Exception sending message(addAccount) to service: ", e); + } + } + } + + + protected boolean checkBound() { + + if (!isBound) { + Log.d(TAG, "GethConnector not bound!"); + return false; + } + return true; + } + + protected Message createMessage(String callbackIdentifier, int idMessage, Bundle data) { + + Message msg = Message.obtain(null, idMessage, 0, 0); + msg.replyTo = clientMessenger; + if (data == null) { + data = new Bundle(); + } + data.putString(CALLBACK_IDENTIFIER, callbackIdentifier); + msg.setData(data); + return msg; + } +} diff --git a/android/app/src/main/java/com/statusim/geth/service/GethMessages.java b/android/app/src/main/java/com/statusim/geth/service/GethMessages.java new file mode 100644 index 0000000000..080725bca2 --- /dev/null +++ b/android/app/src/main/java/com/statusim/geth/service/GethMessages.java @@ -0,0 +1,56 @@ +package com.statusim.geth.service; + + +public class GethMessages { + + /** + * Start the node + */ + public static final int MSG_START_NODE = 1; + + /** + * Node started event + */ + public static final int MSG_NODE_STARTED = 2; + + /** + * Stop the node + */ + public static final int MSG_STOP_NODE = 3; + + /** + * Node stopped event + */ + public static final int MSG_NODE_STOPPED = 4; + + /** + * Unlock an account + */ + public static final int MSG_UNLOCK_ACCOUNT = 5; + + /** + * Account unlocked event + */ + public static final int MSG_ACCOUNT_UNLOCKED = 6; + + /** + * Create an account + */ + public static final int MSG_CREATE_ACCOUNT = 7; + + /** + * Account created event + */ + public static final int MSG_ACCOUNT_CREATED = 8; + + /** + * Add an account + */ + public static final int MSG_ADD_ACCOUNT = 9; + + /** + * Account added event + */ + public static final int MSG_ACCOUNT_ADDED = 10; + +} diff --git a/android/app/src/main/java/com/statusim/geth/service/GethService.java b/android/app/src/main/java/com/statusim/geth/service/GethService.java new file mode 100644 index 0000000000..638c4c3657 --- /dev/null +++ b/android/app/src/main/java/com/statusim/geth/service/GethService.java @@ -0,0 +1,227 @@ +package com.statusim.geth.service; + +import android.app.Service; +import android.content.Intent; +import android.os.*; +import android.support.annotation.Nullable; +import android.util.Log; + +import java.lang.ref.WeakReference; + +import com.github.ethereum.go_ethereum.Statusgo; + +import java.io.File; + +public class GethService extends Service { + + private static final String TAG = "GethService"; + + private static boolean isGethStarted = false; + private static boolean isGethInitialized = false; + private final Handler handler = new Handler(); + + static class IncomingHandler extends Handler { + + private final WeakReference service; + + IncomingHandler(GethService service) { + + this.service = new WeakReference(service); + } + + @Override + public void handleMessage(Message message) { + + GethService service = this.service.get(); + if (service != null) { + if (!service.handleMessage(message)) { + super.handleMessage(message); + } + } + } + } + + final Messenger serviceMessenger = new Messenger(new IncomingHandler(this)); + + + public static void signalEvent(String jsonEvent) { + System.out.println("\n\n\nIT WOOOOOORKS1111!!!!!!\n\n\n"); + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return serviceMessenger.getBinder(); + } + + @Override + public void onCreate() { + super.onCreate(); + System.loadLibrary("statusgoraw"); + System.loadLibrary("statusgo"); + } + + @Override + public void onDestroy() { + super.onDestroy(); + //TODO: stop geth + stopNode(null); + isGethStarted = false; + isGethInitialized = false; + Log.d(TAG, "Geth Service stopped !"); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + return Service.START_STICKY; + } + + protected boolean handleMessage(Message message) { + switch (message.what) { + + case GethMessages.MSG_START_NODE: + startNode(message); + break; + + case GethMessages.MSG_STOP_NODE: + stopNode(message); + break; + + case GethMessages.MSG_CREATE_ACCOUNT: + createAccount(message); + break; + + case GethMessages.MSG_ADD_ACCOUNT: + addAccount(message); + break; + + case GethMessages.MSG_UNLOCK_ACCOUNT: + unlockAccount(message); + break; + + default: + return false; + } + + return true; + } + + protected void startNode(Message message) { + if (!isGethInitialized) { + isGethInitialized = true; + new StartTask(message).execute(); + } + } + + protected class StartTask extends AsyncTask { + + protected Message message; + + public StartTask(Message message) { + this.message = message; + } + + protected Void doInBackground(Void... args) { + startGeth(); + return null; + } + + protected void onPostExecute(Void results) { + onGethStarted(message); + } + } + + protected void onGethStarted(Message message) { + Log.d(TAG, "Geth Service started"); + isGethStarted = true; + + sendReply(message, GethMessages.MSG_NODE_STARTED, null); + } + + protected void startGeth() { + Log.d(TAG, "Starting background Geth Service"); + + File extStore = Environment.getExternalStorageDirectory(); + + final String dataFolder = extStore.exists() ? + extStore.getAbsolutePath() : + getApplicationInfo().dataDir; + + new Thread(new Runnable() { + public void run() { + + Statusgo.doStartNode(dataFolder); + } + }).start(); + } + + protected void stopNode(Message message) { + // TODO: stop node + + sendReply(message, GethMessages.MSG_NODE_STOPPED, null); + } + + protected void createAccount(Message message) { + Bundle data = message.getData(); + String password = data.getString("password"); + // TODO: remove second argument + String address = Statusgo.doCreateAccount(password, ""); + Log.d(TAG, "Created account: " + address); + + Bundle replyData = new Bundle(); + replyData.putString("address", address); + sendReply(message, GethMessages.MSG_ACCOUNT_CREATED, replyData); + } + + protected void addAccount(Message message) { + Bundle data = message.getData(); + String privateKey = data.getString("privateKey"); + String password = data.getString("password"); + // TODO: add account + //String address = Statusgo.doAddAccount(privateKey, password); + String address = "added account address"; + Log.d(TAG, "Added account: " + address); + + Bundle replyData = new Bundle(); + replyData.putString("address", address); + sendReply(message, GethMessages.MSG_ACCOUNT_ADDED, replyData); + } + + protected void unlockAccount(Message message) { + Bundle data = message.getData(); + String address = data.getString("address"); + String password = data.getString("password"); + // TODO: remove third argument + String result = Statusgo.doUnlockAccount(address, password, 0); + Log.d(TAG, "Unlocked account: " + result); + + Bundle replyData = new Bundle(); + replyData.putString("result", result); + sendReply(message, GethMessages.MSG_ACCOUNT_UNLOCKED, replyData); + } + + public static boolean isRunning() { + return isGethInitialized; + } + + protected void sendReply(Message message, int replyIdMessage, Bundle replyData) { + + if (message == null) { + return; + } + Message replyMessage = Message.obtain(null, replyIdMessage, 0, 0, message.obj); + if (replyData == null) { + replyData = new Bundle(); + } + Bundle data = message.getData(); + String callbackIdentifier = data.getString("callbackIdentifier"); + replyData.putString("callbackIdentifier", callbackIdentifier); + replyMessage.setData(replyData); + + try { + message.replyTo.send(replyMessage); + } catch (RemoteException e) { + Log.e(TAG, "Exception sending message id: " + replyIdMessage, e); + } + } +} diff --git a/android/app/src/main/java/com/statusim/geth/service/ServiceConnector.java b/android/app/src/main/java/com/statusim/geth/service/ServiceConnector.java new file mode 100644 index 0000000000..1c70e92992 --- /dev/null +++ b/android/app/src/main/java/com/statusim/geth/service/ServiceConnector.java @@ -0,0 +1,149 @@ +package com.statusim.geth.service; + + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.*; + +import java.util.ArrayList; + +public class ServiceConnector { + + private static final String TAG = "ServiceConnector"; + + /** + * Incoming message handler. Calls to its binder are sequential! + */ + protected final IncomingHandler handler; + + /** + * Handler thread to avoid running on the main UI thread + */ + protected final HandlerThread handlerThread; + + /** Context of the activity from which this connector was launched */ + protected Context context; + + /** The class of the service we want to connect to */ + protected Class serviceClass; + + /** Flag indicating if the service is bound. */ + protected boolean isBound; + + /** Sends messages to the service. */ + protected Messenger serviceMessenger = null; + + /** Receives messages from the service. */ + protected Messenger clientMessenger = null; + + protected ArrayList handlers = new ArrayList<>(); + + /** Handles incoming messages from service. */ + class IncomingHandler extends Handler { + + public IncomingHandler(HandlerThread thread) { + + super(thread.getLooper()); + } + + @Override + public void handleMessage(Message message) { + + boolean isClaimed = false; + if (message.obj != null) { + String identifier = ((Bundle) message.obj).getString("identifier"); + if (identifier != null) { + + for (ConnectorHandler handler : handlers) { + if (identifier.equals(handler.getID())) { + isClaimed = handler.handleMessage(message); + } + } + } + } + if (!isClaimed) { + super.handleMessage(message); + } + } + } + + /** + * Class for interacting with the main interface of the service. + */ + protected ServiceConnection serviceConnection = new ServiceConnection() { + + public void onServiceConnected(ComponentName className, IBinder service) { + + // This is called when the connection with the service has been + // established, giving us the object we can use to + // interact with the service. We are communicating with the + // service using a Messenger, so here we get a client-side + // representation of that from the raw IBinder object. + serviceMessenger = new Messenger(service); + isBound = true; + for (ConnectorHandler handler: handlers) { + handler.onConnectorConnected(); + } + } + + public void onServiceDisconnected(ComponentName className) { + + // This is called when the connection with the service has been + // unexpectedly disconnected -- that is, its process crashed. + serviceMessenger = null; + isBound = false; + for (ConnectorHandler handler: handlers) { + handler.onConnectorDisconnected(); + } + } + }; + + public ServiceConnector(Context context, Class serviceClass) { + + this.context = context; + this.serviceClass = serviceClass; + handlerThread = new HandlerThread("HandlerThread"); + handlerThread.start(); + handler = new IncomingHandler(handlerThread); + clientMessenger = new Messenger(handler); + } + + /** Bind to the service */ + public boolean bindService() { + + if (serviceConnection != null) { + Intent intent = new Intent(context, serviceClass); + context.getApplicationContext().startService(intent); + return context.getApplicationContext().bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); + } else { + return false; + } + } + + /** Unbind from the service */ + public void unbindService() { + + if (isBound && serviceConnection != null) { + context.getApplicationContext().unbindService(serviceConnection); + isBound = false; +/* + Intent intent = new Intent(context, serviceClass); + context.getApplicationContext().stopService(intent); +*/ + } + } + + public void registerHandler(ConnectorHandler handler) { + + if (!handlers.contains(handler)) { + handlers.add(handler); + } + } + + public void removeHandler(ConnectorHandler handler) { + + handlers.remove(handler); + } +} diff --git a/src/status_im/components/react.cljs b/src/status_im/components/react.cljs index f931ce4e00..f180f463c2 100644 --- a/src/status_im/components/react.cljs +++ b/src/status_im/components/react.cljs @@ -4,6 +4,7 @@ [status-im.utils.utils :as u])) (def react (u/require "react-native")) +(def native-modules (.-NativeModules react)) (defn get-react-property [name] (aget react name)) @@ -78,3 +79,5 @@ (def dismiss-keyboard! (u/require "dismissKeyboard")) (def device-event-emitter (.-DeviceEventEmitter react)) (def orientation (u/require "react-native-orientation")) + +(def geth (.-Geth native-modules)) From ec9cfe8f8c32d73f04a3cb37a788b8f156f6b212 Mon Sep 17 00:00:00 2001 From: Adrian Tiberius Date: Thu, 30 Jun 2016 13:37:36 +0300 Subject: [PATCH 02/10] changed add account flow to use new binding system --- android/app/build.gradle | 4 +- android/app/src/main/AndroidManifest.xml | 3 +- .../com/statusim/geth/module/GethModule.java | 24 +++-- .../statusim/geth/service/GethConnector.java | 11 ++- .../statusim/geth/service/GethMessages.java | 4 +- .../statusim/geth/service/GethService.java | 88 ++++++++++++------- .../geth/service/ServiceConnector.java | 14 +-- src/status_im/android/core.cljs | 4 +- src/status_im/chat/handlers.cljs | 8 ++ src/status_im/handlers.cljs | 6 ++ src/status_im/protocol/handlers.cljs | 4 +- 11 files changed, 113 insertions(+), 57 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 301a07656c..c60d4eb2d1 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -132,8 +132,8 @@ dependencies { compile project(':ReactNativeAndroidSmsListener') compile project(':react-native-camera') compile project(':react-native-orientation') -// compile(name:'geth', ext:'aar') - compile(group: 'status-im', name: 'status-go', version: '0.1.0-test-callback', ext: 'aar') + compile(name:'statusgo-android-16', ext:'aar') + //compile(group: 'status-im', name: 'status-go', version: '0.1.0-test-callback', ext: 'aar') compile fileTree(dir: "node_modules/realm/android/libs", include: ["*.jar"]) } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index a7b7a31725..05008651d2 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -25,8 +25,7 @@ + android:exported="true"/> diff --git a/android/app/src/main/java/com/statusim/geth/module/GethModule.java b/android/app/src/main/java/com/statusim/geth/module/GethModule.java index a4bb3e12d0..058ab03667 100644 --- a/android/app/src/main/java/com/statusim/geth/module/GethModule.java +++ b/android/app/src/main/java/com/statusim/geth/module/GethModule.java @@ -8,12 +8,15 @@ import com.statusim.geth.service.ConnectorHandler; import com.statusim.geth.service.GethConnector; import com.statusim.geth.service.GethMessages; import com.statusim.geth.service.GethService; +import android.util.Log; import java.util.HashMap; import java.util.UUID; public class GethModule extends ReactContextBaseJavaModule implements LifecycleEventListener, ConnectorHandler { + private static final String TAG = "GethModule"; + protected GethConnector geth = null; protected String handlerIdentifier = createIdentifier(); @@ -81,15 +84,20 @@ public class GethModule extends ReactContextBaseJavaModule implements LifecycleE @Override public boolean handleMessage(Message message) { + Log.d(TAG, "Received message: " + message.toString()); boolean isClaimed = true; Bundle data = message.getData(); String callbackIdentifier = data.getString(GethConnector.CALLBACK_IDENTIFIER); + Log.d(TAG, "callback identifier: " + callbackIdentifier); Callback callback = null; switch (message.what) { case GethMessages.MSG_NODE_STARTED: + Log.d(TAG, "handle startNodeCallbacks size: " + startNodeCallbacks.size()); callback = startNodeCallbacks.remove(callbackIdentifier); if (callback != null) { - callback.invoke(null); + callback.invoke(true); + } else { + Log.d(TAG, "Could not find callback: " + callbackIdentifier); } break; case GethMessages.MSG_NODE_STOPPED: @@ -97,7 +105,7 @@ public class GethModule extends ReactContextBaseJavaModule implements LifecycleE case GethMessages.MSG_ACCOUNT_CREATED: callback = createAccountCallbacks.remove(callbackIdentifier); if (callback != null) { - callback.invoke(null, "{ \"address\": \"" + data.getString("address") + "\"}"); + callback.invoke(data.getString("data")); } break; case GethMessages.MSG_ACCOUNT_ADDED: @@ -106,7 +114,7 @@ public class GethModule extends ReactContextBaseJavaModule implements LifecycleE callback.invoke(null, "{ \"address\": \"" + data.getString("address") + "\"}"); } break; - case GethMessages.MSG_ACCOUNT_UNLOCKED: + case GethMessages.MSG_LOGGED_IN: callback = unlockAccountCallbacks.remove(callbackIdentifier); if (callback != null) { callback.invoke(null, "{ \"result\": \"" + data.getString("result") + "\"}"); @@ -135,13 +143,15 @@ public class GethModule extends ReactContextBaseJavaModule implements LifecycleE } String callbackIdentifier = createIdentifier(); + Log.d(TAG, "Created callback identifier: " + callbackIdentifier); startNodeCallbacks.put(callbackIdentifier, callback); + Log.d(TAG, "startNodeCallbacks size: " + startNodeCallbacks.size()); geth.startNode(callbackIdentifier); } @ReactMethod - public void unlockAccount(String address, String password, Callback callback) { + public void login(String address, String password, Callback callback) { Activity currentActivity = getCurrentActivity(); @@ -158,11 +168,11 @@ public class GethModule extends ReactContextBaseJavaModule implements LifecycleE String callbackIdentifier = createIdentifier(); unlockAccountCallbacks.put(callbackIdentifier, callback); - geth.unlockAccount(callbackIdentifier, address, password); + geth.login(callbackIdentifier, address, password); } @ReactMethod - public void createAccount(Callback callback) { + public void createAccount(String password, Callback callback) { Activity currentActivity = getCurrentActivity(); @@ -179,7 +189,7 @@ public class GethModule extends ReactContextBaseJavaModule implements LifecycleE String callbackIdentifier = createIdentifier(); createAccountCallbacks.put(callbackIdentifier, callback); - geth.createAccount(callbackIdentifier); + geth.createAccount(callbackIdentifier, password); } @ReactMethod diff --git a/android/app/src/main/java/com/statusim/geth/service/GethConnector.java b/android/app/src/main/java/com/statusim/geth/service/GethConnector.java index 73a1fd74d4..7083dff2d5 100644 --- a/android/app/src/main/java/com/statusim/geth/service/GethConnector.java +++ b/android/app/src/main/java/com/statusim/geth/service/GethConnector.java @@ -42,13 +42,13 @@ public class GethConnector extends ServiceConnector { } } - public void unlockAccount(String callbackIdentifier, String address, String password) { + public void login(String callbackIdentifier, String address, String password) { if (checkBound()) { Bundle data = new Bundle(); data.putString("address", address); data.putString("password", password); - Message msg = createMessage(callbackIdentifier, GethMessages.MSG_UNLOCK_ACCOUNT, data); + Message msg = createMessage(callbackIdentifier, GethMessages.MSG_LOGIN, data); try { serviceMessenger.send(msg); } catch (RemoteException e) { @@ -57,10 +57,12 @@ public class GethConnector extends ServiceConnector { } } - public void createAccount(String callbackIdentifier) { + public void createAccount(String callbackIdentifier, String password) { if (checkBound()) { - Message msg = createMessage(callbackIdentifier, GethMessages.MSG_CREATE_ACCOUNT, null); + Bundle data = new Bundle(); + data.putString("password", password); + Message msg = createMessage(callbackIdentifier, GethMessages.MSG_CREATE_ACCOUNT, data); try { serviceMessenger.send(msg); } catch (RemoteException e) { @@ -95,6 +97,7 @@ public class GethConnector extends ServiceConnector { protected Message createMessage(String callbackIdentifier, int idMessage, Bundle data) { + Log.d(TAG, "Client messenger: " + clientMessenger.toString()); Message msg = Message.obtain(null, idMessage, 0, 0); msg.replyTo = clientMessenger; if (data == null) { diff --git a/android/app/src/main/java/com/statusim/geth/service/GethMessages.java b/android/app/src/main/java/com/statusim/geth/service/GethMessages.java index 080725bca2..f6c3e24737 100644 --- a/android/app/src/main/java/com/statusim/geth/service/GethMessages.java +++ b/android/app/src/main/java/com/statusim/geth/service/GethMessages.java @@ -26,12 +26,12 @@ public class GethMessages { /** * Unlock an account */ - public static final int MSG_UNLOCK_ACCOUNT = 5; + public static final int MSG_LOGIN = 5; /** * Account unlocked event */ - public static final int MSG_ACCOUNT_UNLOCKED = 6; + public static final int MSG_LOGGED_IN = 6; /** * Create an account diff --git a/android/app/src/main/java/com/statusim/geth/service/GethService.java b/android/app/src/main/java/com/statusim/geth/service/GethService.java index 638c4c3657..8a62fcc55f 100644 --- a/android/app/src/main/java/com/statusim/geth/service/GethService.java +++ b/android/app/src/main/java/com/statusim/geth/service/GethService.java @@ -20,6 +20,8 @@ public class GethService extends Service { private static boolean isGethInitialized = false; private final Handler handler = new Handler(); + private static String dataFolder; + static class IncomingHandler extends Handler { private final WeakReference service; @@ -80,6 +82,7 @@ public class GethService extends Service { switch (message.what) { case GethMessages.MSG_START_NODE: + Log.d(TAG, "Received start node message." + message.toString()); startNode(message); break; @@ -95,8 +98,8 @@ public class GethService extends Service { addAccount(message); break; - case GethMessages.MSG_UNLOCK_ACCOUNT: - unlockAccount(message); + case GethMessages.MSG_LOGIN: + login(message); break; default: @@ -109,16 +112,22 @@ public class GethService extends Service { protected void startNode(Message message) { if (!isGethInitialized) { isGethInitialized = true; - new StartTask(message).execute(); + Log.d(TAG, "Client messenger1: " + message.replyTo.toString()); + Bundle data = message.getData(); + String callbackIdentifier = data.getString(GethConnector.CALLBACK_IDENTIFIER); + Log.d(TAG, "Callback identifier: " + callbackIdentifier); + new StartTask(message.replyTo, callbackIdentifier).execute(); } } protected class StartTask extends AsyncTask { - protected Message message; + protected String callbackIdentifier; + protected Messenger messenger; - public StartTask(Message message) { - this.message = message; + public StartTask(Messenger messenger, String callbackIdentifier) { + this.messenger = messenger; + this.callbackIdentifier = callbackIdentifier; } protected Void doInBackground(Void... args) { @@ -127,30 +136,41 @@ public class GethService extends Service { } protected void onPostExecute(Void results) { - onGethStarted(message); + onGethStarted(messenger, callbackIdentifier); } } - protected void onGethStarted(Message message) { + protected void onGethStarted(Messenger messenger, String callbackIdentifier) { Log.d(TAG, "Geth Service started"); isGethStarted = true; - - sendReply(message, GethMessages.MSG_NODE_STARTED, null); + Message replyMessage = Message.obtain(null, GethMessages.MSG_NODE_STARTED, 0, 0, null); + Bundle replyData = new Bundle(); + Log.d(TAG, "Callback identifier: " + callbackIdentifier); + replyData.putString(GethConnector.CALLBACK_IDENTIFIER, callbackIdentifier); + replyMessage.setData(replyData); + sendReply(messenger, replyMessage); } protected void startGeth() { - Log.d(TAG, "Starting background Geth Service"); + File extStore = Environment.getExternalStorageDirectory(); - final String dataFolder = extStore.exists() ? - extStore.getAbsolutePath() : - getApplicationInfo().dataDir; + dataFolder = extStore.exists() ? + extStore.getAbsolutePath() + "/ethereum" : + getApplicationInfo().dataDir + "/ethereum"; + Log.d(TAG, "Starting background Geth Service in folder: " + dataFolder); + try { + final File newFile = new File(dataFolder); + newFile.mkdir(); + } catch (Exception e) { + Log.e(TAG, "error making folder: " + dataFolder, e); + } new Thread(new Runnable() { public void run() { - Statusgo.doStartNode(dataFolder); + Statusgo.StartNode(dataFolder); } }).start(); } @@ -158,19 +178,20 @@ public class GethService extends Service { protected void stopNode(Message message) { // TODO: stop node - sendReply(message, GethMessages.MSG_NODE_STOPPED, null); + createAndSendReply(message, GethMessages.MSG_NODE_STOPPED, null); } protected void createAccount(Message message) { Bundle data = message.getData(); String password = data.getString("password"); // TODO: remove second argument - String address = Statusgo.doCreateAccount(password, ""); - Log.d(TAG, "Created account: " + address); + Log.d(TAG, "Creating account: " + password + " - " + dataFolder); + String jsonData = Statusgo.CreateAccount(password, dataFolder); + Log.d(TAG, "Created account: " + jsonData); Bundle replyData = new Bundle(); - replyData.putString("address", address); - sendReply(message, GethMessages.MSG_ACCOUNT_CREATED, replyData); + replyData.putString("data", jsonData); + createAndSendReply(message, GethMessages.MSG_ACCOUNT_CREATED, replyData); } protected void addAccount(Message message) { @@ -184,27 +205,27 @@ public class GethService extends Service { Bundle replyData = new Bundle(); replyData.putString("address", address); - sendReply(message, GethMessages.MSG_ACCOUNT_ADDED, replyData); + createAndSendReply(message, GethMessages.MSG_ACCOUNT_ADDED, replyData); } - protected void unlockAccount(Message message) { + protected void login(Message message) { Bundle data = message.getData(); String address = data.getString("address"); String password = data.getString("password"); // TODO: remove third argument - String result = Statusgo.doUnlockAccount(address, password, 0); + String result = Statusgo.Login(address, password); Log.d(TAG, "Unlocked account: " + result); Bundle replyData = new Bundle(); replyData.putString("result", result); - sendReply(message, GethMessages.MSG_ACCOUNT_UNLOCKED, replyData); + createAndSendReply(message, GethMessages.MSG_LOGGED_IN, replyData); } public static boolean isRunning() { return isGethInitialized; } - protected void sendReply(Message message, int replyIdMessage, Bundle replyData) { + protected void createAndSendReply(Message message, int replyIdMessage, Bundle replyData) { if (message == null) { return; @@ -214,14 +235,21 @@ public class GethService extends Service { replyData = new Bundle(); } Bundle data = message.getData(); - String callbackIdentifier = data.getString("callbackIdentifier"); - replyData.putString("callbackIdentifier", callbackIdentifier); + String callbackIdentifier = data.getString(GethConnector.CALLBACK_IDENTIFIER); + Log.d(TAG, "Callback identifier: " + callbackIdentifier); + replyData.putString(GethConnector.CALLBACK_IDENTIFIER, callbackIdentifier); replyMessage.setData(replyData); + sendReply(message.replyTo, replyMessage); + } + + protected void sendReply(Messenger messenger, Message message) { try { - message.replyTo.send(replyMessage); - } catch (RemoteException e) { - Log.e(TAG, "Exception sending message id: " + replyIdMessage, e); + messenger.send(message); + + } catch (Exception e) { + + Log.e(TAG, "Exception sending message id: " + message.what, e); } } } diff --git a/android/app/src/main/java/com/statusim/geth/service/ServiceConnector.java b/android/app/src/main/java/com/statusim/geth/service/ServiceConnector.java index 1c70e92992..f20e1fcf66 100644 --- a/android/app/src/main/java/com/statusim/geth/service/ServiceConnector.java +++ b/android/app/src/main/java/com/statusim/geth/service/ServiceConnector.java @@ -52,17 +52,17 @@ public class ServiceConnector { public void handleMessage(Message message) { boolean isClaimed = false; - if (message.obj != null) { - String identifier = ((Bundle) message.obj).getString("identifier"); - if (identifier != null) { + //if (message.obj != null) { + // String identifier = ((Bundle) message.obj).getString("identifier"); + //if (identifier != null) { for (ConnectorHandler handler : handlers) { - if (identifier.equals(handler.getID())) { + // if (identifier.equals(handler.getID())) { isClaimed = handler.handleMessage(message); - } + // } } - } - } + // } + //} if (!isClaimed) { super.handleMessage(message); } diff --git a/src/status_im/android/core.cljs b/src/status_im/android/core.cljs index 38b60a5b77..db4c13c2e0 100644 --- a/src/status_im/android/core.cljs +++ b/src/status_im/android/core.cljs @@ -78,8 +78,10 @@ (defn init [] (dispatch-sync [:initialize-db]) (dispatch [:initialize-crypt]) + (dispatch [:initialize-geth]) (dispatch [:initialize-chats]) - (dispatch [:initialize-protocol]) + ;protocol must be initialized after user enters password and we create account + ;(dispatch [:initialize-protocol]) (dispatch [:load-user-phone-number]) (dispatch [:load-contacts]) ;; load commands from remote server (todo: uncomment) diff --git a/src/status_im/chat/handlers.cljs b/src/status_im/chat/handlers.cljs index ef8ae2d24f..1f05a181bd 100644 --- a/src/status_im/chat/handlers.cljs +++ b/src/status_im/chat/handlers.cljs @@ -19,6 +19,9 @@ [status-im.handlers.content-suggestions :refer [get-content-suggestions]] [status-im.utils.phone-number :refer [format-phone-number]] [status-im.utils.datetime :as time] + [status-im.components.react :refer [geth]] + [status-im.utils.logging :as log] + [status-im.utils.types :refer [json->clj]] [status-im.chat.handlers.animation :refer [update-response-height get-response-height]])) @@ -259,6 +262,11 @@ (register-handler :save-password (fn [db [_ password]] + (.createAccount geth password (fn [result] + (let [data (json->clj result) + public-key (:pubkey data)] + (log/debug "Created account: " result) + (when (not (str/blank? public-key)) (dispatch [:initialize-protocol public-key]))))) (sign-up-service/save-password password) (assoc db :password-saved true))) diff --git a/src/status_im/handlers.cljs b/src/status_im/handlers.cljs index ebf835a9c3..fdfc7f64ff 100644 --- a/src/status_im/handlers.cljs +++ b/src/status_im/handlers.cljs @@ -10,6 +10,7 @@ [status-im.utils.logging :as log] [status-im.utils.crypt :refer [gen-random-bytes]] [status-im.utils.handlers :as u] + [status-im.components.react :refer [geth]] status-im.chat.handlers status-im.group-settings.handlers status-im.navigation.handlers @@ -74,6 +75,11 @@ (.toBits (.. js/ecc -sjcl -codec -hex)) (.addEntropy (.. js/ecc -sjcl -random))) (dispatch [:crypt-initialized])))))))) +(register-handler :initialize-geth + (u/side-effect! + (fn [_ _] + (log/debug "Starting node") + (.startNode geth (fn [result] (log/debug "Started Node: " result)))))) (register-handler :crypt-initialized (u/side-effect! diff --git a/src/status_im/protocol/handlers.cljs b/src/status_im/protocol/handlers.cljs index a9b94e5541..14690d6f47 100644 --- a/src/status_im/protocol/handlers.cljs +++ b/src/status_im/protocol/handlers.cljs @@ -17,8 +17,8 @@ (register-handler :initialize-protocol (u/side-effect! - (fn [db [_]] - (init-protocol (make-handler db))))) + (fn [db [_ public-key]] + (init-protocol public-key (make-handler db))))) (register-handler :protocol-initialized (fn [db [_ identity]] From 8a75e1eea79515522395d27bcd51f7e992720d37 Mon Sep 17 00:00:00 2001 From: Adrian Tiberius Date: Thu, 30 Jun 2016 13:51:06 +0300 Subject: [PATCH 03/10] updated status-lib dependency --- project.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.clj b/project.clj index 4007f3100d..a407735efa 100644 --- a/project.clj +++ b/project.clj @@ -10,7 +10,7 @@ [prismatic/schema "1.0.4"] ^{:voom {:repo "git@github.com:status-im/status-lib.git" :branch "master"}} - [status-im/protocol "0.1.1-20160525_083359-g53ab2c2"] + [status-im/protocol "0.1.1-20160630_104454-gd663db0"] [natal-shell "0.1.6"] [com.andrewmcveigh/cljs-time "0.4.0"]] :plugins [[lein-cljsbuild "1.1.1"] From c878fba6f13f458d4918ea02cab19e03f9d0b3fe Mon Sep 17 00:00:00 2001 From: Adrian Tiberius Date: Thu, 30 Jun 2016 18:06:05 +0300 Subject: [PATCH 04/10] created new accounts realm object and fixed new create account flow --- .../statusim/geth/service/GethService.java | 2 +- src/status_im/accounts/handlers.cljs | 32 +++++++++++++++++++ src/status_im/chat/handlers.cljs | 6 +--- src/status_im/db.cljs | 1 + src/status_im/handlers.cljs | 7 ++-- src/status_im/models/accounts.cljs | 22 +++++++++++++ src/status_im/persistence/realm.cljs | 4 +++ 7 files changed, 65 insertions(+), 9 deletions(-) create mode 100644 src/status_im/accounts/handlers.cljs create mode 100644 src/status_im/models/accounts.cljs diff --git a/android/app/src/main/java/com/statusim/geth/service/GethService.java b/android/app/src/main/java/com/statusim/geth/service/GethService.java index 8a62fcc55f..c0af872fe6 100644 --- a/android/app/src/main/java/com/statusim/geth/service/GethService.java +++ b/android/app/src/main/java/com/statusim/geth/service/GethService.java @@ -186,7 +186,7 @@ public class GethService extends Service { String password = data.getString("password"); // TODO: remove second argument Log.d(TAG, "Creating account: " + password + " - " + dataFolder); - String jsonData = Statusgo.CreateAccount(password, dataFolder); + String jsonData = Statusgo.CreateAccount(password, dataFolder + "/keystore"); Log.d(TAG, "Created account: " + jsonData); Bundle replyData = new Bundle(); diff --git a/src/status_im/accounts/handlers.cljs b/src/status_im/accounts/handlers.cljs new file mode 100644 index 0000000000..e70b48e1d9 --- /dev/null +++ b/src/status_im/accounts/handlers.cljs @@ -0,0 +1,32 @@ +(ns status-im.accounts.handlers + (:require [status-im.models.accounts :as accounts] + [re-frame.core :refer [register-handler after dispatch debug]] + [status-im.utils.logging :as log] + [status-im.components.react :refer [geth]] + [status-im.utils.types :refer [json->clj]] + [clojure.string :as str])) + + +(defn save-account [_ [_ account]] + (accounts/save-accounts [account])) + +(register-handler :add-account + (-> (fn [db [_ {:keys [address] :as account}]] + (update db :accounts assoc address account)) + ((after save-account)))) + +(defn account-created [result] + (let [data (json->clj result) + public-key (:pubkey data) + address (:address data)] + (log/debug "Created account: " result) + (when (not (str/blank? public-key)) + (do + (dispatch [:initialize-protocol public-key]) + (dispatch [:add-account {:address address + :public-key public-key}]))))) + +(register-handler :create-account + (-> (fn [db [_ password]] + (.createAccount geth password (fn [result] (account-created result))) + db))) \ No newline at end of file diff --git a/src/status_im/chat/handlers.cljs b/src/status_im/chat/handlers.cljs index 1f05a181bd..803e09095e 100644 --- a/src/status_im/chat/handlers.cljs +++ b/src/status_im/chat/handlers.cljs @@ -262,11 +262,7 @@ (register-handler :save-password (fn [db [_ password]] - (.createAccount geth password (fn [result] - (let [data (json->clj result) - public-key (:pubkey data)] - (log/debug "Created account: " result) - (when (not (str/blank? public-key)) (dispatch [:initialize-protocol public-key]))))) + (dispatch [:create-account password]) (sign-up-service/save-password password) (assoc db :password-saved true))) diff --git a/src/status_im/db.cljs b/src/status_im/db.cljs index 7c07c77636..963e27f342 100644 --- a/src/status_im/db.cljs +++ b/src/status_im/db.cljs @@ -11,6 +11,7 @@ ;; initial state of app-db (def app-db {:identity-password "replace-me-with-user-entered-password" :identity "me" + :accounts {} :contacts [] :contacts-ids #{} :selected-contacts #{} diff --git a/src/status_im/handlers.cljs b/src/status_im/handlers.cljs index fdfc7f64ff..f98862ff93 100644 --- a/src/status_im/handlers.cljs +++ b/src/status_im/handlers.cljs @@ -19,6 +19,7 @@ status-im.new-group.handlers status-im.participants.handlers status-im.qr-scanner.handlers + status-im.accounts.handlers status-im.protocol.handlers)) ;; -- Middleware ------------------------------------------------------------ @@ -77,9 +78,9 @@ (dispatch [:crypt-initialized])))))))) (register-handler :initialize-geth (u/side-effect! - (fn [_ _] - (log/debug "Starting node") - (.startNode geth (fn [result] (log/debug "Started Node: " result)))))) + (fn [_ _] + (log/debug "Starting node") + (.startNode geth (fn [result] (log/debug "Started Node: " result)))))) (register-handler :crypt-initialized (u/side-effect! diff --git a/src/status_im/models/accounts.cljs b/src/status_im/models/accounts.cljs new file mode 100644 index 0000000000..a9f333c3c7 --- /dev/null +++ b/src/status_im/models/accounts.cljs @@ -0,0 +1,22 @@ +(ns status-im.models.accounts + (:require [status-im.persistence.realm :as r])) + +(defn get-accounts [] + (-> (r/get-all :accounts) + r/collection->map)) + +(defn create-account [{:keys [address public-key] :as account}] + (->> account + (r/create :accounts))) + +(defn save-accounts [accounts] + (r/write #(mapv create-account accounts))) + + +;;;;;;;;;;;;;;;;;;;;---------------------------------------------- + +(defn accounts-list [] + (r/get-all :accounts)) + +(defn account-by-address [address] + (r/single-cljs (r/get-by-field :accounts :address address))) diff --git a/src/status_im/persistence/realm.cljs b/src/status_im/persistence/realm.cljs index 5d304828fe..941cd0f1b0 100644 --- a/src/status_im/persistence/realm.cljs +++ b/src/status_im/persistence/realm.cljs @@ -15,6 +15,10 @@ :optional true} :photo-path {:type "string" :optinal true}}} + {:name :accounts + :primaryKey :address + :properties {:address "string" + :public-key "string"}} {:name :kv-store :primaryKey :key :properties {:key "string" From 763aac2141bd13dd108563f353d0e2f4310c740f Mon Sep 17 00:00:00 2001 From: Adrian Tiberius Date: Thu, 30 Jun 2016 19:05:28 +0300 Subject: [PATCH 05/10] fix signup process --- project.clj | 2 +- src/status_im/accounts/handlers.cljs | 9 +++++---- src/status_im/handlers/server.cljs | 19 +++++++++++-------- src/status_im/models/protocol.cljs | 12 +++++------- src/status_im/profile/screen.cljs | 2 +- src/status_im/protocol/handlers.cljs | 4 ++-- 6 files changed, 25 insertions(+), 23 deletions(-) diff --git a/project.clj b/project.clj index a407735efa..1f1b0c77d2 100644 --- a/project.clj +++ b/project.clj @@ -10,7 +10,7 @@ [prismatic/schema "1.0.4"] ^{:voom {:repo "git@github.com:status-im/status-lib.git" :branch "master"}} - [status-im/protocol "0.1.1-20160630_104454-gd663db0"] + [status-im/protocol "0.1.1-20160630_153846-gbf92f5f"] [natal-shell "0.1.6"] [com.andrewmcveigh/cljs-time "0.4.0"]] :plugins [[lein-cljsbuild "1.1.1"] diff --git a/src/status_im/accounts/handlers.cljs b/src/status_im/accounts/handlers.cljs index e70b48e1d9..8ea9cf3e60 100644 --- a/src/status_im/accounts/handlers.cljs +++ b/src/status_im/accounts/handlers.cljs @@ -18,13 +18,14 @@ (defn account-created [result] (let [data (json->clj result) public-key (:pubkey data) - address (:address data)] + address (:address data) + account {:public-key public-key + :address address}] (log/debug "Created account: " result) (when (not (str/blank? public-key)) (do - (dispatch [:initialize-protocol public-key]) - (dispatch [:add-account {:address address - :public-key public-key}]))))) + (dispatch [:initialize-protocol account]) + (dispatch [:add-account account]))))) (register-handler :create-account (-> (fn [db [_ password]] diff --git a/src/status_im/handlers/server.cljs b/src/status_im/handlers/server.cljs index 5d9674c1d7..565f6f90c0 100644 --- a/src/status_im/handlers/server.cljs +++ b/src/status_im/handlers/server.cljs @@ -1,17 +1,20 @@ (ns status-im.handlers.server (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] - [status-im.utils.utils :refer [log on-error http-post]] + [status-im.utils.utils :refer [on-error http-post]] [status-im.utils.logging :as log])) (defn sign-up [db phone-number handler] - ;(user-data/save-phone-number phone-number) - (http-post "sign-up" {:phone-number phone-number - :whisper-identity (get-in db [:user-identity :public])} - (fn [body] - (log body) - (handler))) - db) + (let [{:keys [public-key address] :as account} (get-in db [:user-identity])] + ;(user-data/save-phone-number phone-number) + (log/debug "signing up with public-key" public-key "and phone " phone-number) + (http-post "sign-up" {:phone-number phone-number + :whisper-identity public-key + :address address} + (fn [body] + (log/debug body) + (handler))) + db)) (defn sign-up-confirm [confirmation-code handler] diff --git a/src/status_im/models/protocol.cljs b/src/status_im/models/protocol.cljs index abe2ad110f..441d433688 100644 --- a/src/status_im/models/protocol.cljs +++ b/src/status_im/models/protocol.cljs @@ -12,13 +12,11 @@ (assoc-in db db/protocol-initialized-path initialized?)) (defn update-identity [db identity] - (let [password (:identity-password db) - encrypted (password-encrypt password (to-edn-string identity))] - (s/put kv/kv-store :identity encrypted) + (let [identity-string (to-edn-string identity)] + (s/put kv/kv-store :identity identity-string) (assoc db :user-identity identity))) (defn stored-identity [db] - (let [encrypted (s/get kv/kv-store :identity) - password (:identity-password db)] - (when encrypted - (read-string (password-decrypt password encrypted))))) + (let [identity (s/get kv/kv-store :identity)] + (when identity + (read-string identity)))) diff --git a/src/status_im/profile/screen.cljs b/src/status_im/profile/screen.cljs index ffff2d2e47..09f2fc3d07 100644 --- a/src/status_im/profile/screen.cljs +++ b/src/status_im/profile/screen.cljs @@ -67,7 +67,7 @@ phone-number [:get :phone-number] email [:get :email] status [:get :status] - identity [:get-in [:user-identity :public]]] + identity [:get-in [:user-identity :public-key]]] [scroll-view {:style st/profile} [touchable-highlight {:style st/back-btn-touchable :on-press #(dispatch [:navigate-back])} diff --git a/src/status_im/protocol/handlers.cljs b/src/status_im/protocol/handlers.cljs index 14690d6f47..a5010bb56c 100644 --- a/src/status_im/protocol/handlers.cljs +++ b/src/status_im/protocol/handlers.cljs @@ -17,8 +17,8 @@ (register-handler :initialize-protocol (u/side-effect! - (fn [db [_ public-key]] - (init-protocol public-key (make-handler db))))) + (fn [db [_ account]] + (init-protocol account (make-handler db))))) (register-handler :protocol-initialized (fn [db [_ identity]] From 06e0332f4fc36d269e6a9b688db3129d3c7529c3 Mon Sep 17 00:00:00 2001 From: Adrian Tiberius Date: Thu, 30 Jun 2016 19:14:03 +0300 Subject: [PATCH 06/10] missed conflict --- src/status_im/handlers.cljs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/status_im/handlers.cljs b/src/status_im/handlers.cljs index f9280d8a0f..cd3ce76f44 100644 --- a/src/status_im/handlers.cljs +++ b/src/status_im/handlers.cljs @@ -7,12 +7,8 @@ [status-im.protocol.state.storage :as storage] [status-im.utils.logging :as log] [status-im.utils.crypt :refer [gen-random-bytes]] -<<<<<<< HEAD - [status-im.utils.handlers :as u] [status-im.components.react :refer [geth]] -======= [status-im.utils.handlers :refer [register-handler] :as u] ->>>>>>> origin/develop status-im.chat.handlers status-im.chat.handlers.animation status-im.group-settings.handlers From df229035e72723fff5266a0a5cec5128ca424c85 Mon Sep 17 00:00:00 2001 From: Adrian Tiberius Date: Thu, 30 Jun 2016 20:28:51 +0300 Subject: [PATCH 07/10] login to account after creating it to enable it in whisper --- .../java/com/statusim/geth/service/GethService.java | 2 +- src/status_im/accounts/handlers.cljs | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/android/app/src/main/java/com/statusim/geth/service/GethService.java b/android/app/src/main/java/com/statusim/geth/service/GethService.java index c0af872fe6..295cacd2c1 100644 --- a/android/app/src/main/java/com/statusim/geth/service/GethService.java +++ b/android/app/src/main/java/com/statusim/geth/service/GethService.java @@ -8,7 +8,7 @@ import android.util.Log; import java.lang.ref.WeakReference; -import com.github.ethereum.go_ethereum.Statusgo; +import com.github.status_im.status_go.Statusgo; import java.io.File; diff --git a/src/status_im/accounts/handlers.cljs b/src/status_im/accounts/handlers.cljs index 8ea9cf3e60..cb64243e8f 100644 --- a/src/status_im/accounts/handlers.cljs +++ b/src/status_im/accounts/handlers.cljs @@ -15,7 +15,7 @@ (update db :accounts assoc address account)) ((after save-account)))) -(defn account-created [result] +(defn account-created [result password] (let [data (json->clj result) public-key (:pubkey data) address (:address data) @@ -24,10 +24,16 @@ (log/debug "Created account: " result) (when (not (str/blank? public-key)) (do + (dispatch [:login-account address password]) (dispatch [:initialize-protocol account]) (dispatch [:add-account account]))))) (register-handler :create-account (-> (fn [db [_ password]] - (.createAccount geth password (fn [result] (account-created result))) - db))) \ No newline at end of file + (.createAccount geth password (fn [result] (account-created result password))) + db))) + +(register-handler :login-account + (-> (fn [db [_ address password]] + (.login geth address password (fn [result] (log/debug "Logged in account: " address result))) + db))) \ No newline at end of file From 6fc1e0b46a0d08dad0bfc2dad5fb415d31b53181 Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Thu, 30 Jun 2016 20:56:57 +0300 Subject: [PATCH 08/10] fix missed dapp params --- src/status_im/chat/handlers.cljs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/status_im/chat/handlers.cljs b/src/status_im/chat/handlers.cljs index db08695e00..97df9c4281 100644 --- a/src/status_im/chat/handlers.cljs +++ b/src/status_im/chat/handlers.cljs @@ -475,7 +475,9 @@ :group-chat false :is-active true :timestamp (.getTime (js/Date.)) - :contacts [{:identity contcat-id}]}] + :contacts [{:identity contcat-id}] + :dapp-url nil + :dapp-hash nil}] (assoc db :new-chat chat))) (defn add-chat [{:keys [new-chat] :as db} [_ chat-id]] From 7f1ac63cdf584b9d69eb28d97eade7c61082c0b8 Mon Sep 17 00:00:00 2001 From: Adrian Tiberius Date: Thu, 30 Jun 2016 23:03:43 +0300 Subject: [PATCH 09/10] autologin to account when its already created --- src/status_im/accounts/handlers.cljs | 12 +++++++++--- src/status_im/handlers.cljs | 22 +++++++++++++++++----- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/status_im/accounts/handlers.cljs b/src/status_im/accounts/handlers.cljs index cb64243e8f..cfb6d32d9b 100644 --- a/src/status_im/accounts/handlers.cljs +++ b/src/status_im/accounts/handlers.cljs @@ -4,6 +4,8 @@ [status-im.utils.logging :as log] [status-im.components.react :refer [geth]] [status-im.utils.types :refer [json->clj]] + [status-im.persistence.simple-kv-store :as kv] + [status-im.protocol.state.storage :as storage] [clojure.string :as str])) @@ -15,6 +17,9 @@ (update db :accounts assoc address account)) ((after save-account)))) +(defn save-password [password] + (storage/put kv/kv-store :password password)) + (defn account-created [result password] (let [data (json->clj result) public-key (:pubkey data) @@ -24,6 +29,7 @@ (log/debug "Created account: " result) (when (not (str/blank? public-key)) (do + (save-password password) (dispatch [:login-account address password]) (dispatch [:initialize-protocol account]) (dispatch [:add-account account]))))) @@ -34,6 +40,6 @@ db))) (register-handler :login-account - (-> (fn [db [_ address password]] - (.login geth address password (fn [result] (log/debug "Logged in account: " address result))) - db))) \ No newline at end of file + (-> (fn [db [_ address password]] + (.login geth address password (fn [result] (log/debug "Logged in account: " address result))) + db))) \ No newline at end of file diff --git a/src/status_im/handlers.cljs b/src/status_im/handlers.cljs index cd3ce76f44..ee070f1ceb 100644 --- a/src/status_im/handlers.cljs +++ b/src/status_im/handlers.cljs @@ -9,6 +9,7 @@ [status-im.utils.crypt :refer [gen-random-bytes]] [status-im.components.react :refer [geth]] [status-im.utils.handlers :refer [register-handler] :as u] + [status-im.models.protocol :as protocol] status-im.chat.handlers status-im.chat.handlers.animation status-im.group-settings.handlers @@ -57,7 +58,9 @@ (register-handler :initialize-db (fn [_ _] (assoc app-db - :signed-up (storage/get kv/kv-store :signed-up)))) + :signed-up (storage/get kv/kv-store :signed-up) + :user-identity (protocol/stored-identity nil) + :password (storage/get kv/kv-store :password)))) (register-handler :initialize-crypt (u/side-effect! @@ -74,11 +77,20 @@ (.toBits (.. js/ecc -sjcl -codec -hex)) (.addEntropy (.. js/ecc -sjcl -random))) (dispatch [:crypt-initialized])))))))) + +(defn node-started [db result] + (let [identity (:user-identity db) + password (:password db)] + (log/debug "Started Node: " result) + (when identity (do + (dispatch [:login-account (:address identity) password]) + (dispatch [:initialize-protocol identity]))))) + (register-handler :initialize-geth - (u/side-effect! - (fn [_ _] - (log/debug "Starting node") - (.startNode geth (fn [result] (log/debug "Started Node: " result)))))) + (u/side-effect! + (fn [db _] + (log/debug "Starting node") + (.startNode geth (fn [result] (node-started db result)))))) (register-handler :crypt-initialized (u/side-effect! From 0c77625155f5d619960756c418aaeaeb3c422ee2 Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Sat, 2 Jul 2016 10:56:10 +0300 Subject: [PATCH 10/10] upgrade statusgo --- android/app/build.gradle | 2 +- .../src/main/java/com/statusim/geth/service/GethService.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 4fe1f11ca2..913abe3bc0 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -134,7 +134,7 @@ dependencies { compile project(':react-native-status') compile project(':react-native-orientation') //compile(name:'statusgo-android-16', ext:'aar') - compile(group: 'status-im', name: 'status-go', version: '0.1.0-201606301634-5d7b29', ext: 'aar') + compile(group: 'status-im', name: 'status-go', version: '0.1.0-201607011545-da53ec', ext: 'aar') compile fileTree(dir: "node_modules/realm/android/libs", include: ["*.jar"]) } diff --git a/android/app/src/main/java/com/statusim/geth/service/GethService.java b/android/app/src/main/java/com/statusim/geth/service/GethService.java index 295cacd2c1..9900b3ef8e 100644 --- a/android/app/src/main/java/com/statusim/geth/service/GethService.java +++ b/android/app/src/main/java/com/statusim/geth/service/GethService.java @@ -186,7 +186,7 @@ public class GethService extends Service { String password = data.getString("password"); // TODO: remove second argument Log.d(TAG, "Creating account: " + password + " - " + dataFolder); - String jsonData = Statusgo.CreateAccount(password, dataFolder + "/keystore"); + String jsonData = Statusgo.CreateAccount(password); Log.d(TAG, "Created account: " + jsonData); Bundle replyData = new Bundle();