forked from liriliri/chii
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request liriliri#39 from coolzjy/master
feat: support rtc peer connection
- Loading branch information
Showing
10 changed files
with
281 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,4 @@ network.patch | |
application.patch | ||
sources.patch | ||
embedded.patch | ||
feat_peer_connection.patch |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||
From: Zhang Visper <[email protected]> | ||
Date: Thu, 25 May 2023 13:42:27 +0800 | ||
Subject: feat: peer connection | ||
|
||
|
||
diff --git a/front_end/core/sdk/Connections.ts b/front_end/core/sdk/Connections.ts | ||
index 6a575078a98de2df5deacd02469b7c038f16696c..faeb15991702678fd929b335bcacc814f57e0c4c 100644 | ||
--- a/front_end/core/sdk/Connections.ts | ||
+++ b/front_end/core/sdk/Connections.ts | ||
@@ -75,6 +75,161 @@ export class MainConnection implements ProtocolClient.InspectorBackend.Connectio | ||
} | ||
} | ||
|
||
+export class PeerConnection implements ProtocolClient.InspectorBackend.Connection { | ||
+ #socket: WebSocket|null; | ||
+ onMessage: ((arg0: (Object|string)) => void)|null; | ||
+ #onDisconnect: ((arg0: string) => void)|null; | ||
+ #onWebSocketDisconnect: (() => void)|null; | ||
+ #messages: string[]; | ||
+ #connection: RTCPeerConnection|null; | ||
+ #channel: RTCDataChannel|null; | ||
+ #channelConnected: boolean; | ||
+ constructor(url: string, onWebSocketDisconnect: () => void) { | ||
+ this.#socket = new WebSocket(url); | ||
+ this.#socket.onerror = this.onSocketError.bind(this); | ||
+ this.#socket.onopen = this.onSocketOpen.bind(this); | ||
+ this.#socket.onmessage = (messageEvent: MessageEvent<string>): void => { | ||
+ const { type, data } = JSON.parse(messageEvent.data) as { type: string; data: any }; | ||
+ if (type === 'answer') { | ||
+ this.#connection?.setRemoteDescription(data); | ||
+ } else if (type === 'candidate') { | ||
+ this.#connection?.addIceCandidate(data); | ||
+ } | ||
+ }; | ||
+ this.#socket.onclose = this.onSocketClose.bind(this); | ||
+ | ||
+ this.onMessage = null; | ||
+ this.#onDisconnect = null; | ||
+ this.#onWebSocketDisconnect = onWebSocketDisconnect; | ||
+ this.#messages = []; | ||
+ | ||
+ const connection = this.#connection = new RTCPeerConnection({ | ||
+ iceServers: [{ | ||
+ urls: ['stun:stun.qq.com:3478'] | ||
+ }] | ||
+ }) | ||
+ | ||
+ this.#channel = connection.createDataChannel('dev-tool'); | ||
+ this.#channel.onerror = this.onChannelError.bind(this); | ||
+ this.#channel.onopen = this.onChannelOpen.bind(this); | ||
+ this.#channel.onmessage = (messageEvent: MessageEvent<string>): void => { | ||
+ if (this.onMessage) { | ||
+ this.onMessage.call(null, messageEvent.data); | ||
+ } | ||
+ } | ||
+ this.#channel.onclose = this.onChannelClose.bind(this); | ||
+ this.#channelConnected = false; | ||
+ connection.onicecandidate = (event) => { | ||
+ if (event.candidate) { | ||
+ this.#socket?.send(JSON.stringify({ | ||
+ type: 'candidate', | ||
+ data: event.candidate, | ||
+ })) | ||
+ } | ||
+ } | ||
+ } | ||
+ | ||
+ setOnMessage(onMessage: (arg0: (Object|string)) => void): void { | ||
+ this.onMessage = onMessage; | ||
+ } | ||
+ | ||
+ setOnDisconnect(onDisconnect: (arg0: string) => void): void { | ||
+ this.#onDisconnect = onDisconnect; | ||
+ } | ||
+ | ||
+ private onSocketError(): void { | ||
+ if (this.#onWebSocketDisconnect) { | ||
+ this.#onWebSocketDisconnect.call(null); | ||
+ } | ||
+ if (this.#onDisconnect) { | ||
+ // This is called if error occurred while connecting. | ||
+ this.#onDisconnect.call(null, 'connection failed'); | ||
+ } | ||
+ this.closeSocket(); | ||
+ } | ||
+ | ||
+ private onChannelError(): void { | ||
+ this.closeChannel(); | ||
+ } | ||
+ | ||
+ private async onSocketOpen(): Promise<void> { | ||
+ if (this.#socket && this.#connection) { | ||
+ this.#socket.onerror = console.error; | ||
+ const offer = await this.#connection.createOffer(); | ||
+ await this.#connection.setLocalDescription(offer); | ||
+ this.#socket.send(JSON.stringify({ | ||
+ type: 'offer', | ||
+ data: offer | ||
+ })); | ||
+ } | ||
+ } | ||
+ | ||
+ private onChannelOpen(): void { | ||
+ this.#channelConnected = true; | ||
+ if (this.#channel) { | ||
+ this.#channel.onerror = console.error; | ||
+ for (const message of this.#messages) { | ||
+ this.#channel.send(message); | ||
+ } | ||
+ } | ||
+ this.#messages = []; | ||
+ } | ||
+ | ||
+ private onSocketClose(): void { | ||
+ if (this.#onWebSocketDisconnect) { | ||
+ this.#onWebSocketDisconnect.call(null); | ||
+ } | ||
+ if (this.#onDisconnect) { | ||
+ this.#onDisconnect.call(null, 'websocket closed'); | ||
+ } | ||
+ this.closeSocket(); | ||
+ } | ||
+ | ||
+ private onChannelClose(): void { | ||
+ this.closeChannel(); | ||
+ } | ||
+ | ||
+ private closeSocket(callback?: (() => void)): void { | ||
+ if (this.#socket) { | ||
+ this.#socket.onerror = null; | ||
+ this.#socket.onopen = null; | ||
+ this.#socket.onclose = callback || null; | ||
+ this.#socket.onmessage = null; | ||
+ this.#socket.close(); | ||
+ this.#socket = null; | ||
+ } | ||
+ this.#onWebSocketDisconnect = null; | ||
+ } | ||
+ | ||
+ private closeChannel(callback?: (() => void)): void { | ||
+ if(this.#channel) { | ||
+ this.#channel.onerror = null; | ||
+ this.#channel.onopen = null; | ||
+ this.#channel.onclose = callback || null | ||
+ this.#channel.onmessage = null; | ||
+ this.#channel.close(); | ||
+ } | ||
+ } | ||
+ | ||
+ sendRawMessage(message: string): void { | ||
+ if (this.#channelConnected && this.#channel) { | ||
+ this.#channel.send(message); | ||
+ } else { | ||
+ this.#messages.push(message); | ||
+ } | ||
+ } | ||
+ | ||
+ async disconnect(): Promise<void> { | ||
+ await Promise.all([ | ||
+ new Promise<void>(this.closeSocket.bind(this)), | ||
+ new Promise<void>(this.closeChannel.bind(this)) | ||
+ ]) | ||
+ if (this.#onDisconnect) { | ||
+ this.#onDisconnect.call(null, 'force disconnect'); | ||
+ } | ||
+ } | ||
+} | ||
+ | ||
export class EmbeddedConnection implements ProtocolClient.InspectorBackend.Connection { | ||
onMessage: ((arg0: Object) => void) | null; | ||
private targetOrigin: string = ''; | ||
@@ -306,6 +461,11 @@ function createMainConnection(websocketConnectionLost: () => void): ProtocolClie | ||
const wsParam = Root.Runtime.Runtime.queryParam('ws'); | ||
const wssParam = Root.Runtime.Runtime.queryParam('wss'); | ||
const embeddedParam = Root.Runtime.Runtime.queryParam('embedded'); | ||
+ const rtc = Root.Runtime.Runtime.queryParam('rtc'); | ||
+ if (rtc === 'true') { | ||
+ const ws = wsParam ? `ws://${wsParam}` : `wss://${wssParam}`; | ||
+ return new PeerConnection(ws, websocketConnectionLost) | ||
+ } | ||
if (embeddedParam) { | ||
return new EmbeddedConnection(embeddedParam) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,14 @@ | ||
import { embedded } from './target/config'; | ||
import { embedded, rtc } from './target/config'; | ||
import connectRtc from './target/connectRtc'; | ||
import connectServer from './target/connectServer'; | ||
import connectIframe from './target/connectIframe'; | ||
|
||
if (!embedded) { | ||
connectServer(); | ||
if (rtc) { | ||
connectRtc() | ||
} else { | ||
connectServer(); | ||
} | ||
} else { | ||
connectIframe(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import Socket from 'licia/Socket'; | ||
import query from 'licia/query'; | ||
import chobitsu from 'chobitsu'; | ||
import { serverUrl, id } from './config'; | ||
import { getFavicon } from './util'; | ||
|
||
export default async function () { | ||
const proxy = `${serverUrl}proxy`; | ||
chobitsu.domain('Page').setProxy({ | ||
proxy, | ||
}); | ||
chobitsu.domain('Debugger').setProxy({ | ||
proxy, | ||
}); | ||
chobitsu.domain('CSS').setProxy({ | ||
proxy, | ||
}); | ||
|
||
const connection = new RTCPeerConnection({ | ||
iceServers: [ | ||
{ | ||
urls: ['stun:stun.qq.com:3478'], | ||
}, | ||
], | ||
}); | ||
|
||
connection.addEventListener('datachannel', event => { | ||
const { channel } = event; | ||
|
||
channel.onmessage = event => { | ||
chobitsu.sendRawMessage(event.data); | ||
}; | ||
|
||
chobitsu.setOnMessage((message: string) => { | ||
channel.send(message); | ||
}); | ||
}); | ||
|
||
const ws = new Socket( | ||
`${serverUrl.replace(/^http/, 'ws')}target/${id}?${query.stringify({ | ||
url: location.href, | ||
title: (window as any).ChiiTitle || document.title, | ||
favicon: getFavicon(), | ||
rtc: true, | ||
})}` | ||
); | ||
|
||
connection.onicecandidate = event => { | ||
if (event.candidate) { | ||
ws.send( | ||
JSON.stringify({ | ||
type: 'candidate', | ||
data: event.candidate, | ||
}) | ||
); | ||
} | ||
}; | ||
|
||
ws.on('message', async (event: MessageEvent<string>) => { | ||
const { type, data } = JSON.parse(event.data) as { type: string; data: any }; | ||
if (type === 'offer') { | ||
connection.setRemoteDescription(new RTCSessionDescription(data)); | ||
const answer = await connection.createAnswer(); | ||
connection.setLocalDescription(answer); | ||
ws.send( | ||
JSON.stringify({ | ||
type: 'answer', | ||
data: answer, | ||
}) | ||
); | ||
} else if (type === 'candidate') { | ||
connection.addIceCandidate(data); | ||
} | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters