Skip to content

Working example

Getting available updates

Use the provided class to enumerate the available update bundles.

    client := grpc.NewUpdateClient()
    if err := client.Connect(); err != nil {
        tools.LogMessage("Error: '%s'", err)
        os.Exit(1)
    }
    if err := client.GetAvailableUpdateBundles(*checkUrlParam); err != nil {
        tools.LogMessage("Error: '%s'", err)
        os.Exit(1)
    }

How to install an update bundle

Use one of the returned update bundle URLs to install the according bundle like this:

    client := grpc.NewUpdateClient()
    if err := client.Connect(); err != nil {
        tools.LogMessage("Error: '%s'", err)
        os.Exit(1)
    }
    if err := client.InstallUpdateBundle(*installUrlParam); err != nil {
        tools.LogMessage("Error: '%s'", err)
        os.Exit(1)
    }
    os.Exit(1)

Retrieving device information

The built-in updater, that is started when no user application has been installed, uses this information to open the Display and install an update from the given source without user intervention.

	fmt.Println("Getting client information...")
	result, _ := uc.updateService.GetClientInformation(uc.mainCtx, &swupdatesvc.Empty{})
	fmt.Printf("Product: '%s'\n", result.Product)
	fmt.Printf("Customer: '%s'\n", result.Customer)
	fmt.Printf("Source: '%s'\n", result.Source)
	fmt.Printf("Bootstrap: '%s'\n", result.BootStrap)
	fmt.Printf("TmpDir: '%s'\n", result.TmpDir)
	for k, v := range result.Infos {
		fmt.Printf("Info: '%s' '%s'\n", k, v)
	}

Information about the installed bundle

You can retrieve information from the manifest file that has been installed together with the update bundle, that is currently executed on the device.

	fmt.Println("Getting installed bundle information...")
	result, _ := uc.updateService.GetInstalledBundleInformation(uc.mainCtx, &swupdatesvc.Empty{})
	for k, v := range result.ComponentVersions {
		fmt.Printf("Component: '%s' Version '%s'\n", k, v)
	}
	for k, v := range result.UserInformation {
		fmt.Printf("User-Key: '%s' Value '%s'\n", k, v)
	}

Communication class

package grpc

import (
	"context"
	"fmt"
	"io"
	"net"

	"github.com/idastroem/swupdatesvc"
	grpc "google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

type UpdateClient struct {
	rootCtx          context.Context
	mainCtx          context.Context
	mainCxl          context.CancelFunc
	updateConnection *grpc.ClientConn
	updateService    swupdatesvc.UpdaterClient
}

func NewUpdateClient() *UpdateClient {
	return &UpdateClient{}
}

func (uc *UpdateClient) Connect() error {
	fmt.Print("connecting to update service... ")
	// connect to update service
	uc.rootCtx = context.Background()
	uc.mainCtx, uc.mainCxl = context.WithCancel(uc.rootCtx)

	var (
		credentials = insecure.NewCredentials() // No SSL/TLS
		dialer      = func(ctx context.Context, addr string) (net.Conn, error) {
			var d net.Dialer
			return d.DialContext(ctx, protocol, addr)
		}
		options = []grpc.DialOption{
			grpc.WithTransportCredentials(credentials),
			grpc.WithBlock(),
			grpc.WithContextDialer(dialer),
		}
	)
	var err error
	uc.updateConnection, err = grpc.Dial(sockAddr, options...)
	if err != nil {
		panic(err)
	}
	uc.updateService = swupdatesvc.NewUpdaterClient(uc.updateConnection)
	fmt.Println("OK")

	return nil
}

func (uc *UpdateClient) GetAvailableUpdateBundles(url string) error {
	result, _ := uc.updateService.GetAvailableUpdateBundles(uc.mainCtx, &swupdatesvc.GetAvailableUpdateBundlesRequest{
		UpdateUrl: url,
	})
	if result.IsError {
		return fmt.Errorf("error: '%s'", result.Message)
	}
	fmt.Printf("Engine Version: %+v\n", result.EngineVersion)
	fmt.Printf("Installed Bundle Version: %+v\n", result.CurrentVersion)
	for k, v := range result.InstalledComponents {
		fmt.Printf("Installed Component: '%s' Version '%s'\n", k, v)
	}

	for _, v := range result.AvailableBundles {
		fmt.Printf("Available Bundle: %+v\n", v)
	}

	return nil
}

func (uc *UpdateClient) InstallUpdateBundle(bundleUrl string) error {
	stream, _ := uc.updateService.InstallUpdateBundle(uc.mainCtx, &swupdatesvc.InstallUpdateBundleRequest{
		BundleUrl: bundleUrl,
	})

	fmt.Println("Starting update...")
	fmt.Println()
	for {
		resp, err := stream.Recv()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}
		if resp != nil {
			if resp.Messsage != "" {
				fmt.Println(resp.Messsage)
			}
			if resp.IsError || resp.IsDone {
				fmt.Println()
				if resp.IsError {
					fmt.Println("Update failed.")
					return fmt.Errorf("error: '%s'", resp.Messsage)
				}
				if resp.IsDone {
					fmt.Println("Update successful.")
				}
				break
			} else {
				fmt.Printf("\rProgress: %d", int(100*resp.Progress))
			}
		}
	}
	return nil
}

func (uc *UpdateClient) GetClientInformation() error {
	fmt.Println("Getting client information...")
	result, _ := uc.updateService.GetClientInformation(uc.mainCtx, &swupdatesvc.Empty{})
	fmt.Printf("Product: '%s'\n", result.Product)
	fmt.Printf("Customer: '%s'\n", result.Customer)
	fmt.Printf("Source: '%s'\n", result.Source)
	fmt.Printf("Bootstrap: '%s'\n", result.BootStrap)
	fmt.Printf("TmpDir: '%s'\n", result.TmpDir)
	for k, v := range result.Infos {
		fmt.Printf("Info: '%s' '%s'\n", k, v)
	}
	return nil
}

func (uc *UpdateClient) GetInstalledBundleInformation() error {
	fmt.Println("Getting installed bundle information...")
	result, _ := uc.updateService.GetInstalledBundleInformation(uc.mainCtx, &swupdatesvc.Empty{})
	for k, v := range result.ComponentVersions {
		fmt.Printf("Component: '%s' Version '%s'\n", k, v)
	}
	for k, v := range result.UserInformation {
		fmt.Printf("User-Key: '%s' Value '%s'\n", k, v)
	}
	return nil
}