func (middleware *Middleware) ReindexBitcoin() rpcmessages.ErrorResponse {
	log.Println("executing full bitcoin resync via the cmd script")
	out, err := middleware.runBBBCmdScript([]string{"bitcoind", "reindex"})
	if err != nil {
		errorCode := handleBBBScriptErrorCode(out, err, nil)
		return rpcmessages.ErrorResponse{
			Success: false,
			Message: strings.Join(out, "\n"),
			Code:    errorCode,
		}
	}
	return rpcmessages.ErrorResponse{Success: true}
}
ReindexBitcoin returns a ErrorResponse struct in response to a rpcserver request
package middleware
import (
	"bufio"
	"encoding/json"
	"fmt"
	"log"
	"os/exec"
	"regexp"
	"strings"
	"time"
	"github.com/digitalbitbox/bitbox-base/middleware/src/authentication"
	"github.com/digitalbitbox/bitbox-base/middleware/src/configuration"
	"github.com/digitalbitbox/bitbox-base/middleware/src/handlers"
	"github.com/digitalbitbox/bitbox-base/middleware/src/ipcnotification"
	"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"
	"github.com/digitalbitbox/bitbox02-api-go/api/firmware/messages"
	"github.com/digitalbitbox/bitbox02-api-go/util/semver"
	"golang.org/x/crypto/bcrypt"
)
type UserAuthStruct struct {
	BCryptedPassword string `json:"password"`
	Role             string `json:"role"`
}
const initialAdminPassword = "ICanHasPasword?"
type Middleware struct {
	config              configuration.Configuration
	events              chan handlers.Event
	prometheusClient    prometheus.Client
	redisClient         redis.Redis
	jwtAuth             *authentication.JwtAuth
	serviceInfo         rpcmessages.GetServiceInfoResponse
	baseUpdateProgress  rpcmessages.GetBaseUpdateProgressResponse
	baseUpdateAvailable rpcmessages.IsBaseUpdateAvailableResponse
	baseVersion         *semver.SemVer
	isMiddlewarePasswordSet bool
	isBaseSetupDone         bool
	hsmFirmware *firmware.Device
}
func (middleware *Middleware) GetMiddlewareVersion() string {
	return middleware.config.GetMiddlewareVersion()
}
func NewMiddleware(config configuration.Configuration, hsmFirmware *firmware.Device) (*Middleware, error) {
	middleware := &Middleware{
		config: config,
		events:      make(chan handlers.Event),  
		serviceInfo: rpcmessages.GetServiceInfoResponse{},
		baseUpdateProgress: rpcmessages.GetBaseUpdateProgressResponse{
			State:                 rpcmessages.UpdateNotInProgress,
			ProgressPercentage:    0,
			ProgressDownloadedKiB: 0,
		},
		isMiddlewarePasswordSet: false,
		baseUpdateAvailable: rpcmessages.IsBaseUpdateAvailableResponse{
			ErrorResponse:   &rpcmessages.ErrorResponse{Success: true},
			UpdateAvailable: false,
		},
		baseVersion: semver.NewSemVer(0, 0, 0),
		hsmFirmware: hsmFirmware,
	}
	middleware.prometheusClient = prometheus.NewClient(middleware.config.GetPrometheusURL())
	if !middleware.config.IsRedisMock() {
		middleware.redisClient = redis.NewClient(middleware.config.GetRedisPort())
	} else {
		middleware.redisClient = redis.NewMockClient("")
	}
	err := middleware.checkMiddlewareSetup()
	if err != nil {
		log.Println("failed to update the middleware password set flag")
		return nil, err
	}
	if !middleware.isMiddlewarePasswordSet {
		usersMap := make(map[string]UserAuthStruct)
		bcryptedPassword, err := bcrypt.GenerateFromPassword([]byte(initialAdminPassword), 12)
		if err != nil {
			log.Println("Failed to generate new standard password")
			return nil, err
		}
		usersMap["admin"] = UserAuthStruct{BCryptedPassword: string(bcryptedPassword), Role: "admin"}
		authStructureString, err := json.Marshal(&usersMap)
		if err != nil {
			log.Println("Unable to marshal auth structure map")
			return nil, err
		}
		err = middleware.redisClient.SetString(redis.MiddlewareAuth, string(authStructureString))
		if err != nil {
			log.Println("Unable to initialize auth data structure")
			return nil, err
		}
	}
	middleware.jwtAuth, err = authentication.NewJwtAuth()
	if err != nil {
		return nil, err
	}
	return middleware, nil
}
func (middleware *Middleware) IsBaseUpdateAvailable() rpcmessages.IsBaseUpdateAvailableResponse {
	return middleware.baseUpdateAvailable
}
func (middleware *Middleware) rpcLoop() {
	for {
		if middleware.didServiceInfoChange() {
			middleware.events <- handlers.Event{
				Identifier:      []byte(rpcmessages.OpServiceInfoChanged),
				QueueIfNoClient: false,
			}
		}
		time.Sleep(5 * time.Second)
	}
}
func (middleware *Middleware) updateCheckLoop() {
	const timeBetweenUpdateChecks time.Duration = 30 * time.Minute
	for {
		updateInfo, err := getBaseUpdateInfo(middleware.config.GetImageUpdateInfoURL())
		if err != nil {
			log.Printf("Could not GET update info: %s\n", err)
			time.Sleep(timeBetweenUpdateChecks)
			continue
		}
		newVersion, err := semver.NewSemVerFromString(updateInfo.Version)
		if err != nil {
			log.Printf("Could not parse update info version as SemVer: %s\n", err)
			time.Sleep(timeBetweenUpdateChecks)
			continue
		}
		if !middleware.baseVersion.AtLeast(newVersion) {
			log.Printf("A Base image update is available from version %s to %s.\n", middleware.baseVersion.String(), newVersion.String())
			middleware.baseUpdateAvailable.UpdateAvailable = true
			middleware.baseUpdateAvailable.UpdateInfo = updateInfo
			middleware.events <- handlers.Event{
				Identifier:      []byte(rpcmessages.OpBaseUpdateIsAvailable),
				QueueIfNoClient: false,
			}
		}
		time.Sleep(timeBetweenUpdateChecks)
	}
}
func (middleware *Middleware) hsmHeartbeatLoop() {
	for {
		err := middleware.hsmFirmware.BitBoxBaseHeartbeat(messages.BitBoxBaseHeartbeatRequest_IDLE, messages.BitBoxBaseHeartbeatRequest_EMPTY)
		if err != nil {
			log.Printf("Received an error from the HSM: %s\n", err)
			time.Sleep(time.Second)
			continue
		}
		time.Sleep(5 * time.Second)
	}
}
func (middleware *Middleware) Start() <-chan handlers.Event {
	if middleware.hsmFirmware != nil {
		go middleware.hsmHeartbeatLoop()
	}
	go middleware.rpcLoop()
	err := middleware.setHSMConfig()
	if err != nil {
		log.Printf("Error: could not set the HSM config: %s", err)
	}
	baseVersion, err := middleware.redisClient.GetString(redis.BaseVersion)
	if err != nil {
		log.Printf("Error: could not get the Base version from Redis: %s", err)
	}
	baseSemVersion, err := semver.NewSemVerFromString(baseVersion)
	if err != nil {
		log.Printf("Error: could not parse the Base version as semver: %s", err)
	}
	middleware.baseVersion = baseSemVersion
	log.Printf("Current Base image version is %s.\n", middleware.baseVersion.String())
	go middleware.updateCheckLoop()
	notificationReader, err := ipcnotification.NewReader(middleware.config.GetNotificationNamedPipePath())
	if err != nil {
		log.Printf("Error creating new IPC notification reader: %s", err)
	} else {
		go middleware.ipcNotificationLoop(notificationReader)
	}
	return middleware.events
}
func (middleware *Middleware) ipcNotificationLoop(reader *ipcnotification.Reader) {
	const supportedNotificationVersion int = 1
	notifications := reader.Notifications()
	for {
		notification := <-notifications
		if notification.Version != supportedNotificationVersion {
			log.Printf("Dropping IPC notification with unsupported version: %s\n", notification.String())
		}
		log.Printf("Received notification with topic '%s': %v\n", notification.Topic, notification.Payload)
		switch notification.Topic {
		case "mender-update":
			if success, ok := ipcnotification.ParseMenderUpdatePayload(notification.Payload); ok {
				switch success {
				case true:
					middleware.events <- handlers.Event{
						Identifier:      []byte(rpcmessages.OpBaseUpdateSuccess),
						QueueIfNoClient: true,
					}
				case false:
					middleware.events <- handlers.Event{
						Identifier:      []byte(rpcmessages.OpBaseUpdateFailure),
						QueueIfNoClient: true,
					}
				}
			} else {
				log.Printf("Could not parse %s notification payload: %v\n", notification.Topic, notification.Payload)
			}
		default:
			log.Printf("Dropping IPC notification with unknown topic: %s\n", notification.String())
		}
	}
}
func (middleware *Middleware) ResyncBitcoin() rpcmessages.ErrorResponse {
	log.Println("executing full bitcoin resync via the cmd script")
	out, err := middleware.runBBBCmdScript([]string{"bitcoind", "resync"})
	if err != nil {
		errorCode := handleBBBScriptErrorCode(out, err, nil)
		return rpcmessages.ErrorResponse{
			Success: false,
			Message: strings.Join(out, "\n"),
			Code:    errorCode,
		}
	}
	return rpcmessages.ErrorResponse{Success: true}
}