Skip to content

Commit c46b353

Browse files
committed
refactor: extract Networks page and Message component
1 parent 2f547d1 commit c46b353

File tree

6 files changed

+262
-229
lines changed

6 files changed

+262
-229
lines changed

src/App.tsx

Lines changed: 18 additions & 229 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,18 @@
1-
import { useEffect, useState } from "react";
1+
import { useEffect } from "react";
2+
import { MemoryRouter, Route, Routes } from "react-router";
23
import * as app from "@tauri-apps/api/app";
34
import * as log from "@tauri-apps/plugin-log";
4-
import * as path from "@tauri-apps/api/path";
55
import { arch, platform } from "@tauri-apps/plugin-os";
6-
import { download } from "@tauri-apps/plugin-upload";
7-
import { fetch } from "@tauri-apps/plugin-http";
8-
import { Child, Command } from "@tauri-apps/plugin-shell";
9-
import { mkdir, exists } from "@tauri-apps/plugin-fs";
10-
import { Footer } from "./components";
6+
import { Footer, Message } from "./components";
7+
import { Networks } from "./pages";
118
import { useStore } from "./store";
12-
import { getNetworks, getPlatformArch, urlNetwork } from "./utils";
9+
import { getNetworks, getPlatformArch } from "./utils";
1310
import "./App.css";
1411

1512
function App() {
16-
const [msg, setMsg] = useState("");
17-
const [msgType, setMsgType] = useState(""); // error, info, success
18-
const [networkId, setNetworkId] = useState("");
19-
const [dlProgress, setDlProgress] = useState(0);
20-
const [clientPid, setClientPid] = useState(0);
21-
22-
const isConnected = useStore((s) => s.isConnected);
23-
const isPlatformSupported = useStore((s) => s.isPlatformSupported);
24-
const networks = useStore((s) => s.networks);
25-
const platformArch = useStore((s) => s.platformArch);
26-
2713
const setAppVersion = useStore((s) => s.setAppVersion);
28-
const setIsConnected = useStore((s) => s.setIsConnected);
2914
const setIsPlatformSupported = useStore((s) => s.setIsPlatformSupported);
15+
const setMessage = useStore((s) => s.setMessage);
3016
const setNetworks = useStore((s) => s.setNetworks);
3117
const setPlatformArch = useStore((s) => s.setPlatformArch);
3218

@@ -45,219 +31,22 @@ function App() {
4531
})();
4632
} catch (error: any) {
4733
log.error(`${error}`);
48-
setMsgType("error");
49-
setMsg(`${error}`);
34+
setMessage("error", `${error}`);
5035
}
5136
}, []);
5237

