add most of the client connection protocol

This commit is contained in:
CoolElectronics 2023-08-11 19:07:22 -04:00
parent ea17f5d71c
commit 9ef8cc4cea
No known key found for this signature in database
GPG key ID: F63593D168636C50
6 changed files with 769 additions and 123 deletions

25
client/AdriftClient.ts Normal file
View 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 {
}
}

View file

@ -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 {
// 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 {
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
View 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);
});
}
}

View file

@ -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
View 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

File diff suppressed because it is too large Load diff