UNPKG

@mothepro/fancy-p2p

Version:

A quick and efficient way to form p2p groups in the browser

76 lines (75 loc) 3.28 kB
import { Emitter, Listener } from 'fancy-emitter'; import type { Name, LobbyID } from '@mothepro/signaling-lobby'; import { SimpleClient } from './Client.js'; import { MySimplePeer, Sendable } from './Peer.js'; /** Represent where we are in the process of connecting to some peers. */ export declare const enum State { /** Still attempting to connect to the server. */ OFFLINE = 0, /** We are now connected to the server in lobby, waiting to make a group or join a group. */ LOBBY = 1, /** We have accepted a group and trying to make the RTCs. */ LOADING = 2, /** The connections with peers are set and we can now broadcast messages. */ READY = 3 } export default class<T extends Sendable = Sendable> { readonly state: State; /** Activated when the state changes, Cancels when finalized, Deactivates when error is throw. */ readonly stateChange: Emitter<State>; /** Activated when a client joins the lobby. */ readonly lobbyConnection: Listener<SimpleClient>; /** The peers who's connections are still open */ readonly peers: MySimplePeer<T>[]; /** Generator for random integers that will be consistent across connections within [-2 ** 31, 2 ** 31). */ private rng?; private readonly server; protected assert(valid: State, message?: string): true; /** * Generates a random number in [0,1), same as Math.random() * If `isInt` is true, then an integer in range [-2 ** 31, 2 ** 31) is generated instead. * * `state` must be `State.READY`. */ readonly random: (isInt?: boolean) => number; /** * Propose a group with other clients connected to this lobby. * * `state` must be `State.LOBBY`. */ readonly proposeGroup: (...members: SimpleClient[]) => void; /** * Whether a group with the following memebers has been proposed or answered. * * `state` must be `State.LOBBY`. */ readonly groupExists: (...members: SimpleClient[]) => boolean; /** * Send data to all connected peers. * * `state` must be `State.READY`. */ readonly broadcast: (data: T, includeSelf?: boolean) => void; constructor({ name, stuns, lobby, server: { address, version }, fallback, retries, timeout }: { /** Name used to connect to lobby with */ name: Name; /** STUN servers to use to initialize P2P connections */ stuns: string[]; /** Lobby ID to use for this app */ lobby: LobbyID; /** Settings for the signaling server */ server: { /** The address of the signaling server */ address: URL | string; /** The version of `@mothepro/signaling-lobby` the signaling server is running */ version: string; }; /** Whether to use the signaling server as a fallback when a direct connection to peer can not be established. */ fallback?: boolean; /** Number of times to attempt to make an RTC connection, if negative direct p2p connections will not be attempted. Defaults to 1 */ retries?: number; /** The number of milliseconds to wait before giving up on the connection. Doesn't give up by default */ timeout?: number; }); private bindServerState; }