func (middleware *Middleware) getAuthStructure() (map[string]UserAuthStruct, error) {
	usersMap := make(map[string]UserAuthStruct)
	authStructureString, err := middleware.redisClient.GetString(redis.MiddlewareAuth)
	if err != nil {
		log.Println("error getting the auth structure string from the redis client")
		return usersMap, err
	}
	err = json.Unmarshal([]byte(authStructureString), &usersMap)
	if err != nil {
		log.Println("Did not receive json from redis's authentication structure")
		return usersMap, err
	}
	return usersMap, nil
}
get userAuthStructure gets the user authentication data from redis and parses it into a map with the username as a key and the UserAuthStruct
as a value.
package middleware
import (
	"encoding/json"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"reflect"
	"strconv"
	"strings"
	"time"
	"github.com/digitalbitbox/bitbox-base/middleware/src/handlers"
	"github.com/digitalbitbox/bitbox-base/middleware/src/prometheus"
	"github.com/digitalbitbox/bitbox-base/middleware/src/redis"
	"github.com/digitalbitbox/bitbox-base/middleware/src/rpcmessages"
	"github.com/digitalbitbox/bitbox02-api-go/api/firmware/messages"
)
func (middleware *Middleware) mountFlashdrive() rpcmessages.ErrorResponse {
	log.Println("Executing a USB flashdrive check via the cmd script")
	outCheck, err := middleware.runBBBCmdScript([]string{"flashdrive", "check"})
	if err != nil {
		errorCode := handleBBBScriptErrorCode(outCheck, err, []rpcmessages.ErrorCode{
			rpcmessages.ErrorFlashdriveCheckMultiple,
			rpcmessages.ErrorFlashdriveCheckNone,
		})
		return rpcmessages.ErrorResponse{
			Success: false,
			Message: strings.Join(outCheck, "\n"),
			Code:    errorCode,
		}
	}
	if len(outCheck) > 1 {  
		log.Printf("Warning: The `bbb-cmd.sh flashdrive check` command returned more than one line. Using '%s' as flashdrive name.\n.", outCheck[len(outCheck)-1])
	} else if len(outCheck) == 0 {
		return rpcmessages.ErrorResponse{  
			Success: false,
			Message: "An unexpected Error occurred: The output of `bbb-cmd.sh flashdrive check` did not contain a flashdrive name.",
			Code:    rpcmessages.ErrorUnexpected,
		}
	}
	flashDriveName := outCheck[len(outCheck)-1]
	log.Println("Executing a USB flashdrive mount via the cmd script")
	outMount, err := middleware.runBBBCmdScript([]string{"flashdrive", "mount", flashDriveName})
	if err != nil {
		errorCode := handleBBBScriptErrorCode(outMount, err, []rpcmessages.ErrorCode{
			rpcmessages.ErrorFlashdriveMountNotFound,
			rpcmessages.ErrorFlashdriveMountNotSupported,
			rpcmessages.ErrorFlashdriveMountNotUnique,
		})
		return rpcmessages.ErrorResponse{
			Success: false,
			Message: strings.Join(outMount, "\n"),
			Code:    errorCode,
		}
	}
	return rpcmessages.ErrorResponse{Success: true}
}
func (middleware *Middleware) unmountFlashdrive() rpcmessages.ErrorResponse {
	log.Println("Executing a USB flashdrive unmount via the cmd script")
	out, err := middleware.runBBBCmdScript([]string{"flashdrive", "unmount"})
	if err != nil {
		errorCode := handleBBBScriptErrorCode(out, err, []rpcmessages.ErrorCode{
			rpcmessages.ErrorFlashdriveUnmountNotMounted,
		})
		return rpcmessages.ErrorResponse{
			Success: false,
			Message: strings.Join(out, "\n"),
			Code:    errorCode,
		}
	}
	return rpcmessages.ErrorResponse{Success: true}
}
func (middleware *Middleware) runBBBSystemctlScript(args []string) (outputLines []string, err error) {
	outputLines, err = runCommand(middleware.config.GetBBBSystemctlScript(), args)
	return
}
func (middleware *Middleware) checkSystemdServiceStatus(serviceName string) (bool, error) {
	active, err := runCommand("systemctl", []string{"is-active", serviceName})
	return active[0] == "active", err
}
func (middleware *Middleware) runBBBCmdScript(args []string) (outputLines []string, err error) {
	outputLines, err = runCommand(middleware.config.GetBBBCmdScript(), args)
	return
}
func (middleware *Middleware) runBBBConfigScript(args []string) (outputLines []string, err error) {
	outputLines, err = runCommand(middleware.config.GetBBBConfigScript(), args)
	return
}
func runCommand(command string, args []string) (combinedLines []string, err error) {
	cmd := exec.Command(command, args...)
	log.Printf("executing command: %s %s", command, strings.Join(args, " "))
	rawstdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		log.Printf("Error executing command '%s %s': '%s'", command, strings.Join(args, " "), err.Error())
	}
	combined := strings.TrimSuffix(string(rawstdoutStderr), "\n")
	combinedLines = strings.Split(combined, "\n")
	return combinedLines, err
}
func handleBBBScriptErrorCode(outputLines []string, err error, possibleErrors []rpcmessages.ErrorCode) rpcmessages.ErrorCode {
	if os.IsNotExist(err) {
		return rpcmessages.ExecutableNotFound
	} else if err.Error() == "exit status 1" {
		if len(outputLines) == 0 {
			log.Println("Error: no log lines provided before exit with error status 1.")
			return rpcmessages.ErrorUnexpected
		}
		outputErrorCode := outputLines[len(outputLines)-1]
		switch outputErrorCode {
		case string(rpcmessages.ErrorScriptNotSuperuser):
			return rpcmessages.ErrorScriptNotSuperuser  
		case string(rpcmessages.ErrorCmdScriptInvalidArg):
			return rpcmessages.ErrorCmdScriptInvalidArg  
		case string(rpcmessages.ErrorConfigScriptInvalidArg):
			return rpcmessages.ErrorConfigScriptInvalidArg  
		}
		for _, possible := range possibleErrors {
			if outputErrorCode == string(possible) {
				return possible
			}
		}
	}
	log.Printf("Error: unhandled error '%s' with output '%s'", err.Error(), outputLines)
	return rpcmessages.ErrorUnexpected
}
func determineEnableValue(enable rpcmessages.ToggleSettingArgs) string {
	if enable.ToggleSetting {
		return "enable"
	}
	return "disable"
}
func (middleware *Middleware) didServiceInfoChange() (changed bool) {
	upToDateServiceInfo := middleware.getServiceInfo()
	if !reflect.DeepEqual(upToDateServiceInfo, middleware.serviceInfo) {
		middleware.serviceInfo = upToDateServiceInfo
		log.Printf("new serviceInfo is available: %+v", middleware.serviceInfo)
		return true
	}
	return false
}
func (middleware *Middleware) getServiceInfo() rpcmessages.GetServiceInfoResponse {
	bitcoindBlocks, err := middleware.prometheusClient.GetInt(prometheus.BitcoinBlockCount)
	if err != nil {
		log.Printf("Error scraping bitcoindBlocks information. Error: %s", err.Error())
		bitcoindBlocks = 0
	}
	bitcoindHeaders, err := middleware.prometheusClient.GetInt(prometheus.BitcoinHeaderCount)
	if err != nil {
		log.Printf("Error scraping bitcoindHeaders information. Error: %s", err.Error())
		bitcoindHeaders = 0
	}
	bitcoindVerificationProgress, err := middleware.prometheusClient.GetFloat(prometheus.BitcoinVerificationProgress)
	if err != nil {
		log.Printf("Error scraping bitcoindVerificationProgress information. Error: %s", err.Error())
		errResponse := middleware.prometheusClient.ConvertErrorToErrorResponse(err)
		return rpcmessages.GetServiceInfoResponse{ErrorResponse: &errResponse}
	}
	bitcoindPeers, err := middleware.prometheusClient.GetInt(prometheus.BitcoinPeers)
	if err != nil {
		log.Printf("Error scraping bitcoindPeers information. Error: %s", err.Error())
		errResponse := middleware.prometheusClient.ConvertErrorToErrorResponse(err)
		return rpcmessages.GetServiceInfoResponse{ErrorResponse: &errResponse}
	}
	bitcoindIBDAsInt, err := middleware.prometheusClient.GetInt(prometheus.BitcoinIBD)
	if err != nil {
		log.Printf("Error scraping bitcoindIBDAsInt information. Error: %s", err.Error())
		errResponse := middleware.prometheusClient.ConvertErrorToErrorResponse(err)
		return rpcmessages.GetServiceInfoResponse{ErrorResponse: &errResponse}
	}
	bitcoindIBD := bitcoindIBDAsInt == 1
	lightningdBlocks, err := middleware.prometheusClient.GetInt(prometheus.LightningBlocks)
	if err != nil {
		log.Printf("Error scraping lightningdBlocks information. Error: %s", err.Error())
		lightningdBlocks = 0
	}
	lightningActiveChannels, err := middleware.prometheusClient.GetInt(prometheus.LightningActiveChannels)
	if err != nil {
		log.Printf("Error scraping lightningActiveChannels information. Error: %s", err.Error())
		lightningActiveChannels = 0
	}
	electrsBlocks, err := middleware.prometheusClient.GetInt(prometheus.ElectrsBlocks)
	if err != nil {
		log.Printf("Error scraping electrsBlocks information. Error: %s", err.Error())
		electrsBlocks = 0
	}
	return rpcmessages.GetServiceInfoResponse{
		ErrorResponse: &rpcmessages.ErrorResponse{
			Success: true,
		},
		BitcoindBlocks:               bitcoindBlocks,
		BitcoindHeaders:              bitcoindHeaders,
		BitcoindVerificationProgress: bitcoindVerificationProgress,
		BitcoindPeers:                bitcoindPeers,
		BitcoindIBD:                  bitcoindIBD,
		LightningdBlocks:             lightningdBlocks,
		LightningActiveChannels:      lightningActiveChannels,
		ElectrsBlocks:                electrsBlocks,
	}
}
func parseBaseUpdateStdout(outputLine string) (containsUpdateProgressInfo bool, percentage int, downloadedKiB int) {
	const prefix string = "................................"
	const suffix string = "KiB"
	if !strings.HasPrefix(outputLine, prefix) || !strings.HasSuffix(outputLine, suffix) {
		return false, 0, 0
	}
	strippedProgress := strings.TrimSpace(strings.TrimPrefix(strings.TrimSuffix(outputLine, suffix), prefix))
	splittedProgress := strings.Split(strippedProgress, " ")
	if len(splittedProgress) != 2 {
		log.Printf("parseBaseUpdateStdout: Unexpected string parts in stripped output '%s'", strippedProgress)
		return false, 0, 0
	}
	a := strings.Replace(splittedProgress[0], "%", "", 1)
	percentage, err := strconv.Atoi(a)
	if err != nil {
		log.Printf("parseBaseUpdateStdout: Could not convert '%s' to an integer: %s", a, err)
		return false, 0, 0
	}
	downloadedKiB, err = strconv.Atoi(splittedProgress[1])
	if err != nil {
		log.Printf("parseBaseUpdateStdout: Could not convert '%s' to an integer: %s", splittedProgress[1], err)
		return false, 0, 0
	}
	log.Println(percentage, downloadedKiB)
	return true, percentage, downloadedKiB
}
func (middleware *Middleware) setBaseUpdateStateAndNotify(state rpcmessages.BaseUpdateState) {
	middleware.baseUpdateProgress.State = state
	middleware.events <- handlers.Event{
		Identifier:      []byte(rpcmessages.OpBaseUpdateProgressChanged),
		QueueIfNoClient: true,
	}
}
func (middleware *Middleware) checkMiddlewareSetup() error {
	passwordSet, err := middleware.redisClient.GetBool(redis.MiddlewarePasswordSet)
	if err != nil {
		return err
	}
	baseSetupDone, err := middleware.redisClient.GetBool(redis.BaseSetupDone)
	if err != nil {
		return err
	}
	middleware.isMiddlewarePasswordSet = passwordSet
	middleware.isBaseSetupDone = baseSetupDone
	return nil
}