From f6a433c8182319bbb6dc0cf1f2cf684bb549bb4a Mon Sep 17 00:00:00 2001 From: Siddarth Kumar Date: Wed, 10 Apr 2024 20:32:56 +0530 Subject: [PATCH] kotlinify account, database, Log & Network Manager (#19426) parent issue: https://github.com/status-im/status-mobile/issues/18310 This commit converts the following `Java` files to `Kotlin` : - modules/react-native-status/android/src/main/java/im/status/ethereum/module/AccountManager.java - modules/react-native-status/android/src/main/java/im/status/ethereum/module/DatabaseManager.java - modules/react-native-status/android/src/main/java/im/status/ethereum/module/LogManager.java - modules/react-native-status/android/src/main/java/im/status/ethereum/module/NetworkManager.java status: ready --- .../ethereum/module/AccountManager.java | 351 ------------------ .../status/ethereum/module/AccountManager.kt | 333 +++++++++++++++++ .../ethereum/module/DatabaseManager.java | 66 ---- .../status/ethereum/module/DatabaseManager.kt | 58 +++ .../im/status/ethereum/module/LogManager.java | 227 ----------- .../im/status/ethereum/module/LogManager.kt | 211 +++++++++++ .../ethereum/module/NetworkManager.java | 78 ---- .../status/ethereum/module/NetworkManager.kt | 77 ++++ 8 files changed, 679 insertions(+), 722 deletions(-) delete mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/module/AccountManager.java create mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/module/AccountManager.kt delete mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/module/DatabaseManager.java create mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/module/DatabaseManager.kt delete mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/module/LogManager.java create mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/module/LogManager.kt delete mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/module/NetworkManager.java create mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/module/NetworkManager.kt diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/AccountManager.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/AccountManager.java deleted file mode 100644 index 1ba44a1033..0000000000 --- a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/AccountManager.java +++ /dev/null @@ -1,351 +0,0 @@ -package im.status.ethereum.module; - -import com.facebook.react.bridge.Callback; -import com.facebook.react.bridge.ReactMethod; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContextBaseJavaModule; -import statusgo.Statusgo; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.IOException; -import org.json.JSONObject; -import org.json.JSONException; -import android.util.Log; -import android.content.Context; -import android.app.Activity; - -public class AccountManager extends ReactContextBaseJavaModule { - private static final String TAG = "AccountManager"; - private static final String gethLogFileName = "geth.log"; - private ReactApplicationContext reactContext; - - private Utils utils; - private LogManager logManager; - - public AccountManager(ReactApplicationContext reactContext) { - super(reactContext); - this.reactContext = reactContext; - this.utils = new Utils(reactContext); - this.logManager = new LogManager(reactContext); - } - - @Override - public String getName() { - return "AccountManager"; - } - - private String getTestnetDataDir(final String absRootDirPath) { - return this.utils.pathCombine(absRootDirPath, "ethereum/testnet"); - } - - @ReactMethod - public void createAccountAndLogin(final String createAccountRequest) { - Log.d(TAG, "createAccountAndLogin"); - String result = Statusgo.createAccountAndLogin(createAccountRequest); - if (result.startsWith("{\"error\":\"\"")) { - Log.d(TAG, "createAccountAndLogin success: " + result); - Log.d(TAG, "Geth node started"); - } else { - Log.e(TAG, "createAccountAndLogin failed: " + result); - } - } - - @ReactMethod - public void restoreAccountAndLogin(final String restoreAccountRequest) { - Log.d(TAG, "restoreAccountAndLogin"); - String result = Statusgo.restoreAccountAndLogin(restoreAccountRequest); - if (result.startsWith("{\"error\":\"\"")) { - Log.d(TAG, "restoreAccountAndLogin success: " + result); - Log.d(TAG, "Geth node started"); - } else { - Log.e(TAG, "restoreAccountAndLogin failed: " + result); - } - } - - private String updateConfig(final String jsonConfigString, final String absRootDirPath, final String keystoreDirPath) throws JSONException { - final JSONObject jsonConfig = new JSONObject(jsonConfigString); - // retrieve parameters from app config, that will be applied onto the Go-side config later on - final String dataDirPath = jsonConfig.getString("DataDir"); - final Boolean logEnabled = jsonConfig.getBoolean("LogEnabled"); - final Context context = this.getReactApplicationContext(); - final File gethLogFile = logEnabled ? this.logManager.prepareLogsFile(context) : null; - String gethLogDirPath = null; - if (gethLogFile != null) { - gethLogDirPath = gethLogFile.getParent(); - } - - Log.d(TAG, "log dir: " + gethLogDirPath + " log name: " + gethLogFileName); - - jsonConfig.put("DataDir", dataDirPath); - jsonConfig.put("KeyStoreDir", keystoreDirPath); - jsonConfig.put("LogDir", gethLogDirPath); - jsonConfig.put("LogFile", gethLogFileName); - - return jsonConfig.toString(); - } - - private static void prettyPrintConfig(final String config) { - Log.d(TAG, "startNode() with config (see below)"); - String configOutput = config; - final int maxOutputLen = 4000; - Log.d(TAG, "********************** NODE CONFIG ****************************"); - while (!configOutput.isEmpty()) { - Log.d(TAG, "Node config:" + configOutput.substring(0, Math.min(maxOutputLen, configOutput.length()))); - if (configOutput.length() > maxOutputLen) { - configOutput = configOutput.substring(maxOutputLen); - } else { - break; - } - } - Log.d(TAG, "******************* ENDOF NODE CONFIG *************************"); - } - - private void copyDirectory(File sourceLocation, File targetLocation) throws IOException { - if (sourceLocation.isDirectory()) { - if (!targetLocation.exists() && !targetLocation.mkdirs()) { - throw new IOException("Cannot create dir " + targetLocation.getAbsolutePath()); - } - - String[] children = sourceLocation.list(); - for (int i = 0; i < children.length; i++) { - copyDirectory(new File(sourceLocation, children[i]), new File(targetLocation, children[i])); - } - } else { - File directory = targetLocation.getParentFile(); - if (directory != null && !directory.exists() && !directory.mkdirs()) { - throw new IOException("Cannot create dir " + directory.getAbsolutePath()); - } - - InputStream in = new FileInputStream(sourceLocation); - OutputStream out = new FileOutputStream(targetLocation); - - byte[] buf = new byte[1024]; - int len; - while ((len = in.read(buf)) > 0) { - out.write(buf, 0, len); - } - in.close(); - out.close(); - } - } - - private String prepareDirAndUpdateConfig(final String jsonConfigString, final String keyUID) { - - final String absRootDirPath = this.utils.getNoBackupDirectory(); - final String dataFolder = this.getTestnetDataDir(absRootDirPath); - Log.d(TAG, "Starting Geth node in folder: " + dataFolder); - - try { - final File newFile = new File(dataFolder); - // todo handle error? - newFile.mkdir(); - } catch (Exception e) { - Log.e(TAG, "error making folder: " + dataFolder, e); - } - - final String ropstenFlagPath = this.utils.pathCombine(absRootDirPath, "ropsten_flag"); - final File ropstenFlag = new File(ropstenFlagPath); - if (!ropstenFlag.exists()) { - try { - final String chaindDataFolderPath = this.utils.pathCombine(dataFolder, "StatusIM/lightchaindata"); - final File lightChainFolder = new File(chaindDataFolderPath); - if (lightChainFolder.isDirectory()) { - String[] children = lightChainFolder.list(); - for (int i = 0; i < children.length; i++) { - new File(lightChainFolder, children[i]).delete(); - } - } - lightChainFolder.delete(); - ropstenFlag.createNewFile(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - String testnetDataDir = dataFolder; - String oldKeystoreDir = this.utils.pathCombine(testnetDataDir, "keystore"); - String newKeystoreDir = this.utils.pathCombine(absRootDirPath, "keystore"); - final File oldKeystore = new File(oldKeystoreDir); - if (oldKeystore.exists()) { - try { - final File newKeystore = new File(newKeystoreDir); - copyDirectory(oldKeystore, newKeystore); - - if (oldKeystore.isDirectory()) { - String[] children = oldKeystore.list(); - for (int i = 0; i < children.length; i++) { - new File(oldKeystoreDir, children[i]).delete(); - } - } - oldKeystore.delete(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - try { - final String multiaccountKeystoreDir = this.utils.pathCombine("/keystore", keyUID); - final String updatedJsonConfigString = this.updateConfig(jsonConfigString, absRootDirPath, multiaccountKeystoreDir); - - prettyPrintConfig(updatedJsonConfigString); - - return updatedJsonConfigString; - } catch (JSONException e) { - Log.e(TAG, "updateConfig failed: " + e.getMessage()); - System.exit(1); - - return ""; - } - } - - @ReactMethod - public void prepareDirAndUpdateConfig(final String keyUID, final String config, final Callback callback) { - Log.d(TAG, "prepareDirAndUpdateConfig"); - String finalConfig = prepareDirAndUpdateConfig(config, keyUID); - callback.invoke(finalConfig); - } - - @ReactMethod - public void saveAccountAndLoginWithKeycard(final String multiaccountData, final String password, final String settings, final String config, final String accountsData, final String chatKey) { - Log.d(TAG, "saveAccountAndLoginWithKeycard"); - String finalConfig = prepareDirAndUpdateConfig(config, this.utils.getKeyUID(multiaccountData)); - String result = Statusgo.saveAccountAndLoginWithKeycard(multiaccountData, password, settings, finalConfig, accountsData, chatKey); - if (result.startsWith("{\"error\":\"\"")) { - Log.d(TAG, "saveAccountAndLoginWithKeycard result: " + result); - Log.d(TAG, "Geth node started"); - } else { - Log.e(TAG, "saveAccountAndLoginWithKeycard failed: " + result); - } - } - - @ReactMethod - public void loginWithKeycard(final String accountData, final String password, final String chatKey, final String nodeConfigJSON) { - Log.d(TAG, "loginWithKeycard"); - this.utils.migrateKeyStoreDir(accountData, password); - String result = Statusgo.loginWithKeycard(accountData, password, chatKey, nodeConfigJSON); - if (result.startsWith("{\"error\":\"\"")) { - Log.d(TAG, "LoginWithKeycard result: " + result); - } else { - Log.e(TAG, "LoginWithKeycard failed: " + result); - } - } - - @ReactMethod - public void loginWithConfig(final String accountData, final String password, final String configJSON) { - Log.d(TAG, "loginWithConfig"); - this.utils.migrateKeyStoreDir(accountData, password); - String result = Statusgo.loginWithConfig(accountData, password, configJSON); - if (result.startsWith("{\"error\":\"\"")) { - Log.d(TAG, "LoginWithConfig result: " + result); - } else { - Log.e(TAG, "LoginWithConfig failed: " + result); - } - } - - @ReactMethod - public void loginAccount(final String request) { - Log.d(TAG, "loginAccount"); - String result = Statusgo.loginAccount(request); - if (result.startsWith("{\"error\":\"\"")) { - Log.d(TAG, "loginAccount result: " + result); - } else { - Log.e(TAG, "loginAccount failed: " + result); - } - } - - @ReactMethod - public void verify(final String address, final String password, final Callback callback) throws JSONException { - Activity currentActivity = getCurrentActivity(); - - final String absRootDirPath = this.utils.getNoBackupDirectory(); - final String newKeystoreDir = this.utils.pathCombine(absRootDirPath, "keystore"); - - this.utils.executeRunnableStatusGoMethod(() -> Statusgo.verifyAccountPassword(newKeystoreDir, address, password), callback); - } - - @ReactMethod - public void verifyDatabasePassword(final String keyUID, final String password, final Callback callback) throws JSONException { - this.utils.executeRunnableStatusGoMethod(() -> Statusgo.verifyDatabasePassword(keyUID, password), callback); - } - - @ReactMethod - private void openAccounts(final Callback callback) throws JSONException { - Log.d(TAG, "openAccounts"); - final String rootDir = this.utils.getNoBackupDirectory(); - Log.d(TAG, "[Opening accounts" + rootDir); - this.utils.executeRunnableStatusGoMethod(() -> Statusgo.openAccounts(rootDir), callback); - } - - //TODO : refactor logout usage to accept callback so that we can do this.utils.executeRunnableStatusGoMethod - @ReactMethod - public void logout() { - Log.d(TAG, "logout"); - Runnable r = new Runnable() { - @Override - public void run() { - String result = Statusgo.logout(); - if (result.startsWith("{\"error\":\"\"")) { - Log.d(TAG, "Logout result: " + result); - } else { - Log.e(TAG, "Logout failed: " + result); - } - } - }; - - StatusThreadPoolExecutor.getInstance().execute(r); - } - - @ReactMethod - public void multiAccountStoreAccount(final String json, final Callback callback) throws JSONException { - this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountStoreAccount(json), callback); - } - - @ReactMethod - public void multiAccountLoadAccount(final String json, final Callback callback) throws JSONException { - this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountLoadAccount(json), callback); - } - - @ReactMethod - public void multiAccountDeriveAddresses(final String json, final Callback callback) throws JSONException { - this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountDeriveAddresses(json), callback); - } - - @ReactMethod - public void multiAccountGenerateAndDeriveAddresses(final String json, final Callback callback) throws JSONException { - this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountGenerateAndDeriveAddresses(json), callback); - } - - @ReactMethod - public void multiAccountStoreDerived(final String json, final Callback callback) throws JSONException { - this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountStoreDerivedAccounts(json), callback); - } - - @ReactMethod - public void multiAccountImportMnemonic(final String json, final Callback callback) throws JSONException { - this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountImportMnemonic(json), callback); - } - - @ReactMethod - public void multiAccountImportPrivateKey(final String json, final Callback callback) throws JSONException { - this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountImportPrivateKey(json), callback); - } - - @ReactMethod - public void deleteMultiaccount(final String keyUID, final Callback callback) throws JSONException { - final String keyStoreDir = this.utils.getKeyStorePath(keyUID); - this.utils.executeRunnableStatusGoMethod(() -> Statusgo.deleteMultiaccount(keyUID, keyStoreDir), callback); - } - - @ReactMethod - public void getRandomMnemonic(final Callback callback) throws JSONException { - this.utils.executeRunnableStatusGoMethod(() -> Statusgo.getRandomMnemonic(), callback); - } - - @ReactMethod - public void createAccountFromMnemonicAndDeriveAccountsForPaths(final String mnemonic, final Callback callback) throws JSONException { - this.utils.executeRunnableStatusGoMethod(() -> Statusgo.createAccountFromMnemonicAndDeriveAccountsForPaths(mnemonic), callback); - } -} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/AccountManager.kt b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/AccountManager.kt new file mode 100644 index 0000000000..e253384ead --- /dev/null +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/AccountManager.kt @@ -0,0 +1,333 @@ +package im.status.ethereum.module + +import android.app.Activity +import android.content.Context +import android.util.Log +import com.facebook.react.bridge.Callback +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReactContextBaseJavaModule +import com.facebook.react.bridge.ReactMethod +import org.json.JSONException +import org.json.JSONObject +import statusgo.Statusgo +import java.io.* + +class AccountManager(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { + + private val utils = Utils(reactContext) + private val logManager = LogManager(reactContext) + + override fun getName() = "AccountManager" + + private fun getTestnetDataDir(absRootDirPath: String) = utils.pathCombine(absRootDirPath, "ethereum/testnet") + + @ReactMethod + fun createAccountAndLogin(createAccountRequest: String) { + Log.d(TAG, "createAccountAndLogin") + val result = Statusgo.createAccountAndLogin(createAccountRequest) + if (result.startsWith("{\"error\":\"\"")) { + Log.d(TAG, "createAccountAndLogin success: $result") + Log.d(TAG, "Geth node started") + } else { + Log.e(TAG, "createAccountAndLogin failed: $result") + } + } + + @ReactMethod + fun restoreAccountAndLogin(restoreAccountRequest: String) { + Log.d(TAG, "restoreAccountAndLogin") + val result = Statusgo.restoreAccountAndLogin(restoreAccountRequest) + if (result.startsWith("{\"error\":\"\"")) { + Log.d(TAG, "restoreAccountAndLogin success: $result") + Log.d(TAG, "Geth node started") + } else { + Log.e(TAG, "restoreAccountAndLogin failed: $result") + } + } + + private fun updateConfig(jsonConfigString: String, absRootDirPath: String, keystoreDirPath: String): String { + val jsonConfig = JSONObject(jsonConfigString) + val dataDirPath = jsonConfig.getString("DataDir") + val logEnabled = jsonConfig.getBoolean("LogEnabled") + val gethLogFile = if (logEnabled) logManager.prepareLogsFile(reactContext) else null + val gethLogDirPath = gethLogFile?.parent + + Log.d(TAG, "log dir: $gethLogDirPath log name: $gethLogFileName") + + jsonConfig.put("DataDir", dataDirPath) + jsonConfig.put("KeyStoreDir", keystoreDirPath) + jsonConfig.put("LogDir", gethLogDirPath) + jsonConfig.put("LogFile", gethLogFileName) + + return jsonConfig.toString() + } + + private fun copyDirectory(sourceLocation: File, targetLocation: File) { + if (sourceLocation.isDirectory) { + if (!targetLocation.exists() && !targetLocation.mkdirs()) { + throw IOException("Cannot create dir ${targetLocation.absolutePath}") + } + + val children = sourceLocation.list() + children?.forEach { child -> + copyDirectory(File(sourceLocation, child), File(targetLocation, child)) + } + } else { + val directory = targetLocation.parentFile + if (directory != null && !directory.exists() && !directory.mkdirs()) { + throw IOException("Cannot create dir ${directory.absolutePath}") + } + + sourceLocation.inputStream().use { input -> + targetLocation.outputStream().use { output -> + input.copyTo(output) + } + } + } + } + + private fun prepareDirAndUpdateConfig(jsonConfigString: String, keyUID: String): String { + val absRootDirPath = utils.getNoBackupDirectory() + val dataFolder = getTestnetDataDir(absRootDirPath) + Log.d(TAG, "Starting Geth node in folder: $dataFolder") + + try { + File(dataFolder).mkdir() + } catch (e: Exception) { + Log.e(TAG, "error making folder: $dataFolder", e) + } + + val ropstenFlagPath = utils.pathCombine(absRootDirPath, "ropsten_flag") + val ropstenFlag = File(ropstenFlagPath) + if (!ropstenFlag.exists()) { + try { + val chaindDataFolderPath = utils.pathCombine(dataFolder, "StatusIM/lightchaindata") + val lightChainFolder = File(chaindDataFolderPath) + if (lightChainFolder.isDirectory) { + lightChainFolder.listFiles()?.forEach { it.delete() } + } + lightChainFolder.delete() + ropstenFlag.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + } + } + + val testnetDataDir = dataFolder + val oldKeystoreDir = utils.pathCombine(testnetDataDir, "keystore") + val newKeystoreDir = utils.pathCombine(absRootDirPath, "keystore") + val oldKeystore = File(oldKeystoreDir) + if (oldKeystore.exists()) { + try { + val newKeystore = File(newKeystoreDir) + copyDirectory(oldKeystore, newKeystore) + + if (oldKeystore.isDirectory) { + oldKeystore.listFiles()?.forEach { it.delete() } + } + oldKeystore.delete() + } catch (e: IOException) { + e.printStackTrace() + } + } + + return try { + val multiaccountKeystoreDir = utils.pathCombine("/keystore", keyUID) + val updatedJsonConfigString = updateConfig(jsonConfigString, absRootDirPath, multiaccountKeystoreDir) + + prettyPrintConfig(updatedJsonConfigString) + + updatedJsonConfigString + } catch (e: JSONException) { + Log.e(TAG, "updateConfig failed: ${e.message}") + System.exit(1) + "" + } + } + + @ReactMethod + fun prepareDirAndUpdateConfig(keyUID: String, config: String, callback: Callback) { + Log.d(TAG, "prepareDirAndUpdateConfig") + val finalConfig = prepareDirAndUpdateConfig(config, keyUID) + callback.invoke(finalConfig) + } + + @ReactMethod + fun saveAccountAndLoginWithKeycard( + multiaccountData: String, + password: String, + settings: String, + config: String, + accountsData: String, + chatKey: String + ) { + try { + Log.d(TAG, "saveAccountAndLoginWithKeycard") + val keyUID = utils.getKeyUID(multiaccountData) + val finalConfig = prepareDirAndUpdateConfig(config, keyUID) + val result = Statusgo.saveAccountAndLoginWithKeycard( + multiaccountData, + password, + settings, + finalConfig, + accountsData, + chatKey + ) + if (result.startsWith("{\"error\":\"\"")) { + Log.d(TAG, "saveAccountAndLoginWithKeycard result: $result") + Log.d(TAG, "Geth node started") + } else { + Log.e(TAG, "saveAccountAndLoginWithKeycard failed: $result") + } + } catch (e: JSONException) { + Log.e(TAG, "JSON conversion failed: ${e.message}") + } + } + + @ReactMethod + fun loginWithKeycard(accountData: String, password: String, chatKey: String, nodeConfigJSON: String) { + Log.d(TAG, "loginWithKeycard") + utils.migrateKeyStoreDir(accountData, password) + val result = Statusgo.loginWithKeycard(accountData, password, chatKey, nodeConfigJSON) + if (result.startsWith("{\"error\":\"\"")) { + Log.d(TAG, "LoginWithKeycard result: $result") + } else { + Log.e(TAG, "LoginWithKeycard failed: $result") + } + } + + @ReactMethod + fun loginWithConfig(accountData: String, password: String, configJSON: String) { + Log.d(TAG, "loginWithConfig") + utils.migrateKeyStoreDir(accountData, password) + val result = Statusgo.loginWithConfig(accountData, password, configJSON) + if (result.startsWith("{\"error\":\"\"")) { + Log.d(TAG, "LoginWithConfig result: $result") + } else { + Log.e(TAG, "LoginWithConfig failed: $result") + } + } + + @ReactMethod + fun loginAccount(request: String) { + Log.d(TAG, "loginAccount") + val result = Statusgo.loginAccount(request) + if (result.startsWith("{\"error\":\"\"")) { + Log.d(TAG, "loginAccount result: $result") + } else { + Log.e(TAG, "loginAccount failed: $result") + } + } + + @ReactMethod + fun verify(address: String, password: String, callback: Callback) { + val absRootDirPath = utils.getNoBackupDirectory() + val newKeystoreDir = utils.pathCombine(absRootDirPath, "keystore") + + utils.executeRunnableStatusGoMethod( + { Statusgo.verifyAccountPassword(newKeystoreDir, address, password) }, + callback + ) + } + + @ReactMethod + fun verifyDatabasePassword(keyUID: String, password: String, callback: Callback) { + utils.executeRunnableStatusGoMethod( + { Statusgo.verifyDatabasePassword(keyUID, password) }, + callback + ) + } + + @ReactMethod + private fun openAccounts(callback: Callback) { + Log.d(TAG, "openAccounts") + val rootDir = utils.getNoBackupDirectory() + Log.d(TAG, "[Opening accounts $rootDir") + utils.executeRunnableStatusGoMethod({ Statusgo.openAccounts(rootDir) }, callback) + } + + @ReactMethod + fun logout() { + Log.d(TAG, "logout") + val runnable = Runnable { + val result = Statusgo.logout() + if (result.startsWith("{\"error\":\"\"")) { + Log.d(TAG, "Logout result: $result") + } else { + Log.e(TAG, "Logout failed: $result") + } + } + StatusThreadPoolExecutor.getInstance().execute(runnable) + } + + @ReactMethod + fun multiAccountStoreAccount(json: String, callback: Callback) { + utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountStoreAccount(json) }, callback) + } + + @ReactMethod + fun multiAccountLoadAccount(json: String, callback: Callback) { + utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountLoadAccount(json) }, callback) + } + + @ReactMethod + fun multiAccountDeriveAddresses(json: String, callback: Callback) { + utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountDeriveAddresses(json) }, callback) + } + + @ReactMethod + fun multiAccountGenerateAndDeriveAddresses(json: String, callback: Callback) { + utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountGenerateAndDeriveAddresses(json) }, callback) + } + + @ReactMethod + fun multiAccountStoreDerived(json: String, callback: Callback) { + utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountStoreDerivedAccounts(json) }, callback) + } + + @ReactMethod + fun multiAccountImportMnemonic(json: String, callback: Callback) { + utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountImportMnemonic(json) }, callback) + } + + @ReactMethod + fun multiAccountImportPrivateKey(json: String, callback: Callback) { + utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountImportPrivateKey(json) }, callback) + } + + @ReactMethod + fun deleteMultiaccount(keyUID: String, callback: Callback) { + val keyStoreDir = utils.getKeyStorePath(keyUID) + utils.executeRunnableStatusGoMethod({ Statusgo.deleteMultiaccount(keyUID, keyStoreDir) }, callback) + } + + @ReactMethod + fun getRandomMnemonic(callback: Callback) { + utils.executeRunnableStatusGoMethod({ Statusgo.getRandomMnemonic() }, callback) + } + + @ReactMethod + fun createAccountFromMnemonicAndDeriveAccountsForPaths(mnemonic: String, callback: Callback) { + utils.executeRunnableStatusGoMethod( + { Statusgo.createAccountFromMnemonicAndDeriveAccountsForPaths(mnemonic) }, + callback + ) + } + + companion object { + private const val TAG = "AccountManager" + private const val gethLogFileName = "geth.log" + + private fun prettyPrintConfig(config: String) { + Log.d(TAG, "startNode() with config (see below)") + var configOutput = config + val maxOutputLen = 4000 + Log.d(TAG, "********************** NODE CONFIG ****************************") + while (configOutput.isNotEmpty()) { + Log.d(TAG, "Node config:${configOutput.take(maxOutputLen)}") + configOutput = configOutput.drop(maxOutputLen) + } + Log.d(TAG, "******************* ENDOF NODE CONFIG *************************") + } + } +} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/DatabaseManager.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/DatabaseManager.java deleted file mode 100644 index e725af99df..0000000000 --- a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/DatabaseManager.java +++ /dev/null @@ -1,66 +0,0 @@ -package im.status.ethereum.module; - -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContextBaseJavaModule; -import com.facebook.react.bridge.ReactMethod; -import com.facebook.react.bridge.Callback; -import statusgo.Statusgo; -import android.util.Log; -import java.io.File; -import android.os.Environment; -import android.content.Context; -public class DatabaseManager extends ReactContextBaseJavaModule { - private static final String TAG = "DatabaseManager"; - private ReactApplicationContext reactContext; - private static final String exportDBFileName = "export.db"; - private Utils utils; - public DatabaseManager(ReactApplicationContext reactContext) { - this.reactContext = reactContext; - this.utils = new Utils(reactContext); - } - @Override - public String getName() { - return "DatabaseManager"; - } - - private File getExportDBFile() { - final Context context = this.getReactApplicationContext(); - // Environment.getExternalStoragePublicDirectory doesn't work as expected on Android Q - // https://developer.android.com/reference/android/os/Environment#getExternalStoragePublicDirectory(java.lang.String) - final File pubDirectory = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS); - final File filename = new File(pubDirectory, exportDBFileName); - - return filename; - } - - @ReactMethod - public void exportUnencryptedDatabase(final String accountData, final String password, final Callback callback) { - Log.d(TAG, "login"); - - final File newFile = getExportDBFile(); - - this.utils.migrateKeyStoreDir(accountData, password); - String result = Statusgo.exportUnencryptedDatabase(accountData, password, newFile.getAbsolutePath()); - if (result.startsWith("{\"error\":\"\"")) { - Log.d(TAG, "Login result: " + result); - } else { - Log.e(TAG, "Login failed: " + result); - } - } - - @ReactMethod - public void importUnencryptedDatabase(final String accountData, final String password) { - Log.d(TAG, "importUnencryptedDatabase"); - - final File newFile = getExportDBFile(); - - this.utils.migrateKeyStoreDir(accountData, password); - String result = Statusgo.importUnencryptedDatabase(accountData, password, newFile.getAbsolutePath()); - if (result.startsWith("{\"error\":\"\"")) { - Log.d(TAG, "import result: " + result); - } else { - Log.e(TAG, "import failed: " + result); - } - } - -} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/DatabaseManager.kt b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/DatabaseManager.kt new file mode 100644 index 0000000000..a0a21d2b3b --- /dev/null +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/DatabaseManager.kt @@ -0,0 +1,58 @@ +package im.status.ethereum.module + +import android.content.Context +import android.os.Environment +import android.util.Log +import com.facebook.react.bridge.Callback +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReactContextBaseJavaModule +import com.facebook.react.bridge.ReactMethod +import statusgo.Statusgo +import java.io.File + +class DatabaseManager(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { + + private val utils = Utils(reactContext) + + override fun getName() = "DatabaseManager" + + private fun getExportDBFile(): File { + val pubDirectory = reactContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS) + return File(pubDirectory, exportDBFileName) + } + + @ReactMethod + fun exportUnencryptedDatabase(accountData: String, password: String, callback: Callback) { + Log.d(TAG, "login") + + val newFile = getExportDBFile() + + utils.migrateKeyStoreDir(accountData, password) + val result = Statusgo.exportUnencryptedDatabase(accountData, password, newFile.absolutePath) + if (result.startsWith("{\"error\":\"\"")) { + Log.d(TAG, "Login result: $result") + } else { + Log.e(TAG, "Login failed: $result") + } + } + + @ReactMethod + fun importUnencryptedDatabase(accountData: String, password: String) { + Log.d(TAG, "importUnencryptedDatabase") + + val newFile = getExportDBFile() + + utils.migrateKeyStoreDir(accountData, password) + val result = Statusgo.importUnencryptedDatabase(accountData, password, newFile.absolutePath) + if (result.startsWith("{\"error\":\"\"")) { + Log.d(TAG, "import result: $result") + } else { + Log.e(TAG, "import failed: $result") + } + } + + companion object { + private const val TAG = "DatabaseManager" + private const val exportDBFileName = "export.db" + } +} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/LogManager.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/LogManager.java deleted file mode 100644 index 6a1873157e..0000000000 --- a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/LogManager.java +++ /dev/null @@ -1,227 +0,0 @@ -package im.status.ethereum.module; - -import com.facebook.react.bridge.ReactMethod; -import com.facebook.react.bridge.ReactContextBaseJavaModule; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.Callback; -import java.io.File; -import java.util.Stack; -import android.util.Log; -import android.net.Uri; -import java.io.OutputStreamWriter; -import java.io.IOException; -import android.app.Activity; -import android.app.AlertDialog; -import android.content.DialogInterface; -import androidx.core.content.FileProvider; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.FileOutputStream; -import java.util.zip.ZipOutputStream; -import java.io.FileInputStream; -import java.util.zip.ZipEntry; -import org.json.JSONObject; -import statusgo.Statusgo; -import android.content.Context; -import org.json.JSONException; -public class LogManager extends ReactContextBaseJavaModule { - private static final String TAG = "LogManager"; - private static final String gethLogFileName = "geth.log"; - private static final String statusLogFileName = "Status.log"; - private static final String logsZipFileName = "Status-debug-logs.zip"; - private ReactApplicationContext reactContext; - private Utils utils; - - public LogManager(ReactApplicationContext reactContext) { - super(reactContext); - this.reactContext = reactContext; - this.utils = new Utils(reactContext); - } - - @Override - public String getName() { - return "LogManager"; - } - - private File getLogsFile() { - final File pubDirectory = this.utils.getPublicStorageDirectory(); - final File logFile = new File(pubDirectory, gethLogFileName); - - return logFile; - } - - public File prepareLogsFile(final Context context) { - final File logFile = this.utils.getLogsFile(); - - try { - logFile.setReadable(true); - File parent = logFile.getParentFile(); - if (!parent.canWrite()) { - return null; - } - if (!parent.exists()) { - parent.mkdirs(); - } - logFile.createNewFile(); - logFile.setWritable(true); - Log.d(TAG, "Can write " + logFile.canWrite()); - Uri gethLogUri = Uri.fromFile(logFile); - - String gethLogFilePath = logFile.getAbsolutePath(); - Log.d(TAG, gethLogFilePath); - - return logFile; - } catch (Exception e) { - Log.d(TAG, "Can't create geth.log file! " + e.getMessage()); - } - - return null; - } - - private void showErrorMessage(final String message) { - final Activity activity = getCurrentActivity(); - - new AlertDialog.Builder(activity) - .setTitle("Error") - .setMessage(message) - .setNegativeButton("Exit", new DialogInterface.OnClickListener() { - public void onClick(final DialogInterface dialog, final int id) { - dialog.dismiss(); - } - }).show(); - } - - private void dumpAdbLogsTo(final FileOutputStream statusLogStream) throws IOException { - final String filter = "logcat -d -b main ReactNativeJS:D StatusModule:D StatusService:D StatusNativeLogs:D *:S"; - final java.lang.Process p = Runtime.getRuntime().exec(filter); - final java.io.BufferedReader in = new java.io.BufferedReader(new java.io.InputStreamReader(p.getInputStream())); - final java.io.BufferedWriter out = new java.io.BufferedWriter(new java.io.OutputStreamWriter(statusLogStream)); - String line; - while ((line = in.readLine()) != null) { - out.write(line); - out.newLine(); - } - out.close(); - in.close(); - } - - private Boolean zip(File[] _files, File zipFile, Stack errorList) { - final int BUFFER = 0x8000; - - try { - BufferedInputStream origin = null; - FileOutputStream dest = new FileOutputStream(zipFile); - ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest)); - byte data[] = new byte[BUFFER]; - - for (int i = 0; i < _files.length; i++) { - final File file = _files[i]; - if (file == null || !file.exists()) { - continue; - } - - Log.v("Compress", "Adding: " + file.getAbsolutePath()); - try { - FileInputStream fi = new FileInputStream(file); - origin = new BufferedInputStream(fi, BUFFER); - - ZipEntry entry = new ZipEntry(file.getName()); - out.putNextEntry(entry); - int count; - - while ((count = origin.read(data, 0, BUFFER)) != -1) { - out.write(data, 0, count); - } - origin.close(); - } catch (IOException e) { - Log.e(TAG, e.getMessage()); - errorList.push(e.getMessage()); - } - } - - out.close(); - - return true; - } catch (Exception e) { - Log.e(TAG, e.getMessage()); - e.printStackTrace(); - return false; - } - } - - @ReactMethod - public void sendLogs(final String dbJson, final String jsLogs, final Callback callback) { - Log.d(TAG, "sendLogs"); - if (!this.utils.checkAvailability()) { - return; - } - - final Context context = this.getReactApplicationContext(); - final File logsTempDir = new File(context.getCacheDir(), "logs"); // This path needs to be in sync with android/app/src/main/res/xml/file_provider_paths.xml - logsTempDir.mkdir(); - - final File dbFile = new File(logsTempDir, "db.json"); - try { - OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(dbFile)); - outputStreamWriter.write(dbJson); - outputStreamWriter.close(); - } catch (IOException e) { - Log.e(TAG, "File write failed: " + e.toString()); - showErrorMessage(e.getLocalizedMessage()); - } - - final File zipFile = new File(logsTempDir, logsZipFileName); - final File statusLogFile = new File(logsTempDir, statusLogFileName); - final File gethLogFile = getLogsFile(); - - try { - if (zipFile.exists() || zipFile.createNewFile()) { - final long usableSpace = zipFile.getUsableSpace(); - if (usableSpace < 20 * 1024 * 1024) { - final String message = String.format("Insufficient space available on device (%s) to write logs.\nPlease free up some space.", android.text.format.Formatter.formatShortFileSize(context, usableSpace)); - Log.e(TAG, message); - showErrorMessage(message); - return; - } - } - - dumpAdbLogsTo(new FileOutputStream(statusLogFile)); - - final Stack errorList = new Stack(); - final Boolean zipped = zip(new File[]{dbFile, gethLogFile, statusLogFile}, zipFile, errorList); - if (zipped && zipFile.exists()) { - zipFile.setReadable(true, false); - Uri extUri = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", zipFile); - callback.invoke(extUri.toString()); - } else { - Log.d(TAG, "File " + zipFile.getAbsolutePath() + " does not exist"); - } - } catch (Exception e) { - Log.e(TAG, e.getMessage()); - showErrorMessage(e.getLocalizedMessage()); - e.printStackTrace(); - return; - } finally { - dbFile.delete(); - statusLogFile.delete(); - zipFile.deleteOnExit(); - } - } - - @ReactMethod - public void initLogging(final boolean enabled, final boolean mobileSystem, final String logLevel, final Callback callback) throws JSONException { - final JSONObject jsonConfig = new JSONObject(); - jsonConfig.put("Enabled", enabled); - jsonConfig.put("MobileSystem", mobileSystem); - jsonConfig.put("Level", logLevel); - jsonConfig.put("File", getLogsFile().getAbsolutePath()); - final String config = jsonConfig.toString(); - this.utils.executeRunnableStatusGoMethod(() -> Statusgo.initLogging(config), callback); - } - - @ReactMethod(isBlockingSynchronousMethod = true) - public String logFileDirectory() { - return this.utils.getPublicStorageDirectory().getAbsolutePath(); - } - -} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/LogManager.kt b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/LogManager.kt new file mode 100644 index 0000000000..f5481a13ee --- /dev/null +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/LogManager.kt @@ -0,0 +1,211 @@ +package im.status.ethereum.module + +import android.app.Activity +import android.app.AlertDialog +import android.content.Context +import android.content.DialogInterface +import android.net.Uri +import android.util.Log +import androidx.core.content.FileProvider +import com.facebook.react.bridge.Callback +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReactContextBaseJavaModule +import com.facebook.react.bridge.ReactMethod +import org.json.JSONException +import org.json.JSONObject +import statusgo.Statusgo +import java.io.* +import java.util.* +import java.util.zip.ZipEntry +import java.util.zip.ZipOutputStream + +class LogManager(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { + + private val utils = Utils(reactContext) + + override fun getName() = "LogManager" + + private fun getLogsFile(): File { + val pubDirectory = utils.getPublicStorageDirectory() + return File(pubDirectory, gethLogFileName) + } + + fun prepareLogsFile(context: Context): File? { + val logFile = utils.getLogsFile() + + try { + logFile.setReadable(true) + val parent = logFile.parentFile + if (!parent?.canWrite()!!) { + return null + } + if (!parent.exists()) { + parent.mkdirs() + } + logFile.createNewFile() + logFile.setWritable(true) + Log.d(TAG, "Can write ${logFile.canWrite()}") + val gethLogUri = Uri.fromFile(logFile) + + val gethLogFilePath = logFile.absolutePath + Log.d(TAG, gethLogFilePath) + + return logFile + } catch (e: Exception) { + Log.d(TAG, "Can't create geth.log file! ${e.message}") + } + + return null + } + + private fun showErrorMessage(message: String) { + val activity = currentActivity + + AlertDialog.Builder(activity) + .setTitle("Error") + .setMessage(message) + .setNegativeButton("Exit") { dialog, _ -> + dialog.dismiss() + }.show() + } + + private fun dumpAdbLogsTo(statusLogStream: FileOutputStream) { + val filter = "logcat -d -b main ReactNativeJS:D StatusModule:D StatusService:D StatusNativeLogs:D *:S" + val p = Runtime.getRuntime().exec(filter) + val input = BufferedReader(InputStreamReader(p.inputStream)) + val output = BufferedWriter(OutputStreamWriter(statusLogStream)) + var line: String? + while (input.readLine().also { line = it } != null) { + output.write(line) + output.newLine() + } + output.close() + input.close() + } + + private fun zip(files: Array, zipFile: File, errorList: Stack): Boolean { + val BUFFER = 0x8000 + + try { + var origin: BufferedInputStream? = null + val dest = FileOutputStream(zipFile) + val out = ZipOutputStream(BufferedOutputStream(dest)) + val data = ByteArray(BUFFER) + + for (file in files) { + if (file == null || !file.exists()) { + continue + } + + Log.v("Compress", "Adding: ${file.absolutePath}") + try { + val fi = FileInputStream(file) + origin = BufferedInputStream(fi, BUFFER) + + val entry = ZipEntry(file.name) + out.putNextEntry(entry) + var count: Int + + while (origin.read(data, 0, BUFFER).also { count = it } != -1) { + out.write(data, 0, count) + } + origin.close() + } catch (e: IOException) { + Log.e(TAG, e.message!!) + errorList.push(e.message!!) + } + } + + out.close() + + return true + } catch (e: Exception) { + Log.e(TAG, e.message!!) + e.printStackTrace() + return false + } + } + + @ReactMethod + fun sendLogs(dbJson: String, jsLogs: String, callback: Callback) { + Log.d(TAG, "sendLogs") + if (!utils.checkAvailability()) { + return + } + + val context = reactApplicationContext + val logsTempDir = File(context.cacheDir, "logs") // This path needs to be in sync with android/app/src/main/res/xml/file_provider_paths.xml + logsTempDir.mkdir() + + val dbFile = File(logsTempDir, "db.json") + try { + val outputStreamWriter = OutputStreamWriter(FileOutputStream(dbFile)) + outputStreamWriter.write(dbJson) + outputStreamWriter.close() + } catch (e: IOException) { + Log.e(TAG, "File write failed: ${e}") + showErrorMessage(e.localizedMessage!!) + } + + val zipFile = File(logsTempDir, logsZipFileName) + val statusLogFile = File(logsTempDir, statusLogFileName) + val gethLogFile = getLogsFile() + + try { + if (zipFile.exists() || zipFile.createNewFile()) { + val usableSpace = zipFile.usableSpace + if (usableSpace < 20 * 1024 * 1024) { + val message = "Insufficient space available on device (${android.text.format.Formatter.formatShortFileSize(context, usableSpace)}) to write logs.\nPlease free up some space." + Log.e(TAG, message) + showErrorMessage(message) + return + } + } + + dumpAdbLogsTo(FileOutputStream(statusLogFile)) + + val errorList = Stack() + val zipped = zip(arrayOf(dbFile, gethLogFile, statusLogFile), zipFile, errorList) + if (zipped && zipFile.exists()) { + zipFile.setReadable(true, false) + val extUri = FileProvider.getUriForFile(context, "${context.packageName}.provider", zipFile) + callback.invoke(extUri.toString()) + } else { + Log.d(TAG, "File ${zipFile.absolutePath} does not exist") + } + } catch (e: Exception) { + Log.e(TAG, e.message!!) + showErrorMessage(e.localizedMessage!!) + e.printStackTrace() + return + } finally { + dbFile.delete() + statusLogFile.delete() + zipFile.deleteOnExit() + } + } + + @ReactMethod + fun initLogging(enabled: Boolean, mobileSystem: Boolean, logLevel: String, callback: Callback) { + val jsonConfig = JSONObject().apply { + put("Enabled", enabled) + put("MobileSystem", mobileSystem) + put("Level", logLevel) + put("File", getLogsFile().absolutePath) + } + val config = jsonConfig.toString() + utils.executeRunnableStatusGoMethod({ Statusgo.initLogging(config) }, callback) + } + + @ReactMethod(isBlockingSynchronousMethod = true) + fun logFileDirectory(): String? { + return utils.getPublicStorageDirectory()?.absolutePath + } + + companion object { + private const val TAG = "LogManager" + private const val gethLogFileName = "geth.log" + private const val statusLogFileName = "Status.log" + private const val logsZipFileName = "Status-debug-logs.zip" + } +} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/NetworkManager.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/NetworkManager.java deleted file mode 100644 index 873aa59671..0000000000 --- a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/NetworkManager.java +++ /dev/null @@ -1,78 +0,0 @@ -package im.status.ethereum.module; - -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContextBaseJavaModule; -import com.facebook.react.bridge.ReactMethod; -import com.facebook.react.bridge.Callback; -import org.json.JSONException; -import statusgo.Statusgo; -import org.json.JSONObject; - -public class NetworkManager extends ReactContextBaseJavaModule { - private ReactApplicationContext reactContext; - private Utils utils; - - public NetworkManager(ReactApplicationContext reactContext) { - super(reactContext); - this.reactContext = reactContext; - this.utils = new Utils(reactContext); - } - - @Override - public String getName() { - return "NetworkManager"; - } - - @ReactMethod - public void startSearchForLocalPairingPeers(final Callback callback) throws JSONException { - this.utils.executeRunnableStatusGoMethod(() -> Statusgo.startSearchForLocalPairingPeers(), callback); - } - - @ReactMethod - public void getConnectionStringForBootstrappingAnotherDevice(final String configJSON, final Callback callback) throws JSONException { - final JSONObject jsonConfig = new JSONObject(configJSON); - final JSONObject senderConfig = jsonConfig.getJSONObject("senderConfig"); - final String keyUID = senderConfig.getString("keyUID"); - final String keyStorePath = this.utils.getKeyStorePath(keyUID); - senderConfig.put("keystorePath", keyStorePath); - - this.utils.executeRunnableStatusGoMethod(() -> Statusgo.getConnectionStringForBootstrappingAnotherDevice(jsonConfig.toString()), callback); - } - - @ReactMethod - public void inputConnectionStringForBootstrapping(final String connectionString, final String configJSON, final Callback callback) throws JSONException { - final JSONObject jsonConfig = new JSONObject(configJSON); - final JSONObject receiverConfig = jsonConfig.getJSONObject("receiverConfig"); - final String keyStorePath = this.utils.pathCombine(this.utils.getNoBackupDirectory(), "/keystore"); - receiverConfig.put("keystorePath", keyStorePath); - receiverConfig.getJSONObject("nodeConfig").put("rootDataDir", this.utils.getNoBackupDirectory()); - - this.utils.executeRunnableStatusGoMethod(() -> Statusgo.inputConnectionStringForBootstrapping(connectionString, jsonConfig.toString()), callback); - } - - @ReactMethod - public void sendTransactionWithSignature(final String txArgsJSON, final String signature, final Callback callback) throws JSONException { - this.utils.executeRunnableStatusGoMethod(() -> Statusgo.sendTransactionWithSignature(txArgsJSON, signature), callback); - } - - @ReactMethod - public void sendTransaction(final String txArgsJSON, final String password, final Callback callback) throws JSONException { - this.utils.executeRunnableStatusGoMethod(() -> Statusgo.sendTransaction(txArgsJSON, password), callback); - } - - @ReactMethod - public void callRPC(final String payload, final Callback callback) throws JSONException { - this.utils.executeRunnableStatusGoMethod(() -> Statusgo.callRPC(payload), callback); - } - - @ReactMethod - public void callPrivateRPC(final String payload, final Callback callback) throws JSONException { - this.utils.executeRunnableStatusGoMethod(() -> Statusgo.callPrivateRPC(payload), callback); - } - - @ReactMethod - public void recover(final String rpcParams, final Callback callback) throws JSONException { - this.utils.executeRunnableStatusGoMethod(() -> Statusgo.recover(rpcParams), callback); - } - -} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/NetworkManager.kt b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/NetworkManager.kt new file mode 100644 index 0000000000..607582d51d --- /dev/null +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/NetworkManager.kt @@ -0,0 +1,77 @@ +package im.status.ethereum.module + +import com.facebook.react.bridge.Callback +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReactContextBaseJavaModule +import com.facebook.react.bridge.ReactMethod +import org.json.JSONException +import org.json.JSONObject +import statusgo.Statusgo + +class NetworkManager(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { + + private val utils = Utils(reactContext) + + override fun getName() = "NetworkManager" + + @ReactMethod + fun startSearchForLocalPairingPeers(callback: Callback) { + utils.executeRunnableStatusGoMethod({ Statusgo.startSearchForLocalPairingPeers() }, callback) + } + + @ReactMethod + fun getConnectionStringForBootstrappingAnotherDevice(configJSON: String, callback: Callback) { + val jsonConfig = JSONObject(configJSON) + val senderConfig = jsonConfig.getJSONObject("senderConfig") + val keyUID = senderConfig.getString("keyUID") + val keyStorePath = utils.getKeyStorePath(keyUID) + senderConfig.put("keystorePath", keyStorePath) + + utils.executeRunnableStatusGoMethod( + { Statusgo.getConnectionStringForBootstrappingAnotherDevice(jsonConfig.toString()) }, + callback + ) + } + + @ReactMethod + fun inputConnectionStringForBootstrapping(connectionString: String, configJSON: String, callback: Callback) { + val jsonConfig = JSONObject(configJSON) + val receiverConfig = jsonConfig.getJSONObject("receiverConfig") + val keyStorePath = utils.pathCombine(utils.getNoBackupDirectory(), "/keystore") + receiverConfig.put("keystorePath", keyStorePath) + receiverConfig.getJSONObject("nodeConfig").put("rootDataDir", utils.getNoBackupDirectory()) + + utils.executeRunnableStatusGoMethod( + { Statusgo.inputConnectionStringForBootstrapping(connectionString, jsonConfig.toString()) }, + callback + ) + } + + @ReactMethod + fun sendTransactionWithSignature(txArgsJSON: String, signature: String, callback: Callback) { + utils.executeRunnableStatusGoMethod( + { Statusgo.sendTransactionWithSignature(txArgsJSON, signature) }, + callback + ) + } + + @ReactMethod + fun sendTransaction(txArgsJSON: String, password: String, callback: Callback) { + utils.executeRunnableStatusGoMethod({ Statusgo.sendTransaction(txArgsJSON, password) }, callback) + } + + @ReactMethod + fun callRPC(payload: String, callback: Callback) { + utils.executeRunnableStatusGoMethod({ Statusgo.callRPC(payload) }, callback) + } + + @ReactMethod + fun callPrivateRPC(payload: String, callback: Callback) { + utils.executeRunnableStatusGoMethod({ Statusgo.callPrivateRPC(payload) }, callback) + } + + @ReactMethod + fun recover(rpcParams: String, callback: Callback) { + utils.executeRunnableStatusGoMethod({ Statusgo.recover(rpcParams) }, callback) + } +}