Skip to content

Commit

Permalink
Added listFailedActions method
Browse files Browse the repository at this point in the history
The listFailedActions acepts a string[] as input, which can be emnoty, and check if any of the cids in the input array have failed being pushed to the backend. It lists all failed cids if input is an empty array.
If any of hte iput cids are failed, then the putput shows tehm. If none failed, output is false.
  • Loading branch information
ehsan6sha committed Jul 10, 2023
1 parent 7cb1418 commit be99b80
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 27 deletions.
41 changes: 25 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# react-native-fula

This package is a bridge to use the [Fula protocols](https://github.com/functionland/go-fula) in the react-native. It uses [WNFS](https://github.com/wnfs-wg/rs-wnfs) to create the Merkle dag from files and folders and transfer the DAG using Graphsync to the nodes.
This package is a bridge to use the [Fula protocols](https://github.com/functionland/go-fula) in the react-native. It uses [WNFS](https://github.com/wnfs-wg/rs-wnfs) to create the Merkle dag from files and folders and transfer the DAG using Graphsync to the nodes.

## Installation

Expand Down Expand Up @@ -34,9 +34,9 @@ const peerId //returns peerId as string
peerId, //returns peerId of the created libp2p instance in form of a string of bytes
cid, //return the root cid of the WNFS merkle DAG in form of a string
private_ref //return the keys needed to decode hte encrypted WNFS tree in form of a string of object
]
=
await fula.init(
]
=
await fula.init(
identity: string, //bytes of the privateKey of did identity in string format
storePath: string, // leave empty to use the default temp one
bloxAddr: string, //leave empty for testing without a backend node
Expand All @@ -50,7 +50,7 @@ await fula.init(
```js
//Creates a Folder
const cid //returns the cid of the new root. Note that on every write action the root cid changes.
=
=
await fula.mkdir(
path: string // This is the Fula path to create a folder and always starts with "root/" and should not start or end with a slash e.g "root/pictures"
);
Expand All @@ -59,7 +59,7 @@ await fula.mkdir(
```js
//Write a local file on the device to the Fula tree (upload). It keeps the original file modification date.
const cid //returns the cid of the new root. Note that on every write action the root cid changes.
=
=
await fula.writeFile(
fulaTargetFilename: string, //path to the file on the tree. It should include the filename and extension and start from the "root/". e.g. "root/pictures/cat.jpg"
localFilename: string //path to the local file. e.g the file that needs to be uploaded
Expand All @@ -70,7 +70,7 @@ await fula.writeFile(
```js
//reads a file on fula tree to a local file on the device (download). It is stream so does not affect memory for large files.
const localFilePath //returns the path to the local file and includes the filename
=
=
await fula.readFile(
fulaTargetFilename: string, //path to the file on the tree. It should include the filename and extension and start from the "root/". e.g. "root/pictures/cat.jpg"
localFilename: string //path to the local file. It should include the filename and extension. e.g. "/temp/cat.jpg"
Expand All @@ -80,7 +80,7 @@ await fula.readFile(
```js
//shows all files and folders under the specified path on Fula
const fileList //returns all the files and folders in a string separated by \n
=
=
await fula.ls(
path: string, //path to the folder on the tree. It always starts from the "root". e.g. "root" or "root/pictures"
);
Expand All @@ -90,7 +90,7 @@ await fula.ls(
```js
//removes all files and folders at the specified path on Fula
const cid //returns the cid of the new root. Note that on every write action the root cid changes.
=
=
await fula.rm(
path: string, //path to the file or folder on the tree. It always starts from the "root". e.g. "root/pictures" or "root/pictures/cat.jpg"
);
Expand All @@ -100,7 +100,7 @@ await fula.rm(
```js
//copies the specified file or folder at sourcePath to the filename at targetPath. the path itself(apart from filename) must exist
const cid //returns the cid of the new root. Note that on every write action the root cid changes.
=
=
await fula.cp(
sourcePath: string, //path to the file or folder on the tree. It always starts from the "root". e.g. "root/pictures" or "root/pictures/cat.jpg"
targetPath: string, //path to the file or folder on the tree. It always starts from the "root". e.g. "root/pictures2" or "root/pictures2/cat.jpg"
Expand All @@ -111,7 +111,7 @@ await fula.cp(
```js
//moves the specified file or folder at sourcePath to the filename at targetPath. the path itself(apart from filename) must exist
const cid //returns the cid of the new root. Note that on every write action the root cid changes.
=
=
await fula.mv(
sourcePath: string, //path to the file or folder on the tree. It always starts from the "root". e.g. "root/pictures" or "root/pictures/cat.jpg"
targetPath: string, //path to the file or folder on the tree. It always starts from the "root". e.g. "root/pictures2" or "root/pictures2/cat.jpg"
Expand All @@ -122,7 +122,7 @@ await fula.mv(
```js
//checks if fula is ready (initialized through newClient or init)
const result //returns true if succesful and false if fails
=
=
await fula.isReady(
filesystemCheck: boolean //Default is true. If true it checks if both WNFS and Fula are ready. If false it only checks fula
);
Expand All @@ -132,7 +132,7 @@ await fula.isReady(
```js
//checks if client can reach server
const result //returns true if it can, and false if it cannot
=
=
await fula.checkConnection(
timeout: number? //default to 20. Maximum time in seconds that checkConnection waits before throwing an error
);
Expand All @@ -142,17 +142,26 @@ await fula.checkConnection(
```js
//checks if there are any un-synced actions on the client
const result //returns true if there are, and false if everything is synced with server
=
=
await fula.checkFailedActions(
retry: boolean //if true, it tries to sync device with server, if not, it only checks
timeout: number? //default to 20. Maximum time in seconds that checkConnection waits before throwing an error
);
```
```js
//lists any cids that are failed to be pushed to backend and only exist on client device
const result //returns an array of cids or false if no cid is found
=
await fula.listFailedActions(
cids: string[] //if [], it returns all failed cids, and if provided, it only return the failed cids that are in the array of cids provided as input
);
```
```js
//Gives access to the blox for a specific peerId. This call must be made from the authorizer only.
const result //returns true if succesful and false if fails
=
=
await fula.setAuth(
peerId: string, //peer ID of the app that needs access to the blox
allow: boolean, // true to allow and false to remove access
Expand All @@ -168,7 +177,7 @@ await fula.shutdown();
```js
//removes all Fula related data and information (Except the encrypted filesystem) at the specified storage local path
const result //returns true if succesful and false if fails
=
=
await fula.logout(
identity: string, //bytes of the privateKey of did identity in string format
storePath: string, // leave empty to use the default temp one
Expand Down
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ repositories {
dependencies {
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+" // From node_modules
implementation 'com.github.functionland:fula-build-aar:1.11.2' // From jitpack.io
implementation 'com.github.functionland:fula-build-aar:1.12.0' // From jitpack.io
implementation 'com.github.functionland:wnfs-build-aar:v1.4.1' // From jitpack.io
implementation 'commons-io:commons-io:20030203.000550'
implementation 'commons-codec:commons-codec:1.15'
Expand Down
71 changes: 61 additions & 10 deletions android/src/main/java/land/fx/fula/FulaModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.ReadableArray;


import org.apache.commons.io.FileUtils;
import org.apache.commons.codec.binary.Base32;
import org.jetbrains.annotations.Contract;

import java.io.File;
Expand All @@ -24,7 +27,7 @@
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Random;
import java.util.ArrayList;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
Expand All @@ -38,9 +41,6 @@
import java.util.concurrent.Future;
import java.util.concurrent.TimeoutException;

import org.json.JSONObject;
import org.json.JSONArray;

import fulamobile.Config;
import fulamobile.Fulamobile;

Expand Down Expand Up @@ -330,7 +330,7 @@ private boolean checkConnectionInternal(int timeout) throws Exception {
}

@ReactMethod
private void checkFailedActions(boolean retry, int timeout, Promise promise) throws Exception {
public void checkFailedActions(boolean retry, int timeout, Promise promise) throws Exception {
try {
if (this.fula != null) {
if (!retry) {
Expand All @@ -356,6 +356,57 @@ private void checkFailedActions(boolean retry, int timeout, Promise promise) thr
}
}

@ReactMethod
private void listFailedActions(ReadableArray cids, Promise promise) throws Exception {
try {
if (this.fula != null) {
Log.d("ReactNative", "listFailedActions");
fulamobile.StringIterator failedLinks = this.fula.listFailedPushesAsString();
ArrayList<String> failedLinksList = new ArrayList<>();
while (failedLinks.hasNext()) {
failedLinksList.add(failedLinks.next());
}
if (cids.size() > 0) {
// If cids array is provided, filter the failedLinksList
ArrayList<String> cidsList = new ArrayList<>();
for (int i = 0; i < cids.size(); i++) {
cidsList.add(cids.getString(i));
}
cidsList.retainAll(failedLinksList); // Keep only the elements in both cidsList and failedLinksList
if (!cidsList.isEmpty()) {
// If there are any matching cids, return them
WritableArray cidsArray = Arguments.createArray();
for (String cid : cidsList) {
cidsArray.pushString(cid);
}
promise.resolve(cidsArray);
} else {
// If there are no matching cids, return false
promise.resolve(false);
}
} else if (!failedLinksList.isEmpty()) {
// If cids array is not provided, return the whole list
Log.d("ReactNative", "listFailedActions found: "+ failedLinksList);
WritableArray failedLinksArray = Arguments.createArray();
for (String link : failedLinksList) {
failedLinksArray.pushString(link);
}
promise.resolve(failedLinksArray);
} else {
promise.resolve(false);
}
} else {
throw new Exception("listFailedActions: Fula is not initialized");
}
} catch (Exception e) {
Log.d("ReactNative", "listFailedActions failed with Error: " + e.getMessage());
throw (e);
}
}




private boolean retryFailedActionsInternal(int timeout) throws Exception {
try {
Log.d("ReactNative", "retryFailedActionsInternal started");
Expand Down Expand Up @@ -412,22 +463,22 @@ private boolean retryFailedActionsInternal(int timeout) throws Exception {
return true;
}*/
} else {
Log.d("ReactNative", "retryFailedActions failed because blox is offline");
Log.d("ReactNative", "retryFailedActionsInternal failed because blox is offline");
//Blox Offline
return false;
}
}
catch (Exception e) {
Log.d("ReactNative", "retryFailedActions failed with Error: " + e.getMessage());
Log.d("ReactNative", "retryFailedActionsInternal failed with Error: " + e.getMessage());
return false;
}
} else {
Log.d("ReactNative", "retryFailedActions failed because fula is not initialized");
Log.d("ReactNative", "retryFailedActionsInternal failed because fula is not initialized");
//Fula is not initialized
return false;
}
} catch (Exception e) {
Log.d("ReactNative", "retryFailedActions failed with Error: " + e.getMessage());
Log.d("ReactNative", "retryFailedActionsInternal failed with Error: " + e.getMessage());
throw (e);
}
}
Expand Down
44 changes: 44 additions & 0 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ import React from 'react';
import { StyleSheet, Text, View, Button, TextInput } from 'react-native';

import { fula, blockchain, chainApi, fxblox } from '@functionland/react-native-fula';
import { listFailedActions } from '../../.history/src/protocols/fula_20230710112519';

const App = () => {
const [key, setKey] = React.useState<string>('');
const [value, setValue] = React.useState<string>('');
const [inprogress, setInprogress] = React.useState<boolean>(false);
const [newRootCid, setNewRootCid] = React.useState<string>('');

const [initComplete, setInitComplete] = React.useState<
{ peerId: string; rootCid: string; private_ref: string } | {}
>({});

var RNFS = require('react-native-fs');
const readFile = () => {
RNFS.readDir(RNFS.DocumentDirectoryPath)
Expand Down Expand Up @@ -121,6 +124,7 @@ const App = () => {
if (resinit) {
console.log('init complete');
console.log(resinit);
setNewRootCid(resinit.rootCid);
} else {
console.log('wait for init to complete');
}
Expand Down Expand Up @@ -149,6 +153,46 @@ const App = () => {
color={inprogress ? 'green' : 'blue'}
/>

<Button
title={inprogress ? 'Putting & Getting...' : 'Test List Failed links for a one'}
onPress={async () => {
try {
console.log("checking: " + newRootCid);
fula
.listFailedActions([newRootCid])
.then((res) => {
console.log('tested');
console.log(res);
})
.catch((e) => {
console.log('test failed');
console.log(e);
});

} catch (e) {}
}}
color={inprogress ? 'green' : 'blue'}
/>
<Button
title={inprogress ? 'Putting & Getting...' : 'Test List Failed links for all'}
onPress={async () => {
try {
fula
.listFailedActions()
.then((res) => {
console.log('tested');
console.log(res);
})
.catch((e) => {
console.log('test failed');
console.log(e);
});

} catch (e) {}
}}
color={inprogress ? 'green' : 'blue'}
/>

<Button
title={inprogress ? 'Putting & Getting...' : 'Write WNFS'}
onPress={async () => {
Expand Down
1 change: 1 addition & 0 deletions src/interfaces/fulaNativeModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ interface FulaNativeModule {
isReady: (filesystemCheck: boolean) => Promise<boolean>;
logout: (identity: string, storePath: string) => Promise<boolean>;
checkFailedActions: (retry: boolean, timeout: number) => Promise<boolean>;
listFailedActions: (cids: string[]) => Promise<string[]>;
checkConnection: (timeout: number) => Promise<boolean>;
get: (key: string) => Promise<string>;
has: (key: Uint8Array) => Promise<boolean>;
Expand Down
7 changes: 7 additions & 0 deletions src/protocols/fula.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@ export const checkFailedActions = (
return Fula.checkFailedActions(retry, timeout);
};

/**
* Lists the cids that failed to be sent to backend and are kept only locally
*/
export const listFailedActions = (cids: string[] = []): Promise<string[]> => {
return Fula.listFailedActions(cids);
};

/**
* Checks if there are any un-synced changes on the device
*/
Expand Down

0 comments on commit be99b80

Please sign in to comment.