Skip to content

Commit

Permalink
await new Peer()
Browse files Browse the repository at this point in the history
  • Loading branch information
jonasgloning committed Aug 28, 2023
1 parent 9a0c9ef commit ecafaf4
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 53 deletions.
46 changes: 46 additions & 0 deletions e2e/peer/id-taken.await.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title></title>
<link rel="stylesheet" href="../style.css" />
</head>
<body>
<h1>ID-TAKEN</h1>
<div id="messages"></div>
<div id="error-message"></div>
<script src="/dist/peerjs.js"></script>
<script type="module">
/**
* @type {typeof import("../..").Peer}
*/
const Peer = window.peerjs.Peer;

const messages = document.getElementById("messages");
const errorMessage = document.getElementById("error-message");

// Peer A should be created without an error
try {
const peerA = await new Peer();
// Create 10 new `Peer`s that will try to steel A's id
let peers_try_to_take = Array.from({ length: 10 }, async (_, i) => {
try {
await new Peer(peerA.id);
throw `Peer ${i} failed! Connection got established.`;
} catch (error) {
if (error.type === "unavailable-id") {
return `ID already taken. (${i})`;
} else {
throw error;
}
}
});
await Promise.all(peers_try_to_take);
messages.textContent = "No ID takeover";
} catch (error) {
errorMessage.textContent += JSON.stringify(error);
}
</script>
</body>
</html>
7 changes: 7 additions & 0 deletions e2e/peer/peer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,10 @@ describe("Peer", () => {
expect(await P.errorMessage.getText()).toBe("");
});
});
describe("Peer:async", () => {
it("should emit an error, when the ID is already taken", async () => {
await P.open("id-taken.await");
await P.waitForMessage("No ID takeover");
expect(await P.errorMessage.getText()).toBe("");
});
});
134 changes: 81 additions & 53 deletions lib/peer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,76 @@ export type PeerEvents = {
*/
error: (error: PeerError) => void;
};

export interface IPeer {
/**
* The brokering ID of this peer
*
* If no ID was specified in {@apilink Peer | the constructor},
* this will be `undefined` until the {@apilink PeerEvents | `open`} event is emitted.
*/
get id(): string;
get open(): boolean;
/**
* A hash of all connections associated with this peer, keyed by the remote peer's ID.
* @deprecated
* Return type will change from Object to Map<string,[]>
*/
get connections(): Object;
/**
* true if this peer and all of its connections can no longer be used.
*/
get destroyed(): boolean;
/**
* Connects to the remote peer specified by id and returns a data connection.
* @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;
/**
* Calls the remote peer specified by id and returns a media connection.
* @param peer The brokering ID of the remote peer (their peer.id).
* @param stream The caller's media stream
* @param options Metadata associated with the connection, passed in by whoever initiated the connection.
*/
call(peer: string, stream: MediaStream, options: CallOption): MediaConnection;
/** Retrieve a data/media connection for this peer. */
getConnection(
peerId: string,
connectionId: string,
): null | DataConnection | MediaConnection;
/**
* Destroys the Peer: closes all active connections as well as the connection
* to the server.
*
* :::caution
* This cannot be undone; the respective peer object will no longer be able
* to create or receive any connections, its ID will be forfeited on the server,
* and all of its data and media connections will be closed.
* :::
*/
destroy(): void;
/**
* Disconnects the Peer's connection to the PeerServer. Does not close any
* active connections.
* Warning: The peer can no longer create or accept connections after being
* disconnected. It also cannot reconnect to the server.
*/
disconnect(): void;
/** Attempts to reconnect with the same ID.
*
* Only {@apilink Peer.disconnect | disconnected peers} can be reconnected.
* Destroyed peers cannot be reconnected.
* If the connection fails (as an example, if the peer's old ID is now taken),
* the peer's existing connections will not close, but any associated errors events will fire.
*/
reconnect(): void;
}

/**
* A peer who can initiate connections with other peers.
*/
export class Peer extends EventEmitter<PeerEvents> {
export class Peer extends EventEmitter<PeerEvents> implements IPeer {
private static readonly DEFAULT_KEY = "peerjs";

private readonly _serializers: SerializerMapping = {
Expand All @@ -150,12 +216,11 @@ export class Peer extends EventEmitter<PeerEvents> {
(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
*
* If no ID was specified in {@apilink Peer | the constructor},
* this will be `undefined` until the {@apilink PeerEvents | `open`} event is emitted.
*/
private then: (
onfulfilled?: (value: IPeer) => any,
onrejected?: (reason: PeerError) => any,
) => void;

get id() {
return this._id;
}
Expand All @@ -175,11 +240,6 @@ export class Peer extends EventEmitter<PeerEvents> {
return this._socket;
}

/**
* A hash of all connections associated with this peer, keyed by the remote peer's ID.
* @deprecated
* Return type will change from Object to Map<string,[]>
*/
get connections(): Object {
const plainConnections = Object.create(null);

Expand All @@ -190,15 +250,9 @@ export class Peer extends EventEmitter<PeerEvents> {
return plainConnections;
}

/**
* true if this peer and all of its connections can no longer be used.
*/
get destroyed() {
return this._destroyed;
}
/**
* false if there is an active connection to the PeerServer.
*/
get disconnected() {
return this._disconnected;
}
Expand Down Expand Up @@ -226,6 +280,15 @@ export class Peer extends EventEmitter<PeerEvents> {
constructor(id?: string | PeerOptions, options?: PeerOptions) {
super();

this.then = (
onfulfilled?: (value: IPeer) => any,
onrejected?: (reason: PeerError) => any,
) => {
delete this.then;
this.once("open", () => onfulfilled?.(this));
this.once("error", onrejected);
};

let userId: string | undefined;

// Deal with overloading
Expand Down Expand Up @@ -495,11 +558,6 @@ export class Peer extends EventEmitter<PeerEvents> {
return [];
}

/**
* Connects to the remote peer specified by id and returns a data connection.
* @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 {
options = {
serialization: "default",
Expand Down Expand Up @@ -528,12 +586,6 @@ export class Peer extends EventEmitter<PeerEvents> {
return dataConnection;
}

/**
* Calls the remote peer specified by id and returns a media connection.
* @param peer The brokering ID of the remote peer (their peer.id).
* @param stream The caller's media stream
* @param options Metadata associated with the connection, passed in by whoever initiated the connection.
*/
call(
peer: string,
stream: MediaStream,
Expand Down Expand Up @@ -598,7 +650,6 @@ export class Peer extends EventEmitter<PeerEvents> {
this._lostMessages.delete(connection.connectionId);
}

/** Retrieve a data/media connection for this peer. */
getConnection(
peerId: string,
connectionId: string,
Expand Down Expand Up @@ -647,16 +698,6 @@ export class Peer extends EventEmitter<PeerEvents> {
this.emit("error", new PeerError(type, err));
}

/**
* Destroys the Peer: closes all active connections as well as the connection
* to the server.
*
* :::caution
* This cannot be undone; the respective peer object will no longer be able
* to create or receive any connections, its ID will be forfeited on the server,
* and all of its data and media connections will be closed.
* :::
*/
destroy(): void {
if (this.destroyed) {
return;
Expand Down Expand Up @@ -693,12 +734,6 @@ export class Peer extends EventEmitter<PeerEvents> {
}
}

/**
* Disconnects the Peer's connection to the PeerServer. Does not close any
* active connections.
* Warning: The peer can no longer create or accept connections after being
* disconnected. It also cannot reconnect to the server.
*/
disconnect(): void {
if (this.disconnected) {
return;
Expand All @@ -719,13 +754,6 @@ export class Peer extends EventEmitter<PeerEvents> {
this.emit("disconnected", currentId);
}

/** Attempts to reconnect with the same ID.
*
* Only {@apilink Peer.disconnect | disconnected peers} can be reconnected.
* Destroyed peers cannot be reconnected.
* If the connection fails (as an example, if the peer's old ID is now taken),
* the peer's existing connections will not close, but any associated errors events will fire.
*/
reconnect(): void {
if (this.disconnected && !this.destroyed) {
logger.log(
Expand Down

0 comments on commit ecafaf4

Please sign in to comment.