2020-05-14 15:20:39 +03:00
|
|
|
/*
|
2020-05-14 17:30:17 +03:00
|
|
|
* Copyright 2020 Fluence Labs Limited
|
2020-05-14 15:20:39 +03:00
|
|
|
*
|
2020-05-14 17:30:17 +03:00
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
2020-05-14 15:20:39 +03:00
|
|
|
*
|
2020-05-14 17:30:17 +03:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2020-05-14 15:20:39 +03:00
|
|
|
*
|
2020-05-14 17:30:17 +03:00
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
2020-05-14 15:20:39 +03:00
|
|
|
*/
|
2022-08-24 18:03:06 +03:00
|
|
|
import { FluenceConnection, ParticleHandler, PeerIdB58 } from '@fluencelabs/interfaces';
|
2022-05-12 17:14:16 +03:00
|
|
|
// @ts-ignore
|
2020-12-23 17:24:22 +03:00
|
|
|
import Websockets from 'libp2p-websockets';
|
2022-05-12 17:14:16 +03:00
|
|
|
// @ts-ignore
|
2020-12-23 17:24:22 +03:00
|
|
|
import Mplex from 'libp2p-mplex';
|
2021-10-20 22:20:43 +03:00
|
|
|
import Lib2p2Peer from 'libp2p';
|
2020-12-23 17:24:22 +03:00
|
|
|
import { decode, encode } from 'it-length-prefixed';
|
2022-05-18 15:33:24 +03:00
|
|
|
import { pipe } from 'it-pipe';
|
2020-09-15 12:09:13 +03:00
|
|
|
import * as log from 'loglevel';
|
2022-05-18 15:33:24 +03:00
|
|
|
import { Noise } from '@chainsafe/libp2p-noise';
|
2021-03-10 15:56:12 +03:00
|
|
|
import PeerId from 'peer-id';
|
2022-08-05 16:43:19 +03:00
|
|
|
import type { MultiaddrInput } from 'multiaddr';
|
2021-08-18 20:13:40 +03:00
|
|
|
import { Multiaddr } from 'multiaddr';
|
2022-05-12 17:14:16 +03:00
|
|
|
// @ts-ignore
|
2021-04-13 15:11:52 +03:00
|
|
|
import { all as allow_all } from 'libp2p-websockets/src/filters';
|
2021-10-20 22:20:43 +03:00
|
|
|
import { Connection } from 'libp2p-interfaces/src/topology';
|
2022-09-05 18:24:19 +03:00
|
|
|
import Buffer from './Buffer';
|
2020-05-14 15:20:39 +03:00
|
|
|
|
2021-08-24 17:37:03 +03:00
|
|
|
export const PROTOCOL_NAME = '/fluence/particle/2.0.0';
|
2020-05-14 15:20:39 +03:00
|
|
|
|
2021-03-25 21:33:27 +03:00
|
|
|
/**
|
|
|
|
* Options to configure fluence connection
|
|
|
|
*/
|
|
|
|
export interface FluenceConnectionOptions {
|
|
|
|
/**
|
2021-10-20 22:20:43 +03:00
|
|
|
* Peer id of the Fluence Peer
|
2021-03-25 21:33:27 +03:00
|
|
|
*/
|
2021-10-20 22:20:43 +03:00
|
|
|
peerId: PeerId;
|
2021-03-25 21:33:27 +03:00
|
|
|
|
|
|
|
/**
|
2021-10-20 22:20:43 +03:00
|
|
|
* Multiaddress of the relay to make connection to
|
2021-03-25 21:33:27 +03:00
|
|
|
*/
|
2022-08-05 16:43:19 +03:00
|
|
|
relayAddress: MultiaddrInput;
|
2021-03-25 21:33:27 +03:00
|
|
|
|
|
|
|
/**
|
2021-10-20 22:20:43 +03:00
|
|
|
* The dialing timeout in milliseconds
|
2021-03-25 21:33:27 +03:00
|
|
|
*/
|
2021-10-20 22:20:43 +03:00
|
|
|
dialTimeoutMs?: number;
|
2022-08-05 16:43:19 +03:00
|
|
|
}
|
2021-10-20 22:20:43 +03:00
|
|
|
|
2022-08-05 16:43:19 +03:00
|
|
|
/**
|
|
|
|
* Implementation for JS peers which connects to Fluence through relay node
|
|
|
|
*/
|
|
|
|
export class RelayConnection extends FluenceConnection {
|
|
|
|
constructor(
|
|
|
|
public peerId: PeerIdB58,
|
|
|
|
private _lib2p2Peer: Lib2p2Peer,
|
|
|
|
private _relayAddress: Multiaddr,
|
|
|
|
public readonly relayPeerId: PeerIdB58,
|
|
|
|
) {
|
|
|
|
super();
|
|
|
|
}
|
2021-04-13 15:11:52 +03:00
|
|
|
|
2022-05-12 17:14:16 +03:00
|
|
|
private _connection?: Connection;
|
2021-04-13 15:11:52 +03:00
|
|
|
|
2022-08-05 16:43:19 +03:00
|
|
|
static async createConnection(options: FluenceConnectionOptions): Promise<RelayConnection> {
|
2021-04-27 17:08:18 +03:00
|
|
|
const transportKey = Websockets.prototype[Symbol.toStringTag];
|
2022-05-12 17:14:16 +03:00
|
|
|
const lib2p2Peer = await Lib2p2Peer.create({
|
2021-10-20 22:20:43 +03:00
|
|
|
peerId: options.peerId,
|
2020-05-14 15:20:39 +03:00
|
|
|
modules: {
|
|
|
|
transport: [Websockets],
|
|
|
|
streamMuxer: [Mplex],
|
2022-05-18 15:33:24 +03:00
|
|
|
connEncryption: [new Noise()],
|
2020-05-14 15:20:39 +03:00
|
|
|
},
|
2021-04-13 15:11:52 +03:00
|
|
|
config: {
|
|
|
|
transport: {
|
|
|
|
[transportKey]: {
|
2021-04-27 17:08:18 +03:00
|
|
|
filter: allow_all,
|
|
|
|
},
|
|
|
|
},
|
2021-04-13 15:11:52 +03:00
|
|
|
},
|
2021-03-25 21:33:27 +03:00
|
|
|
dialer: {
|
2021-10-20 22:20:43 +03:00
|
|
|
dialTimeout: options?.dialTimeoutMs,
|
2021-03-25 21:33:27 +03:00
|
|
|
},
|
2020-05-14 15:20:39 +03:00
|
|
|
});
|
|
|
|
|
2022-08-05 16:43:19 +03:00
|
|
|
const relayMultiaddr = new Multiaddr(options.relayAddress);
|
|
|
|
const relayPeerId = relayMultiaddr.getPeerId();
|
|
|
|
if (relayPeerId === null) {
|
|
|
|
throw new Error('Specified multiaddr is invalid or missing peer id: ' + options.relayAddress);
|
|
|
|
}
|
2020-05-14 15:20:39 +03:00
|
|
|
|
2022-08-05 16:43:19 +03:00
|
|
|
return new RelayConnection(
|
|
|
|
// force new line
|
|
|
|
options.peerId.toB58String(),
|
|
|
|
lib2p2Peer,
|
|
|
|
relayMultiaddr,
|
|
|
|
relayPeerId,
|
|
|
|
);
|
2020-05-14 15:20:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
async disconnect() {
|
2022-08-05 16:43:19 +03:00
|
|
|
await this._lib2p2Peer.unhandle(PROTOCOL_NAME);
|
2021-10-20 22:20:43 +03:00
|
|
|
await this._lib2p2Peer.stop();
|
2020-05-14 15:20:39 +03:00
|
|
|
}
|
|
|
|
|
2022-08-05 16:43:19 +03:00
|
|
|
async sendParticle(nextPeerIds: PeerIdB58[], particle: string): Promise<void> {
|
|
|
|
if (nextPeerIds.length !== 1 && nextPeerIds[0] !== this.relayPeerId) {
|
|
|
|
throw new Error(
|
|
|
|
`Relay connection only accepts peer id of the connected relay. Got: ${JSON.stringify(
|
|
|
|
nextPeerIds,
|
|
|
|
)} instead.`,
|
|
|
|
);
|
|
|
|
}
|
2021-10-20 22:20:43 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
TODO:: find out why this doesn't work and a new connection has to be established each time
|
|
|
|
if (this._connection.streams.length !== 1) {
|
2022-05-12 17:14:16 +03:00
|
|
|
throw new Error('Incorrect number of streams in FluenceConnection');
|
2021-10-20 22:20:43 +03:00
|
|
|
}
|
2020-09-28 17:01:49 +03:00
|
|
|
|
2021-10-20 22:20:43 +03:00
|
|
|
const sink = this._connection.streams[0].sink;
|
|
|
|
*/
|
2020-05-14 15:20:39 +03:00
|
|
|
|
2021-10-20 22:20:43 +03:00
|
|
|
const conn = await this._lib2p2Peer.dialProtocol(this._relayAddress, PROTOCOL_NAME);
|
|
|
|
const sink = conn.stream.sink;
|
2020-05-14 15:20:39 +03:00
|
|
|
|
|
|
|
pipe(
|
2021-10-20 22:20:43 +03:00
|
|
|
// force new line
|
2022-08-05 16:43:19 +03:00
|
|
|
[Buffer.from(particle, 'utf8')],
|
2020-05-14 15:20:39 +03:00
|
|
|
encode(),
|
2021-10-20 22:20:43 +03:00
|
|
|
sink,
|
2020-05-14 15:20:39 +03:00
|
|
|
);
|
|
|
|
}
|
2021-10-20 22:20:43 +03:00
|
|
|
|
2022-08-05 16:43:19 +03:00
|
|
|
async connect(onIncomingParticle: ParticleHandler) {
|
2021-10-20 22:20:43 +03:00
|
|
|
await this._lib2p2Peer.start();
|
|
|
|
|
2022-08-05 16:43:19 +03:00
|
|
|
this._lib2p2Peer.handle([PROTOCOL_NAME], async ({ connection, stream }) => {
|
|
|
|
pipe(
|
|
|
|
stream.source,
|
|
|
|
// @ts-ignore
|
|
|
|
decode(),
|
|
|
|
async (source: AsyncIterable<string>) => {
|
|
|
|
try {
|
|
|
|
for await (const msg of source) {
|
|
|
|
try {
|
|
|
|
onIncomingParticle(msg);
|
|
|
|
} catch (e) {
|
|
|
|
log.error('error on handling a new incoming message: ' + e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
log.debug('connection closed: ' + e);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2021-10-20 22:20:43 +03:00
|
|
|
log.debug(`dialing to the node with client's address: ` + this._lib2p2Peer.peerId.toB58String());
|
|
|
|
|
|
|
|
try {
|
|
|
|
this._connection = await this._lib2p2Peer.dial(this._relayAddress);
|
2022-05-12 17:14:16 +03:00
|
|
|
} catch (e: any) {
|
|
|
|
if (e.name === 'AggregateError' && e._errors?.length === 1) {
|
2021-10-20 22:20:43 +03:00
|
|
|
const error = e._errors[0];
|
2022-05-12 17:14:16 +03:00
|
|
|
throw new Error(`Error dialing node ${this._relayAddress}:\n${error.code}\n${error.message}`);
|
2021-10-20 22:20:43 +03:00
|
|
|
} else {
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-06-19 14:29:06 +03:00
|
|
|
}
|