@peerbit/react 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/esm/index.d.ts +1 -1
- package/lib/esm/index.js +1 -1
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/usePeer.d.ts +25 -11
- package/lib/esm/usePeer.js +95 -125
- package/lib/esm/usePeer.js.map +1 -1
- package/package.json +4 -5
- package/src/index.ts +1 -6
- package/src/usePeer.tsx +147 -188
package/lib/esm/index.d.ts
CHANGED
package/lib/esm/index.js
CHANGED
package/lib/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAClE,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC"}
|
package/lib/esm/usePeer.d.ts
CHANGED
|
@@ -1,25 +1,39 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Multiaddr } from "@multiformats/multiaddr";
|
|
3
|
-
import { Peerbit } from "peerbit";
|
|
4
3
|
import { Ed25519Keypair } from "@peerbit/crypto";
|
|
4
|
+
import { ProgramClient } from "@peerbit/program";
|
|
5
5
|
export type ConnectionStatus = "disconnected" | "connected" | "connecting" | "failed";
|
|
6
6
|
interface IPeerContext {
|
|
7
|
-
peer:
|
|
7
|
+
peer: ProgramClient | undefined;
|
|
8
8
|
promise: Promise<void> | undefined;
|
|
9
9
|
loading: boolean;
|
|
10
10
|
status: ConnectionStatus;
|
|
11
11
|
}
|
|
12
|
-
export declare const subscribeToKeypairChange: (onChange: (keypair: Ed25519Keypair) => any) => void;
|
|
13
|
-
export declare const submitKeypairChange: (element: HTMLIFrameElement, keypair: Ed25519Keypair, origin: string) => void;
|
|
14
12
|
export declare const PeerContext: React.Context<IPeerContext>;
|
|
15
13
|
export declare const usePeer: () => IPeerContext;
|
|
16
|
-
|
|
14
|
+
type IFrameOptions = {
|
|
15
|
+
type: "proxy";
|
|
16
|
+
targetOrigin: string;
|
|
17
|
+
};
|
|
18
|
+
type NodeOptions = {
|
|
19
|
+
type?: "node";
|
|
17
20
|
network: "local" | "remote";
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
waitForConnnected?: boolean;
|
|
22
|
+
keypair?: Ed25519Keypair;
|
|
23
|
+
bootstrap?: (Multiaddr | string)[];
|
|
24
|
+
host?: boolean;
|
|
25
|
+
};
|
|
26
|
+
type TopOptions = NodeOptions & WithMemory;
|
|
27
|
+
type TopAndIframeOptions = {
|
|
28
|
+
iframe: IFrameOptions | NodeOptions;
|
|
29
|
+
top: TopOptions;
|
|
30
|
+
};
|
|
31
|
+
type WithMemory = {
|
|
32
|
+
inMemory?: boolean;
|
|
33
|
+
};
|
|
34
|
+
type WithChildren = {
|
|
23
35
|
children: JSX.Element;
|
|
24
|
-
}
|
|
36
|
+
};
|
|
37
|
+
type PeerOptions = (TopAndIframeOptions | TopOptions) & WithChildren;
|
|
38
|
+
export declare const PeerProvider: (options: PeerOptions) => import("react/jsx-runtime").JSX.Element;
|
|
25
39
|
export {};
|
package/lib/esm/usePeer.js
CHANGED
|
@@ -1,41 +1,23 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import React, { useContext } from "react";
|
|
3
|
-
import { multiaddr } from "@multiformats/multiaddr";
|
|
4
3
|
import { Peerbit } from "peerbit";
|
|
5
4
|
import { webSockets } from "@libp2p/websockets";
|
|
5
|
+
import { DirectSub } from "@peerbit/pubsub";
|
|
6
6
|
import { mplex } from "@libp2p/mplex";
|
|
7
7
|
import { getFreeKeypair, getTabId, inIframe } from "./utils.js";
|
|
8
|
-
import { resolveBootstrapAddresses } from "@peerbit/network-utils";
|
|
9
8
|
import { noise } from "@dao-xyz/libp2p-noise";
|
|
10
9
|
import { v4 as uuid } from "uuid";
|
|
11
|
-
import { Ed25519Keypair } from "@peerbit/crypto";
|
|
12
10
|
import { FastMutex } from "./lockstorage.js";
|
|
13
|
-
import { serialize, deserialize } from "@dao-xyz/borsh";
|
|
14
|
-
import { waitFor } from "@peerbit/time";
|
|
15
11
|
import sodium from "libsodium-wrappers";
|
|
16
12
|
import * as filters from "@libp2p/websockets/filters";
|
|
17
13
|
import { useMount } from "./useMount.js";
|
|
14
|
+
import { createClient, createHost } from "@peerbit/proxy-window";
|
|
18
15
|
if (!window.name) {
|
|
19
16
|
window.name = uuid();
|
|
20
17
|
}
|
|
21
|
-
export const subscribeToKeypairChange = (onChange) => {
|
|
22
|
-
window.onmessage = (c) => {
|
|
23
|
-
if (c.data.type == "keypair") {
|
|
24
|
-
onChange(deserialize(c.data.bytes, Ed25519Keypair));
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
};
|
|
28
|
-
export const submitKeypairChange = (element, keypair, origin) => {
|
|
29
|
-
element.contentWindow.postMessage({ type: "keypair", bytes: serialize(keypair) }, origin);
|
|
30
|
-
};
|
|
31
|
-
let keypairMessages = [];
|
|
32
|
-
subscribeToKeypairChange((keypair) => {
|
|
33
|
-
console.log("got keypair!", keypair);
|
|
34
|
-
keypairMessages.push(keypair);
|
|
35
|
-
});
|
|
36
18
|
export const PeerContext = React.createContext({});
|
|
37
19
|
export const usePeer = () => useContext(PeerContext);
|
|
38
|
-
export const PeerProvider = (
|
|
20
|
+
export const PeerProvider = (options) => {
|
|
39
21
|
const [peer, setPeer] = React.useState(undefined);
|
|
40
22
|
const [promise, setPromise] = React.useState(undefined);
|
|
41
23
|
const [loading, setLoading] = React.useState(false);
|
|
@@ -54,127 +36,115 @@ export const PeerProvider = ({ network, bootstrap, children, inMemory, keypair,
|
|
|
54
36
|
]);
|
|
55
37
|
useMount(() => {
|
|
56
38
|
setLoading(true);
|
|
57
|
-
const fn = async (
|
|
39
|
+
const fn = async () => {
|
|
58
40
|
await sodium.ready;
|
|
59
|
-
if (!keypair && waitForKeypairInIFrame && inIframe()) {
|
|
60
|
-
await waitFor(() => (keypair = keypairMessages[keypairMessages.length - 1]));
|
|
61
|
-
}
|
|
62
|
-
if (keypair &&
|
|
63
|
-
keypairMessages[keypairMessages.length - 1] &&
|
|
64
|
-
keypairMessages[keypairMessages.length - 1].equals(keypair)) {
|
|
65
|
-
console.log("Creating client from identity sent from parent window: " +
|
|
66
|
-
keypair.publicKey.hashcode());
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
if (!keypair) {
|
|
70
|
-
console.log("Generating new keypair for client");
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
console.log("Keypair missmatch with latest keypair message", keypairMessages.map((x) => x.publicKey.hashcode()), keypair.publicKey.hashcode());
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
41
|
if (peer) {
|
|
77
42
|
await peer.stop();
|
|
78
43
|
setPeer(undefined);
|
|
79
44
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
)
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
? {
|
|
100
|
-
connectionGater: {
|
|
101
|
-
denyDialMultiaddr: () => {
|
|
102
|
-
// by default we refuse to dial local addresses from the browser since they
|
|
103
|
-
// are usually sent by remote peers broadcasting undialable multiaddrs but
|
|
104
|
-
// here we are explicitly connecting to a local node so do not deny dialing
|
|
105
|
-
// any discovered address
|
|
106
|
-
return false;
|
|
107
|
-
},
|
|
108
|
-
},
|
|
109
|
-
transports: [
|
|
110
|
-
// Add websocket impl so we can connect to "unsafe" ws (production only allows wss)
|
|
111
|
-
webSockets({
|
|
112
|
-
filter: filters.all,
|
|
113
|
-
}),
|
|
114
|
-
/* circuitRelayTransport({ discoverRelays: 1 }),
|
|
115
|
-
webRTC(), */
|
|
45
|
+
let newPeer;
|
|
46
|
+
const nodeOptions = options.top
|
|
47
|
+
? inIframe()
|
|
48
|
+
? options.iframe
|
|
49
|
+
: options.top
|
|
50
|
+
: options;
|
|
51
|
+
if (nodeOptions.type !== "proxy") {
|
|
52
|
+
const nodeId = nodeOptions.keypair ||
|
|
53
|
+
(await getFreeKeypair("", new FastMutex({
|
|
54
|
+
clientId: getTabId(),
|
|
55
|
+
timeout: 1000,
|
|
56
|
+
}), undefined, true // reuse keypairs from same tab, (force release)
|
|
57
|
+
)).key;
|
|
58
|
+
// We create a new directrory to make tab to tab communication go smoothly
|
|
59
|
+
newPeer = await Peerbit.create({
|
|
60
|
+
libp2p: {
|
|
61
|
+
addresses: {
|
|
62
|
+
listen: [
|
|
63
|
+
/* '/webrtc' */
|
|
116
64
|
],
|
|
117
|
-
}
|
|
118
|
-
:
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
65
|
+
},
|
|
66
|
+
connectionEncryption: [noise()],
|
|
67
|
+
peerId: await nodeId.toPeerId(),
|
|
68
|
+
connectionManager: {
|
|
69
|
+
maxConnections: 100,
|
|
70
|
+
minConnections: 0,
|
|
71
|
+
},
|
|
72
|
+
streamMuxers: [mplex()],
|
|
73
|
+
...(nodeOptions.network === "local"
|
|
74
|
+
? {
|
|
75
|
+
connectionGater: {
|
|
76
|
+
denyDialMultiaddr: () => {
|
|
77
|
+
// by default we refuse to dial local addresses from the browser since they
|
|
78
|
+
// are usually sent by remote peers broadcasting undialable multiaddrs but
|
|
79
|
+
// here we are explicitly connecting to a local node so do not deny dialing
|
|
80
|
+
// any discovered address
|
|
81
|
+
return false;
|
|
82
|
+
},
|
|
126
83
|
},
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
84
|
+
transports: [
|
|
85
|
+
// Add websocket impl so we can connect to "unsafe" ws (production only allows wss)
|
|
86
|
+
webSockets({
|
|
87
|
+
filter: filters.all,
|
|
88
|
+
}),
|
|
89
|
+
/* circuitRelayTransport({ discoverRelays: 1 }),
|
|
90
|
+
webRTC(), */
|
|
91
|
+
],
|
|
92
|
+
}
|
|
93
|
+
: {
|
|
94
|
+
transports: [
|
|
95
|
+
webSockets({ filter: filters.wss }),
|
|
96
|
+
/* circuitRelayTransport({ discoverRelays: 1 }),
|
|
97
|
+
webRTC(), */
|
|
98
|
+
],
|
|
99
|
+
}),
|
|
100
|
+
services: {
|
|
101
|
+
pubsub: (c) => new DirectSub(c, {
|
|
102
|
+
canRelayMessage: true,
|
|
103
|
+
emitSelf: true,
|
|
104
|
+
}),
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
directory: !nodeOptions.inMemory
|
|
108
|
+
? "./repo"
|
|
109
|
+
: undefined,
|
|
110
|
+
limitSigning: true,
|
|
111
|
+
});
|
|
112
|
+
setConnectionState("connecting");
|
|
113
|
+
// Resolve bootstrap nodes async (we want to return before this is done)
|
|
114
|
+
const connectFn = async () => {
|
|
115
|
+
try {
|
|
116
|
+
if (nodeOptions.network === "local") {
|
|
117
|
+
await newPeer.dial("/ip4/127.0.0.1/tcp/8002/ws/p2p/" +
|
|
118
|
+
(await (await fetch("http://localhost:8082/peer/id")).text()));
|
|
151
119
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
throw error;
|
|
120
|
+
else {
|
|
121
|
+
// TODO fix types. When proxy client this will not be available
|
|
122
|
+
await newPeer["bootstrap"]?.();
|
|
156
123
|
}
|
|
124
|
+
setConnectionState("connected");
|
|
157
125
|
}
|
|
158
|
-
|
|
159
|
-
console.error("
|
|
126
|
+
catch (err) {
|
|
127
|
+
console.error("Failed to resolve relay addresses. " + err?.message);
|
|
160
128
|
setConnectionState("failed");
|
|
161
129
|
}
|
|
130
|
+
if (nodeOptions.host) {
|
|
131
|
+
newPeer = await createHost(newPeer);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
const promise = connectFn();
|
|
135
|
+
// Make sure data flow as expected between tabs and windows locally (offline states)
|
|
136
|
+
if (nodeOptions.waitForConnnected) {
|
|
137
|
+
await promise;
|
|
162
138
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
};
|
|
168
|
-
const promise = connectFn();
|
|
169
|
-
// Make sure data flow as expected between tabs and windows locally (offline states)
|
|
170
|
-
if (waitForConnnected) {
|
|
171
|
-
await promise;
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
newPeer = await createClient(nodeOptions.targetOrigin);
|
|
172
142
|
}
|
|
173
143
|
setPeer(newPeer);
|
|
174
144
|
setLoading(false);
|
|
175
145
|
};
|
|
176
|
-
setPromise(fn(
|
|
146
|
+
setPromise(fn());
|
|
177
147
|
});
|
|
178
|
-
return _jsx(PeerContext.Provider, { value: memo, children: children });
|
|
148
|
+
return (_jsx(PeerContext.Provider, { value: memo, children: options.children }));
|
|
179
149
|
};
|
|
180
150
|
//# sourceMappingURL=usePeer.js.map
|
package/lib/esm/usePeer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePeer.js","sourceRoot":"","sources":["../../src/usePeer.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"usePeer.js","sourceRoot":"","sources":["../../src/usePeer.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peerbit/react",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"homepage": "https://dao-xyz.github.io/peerbit-examples",
|
|
5
5
|
"module": "lib/esm/index.js",
|
|
6
6
|
"types": "lib/esm/index.d.ts",
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"@libp2p/webrtc": "^2.0.11",
|
|
28
28
|
"@mui/icons-material": "^5.10.16",
|
|
29
29
|
"@mui/material": "^5.10.13",
|
|
30
|
-
"@peerbit/
|
|
30
|
+
"@peerbit/proxy-window": "^1.0.1",
|
|
31
31
|
"@types/react": "^18.0.25",
|
|
32
32
|
"@types/react-dom": "^18.0.8",
|
|
33
33
|
"path-browserify": "^1.0.1",
|
|
34
|
-
"peerbit": "^1
|
|
34
|
+
"peerbit": "^1",
|
|
35
35
|
"react": "^18.2.0",
|
|
36
36
|
"react-dom": "^18.2.0",
|
|
37
37
|
"react-router-dom": "^6.8.0",
|
|
@@ -42,7 +42,6 @@
|
|
|
42
42
|
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
|
43
43
|
"@babel/plugin-transform-typescript": "^7.20.2",
|
|
44
44
|
"@types/sinon": "^10.0.13",
|
|
45
|
-
"gh-pages": "^4.0.0",
|
|
46
45
|
"node-localstorage": "^2.2.1",
|
|
47
46
|
"sinon": "^15.0.1"
|
|
48
47
|
},
|
|
@@ -72,5 +71,5 @@
|
|
|
72
71
|
"last 1 safari version"
|
|
73
72
|
]
|
|
74
73
|
},
|
|
75
|
-
"gitHead": "
|
|
74
|
+
"gitHead": "61243721632f276a5b6109e147ec375947da9afd"
|
|
76
75
|
}
|
package/src/index.ts
CHANGED
package/src/usePeer.tsx
CHANGED
|
@@ -2,25 +2,26 @@ import React, { useContext } from "react";
|
|
|
2
2
|
import { multiaddr, Multiaddr } from "@multiformats/multiaddr";
|
|
3
3
|
import { Peerbit } from "peerbit";
|
|
4
4
|
import { webSockets } from "@libp2p/websockets";
|
|
5
|
+
import { DirectSub } from "@peerbit/pubsub";
|
|
5
6
|
import { mplex } from "@libp2p/mplex";
|
|
6
7
|
import { getFreeKeypair, getTabId, inIframe } from "./utils.js";
|
|
7
|
-
import { resolveBootstrapAddresses } from "@peerbit/network-utils";
|
|
8
8
|
import { noise } from "@dao-xyz/libp2p-noise";
|
|
9
9
|
import { v4 as uuid } from "uuid";
|
|
10
10
|
import { Ed25519Keypair } from "@peerbit/crypto";
|
|
11
11
|
import { FastMutex } from "./lockstorage.js";
|
|
12
|
-
import { serialize, deserialize } from "@dao-xyz/borsh";
|
|
13
|
-
import { waitFor } from "@peerbit/time";
|
|
14
12
|
import sodium from "libsodium-wrappers";
|
|
15
13
|
import * as filters from "@libp2p/websockets/filters";
|
|
16
14
|
import { useMount } from "./useMount.js";
|
|
15
|
+
import { createClient, createHost } from "@peerbit/proxy-window";
|
|
16
|
+
import { ProgramClient } from "@peerbit/program";
|
|
17
|
+
|
|
17
18
|
export type ConnectionStatus =
|
|
18
19
|
| "disconnected"
|
|
19
20
|
| "connected"
|
|
20
21
|
| "connecting"
|
|
21
22
|
| "failed";
|
|
22
23
|
interface IPeerContext {
|
|
23
|
-
peer:
|
|
24
|
+
peer: ProgramClient | undefined;
|
|
24
25
|
promise: Promise<void> | undefined;
|
|
25
26
|
loading: boolean;
|
|
26
27
|
status: ConnectionStatus;
|
|
@@ -30,59 +31,39 @@ if (!window.name) {
|
|
|
30
31
|
window.name = uuid();
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
bytes: Uint8Array;
|
|
36
|
-
}
|
|
37
|
-
export const subscribeToKeypairChange = (
|
|
38
|
-
onChange: (keypair: Ed25519Keypair) => any
|
|
39
|
-
) => {
|
|
40
|
-
window.onmessage = (c: MessageEvent) => {
|
|
41
|
-
if ((c.data as KeypairMessage).type == "keypair") {
|
|
42
|
-
onChange(
|
|
43
|
-
deserialize((c.data as KeypairMessage).bytes, Ed25519Keypair)
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
};
|
|
34
|
+
export const PeerContext = React.createContext<IPeerContext>({} as any);
|
|
35
|
+
export const usePeer = () => useContext(PeerContext);
|
|
48
36
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
origin: string
|
|
53
|
-
) => {
|
|
54
|
-
element.contentWindow!.postMessage(
|
|
55
|
-
{ type: "keypair", bytes: serialize(keypair) } as KeypairMessage,
|
|
56
|
-
origin
|
|
57
|
-
);
|
|
37
|
+
type IFrameOptions = {
|
|
38
|
+
type: "proxy";
|
|
39
|
+
targetOrigin: string;
|
|
58
40
|
};
|
|
59
41
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
console.log("got keypair!", keypair);
|
|
63
|
-
keypairMessages.push(keypair);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
export const PeerContext = React.createContext<IPeerContext>({} as any);
|
|
67
|
-
export const usePeer = () => useContext(PeerContext);
|
|
68
|
-
export const PeerProvider = ({
|
|
69
|
-
network,
|
|
70
|
-
bootstrap,
|
|
71
|
-
children,
|
|
72
|
-
inMemory,
|
|
73
|
-
keypair,
|
|
74
|
-
waitForConnnected,
|
|
75
|
-
waitForKeypairInIFrame,
|
|
76
|
-
}: {
|
|
42
|
+
type NodeOptions = {
|
|
43
|
+
type?: "node";
|
|
77
44
|
network: "local" | "remote";
|
|
78
|
-
inMemory?: boolean;
|
|
79
45
|
waitForConnnected?: boolean;
|
|
80
46
|
keypair?: Ed25519Keypair;
|
|
81
|
-
waitForKeypairInIFrame?: boolean;
|
|
82
47
|
bootstrap?: (Multiaddr | string)[];
|
|
48
|
+
host?: boolean;
|
|
49
|
+
};
|
|
50
|
+
type TopOptions = NodeOptions & WithMemory;
|
|
51
|
+
type TopAndIframeOptions = {
|
|
52
|
+
iframe: IFrameOptions | NodeOptions;
|
|
53
|
+
top: TopOptions;
|
|
54
|
+
};
|
|
55
|
+
type WithMemory = {
|
|
56
|
+
inMemory?: boolean;
|
|
57
|
+
};
|
|
58
|
+
type WithChildren = {
|
|
83
59
|
children: JSX.Element;
|
|
84
|
-
}
|
|
85
|
-
|
|
60
|
+
};
|
|
61
|
+
type PeerOptions = (TopAndIframeOptions | TopOptions) & WithChildren;
|
|
62
|
+
|
|
63
|
+
export const PeerProvider = (options: PeerOptions) => {
|
|
64
|
+
const [peer, setPeer] = React.useState<ProgramClient | undefined>(
|
|
65
|
+
undefined
|
|
66
|
+
);
|
|
86
67
|
const [promise, setPromise] = React.useState<Promise<void> | undefined>(
|
|
87
68
|
undefined
|
|
88
69
|
);
|
|
@@ -108,163 +89,141 @@ export const PeerProvider = ({
|
|
|
108
89
|
|
|
109
90
|
useMount(() => {
|
|
110
91
|
setLoading(true);
|
|
111
|
-
const fn = async (
|
|
112
|
-
keypair: Ed25519Keypair = keypairMessages[
|
|
113
|
-
keypairMessages.length - 1
|
|
114
|
-
]
|
|
115
|
-
) => {
|
|
92
|
+
const fn = async () => {
|
|
116
93
|
await sodium.ready;
|
|
117
|
-
|
|
118
|
-
if (!keypair && waitForKeypairInIFrame && inIframe()) {
|
|
119
|
-
await waitFor(
|
|
120
|
-
() =>
|
|
121
|
-
(keypair = keypairMessages[keypairMessages.length - 1])
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (
|
|
126
|
-
keypair &&
|
|
127
|
-
keypairMessages[keypairMessages.length - 1] &&
|
|
128
|
-
keypairMessages[keypairMessages.length - 1].equals(keypair)
|
|
129
|
-
) {
|
|
130
|
-
console.log(
|
|
131
|
-
"Creating client from identity sent from parent window: " +
|
|
132
|
-
keypair.publicKey.hashcode()
|
|
133
|
-
);
|
|
134
|
-
} else {
|
|
135
|
-
if (!keypair) {
|
|
136
|
-
console.log("Generating new keypair for client");
|
|
137
|
-
} else {
|
|
138
|
-
console.log(
|
|
139
|
-
"Keypair missmatch with latest keypair message",
|
|
140
|
-
keypairMessages.map((x) => x.publicKey.hashcode()),
|
|
141
|
-
keypair.publicKey.hashcode()
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
94
|
if (peer) {
|
|
147
95
|
await peer.stop();
|
|
148
96
|
setPeer(undefined);
|
|
149
97
|
}
|
|
150
98
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
(
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
99
|
+
let newPeer: ProgramClient;
|
|
100
|
+
const nodeOptions = (options as TopAndIframeOptions).top
|
|
101
|
+
? inIframe()
|
|
102
|
+
? (options as TopAndIframeOptions).iframe
|
|
103
|
+
: (options as TopAndIframeOptions).top
|
|
104
|
+
: (options as TopOptions);
|
|
105
|
+
if (nodeOptions.type !== "proxy") {
|
|
106
|
+
const nodeId =
|
|
107
|
+
nodeOptions.keypair ||
|
|
108
|
+
(
|
|
109
|
+
await getFreeKeypair(
|
|
110
|
+
"",
|
|
111
|
+
new FastMutex({
|
|
112
|
+
clientId: getTabId(),
|
|
113
|
+
timeout: 1000,
|
|
114
|
+
}),
|
|
115
|
+
undefined,
|
|
116
|
+
true // reuse keypairs from same tab, (force release)
|
|
117
|
+
)
|
|
118
|
+
).key;
|
|
119
|
+
|
|
120
|
+
// We create a new directrory to make tab to tab communication go smoothly
|
|
121
|
+
newPeer = await Peerbit.create({
|
|
122
|
+
libp2p: {
|
|
123
|
+
addresses: {
|
|
124
|
+
listen: [
|
|
125
|
+
/* '/webrtc' */
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
connectionEncryption: [noise()],
|
|
129
|
+
peerId: await nodeId.toPeerId(), //, having the same peer accross broswers does not work, only one tab will be recognized by other peers
|
|
130
|
+
connectionManager: {
|
|
131
|
+
maxConnections: 100,
|
|
132
|
+
minConnections: 0,
|
|
133
|
+
},
|
|
134
|
+
streamMuxers: [mplex()],
|
|
135
|
+
...(nodeOptions.network === "local"
|
|
136
|
+
? {
|
|
137
|
+
connectionGater: {
|
|
138
|
+
denyDialMultiaddr: () => {
|
|
139
|
+
// by default we refuse to dial local addresses from the browser since they
|
|
140
|
+
// are usually sent by remote peers broadcasting undialable multiaddrs but
|
|
141
|
+
// here we are explicitly connecting to a local node so do not deny dialing
|
|
142
|
+
// any discovered address
|
|
143
|
+
return false;
|
|
144
|
+
},
|
|
186
145
|
},
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
.
|
|
231
|
-
typeof a === "string" ? multiaddr(a) : a
|
|
232
|
-
)
|
|
233
|
-
.map((a) => newPeer.dial(a))
|
|
234
|
-
);
|
|
235
|
-
setConnectionState("connected");
|
|
236
|
-
} catch (error) {
|
|
237
|
-
console.error(
|
|
238
|
-
"Failed to resolve relay node. Please come back later or start the demo locally"
|
|
146
|
+
transports: [
|
|
147
|
+
// Add websocket impl so we can connect to "unsafe" ws (production only allows wss)
|
|
148
|
+
webSockets({
|
|
149
|
+
filter: filters.all,
|
|
150
|
+
}),
|
|
151
|
+
/* circuitRelayTransport({ discoverRelays: 1 }),
|
|
152
|
+
webRTC(), */
|
|
153
|
+
],
|
|
154
|
+
}
|
|
155
|
+
: {
|
|
156
|
+
transports: [
|
|
157
|
+
webSockets({ filter: filters.wss }),
|
|
158
|
+
/* circuitRelayTransport({ discoverRelays: 1 }),
|
|
159
|
+
webRTC(), */
|
|
160
|
+
],
|
|
161
|
+
}),
|
|
162
|
+
|
|
163
|
+
services: {
|
|
164
|
+
pubsub: (c) =>
|
|
165
|
+
new DirectSub(c, {
|
|
166
|
+
canRelayMessage: true,
|
|
167
|
+
emitSelf: true,
|
|
168
|
+
}),
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
directory: !(nodeOptions as WithMemory).inMemory
|
|
172
|
+
? "./repo"
|
|
173
|
+
: undefined,
|
|
174
|
+
limitSigning: true,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
setConnectionState("connecting");
|
|
178
|
+
|
|
179
|
+
// Resolve bootstrap nodes async (we want to return before this is done)
|
|
180
|
+
const connectFn = async () => {
|
|
181
|
+
try {
|
|
182
|
+
if (nodeOptions.network === "local") {
|
|
183
|
+
await newPeer.dial(
|
|
184
|
+
"/ip4/127.0.0.1/tcp/8002/ws/p2p/" +
|
|
185
|
+
(await (
|
|
186
|
+
await fetch(
|
|
187
|
+
"http://localhost:8082/peer/id"
|
|
188
|
+
)
|
|
189
|
+
).text())
|
|
239
190
|
);
|
|
240
|
-
|
|
241
|
-
|
|
191
|
+
} else {
|
|
192
|
+
// TODO fix types. When proxy client this will not be available
|
|
193
|
+
await newPeer["bootstrap"]?.();
|
|
242
194
|
}
|
|
243
|
-
|
|
244
|
-
|
|
195
|
+
setConnectionState("connected");
|
|
196
|
+
} catch (err: any) {
|
|
197
|
+
console.error(
|
|
198
|
+
"Failed to resolve relay addresses. " + err?.message
|
|
199
|
+
);
|
|
245
200
|
setConnectionState("failed");
|
|
246
201
|
}
|
|
247
|
-
} catch (err: any) {
|
|
248
|
-
console.error(
|
|
249
|
-
"Failed to resolve relay addresses. " + err?.message
|
|
250
|
-
);
|
|
251
|
-
setConnectionState("failed");
|
|
252
|
-
}
|
|
253
|
-
};
|
|
254
202
|
|
|
255
|
-
|
|
203
|
+
if (nodeOptions.host) {
|
|
204
|
+
newPeer = await createHost(newPeer);
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const promise = connectFn();
|
|
256
209
|
|
|
257
|
-
|
|
210
|
+
// Make sure data flow as expected between tabs and windows locally (offline states)
|
|
258
211
|
|
|
259
|
-
|
|
260
|
-
|
|
212
|
+
if (nodeOptions.waitForConnnected) {
|
|
213
|
+
await promise;
|
|
214
|
+
}
|
|
215
|
+
} else {
|
|
216
|
+
newPeer = await createClient(nodeOptions.targetOrigin);
|
|
261
217
|
}
|
|
262
|
-
|
|
263
218
|
setPeer(newPeer);
|
|
264
219
|
setLoading(false);
|
|
265
220
|
};
|
|
266
|
-
setPromise(fn(
|
|
221
|
+
setPromise(fn());
|
|
267
222
|
});
|
|
268
223
|
|
|
269
|
-
return
|
|
224
|
+
return (
|
|
225
|
+
<PeerContext.Provider value={memo}>
|
|
226
|
+
{options.children}
|
|
227
|
+
</PeerContext.Provider>
|
|
228
|
+
);
|
|
270
229
|
};
|