Compare commits

...

19 Commits

Author SHA1 Message Date
Anton Iakimov
284f9a0992
fix: update wakuv2 fleet DNS discovery enrtree
https://github.com/status-im/infra-misc/issues/171
2023-09-27 13:36:26 +02:00
Richard Ramos
49ea163a59 feat: expose DNS Discovery and DiscV5 2023-02-26 20:09:29 -04:00
Brice Stacey
dc6ab3cf27 fix: add serializers for encrypted payloads
The encrypted functions have slightly different APIs, so we decorate the
WakuMessage and only change its toJSON function.
2023-02-10 09:29:49 -04:00
Brice Stacey
dd1f2a222b chore: include go-waku download scripts in releases
Since go-waku needs to be downloaded, including these download scripts
in the releases is helpful.
2023-02-10 09:29:49 -04:00
Brice Stacey
dff2d0259b fix: update package.json
I had forgotten to include it in the PR #15
2023-02-10 09:29:49 -04:00
Brice Stacey
6757cd4dd0 fix: typo calling decodeSymmetric instead of decodeAsymmetric 2023-02-09 10:49:46 -04:00
Brice Stacey
7040e63e41 fix: replace base-64 with more robust Buffer
The original implementation was using a combination of atob and the
base-64 library. Buffer is a more common and robust solution.
2023-02-09 10:49:46 -04:00
Brice Stacey
2ed5c9b376 fix: add missing pods script in the example project 2023-02-09 10:49:46 -04:00
Richard Ramos
98ef3d59f8
fix: timestamp to date, and building .aar 2023-01-23 13:51:17 -04:00
Richard Ramos
b2624f4db1
chore: add docs on how to fix netlink err 2023-01-05 19:22:30 -04:00
Richard Ramos
1b26a8f5f5
feat: remove @waku/react-native dependency from example app 2023-01-05 16:53:32 -04:00
Richard Ramos
e4d75ffdee
chore: use 0.3.1 2023-01-05 13:33:31 -04:00
Richard Ramos
0c2ab3dd5e
fix: storeQuery base64 decode 2023-01-05 11:47:21 -04:00
Richard Ramos
a0990d17c2
fix: use v0.0.11 in example 2023-01-03 15:09:22 -04:00
Richard Ramos
6dea7bb417
fix: bigint 2023-01-03 14:57:48 -04:00
Richard Ramos
a32ebd6bd2
fix: bigint 2023-01-03 14:28:40 -04:00
Richard Ramos
f7022b9c7b v0.0.9 2023-01-03 13:51:54 -04:00
Richard Ramos
3c2371252d fix: format 2023-01-03 13:51:54 -04:00
Richard Ramos
3ab9bb046b fix: use date for timestamps 2023-01-03 13:51:54 -04:00
21 changed files with 5361 additions and 283 deletions

4
.gitignore vendored
View File

@ -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

View File

@ -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.

214
android-netlink.md Normal file
View File

@ -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.

View File

@ -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()) {

View File

@ -0,0 +1,2 @@
configurations.maybeCreate("default")
artifacts.add("default", file('gowaku.aar'))

View File

1
android/settings.gradle Normal file
View File

@ -0,0 +1 @@
include ':gowaku'

View File

@ -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()))
}
}

View File

@ -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"

View File

@ -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,9 +85,9 @@ 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 = Date.now();
msg.timestamp = new Date();
msg.version = 0;
let messageID = await relayPublish(msg);
@ -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('/toy-chat/2/luzhou/proto'));
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();

View File

@ -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')

View File

@ -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;

View File

@ -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",

View File

@ -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",

View File

@ -1 +1 @@
0.3.0
0.5.1

View File

@ -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

View File

@ -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))
}
}

View File

@ -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}"

4555
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "@waku/react-native",
"version": "0.0.8",
"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"
}
}

View File

