Skip to content

Commit

Permalink
feat: .type property on Errors emitted from connections (#1126)
Browse files Browse the repository at this point in the history
  • Loading branch information
jonasgloning committed Sep 2, 2023
2 parents 880c486 + ad3a0cb commit debe7a6
Show file tree
Hide file tree
Showing 14 changed files with 134 additions and 80 deletions.
24 changes: 18 additions & 6 deletions lib/baseconnection.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import { EventEmitter, ValidEventTypes } from "eventemitter3";
import type { Peer } from "./peer";
import type { ServerMessage } from "./servermessage";
import type { ConnectionType } from "./enums";
import { BaseConnectionErrorType } from "./enums";
import {
EventEmitterWithError,
type EventsWithError,
PeerError,
} from "./peerError";
import type { ValidEventTypes } from "eventemitter3";

export type BaseConnectionEvents = {
export interface BaseConnectionEvents<
ErrorType extends string = BaseConnectionErrorType,
> extends EventsWithError<ErrorType> {
/**
* Emitted when either you or the remote peer closes the connection.
*
Expand All @@ -17,13 +25,17 @@ export type BaseConnectionEvents = {
* connection.on('error', (error) => { ... });
* ```
*/
error: (error: Error) => void;
error: (error: PeerError<`${ErrorType}`>) => void;
iceStateChanged: (state: RTCIceConnectionState) => void;
};
}

export abstract class BaseConnection<
T extends ValidEventTypes,
> extends EventEmitter<T & BaseConnectionEvents> {
SubClassEvents extends ValidEventTypes,
ErrorType extends string = never,
> extends EventEmitterWithError<
ErrorType | BaseConnectionErrorType,
SubClassEvents & BaseConnectionEvents<BaseConnectionErrorType | ErrorType>
> {
protected _open = false;

/**
Expand Down
2 changes: 1 addition & 1 deletion lib/cborPeer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Peer, SerializerMapping } from "./peer";
import { Peer, type SerializerMapping } from "./peer";
import { Cbor } from "./dataconnection/StreamConnection/Cbor";

export class CborPeer extends Peer {
Expand Down
2 changes: 1 addition & 1 deletion lib/dataconnection/BufferedConnection/BinaryPack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import logger from "../../logger";
import type { Peer } from "../../peer";
import { BufferedConnection } from "./BufferedConnection";
import { SerializationType } from "../../enums";
import { type Packable, pack, unpack } from "peerjs-js-binarypack";
import { pack, type Packable, unpack } from "peerjs-js-binarypack";

export class BinaryPack extends BufferedConnection {
private readonly chunker = new BinaryPackChunker();
Expand Down
8 changes: 6 additions & 2 deletions lib/dataconnection/BufferedConnection/Json.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { BufferedConnection } from "./BufferedConnection";
import { SerializationType } from "../../enums";
import { DataConnectionErrorType, SerializationType } from "../../enums";
import { util } from "../../util";

export class Json extends BufferedConnection {
readonly serialization = SerializationType.JSON;
private readonly encoder = new TextEncoder();
Expand All @@ -26,7 +27,10 @@ export class Json extends BufferedConnection {
override _send(data, _chunked) {
const encodedData = this.encoder.encode(this.stringify(data));
if (encodedData.byteLength >= util.chunkedMTU) {
this.emit("error", new Error("Message too big for JSON channel"));
this.emitError(
DataConnectionErrorType.MessageToBig,
"Message too big for JSON channel",
);
return;
}
this._bufferedSend(encodedData);
Expand Down
34 changes: 19 additions & 15 deletions lib/dataconnection/DataConnection.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
import logger from "../logger";
import { Negotiator } from "../negotiator";
import { ConnectionType, ServerMessageType } from "../enums";
import {
BaseConnectionErrorType,
ConnectionType,
DataConnectionErrorType,
ServerMessageType,
} from "../enums";
import type { Peer } from "../peer";
import { BaseConnection } from "../baseconnection";
import { BaseConnection, type BaseConnectionEvents } from "../baseconnection";
import type { ServerMessage } from "../servermessage";
import type { DataConnection as IDataConnection } from "./DataConnection";
import type { EventsWithError } from "../peerError";
import { randomToken } from "../utils/randomToken";

type DataConnectionEvents = {
export interface DataConnectionEvents
extends EventsWithError<DataConnectionErrorType | BaseConnectionErrorType>,
BaseConnectionEvents<DataConnectionErrorType | BaseConnectionErrorType> {
/**
* Emitted when data is received from the remote peer.
*/
Expand All @@ -16,23 +23,22 @@ type DataConnectionEvents = {
* Emitted when the connection is established and ready-to-use.
*/
open: () => void;
};
}

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

private _negotiator: Negotiator<DataConnectionEvents, this>;
abstract readonly serialization: string;
readonly reliable: boolean;

// public type: ConnectionType.Data;
public get type() {
return ConnectionType.Data;
}
Expand Down Expand Up @@ -123,11 +129,9 @@ export abstract class DataConnection
/** Allows user to send data. */
public send(data: any, chunked = false) {
if (!this.open) {
super.emit(
"error",
new Error(
"Connection is not open. You should listen for the `open` event before sending messages.",
),
this.emitError(
DataConnectionErrorType.NotOpenYet,
"Connection is not open. You should listen for the `open` event before sending messages.",
);
return;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/dataconnection/StreamConnection/Cbor.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Peer } from "../../peer.js";
import { Encoder, Decoder } from "cbor-x";
import { Decoder, Encoder } from "cbor-x";
import { StreamConnection } from "./StreamConnection.js";

const NullValue = Symbol.for(null);
Expand Down
10 changes: 10 additions & 0 deletions lib/enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@ export enum PeerErrorType {
WebRTC = "webrtc",
}

export enum BaseConnectionErrorType {
NegotiationFailed = "negotiation-failed",
ConnectionClosed = "connection-closed",
}

export enum DataConnectionErrorType {
NotOpenYet = "not-open-yet",
MessageToBig = "message-too-big",
}

export enum SerializationType {
Binary = "binary",
BinaryUTF8 = "binary-utf8",
Expand Down
11 changes: 3 additions & 8 deletions lib/exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Peer } from "./peer";
import { CborPeer } from "./cborPeer";
import { MsgPackPeer } from "./msgPackPeer";

export type { PeerEvents, PeerError, PeerOptions } from "./peer";
export type { PeerEvents, PeerOptions } from "./peer";

export type {
PeerJSOption,
Expand All @@ -15,13 +15,7 @@ export type { UtilSupportsObj } from "./util";
export type { DataConnection } from "./dataconnection/DataConnection";
export type { MediaConnection } from "./mediaconnection";
export type { LogLevel } from "./logger";
export type {
ConnectionType,
PeerErrorType,
SerializationType,
SocketEventType,
ServerMessageType,
} from "./enums";
export * from "./enums";

export { BufferedConnection } from "./dataconnection/BufferedConnection/BufferedConnection";
export { StreamConnection } from "./dataconnection/StreamConnection/StreamConnection";
Expand All @@ -31,4 +25,5 @@ export type { SerializerMapping } from "./peer";

export { Peer, MsgPackPeer, CborPeer };

export { PeerError } from "./peerError";
export default Peer;
8 changes: 4 additions & 4 deletions lib/mediaconnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import logger from "./logger";
import { Negotiator } from "./negotiator";
import { ConnectionType, ServerMessageType } from "./enums";
import type { Peer } from "./peer";
import { BaseConnection } from "./baseconnection";
import { BaseConnection, type BaseConnectionEvents } from "./baseconnection";
import type { ServerMessage } from "./servermessage";
import type { AnswerOption } from "./optionInterfaces";

export type MediaConnectionEvents = {
export interface MediaConnectionEvents extends BaseConnectionEvents<never> {
/**
* Emitted when a connection to the PeerServer is established.
*
Expand All @@ -22,7 +22,7 @@ export type MediaConnectionEvents = {
* @beta
*/
willCloseOnRemote: () => void;
};
}

/**
* Wraps WebRTC's media streams.
Expand All @@ -32,7 +32,7 @@ export class MediaConnection extends BaseConnection<MediaConnectionEvents> {
private static readonly ID_PREFIX = "mc_";
readonly label: string;

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

Expand Down
2 changes: 1 addition & 1 deletion lib/msgPackPeer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Peer, SerializerMapping } from "./peer";
import { Peer, type SerializerMapping } from "./peer";
import { MsgPack } from "./exports";

export class MsgPackPeer extends Peer {
Expand Down
25 changes: 15 additions & 10 deletions lib/negotiator.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import logger from "./logger";
import type { MediaConnection } from "./mediaconnection";
import type { DataConnection } from "./dataconnection/DataConnection";
import { ConnectionType, PeerErrorType, ServerMessageType } from "./enums";
import {
BaseConnectionErrorType,
ConnectionType,
PeerErrorType,
ServerMessageType,
} from "./enums";
import type { BaseConnection, BaseConnectionEvents } from "./baseconnection";
import type { ValidEventTypes } from "eventemitter3";

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

/** Returns a PeerConnection object set up correctly (for data, media). */
startConnection(options: any) {
Expand Down Expand Up @@ -88,19 +93,19 @@ export class Negotiator<
logger.log(
"iceConnectionState is failed, closing connections to " + peerId,
);
this.connection.emit(
"error",
new Error("Negotiation of connection to " + peerId + " failed."),
this.connection.emitError(
BaseConnectionErrorType.NegotiationFailed,
"Negotiation of connection to " + peerId + " failed.",
);
this.connection.close();
break;
case "closed":
logger.log(
"iceConnectionState is closed, closing connections to " + peerId,
);
this.connection.emit(
"error",
new Error("Connection to " + peerId + " closed."),
this.connection.emitError(
BaseConnectionErrorType.ConnectionClosed,
"Connection to " + peerId + " closed.",
);
this.connection.close();
break;
Expand Down
40 changes: 10 additions & 30 deletions lib/peer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { EventEmitter } from "eventemitter3";
import { util } from "./util";
import logger, { LogLevel } from "./logger";
import { Socket } from "./socket";
Expand All @@ -7,20 +6,22 @@ import type { DataConnection } from "./dataconnection/DataConnection";
import {
ConnectionType,
PeerErrorType,
SocketEventType,
ServerMessageType,
SocketEventType,
} from "./enums";
import type { ServerMessage } from "./servermessage";
import { API } from "./api";
import type {
CallOption,
PeerConnectOption,
PeerJSOption,
CallOption,
} from "./optionInterfaces";
import { BinaryPack } from "./dataconnection/BufferedConnection/BinaryPack";
import { Raw } from "./dataconnection/BufferedConnection/Raw";
import { Json } from "./dataconnection/BufferedConnection/Json";

import { EventEmitterWithError, PeerError } from "./peerError";

class PeerOptions implements PeerJSOption {
/**
* Prints log messages depending on the debug level passed in.
Expand Down Expand Up @@ -66,21 +67,7 @@ class PeerOptions implements PeerJSOption {
serializers?: SerializerMapping;
}

class PeerError extends Error {
constructor(type: PeerErrorType, err: Error | string) {
if (typeof err === "string") {
super(err);
} else {
super();
Object.assign(this, err);
}

this.type = type;
}

type: PeerErrorType;
}
export type { PeerError, PeerOptions };
export { type PeerOptions };

export type SerializerMapping = {
[key: string]: new (
Expand All @@ -90,7 +77,7 @@ export type SerializerMapping = {
) => DataConnection;
};

export type PeerEvents = {
export interface PeerEvents {
/**
* Emitted when a connection to the PeerServer is established.
*
Expand Down Expand Up @@ -118,12 +105,12 @@ export type PeerEvents = {
*
* Errors from the underlying socket and PeerConnections are forwarded here.
*/
error: (error: PeerError) => void;
};
error: (error: PeerError<`${PeerErrorType}`>) => void;
}
/**
* A peer who can initiate connections with other peers.
*/
export class Peer extends EventEmitter<PeerEvents> {
export class Peer extends EventEmitterWithError<PeerErrorType, PeerEvents> {
private static readonly DEFAULT_KEY = "peerjs";

protected readonly _serializers: SerializerMapping = {
Expand Down Expand Up @@ -500,7 +487,7 @@ export class Peer extends EventEmitter<PeerEvents> {
* @param peer The brokering ID of the remote peer (their {@apilink Peer.id}).
* @param options for specifying details about Peer Connection
*/
connect(peer: string, options: PeerConnectOption): DataConnection {
connect(peer: string, options: PeerConnectOption = {}): DataConnection {
options = {
serialization: "default",
...options,
Expand Down Expand Up @@ -640,13 +627,6 @@ export class Peer extends EventEmitter<PeerEvents> {
}
}

/** Emits a typed error message. */
emitError(type: PeerErrorType, err: string | Error): void {
logger.error("Error:", err);

this.emit("error", new PeerError(type, err));
}

/**
* Destroys the Peer: closes all active connections as well as the connection
* to the server.
Expand Down

0 comments on commit debe7a6

Please sign in to comment.