1- import { useEffect , useRef , useCallback } from ' react' ;
2- import { useInstallationStore } from ' @/store/installationStore' ;
3- import { useAuthStore } from ' @/store/authStore' ;
1+ import { useEffect , useRef , useCallback } from " react" ;
2+ import { useInstallationStore } from " @/store/installationStore" ;
3+ import { useAuthStore } from " @/store/authStore" ;
44
55/**
66 * Hook that sets up Electron IPC listeners and handles installation state synchronization
@@ -12,78 +12,110 @@ export const useInstallationSetup = () => {
1212 const hasCheckedOnMount = useRef ( false ) ;
1313 const installationCompleted = useRef ( false ) ;
1414 const backendReady = useRef ( false ) ;
15- const startInstallation = useInstallationStore ( state => state . startInstallation ) ;
16- const performInstallation = useInstallationStore ( state => state . performInstallation ) ;
17- const addLog = useInstallationStore ( state => state . addLog ) ;
18- const setSuccess = useInstallationStore ( state => state . setSuccess ) ;
19- const setError = useInstallationStore ( state => state . setError ) ;
20- const setBackendError = useInstallationStore ( state => state . setBackendError ) ;
21- const setWaitingBackend = useInstallationStore ( state => state . setWaitingBackend ) ;
22- const needsBackendRestart = useInstallationStore ( state => state . needsBackendRestart ) ;
23- const setNeedsBackendRestart = useInstallationStore ( state => state . setNeedsBackendRestart ) ;
15+ const startInstallation = useInstallationStore (
16+ ( state ) => state . startInstallation
17+ ) ;
18+ const performInstallation = useInstallationStore (
19+ ( state ) => state . performInstallation
20+ ) ;
21+ const addLog = useInstallationStore ( ( state ) => state . addLog ) ;
22+ const setSuccess = useInstallationStore ( ( state ) => state . setSuccess ) ;
23+ const setError = useInstallationStore ( ( state ) => state . setError ) ;
24+ const setBackendError = useInstallationStore (
25+ ( state ) => state . setBackendError
26+ ) ;
27+ const setWaitingBackend = useInstallationStore (
28+ ( state ) => state . setWaitingBackend
29+ ) ;
30+ const needsBackendRestart = useInstallationStore (
31+ ( state ) => state . needsBackendRestart
32+ ) ;
33+ const setNeedsBackendRestart = useInstallationStore (
34+ ( state ) => state . setNeedsBackendRestart
35+ ) ;
2436
2537 // Shared function to poll backend status
2638 const startBackendPolling = useCallback ( ( ) => {
27- console . log ( ' [useInstallationSetup] Starting backend polling' ) ;
39+ console . log ( " [useInstallationSetup] Starting backend polling" ) ;
2840
2941 // Immediately check backend status once
3042 const checkBackendStatus = async ( ) => {
3143 try {
3244 const backendPort = await window . electronAPI . getBackendPort ( ) ;
3345 if ( backendPort && backendPort > 0 ) {
34- console . log ( '[useInstallationSetup] Backend immediately detected on port:' , backendPort ) ;
46+ console . log (
47+ "[useInstallationSetup] Backend immediately detected on port:" ,
48+ backendPort
49+ ) ;
3550
3651 // Verify backend is actually responding
37- const response = await fetch ( `http://localhost:${ backendPort } /health` ) . catch ( ( ) => null ) ;
52+ const response = await fetch (
53+ `http://localhost:${ backendPort } /health`
54+ ) . catch ( ( ) => null ) ;
3855 if ( response && response . ok ) {
39- console . log ( '[useInstallationSetup] Backend health check passed immediately' ) ;
56+ console . log (
57+ "[useInstallationSetup] Backend health check passed immediately"
58+ ) ;
4059 backendReady . current = true ;
4160 setSuccess ( ) ;
42- setInitState ( ' done' ) ;
61+ setInitState ( " done" ) ;
4362 setNeedsBackendRestart ( false ) ;
4463 return true ; // Backend is ready, no need to poll
4564 }
4665 }
4766 } catch ( error ) {
48- console . log ( '[useInstallationSetup] Initial backend check failed:' , error ) ;
67+ console . log (
68+ "[useInstallationSetup] Initial backend check failed:" ,
69+ error
70+ ) ;
4971 }
5072 return false ; // Backend not ready, need to poll
5173 } ;
5274
5375 // Check immediately, then start polling if needed
5476 checkBackendStatus ( ) . then ( ( isReady ) => {
5577 if ( isReady ) {
56- console . log ( '[useInstallationSetup] Backend already ready, skipping polling' ) ;
78+ console . log (
79+ "[useInstallationSetup] Backend already ready, skipping polling"
80+ ) ;
5781 return ;
5882 }
5983
60- console . log ( ' [useInstallationSetup] Backend not ready, starting polling' ) ;
84+ console . log ( " [useInstallationSetup] Backend not ready, starting polling" ) ;
6185
6286 // Poll backend status every 2 seconds to ensure we catch when it's ready
6387 // This is a fallback in case the backend-ready event is missed
6488 const pollInterval = setInterval ( async ( ) => {
6589 try {
6690 const backendPort = await window . electronAPI . getBackendPort ( ) ;
6791 if ( backendPort && backendPort > 0 ) {
68- console . log ( '[useInstallationSetup] Backend poll detected ready on port:' , backendPort ) ;
92+ console . log (
93+ "[useInstallationSetup] Backend poll detected ready on port:" ,
94+ backendPort
95+ ) ;
6996
7097 // Verify backend is actually responding
71- const response = await fetch ( `http://localhost:${ backendPort } /health` ) . catch ( ( ) => null ) ;
98+ const response = await fetch (
99+ `http://localhost:${ backendPort } /health`
100+ ) . catch ( ( ) => null ) ;
72101 if ( response && response . ok ) {
73- console . log ( ' [useInstallationSetup] Backend health check passed' ) ;
102+ console . log ( " [useInstallationSetup] Backend health check passed" ) ;
74103 clearInterval ( pollInterval ) ;
75104
76105 if ( ! backendReady . current ) {
77106 backendReady . current = true ;
78107 setSuccess ( ) ;
79- setInitState ( ' done' ) ;
108+ setInitState ( " done" ) ;
80109 // Clear the flag after backend is ready
81110 setNeedsBackendRestart ( false ) ;
82111 }
83112 }
84113 }
85114 } catch ( error ) {
86- console . log ( '[useInstallationSetup] Backend poll check failed:' , error ) ;
115+ console . log (
116+ "[useInstallationSetup] Backend poll check failed:" ,
117+ error
118+ ) ;
87119 }
88120 } , 2000 ) ;
89121
@@ -98,7 +130,9 @@ export const useInstallationSetup = () => {
98130 useEffect ( ( ) => {
99131 // When user logs in after logout, needsBackendRestart will be true
100132 if ( needsBackendRestart && email !== null ) {
101- console . log ( '[useInstallationSetup] Detected login after logout, waiting for backend restart' ) ;
133+ console . log (
134+ "[useInstallationSetup] Detected login after logout, waiting for backend restart"
135+ ) ;
102136
103137 // For account switching, tools are already installed, only backend needs restart
104138 // So we mark installation as completed and only wait for backend
@@ -113,7 +147,6 @@ export const useInstallationSetup = () => {
113147 }
114148 } , [ needsBackendRestart , email , setWaitingBackend , startBackendPolling ] ) ;
115149
116-
117150 useEffect ( ( ) => {
118151 if ( hasCheckedOnMount . current ) {
119152 return ;
@@ -127,56 +160,74 @@ export const useInstallationSetup = () => {
127160
128161 if ( result . success ) {
129162 if ( result . isInstalled ) {
130- console . log ( '[useInstallationSetup] Tools already installed, waiting for backend' ) ;
163+ console . log (
164+ "[useInstallationSetup] Tools already installed, waiting for backend"
165+ ) ;
131166 installationCompleted . current = true ;
132167 setWaitingBackend ( ) ;
133168
134169 // Start polling for backend when tools are already installed
135170 startBackendPolling ( ) ;
136171 }
137172
138- if ( initState !== ' done' ) {
173+ if ( initState !== " done" ) {
139174 if ( ! result . isInstalled && initState === "permissions" ) {
140- console . log ( '[useInstallationSetup] Tools not installed and initState is permissions, setting to carousel' ) ;
175+ console . log (
176+ "[useInstallationSetup] Tools not installed and initState is permissions, setting to carousel"
177+ ) ;
141178 setInitState ( "carousel" ) ;
142179 }
143180 }
144181 }
145182 return result ;
146183 } catch ( error ) {
147- console . error ( "[useInstallationSetup] Tool installation check failed:" , error ) ;
184+ console . error (
185+ "[useInstallationSetup] Tool installation check failed:" ,
186+ error
187+ ) ;
148188 return { success : false , error } ;
149189 }
150190 } ;
151191
152- const checkBackendStatus = async ( toolResult ?: any ) => {
192+ const checkBackendStatus = async ( toolResult ?: any ) => {
153193 try {
154- const installationStatus = await window . electronAPI . getInstallationStatus ( ) ;
194+ const installationStatus =
195+ await window . electronAPI . getInstallationStatus ( ) ;
155196
156197 if ( installationStatus . success && installationStatus . isInstalling ) {
157198 startInstallation ( ) ;
158199 }
159200 } catch ( err ) {
160- console . error ( '[useInstallationSetup] Failed to check installation status:' , err ) ;
201+ console . error (
202+ "[useInstallationSetup] Failed to check installation status:" ,
203+ err
204+ ) ;
161205 }
162- }
206+ } ;
163207
164208 const runInitialChecks = async ( ) => {
165209 const toolResult = await checkToolInstalled ( ) ;
166210 await checkBackendStatus ( toolResult ) ;
167211 } ;
168212
169213 runInitialChecks ( ) ;
170- // eslint-disable-next-line react-hooks/exhaustive-deps
214+ // eslint-disable-next-line react-hooks/exhaustive-deps
171215 } , [ ] ) ;
172216
173217 useEffect ( ( ) => {
174218 const checkAndSetDone = ( ) => {
175- console . log ( '[useInstallationSetup] Checking readiness - Installation:' , installationCompleted . current , 'Backend:' , backendReady . current ) ;
219+ console . log (
220+ "[useInstallationSetup] Checking readiness - Installation:" ,
221+ installationCompleted . current ,
222+ "Backend:" ,
223+ backendReady . current
224+ ) ;
176225
177226 if ( installationCompleted . current && backendReady . current ) {
178- console . log ( '[useInstallationSetup] Both installation and backend are ready, setting initState to done' ) ;
179- setInitState ( 'done' ) ;
227+ console . log (
228+ "[useInstallationSetup] Both installation and backend are ready, setting initState to done"
229+ ) ;
230+ setInitState ( "done" ) ;
180231 }
181232 } ;
182233
@@ -188,39 +239,63 @@ export const useInstallationSetup = () => {
188239
189240 const handleInstallLog = ( data : { type : string ; data : string } ) => {
190241 addLog ( {
191- type : data . type as ' stdout' | ' stderr' ,
242+ type : data . type as " stdout" | " stderr" ,
192243 data : data . data ,
193244 timestamp : new Date ( ) ,
194245 } ) ;
195246 } ;
196247
197- const handleInstallComplete = ( data : { success : boolean ; code ?: number ; error ?: string } ) => {
198- console . log ( '[useInstallationSetup] Installation complete event received:' , data ) ;
248+ const handleInstallComplete = ( data : {
249+ success : boolean ;
250+ code ?: number ;
251+ error ?: string ;
252+ } ) => {
253+ console . log (
254+ "[useInstallationSetup] Installation complete event received:" ,
255+ data
256+ ) ;
199257
200258 if ( data . success ) {
201259 installationCompleted . current = true ;
202- console . log ( ' [useInstallationSetup] Installation marked as completed' ) ;
260+ console . log ( " [useInstallationSetup] Installation marked as completed" ) ;
203261
204262 // setSuccess() will be called in handleBackendReady to prevent premature state change
205263 checkAndSetDone ( ) ;
206264 } else {
207- setError ( data . error || ' Installation failed' ) ;
265+ setError ( data . error || " Installation failed" ) ;
208266 }
209267 } ;
210268
211- const handleBackendReady = ( data : { success : boolean ; port ?: number ; error ?: string } ) => {
212- console . log ( '[useInstallationSetup] Backend ready event received:' , data ) ;
269+ const handleBackendReady = ( data : {
270+ success : boolean ;
271+ port ?: number ;
272+ error ?: string ;
273+ } ) => {
274+ console . log ( "[useInstallationSetup] Backend ready event received:" , data ) ;
213275
214276 if ( data . success && data . port ) {
215- console . log ( `[useInstallationSetup] Backend is ready on port ${ data . port } ` ) ;
277+ console . log (
278+ `[useInstallationSetup] Backend is ready on port ${ data . port } `
279+ ) ;
216280 backendReady . current = true ;
217- console . log ( '[useInstallationSetup] Backend marked as ready' ) ;
281+ // If backend is ready, installation must be complete (or satisfied enough)
282+ // This handles race condition where install-complete event is missed or skipped
283+ if ( ! installationCompleted . current ) {
284+ console . log (
285+ "[useInstallationSetup] Backend ready implies installation complete - setting flag"
286+ ) ;
287+ installationCompleted . current = true ;
288+ }
289+ console . log ( "[useInstallationSetup] Backend marked as ready" ) ;
218290
219291 setSuccess ( ) ;
220292 checkAndSetDone ( ) ;
221293 } else {
222- console . error ( '[useInstallationSetup] Backend failed to start:' , data . error ) ;
223- setBackendError ( data . error || 'Backend startup failed' ) ;
294+ console . error (
295+ "[useInstallationSetup] Backend failed to start:" ,
296+ data . error
297+ ) ;
298+ setBackendError ( data . error || "Backend startup failed" ) ;
224299 }
225300 } ;
226301
@@ -230,10 +305,17 @@ export const useInstallationSetup = () => {
230305 window . electronAPI . onBackendReady ( handleBackendReady ) ;
231306
232307 return ( ) => {
233- window . electronAPI . removeAllListeners ( ' install-dependencies-start' ) ;
234- window . electronAPI . removeAllListeners ( ' install-dependencies-log' ) ;
235- window . electronAPI . removeAllListeners ( ' install-dependencies-complete' ) ;
236- window . electronAPI . removeAllListeners ( ' backend-ready' ) ;
308+ window . electronAPI . removeAllListeners ( " install-dependencies-start" ) ;
309+ window . electronAPI . removeAllListeners ( " install-dependencies-log" ) ;
310+ window . electronAPI . removeAllListeners ( " install-dependencies-complete" ) ;
311+ window . electronAPI . removeAllListeners ( " backend-ready" ) ;
237312 } ;
238- } , [ startInstallation , addLog , setSuccess , setError , setBackendError , setInitState ] ) ;
239- } ;
313+ } , [
314+ startInstallation ,
315+ addLog ,
316+ setSuccess ,
317+ setError ,
318+ setBackendError ,
319+ setInitState ,
320+ ] ) ;
321+ } ;
0 commit comments