1
- import { useEffect , useState } from "react" ;
1
+ import { useEffect } from "react" ;
2
+ import { MemoryRouter , Route , Routes } from "react-router" ;
2
3
import * as app from "@tauri-apps/api/app" ;
3
4
import * as log from "@tauri-apps/plugin-log" ;
4
- import * as path from "@tauri-apps/api/path" ;
5
5
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" ;
11
8
import { useStore } from "./store" ;
12
- import { getNetworks , getPlatformArch , urlNetwork } from "./utils" ;
9
+ import { getNetworks , getPlatformArch } from "./utils" ;
13
10
import "./App.css" ;
14
11
15
12
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
-
27
13
const setAppVersion = useStore ( ( s ) => s . setAppVersion ) ;
28
- const setIsConnected = useStore ( ( s ) => s . setIsConnected ) ;
29
14
const setIsPlatformSupported = useStore ( ( s ) => s . setIsPlatformSupported ) ;
15
+ const setMessage = useStore ( ( s ) => s . setMessage ) ;
30
16
const setNetworks = useStore ( ( s ) => s . setNetworks ) ;
31
17
const setPlatformArch = useStore ( ( s ) => s . setPlatformArch ) ;
32
18
@@ -45,219 +31,22 @@ function App() {
45
31
} ) ( ) ;
46
32
} catch ( error : any ) {
47
33
log . error ( `${ error } ` ) ;
48
- setMsgType ( "error" ) ;
49
- setMsg ( `${ error } ` ) ;
34
+ setMessage ( "error" , `${ error } ` ) ;
50
35
}
51
36
} , [ ] ) ;
52
37
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
-
195
38
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 >
261
50
) ;
262
51
}
263
52
0 commit comments