@ -1,5 +1,6 @@
import { NativeModules, Platform, NativeEventEmitter} from 'react-native';
import {decode, encode} from 'base-64'
import { NativeModules, Platform, NativeEventEmitter } from 'react-native';
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` +
@ -7,7 +8,9 @@ const LINKING_ERROR =
'- You rebuilt the app after installing the package\n' +
'- You are not using Expo managed workflow\n';
const ReactNative = NativeModules.ReactNative ? NativeModules.ReactNative : new Proxy(
const ReactNative = NativeModules.ReactNative
? NativeModules.ReactNative
: new Proxy(
{},
{
get() {
@ -16,27 +19,25 @@ const ReactNative = NativeModules.ReactNative ? NativeModules.ReactNative : ne
}
);
export function multiply(a: number, b: number): Promise<number> {
return ReactNative.multiply(a, b);
}
const OneMillion = bigInt(1000000);
export class WakuMessage {
payload: Uint8Array = new Uint8Array();
contentTopic: String | null = "";
version: Number | null = 0;
timestamp: Number | null = null;
toJSON(){
const b64encoded = encode(String.fromCharCode(...this.payload));
return {
contentTopic: this.contentTopic,
version: this.version,
timestamp: this.timestamp,
payload: b64encoded
}
}
}
payload: Uint8Array = new Uint8Array();
contentTopic: String | null = '';
version: Number | null = 0;
timestamp?: Date = undefined;
toJSON() {
return {
contentTopic: this.contentTopic,
version: this.version,
timestamp: this.timestamp
? bigInt(this.timestamp.valueOf()).multiply(OneMillion).toString(10)
: 0,
payload: Buffer.from(this.payload).toString('base64'),
};
}
}
var eventEmitter = new NativeEventEmitter(NativeModules.ReactNative);
@ -44,28 +45,36 @@ var eventEmitter = new NativeEventEmitter(NativeModules.ReactNative);
* Execute function each time a message is received
* @param cb callback to be eecuted
*/
export function onMessage(cb: (arg0:any) => void) {
eventEmitter.addListener("message", event => {
export function onMessage(cb: (arg0: any) => void) {
eventEmitter.addListener('message', (event) => {
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
minPeersToPublish: Number | 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"
}
/**
@ -73,9 +82,11 @@ export class Config {
* @param config options used to initialize a go-waku node
*/
export function newNode(config: Config | null): Promise<void> {
return new Promise<void>(async (resolve, reject) => {
let response = JSON.parse(await ReactNative.newNode(config ? JSON.stringify(config) : ""));
if(response.error){
return new Promise<void>(async (resolve, reject) => {
let response = JSON.parse(
await ReactNative.newNode(config ? JSON.stringify(config) : '')
);
if (response.error) {
reject(response.error);
} else {
resolve();
@ -89,7 +100,7 @@ export function newNode(config: Config | null): Promise<void> {
export function start(): Promise<void> {
return new Promise<void>(async (resolve, reject) => {
let response = JSON.parse(await ReactNative.start());
if(response.error){
if (response.error) {
reject(response.error);
} else {
resolve();
@ -103,7 +114,7 @@ export function start(): Promise<void> {
export function stop(): Promise<void> {
return new Promise<void>(async (resolve, reject) => {
let response = JSON.parse(await ReactNative.stop());
if(response.error){
if (response.error) {
reject(response.error);
} else {
resolve();
@ -118,7 +129,7 @@ export function stop(): Promise<void> {
export function isStarted(): Promise<Boolean> {
return new Promise<Boolean>(async (resolve, reject) => {
let response = JSON.parse(await ReactNative.isStarted());
if(response.error){
if (response.error) {
reject(response.error);
} else {
resolve(response.result);
@ -133,7 +144,7 @@ export function isStarted(): Promise<Boolean> {
export function peerID(): Promise<string> {
return new Promise<string>(async (resolve, reject) => {
let response = JSON.parse(await ReactNative.peerID());
if(response.error){
if (response.error) {
reject(response.error);
} else {
resolve(response.result);
@ -148,11 +159,20 @@ export function peerID(): Promise<string> {
* @param timeoutMs Timeout value in milliseconds to execute the call. If the function takes longer than this value, the execution will be canceled and an error returned
* @returns string containing the message id
*/
export function relayPublish(msg: WakuMessage, pubsubTopic: String = "", timeoutMs: Number = 0): Promise<string> {
export function relayPublish(
msg: WakuMessage,
pubsubTopic: String = '',
timeoutMs: Number = 0
): Promise<string> {
return new Promise<string>(async (resolve, reject) => {
let messageJSON = JSON.stringify(msg)
let response = JSON.parse(await ReactNative.relayPublish(messageJSON, pubsubTopic, timeoutMs));
if(response.error){
let messageJSON = JSON.stringify(msg).replace(
/"timestamp":"([0-9]+)"/,
`"timestamp":$1`
);
let response = JSON.parse(
await ReactNative.relayPublish(messageJSON, pubsubTopic, timeoutMs)
);
if (response.error) {
reject(response.error);
} else {
resolve(response.result);
@ -161,7 +181,7 @@ export function relayPublish(msg: WakuMessage, pubsubTopic: String = "", timeout
}
/**
* Optionally sign, encrypt using asymmetric encryption and publish a message using Waku Relay.
* Optionally sign, encrypt using asymmetric encryption and publish a message using Waku Relay.
* @param msg WakuMessage to publish. The message version is overwritten to `1`
* @param publicKey hex encoded public key to be used for encryption.
* @param optionalSigningKey hex encoded private key to be used to sign the message.
@ -169,11 +189,25 @@ export function relayPublish(msg: WakuMessage, pubsubTopic: String = "", timeout
* @param timeoutMs Timeout value in milliseconds to execute the call. If the function takes longer than this value, the execution will be canceled and an error returned
* @returns string containing the message id
*/
export function relayPublishEncodeAsymmetric(msg: WakuMessage, publicKey: String, optionalSigningKey: String = "", pubsubTopic: String = "", timeoutMs: Number = 0): Promise<string> {
export function relayPublishEncodeAsymmetric(
msg: WakuMessage,
publicKey: String,
optionalSigningKey: String = '',
pubsubTopic: String = '',
timeoutMs: Number = 0
): Promise<string> {
return new Promise<string>(async (resolve, reject) => {
let messageJSON = JSON.stringify(msg)
let response = JSON.parse(await ReactNative.relayPublishEncodeAsymmetric(messageJSON, pubsubTopic, publicKey, optionalSigningKey, timeoutMs));
if(response.error){
let messageJSON = JSON.stringify(msg);
let response = JSON.parse(
await ReactNative.relayPublishEncodeAsymmetric(
messageJSON,
pubsubTopic,
publicKey,
optionalSigningKey,
timeoutMs
)
);
if (response.error) {
reject(response.error);
} else {
resolve(response.result);
@ -190,11 +224,25 @@ export function relayPublishEncodeAsymmetric(msg: WakuMessage, publicKey: String
* @param timeoutMs Timeout value in milliseconds to execute the call. If the function takes longer than this value, the execution will be canceled and an error returned
* @returns string containing the message id
*/
export function relayPublishEncodeSymmetric(msg: WakuMessage, symmetricKey: String, optionalSigningKey: String = "", pubsubTopic: String = "", timeoutMs: Number = 0): Promise<string> {
export function relayPublishEncodeSymmetric(
msg: WakuMessage,
symmetricKey: String,
optionalSigningKey: String = '',
pubsubTopic: String = '',
timeoutMs: Number = 0
): Promise<string> {
return new Promise<string>(async (resolve, reject) => {
let messageJSON = JSON.stringify(msg)
let response = JSON.parse(await ReactNative.relayPublishEncodeAsymmetric(messageJSON, pubsubTopic, symmetricKey, optionalSigningKey, timeoutMs));
if(response.error){
let messageJSON = JSON.stringify(msg);
let response = JSON.parse(
await ReactNative.relayPublishEncodeAsymmetric(
messageJSON,
pubsubTopic,
symmetricKey,
optionalSigningKey,
timeoutMs
)
);
if (response.error) {
reject(response.error);
} else {
resolve(response.result);
@ -204,12 +252,12 @@ export function relayPublishEncodeSymmetric(msg: WakuMessage, symmetricKey: Stri
/**
* Subscribe to a Waku Relay pubsub topic to receive messages.
* @param topic Pubsub topic to subscribe to.
* @param topic Pubsub topic to subscribe to.
*/
export function relaySubscribe(topic: String = ""): Promise<void> {
export function relaySubscribe(topic: String = ''): Promise<void> {
return new Promise<void>(async (resolve, reject) => {
let response = JSON.parse(await ReactNative.relaySubscribe(topic));
if(response.error){
if (response.error) {
reject(response.error);
} else {
resolve(response.result);
@ -232,7 +280,7 @@ export function defaultPubsubTopic(): Promise<String> {
export function listenAddresses(): Promise<Array<String>> {
return new Promise<Array<string>>(async (resolve, reject) => {
let response = JSON.parse(await ReactNative.listenAddresses());
if(response.error){
if (response.error) {
reject(response.error);
} else {
resolve(response.result);
@ -246,10 +294,15 @@ export function listenAddresses(): Promise<Array<String>> {
* @param protocol protocol we expect the peer to support
* @returns peer ID as a base58 `string` of the peer that was added
*/
export function addPeer(multiAddress: String, protocol: String): Promise<String> {
export function addPeer(
multiAddress: String,
protocol: String
): Promise<String> {
return new Promise<string>(async (resolve, reject) => {
let response = JSON.parse(await ReactNative.addPeer(multiAddress, protocol));
if(response.error){
let response = JSON.parse(
await ReactNative.addPeer(multiAddress, protocol)
);
if (response.error) {
reject(response.error);
} else {
resolve(response.result);
@ -262,10 +315,15 @@ export function addPeer(multiAddress: String, protocol: String): Promise<String>
* @param multiAddress multiaddress to reach the peer being dialed
* @param timeoutMs Timeout value in milliseconds to execute the call. If the function takes longer than this value, the execution will be canceled and an error returned
*/
export function connect(multiAddress: String, timeoutMs: Number = 0): Promise<void> {
export function connect(
multiAddress: String,
timeoutMs: Number = 0
): Promise<void> {
return new Promise<void>(async (resolve, reject) => {
let response = JSON.parse(await ReactNative.connect(multiAddress, timeoutMs));
if(response.error){
let response = JSON.parse(
await ReactNative.connect(multiAddress, timeoutMs)
);
if (response.error) {
reject(response.error);
} else {
resolve();
@ -278,10 +336,15 @@ export function connect(multiAddress: String, timeoutMs: Number = 0): Promise<vo
* @param peerID Peer ID to dial. The peer must be already known. It must have been added before with `addPeer` or previously dialed with `connect`
* @param timeoutMs Timeout value in milliseconds to execute the call. If the function takes longer than this value, the execution will be canceled and an error returned
*/
export function connectPeerID(peerID: String, timeoutMs: Number = 0): Promise<void> {
export function connectPeerID(
peerID: String,
timeoutMs: Number = 0
): Promise<void> {
return new Promise<void>(async (resolve, reject) => {
let response = JSON.parse(await ReactNative.connectPeerID(peerID, timeoutMs));
if(response.error){
let response = JSON.parse(
await ReactNative.connectPeerID(peerID, timeoutMs)
);
if (response.error) {
reject(response.error);
} else {
resolve();
@ -296,7 +359,7 @@ export function connectPeerID(peerID: String, timeoutMs: Number = 0): Promise<vo
export function disconnect(peerID: String): Promise<void> {
return new Promise<void>(async (resolve, reject) => {
let response = JSON.parse(await ReactNative.disconnect(peerID));
if(response.error){
if (response.error) {
reject(response.error);
} else {
resolve();
@ -311,7 +374,7 @@ export function disconnect(peerID: String): Promise<void> {
export function peerCnt(): Promise<Number> {
return new Promise<Number>(async (resolve, reject) => {
let response = JSON.parse(await ReactNative.peerCnt());
if(response.error){
if (response.error) {
reject(response.error);
} else {
resolve(response.result);
@ -319,21 +382,40 @@ 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();
pubkey: String | null = "";
signature: String | null = "";
pubkey: String | null = '';
signature: String | null = '';
toJSON(){
const b64payload = encode(String.fromCharCode(...this.payload));
const b64padding = encode(String.fromCharCode(...this.padding));
toJSON() {
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,
}
};
}
}
@ -343,16 +425,22 @@ export class DecodedPayload {
* @param symmetricKey 32 byte symmetric key hex encoded
* @returns DecodedPayload
*/
export function decodeSymmetric(msg: WakuMessage, symmetricKey: String): Promise<DecodedPayload> {
export function decodeSymmetric(
msg: WakuMessage,
symmetricKey: String
): Promise<DecodedPayload> {
return new Promise<DecodedPayload>(async (resolve, reject) => {
let messageJSON = JSON.stringify(msg);
let response = JSON.parse(await ReactNative.decodeSymmetric(messageJSON, symmetricKey));
if(response.error){
let message = new EncryptedPayload(msg);
let messageJSON = JSON.stringify(message);
let response = JSON.parse(
await ReactNative.decodeSymmetric(messageJSON, symmetricKey)
);
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);
@ -361,21 +449,27 @@ export function decodeSymmetric(msg: WakuMessage, symmetricKey: String): Promise
}
/**
* Decrypt a message using a secp256k1 private key
* Decrypt a message using a secp256k1 private key
* @param msg WakuMessage to decode. The message version is expected to be 1
* @param privateKey secp256k1 private key hex encoded
* @returns DecodedPayload
*/
export function decodeAsymmetric(msg: WakuMessage, privateKey: String): Promise<DecodedPayload> {
export function decodeAsymmetric(
msg: WakuMessage,
privateKey: String
): Promise<DecodedPayload> {
return new Promise<DecodedPayload>(async (resolve, reject) => {
let messageJSON = JSON.stringify(msg);
let response = JSON.parse(await ReactNative.decodeSymmetric(messageJSON, privateKey));
if(response.error){
let message = new EncryptedPayload(msg);
let messageJSON = JSON.stringify(message);
let response = JSON.parse(
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);
@ -388,10 +482,10 @@ export function decodeAsymmetric(msg: WakuMessage, privateKey: String): Promise<
* @param pubsubTopic Pubsub topic to verify. If not specified, it will verify the default pubsub topic
* @returns boolean indicates whether there are enough peers
*/
export function relayEnoughPeers(pubsubTopic: String = ""): Promise<Boolean> {
export function relayEnoughPeers(pubsubTopic: String = ''): Promise<Boolean> {
return new Promise<Boolean>(async (resolve, reject) => {
let response = JSON.parse(await ReactNative.relayEnoughPeers(pubsubTopic));
if(response.error){
if (response.error) {
reject(response.error);
} else {
resolve(response.result);
@ -401,12 +495,12 @@ export function relayEnoughPeers(pubsubTopic: String = ""): Promise<Boolean> {
/**
* Closes the pubsub subscription to a pubsub topic. No more messages will be received from this pubsub topic.
* @param pubsubTopic
* @param pubsubTopic
*/
export function relayUnsubscribe(pubsubTopic: String = ""): Promise<void> {
export function relayUnsubscribe(pubsubTopic: String = ''): Promise<void> {
return new Promise<void>(async (resolve, reject) => {
let response = JSON.parse(await ReactNative.relayUnsubscribe(pubsubTopic));
if(response.error){
if (response.error) {
reject(response.error);
} else {
resolve(response.result);
@ -417,16 +511,31 @@ export function relayUnsubscribe(pubsubTopic: String = ""): Promise<void> {
/**
* Publish a message using Waku Lightpush.
* @param msg WakuMessage to publish. The message version is overwritten to `0`
* @param pubsubTopic pubsub topic on which to publish the message. If not specified, it uses the default pubsub topic.
* @param pubsubTopic pubsub topic on which to publish the message. If not specified, it uses the default pubsub topic.
* @param peerID Peer ID supporting the lightpush protocol. The peer must be already known. It must have been added before with `addPeer` or previously dialed with `connect`
* @param timeoutMs Timeout value in milliseconds to execute the call. If the function takes longer than this value, the execution will be canceled and an error returned
* @returns the message ID
*/
export function lightpushPublish(msg: WakuMessage, pubsubTopic: String = "", peerID: String = "", timeoutMs: Number = 0): Promise<string> {
export function lightpushPublish(
msg: WakuMessage,
pubsubTopic: String = '',
peerID: String = '',
timeoutMs: Number = 0
): Promise<string> {
return new Promise<string>(async (resolve, reject) => {
let messageJSON = JSON.stringify(msg)
let response = JSON.parse(await ReactNative.lightpushPublish(messageJSON, pubsubTopic, peerID, timeoutMs));
if(response.error){
let messageJSON = JSON.stringify(msg).replace(
/"timestamp":"([0-9]+)"/,
`"timestamp":$1`
);
let response = JSON.parse(
await ReactNative.lightpushPublish(
messageJSON,
pubsubTopic,
peerID,
timeoutMs
)
);
if (response.error) {
reject(response.error);
} else {
resolve(response.result);
@ -439,16 +548,33 @@ export function lightpushPublish(msg: WakuMessage, pubsubTopic: String = "", pee
* @param msg WakuMessage to publish. The message version is overwritten to `1`
* @param publicKey hex encoded public key to be used for encryption
* @param optionalSigningKey hex encoded private key to be used to sign the message
* @param pubsubTopic pubsub topic on which to publish the message. If not specified, it uses the default pubsub topic.
* @param pubsubTopic pubsub topic on which to publish the message. If not specified, it uses the default pubsub topic.
* @param peerID Peer ID supporting the lightpush protocol. The peer must be already known. It must have been added before with `addPeer` or previously dialed with `connect`
* @param timeoutMs Timeout value in milliseconds to execute the call. If the function takes longer than this value, the execution will be canceled and an error returned
* @returns the message ID
*/
export function lightpushPublishEncAsymmetric(msg: WakuMessage, publicKey: String, optionalSigningKey: String = "", pubsubTopic: String = "", peerID: String = "", timeoutMs: Number = 0): Promise<string> {
export function lightpushPublishEncAsymmetric(
msg: WakuMessage,
publicKey: String,
optionalSigningKey: String = '',
pubsubTopic: String = '',
peerID: String = '',
timeoutMs: Number = 0
): Promise<string> {
return new Promise<string>(async (resolve, reject) => {
let messageJSON = JSON.stringify(msg)
let response = JSON.parse(await ReactNative.lightpushPublishEncodeAsymmetric(messageJSON, pubsubTopic, peerID, publicKey, optionalSigningKey, timeoutMs));
if(response.error){
let message = new EncryptedPayload(msg);
let messageJSON = JSON.stringify(message);
let response = JSON.parse(
await ReactNative.lightpushPublishEncodeAsymmetric(
messageJSON,
pubsubTopic,
peerID,
publicKey,
optionalSigningKey,
timeoutMs
)
);
if (response.error) {
reject(response.error);
} else {
resolve(response.result);
@ -461,16 +587,33 @@ export function lightpushPublishEncAsymmetric(msg: WakuMessage, publicKey: Strin
* @param msg WakuMessage to publish. The message version is overwritten to `1`
* @param symmetricKey hex encoded secret key to be used for encryption.
* @param optionalSigningKey hex encoded private key to be used to sign the message.
* @param pubsubTopic pubsub topic on which to publish the message. If not specified, it uses the default pubsub topic.
* @param pubsubTopic pubsub topic on which to publish the message. If not specified, it uses the default pubsub topic.
* @param peerID Peer ID supporting the lightpush protocol. The peer must be already known. It must have been added before with `addPeer` or previously dialed with `connect`
* @param timeoutMs Timeout value in milliseconds to execute the call. If the function takes longer than this value, the execution will be canceled and an error returned
* @returns the message ID
*/
export function lightpushPublishEncSymmetric(msg: WakuMessage, symmetricKey: String, optionalSigningKey: String = "", pubsubTopic: String = "", peerID: String = "", timeoutMs: Number = 0): Promise<string> {
export function lightpushPublishEncSymmetric(
msg: WakuMessage,
symmetricKey: String,
optionalSigningKey: String = '',
pubsubTopic: String = '',
peerID: String = '',
timeoutMs: Number = 0
): Promise<string> {
return new Promise<string>(async (resolve, reject) => {
let messageJSON = JSON.stringify(msg)
let response = JSON.parse(await ReactNative.lightpushPublishEncodeAsymmetric(messageJSON, pubsubTopic, peerID, symmetricKey, optionalSigningKey, timeoutMs));
if(response.error){
let message = new EncryptedPayload(msg);
let messageJSON = JSON.stringify(message);
let response = JSON.parse(
await ReactNative.lightpushPublishEncodeAsymmetric(
messageJSON,
pubsubTopic,
peerID,
symmetricKey,
optionalSigningKey,
timeoutMs
)
);
if (response.error) {
reject(response.error);
} else {
resolve(response.result);
@ -479,12 +622,17 @@ export function lightpushPublishEncSymmetric(msg: WakuMessage, symmetricKey: Str
}
export class Peer {
addrs: Array<String> = Array()
connected: Boolean = false
peerID: String = ""
protocols: Array<String> = Array()
addrs: Array<String> = Array();
connected: Boolean = false;
peerID: String = '';
protocols: Array<String> = Array();
constructor(addrs: Array<String>, connected: Boolean, peerID: String, protocols: Array<String>){
constructor(
addrs: Array<String>,
connected: Boolean,
peerID: String,
protocols: Array<String>
) {
this.addrs = addrs;
this.connected = connected;
this.peerID = peerID;
@ -499,98 +647,190 @@ export class Peer {
export function peers(): Promise<Array<Peer>> {
return new Promise<Array<Peer>>(async (resolve, reject) => {
let response = JSON.parse(await ReactNative.peers());
if(response.error){
if (response.error) {
reject(response.error);
} else {
resolve(response.result.map((x:any) => new Peer(x.addrs, x.connected, x.peerID, x.protocols)));
resolve(
response.result.map(
(x: any) => new Peer(x.addrs, x.connected, x.peerID, x.protocols)
)
);
}
})
});
}
export class Index {
digest: Uint8Array = new Uint8Array();
receiverTime: Number = 0
senderTime: Number = 0
pubsubTopic: String = ""
}
export class PagingOptions {
pageSize: Number = 0
cursor: Index | null = null
forward: Boolean = false
export class DiscoveredNode {
peerID: String = '';
addrs: Array<String> = Array();
enr: String = '';
constructor(pageSize: Number = 0, forward: Boolean = false, cursor: Index | null = null){
this.pageSize = pageSize
this.forward = forward
this.cursor = cursor
}
}
export class ContentFilter {
contentTopic: String = ""
constructor(contentTopic: String = "") {
this.contentTopic = contentTopic
}
}
export class StoreQuery {
pubsubTopic: String | null = null
contentFilters: Array<ContentFilter> = Array()
startTime: Number = 0
endTime: Number = 0
pagingOptions: PagingOptions | null = null
constructor(pubsubTopic: String | null = null, contentFilters: Array<ContentFilter> = Array(), startTime: Number = 0, endTime: Number = 0, pagingOptions: PagingOptions | null = null) {
this.pubsubTopic = pubsubTopic
this.contentFilters = contentFilters
this.startTime = startTime
this.endTime = endTime
this.pagingOptions = pagingOptions
constructor(
peerID: String,
addrs: Array<String>,
enr: String
) {
this.peerID = peerID;
this.addrs = addrs;
this.enr = enr;
}
}
/**
*
* @param query
* @param peerID
* @param timeoutMs Timeout value in milliseconds to execute the call. If the function takes longer than this value, the execution will be canceled and an error returned
* @returns
* Use DNS Discovery to retrieve a list of nodes from an enrtree:// URL
* @return List of Nodes
*/
export function storeQuery(query: StoreQuery, peerID: String = "", timeoutMs: Number = 0): Promise<any> {
return new Promise<string>(async (resolve, reject) => {
let queryJSON = JSON.stringify(query)
let response = JSON.parse(await ReactNative.storeQuery(queryJSON, peerID, timeoutMs));
if(response.error){
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;
senderTime: Number = 0;
pubsubTopic: String = '';
}
export class PagingOptions {
pageSize: Number = 0;
cursor: Index | null = null;
forward: Boolean = false;
constructor(
pageSize: Number = 0,
forward: Boolean = false,
cursor: Index | null = null
) {
this.pageSize = pageSize;
this.forward = forward;
this.cursor = cursor;
}
}
export class ContentFilter {
contentTopic: String = '';
constructor(contentTopic: String = '') {
this.contentTopic = contentTopic;
}
}
export class StoreQuery {
pubsubTopic: String | null = null;
contentFilters: Array<ContentFilter> = Array();
startTime?: Date = undefined;
endTime?: Date = undefined;
pagingOptions: PagingOptions | null = null;
constructor(
pubsubTopic: String | null = null,
contentFilters: Array<ContentFilter> = Array(),
startTime: Date | undefined = undefined,
endTime: Date | undefined = undefined,
pagingOptions: PagingOptions | null = null
) {
this.pubsubTopic = pubsubTopic;
this.contentFilters = contentFilters;
this.startTime = startTime;
this.endTime = endTime;
this.pagingOptions = pagingOptions;
}
}
/**
*
* @param query
* @param peerID
* @param timeoutMs Timeout value in milliseconds to execute the call. If the function takes longer than this value, the execution will be canceled and an error returned
* @returns
*/
export function storeQuery(
query: StoreQuery,
peerID: String = '',
timeoutMs: Number = 0
): Promise<any> {
return new Promise<string>(async (resolve, reject) => {
let queryJSON = JSON.stringify({
pubsubTopic: query.pubsubTopic,
contentFilters: query.contentFilters,
startTime: query.startTime
? bigInt(query.startTime.valueOf()).multiply(OneMillion).toString(10)
: 0,
endTime: query.endTime
? 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)
);
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);
}
});
}
export class FilterSubscription {
pubsubTopic: String | null = null
contentFilters: Array<ContentFilter> = Array()
pubsubTopic: String | null = null;
contentFilters: Array<ContentFilter> = Array();
constructor(pubsubTopic: String | null = null, contentFilters: Array<ContentFilter> = Array()) {
this.pubsubTopic = pubsubTopic
this.contentFilters = contentFilters
constructor(
pubsubTopic: String | null = null,
contentFilters: Array<ContentFilter> = Array()
) {
this.pubsubTopic = pubsubTopic;
this.contentFilters = contentFilters;
}
}
/**
*
* @param filter
* @param peerID
*
* @param filter
* @param peerID
* @param timeoutMs Timeout value in milliseconds to execute the call. If the function takes longer than this value, the execution will be canceled and an error returned
*/
export function filterSubscribe(filter: FilterSubscription, peerID: String = "", timeoutMs: Number = 0): Promise<void> {
export function filterSubscribe(
filter: FilterSubscription,
peerID: String = '',
timeoutMs: Number = 0
): Promise<void> {
return new Promise<void>(async (resolve, reject) => {
let filterJSON = JSON.stringify(filter)
let response = JSON.parse(await ReactNative.filterSubscribe(filterJSON, peerID, timeoutMs));
let filterJSON = JSON.stringify(filter);
let response = JSON.parse(
await ReactNative.filterSubscribe(filterJSON, peerID, timeoutMs)
);
if(response.error){
if (response.error) {
reject(response.error);
} else {
resolve();
@ -599,16 +839,21 @@ export function filterSubscribe(filter: FilterSubscription, peerID: String = "",
}
/**
*
* @param filter
*
* @param filter
* @param timeoutMs Timeout value in milliseconds to execute the call. If the function takes longer than this value, the execution will be canceled and an error returned
*/
export function filterUnsubscribe(filter: FilterSubscription, timeoutMs: Number = 0): Promise<void> {
export function filterUnsubscribe(
filter: FilterSubscription,
timeoutMs: Number = 0
): Promise<void> {
return new Promise<void>(async (resolve, reject) => {
let filterJSON = JSON.stringify(filter)
let response = JSON.parse(await ReactNative.filterUnsubscribe(filterJSON, timeoutMs));
let filterJSON = JSON.stringify(filter);
let response = JSON.parse(
await ReactNative.filterUnsubscribe(filterJSON, timeoutMs)
);
if(response.error){
if (response.error) {
reject(response.error);
} else {
resolve();