@functionland/react-native-fula 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +35 -0
- package/android/.gradle/7.5.1/checksums/checksums.lock +0 -0
- package/android/.gradle/7.5.1/checksums/md5-checksums.bin +0 -0
- package/android/.gradle/7.5.1/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/7.5.1/dependencies-accessors/dependencies-accessors.lock +0 -0
- package/android/.gradle/7.5.1/dependencies-accessors/gc.properties +0 -0
- package/android/.gradle/7.5.1/executionHistory/executionHistory.bin +0 -0
- package/android/.gradle/7.5.1/executionHistory/executionHistory.lock +0 -0
- package/android/.gradle/7.5.1/fileChanges/last-build.bin +0 -0
- package/android/.gradle/7.5.1/fileHashes/fileHashes.bin +0 -0
- package/android/.gradle/7.5.1/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/7.5.1/fileHashes/resourceHashesCache.bin +0 -0
- package/android/.gradle/7.5.1/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
- package/android/.gradle/buildOutputCleanup/outputFiles.bin +0 -0
- package/android/.gradle/file-system.probe +0 -0
- package/android/.gradle/vcs-1/gc.properties +0 -0
- package/android/.idea/compiler.xml +6 -0
- package/android/.idea/gradle.xml +19 -0
- package/android/.idea/jarRepositories.xml +50 -0
- package/android/.idea/misc.xml +10 -0
- package/android/.idea/vcs.xml +6 -0
- package/android/build.gradle +67 -0
- package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +6 -0
- package/android/gradle.properties +1 -0
- package/android/gradlew +240 -0
- package/android/gradlew.bat +91 -0
- package/android/local.properties +8 -0
- package/android/src/main/AndroidManifest.xml +4 -0
- package/android/src/main/java/land/fx/fula/ConfigRef.java +7 -0
- package/android/src/main/java/land/fx/fula/Cryptography.java +47 -0
- package/android/src/main/java/land/fx/fula/FulaModule.java +443 -0
- package/android/src/main/java/land/fx/fula/FulaPackage.java +32 -0
- package/android/src/main/java/land/fx/fula/SharedPreferenceHelper.java +65 -0
- package/android/src/main/java/land/fx/fula/StaticHelper.java +13 -0
- package/android/src/main/java/land/fx/fula/ThreadUtils.java +42 -0
- package/ios/FulaModule.h +10 -0
- package/ios/FulaModule.m +149 -0
- package/ios/FulaModule.xcodeproj/project.pbxproj +267 -0
- package/lib/commonjs/index.js +11 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/interfaces/fulaNativeModule.js +19 -0
- package/lib/commonjs/interfaces/fulaNativeModule.js.map +1 -0
- package/lib/commonjs/protocols/fula.js +130 -0
- package/lib/commonjs/protocols/fula.js.map +1 -0
- package/lib/module/index.js +3 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/interfaces/fulaNativeModule.js +12 -0
- package/lib/module/interfaces/fulaNativeModule.js.map +1 -0
- package/lib/module/protocols/fula.js +113 -0
- package/lib/module/protocols/fula.js.map +1 -0
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/interfaces/fulaNativeModule.d.ts +17 -0
- package/lib/typescript/protocols/fula.d.ts +70 -0
- package/package.json +152 -0
- package/react-native-fula.podspec +19 -0
- package/src/index.tsx +1 -0
- package/src/interfaces/fulaNativeModule.ts +39 -0
- package/src/protocols/fula.ts +116 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
package land.fx.fula;
|
|
2
|
+
|
|
3
|
+
import android.util.Base64;
|
|
4
|
+
|
|
5
|
+
import java.io.UnsupportedEncodingException;
|
|
6
|
+
import java.security.InvalidAlgorithmParameterException;
|
|
7
|
+
import java.security.InvalidKeyException;
|
|
8
|
+
import java.security.NoSuchAlgorithmException;
|
|
9
|
+
import java.security.spec.InvalidKeySpecException;
|
|
10
|
+
import java.security.spec.InvalidParameterSpecException;
|
|
11
|
+
|
|
12
|
+
import javax.crypto.BadPaddingException;
|
|
13
|
+
import javax.crypto.Cipher;
|
|
14
|
+
import javax.crypto.IllegalBlockSizeException;
|
|
15
|
+
import javax.crypto.NoSuchPaddingException;
|
|
16
|
+
import javax.crypto.SecretKey;
|
|
17
|
+
import javax.crypto.SecretKeyFactory;
|
|
18
|
+
import javax.crypto.spec.PBEKeySpec;
|
|
19
|
+
import javax.crypto.spec.SecretKeySpec;
|
|
20
|
+
|
|
21
|
+
public class Cryptography {
|
|
22
|
+
public static String encryptMsg(String message, SecretKey secret)
|
|
23
|
+
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidParameterSpecException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
|
|
24
|
+
Cipher cipher = null;
|
|
25
|
+
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
|
26
|
+
cipher.init(Cipher.ENCRYPT_MODE, secret);
|
|
27
|
+
byte[] cipherText = cipher.doFinal(message.getBytes("UTF-8"));
|
|
28
|
+
return Base64.encodeToString(cipherText, Base64.NO_WRAP);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public static String decryptMsg(String cipherText, SecretKey secret)
|
|
32
|
+
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidParameterSpecException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException {
|
|
33
|
+
Cipher cipher = null;
|
|
34
|
+
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
|
35
|
+
cipher.init(Cipher.DECRYPT_MODE, secret);
|
|
36
|
+
byte[] decode = Base64.decode(cipherText, Base64.NO_WRAP);
|
|
37
|
+
String decryptString = new String(cipher.doFinal(decode), "UTF-8");
|
|
38
|
+
return decryptString;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public static SecretKey generateKey(byte[] key)
|
|
42
|
+
throws NoSuchAlgorithmException, InvalidKeySpecException {
|
|
43
|
+
PBEKeySpec pbeKeySpec = new PBEKeySpec(StaticHelper.bytesToBase64(key).toCharArray(), key, 1000, 128);
|
|
44
|
+
SecretKey pbeKey = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256").generateSecret(pbeKeySpec);
|
|
45
|
+
return new SecretKeySpec(pbeKey.getEncoded(), "AES");
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
package land.fx.fula;
|
|
2
|
+
|
|
3
|
+
import android.util.Log;
|
|
4
|
+
|
|
5
|
+
import androidx.annotation.NonNull;
|
|
6
|
+
|
|
7
|
+
import com.facebook.react.bridge.Promise;
|
|
8
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
9
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
10
|
+
import com.facebook.react.bridge.ReactMethod;
|
|
11
|
+
import com.facebook.react.module.annotations.ReactModule;
|
|
12
|
+
|
|
13
|
+
import org.jetbrains.annotations.Contract;
|
|
14
|
+
|
|
15
|
+
import java.io.File;
|
|
16
|
+
import java.nio.charset.StandardCharsets;
|
|
17
|
+
import java.util.Arrays;
|
|
18
|
+
|
|
19
|
+
import javax.crypto.SecretKey;
|
|
20
|
+
|
|
21
|
+
import fulamobile.Config;
|
|
22
|
+
import fulamobile.Fulamobile;
|
|
23
|
+
|
|
24
|
+
import land.fx.wnfslib.LibKt;
|
|
25
|
+
|
|
26
|
+
@ReactModule(name = FulaModule.NAME)
|
|
27
|
+
public class FulaModule extends ReactContextBaseJavaModule {
|
|
28
|
+
public static final String NAME = "FulaModule";
|
|
29
|
+
fulamobile.Client fula;
|
|
30
|
+
Client client;
|
|
31
|
+
String appDir;
|
|
32
|
+
String fulaStorePath;
|
|
33
|
+
String privateForest;
|
|
34
|
+
land.fx.wnfslib.Config rootConfig;
|
|
35
|
+
SharedPreferenceHelper sharedPref;
|
|
36
|
+
static String PRIVATE_KEY_STORE_ID = "PRIVATE_KEY";
|
|
37
|
+
|
|
38
|
+
public class Client implements land.fx.wnfslib.Client {
|
|
39
|
+
|
|
40
|
+
private fulamobile.Client internalClient;
|
|
41
|
+
|
|
42
|
+
Client(fulamobile.Client clientInput) {
|
|
43
|
+
internalClient = clientInput;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@NonNull
|
|
47
|
+
@Override
|
|
48
|
+
public byte[] get(@NonNull byte[] cid) {
|
|
49
|
+
try {
|
|
50
|
+
internalClient.get(cid);
|
|
51
|
+
} catch (Exception e) {
|
|
52
|
+
e.printStackTrace();
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@NonNull
|
|
58
|
+
@Override
|
|
59
|
+
public byte[] put(@NonNull byte[] data, long codec) {
|
|
60
|
+
try {
|
|
61
|
+
return client.put(data, codec);
|
|
62
|
+
} catch (Exception e) {
|
|
63
|
+
e.printStackTrace();
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public FulaModule(ReactApplicationContext reactContext) {
|
|
70
|
+
super(reactContext);
|
|
71
|
+
appDir = reactContext.getFilesDir().toString();
|
|
72
|
+
fulaStorePath = appDir + "/fula";
|
|
73
|
+
File storeDir = new File(fulaStorePath);
|
|
74
|
+
sharedPref = SharedPreferenceHelper.getInstance(reactContext.getApplicationContext());
|
|
75
|
+
boolean success = true;
|
|
76
|
+
if (!storeDir.exists()) {
|
|
77
|
+
success = storeDir.mkdirs();
|
|
78
|
+
}
|
|
79
|
+
if (success) {
|
|
80
|
+
Log.d(NAME, "Fula store folder created");
|
|
81
|
+
} else {
|
|
82
|
+
Log.d(NAME, "Unable to create fula store folder!");
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@Override
|
|
87
|
+
@NonNull
|
|
88
|
+
public String getName() {
|
|
89
|
+
return NAME;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
private byte[] toByte(@NonNull String input) {
|
|
94
|
+
return input.getBytes(StandardCharsets.UTF_8);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
@NonNull
|
|
98
|
+
@Contract("_ -> new")
|
|
99
|
+
private String toString(byte[] input) {
|
|
100
|
+
return new String(input, StandardCharsets.UTF_8);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
@NonNull
|
|
104
|
+
private static int[] stringArrToIntArr(@NonNull String[] s) {
|
|
105
|
+
int[] result = new int[s.length];
|
|
106
|
+
for (int i = 0; i < s.length; i++) {
|
|
107
|
+
result[i] = Integer.parseInt(s[i]);
|
|
108
|
+
}
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@NonNull
|
|
113
|
+
@Contract(pure = true)
|
|
114
|
+
private static byte[] convertIntToByte(@NonNull int[] input) {
|
|
115
|
+
byte[] result = new byte[input.length];
|
|
116
|
+
for (int i = 0; i < input.length; i++) {
|
|
117
|
+
byte b = (byte) input[i];
|
|
118
|
+
result[i] = b;
|
|
119
|
+
}
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
@NonNull
|
|
124
|
+
private static byte[] convertStringToByte(@NonNull String data) {
|
|
125
|
+
String[] keyInt_S = data.split(",");
|
|
126
|
+
int[] keyInt = stringArrToIntArr(keyInt_S);
|
|
127
|
+
|
|
128
|
+
return convertIntToByte(keyInt);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
@ReactMethod
|
|
132
|
+
public void init(String identityString, String storePath, String bloxAddr, Promise promise) {
|
|
133
|
+
Log.d("ReactNative", "init started");
|
|
134
|
+
ThreadUtils.runOnExecutor(() -> {
|
|
135
|
+
try {
|
|
136
|
+
Log.d("ReactNative", "init storePath= " + storePath);
|
|
137
|
+
byte[] identity = toByte(identityString);
|
|
138
|
+
Log.d("ReactNative", "init identity= " + identityString);
|
|
139
|
+
String[] obj = initInternal(identity, storePath, bloxAddr);
|
|
140
|
+
Log.d("ReactNative", "init object created: [ " + obj[0] + ", " + obj[1] + ", " + obj[2] + " ]");
|
|
141
|
+
promise.resolve(obj);
|
|
142
|
+
} catch (Exception e) {
|
|
143
|
+
Log.d("ReactNative", "init failed with Error: " + e.getMessage());
|
|
144
|
+
promise.reject(e);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
@NonNull
|
|
150
|
+
private byte[] createPeerIdentity(byte[] privateKey) throws Exception {
|
|
151
|
+
try {
|
|
152
|
+
// 1: First: create public key from provided private key
|
|
153
|
+
// 2: Should read the local keychain store (if it is key-value, key is public key above,
|
|
154
|
+
// 3: if found, decrypt using the private key
|
|
155
|
+
// 4: If not found or decryption not successful, generate an identity
|
|
156
|
+
// 5: then encrypt and store in keychain
|
|
157
|
+
|
|
158
|
+
String encryptedKey = sharedPref.getValue(PRIVATE_KEY_STORE_ID);
|
|
159
|
+
SecretKey secretKey = Cryptography.generateKey(privateKey);
|
|
160
|
+
if (encryptedKey == null) {
|
|
161
|
+
byte[] autoGeneratedIdentity = Fulamobile.generateEd25519Key();
|
|
162
|
+
encryptedKey = Cryptography.encryptMsg(StaticHelper.bytesToBase64(autoGeneratedIdentity), secretKey);
|
|
163
|
+
sharedPref.add(PRIVATE_KEY_STORE_ID, encryptedKey);
|
|
164
|
+
}
|
|
165
|
+
return StaticHelper.base64ToBytes(Cryptography.decryptMsg(encryptedKey, secretKey));
|
|
166
|
+
|
|
167
|
+
} catch (Exception e) {
|
|
168
|
+
Log.d("ReactNative", "createPeerIdentity failed with Error: " + e.getMessage());
|
|
169
|
+
throw (e);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
@NonNull
|
|
174
|
+
private String[] initInternal(byte[] identity, String storePath, String bloxAddr) throws Exception {
|
|
175
|
+
try {
|
|
176
|
+
Config config_ext = new Config();
|
|
177
|
+
if (storePath == null || storePath.trim().isEmpty()) {
|
|
178
|
+
config_ext.setStorePath(fulaStorePath);
|
|
179
|
+
} else {
|
|
180
|
+
config_ext.setStorePath(storePath);
|
|
181
|
+
}
|
|
182
|
+
Log.d("ReactNative", "storePath is set: " + config_ext.getStorePath());
|
|
183
|
+
|
|
184
|
+
byte[] peerIdentity = createPeerIdentity(identity);
|
|
185
|
+
config_ext.setIdentity(peerIdentity);
|
|
186
|
+
Log.d("ReactNative", "peerIdentity is set: " + toString(config_ext.getIdentity()));
|
|
187
|
+
config_ext.setBloxAddr(bloxAddr);
|
|
188
|
+
Log.d("ReactNative", "bloxAddr is set: " + config_ext.getBloxAddr());
|
|
189
|
+
this.fula = Fulamobile.newClient(config_ext);
|
|
190
|
+
this.client = new Client(this.fula);
|
|
191
|
+
Log.d("ReactNative", "fula initialized: " + this.fula.id());
|
|
192
|
+
if (this.rootConfig == null) {
|
|
193
|
+
Log.d("ReactNative", "creating rootConfig");
|
|
194
|
+
this.privateForest = LibKt.createPrivateForest(this.client);
|
|
195
|
+
Log.d("ReactNative", "privateForest is created: " + this.privateForest);
|
|
196
|
+
this.rootConfig = LibKt.createRootDir(this.client, this.privateForest);
|
|
197
|
+
Log.d("ReactNative", "rootConfig is created: " + this.rootConfig.getCid());
|
|
198
|
+
} else {
|
|
199
|
+
Log.d("ReactNative", "rootConfig existed: " + this.rootConfig.getCid());
|
|
200
|
+
}
|
|
201
|
+
String peerId = this.fula.id();
|
|
202
|
+
String[] obj = new String[3];
|
|
203
|
+
obj[0] = peerId;
|
|
204
|
+
obj[1] = this.rootConfig.getCid();
|
|
205
|
+
obj[2] = this.rootConfig.getPrivate_ref();
|
|
206
|
+
Log.d("ReactNative", "initInternal is completed successfully");
|
|
207
|
+
return obj;
|
|
208
|
+
} catch (Exception e) {
|
|
209
|
+
Log.d("ReactNative", "init internal failed with Error: " + e.getMessage());
|
|
210
|
+
throw (e);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
@ReactMethod
|
|
215
|
+
public void mkdir(String path, Promise promise) {
|
|
216
|
+
ThreadUtils.runOnExecutor(() -> {
|
|
217
|
+
Log.d("ReactNative", "mkdir: path = " + path);
|
|
218
|
+
try {
|
|
219
|
+
land.fx.wnfslib.Config config = LibKt.mkdir(this.client, this.rootConfig.getCid(), this.rootConfig.getPrivate_ref(), path);
|
|
220
|
+
this.rootConfig = config;
|
|
221
|
+
promise.resolve(config.getCid());
|
|
222
|
+
} catch (Exception e) {
|
|
223
|
+
Log.d("get", e.getMessage());
|
|
224
|
+
promise.reject(e);
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
@ReactMethod
|
|
230
|
+
public void writeFile(String fulaTargetFilename, String localFilename, Promise promise) {
|
|
231
|
+
/*
|
|
232
|
+
// reads content of the file form localFilename (should include full absolute path to local file with read permission
|
|
233
|
+
// writes content to the specified location by fulaTargetFilename in Fula filesystem
|
|
234
|
+
// fulaTargetFilename: a string including full path and filename of target file on Fula (e.g. root/pictures/cat.jpg)
|
|
235
|
+
// localFilename: a string containing full path and filename of local file on hte device (e.g /usr/bin/cat.jpg)
|
|
236
|
+
// Returns: new cid of the root after this file is placed in the tree
|
|
237
|
+
*/
|
|
238
|
+
ThreadUtils.runOnExecutor(() -> {
|
|
239
|
+
Log.d("ReactNative", "writeFile to : path = " + fulaTargetFilename + ", from: " + localFilename);
|
|
240
|
+
try {
|
|
241
|
+
land.fx.wnfslib.Config config = LibKt.writeFileFromPath(this.client, this.rootConfig.getCid(), this.rootConfig.getPrivate_ref(), fulaTargetFilename, localFilename);
|
|
242
|
+
this.rootConfig = config;
|
|
243
|
+
promise.resolve(config.getCid());
|
|
244
|
+
} catch (Exception e) {
|
|
245
|
+
Log.d("get", e.getMessage());
|
|
246
|
+
promise.reject(e);
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
@ReactMethod
|
|
252
|
+
public void writeFileContent(String path, String contentString, Promise promise) {
|
|
253
|
+
ThreadUtils.runOnExecutor(() -> {
|
|
254
|
+
Log.d("ReactNative", "writeFile: contentString = " + contentString);
|
|
255
|
+
Log.d("ReactNative", "writeFile: path = " + path);
|
|
256
|
+
try {
|
|
257
|
+
byte[] content = convertStringToByte(contentString);
|
|
258
|
+
land.fx.wnfslib.Config config = LibKt.writeFile(this.client, this.rootConfig.getCid(), this.rootConfig.getPrivate_ref(), path, content);
|
|
259
|
+
this.rootConfig = config;
|
|
260
|
+
promise.resolve(config.getCid());
|
|
261
|
+
} catch (Exception e) {
|
|
262
|
+
Log.d("get", e.getMessage());
|
|
263
|
+
promise.reject(e);
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
@ReactMethod
|
|
269
|
+
public void ls(String path, Promise promise) {
|
|
270
|
+
ThreadUtils.runOnExecutor(() -> {
|
|
271
|
+
Log.d("ReactNative", "ls: path = " + path);
|
|
272
|
+
try {
|
|
273
|
+
String res = LibKt.ls(this.client, this.rootConfig.getCid(), this.rootConfig.getPrivate_ref(), path);
|
|
274
|
+
promise.resolve(res);
|
|
275
|
+
} catch (Exception e) {
|
|
276
|
+
Log.d("get", e.getMessage());
|
|
277
|
+
promise.reject(e);
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
@ReactMethod
|
|
283
|
+
public void readFile(String path, Promise promise) {
|
|
284
|
+
ThreadUtils.runOnExecutor(() -> {
|
|
285
|
+
Log.d("ReactNative", "ls: path = " + path);
|
|
286
|
+
try {
|
|
287
|
+
byte[] res = LibKt.readFile(this.client, this.rootConfig.getCid(), this.rootConfig.getPrivate_ref(), path);
|
|
288
|
+
String resString = toString(res);
|
|
289
|
+
promise.resolve(resString);
|
|
290
|
+
} catch (Exception e) {
|
|
291
|
+
Log.d("get", e.getMessage());
|
|
292
|
+
promise.reject(e);
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
@ReactMethod
|
|
298
|
+
public void get(String keyString, Promise promise) {
|
|
299
|
+
ThreadUtils.runOnExecutor(() -> {
|
|
300
|
+
Log.d("ReactNative", "get: keyString = " + keyString);
|
|
301
|
+
try {
|
|
302
|
+
byte[] key = convertStringToByte(keyString);
|
|
303
|
+
byte[] value = getInternal(key);
|
|
304
|
+
String valueString = toString(value);
|
|
305
|
+
promise.resolve(valueString);
|
|
306
|
+
} catch (Exception e) {
|
|
307
|
+
Log.d("get", e.getMessage());
|
|
308
|
+
promise.reject(e);
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
@NonNull
|
|
314
|
+
private byte[] getInternal(byte[] key) throws Exception {
|
|
315
|
+
try {
|
|
316
|
+
Log.d("ReactNative", "getInternal: key.toString() = " + toString(key));
|
|
317
|
+
Log.d("ReactNative", "getInternal: key.toString().bytes = " + Arrays.toString(key));
|
|
318
|
+
byte[] value = this.fula.get(key);
|
|
319
|
+
Log.d("ReactNative", "getInternal: value.toString() = " + toString(value));
|
|
320
|
+
return value;
|
|
321
|
+
} catch (Exception e) {
|
|
322
|
+
Log.d("ReactNative", "getInternal: error = " + e.getMessage());
|
|
323
|
+
Log.d("getInternal", e.getMessage());
|
|
324
|
+
throw (e);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
@ReactMethod
|
|
329
|
+
public void has(String keyString, Promise promise) {
|
|
330
|
+
ThreadUtils.runOnExecutor(() -> {
|
|
331
|
+
Log.d("ReactNative", "has: keyString = " + keyString);
|
|
332
|
+
try {
|
|
333
|
+
byte[] key = convertStringToByte(keyString);
|
|
334
|
+
boolean result = hasInternal(key);
|
|
335
|
+
promise.resolve(result);
|
|
336
|
+
} catch (Exception e) {
|
|
337
|
+
Log.d("get", e.getMessage());
|
|
338
|
+
promise.reject(e);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
@NonNull
|
|
344
|
+
private boolean hasInternal(byte[] key) throws Exception {
|
|
345
|
+
try {
|
|
346
|
+
boolean res = this.fula.has(key);
|
|
347
|
+
return res;
|
|
348
|
+
} catch (Exception e) {
|
|
349
|
+
Log.d("hasInternal", e.getMessage());
|
|
350
|
+
throw (e);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
@NonNull
|
|
355
|
+
private void pullInternal(byte[] key) throws Exception {
|
|
356
|
+
try {
|
|
357
|
+
this.fula.pull(key);
|
|
358
|
+
} catch (Exception e) {
|
|
359
|
+
Log.d("pullInternal", e.getMessage());
|
|
360
|
+
throw (e);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
@ReactMethod
|
|
365
|
+
public void push(Promise promise) {
|
|
366
|
+
ThreadUtils.runOnExecutor(() -> {
|
|
367
|
+
Log.d("ReactNative", "push started");
|
|
368
|
+
try {
|
|
369
|
+
pushInternal(convertStringToByte(this.rootConfig.getCid()));
|
|
370
|
+
promise.resolve(this.rootConfig.getCid());
|
|
371
|
+
} catch (Exception e) {
|
|
372
|
+
Log.d("get", e.getMessage());
|
|
373
|
+
promise.reject(e);
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
@NonNull
|
|
379
|
+
private void pushInternal(byte[] key) throws Exception {
|
|
380
|
+
try {
|
|
381
|
+
if (this.fula.has(key)) {
|
|
382
|
+
this.fula.push(key);
|
|
383
|
+
} else {
|
|
384
|
+
Log.d("pushInternal", "error: key wasn't found");
|
|
385
|
+
throw new Exception("key wasn't found in local storage");
|
|
386
|
+
}
|
|
387
|
+
} catch (Exception e) {
|
|
388
|
+
Log.d("pushInternal", e.getMessage());
|
|
389
|
+
throw (e);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
@ReactMethod
|
|
394
|
+
public void put(String valueString, String codecString, Promise promise) {
|
|
395
|
+
ThreadUtils.runOnExecutor(() -> {
|
|
396
|
+
Log.d("ReactNative", "put: codecString = " + codecString);
|
|
397
|
+
Log.d("ReactNative", "put: valueString = " + valueString);
|
|
398
|
+
try {
|
|
399
|
+
//byte[] codec = convertStringToByte(CodecString);
|
|
400
|
+
long codec = Long.parseLong(codecString);
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
Log.d("ReactNative", "put: codec = " + codec);
|
|
404
|
+
byte[] value = toByte(valueString);
|
|
405
|
+
|
|
406
|
+
Log.d("ReactNative", "put: value.toString() = " + toString(value));
|
|
407
|
+
byte[] key = putInternal(value, codec);
|
|
408
|
+
Log.d("ReactNative", "put: key.toString() = " + toString(key));
|
|
409
|
+
promise.resolve(toString(key));
|
|
410
|
+
} catch (Exception e) {
|
|
411
|
+
Log.d("ReactNative", "put: error = " + e.getMessage());
|
|
412
|
+
Log.d("put", e.getMessage());
|
|
413
|
+
promise.reject(e);
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
@NonNull
|
|
419
|
+
private byte[] putInternal(byte[] value, long codec) throws Exception {
|
|
420
|
+
try {
|
|
421
|
+
byte[] key = this.fula.put(value, codec);
|
|
422
|
+
return key;
|
|
423
|
+
} catch (Exception e) {
|
|
424
|
+
Log.d("putInternal", e.getMessage());
|
|
425
|
+
throw (e);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
@ReactMethod
|
|
430
|
+
public void shutdown(Promise promise) {
|
|
431
|
+
ThreadUtils.runOnExecutor(() -> {
|
|
432
|
+
try {
|
|
433
|
+
fula.shutdown();
|
|
434
|
+
promise.resolve(true);
|
|
435
|
+
} catch (Exception e) {
|
|
436
|
+
promise.reject(e);
|
|
437
|
+
Log.d("shutdown", e.getMessage());
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
package land.fx.fula;
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.NonNull;
|
|
4
|
+
|
|
5
|
+
import com.facebook.react.ReactPackage;
|
|
6
|
+
import com.facebook.react.bridge.NativeModule;
|
|
7
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
8
|
+
import com.facebook.react.uimanager.ViewManager;
|
|
9
|
+
|
|
10
|
+
import java.util.ArrayList;
|
|
11
|
+
import java.util.Collections;
|
|
12
|
+
import java.util.List;
|
|
13
|
+
|
|
14
|
+
public class FulaPackage implements ReactPackage {
|
|
15
|
+
@NonNull
|
|
16
|
+
@Override
|
|
17
|
+
public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
|
|
18
|
+
List<NativeModule> modules = new ArrayList<>();
|
|
19
|
+
try {
|
|
20
|
+
modules.add(new FulaModule(reactContext));
|
|
21
|
+
} catch (Exception e) {
|
|
22
|
+
e.printStackTrace();
|
|
23
|
+
}
|
|
24
|
+
return modules;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@NonNull
|
|
28
|
+
@Override
|
|
29
|
+
public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
|
|
30
|
+
return Collections.emptyList();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
package land.fx.fula;
|
|
2
|
+
|
|
3
|
+
import static android.content.Context.MODE_PRIVATE;
|
|
4
|
+
|
|
5
|
+
import android.content.Context;
|
|
6
|
+
import android.content.SharedPreferences;
|
|
7
|
+
import android.util.Log;
|
|
8
|
+
|
|
9
|
+
public class SharedPreferenceHelper {
|
|
10
|
+
private static SharedPreferenceHelper me;
|
|
11
|
+
private static String sharedPrefName;
|
|
12
|
+
private static Context context;
|
|
13
|
+
|
|
14
|
+
private SharedPreferenceHelper() {
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public static SharedPreferenceHelper getInstance(Context cntx) {
|
|
18
|
+
if (me == null) {
|
|
19
|
+
me = new SharedPreferenceHelper();
|
|
20
|
+
}
|
|
21
|
+
context = cntx;
|
|
22
|
+
sharedPrefName = "APP_KEY_PAIR_VALUE";
|
|
23
|
+
return me;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public String getValue(String key) {
|
|
27
|
+
SharedPreferences prefs = context.getSharedPreferences(sharedPrefName, MODE_PRIVATE);
|
|
28
|
+
return prefs.getString(key, null);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public boolean getBooleanValue(String key) {
|
|
32
|
+
SharedPreferences prefs = context.getSharedPreferences(sharedPrefName, MODE_PRIVATE);
|
|
33
|
+
return prefs.getBoolean(key, false);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public SharedPreferenceHelper add(String key, String value) {
|
|
37
|
+
try {
|
|
38
|
+
context.getSharedPreferences(sharedPrefName, MODE_PRIVATE).edit().putString(key, value).apply();
|
|
39
|
+
return me;
|
|
40
|
+
} catch (Exception ex) {
|
|
41
|
+
Log.e("React-Native-Fula", "SharedPrefHandler: AddSharedPref: Exception: " + ex.getMessage(), ex);
|
|
42
|
+
throw ex;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public SharedPreferenceHelper add(String key, boolean value) {
|
|
47
|
+
try {
|
|
48
|
+
context.getSharedPreferences(sharedPrefName, MODE_PRIVATE).edit().putBoolean(key, value).apply();
|
|
49
|
+
return me;
|
|
50
|
+
} catch (Exception e) {
|
|
51
|
+
Log.e("React-Native-Fula", "SharedPrefHandler: AddSharedPref: Exception: " + e.getMessage(), e);
|
|
52
|
+
throw e;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public SharedPreferenceHelper remove(String key) {
|
|
57
|
+
try {
|
|
58
|
+
context.getSharedPreferences(sharedPrefName, MODE_PRIVATE).edit().remove(key).apply();
|
|
59
|
+
return me;
|
|
60
|
+
} catch (Exception ex) {
|
|
61
|
+
Log.e("React-Native-Fula", "SharedPrefHandler: AddSharedPref: Exception: " + ex.getMessage(), ex);
|
|
62
|
+
throw ex;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
package land.fx.fula;
|
|
2
|
+
|
|
3
|
+
import java.util.Base64;
|
|
4
|
+
|
|
5
|
+
public class StaticHelper {
|
|
6
|
+
public static String bytesToBase64(byte[] bytes) {
|
|
7
|
+
return Base64.getEncoder().encodeToString(bytes);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
public static byte[] base64ToBytes(String base64) {
|
|
11
|
+
return Base64.getDecoder().decode(base64);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
package land.fx.fula;
|
|
2
|
+
|
|
3
|
+
import java.util.concurrent.Callable;
|
|
4
|
+
import java.util.concurrent.ExecutorService;
|
|
5
|
+
import java.util.concurrent.Executors;
|
|
6
|
+
import java.util.concurrent.Future;
|
|
7
|
+
|
|
8
|
+
final class ThreadUtils {
|
|
9
|
+
/**
|
|
10
|
+
* Thread which will be used to call all APIs. They
|
|
11
|
+
* they don't run on the calling thread anyway, we are deferring the calls
|
|
12
|
+
* to this thread to avoid (potentially) blocking the calling thread.
|
|
13
|
+
*/
|
|
14
|
+
private static final ExecutorService executor
|
|
15
|
+
= Executors.newSingleThreadExecutor();
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Runs the given {@link Runnable} on the executor.
|
|
19
|
+
* @param runnable
|
|
20
|
+
*/
|
|
21
|
+
public static void runOnExecutor(Runnable runnable) {
|
|
22
|
+
executor.execute(runnable);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Submits the given {@link Callable} to be run on the executor.
|
|
27
|
+
* @param callable
|
|
28
|
+
* @return Future.
|
|
29
|
+
*/
|
|
30
|
+
public static <T> Future<T> submitToExecutor(Callable<T> callable) {
|
|
31
|
+
return executor.submit(callable);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Submits the given {@link Runnable} to be run on the executor.
|
|
36
|
+
* @param runnable
|
|
37
|
+
* @return Future.
|
|
38
|
+
*/
|
|
39
|
+
public static Future<?> submitToExecutor(Runnable runnable) {
|
|
40
|
+
return executor.submit(runnable);
|
|
41
|
+
}
|
|
42
|
+
}
|