소스 검색

fix(typings): much stronger event typings for `DataConnection`,`MediaConnection`

Jonas Gloning 3 년 전
부모
커밋
0c96603a3f
8개의 변경된 파일78개의 추가작업 그리고 72개의 파일을 삭제
  1. 13 2
      lib/baseconnection.ts
  2. 22 13
      lib/dataconnection.ts
  3. 0 17
      lib/enums.ts
  4. 0 2
      lib/exports.ts
  5. 12 9
      lib/mediaconnection.ts
  6. 14 15
      lib/negotiator.ts
  7. 13 5
      lib/peer.ts
  8. 4 9
      test/peer.ts

+ 13 - 2
lib/baseconnection.ts

@@ -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;

+ 22 - 13
lib/dataconnection.ts

@@ -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;
@@ -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) => {
@@ -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) {
@@ -152,7 +161,7 @@ export class DataConnection extends BaseConnection implements IDataConnection {
 			return;
 		}
 
-		super.emit(ConnectionEventType.Data, deserializedData);
+		super.emit("data", deserializedData);
 	}
 
 	private _handleChunk(data: {
@@ -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.",
 				),

+ 0 - 17
lib/enums.ts

@@ -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",

+ 0 - 2
lib/exports.ts

@@ -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,

+ 12 - 9
lib/mediaconnection.ts

@@ -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;
 
@@ -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 {
@@ -134,6 +137,6 @@ export class MediaConnection extends BaseConnection {
 
 		this._open = false;
 
-		super.emit(ConnectionEventType.Close);
+		super.emit("close");
 	}
 }

+ 14 - 15
lib/negotiator.ts

@@ -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) {
@@ -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 };
 
@@ -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();
@@ -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();
@@ -120,7 +119,7 @@ export class Negotiator {
 			}
 
 			this.connection.emit(
-				ConnectionEventType.IceStateChanged,
+				"iceStateChanged",
 				peerConnection.iceConnectionState,
 			);
 		};
@@ -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) {
@@ -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,

+ 13 - 5
lib/peer.ts

@@ -10,7 +10,6 @@ import {
 	SocketEventType,
 	ServerMessageType,
 } from "./enums";
-import { BaseConnection } from "./baseconnection";
 import { ServerMessage } from "./servermessage";
 import { API } from "./api";
 import type {
@@ -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
@@ -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}`,
 		);
@@ -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) {
@@ -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;

+ 4 - 9
test/peer.ts

@@ -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";
@@ -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;