Simplify nodeStore, and make it part of the httpdStore

This commit is contained in:
Sebastian Martinez
2023-11-16 10:03:06 +01:00
parent 7f4af6fb72
commit 54be2b78e4
5 changed files with 14 additions and 113 deletions
-2
View File
@@ -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({
+1 -4
View File
@@ -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
View File
@@ -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") {
-91
View File
@@ -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();
}
+3 -2
View File
@@ -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={{