Control your backup NAS from the desktop

Wake Up on Command

If the user clicks the Up button, the callback notifies the state machine in line 36, which uses its transition rules to determine the next steps of the application. Line 36 sends the wake event to the machine with the Event() function. The machine then blocks until the NAS wakes up, before finally sending the UP message on the stateReporter channel. Because I don't want the GUI to freeze while the machine is blocking, the callback wraps the call to the machine's Event() function in a Go routine that continues to run concurrently while the callback completes.

Events from channel stateReporter are intercepted by a Go routine running concurrently starting in line 51. It uses a select statement to listen on the channel. As soon as the state machine announces a new state, the code jumps to one of the two case blocks handling the up or down states. These in turn prompt the GUI to refresh the display to reflect the new state.

The new container generated starting in line 74 lines up all the widgets, both visible and invisible. NewHBox() in line 80 defines the sub-container at the bottom of the main GUI container, and the three buttons for controlling the app are arranged horizontally next to each other at the bottom of the application window. Meanwhile, the main container uses NewVBox() to stack the rest of the widgets on top of each other; they include the text and icon for the state, the progress bar, and the sub-container.

Line 88 dumps everything into the application window. Finally, line 89 jumps to the endless GUI loop by calling ShowAndRun(). From there, the GUI intercepts mouse input from the user and displays the GUI changes initiated by the program code running smoothly and concurrently.

Not Below 400 Pixels

The Fyne framework not only runs on desktop interfaces, but it was designed to work on mobile devices as well. This is why, among other things that look awkward at first, it does not provide an option for setting an application window to a defined minimum size after the program start.

That's a good strategy in the grand scheme of cross-platform framework development. However it's quite jarring if an application like Syno comes up as a mini window measuring 50x50 pixels that you can hardly see on the desktop. Fortunately, you can use a trick to define a minimum size. The app stuffs the main container with an empty image measuring 400x0 pixels, which invisibly becomes part of the VBox with the widgets. This forces the renderer to open an application window with a width of at least 400 pixels wide from the outset.

Switching Off with sudo

The last part of the application in Listing 4 defines the utility function isPingable(), which checks whether the NAS is operational. This could of course be done with a component from the net standard library from the Go repository, but for simplicity's sake the function simply calls the Ping program in the shell. Depending on that command's return code, the function returns a true or false value to the caller.

Listing 4

util.go

01 package main
02 import (
03   "os/exec"
04 )
05 const synIP = "192.168.3.33"
06 func shutdownNAS() {
07   cmd := exec.Command("ssh", "synuser@"+synIP, "sudo", "/sbin/poweroff")
08   if err := cmd.Run(); err != nil {
09       panic(err)
10   }
11 }
12 func isPingable() bool {
13   cmd := exec.Command("ping", "-c", "1", "-t", "3", synIP)
14   if err := cmd.Run(); err != nil {
15     return false
16   }
17   return true
18 }

To shut down the NAS when the user presses the Down button, the shutdownNAS() function contacts the NAS at its IP address starting in line 6 and logs into a predefined SSH account. It then issues the sudo poweroff command in the opened shell. This causes the monster disk array to shut down and disconnect itself from the power supply. Meanwhile, the state machine notices this in the course of its continuous checks and the GUI jumps to the DOWN visualization.

To do this, the controlling host needs to be able to use SSH to log in to the NAS without entering a password. This is typically achieved by storing the public key of a key pair maintained by the controlling host in the ~/.ssh/authorized_keys file on the NAS. Also, the user on the NAS needs sudo privileges to execute the poweroff command. This is handled by the line

synouser ALL=(ALL) NOPASSWD: /sbin/poweroff

in /etc/sudoers file on the NAS.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

  • GUI Apps with Fyne

    The Fyne toolkit offers a simple way to build native apps that work across multiple platforms. We show you how to build a to-do list app to demonstrate Fyne's power.

  • Straight to the Point

    With the Fyne framework, Go offers an easy-to-use graphical interface for all popular platforms. As a sample application, Mike uses an algorithm to draw arrows onto images.

  • Wheat and Chaff

    If you want to keep only the good photos from your digital collection, you have to find and delete the fails. Mike Schilli writes a graphical application with Go and the Fyne framework to help you cull your photo library.

  • Treasure Hunt

    A geolocation guessing game based on the popular Wordle evaluates a player's guesses based on the distance from and direction to the target location. Mike Schilli turns this concept into a desktop game in Go using the photos from his private collection.

  • Chip Shot

    We all know that the Fyne framework for Go can be used to create GUIs for the desktop, but you can also write games with it. Mike Schilli takes on a classic from the soccer field.

comments powered by Disqus
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters

Support Our Work

Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.

Learn More

News