Skip to content

Commit

Permalink
fix(typings): much stronger event typings for DataConnection,`Media…
Browse files Browse the repository at this point in the history
…Connection`
  • Loading branch information
jonasgloning committed May 25, 2022
1 parent 666dcd9 commit 0c96603
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 72 deletions.
15 changes: 13 additions & 2 deletions lib/baseconnection.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
import { EventEmitter } from "eventemitter3";
import { EventEmitter, ValidEventTypes } from "eventemitter3";
import { Peer } from "./peer";
import { ServerMessage } from "./servermessage";
import { ConnectionType } from "./enums";

export abstract class BaseConnection extends EventEmitter {
export type BaseConnectionEvents = {
/**
* Emitted when either you or the remote peer closes the connection.
*/
close: () => void;
error: (error: Error) => void;
iceStateChanged: (state: RTCIceConnectionState) => void;
};

export abstract class BaseConnection<
T extends ValidEventTypes,
> extends EventEmitter<T & BaseConnectionEvents> {
protected _open = false;

readonly metadata: any;
Expand Down
35 changes: 22 additions & 13 deletions lib/dataconnection.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,35 @@
import { util } from "./util";
import logger from "./logger";
import { Negotiator } from "./negotiator";
import {
ConnectionType,
ConnectionEventType,
SerializationType,
ServerMessageType,
} from "./enums";
import { ConnectionType, SerializationType, ServerMessageType } from "./enums";
import { Peer } from "./peer";
import { BaseConnection } from "./baseconnection";
import { ServerMessage } from "./servermessage";
import { EncodingQueue } from "./encodingQueue";
import type { DataConnection as IDataConnection } from "./dataconnection";

type DataConnectionEvents = {
/**
* Emitted when data is received from the remote peer.
*/
data: (data: unknown) => void;
/**
* Emitted when the connection is established and ready-to-use.
*/
open: () => void;
};

/**
* Wraps a DataChannel between two Peers.
*/
export class DataConnection extends BaseConnection implements IDataConnection {
export class DataConnection
extends BaseConnection<DataConnectionEvents>
implements IDataConnection
{
private static readonly ID_PREFIX = "dc_";
private static readonly MAX_BUFFERED_AMOUNT = 8 * 1024 * 1024;

private _negotiator: Negotiator;
private _negotiator: Negotiator<DataConnectionEvents, DataConnection>;
readonly label: string;
readonly serialization: SerializationType;
readonly reliable: boolean;
Expand Down Expand Up @@ -98,7 +107,7 @@ export class DataConnection extends BaseConnection implements IDataConnection {
this.dataChannel.onopen = () => {
logger.log(`DC#${this.connectionId} dc connection success`);
this._open = true;
this.emit(ConnectionEventType.Open);
this.emit("open");
};

this.dataChannel.onmessage = (e) => {
Expand Down Expand Up @@ -131,7 +140,7 @@ export class DataConnection extends BaseConnection implements IDataConnection {
// Datatype should never be blob
util.blobToArrayBuffer(data as Blob, (ab) => {
const unpackedData = util.unpack(ab);
this.emit(ConnectionEventType.Data, unpackedData);
this.emit("data", unpackedData);
});
return;
} else if (datatype === ArrayBuffer) {
Expand All @@ -152,7 +161,7 @@ export class DataConnection extends BaseConnection implements IDataConnection {
return;
}

super.emit(ConnectionEventType.Data, deserializedData);
super.emit("data", deserializedData);
}

private _handleChunk(data: {
Expand Down Expand Up @@ -222,14 +231,14 @@ export class DataConnection extends BaseConnection implements IDataConnection {

this._open = false;

super.emit(ConnectionEventType.Close);
super.emit("close");
}

/** Allows user to send data. */
send(data: any, chunked?: boolean): void {
if (!this.open) {
super.emit(
ConnectionEventType.Error,
"error",
new Error(
"Connection is not open. You should listen for the `open` event before sending messages.",
),
Expand Down
17 changes: 0 additions & 17 deletions lib/enums.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,8 @@
export enum ConnectionEventType {
Open = "open",
Stream = "stream",
Data = "data",
Close = "close",
Error = "error",
IceStateChanged = "iceStateChanged",
}

export enum ConnectionType {
Data = "data",
Media = "media",
}

export type PeerEventType =
| "open"
| "close"
| "connection"
| "call"
| "disconnected"
| "error";

export enum PeerErrorType {
BrowserIncompatible = "browser-incompatible",
Disconnected = "disconnected",
Expand Down
2 changes: 0 additions & 2 deletions lib/exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ export type { DataConnection } from "./dataconnection";
export type { MediaConnection } from "./mediaconnection";
export type { LogLevel } from "./logger";
export type {
ConnectionEventType,
ConnectionType,
PeerEventType,
PeerErrorType,
SerializationType,
SocketEventType,
Expand Down
21 changes: 12 additions & 9 deletions lib/mediaconnection.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
import { util } from "./util";
import logger from "./logger";
import { Negotiator } from "./negotiator";
import {
ConnectionType,
ConnectionEventType,
ServerMessageType,
} from "./enums";
import { ConnectionType, ServerMessageType } from "./enums";
import { Peer } from "./peer";
import { BaseConnection } from "./baseconnection";
import { ServerMessage } from "./servermessage";
import type { AnswerOption } from "./optionInterfaces";

type MediaConnectionEvents = {
/**
* Emitted when a connection to the PeerServer is established.
*/
stream: (stream: MediaStream) => void;
};

/**
* Wraps the streaming interface between two Peers.
*/
export class MediaConnection extends BaseConnection {
export class MediaConnection extends BaseConnection<MediaConnectionEvents> {
private static readonly ID_PREFIX = "mc_";

private _negotiator: Negotiator;
private _negotiator: Negotiator<MediaConnectionEvents, MediaConnection>;
private _localStream: MediaStream;
private _remoteStream: MediaStream;

Expand Down Expand Up @@ -54,7 +57,7 @@ export class MediaConnection extends BaseConnection {
logger.log("Receiving stream", remoteStream);

this._remoteStream = remoteStream;
super.emit(ConnectionEventType.Stream, remoteStream); // Should we call this `open`?
super.emit("stream", remoteStream); // Should we call this `open`?
}

handleMessage(message: ServerMessage): void {
Expand Down Expand Up @@ -134,6 +137,6 @@ export class MediaConnection extends BaseConnection {

this._open = false;

super.emit(ConnectionEventType.Close);
super.emit("close");
}
}
29 changes: 14 additions & 15 deletions lib/negotiator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@ import { util } from "./util";
import logger from "./logger";
import { MediaConnection } from "./mediaconnection";
import { DataConnection } from "./dataconnection";
import {
ConnectionType,
PeerErrorType,
ConnectionEventType,
ServerMessageType,
} from "./enums";
import { BaseConnection } from "./baseconnection";
import { ConnectionType, PeerErrorType, ServerMessageType } from "./enums";
import { BaseConnection, BaseConnectionEvents } from "./baseconnection";
import { ValidEventTypes } from "eventemitter3";

/**
* Manages all negotiations between Peers.
*/
export class Negotiator {
constructor(readonly connection: BaseConnection) {}
export class Negotiator<
A extends ValidEventTypes,
T extends BaseConnection<A | BaseConnectionEvents>,
> {
constructor(readonly connection: T) {}

/** Returns a PeerConnection object set up correctly (for data, media). */
startConnection(options: any) {
Expand All @@ -30,7 +29,7 @@ export class Negotiator {
// What do we need to do now?
if (options.originator) {
if (this.connection.type === ConnectionType.Data) {
const dataConnection = <DataConnection>this.connection;
const dataConnection = <DataConnection>(<unknown>this.connection);

const config: RTCDataChannelInit = { ordered: !!options.reliable };

Expand Down Expand Up @@ -93,7 +92,7 @@ export class Negotiator {
"iceConnectionState is failed, closing connections to " + peerId,
);
this.connection.emit(
ConnectionEventType.Error,
"error",
new Error("Negotiation of connection to " + peerId + " failed."),
);
this.connection.close();
Expand All @@ -103,7 +102,7 @@ export class Negotiator {
"iceConnectionState is closed, closing connections to " + peerId,
);
this.connection.emit(
ConnectionEventType.Error,
"error",
new Error("Connection to " + peerId + " closed."),
);
this.connection.close();
Expand All @@ -120,7 +119,7 @@ export class Negotiator {
}

this.connection.emit(
ConnectionEventType.IceStateChanged,
"iceStateChanged",
peerConnection.iceConnectionState,
);
};
Expand Down Expand Up @@ -179,7 +178,7 @@ export class Negotiator {
let dataChannelNotClosed = false;

if (this.connection.type === ConnectionType.Data) {
const dataConnection = <DataConnection>this.connection;
const dataConnection = <DataConnection>(<unknown>this.connection);
const dataChannel = dataConnection.dataChannel;

if (dataChannel) {
Expand Down Expand Up @@ -230,7 +229,7 @@ export class Negotiator {
};

if (this.connection.type === ConnectionType.Data) {
const dataConnection = <DataConnection>this.connection;
const dataConnection = <DataConnection>(<unknown>this.connection);

payload = {
...payload,
Expand Down
18 changes: 13 additions & 5 deletions lib/peer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
SocketEventType,
ServerMessageType,
} from "./enums";
import { BaseConnection } from "./baseconnection";
import { ServerMessage } from "./servermessage";
import { API } from "./api";
import type {
Expand Down Expand Up @@ -76,7 +75,10 @@ export class Peer extends EventEmitter<PeerEvents> {
private _destroyed = false; // Connections have been killed
private _disconnected = false; // Connection to PeerServer killed but P2P connections still active
private _open = false; // Sockets and such are not yet open.
private readonly _connections: Map<string, BaseConnection[]> = new Map(); // All connections for this peer.
private readonly _connections: Map<
string,
(DataConnection | MediaConnection)[]
> = new Map(); // All connections for this peer.
private readonly _lostMessages: Map<string, ServerMessage[]> = new Map(); // src => [list of messages]
/**
* The brokering ID of this peer
Expand Down Expand Up @@ -471,7 +473,10 @@ export class Peer extends EventEmitter<PeerEvents> {
}

/** Add a data/media connection to this peer. */
private _addConnection(peerId: string, connection: BaseConnection): void {
private _addConnection(
peerId: string,
connection: MediaConnection | DataConnection,
): void {
logger.log(
`add connection ${connection.type}:${connection.connectionId} to peerId:${peerId}`,
);
Expand All @@ -483,7 +488,7 @@ export class Peer extends EventEmitter<PeerEvents> {
}

//TODO should be private
_removeConnection(connection: BaseConnection): void {
_removeConnection(connection: DataConnection | MediaConnection): void {
const connections = this._connections.get(connection.peer);

if (connections) {
Expand All @@ -499,7 +504,10 @@ export class Peer extends EventEmitter<PeerEvents> {
}

/** Retrieve a data/media connection for this peer. */
getConnection(peerId: string, connectionId: string): null | BaseConnection {
getConnection(
peerId: string,
connectionId: string,
): null | DataConnection | MediaConnection {
const connections = this._connections.get(peerId);
if (!connections) {
return null;
Expand Down
13 changes: 4 additions & 9 deletions test/peer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,7 @@ import "./setup";
import { expect } from "chai";
import { Peer } from "../lib/peer";
import { Server } from "mock-socket";
import {
ConnectionType,
ServerMessageType,
PeerErrorType,
PeerEventType,
} from "../lib/enums";
import { ConnectionType, ServerMessageType } from "../lib/enums";

const createMockServer = (): Server => {
const fakeURL = "ws://localhost:8080/peerjs?key=peerjs&id=1&token=testToken";
Expand Down Expand Up @@ -202,10 +197,10 @@ describe("Peer", function () {

const peer1 = new Peer({ port: 8080, host: "localhost" });

peer1.once(PeerEventType.Error, (error) => {
expect(error.type).to.be.eq(PeerErrorType.ServerError);
peer1.once("error", (_error) => {
// expect(error.type).to.be.eq(PeerErrorType.ServerError);

peer1.once(PeerEventType.Close, () => {
peer1.once("close", () => {
expect(peer1.disconnected).to.be.true;
expect(peer1.destroyed).to.be.true;
expect(peer1.open).to.be.false;
Expand Down

0 comments on commit 0c96603

Please sign in to comment.