Skip to content

Commit 1e5579a

Browse files
committed
Refactor Besu installation process and enhance error handling
- Updated error messages in the Besu installation process for improved clarity, changing "Docker daemon" to "docker daemon" for consistency. - Removed redundant symlink creation and verification steps in the installation method, streamlining the process. - Enhanced the ChaincodeDefinitionCard component by removing the deploy mutation logic, delegating it to the DeployChaincodeDialog for better separation of concerns. - Simplified the DeployChaincodeDialog by removing unused imports and ensuring it integrates smoothly with the updated deployment logic. These changes improve the maintainability and clarity of the Besu installation and chaincode management processes, enhancing overall user experience. Signed-off-by: David VIEJO <dviejo@kungfusoftware.es>
1 parent 5f02901 commit 1e5579a

File tree

4 files changed

+53
-120
lines changed

4 files changed

+53
-120
lines changed

pkg/nodes/besu/besu.go

Lines changed: 1 addition & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ func (b *LocalBesu) checkPrerequisites() error {
227227
// Ping Docker daemon to verify connectivity
228228
ctx := context.Background()
229229
if _, err := cli.Ping(ctx); err != nil {
230-
return fmt.Errorf("Docker daemon is not running or not accessible: %w", err)
230+
return fmt.Errorf("docker daemon is not running or not accessible: %w", err)
231231
}
232232
}
233233

