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 { RTCConnection } from "./rtc";
|
||||
import { RTCTransport } from "./RTCTransport";
|
||||
|
||||
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 { 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 {
|
||||
|
||||
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 {
|
||||
|
||||
}
|
||||
}
|
||||
// let client = new AdriftBareClient;
|
||||
// setBareClientImplementation(client);
|
||||
//
|
||||
|
||||
},
|
||||
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 {
|
||||
rtc = new RTCConnection({
|
||||
onmessage: console.log,
|
||||
onopen: () => {
|
||||
this.rtc.dataChannel.send("test message");
|
||||
|
||||
|
||||
let client = new AdriftClient;
|
||||
setBareClientImplementation(client);
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
rtc = rtc;
|
||||
|
||||
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 = {
|
||||
iceServers: [
|
||||
{
|
||||
|
@ -19,56 +22,41 @@ interface RTCOptions {
|
|||
onmessage?
|
||||
}
|
||||
|
||||
export class RTCConnection {
|
||||
export class RTCTransport extends Transport {
|
||||
peer: RTCPeerConnection;
|
||||
|
||||
dataChannel: RTCDataChannel;
|
||||
|
||||
constructor(options: RTCOptions) {
|
||||
let {
|
||||
|
||||
onconnectionstatechange,
|
||||
onsignalingstatechange,
|
||||
oniceconnectionstatechange,
|
||||
onicegatheringstatechange,
|
||||
onopen,
|
||||
onclose,
|
||||
onmessage
|
||||
} = options;
|
||||
|
||||
constructor(onopen, onclose,
|
||||
public onconnectionstatechange: () => void,
|
||||
public onsignalingstatechange: () => void,
|
||||
public onicegatheringstatechange: () => void,
|
||||
) {
|
||||
super(onopen, onclose);
|
||||
this.peer = new RTCPeerConnection(rtcConf);
|
||||
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.onopen = onopen;
|
||||
// () => {
|
||||
// console.log("READY!!!");
|
||||
//
|
||||
// dataChannel.send("test data");
|
||||
// };
|
||||
|
||||
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