Browse Source

feat: `await peer.connect(...)`

Jonas Gloning 1 năm trước cách đây
mục cha
commit
bee2bdbcfc

+ 1 - 1
e2e/peer/id-taken.await.html

@@ -14,7 +14,7 @@
 		<script type="application/javascript">
 			(async () => {
 				/**
-				 * @type {typeof import("../..").Peer}
+				 * @type {typeof import("../../lib/exports.ts").Peer}
 				 */
 				const Peer = window.peerjs.Peer;
 

+ 41 - 0
e2e/peer/peer-unavailable.async.html

@@ -0,0 +1,41 @@
+<!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>PEER-UNAVAILABLE</h1>
+		<div id="messages"></div>
+		<div id="error-message"></div>
+		<script src="/dist/peerjs.js"></script>
+		<script type="application/javascript">
+			(async () => {
+				/**
+				 * @type {typeof import("../../lib/exports.ts").Peer}
+				 */
+				const Peer = window.peerjs.Peer;
+
+				const messages = document.getElementById("messages");
+				const errors = document.getElementById("error-message");
+
+				const not_existing_peer = crypto
+					.getRandomValues(new Uint8Array(16))
+					.join("");
+
+				try {
+					const peer = await new Peer();
+					await peer.connect(not_existing_peer);
+				} catch (error) {
+					if (error.type === "peer-unavailable") {
+						messages.textContent = "Success: Peer unavailable";
+					} else {
+						errors.textContent += JSON.stringify(error);
+					}
+				}
+			})();
+		</script>
+	</body>
+</html>

+ 5 - 0
e2e/peer/peer.spec.ts

@@ -29,4 +29,9 @@ describe("Peer:async", () => {
 		await P.waitForMessage("No ID takeover");
 		expect(await P.errorMessage.getText()).toBe("");
 	});
+	it("should emit an error, when the remote peer is unavailable", async () => {
+		await P.open("peer-unavailable.async");
+		await P.waitForMessage("Success: Peer unavailable");
+		expect(await P.errorMessage.getText()).toBe("");
+	});
 });

+ 27 - 2
lib/dataconnection/DataConnection.ts

@@ -11,6 +11,7 @@ import { BaseConnection, type BaseConnectionEvents } from "../baseconnection";
 import type { ServerMessage } from "../servermessage";
 import type { EventsWithError } from "../peerError";
 import { randomToken } from "../utils/randomToken";
+import { PeerError } from "../peerError";
 
 export interface DataConnectionEvents
 	extends EventsWithError<DataConnectionErrorType | BaseConnectionErrorType>,
@@ -25,6 +26,14 @@ export interface DataConnectionEvents
 	open: () => void;
 }
 
+export interface IDataConnection
+	extends BaseConnection<DataConnectionEvents, DataConnectionErrorType> {
+	/** Allows user to close connection. */
+	close(options?: { flush?: boolean }): void;
+	/** Allows user to send data. */
+	send(data: any, chunked?: boolean): void;
+}
+
 /**
  * Wraps a DataChannel between two Peers.
  */
@@ -38,6 +47,10 @@ export abstract class DataConnection extends BaseConnection<
 	private _negotiator: Negotiator<DataConnectionEvents, this>;
 	abstract readonly serialization: string;
 	readonly reliable: boolean;
+	private then: (
+		onfulfilled?: (value: IDataConnection) => any,
+		onrejected?: (reason: PeerError<DataConnectionErrorType>) => any,
+	) => void;
 
 	public get type() {
 		return ConnectionType.Data;
@@ -46,6 +59,20 @@ export abstract class DataConnection extends BaseConnection<
 	constructor(peerId: string, provider: Peer, options: any) {
 		super(peerId, provider, options);
 
+		this.then = (
+			onfulfilled?: (value: IDataConnection) => any,
+			onrejected?: (reason: PeerError<DataConnectionErrorType>) => any,
+		) => {
+			// Remove 'then' to prevent potential recursion issues
+			// `await` will wait for a Promise-like to resolve recursively
+			delete this.then;
+
+			// We don’t need to worry about cleaning up listeners here
+			// `await`ing a Promise will make sure only one of the paths executes
+			this.once("open", () => onfulfilled(this));
+			this.once("error", onrejected);
+		};
+
 		this.connectionId =
 			this.options.connectionId || DataConnection.ID_PREFIX + randomToken();
 
@@ -87,7 +114,6 @@ export abstract class DataConnection extends BaseConnection<
 	 * Exposed functionality for users.
 	 */
 
-	/** Allows user to close connection. */
 	close(options?: { flush?: boolean }): void {
 		if (options?.flush) {
 			this.send({
@@ -126,7 +152,6 @@ export abstract class DataConnection extends BaseConnection<
 
 	protected abstract _send(data: any, chunked: boolean): void;
 
-	/** Allows user to send data. */
 	public send(data: any, chunked = false) {
 		if (!this.open) {
 			this.emitError(