mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-11-06 04:10:31 +08:00
Simplify nodeStore, and make it part of the httpdStore
This commit is contained in:
@@ -3,7 +3,6 @@
|
||||
|
||||
import * as router from "@app/lib/router";
|
||||
import * as httpd from "@app/lib/httpd";
|
||||
import * as node from "@app/lib/node";
|
||||
import { unreachable } from "@app/lib/utils";
|
||||
|
||||
import Footer from "./App/Footer.svelte";
|
||||
@@ -31,7 +30,6 @@
|
||||
const activeRouteStore = router.activeRouteStore;
|
||||
|
||||
void httpd.initialize().finally(() => void router.loadFromLocation());
|
||||
void node.initialize();
|
||||
|
||||
if (!window.VITEST && !window.PLAYWRIGHT && import.meta.env.PROD) {
|
||||
const plausible = Plausible({
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
import NodeInfo from "@app/App/Header/NodeInfo.svelte";
|
||||
import Authenticate from "./Header/Authenticate.svelte";
|
||||
import { httpdStore } from "@app/lib/httpd";
|
||||
import { nodeStore } from "@app/lib/node";
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@@ -50,9 +49,7 @@
|
||||
|
||||
<div class="right layout-desktop-flex">
|
||||
{#if $httpdStore.state !== "stopped"}
|
||||
{#if $nodeStore}
|
||||
<NodeInfo running={$nodeStore === "running"} />
|
||||
{/if}
|
||||
<NodeInfo running={$httpdStore.node === "running"} />
|
||||
<Authenticate />
|
||||
{/if}
|
||||
<Connect />
|
||||
|
||||
+10
-14
@@ -3,7 +3,6 @@ import { withTimeout, Mutex, E_CANCELED, E_TIMEOUT } from "async-mutex";
|
||||
|
||||
import { HttpdClient } from "@httpd-client";
|
||||
import { config } from "@app/lib/config";
|
||||
import { isLocal } from "@app/lib/utils";
|
||||
|
||||
export interface Session {
|
||||
id: string;
|
||||
@@ -13,10 +12,11 @@ export interface Session {
|
||||
|
||||
export type HttpdState =
|
||||
| { state: "stopped" }
|
||||
| { state: "running" }
|
||||
| { state: "running"; node: "running" | "stopped" }
|
||||
| {
|
||||
state: "authenticated";
|
||||
session: Session;
|
||||
node: "running" | "stopped";
|
||||
};
|
||||
|
||||
const HTTPD_STATE_STORAGE_KEY = "httpdState";
|
||||
@@ -24,13 +24,6 @@ const HTTPD_CUSTOM_PORT_KEY = "httpdCustomPort";
|
||||
|
||||
const store = writable<HttpdState>({ state: "stopped" });
|
||||
export const httpdStore = derived(store, s => s);
|
||||
export const authenticated = derived(store, s =>
|
||||
s.state === "authenticated" ? s : undefined,
|
||||
);
|
||||
export const authenticatedLocal = derived(
|
||||
store,
|
||||
s => (hostname: string) => s.state === "authenticated" && isLocal(hostname),
|
||||
);
|
||||
|
||||
export const api = new HttpdClient({
|
||||
hostname: "127.0.0.1",
|
||||
@@ -64,6 +57,7 @@ export async function authenticate(params: {
|
||||
sig: params.signature,
|
||||
pk: params.publicKey,
|
||||
});
|
||||
const { state: node } = await api.getNode();
|
||||
const sess = await api.session.getById(params.id);
|
||||
update({
|
||||
state: "authenticated",
|
||||
@@ -72,6 +66,7 @@ export async function authenticate(params: {
|
||||
publicKey: params.publicKey,
|
||||
alias: sess.alias,
|
||||
},
|
||||
node,
|
||||
});
|
||||
return true;
|
||||
} catch (error) {
|
||||
@@ -93,7 +88,8 @@ export async function disconnect() {
|
||||
|
||||
try {
|
||||
await api.session.delete(httpd.session.id);
|
||||
update({ state: "running" });
|
||||
const { state: node } = await api.getNode();
|
||||
update({ state: "running", node });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
update({ state: "stopped" });
|
||||
@@ -124,6 +120,7 @@ async function checkState() {
|
||||
await stateMutex
|
||||
.runExclusive(async () => {
|
||||
try {
|
||||
const { state: node } = await api.getNode();
|
||||
if (httpdState && httpdState.state === "authenticated") {
|
||||
const sess = await api.session.getById(httpdState.session.id);
|
||||
const unixTimeInSeconds = Math.floor(Date.now() / 1000);
|
||||
@@ -131,13 +128,12 @@ async function checkState() {
|
||||
sess.status === "unauthorized" ||
|
||||
sess.expiresAt < unixTimeInSeconds
|
||||
) {
|
||||
update({ state: "running" });
|
||||
update({ state: "running", node });
|
||||
} else {
|
||||
update(httpdState);
|
||||
update({ ...httpdState, node });
|
||||
}
|
||||
} else {
|
||||
await api.getNodeInfo();
|
||||
update({ state: "running" });
|
||||
update({ state: "running", node });
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof TypeError && error.message !== "Failed to fetch") {
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
import { derived, writable } from "svelte/store";
|
||||
import { withTimeout, Mutex, E_CANCELED, E_TIMEOUT } from "async-mutex";
|
||||
|
||||
import { HttpdClient } from "@httpd-client";
|
||||
import { config } from "@app/lib/config";
|
||||
|
||||
export type NodeState = "stopped" | "running";
|
||||
|
||||
const NODE_STATE_STORAGE_KEY = "nodeState";
|
||||
|
||||
const store = writable<NodeState>("stopped");
|
||||
export const nodeStore = derived(store, s => s);
|
||||
|
||||
export const api = new HttpdClient({
|
||||
hostname: "127.0.0.1",
|
||||
port: config.nodes.defaultLocalHttpdPort,
|
||||
scheme: "http",
|
||||
});
|
||||
|
||||
let pollHttpdStateHandle: number | undefined = undefined;
|
||||
|
||||
function update(state: NodeState) {
|
||||
window.localStorage.setItem(NODE_STATE_STORAGE_KEY, state);
|
||||
store.set(state);
|
||||
}
|
||||
|
||||
const stateMutex = withTimeout(new Mutex(), 5_000);
|
||||
|
||||
async function checkState() {
|
||||
let nodeState: NodeState | null = null;
|
||||
const rawNodeState = window.localStorage.getItem(NODE_STATE_STORAGE_KEY);
|
||||
if (rawNodeState === "running" || rawNodeState === "stopped") {
|
||||
nodeState = rawNodeState;
|
||||
}
|
||||
|
||||
await stateMutex
|
||||
.runExclusive(async () => {
|
||||
try {
|
||||
if (nodeState) {
|
||||
update(nodeState);
|
||||
}
|
||||
const node = await api.getNode();
|
||||
update(node.state);
|
||||
} catch (error) {
|
||||
if (error instanceof TypeError) {
|
||||
console.error(error);
|
||||
}
|
||||
update("stopped");
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
if (error !== E_CANCELED && error !== E_TIMEOUT) {
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function pollSession() {
|
||||
if (pollHttpdStateHandle) {
|
||||
return;
|
||||
}
|
||||
|
||||
pollHttpdStateHandle = window.setInterval(() => checkState(), 10_000);
|
||||
}
|
||||
|
||||
export async function initialize() {
|
||||
// Sync session state changes with other open tabs and windows.
|
||||
addEventListener("storage", event => {
|
||||
if (
|
||||
event.key === NODE_STATE_STORAGE_KEY &&
|
||||
event.oldValue !== event.newValue
|
||||
) {
|
||||
void checkState();
|
||||
}
|
||||
});
|
||||
|
||||
await checkState();
|
||||
|
||||
// Properly clean up setInterval and restart session polling when Vite
|
||||
// performs hot module reload on file changes.
|
||||
if (import.meta.hot) {
|
||||
import.meta.hot.accept();
|
||||
import.meta.hot.dispose(() => {
|
||||
clearInterval(pollHttpdStateHandle);
|
||||
pollHttpdStateHandle = undefined;
|
||||
pollSession();
|
||||
});
|
||||
}
|
||||
|
||||
pollSession();
|
||||
}
|
||||
@@ -4,7 +4,8 @@
|
||||
import { HttpdClient } from "@httpd-client";
|
||||
import { ISSUES_PER_PAGE } from "./router";
|
||||
import { closeFocused } from "@app/components/Popover.svelte";
|
||||
import { authenticatedLocal } from "@app/lib/httpd";
|
||||
import { httpdStore } from "@app/lib/httpd";
|
||||
import { isLocal } from "@app/lib/utils";
|
||||
|
||||
import Button from "@app/components/Button.svelte";
|
||||
import DropdownList from "@app/components/DropdownList.svelte";
|
||||
@@ -125,7 +126,7 @@
|
||||
</Link>
|
||||
</DropdownList>
|
||||
</Popover>
|
||||
{#if $authenticatedLocal(baseUrl.hostname)}
|
||||
{#if $httpdStore.state === "authenticated" && isLocal(baseUrl.hostname)}
|
||||
<div style="margin-left: auto;">
|
||||
<Link
|
||||
route={{
|
||||
|
||||
Reference in New Issue
Block a user