From 54a5ef53570448cc8eb5643e5fcb5eed3d9c8b49 Mon Sep 17 00:00:00 2001 From: ehsan shariati Date: Sat, 14 Jan 2023 01:25:56 -0500 Subject: [PATCH 01/39] separated blockchain from fula --- android/build.gradle | 2 +- .../land/fx/blockchain/BlockchainModule.java | 289 ++++++++++++++++++ .../land/fx/blockchain/BlockchainPackage.java | 32 ++ .../java/land/fx/blockchain/ThreadUtils.java | 42 +++ .../main/java/land/fx/fula/FulaModule.java | 4 + .../main/java/land/fx/fula/FulaPackage.java | 4 +- example/src/App.tsx | 68 ++++- example/yarn.lock | 112 +++---- src/index.tsx | 3 +- src/interfaces/blockchainNativeModule.ts | 40 +++ src/interfaces/fulaNativeModule.ts | 2 +- src/protocols/blockchain.ts | 52 ++++ 12 files changed, 588 insertions(+), 62 deletions(-) create mode 100644 android/src/main/java/land/fx/blockchain/BlockchainModule.java create mode 100644 android/src/main/java/land/fx/blockchain/BlockchainPackage.java create mode 100644 android/src/main/java/land/fx/blockchain/ThreadUtils.java create mode 100644 src/interfaces/blockchainNativeModule.ts create mode 100644 src/protocols/blockchain.ts diff --git a/android/build.gradle b/android/build.gradle index 1bda750..2d38f96 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -62,7 +62,7 @@ repositories { dependencies { //noinspection GradleDynamicVersion implementation "com.facebook.react:react-native:+" // From node_modules - implementation 'com.github.functionland:fula-build-aar:v0.8.4' // From jitpack.io + implementation 'com.github.functionland:fula-build-aar:blockchain-SNAPSHOT' // From jitpack.io implementation 'com.github.functionland:wnfs-build-aar:v1.4.1' // From jitpack.io implementation 'commons-io:commons-io:20030203.000550' // implementation files('mobile.aar') diff --git a/android/src/main/java/land/fx/blockchain/BlockchainModule.java b/android/src/main/java/land/fx/blockchain/BlockchainModule.java new file mode 100644 index 0000000..6a12ab3 --- /dev/null +++ b/android/src/main/java/land/fx/blockchain/BlockchainModule.java @@ -0,0 +1,289 @@ +package land.fx.blockchain; + +import fulamobile.Fulamobile; +import land.fx.fula.FulaModule; +import android.util.Log; + +import androidx.annotation.NonNull; + +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.bridge.WritableNativeMap; +import com.facebook.react.module.annotations.ReactModule; + +import org.jetbrains.annotations.Contract; +import org.json.JSONObject; + +import java.nio.charset.StandardCharsets; + +@ReactModule(name = BlockchainModule.NAME) +public class BlockchainModule extends ReactContextBaseJavaModule { + + @Override + public void initialize() { + System.loadLibrary("gojni"); + } + + public static final String NAME = "BlockchainModule"; + fulamobile.Client fula; + + public BlockchainModule(ReactApplicationContext reactContext) { + super(reactContext); + FulaModule fulaModule = new FulaModule(getReactApplicationContext()); + fula = fulaModule.getFulaClient(); + } + + @Override + @NonNull + public java.lang.String getName() { + return NAME; + } + + private byte[] toByte(@NonNull String input) { + return input.getBytes(StandardCharsets.UTF_8); + } + + @NonNull + @Contract("_ -> new") + private String toString(byte[] input) { + return new String(input, StandardCharsets.UTF_8); + } + + @ReactMethod + public void createAccount(String seedString, Promise promise) { + ThreadUtils.runOnExecutor(() -> { + Log.d("ReactNative", "createAccount: seedString = " + seedString); + try { + if (this.fula == null || this.fula.id() == null || this.fula.id().isEmpty()) { + promise.reject(new Error("Fula client is not initialized")); + } else { + + if (!seedString.startsWith("/")) { + promise.reject(new Error("seed should start with /")); + } + byte[] result = this.fula.seeded(seedString); + String resultString = toString(result); + promise.resolve(resultString); + } + } catch (Exception e) { + Log.d("get", e.getMessage()); + promise.reject(e); + } + }); + } + + @ReactMethod + public void checkAccountExists(String accountString, Promise promise) { + ThreadUtils.runOnExecutor(() -> { + Log.d("ReactNative", "checkAccountExists: accountString = " + accountString); + try { + byte[] result = this.fula.accountExists(accountString); + String resultString = toString(result); + promise.resolve(resultString); + } catch (Exception e) { + Log.d("get", e.getMessage()); + promise.reject(e); + } + }); + } + + @ReactMethod + public void createPool(String seedString, String poolName, Promise promise) { + ThreadUtils.runOnExecutor(() -> { + Log.d("ReactNative", "createPool: seedString = " + seedString + "; poolName = " + poolName); + try { + byte[] result = this.fula.poolCreate(seedString, poolName); + String resultString = toString(result); + promise.resolve(resultString); + } catch (Exception e) { + Log.d("get", e.getMessage()); + promise.reject(e); + } + }); + } + + @ReactMethod + public void listPools(Promise promise) { + ThreadUtils.runOnExecutor(() -> { + Log.d("ReactNative", "listPools"); + try { + byte[] result = this.fula.poolList(); + String resultString = toString(result); + promise.resolve(resultString); + } catch (Exception e) { + Log.d("get", e.getMessage()); + promise.reject(e); + } + }); + } + + @ReactMethod + public void joinPool(String seedString, long poolID, Promise promise) { + ThreadUtils.runOnExecutor(() -> { + Log.d("ReactNative", "joinPool: seedString = " + seedString + "; poolID = " + poolID); + try { + byte[] result = this.fula.poolJoin(seedString, poolID); + String resultString = toString(result); + promise.resolve(resultString); + } catch (Exception e) { + Log.d("get", e.getMessage()); + promise.reject(e); + } + }); + } + + @ReactMethod + public void cancelPoolJoin(String seedString, long poolID, Promise promise) { + ThreadUtils.runOnExecutor(() -> { + Log.d("ReactNative", "cancelPoolJoin: seedString = " + seedString + "; poolID = " + poolID); + try { + byte[] result = this.fula.poolCancelJoin(seedString, poolID); + String resultString = toString(result); + promise.resolve(resultString); + } catch (Exception e) { + Log.d("get", e.getMessage()); + promise.reject(e); + } + }); + } + + @ReactMethod + public void listPoolJoinRequests(long poolID, Promise promise) { + ThreadUtils.runOnExecutor(() -> { + Log.d("ReactNative", "listPoolJoinRequests: poolID = " + poolID); + try { + byte[] result = this.fula.poolRequests(poolID); + String resultString = toString(result); + promise.resolve(resultString); + } catch (Exception e) { + Log.d("get", e.getMessage()); + promise.reject(e); + } + }); + } + + @ReactMethod + public void votePoolJoinRequest(String seedString, long poolID, String accountString, boolean accept, Promise promise) { + ThreadUtils.runOnExecutor(() -> { + Log.d("ReactNative", "votePoolJoinRequest: seedString = " + seedString + "; poolID = " + poolID + "; accountString = " + accountString + "; accept = " + accept); + try { + byte[] result = this.fula.poolVote(seedString, poolID, accountString, accept); + String resultString = toString(result); + promise.resolve(resultString); + } catch (Exception e) { + Log.d("get", e.getMessage()); + promise.reject(e); + } + }); + } + + @ReactMethod + public void leavePool(String seedString, long poolID, Promise promise) { + ThreadUtils.runOnExecutor(() -> { + Log.d("ReactNative", "leavePool: seedString = " + seedString + "; poolID = " + poolID); + try { + byte[] result = this.fula.poolLeave(seedString, poolID); + String resultString = toString(result); + promise.resolve(resultString); + } catch (Exception e) { + Log.d("get", e.getMessage()); + promise.reject(e); + } + }); + } + + @ReactMethod + public void newReplicationRequest(String seedString, long poolID, long replicationFactor, String cid, Promise promise) { + ThreadUtils.runOnExecutor(() -> { + Log.d("ReactNative", "newReplicationRequest: seedString = " + seedString + "; poolID = " + poolID + "; replicationFactor = " + replicationFactor + "; cid = " + cid); + try { + byte[] result = this.fula.manifestUpload(seedString, poolID, replicationFactor, cid); + String resultString = toString(result); + promise.resolve(resultString); + } catch (Exception e) { + Log.d("get", e.getMessage()); + promise.reject(e); + } + }); + } + + @ReactMethod + public void newStoreRequest(String seedString, long poolID, String uploader, String cid, Promise promise) { + ThreadUtils.runOnExecutor(() -> { + Log.d("ReactNative", "newStoreRequest: seedString = " + seedString + "; poolID = " + poolID + "; uploader = " + uploader + "; cid = " + cid); + try { + byte[] result = this.fula.manifestStore(seedString, poolID, uploader, cid); + String resultString = toString(result); + promise.resolve(resultString); + } catch (Exception e) { + Log.d("get", e.getMessage()); + promise.reject(e); + } + }); + } + + @ReactMethod + public void listAvailableReplicationRequests(long poolID, Promise promise) { + ThreadUtils.runOnExecutor(() -> { + Log.d("ReactNative", "listAvailableReplicationRequests: poolID = " + poolID); + try { + byte[] result = this.fula.manifestAvailable(poolID); + String resultString = toString(result); + promise.resolve(resultString); + } catch (Exception e) { + Log.d("get", e.getMessage()); + promise.reject(e); + } + }); + } + + @ReactMethod + public void removeReplicationRequest(String seedString, long poolID, String cid, Promise promise) { + ThreadUtils.runOnExecutor(() -> { + Log.d("ReactNative", "newReplicationRequest: seedString = " + seedString + "; poolID = " + poolID + "; cid = " + cid); + try { + byte[] result = this.fula.manifestRemove(seedString, poolID, cid); + String resultString = toString(result); + promise.resolve(resultString); + } catch (Exception e) { + Log.d("get", e.getMessage()); + promise.reject(e); + } + }); + } + + @ReactMethod + public void removeStorer(String seedString, String storage, long poolID, String cid, Promise promise) { + ThreadUtils.runOnExecutor(() -> { + Log.d("ReactNative", "removeStorer: seedString = " + seedString + "; storage = " + storage + "; poolID = " + poolID + "; cid = " + cid); + try { + byte[] result = this.fula.manifestRemoveStorer(seedString, storage, poolID, cid); + String resultString = toString(result); + promise.resolve(resultString); + } catch (Exception e) { + Log.d("get", e.getMessage()); + promise.reject(e); + } + }); + } + + @ReactMethod + public void removeStoredReplication(String seedString, String uploader, long poolID, String cid, Promise promise) { + ThreadUtils.runOnExecutor(() -> { + Log.d("ReactNative", "removeStoredReplication: seedString = " + seedString + "; uploader = " + uploader + "; poolID = " + poolID + "; cid = " + cid); + try { + byte[] result = this.fula.manifestRemoveStored(seedString, uploader, poolID, cid); + String resultString = toString(result); + promise.resolve(resultString); + } catch (Exception e) { + Log.d("get", e.getMessage()); + promise.reject(e); + } + }); + } + +} diff --git a/android/src/main/java/land/fx/blockchain/BlockchainPackage.java b/android/src/main/java/land/fx/blockchain/BlockchainPackage.java new file mode 100644 index 0000000..b6f2f60 --- /dev/null +++ b/android/src/main/java/land/fx/blockchain/BlockchainPackage.java @@ -0,0 +1,32 @@ +package land.fx.blockchain; + +import androidx.annotation.NonNull; + +import com.facebook.react.ReactPackage; +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 BlockchainPackage implements ReactPackage { + @NonNull + @Override + public List createNativeModules(@NonNull ReactApplicationContext reactContext) { + List modules = new ArrayList<>(); + try { + modules.add(new BlockchainModule(reactContext)); + } catch (Exception e) { + e.printStackTrace(); + } + return modules; + } + + @NonNull + @Override + public List createViewManagers(@NonNull ReactApplicationContext reactContext) { + return Collections.emptyList(); + } +} diff --git a/android/src/main/java/land/fx/blockchain/ThreadUtils.java b/android/src/main/java/land/fx/blockchain/ThreadUtils.java new file mode 100644 index 0000000..da3f674 --- /dev/null +++ b/android/src/main/java/land/fx/blockchain/ThreadUtils.java @@ -0,0 +1,42 @@ +package land.fx.blockchain; + +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +final class ThreadUtils { + /** + * Thread which will be used to call all APIs. They + * they don't run on the calling thread anyway, we are deferring the calls + * to this thread to avoid (potentially) blocking the calling thread. + */ + private static final ExecutorService executor + = Executors.newSingleThreadExecutor(); + + /** + * Runs the given {@link Runnable} on the executor. + * @param runnable + */ + public static void runOnExecutor(Runnable runnable) { + executor.execute(runnable); + } + + /** + * Submits the given {@link Callable} to be run on the executor. + * @param callable + * @return Future. + */ + public static Future submitToExecutor(Callable callable) { + return executor.submit(callable); + } + + /** + * Submits the given {@link Runnable} to be run on the executor. + * @param runnable + * @return Future. + */ + public static Future submitToExecutor(Runnable runnable) { + return executor.submit(runnable); + } +} diff --git a/android/src/main/java/land/fx/fula/FulaModule.java b/android/src/main/java/land/fx/fula/FulaModule.java index 62b13f0..21d92c1 100755 --- a/android/src/main/java/land/fx/fula/FulaModule.java +++ b/android/src/main/java/land/fx/fula/FulaModule.java @@ -468,6 +468,10 @@ private boolean logoutInternal(byte[] identity, String storePath) throws Excepti } } + public fulamobile.Client getFulaClient() { + return this.fula; + } + @NonNull private byte[] newClientInternal(byte[] identity, String storePath, String bloxAddr, String exchange, boolean autoFlush, boolean useRelay) throws Exception { try { diff --git a/android/src/main/java/land/fx/fula/FulaPackage.java b/android/src/main/java/land/fx/fula/FulaPackage.java index da4a4d8..6256d2d 100644 --- a/android/src/main/java/land/fx/fula/FulaPackage.java +++ b/android/src/main/java/land/fx/fula/FulaPackage.java @@ -17,9 +17,9 @@ public class FulaPackage implements ReactPackage { public List createNativeModules(@NonNull ReactApplicationContext reactContext) { List modules = new ArrayList<>(); try { - modules.add(new FulaModule(reactContext)); + modules.add(new FulaModule(reactContext)); } catch (Exception e) { - e.printStackTrace(); + e.printStackTrace(); } return modules; } diff --git a/example/src/App.tsx b/example/src/App.tsx index 643c23e..83b92d1 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { StyleSheet, Text, View, Button, TextInput } from 'react-native'; -import { fula } from '@functionland/react-native-fula'; +import { fula, blockchain } from '@functionland/react-native-fula'; const App = () => { const [key, setKey] = React.useState(''); @@ -31,13 +31,15 @@ const App = () => { console.log(err.message, err.code); }); }; + //Key for peerId: 12D3KooWQGQo81K99HfbwuwhvbP4MYfo13fo7U6SAdkAnxoNBdPE const privateKey = [ 183, 7, 117, 9, 159, 132, 170, 235, 215, 34, 145, 181, 60, 207, 4, 27, 27, 17, 17, 167, 100, 89, 157, 218, 73, 200, 183, 145, 104, 151, 204, 142, 241, 94, 225, 7, 153, 168, 239, 94, 7, 187, 123, 158, 149, 149, 227, 170, 32, 54, 203, 243, 211, 78, 120, 114, 199, 1, 197, 134, 6, 91, 87, 152, ]; - const bloxAddr = '/dns/relay.dev.fx.land/tcp/4001/p2p/12D3KooWDRrBaAfPwsGJivBoUw5fE7ZpDiyfUjqgiURq2DEcL835/p2p-circuit/p2p/12D3KooWR2EiA8DbULqDAJZCcN2V2Nasmh756R1aLe5t3NniCnAS'; + const privateKeyString = "\\test"; + const bloxAddr = '/ip4/192.168.2.14/udp/40001/quic/p2p/12D3KooWR2EiA8DbULqDAJZCcN2V2Nasmh756R1aLe5t3NniCnAS'; const newClient = async () => { try { return fula.newClient( @@ -261,6 +263,68 @@ const App = () => { }} color={inprogress ? 'green' : 'blue'} /> + + +