@@ -348,15 +348,6 @@ func (b *LocalBesu) installBesu() error {
348348

349349
b.logger.Info("Installing Besu binary", "version", b.opts.Version, "platform", runtime.GOOS)
350350

351-
if runtime.GOOS == "darwin" {
352-
err := b.installBesuMacOS()
353-
if err != nil {
354-
return err
355-
}
356-
b.logger.Info("Besu installed via Homebrew", "path", besuBinary)
357-
return nil
358-
}
359-
360351
err := b.downloadBesu(b.opts.Version)
361352
if err != nil {
362353
return err
@@ -551,82 +542,6 @@ func copyDir(src string, dst string) error {
551542
return nil
552543
}
553544

554-
func (b *LocalBesu) installBesuMacOS() error {
555-
// Check if brew is installed
556-
if _, err := exec.LookPath("brew"); err != nil {
557-
return fmt.Errorf("homebrew is not installed: %w", err)
558-
}
559-
560-
// Add hyperledger/besu tap if not already added
561-
tapCmd := exec.Command("brew", "tap", "hyperledger/besu")
562-
if err := tapCmd.Run(); err != nil {
563-
return fmt.Errorf("failed to tap hyperledger/besu: %w", err)
564-
}
565-
566-
// Check if besu is already installed
567-
checkCmd := exec.Command("brew", "list", "hyperledger/besu/besu")
568-
if checkCmd.Run() == nil {
569-
// Besu is installed, check version
570-
versionCmd := exec.Command("besu", "--version")
571-
output, err := versionCmd.Output()
572-
if err != nil {
573-
return fmt.Errorf("failed to get installed Besu version: %w", err)
574-
}
575-
576-
// Parse installed version
577-
installedVersion := strings.TrimSpace(string(output))
578-
if strings.Contains(installedVersion, b.opts.Version) {
579-
// Correct version is already installed, create symlink structure
580-
return b.createMacOSBinaryStructure()
581-
}
582-
583-
// Uninstall current version if it's different
584-
uninstallCmd := exec.Command("brew", "uninstall", "hyperledger/besu/besu")
585-
if err := uninstallCmd.Run(); err != nil {
586-
return fmt.Errorf("failed to uninstall existing Besu version: %w", err)
587-
}
588-
}
589-
590-
// Install specific version
591-
installCmd := exec.Command("brew", "install", "hyperledger/besu/besu")
592-
if output, err := installCmd.CombinedOutput(); err != nil {
593-
return fmt.Errorf("failed to install Besu %s: %w\nOutput: %s", b.opts.Version, err, string(output))
594-
}
595-
596-
// Create binary structure
597-
return b.createMacOSBinaryStructure()
598-
}
599-
600-
// createMacOSBinaryStructure creates the proper directory structure and symlinks for macOS
601-
func (b *LocalBesu) createMacOSBinaryStructure() error {
602-
binDir := filepath.Join(b.configService.GetDataPath(), "bin/besu", b.opts.Version)
603-
604-
// Create the bin directory structure
605-
if err := os.MkdirAll(filepath.Join(binDir, "bin"), 0755); err != nil {
606-
return fmt.Errorf("failed to create bin directory: %w", err)
607-
}
608-
609-
// Determine the Homebrew binary path
610-
brewPrefix := "/usr/local/opt/besu/bin/besu"
611-
if runtime.GOARCH == "arm64" {
612-
brewPrefix = "/opt/homebrew/opt/besu/bin/besu"
613-
}
614-
615-
// Create symlink to our bin directory
616-
targetBinary := b.GetBinaryPath()
617-
if err := os.Symlink(brewPrefix, targetBinary); err != nil && !os.IsExist(err) {
618-
return fmt.Errorf("failed to create symlink: %w", err)
619-
}
620-
621-
// Verify the symlink works
622-
if _, err := os.Stat(targetBinary); err != nil {
623-
return fmt.Errorf("failed to verify symlink: %w", err)
624-
}
625-
626-
b.logger.Info("Created Besu binary symlink", "path", targetBinary, "target", brewPrefix)
627-
return nil
628-
}
629-
630545
// TailLogs tails the logs of the besu service
631546
func (b *LocalBesu) TailLogs(ctx context.Context, tail int, follow bool) (<-chan string, error) {
632547
logChan := make(chan string, 100)

web/src/components/fabric/ChaincodeDefinitionCard.tsx

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -125,16 +125,6 @@ export function ChaincodeDefinitionCard({ definition: v, DefinitionTimelineCompo
125125
},
126126
})
127127

128-
// Deploy mutation - now handled by DeployChaincodeDialog
129-
const deployMutation = useMutation({
130-
...postScFabricDefinitionsByDefinitionIdDeployMutation(),
131-
onSuccess: () => {
132-
setTimelineKey((prev) => prev + 1)
133-
onSuccess?.()
134-
refetch?.()
135-
},
136-
})
137-
138128
// Undeploy mutation
139129
const stopMutation = useMutation({
140130
...postScFabricDefinitionsByDefinitionIdUndeployMutation(),

web/src/components/fabric/DeployChaincodeDialog.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { postScFabricDefinitionsByDefinitionIdDeployMutation } from '@/api/client/@tanstack/react-query.gen'
22
import { Button } from '@/components/ui/button'
33
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'
4-
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'
4+
import { Form, FormLabel } from '@/components/ui/form'
55
import { Input } from '@/components/ui/input'
66
import { zodResolver } from '@hookform/resolvers/zod'
77
import { useMutation } from '@tanstack/react-query'
@@ -183,4 +183,4 @@ function DeployChaincodeDialog({ deployDialogOpen, setDeployDialogOpen, definiti
183183
)
184184
}
185185

186-
export { DeployChaincodeDialog }
186+
export { DeployChaincodeDialog }

web/src/pages/nodes/[id].tsx

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { BesuNodeDetails } from '@/components/nodes/BesuNodeDetails'
1313
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from '@/components/ui/alert-dialog'
1414
import { Badge } from '@/components/ui/badge'
1515
import { Button } from '@/components/ui/button'
16-
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
16+
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
1717
import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'
1818
import { TimeAgo } from '@/components/ui/time-ago'
1919
import { cn } from '@/lib/utils'
@@ -131,9 +131,10 @@ export default function NodeDetailPage() {
131131
const [searchParams, setSearchParams] = useSearchParams()
132132
const [logs, setLogs] = useState<string>('')
133133
const logsRef = useRef<HTMLTextAreaElement>(null)
134-
const abortControllerRef = useRef<AbortController | null>(null)
134+
const eventSourceRef = useRef<EventSource | null>(null)
135135
const [showRenewCertDialog, setShowRenewCertDialog] = useState(false)
136136
const [showDeleteDialog, setShowDeleteDialog] = useState(false)
137+
const [logRefreshKey, setLogRefreshKey] = useState(0)
137138

138139
// Get the active tab from URL or default to 'logs'
139140
const activeTab = searchParams.get('tab') || 'logs'
@@ -158,33 +159,27 @@ export default function NodeDetailPage() {
158159
const startNode = useMutation({
159160
...postNodesByIdStartMutation(),
160161
onSuccess: () => {
161-
toast.success('Node started successfully')
162+
refetchEvents()
162163
refetch()
163-
},
164-
onError: (error: any) => {
165-
toast.error(`Failed to start node: ${(error as any).error.message}`)
164+
setLogRefreshKey(prev => prev + 1)
166165
},
167166
})
168167

169168
const stopNode = useMutation({
170169
...postNodesByIdStopMutation(),
171170
onSuccess: () => {
172-
toast.success('Node stopped successfully')
171+
refetchEvents()
173172
refetch()
174-
},
175-
onError: (error: any) => {
176-
toast.error(`Failed to stop node: ${(error as any).error.message}`)
173+
setLogRefreshKey(prev => prev + 1)
177174
},
178175
})
179176

180177
const restartNode = useMutation({
181178
...postNodesByIdRestartMutation(),
182179
onSuccess: () => {
183-
toast.success('Node restarted successfully')
180+
refetchEvents()
184181
refetch()
185-
},
186-
onError: (error: any) => {
187-
toast.error(`Failed to restart node: ${(error as any).error.message}`)
182+
setLogRefreshKey(prev => prev + 1)
188183
},
189184
})
190185

@@ -214,22 +209,46 @@ export default function NodeDetailPage() {
214209
}),
215210
})
216211

212+
// Function to refresh logs by restarting the EventSource connection
213+
const refreshLogs = () => {
214+
setLogRefreshKey(prev => prev + 1)
215+
setLogs('') // Clear existing logs
216+
}
217+
217218
const handleAction = async (action: string) => {
218219
if (!node) return
219220

220221
try {
221222
switch (action) {
222223
case 'start':
223-
await startNode.mutateAsync({ path: { id: node.id! } })
224-
refetchEvents()
224+
await toast.promise(
225+
startNode.mutateAsync({ path: { id: node.id! } }),
226+
{
227+
loading: 'Starting node...',
228+
success: 'Node started successfully',
229+
error: (error: any) => `Failed to start node: ${error?.error?.message || error.message}`,
230+
}
231+
)
225232
break
226233
case 'stop':
227-
await stopNode.mutateAsync({ path: { id: node.id! } })
228-
refetchEvents()
234+
await toast.promise(
235+
stopNode.mutateAsync({ path: { id: node.id! } }),
236+
{
237+
loading: 'Stopping node...',
238+
success: 'Node stopped successfully',
239+
error: (error: any) => `Failed to stop node: ${error?.error?.message || error.message}`,
240+
}
241+
)
229242
break
230243
case 'restart':
231-
await restartNode.mutateAsync({ path: { id: node.id! } })
232-
refetchEvents()
244+
await toast.promise(
245+
restartNode.mutateAsync({ path: { id: node.id! } }),
246+
{
247+
loading: 'Restarting node...',
248+
success: 'Node restarted successfully',
249+
error: (error: any) => `Failed to restart node: ${error?.error?.message || error.message}`,
250+
}
251+
)
233252
break
234253
case 'delete':
235254
setShowDeleteDialog(true)
@@ -239,7 +258,7 @@ export default function NodeDetailPage() {
239258
break
240259
}
241260
} catch (error) {
242-
// Error handling is done in the mutation callbacks
261+
// Error handling is now done by toast.promise
243262
}
244263
}
245264

@@ -257,10 +276,16 @@ export default function NodeDetailPage() {
257276
}
258277

259278
useEffect(() => {
279+
// Close existing EventSource if it exists
280+
if (eventSourceRef.current) {
281+
eventSourceRef.current.close()
282+
}
283+
260284
const eventSource = new EventSource(`/api/v1/nodes/${id}/logs?follow=true`, {
261285
withCredentials: true,
262286
})
263287

288+
eventSourceRef.current = eventSource
264289
let fullText = ''
265290

266291
eventSource.onmessage = (event) => {
@@ -284,8 +309,11 @@ export default function NodeDetailPage() {
284309

285310
return () => {
286311
eventSource.close()
312+
if (eventSourceRef.current === eventSource) {
313+
eventSourceRef.current = null
314+
}
287315
}
288-
}, [id])
316+
}, [id, logRefreshKey])
289317

290318
if (isLoading) {
291319
return <div>Loading...</div>

0 commit comments

Comments
 (0)