Better structure and docs

This commit is contained in:
2026-08-17 08:28:03 +02:00
parent 2a8e3f41d7
commit 210f6668cd
5 changed files with 79 additions and 21 deletions
+6 -20
View File
@@ -1,31 +1,17 @@
import { useEffect, useRef, useState } from "react";
import { useRef, useState } from "react";
import reactLogo from "./assets/react.svg";
import { invoke } from "@tauri-apps/api/core";
import "./App.css";
import { EnclaveWebSocket } from "./protocol/ws";
import * as ed from "@noble/ed25519";
import { sha512 } from "@noble/hashes/sha2.js";
ed.hashes.sha512 = sha512;
import Enclave from "./app/app";
function App() {
const [greetMsg, setGreetMsg] = useState("");
const [name, setName] = useState("");
const initialized = useRef(false);
useEffect(() => {
if (initialized.current) return;
initialized.current = true;
(async () => {
const ws = new EnclaveWebSocket("localhost:3415");
ws.clientSecretKey = ed.utils.randomSecretKey();
ws.clientPublicKey = ed.getPublicKey(ws.clientSecretKey);
ws.init();
console.log("OK");
})();
}, []);
const appRef = useRef<Enclave | null>(null);
if (!appRef.current) {
appRef.current = new Enclave();
}
async function greet() {
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
+32
View File
@@ -0,0 +1,32 @@
import EnclaveServer from "./server";
import * as ed from "@noble/ed25519";
/**
* Top-level application state and client-side logic.
*
* Owns all active connections — currently `EnclaveServer` instances, one
* per connected server, keyed by server id — and will later also own
* `DMServer` connections once direct messages are implemented.
*
* This is where UI-facing logic lives: handling user actions (button
* clicks, switching the active server, sending a message from an input
* box), and exposing state for the UI layer to render. The UI itself
* should stay a pure display of what `Enclave` exposes — it should not
* reach into `EnclaveServer` or `EnclaveWebSocket` directly.
*/
export default class Enclave {
private clientSecretKey: Uint8Array;
private clientPublicKey: Uint8Array;
public server: EnclaveServer;
public constructor() {
this.clientSecretKey = ed.utils.randomSecretKey();
this.clientPublicKey = ed.getPublicKey(this.clientSecretKey);
this.server = new EnclaveServer(
"localhost:3415",
this.clientSecretKey,
this.clientPublicKey,
);
}
}
+28
View File
@@ -0,0 +1,28 @@
import EnclaveWebSocket from "./ws";
/**
* Manages a single connection to an Enclave server: channels, server
* metadata, and messages for that server.
*
* Wraps one `EnclaveWebSocket` instance and layers server-level concepts
* on top of the raw protocol (channels, messages, server meta) — it does
* not know about the handshake/key exchange itself, only the connection
* it's given.
*
* One `EnclaveServer` instance exists per connected server. It has no
* knowledge of other servers, DMs, or app-level UI state — that lives in
* `Enclave`, which owns and manages multiple `EnclaveServer` instances.
*/
export default class EnclaveServer {
public websocket: EnclaveWebSocket;
public constructor(
hostname: string,
clientSecretKey: Uint8Array,
clientPublicKey: Uint8Array,
) {
this.websocket = new EnclaveWebSocket(hostname);
this.websocket.clientSecretKey = clientSecretKey;
this.websocket.clientPublicKey = clientPublicKey;
this.websocket.init();
}
}
+13 -1
View File
@@ -5,7 +5,19 @@ import { sha512 } from "@noble/hashes/sha2.js";
ed.hashes.sha512 = sha512;
export class EnclaveWebSocket {
/**
* A protocol-aware wrapper around the browser `WebSocket`.
*
* Owns exactly one connection's lifecycle: the initial key exchange and
* identity handshake, and storage of the resulting keys (this client's
* keypair, the server's verified public key) for the lifetime of the
* connection.
*
* Exposes typed protocol methods (`ServerMethod` / `ClientMethod`) rather
* than raw WebSocket messages. Has no concept of channels, messages, or
* app state — `EnclaveServer` builds on top of this to add those.
*/
export default class EnclaveWebSocket {
public websocket: WebSocket;
public hostname: string;
onOpenQueue: Array<() => void>;