Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
284f9a0992 | ||
|
|
49ea163a59 | ||
|
|
dc6ab3cf27 | ||
|
|
dd1f2a222b | ||
|
|
dff2d0259b | ||
|
|
6757cd4dd0 | ||
|
|
7040e63e41 | ||
|
|
2ed5c9b376 | ||
|
|
98ef3d59f8 | ||
|
|
b2624f4db1 | ||
|
|
1b26a8f5f5 | ||
|
|
e4d75ffdee | ||
|
|
0c2ab3dd5e | ||
|
|
a0990d17c2 | ||
|
|
6dea7bb417 | ||
|
|
a32ebd6bd2 | ||
|
|
f7022b9c7b | ||
|
|
3c2371252d | ||
|
|
3ab9bb046b |
+2
-2
@@ -67,6 +67,6 @@ android/keystores/debug.keystore
|
||||
lib/
|
||||
|
||||
tmp/
|
||||
android/libs/gowaku-sources.jar
|
||||
android/libs/gowaku.aar
|
||||
gowaku-sources.jar
|
||||
gowaku.aar
|
||||
ios/Gowaku.xcframework
|
||||
@@ -6,16 +6,20 @@ Waku React Native
|
||||
npm install @waku/react-native
|
||||
```
|
||||
|
||||
Edit `settings.gradle` from your app and add:
|
||||
```
|
||||
include ':gowaku'
|
||||
project(':gowaku').projectDir = new File(rootProject.projectDir, './../node_modules/@waku/react-native/android/gowaku')
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
import { multiply } from "@waku/react-native";
|
||||
|
||||
// ...
|
||||
|
||||
const result = await multiply(3, 7);
|
||||
import * as waku from "@waku/react-native";
|
||||
```
|
||||
|
||||
See also [Fixing `route ip+net: netlinkrib: permission denied` in android](android-netlink.md)
|
||||
|
||||
## Contributing
|
||||
|
||||
See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
# Fixing `route ip+net: netlinkrib: permission denied` in android
|
||||
|
||||
|
||||
The details for this error can be seen in https://github.com/ipfs-shipyard/gomobile-ipfs/issues/68, and happens when targeting android API version +30. (`targetSdkVersion 30` in your `gradle.properties` / `build.gradle`) In this issue a possible solution was described which involved all the steps shown below. I have modified these to take in account that we are using +Go 1.18 as well as using a newer version of the Android NDK. These instructions should be used until https://github.com/golang/go/issues/40569 is fixed and a new gomobile version is released that includes this fix
|
||||
|
||||
|
||||
### Installing the requirements to build go-waku for android
|
||||
|
||||
These instructions assume that you are running Ubuntu, have NodeJS installed, and don't have any of the go and android required software installed. `root` access is required. Paths containing `/home/YOUR_USER` are referenced in different places. Replace `YOUR_USER` with your username (obtained with `whoami`). Don't blindly copy/paste the commands (It's not a good practice anyway)
|
||||
|
||||
**Installing required dependencies**
|
||||
```
|
||||
sudo apt update
|
||||
sudo apt install build-essential unzip openjdk-11-jdk
|
||||
```
|
||||
|
||||
**Installing Go 1.18**
|
||||
```
|
||||
wget https://go.dev/dl/go1.18.6.linux-amd64.tar.gz
|
||||
sudo rm -rf /usr/local/go
|
||||
sudo tar -C /usr/local -xzf go1.18.6.linux-amd64.tar.gz
|
||||
export PATH=$PATH:/usr/local/go/bin
|
||||
```
|
||||
|
||||
**Installing the Android NDK 25**
|
||||
```
|
||||
mkdir -p /home/YOUR_USER/Android/Sdk/
|
||||
wget https://dl.google.com/android/repository/android-ndk-r25b-linux.zip
|
||||
unzip android-ndk-r25b-linux.zip
|
||||
mv -r android-ndk-r25b /home/YOUR_USER/Android/Sdk/ndk
|
||||
export ANDROID_NDK_HOME=/home/YOUR_USER/Android/Sdk/ndk
|
||||
```
|
||||
|
||||
**Installing the Android SDK command line tools and android-30**
|
||||
```
|
||||
mkdir /home/YOUR_USER/Android/Sdk/cmdline-tools
|
||||
wget https://dl.google.com/android/repository/commandlinetools-linux-8512546_latest.zip
|
||||
unzip commandlinetools-linux-8512546_latest.zip
|
||||
mv cmdline-tools /home/YOUR_USER/Android/Sdk/cmdline-tools/latest
|
||||
export PATH=$PATH:/home/YOUR_USER/Android/Sdk/cmdline-tools/latest/bin
|
||||
sdkmanager "platform-tools" "platforms;android-30"
|
||||
```
|
||||
|
||||
### Building go-waku for android
|
||||
```
|
||||
mkdir -p /home/YOUR_USER/go/src/github.com/waku-org
|
||||
cd /home/YOUR_USER/go/src/github.com/status-im
|
||||
git clone https://github.com/waku-org/go-waku
|
||||
cd go-waku
|
||||
echo "replace github.com/multiformats/go-multiaddr v0.7.0 => github.com/waku-org/go-multiaddr v0.0.0-20230105211400-b3bd508cf855" >> go.mod
|
||||
export GO111MODULE=off
|
||||
go get golang.org/x/mobile/cmd/gobind
|
||||
go get golang.org/x/mobile/cmd/gomobile
|
||||
export GO111MODULE=on
|
||||
gomobile init
|
||||
export GO111MODULE=off
|
||||
gomobile bind -v -target=android -androidapi=23 -ldflags="-s -w" -v -o ./build/lib/gowaku.aar ./mobile
|
||||
```
|
||||
|
||||
### Edit waku-react-native
|
||||
```
|
||||
mkdir -p /home/YOUR_USER/waku
|
||||
cd /home/YOUR_USER/waku
|
||||
git clone https://github.com/waku-org/waku-react-native
|
||||
cd waku-react-native
|
||||
npm install
|
||||
./download-gowaku.sh
|
||||
cp /home/YOUR_USER/go/src/github.com/waku-org/build/lib/gowaku.aar ./android/libs/.
|
||||
```
|
||||
|
||||
### Edit your react-native project
|
||||
**Edit packages.json**
|
||||
Set `@waku/react-native` to the absolute path of your local copy of `waku-react-native` downloaded in the previous step
|
||||
```json
|
||||
...
|
||||
"dependencies": {
|
||||
"@waku/react-native": "file:/home/YOUR_USER/waku/waku-react-native/",
|
||||
}
|
||||
...
|
||||
```
|
||||
And execute `npm install` (or `yarn`) to link your local dependency
|
||||
|
||||
**Edit metro.config.js**
|
||||
```js
|
||||
const { getDefaultConfig } = require('expo/metro-config');
|
||||
const exclusionList = require('metro-config/src/defaults/exclusionList');
|
||||
const path = require('path');
|
||||
|
||||
const root = '/home/YOUR_USER/waku/waku-react-native/';
|
||||
const pak = require(root + 'package.json');
|
||||
|
||||
module.exports = {
|
||||
// ...
|
||||
watchFolders: [root],
|
||||
resolver: {
|
||||
blacklistRE: exclusionList(
|
||||
Object
|
||||
.keys({...pak.peerDependencies})
|
||||
.map(m => new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`))
|
||||
),
|
||||
extraNodeModules: new Proxy(
|
||||
{},
|
||||
{
|
||||
get: (target, name) => {
|
||||
if (target.hasOwnProperty(name)) {
|
||||
return target[name]
|
||||
}
|
||||
return path.join(process.cwd(), `node_modules/${name}`)
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
}
|
||||
```
|
||||
If you're using `expo`, in `waku-react-native`'s example app, you can see an example configuration achieving the same result
|
||||
|
||||
**Edit your application `android/build.gradle`**
|
||||
Add `gowaku.aar` to the list of dependencies
|
||||
```js
|
||||
...
|
||||
dependencies {
|
||||
|
||||
implementation files("$rootDir/../node_modules/@waku/react-native/android/libs/gowaku.aar")
|
||||
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
**Edit `MainApplication.java`**
|
||||
|
||||
```java
|
||||
// Add the following imports
|
||||
import go.Seq;
|
||||
import java.lang.StringBuilder;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InterfaceAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
...
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
// ...
|
||||
|
||||
// Add this line so that if RunOnJVM() with golang.org/x/mobile/app to call JAVA from GO,
|
||||
// will not cause error "no current JVM"
|
||||
Seq.setContext(getApplicationContext());
|
||||
}
|
||||
|
||||
...
|
||||
// Add this function
|
||||
// To fix [x/mobile: Calling net.InterfaceAddrs() fails on Android SDK 30](https://github.com/golang/go/issues/40569)
|
||||
// Ref to getInterfaces() in https://github.com/tailscale/tailscale-android/pull/21/files
|
||||
//
|
||||
// Returns details of the interfaces in the system, encoded as a single string for ease
|
||||
// of JNI transfer over to the Go environment.
|
||||
//
|
||||
// Example:
|
||||
// rmnet_data0 10 2000 true false false false false | fe80::4059:dc16:7ed3:9c6e%rmnet_data0/64
|
||||
// dummy0 3 1500 true false false false false | fe80::1450:5cff:fe13:f891%dummy0/64
|
||||
// wlan0 30 1500 true true false false true | fe80::2f60:2c82:4163:8389%wlan0/64 10.1.10.131/24
|
||||
// r_rmnet_data0 21 1500 true false false false false | fe80::9318:6093:d1ad:ba7f%r_rmnet_data0/64
|
||||
// rmnet_data2 12 1500 true false false false false | fe80::3c8c:44dc:46a9:9907%rmnet_data2/64
|
||||
// r_rmnet_data1 22 1500 true false false false false | fe80::b6cd:5cb0:8ae6:fe92%r_rmnet_data1/64
|
||||
// rmnet_data1 11 1500 true false false false false | fe80::51f2:ee00:edce:d68b%rmnet_data1/64
|
||||
// lo 1 65536 true false true false false | ::1/128 127.0.0.1/8
|
||||
// v4-rmnet_data2 68 1472 true true false true true | 192.0.0.4/32
|
||||
//
|
||||
// Where the fields are:
|
||||
// name ifindex mtu isUp hasBroadcast isLoopback isPointToPoint hasMulticast | ip1/N ip2/N ip3/N;
|
||||
String getInterfacesAsString() {
|
||||
List<NetworkInterface> interfaces;
|
||||
try {
|
||||
interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
|
||||
} catch (Exception e) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder("");
|
||||
for (NetworkInterface nif : interfaces) {
|
||||
try {
|
||||
// Android doesn't have a supportsBroadcast() but the Go net.Interface wants
|
||||
// one, so we say the interface has broadcast if it has multicast.
|
||||
sb.append(String.format(java.util.Locale.ROOT, "%s %d %d %b %b %b %b %b |", nif.getName(),
|
||||
nif.getIndex(), nif.getMTU(), nif.isUp(), nif.supportsMulticast(),
|
||||
nif.isLoopback(), nif.isPointToPoint(), nif.supportsMulticast()));
|
||||
|
||||
for (InterfaceAddress ia : nif.getInterfaceAddresses()) {
|
||||
// InterfaceAddress == hostname + "/" + IP
|
||||
String[] parts = ia.toString().split("/", 0);
|
||||
if (parts.length > 1) {
|
||||
sb.append(String.format(java.util.Locale.ROOT, "%s/%d ", parts[1], ia.getNetworkPrefixLength()));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// TODO(dgentry) should log the exception not silently suppress it.
|
||||
continue;
|
||||
}
|
||||
sb.append("\n");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
...
|
||||
|
||||
```
|
||||
|
||||
After this step, build your app. The error should have dissapeared.
|
||||
In `adb logcat` you will see this message instead `avc: denied { bind } for scontext=u:r:untrusted_app` which seems to be due to Android restrictions which prevents Waku from obtaining the IP address of the device, but it will still be able to connect to other devices succesfully.
|
||||
@@ -133,8 +133,8 @@ dependencies {
|
||||
//noinspection GradleDynamicVersion
|
||||
implementation "com.facebook.react:react-native:+"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
implementation files('libs/gowaku.aar')
|
||||
// From node_modules
|
||||
implementation project(":gowaku")
|
||||
// From node_modules
|
||||
}
|
||||
|
||||
if (isNewArchitectureEnabled()) {
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
configurations.maybeCreate("default")
|
||||
artifacts.add("default", file('gowaku.aar'))
|
||||
@@ -0,0 +1 @@
|
||||
include ':gowaku'
|
||||
@@ -183,4 +183,8 @@ class ReactNativeModule(reactContext: ReactApplicationContext) : ReactContextBas
|
||||
promise.resolve(Gowaku.filterUnsubscribe(filterJSON, ms.toLong()))
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun dnsDiscovery(url: String, nameserver: String = "", ms: Double, promise: Promise) {
|
||||
promise.resolve(Gowaku.dnsDiscovery(url, nameserver, ms.toLong()))
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -30,24 +30,24 @@ mkdir -p tmp
|
||||
cd tmp
|
||||
|
||||
rm -f ${SHA_FILE}
|
||||
wget "https://github.com/status-im/go-waku/releases/download/v${VERSION}/${SHA_FILE}"
|
||||
wget "https://github.com/waku-org/go-waku/releases/download/v${VERSION}/${SHA_FILE}"
|
||||
|
||||
if [ "$DOWNLOAD_ANDROID" = true ]; then
|
||||
rm -f ${ANDROID_TAR}
|
||||
wget "https://github.com/status-im/go-waku/releases/download/v${VERSION}/${ANDROID_TAR}"
|
||||
curl -L "https://github.com/waku-org/go-waku/releases/download/v${VERSION}/${ANDROID_TAR}" --output $ANDROID_TAR
|
||||
sha256sum --status --ignore-missing -c ${SHA_FILE}
|
||||
if ! sha256sum --status --ignore-missing -c ${SHA_FILE}; then
|
||||
echo "checksum failed - verify download"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -f ../android/libs/gowaku*
|
||||
tar xvfz ${ANDROID_TAR} -C ../android/libs
|
||||
rm -f ../android/gowaku/gowaku*
|
||||
tar xvfz ${ANDROID_TAR} -C ../android/gowaku
|
||||
fi
|
||||
|
||||
if [ "$DOWNLOAD_IOS" = true ]; then
|
||||
rm -f ${IOS_TAR}
|
||||
wget "https://github.com/status-im/go-waku/releases/download/v${VERSION}/${IOS_TAR}"
|
||||
curl -L "https://github.com/waku-org/go-waku/releases/download/v${VERSION}/${IOS_TAR}" --output $IOS_TAR
|
||||
|
||||
if ! sha256sum --status --ignore-missing -c ${SHA_FILE}; then
|
||||
echo "checksum failed - verify download"
|
||||
|
||||
+16
-3
@@ -24,8 +24,11 @@ import {
|
||||
FilterSubscription,
|
||||
ContentFilter,
|
||||
filterSubscribe,
|
||||
dnsDiscovery,
|
||||
} from '@waku/react-native';
|
||||
|
||||
const myContentTopic = '/example/1/react-native-app/proto';
|
||||
|
||||
export default function App() {
|
||||
const [result, setResult] = React.useState();
|
||||
|
||||
@@ -42,11 +45,13 @@ export default function App() {
|
||||
await relaySubscribe();
|
||||
|
||||
onMessage((event) => {
|
||||
if (event.wakuMessage.contentTopic !== myContentTopic) return;
|
||||
|
||||
setResult(
|
||||
'Message received: ' +
|
||||
event.wakuMessage.timestamp +
|
||||
' - payload:[' +
|
||||
event.wakuMessage.payload +
|
||||
JSON.stringify(event.wakuMessage.payload) +
|
||||
']'
|
||||
);
|
||||
console.log('Message received: ', event);
|
||||
@@ -80,7 +85,7 @@ export default function App() {
|
||||
console.log('Peers', await peers());
|
||||
|
||||
let msg = new WakuMessage();
|
||||
msg.contentTopic = 'ABC';
|
||||
msg.contentTopic = myContentTopic;
|
||||
msg.payload = new Uint8Array([1, 2, 3, 4, 5]);
|
||||
msg.timestamp = new Date();
|
||||
msg.version = 0;
|
||||
@@ -92,13 +97,21 @@ export default function App() {
|
||||
// TO RETRIEVE HISTORIC MESSAGES:
|
||||
console.log('Retrieving messages from store node');
|
||||
const query = new StoreQuery();
|
||||
query.contentFilters.push(new ContentFilter('test-rramos'));
|
||||
query.contentFilters.push(new ContentFilter(myContentTopic));
|
||||
const queryResult = await storeQuery(
|
||||
query,
|
||||
'16Uiu2HAkvWiyFsgRhuJEb9JfjYxEkoHLgnUQmr1N5mKWnYjxYRVm'
|
||||
);
|
||||
console.log(queryResult);
|
||||
|
||||
// DNS Discovery
|
||||
console.log('Retrieving Nodes using DNS Discovery');
|
||||
const dnsDiscoveryResult = await dnsDiscovery(
|
||||
'enrtree://AO47IDOLBKH72HIZZOXQP6NMRESAN7CHYWIBNXDXWRJRZWLODKII6@test.wakuv2.nodes.status.im',
|
||||
'1.1.1.1'
|
||||
);
|
||||
console.log(dnsDiscoveryResult);
|
||||
|
||||
// USING FILTER INSTEAD OF RELAY:
|
||||
// Instantiate the node passing these parameters:
|
||||
// let config = new Config();
|
||||
|
||||
@@ -15,3 +15,6 @@ if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true")
|
||||
include(":ReactAndroid:hermes-engine")
|
||||
project(":ReactAndroid:hermes-engine").projectDir = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), "../ReactAndroid/hermes-engine");
|
||||
}
|
||||
|
||||
include ':gowaku'
|
||||
project(':gowaku').projectDir = new File(rootProject.projectDir, './../node_modules/@waku/react-native/android/gowaku')
|
||||
+26
-1
@@ -1,4 +1,29 @@
|
||||
// Learn more https://docs.expo.io/guides/customizing-metro
|
||||
const { getDefaultConfig } = require('expo/metro-config');
|
||||
const exclusionList = require('metro-config/src/defaults/exclusionList');
|
||||
|
||||
module.exports = getDefaultConfig(__dirname);
|
||||
const path = require('path');
|
||||
const pak = require('../package.json');
|
||||
|
||||
const root = path.resolve(__dirname, '..');
|
||||
const modules = Object.keys({
|
||||
...pak.peerDependencies,
|
||||
});
|
||||
|
||||
let config = getDefaultConfig(__dirname);
|
||||
config.projectRoot = __dirname;
|
||||
config.watchFolders = [root];
|
||||
|
||||
config.resolver = {
|
||||
blacklistRE: exclusionList(
|
||||
modules.map(
|
||||
(m) => new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`)
|
||||
)
|
||||
),
|
||||
extraNodeModules: modules.reduce((acc, name) => {
|
||||
acc[name] = path.join(__dirname, 'node_modules', name);
|
||||
return acc;
|
||||
}, {}),
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
|
||||
Generated
+63
-25
@@ -8,7 +8,7 @@
|
||||
"name": "@waku/react-native-example",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"@waku/react-native": "^0.0.8",
|
||||
"@waku/react-native": "file:../",
|
||||
"expo": "~47.0.8",
|
||||
"expo-splash-screen": "~0.17.5",
|
||||
"expo-status-bar": "~1.4.2",
|
||||
@@ -19,6 +19,42 @@
|
||||
"@babel/core": "^7.12.9"
|
||||
}
|
||||
},
|
||||
"..": {
|
||||
"name": "@waku/react-native",
|
||||
"version": "0.2.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"big-integer": "^1.6.51",
|
||||
"buffer": "^6.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@arkweid/lefthook": "^0.7.7",
|
||||
"@babel/eslint-parser": "^7.18.2",
|
||||
"@commitlint/config-conventional": "^17.0.2",
|
||||
"@react-native-community/eslint-config": "^3.0.2",
|
||||
"@release-it/conventional-changelog": "^5.0.0",
|
||||
"@types/base-64": "^1.0.0",
|
||||
"@types/jest": "^28.1.2",
|
||||
"@types/react": "~17.0.21",
|
||||
"@types/react-native": "0.68.0",
|
||||
"commitlint": "^17.0.2",
|
||||
"eslint": "^8.4.1",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"jest": "^28.1.1",
|
||||
"pod-install": "^0.1.0",
|
||||
"prettier": "^2.0.5",
|
||||
"react": "17.0.2",
|
||||
"react-native": "0.68.2",
|
||||
"react-native-builder-bob": "^0.18.3",
|
||||
"release-it": "^15.0.0",
|
||||
"typescript": "^4.5.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
|
||||
@@ -3801,16 +3837,8 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@waku/react-native": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@waku/react-native/-/react-native-0.0.8.tgz",
|
||||
"integrity": "sha512-Ybef43I+B5as2F5UBZhS4Jmk6T9Fstp3kpMkQcAlsa+A/AeEYN1uKFT3ykBXUa5jPGDtreDYhRbOOdmA0ptOiQ==",
|
||||
"dependencies": {
|
||||
"base-64": "^1.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
"resolved": "..",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@xmldom/xmldom": {
|
||||
"version": "0.7.9",
|
||||
@@ -4308,11 +4336,6 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/base-64": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz",
|
||||
"integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg=="
|
||||
},
|
||||
"node_modules/base/node_modules/define-property": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
|
||||
@@ -14021,11 +14044,31 @@
|
||||
}
|
||||
},
|
||||
"@waku/react-native": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@waku/react-native/-/react-native-0.0.8.tgz",
|
||||
"integrity": "sha512-Ybef43I+B5as2F5UBZhS4Jmk6T9Fstp3kpMkQcAlsa+A/AeEYN1uKFT3ykBXUa5jPGDtreDYhRbOOdmA0ptOiQ==",
|
||||
"version": "file:..",
|
||||
"requires": {
|
||||
"base-64": "^1.0.0"
|
||||
"@arkweid/lefthook": "^0.7.7",
|
||||
"@babel/eslint-parser": "^7.18.2",
|
||||
"@commitlint/config-conventional": "^17.0.2",
|
||||
"@react-native-community/eslint-config": "^3.0.2",
|
||||
"@release-it/conventional-changelog": "^5.0.0",
|
||||
"@types/base-64": "^1.0.0",
|
||||
"@types/jest": "^28.1.2",
|
||||
"@types/react": "~17.0.21",
|
||||
"@types/react-native": "0.68.0",
|
||||
"big-integer": "^1.6.51",
|
||||
"buffer": "^6.0.3",
|
||||
"commitlint": "^17.0.2",
|
||||
"eslint": "^8.4.1",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"jest": "^28.1.1",
|
||||
"pod-install": "^0.1.0",
|
||||
"prettier": "^2.0.5",
|
||||
"react": "17.0.2",
|
||||
"react-native": "0.68.2",
|
||||
"react-native-builder-bob": "^0.18.3",
|
||||
"release-it": "^15.0.0",
|
||||
"typescript": "^4.5.2"
|
||||
}
|
||||
},
|
||||
"@xmldom/xmldom": {
|
||||
@@ -14387,11 +14430,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"base-64": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz",
|
||||
"integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg=="
|
||||
},
|
||||
"base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
|
||||
@@ -7,10 +7,11 @@
|
||||
"start": "expo start --dev-client",
|
||||
"android": "expo run:android",
|
||||
"ios": "expo run:ios",
|
||||
"web": "expo start --web"
|
||||
"web": "expo start --web",
|
||||
"pods": "npx pod-install"
|
||||
},
|
||||
"dependencies": {
|
||||
"@waku/react-native": "^0.0.8",
|
||||
"@waku/react-native": "file:../",
|
||||
"expo": "~47.0.8",
|
||||
"expo-splash-screen": "~0.17.5",
|
||||
"expo-status-bar": "~1.4.2",
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
0.3.0
|
||||
0.5.1
|
||||
|
||||
@@ -146,5 +146,11 @@ RCT_EXTERN_METHOD(filterUnsubscribe:(NSString *)filterJSON
|
||||
withResolver:(RCTPromiseResolveBlock)resolve
|
||||
withRejecter:(RCTPromiseRejectBlock)reject)
|
||||
|
||||
RCT_EXTERN_METHOD(dnsDiscovery:(NSString *)url
|
||||
withNameserver:(NSString *)nameserver
|
||||
withMs:(nonnull NSNumber *)ms
|
||||
withResolver:(RCTPromiseResolveBlock)resolve
|
||||
withRejecter:(RCTPromiseRejectBlock)reject)
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@@ -177,4 +177,9 @@ class ReactNative: RCTEventEmitter {
|
||||
resolve(GowakuFilterUnsubscribe(filterJSON, ms))
|
||||
}
|
||||
|
||||
@objc(dnsDiscovery:withNameserver:withMs:withResolver:withRejecter:)
|
||||
func dnsDiscovery(url: String, nameserver: String, ms: Int, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
|
||||
resolve(GowakuDnsDiscovery(url, nameserver, ms))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
pre-commit:
|
||||
parallel: true
|
||||
commands:
|
||||
lint:
|
||||
files: git diff --name-only @{push}
|
||||
glob: "*.{js,ts,jsx,tsx}"
|
||||
run: npx eslint {files}
|
||||
types:
|
||||
files: git diff --name-only @{push}
|
||||
glob: "*.{js,ts, jsx, tsx}"
|
||||
|
||||
Generated
+4536
-19
File diff suppressed because it is too large
Load Diff
+31
-27
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@waku/react-native",
|
||||
"version": "0.0.9",
|
||||
"version": "0.2.0",
|
||||
"description": "Waku React Native",
|
||||
"author": "Status Research & Development GMBH",
|
||||
"authors": [
|
||||
@@ -21,6 +21,8 @@
|
||||
"android",
|
||||
"ios",
|
||||
"cpp",
|
||||
"download-gowaku.sh",
|
||||
"go-waku.VERSION",
|
||||
"waku-react-native.podspec",
|
||||
"!lib/typescript/example",
|
||||
"!android/build",
|
||||
@@ -36,6 +38,7 @@
|
||||
"prepare": "bob build",
|
||||
"release": "release-it",
|
||||
"example": "yarn --cwd example",
|
||||
"pods": "npx pod-install",
|
||||
"bootstrap": "yarn example && yarn && yarn example pods"
|
||||
},
|
||||
"keywords": [
|
||||
@@ -54,31 +57,31 @@
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@arkweid/lefthook": "^0.7.7",
|
||||
"@babel/eslint-parser": "^7.18.2",
|
||||
"@commitlint/config-conventional": "^17.0.2",
|
||||
"@react-native-community/eslint-config": "^3.0.2",
|
||||
"@release-it/conventional-changelog": "^5.0.0",
|
||||
"@types/base-64": "^1.0.0",
|
||||
"@types/jest": "^28.1.2",
|
||||
"@types/react": "~17.0.21",
|
||||
"@types/react-native": "0.68.0",
|
||||
"commitlint": "^17.0.2",
|
||||
"eslint": "^8.4.1",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"jest": "^28.1.1",
|
||||
"pod-install": "^0.1.0",
|
||||
"prettier": "^2.0.5",
|
||||
"react": "17.0.2",
|
||||
"react-native": "0.68.2",
|
||||
"react-native-builder-bob": "^0.18.3",
|
||||
"release-it": "^15.0.0",
|
||||
"typescript": "^4.5.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/react": "17.0.21"
|
||||
},
|
||||
"@arkweid/lefthook": "^0.7.7",
|
||||
"@babel/eslint-parser": "^7.18.2",
|
||||
"@commitlint/config-conventional": "^17.0.2",
|
||||
"@react-native-community/eslint-config": "^3.0.2",
|
||||
"@release-it/conventional-changelog": "^5.0.0",
|
||||
"@types/base-64": "^1.0.0",
|
||||
"@types/jest": "^28.1.2",
|
||||
"@types/react": "~17.0.21",
|
||||
"@types/react-native": "0.68.0",
|
||||
"commitlint": "^17.0.2",
|
||||
"eslint": "^8.4.1",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"jest": "^28.1.1",
|
||||
"pod-install": "^0.1.0",
|
||||
"prettier": "^2.0.5",
|
||||
"react": "17.0.2",
|
||||
"react-native": "0.68.2",
|
||||
"react-native-builder-bob": "^0.18.3",
|
||||
"release-it": "^15.0.0",
|
||||
"typescript": "^4.5.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/react": "17.0.21"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
@@ -158,6 +161,7 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"base-64": "^1.0.0"
|
||||
"big-integer": "^1.6.51",
|
||||
"buffer": "^6.0.3"
|
||||
}
|
||||
}
|
||||
|
||||
+122
-56
@@ -1,5 +1,6 @@
|
||||
import { NativeModules, Platform, NativeEventEmitter } from 'react-native';
|
||||
import { decode, encode } from 'base-64';
|
||||
import bigInt from 'big-integer';
|
||||
import { Buffer } from 'buffer';
|
||||
|
||||
const LINKING_ERROR =
|
||||
`The package '@waku/react-native' doesn't seem to be linked. Make sure: \n\n` +
|
||||
@@ -18,11 +19,7 @@ const ReactNative = NativeModules.ReactNative
|
||||
}
|
||||
);
|
||||
|
||||
export function multiply(a: number, b: number): Promise<number> {
|
||||
return ReactNative.multiply(a, b);
|
||||
}
|
||||
|
||||
const OneMillion = BigInt(1_000_000);
|
||||
const OneMillion = bigInt(1000000);
|
||||
|
||||
export class WakuMessage {
|
||||
payload: Uint8Array = new Uint8Array();
|
||||
@@ -31,14 +28,13 @@ export class WakuMessage {
|
||||
timestamp?: Date = undefined;
|
||||
|
||||
toJSON() {
|
||||
const b64encoded = encode(String.fromCharCode(...this.payload));
|
||||
return {
|
||||
contentTopic: this.contentTopic,
|
||||
version: this.version,
|
||||
timestamp: this.timestamp
|
||||
? (BigInt(this.timestamp.valueOf()) * OneMillion).toString(10)
|
||||
? bigInt(this.timestamp.valueOf()).multiply(OneMillion).toString(10)
|
||||
: 0,
|
||||
payload: b64encoded,
|
||||
payload: Buffer.from(this.payload).toString('base64'),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -54,27 +50,31 @@ export function onMessage(cb: (arg0: any) => void) {
|
||||
let signal = JSON.parse(event.signal);
|
||||
let msg = signal.event.wakuMessage;
|
||||
signal.event.wakuMessage = new WakuMessage();
|
||||
signal.event.wakuMessage.timestamp = msg.timestamp;
|
||||
signal.event.wakuMessage.timestamp =
|
||||
msg.timestamp != 0
|
||||
? new Date(bigInt(msg.timestamp).divide(OneMillion).toJSNumber())
|
||||
: undefined;
|
||||
signal.event.wakuMessage.version = msg.version || 0;
|
||||
signal.event.wakuMessage.contentTopic = msg.contentTopic;
|
||||
signal.event.wakuMessage.payload = new Uint8Array(
|
||||
decode(msg.payload ?? [])
|
||||
.split('')
|
||||
.map((c: any) => c.charCodeAt(0))
|
||||
);
|
||||
signal.event.wakuMessage.payload = Buffer.from(msg.payload || [], 'base64');
|
||||
cb(signal.event);
|
||||
});
|
||||
}
|
||||
|
||||
export class Config {
|
||||
host: String | null = null;
|
||||
port: Number | null = null;
|
||||
advertiseAddr: String | null = null;
|
||||
nodeKey: String | null = null;
|
||||
keepAliveInterval: Number | null = null;
|
||||
relay: Boolean | null = null;
|
||||
filter: Boolean | null = null;
|
||||
host: String | null = null; // IP address. Default 0.0.0.0
|
||||
port: Number | null = null; // TCP port to listen. Default 60000. Use 0 for random
|
||||
advertiseAddr: String | null = null; // Advertise custom multiaddress
|
||||
nodeKey: String | null = null; // secp256k1 private key. Default random
|
||||
keepAliveInterval: Number | null = null; // interval in seconds to ping all peers
|
||||
relay: Boolean | null = null; // enable waku relay
|
||||
relayTopics: Array<String> = []; // array of pubsub topics that WakuRelay will automatically subscribe to when the node starts
|
||||
minPeersToPublish: Number | null = null;
|
||||
filter: Boolean | null = null; // enable waku filter
|
||||
discv5: Boolean | null = null; // enable discv5
|
||||
discV5BootstrapNodes: Array<String> = []; // array of bootstrap nodes ENR
|
||||
discV5UDPPort: Number | null = null; // UDP port for DiscoveryV5
|
||||
logLevel: String | null = null; // Set the log level. Default `INFO`. Allowed values "DEBUG", "INFO", "WARN", "ERROR", "DPANIC", "PANIC", "FATAL"
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,7 +165,10 @@ export function relayPublish(
|
||||
timeoutMs: Number = 0
|
||||
): Promise<string> {
|
||||
return new Promise<string>(async (resolve, reject) => {
|
||||
let messageJSON = JSON.stringify(msg);
|
||||
let messageJSON = JSON.stringify(msg).replace(
|
||||
/"timestamp":"([0-9]+)"/,
|
||||
`"timestamp":$1`
|
||||
);
|
||||
let response = JSON.parse(
|
||||
await ReactNative.relayPublish(messageJSON, pubsubTopic, timeoutMs)
|
||||
);
|
||||
@@ -379,6 +382,27 @@ export function peerCnt(): Promise<Number> {
|
||||
});
|
||||
}
|
||||
|
||||
export class EncryptedPayload extends WakuMessage {
|
||||
constructor(msg: WakuMessage) {
|
||||
super();
|
||||
this.contentTopic = msg.contentTopic;
|
||||
this.version = msg.version;
|
||||
this.timestamp = msg.timestamp;
|
||||
this.payload = msg.payload;
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
contentTopic: this.contentTopic,
|
||||
version: this.version,
|
||||
timestamp: this.timestamp
|
||||
? bigInt(this.timestamp.valueOf()).multiply(OneMillion).toJSNumber()
|
||||
: 0,
|
||||
payload: Buffer.from(Array.from(this.payload)).toString('base64'),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class DecodedPayload {
|
||||
payload: Uint8Array = new Uint8Array();
|
||||
padding: Uint8Array = new Uint8Array();
|
||||
@@ -386,11 +410,9 @@ export class DecodedPayload {
|
||||
signature: String | null = '';
|
||||
|
||||
toJSON() {
|
||||
const b64payload = encode(String.fromCharCode(...this.payload));
|
||||
const b64padding = encode(String.fromCharCode(...this.padding));
|
||||
return {
|
||||
payload: b64payload,
|
||||
padding: b64padding,
|
||||
payload: Buffer.from(this.payload).toString('base64'),
|
||||
padding: Buffer.from(this.padding).toString('base64'),
|
||||
pubkey: this.pubkey,
|
||||
signature: this.signature,
|
||||
};
|
||||
@@ -408,7 +430,8 @@ export function decodeSymmetric(
|
||||
symmetricKey: String
|
||||
): Promise<DecodedPayload> {
|
||||
return new Promise<DecodedPayload>(async (resolve, reject) => {
|
||||
let messageJSON = JSON.stringify(msg);
|
||||
let message = new EncryptedPayload(msg);
|
||||
let messageJSON = JSON.stringify(message);
|
||||
let response = JSON.parse(
|
||||
await ReactNative.decodeSymmetric(messageJSON, symmetricKey)
|
||||
);
|
||||
@@ -416,16 +439,8 @@ export function decodeSymmetric(
|
||||
reject(response.error);
|
||||
} else {
|
||||
let decodedPayload = new DecodedPayload();
|
||||
decodedPayload.payload = new Uint8Array(
|
||||
atob(response.result.payload)
|
||||
.split('')
|
||||
.map((c) => c.charCodeAt(0))
|
||||
);
|
||||
decodedPayload.padding = new Uint8Array(
|
||||
atob(response.result.padding)
|
||||
.split('')
|
||||
.map((c) => c.charCodeAt(0))
|
||||
);
|
||||
decodedPayload.payload = Buffer.from(response.result.data, 'base64');
|
||||
decodedPayload.padding = Buffer.from(response.result.padding, 'base64');
|
||||
decodedPayload.pubkey = response.result.pubkey;
|
||||
decodedPayload.signature = response.result.signature;
|
||||
resolve(decodedPayload);
|
||||
@@ -444,24 +459,17 @@ export function decodeAsymmetric(
|
||||
privateKey: String
|
||||
): Promise<DecodedPayload> {
|
||||
return new Promise<DecodedPayload>(async (resolve, reject) => {
|
||||
let messageJSON = JSON.stringify(msg);
|
||||
let message = new EncryptedPayload(msg);
|
||||
let messageJSON = JSON.stringify(message);
|
||||
let response = JSON.parse(
|
||||
await ReactNative.decodeSymmetric(messageJSON, privateKey)
|
||||
await ReactNative.decodeAsymmetric(messageJSON, privateKey)
|
||||
);
|
||||
if (response.error) {
|
||||
reject(response.error);
|
||||
} else {
|
||||
let decodedPayload = new DecodedPayload();
|
||||
decodedPayload.payload = new Uint8Array(
|
||||
atob(response.result.payload)
|
||||
.split('')
|
||||
.map((c) => c.charCodeAt(0))
|
||||
);
|
||||
decodedPayload.padding = new Uint8Array(
|
||||
atob(response.result.padding)
|
||||
.split('')
|
||||
.map((c) => c.charCodeAt(0))
|
||||
);
|
||||
decodedPayload.payload = Buffer.from(response.result.data, 'base64');
|
||||
decodedPayload.padding = Buffer.from(response.result.padding, 'base64');
|
||||
decodedPayload.pubkey = response.result.pubkey;
|
||||
decodedPayload.signature = response.result.signature;
|
||||
resolve(decodedPayload);
|
||||
@@ -515,7 +523,10 @@ export function lightpushPublish(
|
||||
timeoutMs: Number = 0
|
||||
): Promise<string> {
|
||||
return new Promise<string>(async (resolve, reject) => {
|
||||
let messageJSON = JSON.stringify(msg);
|
||||
let messageJSON = JSON.stringify(msg).replace(
|
||||
/"timestamp":"([0-9]+)"/,
|
||||
`"timestamp":$1`
|
||||
);
|
||||
let response = JSON.parse(
|
||||
await ReactNative.lightpushPublish(
|
||||
messageJSON,
|
||||
@@ -551,7 +562,8 @@ export function lightpushPublishEncAsymmetric(
|
||||
timeoutMs: Number = 0
|
||||
): Promise<string> {
|
||||
return new Promise<string>(async (resolve, reject) => {
|
||||
let messageJSON = JSON.stringify(msg);
|
||||
let message = new EncryptedPayload(msg);
|
||||
let messageJSON = JSON.stringify(message);
|
||||
let response = JSON.parse(
|
||||
await ReactNative.lightpushPublishEncodeAsymmetric(
|
||||
messageJSON,
|
||||
@@ -589,7 +601,8 @@ export function lightpushPublishEncSymmetric(
|
||||
timeoutMs: Number = 0
|
||||
): Promise<string> {
|
||||
return new Promise<string>(async (resolve, reject) => {
|
||||
let messageJSON = JSON.stringify(msg);
|
||||
let message = new EncryptedPayload(msg);
|
||||
let messageJSON = JSON.stringify(message);
|
||||
let response = JSON.parse(
|
||||
await ReactNative.lightpushPublishEncodeAsymmetric(
|
||||
messageJSON,
|
||||
@@ -646,6 +659,45 @@ export function peers(): Promise<Array<Peer>> {
|
||||
});
|
||||
}
|
||||
|
||||
export class DiscoveredNode {
|
||||
peerID: String = '';
|
||||
addrs: Array<String> = Array();
|
||||
enr: String = '';
|
||||
|
||||
constructor(
|
||||
peerID: String,
|
||||
addrs: Array<String>,
|
||||
enr: String
|
||||
) {
|
||||
this.peerID = peerID;
|
||||
this.addrs = addrs;
|
||||
this.enr = enr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use DNS Discovery to retrieve a list of nodes from an enrtree:// URL
|
||||
* @return List of Nodes
|
||||
*/
|
||||
export function dnsDiscovery(
|
||||
url: String,
|
||||
nameserver: String,
|
||||
timeoutMs: Number = 0
|
||||
): Promise<Array<DiscoveredNode>> {
|
||||
return new Promise<Array<DiscoveredNode>>(async (resolve, reject) => {
|
||||
let response = JSON.parse(await ReactNative.dnsDiscovery(url, nameserver, timeoutMs));
|
||||
if (response.error) {
|
||||
reject(response.error);
|
||||
} else {
|
||||
resolve(
|
||||
response.result.map(
|
||||
(x: any) => new DiscoveredNode(x.peerID, x.multiaddrs, x.enr)
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export class Index {
|
||||
digest: Uint8Array = new Uint8Array();
|
||||
receiverTime: Number = 0;
|
||||
@@ -715,13 +767,15 @@ export function storeQuery(
|
||||
pubsubTopic: query.pubsubTopic,
|
||||
contentFilters: query.contentFilters,
|
||||
startTime: query.startTime
|
||||
? (BigInt(query.startTime.valueOf()) * OneMillion).toString(10)
|
||||
? bigInt(query.startTime.valueOf()).multiply(OneMillion).toString(10)
|
||||
: 0,
|
||||
endTime: query.endTime
|
||||
? (BigInt(query.endTime.valueOf()) * OneMillion).toString(10)
|
||||
? bigInt(query.endTime.valueOf()).multiply(OneMillion).toString(10)
|
||||
: 0,
|
||||
pagingOptions: query.pagingOptions,
|
||||
});
|
||||
})
|
||||
.replace(/"startTime":"([0-9]+)"/, `"startTime":$1`)
|
||||
.replace(/"endTime":"([0-9]+)"/, `"endTime":$1`);
|
||||
let response = JSON.parse(
|
||||
await ReactNative.storeQuery(queryJSON, peerID, timeoutMs)
|
||||
);
|
||||
@@ -729,6 +783,18 @@ export function storeQuery(
|
||||
if (response.error) {
|
||||
reject(response.error);
|
||||
} else {
|
||||
if (response.result.messages) {
|
||||
for (let i = 0; i < response.result.messages.length; i++) {
|
||||
const t = response.result.messages[i].timestamp;
|
||||
response.result.messages[i].timestamp =
|
||||
t != 0
|
||||
? new Date(bigInt(t).divide(OneMillion).toJSNumber())
|
||||
: undefined;
|
||||
response.result.messages[i].payload = new Uint8Array(
|
||||
Buffer.from(response.result.messages[i].payload ?? [], 'base64')
|
||||
);
|
||||
}
|
||||
}
|
||||
resolve(response.result);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user