53-
async function connect() {
54-
try {
55-
const pid = await clientStart();
56-
setClientPid(pid);
57-
setMsgType("info");
58-
setMsg("");
59-
setIsConnected(true);
60-
setNetworks(await getNetworks());
61-
} catch (error: any) {
62-
log.error(`${error}`);
63-
setMsgType("error");
64-
setMsg(`${error}`);
65-
}
66-
}
67-
68-
async function disconnect() {
69-
try {
70-
await clientStop();
71-
setClientPid(0);
72-
setMsgType("info");
73-
setMsg("Disconnected from Network");
74-
setIsConnected(false);
75-
} catch (error: any) {
76-
log.error(`${error}`);
77-
setMsgType("error");
78-
setMsg(`${error}`);
79-
}
80-
}
81-
82-
async function clientStop() {
83-
if (clientPid > 0) {
84-
const c = new Child(clientPid);
85-
c.kill();
86-
}
87-
}
88-
89-
async function clientStart() {
90-
const urlClientCfg = `${urlNetwork}/${networkId}/client.toml`;
91-
const urlWalletshield = `${urlNetwork}/${networkId}/walletshield-${platformArch}`;
92-
const appLocalDataDirPath = await path.appLocalDataDir();
93-
const dirNetworks = await path.join(appLocalDataDirPath, "networks");
94-
const dirNetwork = await path.join(dirNetworks, networkId);
95-
const fileClientCfg = await path.join(dirNetwork, "client.toml");
96-
const fileWalletshield =
97-
(await path.join(dirNetwork, "walletshield")) +
98-
(platform() === "windows" ? ".exe" : "");
99-
const updateInterval = 1; // download progress update interval
100-
101-
////////////////////////////////////////////////////////////////////////
102-
// check network existence
103-
////////////////////////////////////////////////////////////////////////
104-
setMsgType(() => "info");
105-
setMsg(() => `Checking network...`);
106-
const response = await fetch(urlClientCfg, {
107-
method: "GET",
108-
connectTimeout: 5000,
109-
});
110-
if (!response.ok || response.body === null) {
111-
log.warn(`Failed to download client config: ${response.statusText}`);
112-
throw new Error("Invalid network id (or local network error)");
113-
}
114-
115-
////////////////////////////////////////////////////////////////////////
116-
// save the network's client.toml in a network-specific directory
117-
////////////////////////////////////////////////////////////////////////
118-
log.debug(`local network directory: ${dirNetwork}`);
119-
if (!(await exists(dirNetwork)))
120-
await mkdir(dirNetwork, { recursive: true });
121-
await download(urlClientCfg, fileClientCfg);
122-
setMsgType(() => "success");
123-
setMsg(() => "Retrieved network client configuration");
124-
125-
////////////////////////////////////////////////////////////////////////
126-
// save the network's walletshield binary
127-
////////////////////////////////////////////////////////////////////////
128-
if (!(await exists(fileWalletshield))) {
129-
setMsgType(() => "info");
130-
setMsg(() => `Downloading network client...`);
131-
await download(
132-
urlWalletshield,
133-
fileWalletshield,
134-
({ progressTotal, total }) => {
135-
const percentComplete = Math.floor((progressTotal / total) * 100);
136-
if (
137-
(dlProgress !== percentComplete &&
138-
percentComplete % updateInterval === 0) ||
139-
progressTotal === total
140-
) {
141-
let msg = `Downloading client... ${percentComplete}%`;
142-
if (progressTotal === total)
143-
msg = `Downloaded client for OS: ${platformArch}`;
144-
setMsg(() => msg);
145-
setDlProgress(() => percentComplete);
146-
}
147-
},
148-
);
149-
}
150-
151-
////////////////////////////////////////////////////////////////////////
152-
// prepare the walletshield binary for execution
153-
////////////////////////////////////////////////////////////////////////
154-
if (platform() === "linux" || platform() === "macos") {
155-
log.debug(`executing command: chmod +x walletshield`);
156-
const output = await Command.create(
157-
"chmod-walletshield",
158-
["+x", "walletshield"],
159-
{
160-
cwd: dirNetwork,
161-
},
162-
).execute();
163-
if (output.code !== 0) {
164-
throw new Error(`Failed to chmod+x walletshield: ${output.stderr}`);
165-
}
166-
}
167-
168-
////////////////////////////////////////////////////////////////////////
169-
// execute the walletshield client with the client.toml
170-
////////////////////////////////////////////////////////////////////////
171-
setMsgType(() => "info");
172-
setMsg(() => `Starting network client...`);
173-
const cmd = "walletshield";
174-
const args = ["-listen", ":7070", "-config", "client.toml"];
175-
const command = Command.create("walletshield-listen", args, {
176-
cwd: dirNetwork,
177-
env: {
178-
PATH: dirNetwork,
179-
},
180-
});
181-
log.debug(`spawning command: ${cmd} ${args.join(" ")}`);
182-
command.on("close", (data) => {
183-
log.debug(`closed: ${cmd} code=${data.code} signal=${data.signal}`);
184-
setMsgType(() => "info");
185-
setMsg(() => `Network client stopped.`);
186-
});
187-
command.on("error", (e) => log.error(`${cmd}: ${e.trim()}`));
188-
command.stdout.on("data", (d) => log.info(`${cmd}: ${d.trim()}`));
189-
command.stderr.on("data", (d) => log.error(`${cmd}: ${d.trim()}`));
190-
191-
const child = await command.spawn();
192-
return child.pid;
193-
}
194-
19538
return (
196-
<div className="flex flex-col min-h-screen">
197-
<main className="flex flex-col flex-grow items-center justify-center gap-5">
198-
<h1 className="text-3xl font-extrabold">Zero Knowledge Network</h1>
199-
200-
<img
201-
src="/zkn.svg"
202-
alt="ZKN"
203-
onClick={() => isConnected && disconnect()}
204-
className={`logo ${isConnected ? "pulsing" : ""}`}
205-
/>
206-
207-
{isPlatformSupported &&
208-
(clientPid === 0 ? (
209-
<>
210-
<p>Enter a network identifier for access.</p>
211-
<form
212-
className="join"
213-
onSubmit={(e) => {
214-
e.preventDefault();
215-
connect();
216-
217-
// blur the input field to clear visual artifact
218-
e.currentTarget.querySelector("input")?.blur();
219-
}}
220-
>
221-
<input
222-
className="input validator focus:outline-none join-item"
223-
onChange={(e) => setNetworkId(e.currentTarget.value)}
224-
placeholder="Enter a network id..."
225-
maxLength={36}
226-
minLength={5}
227-
required
228-
list="networks"
229-
/>
230-
<datalist id="networks">
231-
{networks.map((n) => (
232-
<option key={n} value={n} />
233-
))}
234-
</datalist>
235-
<button className="btn btn-primary join-item" type="submit">
236-
Connect
237-
</button>
238-
</form>
239-
</>
240-
) : (
241-
<>
242-
<p className="text-lg font-bold">
243-
Connected Network: {networkId}
244-
</p>
245-
<button onClick={disconnect} className="btn btn-secondary">
246-
Disconnect
247-
</button>
248-
</>
249-
))}
250-
251-
{msg && (
252-
<p
253-
className={`alert ${msgType === "error" ? "alert-error" : "alert-info"}`}
254-
>
255-
{msg}
256-
</p>
257-
)}
258-
</main>
259-
<Footer />
260-
</div>
39+
<MemoryRouter>
40+
<div className="flex flex-col min-h-screen">
41+
<main className="flex-grow">
42+
<Routes>
43+
<Route path="/" element={<Networks />} />
44+
</Routes>
45+
</main>
46+
<Message />
47+
<Footer />
48+
</div>
49+
</MemoryRouter>
26150
);
26251
}
26352

src/components/Message.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { useStore } from "../store";
2+
3+
export function Message() {
4+
const msg = useStore((s) => s.message);
5+
const msgType = useStore((s) => s.messageType);
6+
7+
const msgClass =
8+
{
9+
error: "alert-error",
10+
info: "alert-info",
11+
success: "alert-success",
12+
}[msgType] ?? "";
13+
14+
return (
15+
<>
16+
{msg && (
17+
<div className="flex justify-center my-5">
18+
<p className={`alert ${msgClass}`}>{msg}</p>
19+
</div>
20+
)}
21+
</>
22+
);
23+
}

src/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export { Footer } from "./Footer";
2+
export { Message } from "./Message";

0 commit comments

Comments
 (0)