Skip to content
This repository was archived by the owner on Jun 19, 2023. It is now read-only.

feat: browser-to-browser #88

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,12 @@
},
"scripts": {
"generate:proto": "npx protoc --ts_out proto_ts --proto_path src src/*.proto",
"generate:webrtc-peer": "npx protoc --ts_out proto_ts --proto_path src src/peer_transport/pb/hs.proto",
"build": "aegir build",
"test": "aegir test -t browser",
"test:chrome": "aegir test -t browser -f \"./dist/test/**/*.spec.js\" --cov",
"test:firefox": "aegir test -t browser -f \"./dist/test/**/*.spec.js\" -- --browser firefox",
"test:peer": "aegir test -t browser -f \"./dist/test/peer.browser.spec.js\"",
"lint": "aegir lint",
"lint:fix": "aegir lint --fix",
"clean": "aegir clean",
Expand All @@ -138,33 +140,41 @@
"@chainsafe/libp2p-noise": "^10.0.0",
"@libp2p/interface-connection": "^3.0.2",
"@libp2p/interface-peer-id": "^1.0.5",
"@libp2p/interface-stream-muxer": "^3.0.0",
"@libp2p/interface-stream-muxer": "^3.0.4",
"@libp2p/interface-transport": "^2.0.0",
"@libp2p/logger": "^2.0.0",
"@libp2p/peer-id": "^1.1.15",
"@multiformats/multiaddr": "^11.0.3",
"@multiformats/multiaddr": "../libp2p/js-multiaddr",
"@multiformats/mafmt": "../libp2p/js-mafmt",
"@protobuf-ts/runtime": "^2.8.0",
"err-code": "^3.0.1",
"it-handshake": "^4.1.2",
"it-length-prefixed": "^8.0.3",
"it-merge": "^2.0.0",
"it-pb-stream": "^2.0.3",
"it-pipe": "^2.0.4",
"it-pushable": "^3.1.0",
"it-stream-types": "^1.0.4",
"multiformats": "^10.0.0",
"multihashes": "^4.0.3",
"p-defer": "^4.0.0",
"protons-runtime": "^4.0.1",
"timeout-abort-controller": "^3.0.0",
"uint8arraylist": "^2.3.3",
"uint8arrays": "^4.0.2",
"uuid": "^9.0.0"
},
"devDependencies": {
"@libp2p/interface-mocks": "^8.0.1",
"@libp2p/mplex": "^7.1.1",
"@libp2p/peer-id-factory": "^1.0.19",
"@libp2p/websockets": "^5.0.2",
"@protobuf-ts/plugin": "^2.8.0",
"@protobuf-ts/protoc": "^2.8.0",
"@types/uuid": "^8.3.4",
"aegir": "^37.6.6",
"it-first": "^2.0.0",
"libp2p": "^0.40.0"
"libp2p": "file:../js-libp2p",
"protons": "^6.0.1"
}
}
97 changes: 97 additions & 0 deletions proto_ts/peer_transport/pb/hs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// @generated by protobuf-ts 2.8.2
// @generated from protobuf file "peer_transport/pb/hs.proto" (package "webrtc_peer.pb", syntax proto2)
// tslint:disable
import type { BinaryWriteOptions } from "@protobuf-ts/runtime";
import type { IBinaryWriter } from "@protobuf-ts/runtime";
import { WireType } from "@protobuf-ts/runtime";
import type { BinaryReadOptions } from "@protobuf-ts/runtime";
import type { IBinaryReader } from "@protobuf-ts/runtime";
import { UnknownFieldHandler } from "@protobuf-ts/runtime";
import type { PartialMessage } from "@protobuf-ts/runtime";
import { reflectionMergePartial } from "@protobuf-ts/runtime";
import { MESSAGE_TYPE } from "@protobuf-ts/runtime";
import { MessageType } from "@protobuf-ts/runtime";
/**
* @generated from protobuf message webrtc_peer.pb.Message
*/
export interface Message {
/**
* @generated from protobuf field: webrtc_peer.pb.Message.MessageType type = 1;
*/
type: Message_MessageType;
/**
* @generated from protobuf field: string data = 2;
*/
data: string;
}
/**
* @generated from protobuf enum webrtc_peer.pb.Message.MessageType
*/
export enum Message_MessageType {
/**
* @generated from protobuf enum value: OFFER = 0;
*/
OFFER = 0,
/**
* @generated from protobuf enum value: ANSWER = 1;
*/
ANSWER = 1,
/**
* @generated from protobuf enum value: CANDIDATE = 2;
*/
CANDIDATE = 2
}
// @generated message type with reflection information, may provide speed optimized methods
class Message$Type extends MessageType<Message> {
constructor() {
super("webrtc_peer.pb.Message", [
{ no: 1, name: "type", kind: "enum", T: () => ["webrtc_peer.pb.Message.MessageType", Message_MessageType] },
{ no: 2, name: "data", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
]);
}
create(value?: PartialMessage<Message>): Message {
const message = { type: 0, data: "" };
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
if (value !== undefined)
reflectionMergePartial<Message>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Message): Message {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* webrtc_peer.pb.Message.MessageType type */ 1:
message.type = reader.int32();
break;
case /* string data */ 2:
message.data = reader.string();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: Message, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* webrtc_peer.pb.Message.MessageType type = 1; */
if (message.type !== 0)
writer.tag(1, WireType.Varint).int32(message.type);
/* string data = 2; */
if (message.data !== "")
writer.tag(2, WireType.LengthDelimited).string(message.data);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message webrtc_peer.pb.Message
*/
export const Message = new Message$Type();
6 changes: 6 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import type { Transport } from '@libp2p/interface-transport'
import type { WebRTCPeerTransportComponents, WebRTCPeerTransportInit } from './peer_transport/transport.js'
import { WebRTCPeerTransport } from './peer_transport/transport.js'
import { WebRTCTransport, WebRTCTransportComponents } from './transport.js'

export function webRTC (): (components: WebRTCTransportComponents) => Transport {
return (components: WebRTCTransportComponents) => new WebRTCTransport(components)
}

export function webRTCPeer (init: WebRTCPeerTransportInit): (components: WebRTCPeerTransportComponents) => Transport {
return (components: WebRTCPeerTransportComponents) => new WebRTCPeerTransport(components, init)
}
20 changes: 8 additions & 12 deletions src/muxer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ export class DataChannelMuxerFactory implements StreamMuxerFactory {
*/
private readonly peerConnection: RTCPeerConnection

/**
* The string representation of the protocol, required by `StreamMuxerFactory`
*/
protocol: string = '/webrtc'

constructor (peerConnection: RTCPeerConnection) {
constructor (peerConnection: RTCPeerConnection, readonly protocol = '/webrtc') {
this.peerConnection = peerConnection
// reject any datachannels as the muxer is not yet ready to process
// streams
this.peerConnection.ondatachannel = ({ channel }) => {
channel.close()
}
}

createStreamMuxer (init?: StreamMuxerInit | undefined): StreamMuxer {
return new DataChannelMuxer(this.peerConnection, init)
return new DataChannelMuxer(this.peerConnection, this.protocol, init)
}
}

Expand All @@ -33,10 +33,6 @@ export class DataChannelMuxer implements StreamMuxer {
* WebRTC Peer Connection
*/
private readonly peerConnection: RTCPeerConnection
/**
* The protocol as represented in the multiaddress
*/
readonly protocol: string = '/webrtc'

/**
* Array of streams in the data channel
Expand All @@ -63,7 +59,7 @@ export class DataChannelMuxer implements StreamMuxer {
*/
sink: Sink<Uint8Array, Promise<void>> = nopSink;

constructor (peerConnection: RTCPeerConnection, init?: StreamMuxerInit) {
constructor (peerConnection: RTCPeerConnection, readonly protocol = '/webrtc', init?: StreamMuxerInit) {
/**
* Initialized stream muxer
*/
Expand Down
35 changes: 35 additions & 0 deletions src/peer_transport/listener.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// import type { ConnectionManager } from '@libp2p/interface-connection-manager'
import type { PeerId } from '@libp2p/interface-peer-id'
import type { ListenerEvents, TransportManager, Upgrader, Listener } from '@libp2p/interface-transport'
import { EventEmitter } from '@libp2p/interfaces/events'
import { multiaddr, Multiaddr } from '@multiformats/multiaddr'

export interface ListenerOptions {
peerId: PeerId
upgrader: Upgrader
transportManager: TransportManager
}

export class WebRTCPeerListener extends EventEmitter<ListenerEvents> implements Listener {
constructor (
private readonly opts: ListenerOptions
) {
super()
}

private listeningAddrs: Multiaddr[] = []
async listen (ma: Multiaddr): Promise<void> {
const baseAddr = multiaddr(ma.toString().split('/webrtc-peer').find(a => a !== ''))
const tpt = this.opts.transportManager.transportForMultiaddr(baseAddr)
const listener = tpt?.createListener({ ...this.opts })
await listener?.listen(baseAddr)
const listeningAddr = ma.encapsulate(`/p2p/${this.opts.peerId}`)
this.listeningAddrs.push(listeningAddr)
listener?.addEventListener('close', () => {
this.listeningAddrs = this.listeningAddrs.filter(a => a !== listeningAddr)
})
}

getAddrs (): Multiaddr[] { return this.listeningAddrs }
async close () { }
}
14 changes: 14 additions & 0 deletions src/peer_transport/pb/hs.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
syntax = "proto2";

package webrtc_peer.pb;

message Message {
enum MessageType {
OFFER = 0;
ANSWER = 1;
CANDIDATE = 2;
}

required MessageType type = 1;
required string data = 2;
}
Loading