mirror of
https://github.com/MercuryWorkshop/adrift.git
synced 2025-05-13 06:10:01 -04:00
add most of the client connection protocol
This commit is contained in:
parent
ea17f5d71c
commit
9ef8cc4cea
6 changed files with 769 additions and 123 deletions
25
client/AdriftClient.ts
Normal file
25
client/AdriftClient.ts
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
|
||||||
|
import Connection from "./Connection";
|
||||||
|
import { BareClient as BareClientCustom, registerRemoteListener, setBareClientImplementation, Client, GetRequestHeadersCallback, MetaCallback, ReadyStateCallback, WebSocketImpl, BareHeaders, BareResponse } from "bare-client-custom";
|
||||||
|
|
||||||
|
|
||||||
|
// export class Adrift {
|
||||||
|
// bareclient:AdriftBareClient,
|
||||||
|
// constructor(connection:Connection){
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
export class AdriftBareClient extends Client {
|
||||||
|
constructor(private connection: Connection) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
async request(method: string, requestHeaders: BareHeaders, body: BodyInit | null, remote: URL, cache: string | undefined, duplex: string | undefined, signal: AbortSignal | undefined): Promise<BareResponse> {
|
||||||
|
let rawResponse = await this.connection.httprequest({ a: "test data" });
|
||||||
|
|
||||||
|
return new Response(JSON.stringify(rawResponse)) as BareResponse;
|
||||||
|
}
|
||||||
|
async connect(remote: URL, protocols: string[], getRequestHeaders: GetRequestHeadersCallback, onMeta: MetaCallback, onReadyState: ReadyStateCallback, webSocketImpl: WebSocketImpl): WebSocket {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,37 +1,40 @@
|
||||||
import { Component, Fragment, h, render } from "preact";
|
import { Component, Fragment, h, render } from "preact";
|
||||||
import { RTCConnection } from "./rtc";
|
import { RTCTransport } from "./RTCTransport";
|
||||||
|
|
||||||
const _ = [h, render, Component, Fragment];
|
const _ = [h, render, Component, Fragment];
|
||||||
// import { setOffer, setCallback } from "./firebase";
|
import "./firebase";
|
||||||
import { BareClient as BareClientCustom, registerRemoteListener, setBareClientImplementation, Client, GetRequestHeadersCallback, MetaCallback, ReadyStateCallback, WebSocketImpl, BareHeaders, BareResponse } from "bare-client-custom";
|
import { BareClient as BareClientCustom, registerRemoteListener, setBareClientImplementation, Client, GetRequestHeadersCallback, MetaCallback, ReadyStateCallback, WebSocketImpl, BareHeaders, BareResponse } from "bare-client-custom";
|
||||||
|
|
||||||
import { createBareClient } from "@tomphttp/bare-client";
|
import { createBareClient } from "@tomphttp/bare-client";
|
||||||
|
import { AdriftBareClient } from "./AdriftClient";
|
||||||
|
import Connection from "./Connection";
|
||||||
|
|
||||||
|
let rtc = new RTCTransport(
|
||||||
|
console.log,
|
||||||
|
() => {
|
||||||
|
// rtc.dataChannel.send("test message");
|
||||||
|
|
||||||
|
|
||||||
class AdriftClient extends Client {
|
// let client = new AdriftBareClient;
|
||||||
|
// setBareClientImplementation(client);
|
||||||
async request(method: string, requestHeaders: BareHeaders, body: BodyInit | null, remote: URL, cache: string | undefined, duplex: string | undefined, signal: AbortSignal | undefined): Promise<BareResponse> {
|
//
|
||||||
return new Response("test") as BareResponse;
|
|
||||||
}
|
},
|
||||||
async connect(remote: URL, protocols: string[], getRequestHeaders: GetRequestHeadersCallback, onMeta: MetaCallback, onReadyState: ReadyStateCallback, webSocketImpl: WebSocketImpl): WebSocket {
|
console.log,
|
||||||
|
console.log,
|
||||||
}
|
console.log
|
||||||
}
|
);
|
||||||
|
let connection = new Connection(rtc);
|
||||||
|
window["co"] = connection;
|
||||||
|
// connection.httprequest({ a: 1, b: 2 });
|
||||||
|
|
||||||
|
let bare = new AdriftBareClient(connection);
|
||||||
|
setBareClientImplementation(bare);
|
||||||
|
registerRemoteListener();
|
||||||
|
|
||||||
|
|
||||||
export default class App extends Component {
|
export default class App extends Component {
|
||||||
rtc = new RTCConnection({
|
rtc = rtc;
|
||||||
onmessage: console.log,
|
|
||||||
onopen: () => {
|
|
||||||
this.rtc.dataChannel.send("test message");
|
|
||||||
|
|
||||||
|
|
||||||
let client = new AdriftClient;
|
|
||||||
setBareClientImplementation(client);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
state = {};
|
state = {};
|
||||||
|
|
||||||
|
|
96
client/Connection.ts
Normal file
96
client/Connection.ts
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
import Transport from "./Transport";
|
||||||
|
|
||||||
|
|
||||||
|
type ObjectValues<T> = T[keyof T];
|
||||||
|
const C2SRequestTypes = {
|
||||||
|
HTTPRequest: 0,
|
||||||
|
WSOpen: 1,
|
||||||
|
WSClose: 2,
|
||||||
|
WSSendText: 3,
|
||||||
|
WSSendBinary: 4,
|
||||||
|
} as const;
|
||||||
|
type C2SRequestType = ObjectValues<typeof C2SRequestTypes>
|
||||||
|
|
||||||
|
const S2CRequestTypes = {
|
||||||
|
HTTPResponse: 0,
|
||||||
|
WSOpen: 1,
|
||||||
|
WSDataText: 2,
|
||||||
|
WSDataBinary: 3,
|
||||||
|
} as const;
|
||||||
|
type S2CRequestType = ObjectValues<typeof S2CRequestTypes>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default class Connection {
|
||||||
|
|
||||||
|
|
||||||
|
callbacks: Record<number, Function> = {};
|
||||||
|
|
||||||
|
counter: number = 0;
|
||||||
|
|
||||||
|
constructor(public transport: Transport) {
|
||||||
|
|
||||||
|
transport.ondata = this.ondata.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
ondata(data: ArrayBuffer) {
|
||||||
|
let cursor = 0;
|
||||||
|
const view = new DataView(data);
|
||||||
|
|
||||||
|
let requestID = view.getUint16(cursor);
|
||||||
|
cursor += 2;
|
||||||
|
let requestType = view.getUint8(cursor) as S2CRequestType;
|
||||||
|
cursor += 1;
|
||||||
|
|
||||||
|
console.log(requestID, requestType);
|
||||||
|
|
||||||
|
switch (requestType) {
|
||||||
|
case S2CRequestTypes.HTTPResponse: {
|
||||||
|
let decoder = new TextDecoder();
|
||||||
|
let text = decoder.decode(data.slice(cursor));
|
||||||
|
console.log(text);
|
||||||
|
let json = JSON.parse(text);
|
||||||
|
|
||||||
|
console.log(requestID);
|
||||||
|
|
||||||
|
this.callbacks[requestID](json);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async send(data: ArrayBuffer | Blob, type: C2SRequestType): Promise<number> {
|
||||||
|
|
||||||
|
let requestID = this.counter++;
|
||||||
|
|
||||||
|
let header = new ArrayBuffer(2 + 1);
|
||||||
|
let view = new DataView(header);
|
||||||
|
|
||||||
|
let cursor = 0;
|
||||||
|
|
||||||
|
view.setUint16(cursor, requestID);
|
||||||
|
cursor += 2;
|
||||||
|
view.setUint8(cursor, type);
|
||||||
|
cursor += 1;
|
||||||
|
|
||||||
|
let buf = await new Blob([header, data]).arrayBuffer();
|
||||||
|
|
||||||
|
this.transport.send(buf);
|
||||||
|
console.log(buf);
|
||||||
|
|
||||||
|
return requestID;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
httprequest(data: object): Promise<object> {
|
||||||
|
let json = JSON.stringify(data);
|
||||||
|
|
||||||
|
return new Promise(async (resolve) => {
|
||||||
|
|
||||||
|
let id = this.counter;
|
||||||
|
this.callbacks[id] = resolve;
|
||||||
|
await this.send(new Blob([json]), C2SRequestTypes.HTTPRequest);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,6 @@
|
||||||
|
import Transport from "./Transport";
|
||||||
|
import Connection from "./Connection";
|
||||||
|
|
||||||
const rtcConf = {
|
const rtcConf = {
|
||||||
iceServers: [
|
iceServers: [
|
||||||
{
|
{
|
||||||
|
@ -19,56 +22,41 @@ interface RTCOptions {
|
||||||
onmessage?
|
onmessage?
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RTCConnection {
|
export class RTCTransport extends Transport {
|
||||||
peer: RTCPeerConnection;
|
peer: RTCPeerConnection;
|
||||||
|
|
||||||
dataChannel: RTCDataChannel;
|
dataChannel: RTCDataChannel;
|
||||||
|
constructor(onopen, onclose,
|
||||||
constructor(options: RTCOptions) {
|
public onconnectionstatechange: () => void,
|
||||||
let {
|
public onsignalingstatechange: () => void,
|
||||||
|
public onicegatheringstatechange: () => void,
|
||||||
onconnectionstatechange,
|
) {
|
||||||
onsignalingstatechange,
|
super(onopen, onclose);
|
||||||
oniceconnectionstatechange,
|
|
||||||
onicegatheringstatechange,
|
|
||||||
onopen,
|
|
||||||
onclose,
|
|
||||||
onmessage
|
|
||||||
} = options;
|
|
||||||
|
|
||||||
this.peer = new RTCPeerConnection(rtcConf);
|
this.peer = new RTCPeerConnection(rtcConf);
|
||||||
this.peer.onconnectionstatechange = onconnectionstatechange;
|
this.peer.onconnectionstatechange = onconnectionstatechange;
|
||||||
// (event) => {
|
|
||||||
// console.log('Connection state:', this.peer.connectionState);
|
|
||||||
// };
|
|
||||||
this.peer.onsignalingstatechange = onsignalingstatechange;
|
|
||||||
// (event) => {
|
|
||||||
// console.log('Signaling state:', this.peer.signalingState);
|
|
||||||
// };
|
|
||||||
this.peer.oniceconnectionstatechange = oniceconnectionstatechange;
|
|
||||||
// (event) => {
|
|
||||||
// console.log('ICE connection state:', this.peer.iceConnectionState);
|
|
||||||
// if (this.peer.iceConnectionState == "disconnected" || this.peer.iceConnectionState == "failed") {
|
|
||||||
// console.log("disconnected");
|
|
||||||
// // ondisconnect();
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
this.peer.onicegatheringstatechange = onicegatheringstatechange;
|
|
||||||
// (event) => {
|
|
||||||
// console.log('ICE gathering state:', this.peer.iceGatheringState);
|
|
||||||
// };
|
|
||||||
|
|
||||||
|
this.peer.onsignalingstatechange = onsignalingstatechange;
|
||||||
|
|
||||||
|
this.peer.oniceconnectionstatechange =
|
||||||
|
(event) => {
|
||||||
|
console.log('ICE connection state:', this.peer.iceConnectionState);
|
||||||
|
if (this.peer.iceConnectionState == "disconnected" || this.peer.iceConnectionState == "failed") {
|
||||||
|
console.log("disconnected");
|
||||||
|
onclose();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.peer.onicegatheringstatechange = onicegatheringstatechange;
|
||||||
this.dataChannel = this.peer.createDataChannel('host-server');
|
this.dataChannel = this.peer.createDataChannel('host-server');
|
||||||
this.dataChannel.onopen = onopen;
|
this.dataChannel.onopen = onopen;
|
||||||
// () => {
|
|
||||||
// console.log("READY!!!");
|
|
||||||
//
|
|
||||||
// dataChannel.send("test data");
|
|
||||||
// };
|
|
||||||
this.dataChannel.onclose = onclose;
|
this.dataChannel.onclose = onclose;
|
||||||
this.dataChannel.onmessage = onmessage;
|
this.dataChannel.onmessage = (event) => {
|
||||||
|
this.ondata(event.data)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
send(data: ArrayBuffer) {
|
||||||
|
this.dataChannel.send(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
10
client/Transport.ts
Normal file
10
client/Transport.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
export default abstract class Transport {
|
||||||
|
public ondata: (data: ArrayBuffer) => void = () => { }
|
||||||
|
constructor(
|
||||||
|
public onopen: () => void,
|
||||||
|
public onclose: () => void
|
||||||
|
) { }
|
||||||
|
|
||||||
|
abstract send(data: ArrayBuffer): void;
|
||||||
|
abstract send(data: ArrayBuffer): void;
|
||||||
|
}
|
644
package-lock.json
generated
644
package-lock.json
generated
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue