diff --git a/Dockerfile b/Dockerfile
index e6cda073..ea049e10 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -4,7 +4,7 @@ WORKDIR /app
ADD . .
-RUN CGO_ENABLED=0 go build -o ./bin/algorun *.go
+RUN CGO_ENABLED=0 go build -o ./bin/algorun main.go && CGO_ENABLED=0 go build -o ./bin/fortiter daemon/main.go
FROM algorand/algod:latest
@@ -20,6 +20,7 @@ ADD .docker/start_empty.sh /node/run/start_empty.sh
ADD .docker/start_fast_catchup.sh /node/run/start_fast_catchup.sh
COPY --from=builder /app/bin/algorun /bin/algorun
+COPY --from=BUILDER /app/bin/fortiter /bin/fortiter
RUN apt-get update && apt-get install jq -y
diff --git a/Makefile b/Makefile
index 195d9e3a..a77c39c0 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,7 @@
build:
- CGO_ENABLED=0 go build -o bin/algorun *.go
+ CGO_ENABLED=0 go build -o bin/algorun main.go
+build-daemon:
+ CGO_ENABLED=0 go build -o bin/fortiter -ldflags "-X cmd.version=testing" daemon/main.go
test:
go test -coverpkg=./... -covermode=atomic ./...
generate:
diff --git a/cmd/root.go b/cmd/root.go
index 2e03a8d9..6deb5400 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -7,7 +7,7 @@ import (
"github.com/algorandfoundation/algorun-tui/api"
"github.com/algorandfoundation/algorun-tui/cmd/configure"
"github.com/algorandfoundation/algorun-tui/cmd/node"
- "github.com/algorandfoundation/algorun-tui/internal"
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
"github.com/algorandfoundation/algorun-tui/ui"
"github.com/algorandfoundation/algorun-tui/ui/explanations"
"github.com/algorandfoundation/algorun-tui/ui/style"
@@ -64,15 +64,15 @@ var (
v.StatusCode())
}
- partkeys, err := internal.GetPartKeys(ctx, client)
+ partkeys, err := nodekit.GetPartKeys(ctx, client)
if err != nil {
return fmt.Errorf(
style.Red.Render("failed to get participation keys: %s")+
explanations.TokenNotAdmin,
err)
}
- state := internal.StateModel{
- Status: internal.StatusModel{
+ state := nodekit.StateModel{
+ Status: nodekit.StatusModel{
State: "INITIALIZING",
Version: "N/A",
Network: "N/A",
@@ -80,7 +80,7 @@ var (
NeedsUpdate: true,
LastRound: 0,
},
- Metrics: internal.MetricsModel{
+ Metrics: nodekit.MetricsModel{
RoundTime: 0,
TPS: 0,
RX: 0,
@@ -91,10 +91,10 @@ var (
Client: client,
Context: ctx,
}
- state.Accounts, err = internal.AccountsFromState(&state, new(internal.Clock), client)
+ state.Accounts, err = nodekit.AccountsFromState(&state, new(nodekit.Clock), client)
cobra.CheckErr(err)
// Fetch current state
- err = state.Status.Fetch(ctx, client, new(internal.HttpPkg))
+ err = state.Status.Fetch(ctx, client, new(nodekit.HttpPkg))
cobra.CheckErr(err)
m, err := ui.NewViewportViewModel(&state, client)
@@ -106,7 +106,7 @@ var (
tea.WithFPS(120),
)
go func() {
- state.Watch(func(status *internal.StateModel, err error) {
+ state.Watch(func(status *nodekit.StateModel, err error) {
if err == nil {
p.Send(state)
}
diff --git a/cmd/status.go b/cmd/status.go
index 62bd010f..a1b7abc8 100644
--- a/cmd/status.go
+++ b/cmd/status.go
@@ -4,7 +4,7 @@ import (
"context"
"errors"
"fmt"
- "github.com/algorandfoundation/algorun-tui/internal"
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
"github.com/algorandfoundation/algorun-tui/ui"
"github.com/algorandfoundation/algorun-tui/ui/style"
tea "github.com/charmbracelet/bubbletea"
@@ -27,8 +27,8 @@ var statusCmd = &cobra.Command{
// Get Algod from configuration
client, err := getClient()
cobra.CheckErr(err)
- state := internal.StateModel{
- Status: internal.StatusModel{
+ state := nodekit.StateModel{
+ Status: nodekit.StatusModel{
State: "SYNCING",
Version: "N/A",
Network: "N/A",
@@ -36,7 +36,7 @@ var statusCmd = &cobra.Command{
NeedsUpdate: true,
LastRound: 0,
},
- Metrics: internal.MetricsModel{
+ Metrics: nodekit.MetricsModel{
RoundTime: 0,
TPS: 0,
RX: 0,
@@ -44,14 +44,14 @@ var statusCmd = &cobra.Command{
},
ParticipationKeys: nil,
}
- err = state.Status.Fetch(context.Background(), client, new(internal.HttpPkg))
+ err = state.Status.Fetch(context.Background(), client, new(nodekit.HttpPkg))
cobra.CheckErr(err)
// Create the TUI
view := ui.MakeStatusViewModel(&state)
p := tea.NewProgram(view, tea.WithAltScreen())
go func() {
- state.Watch(func(status *internal.StateModel, err error) {
+ state.Watch(func(status *nodekit.StateModel, err error) {
cobra.CheckErr(err)
p.Send(state)
}, context.Background(), client)
diff --git a/daemon/cmd/root.go b/daemon/cmd/root.go
new file mode 100644
index 00000000..ec9a5a3c
--- /dev/null
+++ b/daemon/cmd/root.go
@@ -0,0 +1,204 @@
+package cmd
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "github.com/algorand/go-algorand/config"
+ "github.com/algorandfoundation/algorun-tui/daemon/fortiter"
+ "github.com/algorandfoundation/algorun-tui/daemon/rpc"
+ "github.com/algorandfoundation/algorun-tui/ui/style"
+ "github.com/charmbracelet/log"
+ "github.com/jmoiron/sqlx"
+ "github.com/labstack/echo-contrib/echoprometheus"
+ "github.com/labstack/echo/v4"
+ "github.com/labstack/echo/v4/middleware"
+ _ "github.com/mattn/go-sqlite3"
+ "github.com/spf13/cobra"
+ "github.com/spf13/viper"
+ "io"
+ "os"
+ "strings"
+)
+
+const BANNER = `
+ ______ ______ ______ ______ __ ______ ______ ______
+/\ ___\ /\ __ \ /\ == \ /\__ _\ /\ \ /\__ _\ /\ ___\ /\ == \
+\ \ __\ \ \ \/\ \ \ \ __< \/_/\ \/ \ \ \ \/_/\ \/ \ \ __\ \ \ __<
+ \ \_\ \ \_____\ \ \_\ \_\ \ \_\ \ \_\ \ \_\ \ \_____\ \ \_\ \_\
+ \/_/ \/_____/ \/_/ /_/ \/_/ \/_/ \/_/ \/_____/ \/_/ /_/
+`
+
+var version = ""
+var (
+ Version = version
+ sqlFile string
+ rootCmd = &cobra.Command{
+ Version: Version,
+ Use: "fortiter",
+ Short: "Consume all the data",
+ Long: style.Purple(BANNER) + "\n",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ log.SetOutput(cmd.OutOrStdout())
+
+ e := echo.New()
+ e.HideBanner = true
+
+ // TODO: handle user interaction
+ e.Use(middleware.Logger())
+ e.Use(middleware.Recover())
+ e.Use(echoprometheus.NewMiddleware("fortiter"))
+ e.Static("/", "public")
+
+ fmt.Println(style.Magenta(BANNER))
+ fmt.Println(style.LightBlue("Database: ") + viper.GetString("database"))
+
+ algodConfig := viper.GetString("data")
+ if algodConfig != "" {
+ fmt.Println(style.LightBlue("Configuration: ") + algodConfig)
+ }
+ logFile := viper.GetString("log")
+ if logFile != "" {
+ fmt.Println(style.LightBlue("Log: ") + logFile)
+ }
+ var si = fortiter.Handlers{PrometheusHandler: echoprometheus.NewHandler()}
+ rpc.RegisterHandlers(e, si)
+
+ db, err := sqlx.Connect("sqlite3", viper.GetString("database"))
+ cobra.CheckErr(err)
+
+ // exec the schema or fail; multi-statement Exec behavior varies between
+ // database drivers; pq will exec them all, sqlite3 won't, ymmv
+ db.MustExec(fortiter.Schema)
+ db.MustExec(fortiter.StatsSchema)
+
+ err = fortiter.Sync(context.Background(), logFile, db)
+ cobra.CheckErr(err)
+
+ return e.Start(":1337")
+ },
+ }
+)
+
+func check(err interface{}) {
+ if err != nil {
+ log.Fatal(err)
+ panic(err)
+ }
+}
+
+// Handle global flags and set usage templates
+func init() {
+ log.SetReportTimestamp(false)
+ initConfig()
+ // Configure Version
+ if Version == "" {
+ Version = "unknown (built from source)"
+ }
+ rootCmd.Version = Version
+
+ // Bindings
+ rootCmd.PersistentFlags().StringVar(&sqlFile, "database", "fortiter.db", style.LightBlue("database file location"))
+ _ = viper.BindPFlag("database", rootCmd.PersistentFlags().Lookup("database"))
+ // Update Long Text
+ rootCmd.Long +=
+ //style.Magenta("Database: ") + viper.GetViper().ConfigFileUsed() + "\n" +
+ style.LightBlue("Database: ") + viper.GetString("database")
+
+ if viper.GetString("data") != "" {
+ rootCmd.Long +=
+ style.Magenta("\nAlgorand Data: ") + viper.GetString("data")
+ }
+}
+
+// Execute executes the root command.
+func Execute() error {
+ return rootCmd.Execute()
+}
+
+type AlgodConfig struct {
+ EndpointAddress string `json:"EndpointAddress"`
+}
+
+func initExistingAlgod() {
+ algorandData, exists := os.LookupEnv("ALGORAND_DATA")
+
+ // Load the Algorand Data Configuration
+ if exists && algorandData != "" {
+ // Placeholder for Struct
+ var algodConfig config.Local
+
+ dataConfigPath := algorandData + "/config.json"
+
+ // Open the config.json File
+ configFile, err := os.Open(dataConfigPath)
+ check(err)
+
+ // Read the bytes of the File
+ byteValue, _ := io.ReadAll(configFile)
+ err = json.Unmarshal(byteValue, &algodConfig)
+ check(err)
+
+ // Close the open handle
+ err = configFile.Close()
+ check(err)
+
+ // Replace catchall address with localhost
+ if strings.Contains(algodConfig.EndpointAddress, "0.0.0.0") {
+ algodConfig.EndpointAddress = strings.Replace(algodConfig.EndpointAddress, "0.0.0.0", "127.0.0.1", 1)
+ }
+
+ // Handle Token Path
+ tokenPath := algorandData + "/algod.admin.token"
+
+ tokenFile, err := os.Open(tokenPath)
+ check(err)
+
+ byteValue, err = io.ReadAll(tokenFile)
+ check(err)
+ }
+}
+func initConfig() {
+ // Load ALGORAND_DATA/config.json
+ algorandData, exists := os.LookupEnv("ALGORAND_DATA")
+
+ // Load the Algorand Data Configuration
+ if exists && algorandData != "" {
+ // Placeholder for Struct
+ var algodConfig config.Local
+
+ dataConfigPath := algorandData + "/config.json"
+
+ // Open the config.json File
+ configFile, err := os.Open(dataConfigPath)
+ check(err)
+
+ // Read the bytes of the File
+ byteValue, _ := io.ReadAll(configFile)
+ err = json.Unmarshal(byteValue, &algodConfig)
+ check(err)
+
+ // Close the open handle
+ err = configFile.Close()
+ check(err)
+
+ // Find the log file
+ logPath, _ := algodConfig.ResolveLogPaths(algorandData)
+
+ // Handle Token Path
+ tokenPath := algorandData + "/algod.admin.token"
+
+ tokenFile, err := os.Open(tokenPath)
+ check(err)
+
+ byteValue, err = io.ReadAll(tokenFile)
+ check(err)
+
+ // Set the server configuration
+ viper.Set("server", "http://"+algodConfig.EndpointAddress)
+ viper.Set("token", string(byteValue))
+ viper.Set("data", dataConfigPath)
+ viper.Set("log", logPath)
+ }
+
+}
diff --git a/daemon/fortiter.db b/daemon/fortiter.db
new file mode 100644
index 00000000..887f7907
Binary files /dev/null and b/daemon/fortiter.db differ
diff --git a/daemon/fortiter/agreements.go b/daemon/fortiter/agreements.go
new file mode 100644
index 00000000..2d43800a
--- /dev/null
+++ b/daemon/fortiter/agreements.go
@@ -0,0 +1,20 @@
+package fortiter
+
+import (
+ "github.com/algorand/go-algorand/logging/logspec"
+ "github.com/jmoiron/sqlx"
+ _ "github.com/mattn/go-sqlite3"
+ "time"
+)
+
+type AgreementEvent struct {
+ logspec.AgreementEvent
+ Message string `json:"msg"`
+ Time time.Time `json:"time"`
+}
+
+func SaveAgreement(event AgreementEvent, db *sqlx.DB) error {
+ a := event.AgreementEvent
+ db.MustExec("INSERT INTO agreements (type, round, period, step, hash, sender, object_round, object_period, object_step, weight, weight_total, message, time) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)", a.Type, a.Round, a.Period, a.Step, a.Hash, a.Sender, a.ObjectRound, a.ObjectPeriod, a.ObjectStep, a.Weight, a.WeightTotal, event.Message, event.Time)
+ return nil
+}
diff --git a/daemon/fortiter/handlers.go b/daemon/fortiter/handlers.go
new file mode 100644
index 00000000..4fa7acbf
--- /dev/null
+++ b/daemon/fortiter/handlers.go
@@ -0,0 +1,65 @@
+package fortiter
+
+import (
+ "fmt"
+ "github.com/algorandfoundation/algorun-tui/api"
+ "github.com/gorilla/websocket"
+ "github.com/jmoiron/sqlx"
+ "github.com/labstack/echo/v4"
+ "net/http"
+)
+
+type Handlers struct {
+ PrometheusHandler echo.HandlerFunc
+ client api.ClientWithResponses
+ db *sqlx.DB
+}
+
+var (
+ upgrader = websocket.Upgrader{}
+)
+
+func (h Handlers) GetAgreementEvents(c echo.Context, hash string) error {
+ //rows, err := h.db.NamedQuery(`SELECT * FROM agreements WHERE hash=:first_name`)
+ //if err != nil {
+ // return err
+ //}
+ return c.String(http.StatusOK, "Hello")
+}
+
+func (h Handlers) GetStatus(c echo.Context) error {
+ return c.String(http.StatusOK, "Hello, World!")
+}
+
+type LogWssMessage struct {
+ method string
+}
+
+func (h Handlers) GetWs(c echo.Context) error {
+ ws, err := upgrader.Upgrade(c.Response(), c.Request(), nil)
+ if err != nil {
+ return err
+ }
+ defer ws.Close()
+ for {
+ // Write
+ err := ws.WriteMessage(websocket.TextMessage, []byte("Hello, Client!"))
+ if err != nil {
+ break
+ //c.Logger().Error(err)
+ }
+
+ // Read
+ _, msg, err := ws.ReadMessage()
+ if err != nil {
+ break
+ //c.Logger().Error(err)
+ }
+ fmt.Printf("{ \"message\": \"%s\" }\n", msg)
+ }
+ return nil
+}
+
+func (h Handlers) GetMetrics(c echo.Context) error {
+ return h.PrometheusHandler(c)
+}
diff --git a/daemon/fortiter/logspec.go b/daemon/fortiter/logspec.go
new file mode 100644
index 00000000..34fdbfce
--- /dev/null
+++ b/daemon/fortiter/logspec.go
@@ -0,0 +1,101 @@
+package fortiter
+
+import (
+ "bufio"
+ "context"
+ "encoding/json"
+ "errors"
+ "github.com/algorand/go-algorand/logging/logspec"
+ "github.com/jmoiron/sqlx"
+ "io"
+ "os"
+ "os/exec"
+ "strings"
+ "time"
+)
+
+func LogFile(filename *string) (io.ReadCloser, error) {
+ var inputStream io.ReadCloser = os.Stdin
+ if *filename == "" {
+ return inputStream, errors.New("no input file specified")
+ }
+ if *filename != "" {
+ f, err := os.Open(*filename)
+ if err != nil {
+ return nil, err
+ }
+ // Close the handle - we just wanted to verify it was valid
+ f.Close()
+ cmd := exec.Command("tail", "-n", "-1000", "-F", *filename)
+ inputStream, err = cmd.StdoutPipe()
+ if err != nil {
+ return nil, err
+ }
+ err = cmd.Start()
+ if err != nil {
+ return nil, err
+ }
+ }
+ return inputStream, nil
+}
+
+func Sync(ctx context.Context, filepath string, db *sqlx.DB) error {
+ stats := make(map[string]Stats)
+
+ go Watch(filepath, func(line string, lm map[string]interface{}, err error) {
+ if lm["Context"] != nil && lm["Context"] == "Agreement" {
+ if lm["Hash"] != nil {
+ var event logspec.AgreementEvent
+ dec := json.NewDecoder(strings.NewReader(line))
+ _ = dec.Decode(&event)
+
+ t, _ := time.Parse(time.RFC3339, lm["time"].(string))
+ err = SaveAgreement(AgreementEvent{
+ AgreementEvent: event,
+ Message: lm["msg"].(string),
+ Time: t,
+ }, db)
+
+ if event.Sender != "" {
+ var stat Stats
+ stat, ok := stats[event.Sender]
+ if !ok {
+ stats[event.Sender] = Stats{
+ Address: event.Sender,
+ Sent: 0,
+ Received: 0,
+ Failed: 0,
+ Success: 0,
+ }
+ stat = stats[event.Sender]
+ } else {
+ stat.Received++
+ }
+ stat.SaveStats(*db)
+ }
+ }
+ }
+ })
+
+ return nil
+}
+
+func Watch(filepath string, cb func(line string, lm map[string]interface{}, err error)) {
+ inputStream, err := LogFile(&filepath)
+ if err != nil {
+ cb("", make(map[string]interface{}), err)
+ }
+ scanner := bufio.NewScanner(inputStream)
+ for scanner.Scan() {
+ line := scanner.Text()
+ var event map[string]interface{}
+ dec := json.NewDecoder(strings.NewReader(line))
+ err := dec.Decode(&event)
+ if err != nil {
+ cb("", event, err)
+ break
+ } else {
+ cb(line, event, nil)
+ }
+ }
+}
diff --git a/daemon/fortiter/schema.go b/daemon/fortiter/schema.go
new file mode 100644
index 00000000..9eebf299
--- /dev/null
+++ b/daemon/fortiter/schema.go
@@ -0,0 +1,20 @@
+package fortiter
+
+var Schema = `
+CREATE TABLE IF NOT EXISTS agreements (
+ type INTEGER,
+ round INTEGER,
+ period INTEGER,
+ step INTEGER,
+ hash TEXT,
+ sender TEXT,
+ object_round INTEGER,
+ object_period INTEGER,
+ object_step INTEGER,
+ weight INTEGER,
+ weight_total INTEGER,
+
+ message TEXT,
+ time INTEGER
+);
+`
diff --git a/daemon/fortiter/stats.go b/daemon/fortiter/stats.go
new file mode 100644
index 00000000..406ceb10
--- /dev/null
+++ b/daemon/fortiter/stats.go
@@ -0,0 +1,41 @@
+package fortiter
+
+import (
+ "fmt"
+ "github.com/jmoiron/sqlx"
+)
+
+var StatsSchema = `
+CREATE TABLE IF NOT EXISTS stats (
+ address TEXT PRIMARY KEY,
+ sent INTEGER,
+ received INTEGER,
+ failed INTEGER,
+ success INTEGER
+)
+`
+
+type Stats struct {
+ Address string
+ Sent uint64
+ Received uint64
+ Failed uint64
+ Success uint64
+}
+
+func (s *Stats) String() string {
+ return fmt.Sprintf("Address: %s\nSent: %d\nReceived: %d\nFailed: %d\nSuccess: %d\n",
+ s.Address, s.Sent, s.Received, s.Failed, s.Success)
+}
+
+func (s *Stats) SaveStats(db sqlx.DB) error {
+ var stats Stats
+ err := db.Get(&stats, "SELECT * FROM stats WHERE address = ?", s.Address)
+ if err != nil {
+ db.MustExec("INSERT INTO stats (address, sent, received, failed, success) VALUES (?, ?, ?, ?, ?)", s.Address, s.Sent, s.Received, s.Failed, s.Success)
+ } else {
+ db.MustExec("UPDATE stats SET sent = ?, received = ?, failed = ?, success = ? WHERE address = ?",
+ s.Sent, s.Received, s.Failed, s.Success, s.Address)
+ }
+ return nil
+}
diff --git a/daemon/generate.yaml b/daemon/generate.yaml
new file mode 100644
index 00000000..6ef41060
--- /dev/null
+++ b/daemon/generate.yaml
@@ -0,0 +1,2 @@
+package: rpc
+output: ./rpc/gen.go
\ No newline at end of file
diff --git a/daemon/main.go b/daemon/main.go
new file mode 100644
index 00000000..ca7cf3e6
--- /dev/null
+++ b/daemon/main.go
@@ -0,0 +1,19 @@
+package main
+
+import (
+ "fmt"
+ "github.com/algorandfoundation/algorun-tui/daemon/cmd"
+)
+
+var version = "development"
+
+// main initializes the Echo framework, hides its default startup banner, prints a custom BANNER,
+// registers the HTTP handlers, starts the algod process, and begins listening for HTTP requests on port 1323.
+func main() {
+ fmt.Println("Algorun TUI")
+ fmt.Println("Version:", version)
+ err := cmd.Execute()
+ if err != nil {
+ return
+ }
+}
diff --git a/daemon/migrations/.gitkeep b/daemon/migrations/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/daemon/oas3.schema.yaml b/daemon/oas3.schema.yaml
new file mode 100644
index 00000000..a4d9d35d
--- /dev/null
+++ b/daemon/oas3.schema.yaml
@@ -0,0 +1,86 @@
+openapi: 3.0.1
+info:
+ contact:
+ name: Algonode.io
+ url: https://algonode.io/contact
+ description: API endpoint for algod operations.
+ title: Algod REST API.
+ version: '3.16'
+servers:
+ - url: http://localhost:1337/
+ - url: https://mainnet-api.algonode.cloud/
+ - url: https://testnet-api.algonode.cloud/
+ - url: https://betanet-api.algonode.cloud/
+paths:
+ /metrics:
+ get:
+ operationId: getMetrics
+ responses:
+ '200':
+ content:
+ application/text:
+ schema:
+ type: string
+ description: Prometheus Exposition Endpoint
+ /agreement/{hash}:
+ get:
+ operationId: getAgreementEvents
+ parameters:
+ - name: hash
+ in: path
+ description: 'Hash to lookup'
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ type: string
+ description: Get Agreement events by Hash
+ /ws:
+ get:
+ operationId: getWs
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ type: string
+ description: Stuff
+ /status:
+ get:
+ operationId: getStatus
+ summary: Retrieve current status
+ responses:
+ '200':
+ description: Respond with Status
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/Status"
+components:
+ schemas:
+ Status:
+ type: object
+ description: A status response
+ properties:
+ state:
+ type: string
+ description: The state of the node
+ version:
+ type: string
+ description: Version reported by the node
+ network:
+ type: string
+ description: Network ID
+ voting:
+ type: boolean
+ description: If the network is voting on an upgrade
+ needsUpdate:
+ type: boolean
+ description: If the node requires and update
+ lastRound:
+ type: number
+ description: Last round the status has knowledge of
\ No newline at end of file
diff --git a/daemon/public/favicon.ico b/daemon/public/favicon.ico
new file mode 100644
index 00000000..a8b07957
Binary files /dev/null and b/daemon/public/favicon.ico differ
diff --git a/daemon/public/index.html b/daemon/public/index.html
new file mode 100644
index 00000000..e9901162
--- /dev/null
+++ b/daemon/public/index.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+ WebSocket
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/daemon/rpc/gen.go b/daemon/rpc/gen.go
new file mode 100644
index 00000000..3534699e
--- /dev/null
+++ b/daemon/rpc/gen.go
@@ -0,0 +1,228 @@
+// Package rpc provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/deepmap/oapi-codegen/v2 version v2.2.0 DO NOT EDIT.
+package rpc
+
+import (
+ "bytes"
+ "compress/gzip"
+ "encoding/base64"
+ "fmt"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/labstack/echo/v4"
+ "github.com/oapi-codegen/runtime"
+)
+
+// Status A status response
+type Status struct {
+ // LastRound Last round the status has knowledge of
+ LastRound *float32 `json:"lastRound,omitempty"`
+
+ // NeedsUpdate If the node requires and update
+ NeedsUpdate *bool `json:"needsUpdate,omitempty"`
+
+ // Network Network ID
+ Network *string `json:"network,omitempty"`
+
+ // State The state of the node
+ State *string `json:"state,omitempty"`
+
+ // Version Version reported by the node
+ Version *string `json:"version,omitempty"`
+
+ // Voting If the network is voting on an upgrade
+ Voting *bool `json:"voting,omitempty"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /agreement/{hash})
+ GetAgreementEvents(ctx echo.Context, hash string) error
+
+ // (GET /metrics)
+ GetMetrics(ctx echo.Context) error
+ // Retrieve current status
+ // (GET /status)
+ GetStatus(ctx echo.Context) error
+
+ // (GET /ws)
+ GetWs(ctx echo.Context) error
+}
+
+// ServerInterfaceWrapper converts echo contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+}
+
+// GetAgreementEvents converts echo context to params.
+func (w *ServerInterfaceWrapper) GetAgreementEvents(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "hash" -------------
+ var hash string
+
+ err = runtime.BindStyledParameterWithOptions("simple", "hash", ctx.Param("hash"), &hash, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter hash: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetAgreementEvents(ctx, hash)
+ return err
+}
+
+// GetMetrics converts echo context to params.
+func (w *ServerInterfaceWrapper) GetMetrics(ctx echo.Context) error {
+ var err error
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetMetrics(ctx)
+ return err
+}
+
+// GetStatus converts echo context to params.
+func (w *ServerInterfaceWrapper) GetStatus(ctx echo.Context) error {
+ var err error
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetStatus(ctx)
+ return err
+}
+
+// GetWs converts echo context to params.
+func (w *ServerInterfaceWrapper) GetWs(ctx echo.Context) error {
+ var err error
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetWs(ctx)
+ return err
+}
+
+// This is a simple interface which specifies echo.Route addition functions which
+// are present on both echo.Echo and echo.Group, since we want to allow using
+// either of them for path registration
+type EchoRouter interface {
+ CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+}
+
+// RegisterHandlers adds each server route to the EchoRouter.
+func RegisterHandlers(router EchoRouter, si ServerInterface) {
+ RegisterHandlersWithBaseURL(router, si, "")
+}
+
+// Registers handlers, and prepends BaseURL to the paths, so that the paths
+// can be served under a prefix.
+func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ }
+
+ router.GET(baseURL+"/agreement/:hash", wrapper.GetAgreementEvents)
+ router.GET(baseURL+"/metrics", wrapper.GetMetrics)
+ router.GET(baseURL+"/status", wrapper.GetStatus)
+ router.GET(baseURL+"/ws", wrapper.GetWs)
+
+}
+
+// Base64 encoded, gzipped, json marshaled Swagger object
+var swaggerSpec = []string{
+
+ "H4sIAAAAAAAC/6RUXW/bOgz9KwTvffSN21vgXsBvARZ0AbahaLvtYeiDYjGxWlvUJDppEfi/D1JsB8hH",
+ "t6Jvgnh4eHhEcYslN44tWQlYbDGUFTUqHe9ESZtOmkLpjRPDFgucQkgR8BQc20CYofPsyIuhhK9VkFtu",
+ "rT5O/qSCgI8xkIoGpkoFeLK8qUmvCHiJGcqLIyzQts2CPHYZWiIdvjqthI5p58tEZ1kTePrZGk8BlNXQ",
+ "7hJGvgVzTcruCGXD/umY7MsuAPMP+7wg3thVTIuSTyi477uJ8kctp/LX5ENKOWT4tguAJ8deSMPi5XUi",
+ "lng660XfhQmwQwJbUBZat/JKn7KkG6948UilYBevjF1yLFKyFVVKPFrVRNS0XnEUNzGMGba+xgIrEReK",
+ "PFf7WD5kdtnhJN3Mgax2bKzAkj3ELA1xlFSEhElUaaQeqmm4nd3dw/RmHiOjk3g1ufwv0rMjq5xJNxeT",
+ "yziYSqo0k7laeaKGrOTbSoWqi5crSv2MBecaC7wmmQ7Y2Tp9jMjjVUNCPmDx49DxjypUIAw181PrMHqG",
+ "RSqN2WBWrIkZ9sOpsRDfUtb/tyji4H27hwjefbDUwL8XF8MzkE2ylXO1KZPw/DHsRuo835H71yQwNgqU",
+ "Oo0zF7uJ+C7DvCHxpgyvefW5h7xJrtCzvFHujeeGpKI2wOzZcTDxHmb9+AyCw7i0zunt19o73f3b0xIL",
+ "/Cvfr8+83515X+FED7eppIaNkQpGWIahbRrlXxJCvKE1Qdl6H98l7FH55tXGvr+7qd++wZ20y2WyOoom",
+ "vx7+w/7zF3lec6nqioMUl1dX/+fYZduD7dAoYy3JP8qZybgpyppbfQotFOTP0QsSdRb90P0KAAD//34V",
+ "Tl3xBgAA",
+}
+
+// GetSwagger returns the content of the embedded swagger specification file
+// or error if failed to decode
+func decodeSpec() ([]byte, error) {
+ zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr, err := gzip.NewReader(bytes.NewReader(zipped))
+ if err != nil {
+ return nil, fmt.Errorf("error decompressing spec: %w", err)
+ }
+ var buf bytes.Buffer
+ _, err = buf.ReadFrom(zr)
+ if err != nil {
+ return nil, fmt.Errorf("error decompressing spec: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cached of a decoded swagger spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSwagger returns the Swagger specification corresponding to the generated code
+// in this file. The external references of Swagger specification are resolved.
+// The logic of resolving external references is tightly connected to "import-mapping" feature.
+// Externally referenced files must be embedded in the corresponding golang packages.
+// Urls can be supported but this task was out of the scope.
+func GetSwagger() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
diff --git a/go.mod b/go.mod
index 7134e0ea..1c2f7342 100644
--- a/go.mod
+++ b/go.mod
@@ -1,17 +1,24 @@
module github.com/algorandfoundation/algorun-tui
-go 1.22.0
+go 1.23
-toolchain go1.23.1
+toolchain go1.23.3
require (
+ github.com/algorand/go-algorand v0.0.0-20241210191903-f87ae8a83df0
github.com/algorandfoundation/algourl v0.0.0-20241023193235-8bbf72ad0b37
github.com/charmbracelet/bubbles v0.20.0
github.com/charmbracelet/bubbletea v1.1.1
github.com/charmbracelet/lipgloss v0.13.1
github.com/charmbracelet/log v0.4.0
github.com/charmbracelet/x/exp/teatest v0.0.0-20241022174419-46d9bb99a691
+ github.com/getkin/kin-openapi v0.127.0
+ github.com/gorilla/websocket v1.5.3
+ github.com/jmoiron/sqlx v1.4.0
+ github.com/labstack/echo-contrib v0.17.1
+ github.com/labstack/echo/v4 v4.12.0
github.com/manifoldco/promptui v0.9.0
+ github.com/mattn/go-sqlite3 v1.14.24
github.com/oapi-codegen/oapi-codegen/v2 v2.4.1
github.com/oapi-codegen/runtime v1.1.1
github.com/spf13/cobra v1.8.1
@@ -20,10 +27,42 @@ require (
)
require (
+ github.com/algorand/go-deadlock v0.2.4 // indirect
+ github.com/algorand/msgp v1.1.60 // indirect
+ github.com/beorn7/perks v1.0.1 // indirect
+ github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
+ github.com/go-openapi/jsonpointer v0.21.0 // indirect
+ github.com/go-openapi/swag v0.23.0 // indirect
+ github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
+ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
+ github.com/google/go-cmp v0.6.0 // indirect
+ github.com/invopop/yaml v0.3.1 // indirect
+ github.com/josharian/intern v1.0.0 // indirect
+ github.com/josharian/native v1.1.0 // indirect
+ github.com/jsimonetti/rtnetlink v1.4.2 // indirect
+ github.com/klauspost/compress v1.17.11 // indirect
+ github.com/labstack/gommon v0.4.2 // indirect
+ github.com/mailru/easyjson v0.7.7 // indirect
+ github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/mdlayher/netlink v1.7.2 // indirect
+ github.com/mdlayher/socket v0.4.1 // indirect
+ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
+ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
+ github.com/perimeterx/marshmallow v1.1.5 // indirect
+ github.com/petermattis/goid v0.0.0-20241025130422-66cb2e6d7274 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
- gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
+ github.com/prometheus/client_golang v1.20.5 // indirect
+ github.com/prometheus/client_model v0.6.1 // indirect
+ github.com/prometheus/common v0.60.0 // indirect
+ github.com/prometheus/procfs v0.15.1 // indirect
+ github.com/valyala/bytebufferpool v1.0.0 // indirect
+ github.com/valyala/fasttemplate v1.2.2 // indirect
+ go.opencensus.io v0.24.0 // indirect
+ golang.org/x/net v0.30.0 // indirect
+ golang.org/x/time v0.5.0 // indirect
+ google.golang.org/protobuf v1.35.1 // indirect
)
require (
@@ -64,11 +103,11 @@ require (
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
- golang.org/x/crypto v0.28.0 // indirect
- golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
- golang.org/x/sync v0.8.0 // indirect
- golang.org/x/sys v0.26.0 // indirect
- golang.org/x/text v0.19.0 // indirect
+ golang.org/x/crypto v0.29.0 // indirect
+ golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect
+ golang.org/x/sync v0.9.0 // indirect
+ golang.org/x/sys v0.27.0 // indirect
+ golang.org/x/text v0.20.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/go.sum b/go.sum
index 0b57cc4a..d3209058 100644
--- a/go.sum
+++ b/go.sum
@@ -1,8 +1,18 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
+filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
+github.com/algorand/go-algorand v0.0.0-20241210191903-f87ae8a83df0 h1:BhP29Vz4Mc+vBaKvGmFJXOPd6r9BMf8vDFC9vXD0CoY=
+github.com/algorand/go-algorand v0.0.0-20241210191903-f87ae8a83df0/go.mod h1:TkqTtafNw3U8TLpRUdGNwgptFY7lJ+R5t5CfT90r81Q=
github.com/algorand/go-algorand-sdk/v2 v2.6.0 h1:pfL8lloEi26l6PwAFicmPUguWgKpy1eZZTMlQcci5h0=
github.com/algorand/go-algorand-sdk/v2 v2.6.0/go.mod h1:4ayerzjoWChm3kuVhbgFgURTbaYTtlj0c41eP3av5lw=
github.com/algorand/go-codec/codec v1.1.10 h1:zmWYU1cp64jQVTOG8Tw8wa+k0VfwgXIPbnDfiVa+5QA=
github.com/algorand/go-codec/codec v1.1.10/go.mod h1:YkEx5nmr/zuCeaDYOIhlDg92Lxju8tj2d2NrYqP7g7k=
+github.com/algorand/go-deadlock v0.2.4 h1:UMs6GwE2wHC6BUZo5z32/+SrBey1LQjbkZQ3V7DoGVA=
+github.com/algorand/go-deadlock v0.2.4/go.mod h1:tewhAviZpVq2cnGHmfT50l6RwWLnuygnfNntCN2fz0M=
+github.com/algorand/msgp v1.1.60 h1:+IVUC34+tSj1P2M1mkYtl4GLyfzdzXfBLSw6TDT19M8=
+github.com/algorand/msgp v1.1.60/go.mod h1:RqZQBzAFDWpwh5TlabzZkWy+6kwL9cvXfLbU0gD99EA=
github.com/algorandfoundation/algourl v0.0.0-20241023193235-8bbf72ad0b37 h1:zt00SDlTcFiYPvq+Wo/ZDmRwM2gBRW/VhOQ/zaplBAk=
github.com/algorandfoundation/algourl v0.0.0-20241023193235-8bbf72ad0b37/go.mod h1:o91gtX3JDwJpS10P5cm6dwUsArtNtX+3kDshhelHTJ8=
github.com/algorandfoundation/go-tinyqr v0.0.0-20241018103413-2082a3d637eb h1:NFKjd5BKatUpYUXiofxvWd0VqVoinsVzugtQw/W+vKs=
@@ -11,11 +21,18 @@ github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7D
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
+github.com/aws/aws-sdk-go v1.34.0 h1:brux2dRrlwCF5JhTL7MUT3WUwo9zfDHZZp3+g3Mvlmo=
+github.com/aws/aws-sdk-go v1.34.0/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
+github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE=
github.com/charmbracelet/bubbles v0.20.0/go.mod h1:39slydyswPy+uVOHZ5x/GjwVAFkCsV8IIVy+4MhzwwU=
github.com/charmbracelet/bubbletea v1.1.1 h1:KJ2/DnmpfqFtDNVTvYZ6zpPFL9iRCRr0qqKOCvppbPY=
@@ -38,67 +55,160 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5O
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/cilium/ebpf v0.12.3 h1:8ht6F9MquybnY97at+VDZb3eQQr8ev79RueWeVaEcG4=
+github.com/cilium/ebpf v0.12.3/go.mod h1:TctK1ivibvI3znr66ljgi4hqOT8EYQjz1KWBfb1UVgM=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
+github.com/getkin/kin-openapi v0.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY=
+github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM=
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
+github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
+github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
+github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
+github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
+github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
+github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
+github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
+github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
+github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
+github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
+github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso=
+github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA=
+github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=
+github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
+github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
+github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
+github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
+github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
+github.com/jsimonetti/rtnetlink v1.4.2 h1:Df9w9TZ3npHTyDn0Ev9e1uzmN2odmXd0QX+J5GTEn90=
+github.com/jsimonetti/rtnetlink v1.4.2/go.mod h1:92s6LJdE+1iOrw+F2/RO7LYI2Qd8pPpFNNUYW06gcoM=
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
-github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
+github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
+github.com/labstack/echo-contrib v0.17.1 h1:7I/he7ylVKsDUieaGRZ9XxxTYOjfQwVzHzUYrNykfCU=
+github.com/labstack/echo-contrib v0.17.1/go.mod h1:SnsCZtwHBAZm5uBSAtQtXQHI3wqEA73hvTn0bYMKnZA=
+github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0=
+github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM=
+github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
+github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
+github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
+github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
+github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
+github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
+github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
+github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
+github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
+github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a h1:2MaM6YC3mGu54x+RKAA6JiFFHlHDY1UbkxqppT7wYOg=
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a/go.mod h1:hxSnBBYLK21Vtq/PHd0S2FYCxBXzBua8ov5s1RobyRQ=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/oapi-codegen/oapi-codegen/v2 v2.4.1 h1:ykgG34472DWey7TSjd8vIfNykXgjOgYJZoQbKfEeY/Q=
github.com/oapi-codegen/oapi-codegen/v2 v2.4.1/go.mod h1:N5+lY1tiTDV3V1BeHtOxeWXHoPVeApvsvjJqegfoaz8=
github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro=
github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
+github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
+github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
+github.com/petermattis/goid v0.0.0-20241025130422-66cb2e6d7274 h1:qli3BGQK0tYDkSEvZ/FzZTi9ZrOX86Q6CIhKLGc489A=
+github.com/petermattis/goid v0.0.0-20241025130422-66cb2e6d7274/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
+github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
+github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
+github.com/prometheus/common v0.60.0 h1:+V9PAREWNvJMAuJ1x1BaWl9dewMW4YrHZQbx0sJNllA=
+github.com/prometheus/common v0.60.0/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
+github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
+github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
@@ -123,56 +233,121 @@ github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
+github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
+github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
+github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
+github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
+github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
+github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
+go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
-golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
-golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
-golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
+golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
+golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
+golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
+golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
-golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
+golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
-golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
+golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
-golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
+golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
+golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
+golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
+google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+pgregory.net/rapid v0.6.2 h1:ErW5sL+UKtfBfUTsWHDCoeB+eZKLKMxrSd1VJY6W4bw=
+pgregory.net/rapid v0.6.2/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
diff --git a/internal/README.md b/internal/nodekit/README.md
similarity index 100%
rename from internal/README.md
rename to internal/nodekit/README.md
diff --git a/internal/accounts.go b/internal/nodekit/accounts.go
similarity index 99%
rename from internal/accounts.go
rename to internal/nodekit/accounts.go
index 28d815fe..1dacee91 100644
--- a/internal/accounts.go
+++ b/internal/nodekit/accounts.go
@@ -1,4 +1,4 @@
-package internal
+package nodekit
import (
"bytes"
diff --git a/internal/accounts_test.go b/internal/nodekit/accounts_test.go
similarity index 99%
rename from internal/accounts_test.go
rename to internal/nodekit/accounts_test.go
index e1f23e82..0f04210a 100644
--- a/internal/accounts_test.go
+++ b/internal/nodekit/accounts_test.go
@@ -1,4 +1,4 @@
-package internal
+package nodekit
import (
"context"
diff --git a/internal/block.go b/internal/nodekit/block.go
similarity index 98%
rename from internal/block.go
rename to internal/nodekit/block.go
index 8ca8d54e..2d4794b1 100644
--- a/internal/block.go
+++ b/internal/nodekit/block.go
@@ -1,4 +1,4 @@
-package internal
+package nodekit
import (
"context"
diff --git a/internal/block_test.go b/internal/nodekit/block_test.go
similarity index 97%
rename from internal/block_test.go
rename to internal/nodekit/block_test.go
index 5b39feed..fadacfa0 100644
--- a/internal/block_test.go
+++ b/internal/nodekit/block_test.go
@@ -1,4 +1,4 @@
-package internal
+package nodekit
import (
"context"
diff --git a/internal/github.go b/internal/nodekit/github.go
similarity index 97%
rename from internal/github.go
rename to internal/nodekit/github.go
index 87abc699..1fd56302 100644
--- a/internal/github.go
+++ b/internal/nodekit/github.go
@@ -1,4 +1,4 @@
-package internal
+package nodekit
import (
"encoding/json"
diff --git a/internal/github_test.go b/internal/nodekit/github_test.go
similarity index 98%
rename from internal/github_test.go
rename to internal/nodekit/github_test.go
index 8b0b1d40..91c4fa32 100644
--- a/internal/github_test.go
+++ b/internal/nodekit/github_test.go
@@ -1,4 +1,4 @@
-package internal
+package nodekit
import (
"bytes"
diff --git a/internal/http.go b/internal/nodekit/http.go
similarity index 93%
rename from internal/http.go
rename to internal/nodekit/http.go
index 9f2fc57f..f27f3aaa 100644
--- a/internal/http.go
+++ b/internal/nodekit/http.go
@@ -1,4 +1,4 @@
-package internal
+package nodekit
import "net/http"
diff --git a/internal/metrics.go b/internal/nodekit/metrics.go
similarity index 98%
rename from internal/metrics.go
rename to internal/nodekit/metrics.go
index c3bd98b0..54928ade 100644
--- a/internal/metrics.go
+++ b/internal/nodekit/metrics.go
@@ -1,4 +1,4 @@
-package internal
+package nodekit
import (
"context"
diff --git a/internal/metrics_test.go b/internal/nodekit/metrics_test.go
similarity index 99%
rename from internal/metrics_test.go
rename to internal/nodekit/metrics_test.go
index 7cf091d9..383215cf 100644
--- a/internal/metrics_test.go
+++ b/internal/nodekit/metrics_test.go
@@ -1,4 +1,4 @@
-package internal
+package nodekit
import (
"context"
diff --git a/internal/participation.go b/internal/nodekit/participation.go
similarity index 99%
rename from internal/participation.go
rename to internal/nodekit/participation.go
index 55b0594d..62ca7de3 100644
--- a/internal/participation.go
+++ b/internal/nodekit/participation.go
@@ -1,4 +1,4 @@
-package internal
+package nodekit
import (
"context"
diff --git a/internal/participation_test.go b/internal/nodekit/participation_test.go
similarity index 99%
rename from internal/participation_test.go
rename to internal/nodekit/participation_test.go
index 55bac2d0..cca4727e 100644
--- a/internal/participation_test.go
+++ b/internal/nodekit/participation_test.go
@@ -1,4 +1,4 @@
-package internal
+package nodekit
import (
"context"
diff --git a/internal/rangetype.go b/internal/nodekit/rangetype.go
similarity index 85%
rename from internal/rangetype.go
rename to internal/nodekit/rangetype.go
index 10e8497f..7f704ad2 100644
--- a/internal/rangetype.go
+++ b/internal/nodekit/rangetype.go
@@ -1,4 +1,4 @@
-package internal
+package nodekit
type RangeType string
diff --git a/internal/state.go b/internal/nodekit/state.go
similarity index 99%
rename from internal/state.go
rename to internal/nodekit/state.go
index 0db012b3..2b44a4c5 100644
--- a/internal/state.go
+++ b/internal/nodekit/state.go
@@ -1,4 +1,4 @@
-package internal
+package nodekit
import (
"context"
diff --git a/internal/state_test.go b/internal/nodekit/state_test.go
similarity index 98%
rename from internal/state_test.go
rename to internal/nodekit/state_test.go
index a3f19e45..dad50b77 100644
--- a/internal/state_test.go
+++ b/internal/nodekit/state_test.go
@@ -1,4 +1,4 @@
-package internal
+package nodekit
import (
"context"
diff --git a/internal/status.go b/internal/nodekit/status.go
similarity index 99%
rename from internal/status.go
rename to internal/nodekit/status.go
index adb2c25a..3732c651 100644
--- a/internal/status.go
+++ b/internal/nodekit/status.go
@@ -1,4 +1,4 @@
-package internal
+package nodekit
import (
"context"
diff --git a/internal/status_test.go b/internal/nodekit/status_test.go
similarity index 98%
rename from internal/status_test.go
rename to internal/nodekit/status_test.go
index e8d969bd..0a5faac1 100644
--- a/internal/status_test.go
+++ b/internal/nodekit/status_test.go
@@ -1,4 +1,4 @@
-package internal
+package nodekit
import (
"context"
diff --git a/internal/time.go b/internal/nodekit/time.go
similarity index 88%
rename from internal/time.go
rename to internal/nodekit/time.go
index eb3fa8fb..6e862cbc 100644
--- a/internal/time.go
+++ b/internal/nodekit/time.go
@@ -1,4 +1,4 @@
-package internal
+package nodekit
import "time"
diff --git a/ui/app/accounts.go b/ui/app/accounts.go
index 1287fac4..0761c048 100644
--- a/ui/app/accounts.go
+++ b/ui/app/accounts.go
@@ -1,14 +1,14 @@
package app
import (
- "github.com/algorandfoundation/algorun-tui/internal"
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
tea "github.com/charmbracelet/bubbletea"
)
-type AccountSelected internal.Account
+type AccountSelected nodekit.Account
// EmitAccountSelected waits for and retrieves a new set of table rows from a given channel.
-func EmitAccountSelected(account internal.Account) tea.Cmd {
+func EmitAccountSelected(account nodekit.Account) tea.Cmd {
return func() tea.Msg {
return AccountSelected(account)
}
diff --git a/ui/app/app_test.go b/ui/app/app_test.go
index 90ce2deb..e1096c16 100644
--- a/ui/app/app_test.go
+++ b/ui/app/app_test.go
@@ -2,7 +2,7 @@ package app
import (
"context"
- "github.com/algorandfoundation/algorun-tui/internal"
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
"github.com/algorandfoundation/algorun-tui/internal/test"
uitest "github.com/algorandfoundation/algorun-tui/ui/internal/test"
"testing"
@@ -11,7 +11,7 @@ import (
func Test_GenerateCmd(t *testing.T) {
client := test.GetClient(false)
- fn := GenerateCmd("ABC", internal.TimeRange, int(time.Second*60), uitest.GetState(client))
+ fn := GenerateCmd("ABC", nodekit.TimeRange, int(time.Second*60), uitest.GetState(client))
res := fn()
evt, ok := res.(ModalEvent)
if !ok {
@@ -22,7 +22,7 @@ func Test_GenerateCmd(t *testing.T) {
}
client = test.GetClient(true)
- fn = GenerateCmd("ABC", internal.TimeRange, int(time.Second*60), uitest.GetState(client))
+ fn = GenerateCmd("ABC", nodekit.TimeRange, int(time.Second*60), uitest.GetState(client))
res = fn()
evt, ok = res.(ModalEvent)
if !ok {
diff --git a/ui/app/keys.go b/ui/app/keys.go
index f5eb4ead..7d73b721 100644
--- a/ui/app/keys.go
+++ b/ui/app/keys.go
@@ -2,10 +2,10 @@ package app
import (
"context"
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
"time"
"github.com/algorandfoundation/algorun-tui/api"
- "github.com/algorandfoundation/algorun-tui/internal"
tea "github.com/charmbracelet/bubbletea"
)
@@ -18,7 +18,7 @@ type DeleteKey *api.ParticipationKey
func EmitDeleteKey(ctx context.Context, client api.ClientWithResponsesInterface, id string) tea.Cmd {
return func() tea.Msg {
- err := internal.DeletePartKey(ctx, client, id)
+ err := nodekit.DeletePartKey(ctx, client, id)
if err != nil {
return DeleteFinished{
Err: &err,
@@ -32,11 +32,11 @@ func EmitDeleteKey(ctx context.Context, client api.ClientWithResponsesInterface,
}
}
-func GenerateCmd(account string, rangeType internal.RangeType, duration int, state *internal.StateModel) tea.Cmd {
+func GenerateCmd(account string, rangeType nodekit.RangeType, duration int, state *nodekit.StateModel) tea.Cmd {
return func() tea.Msg {
var params api.GenerateParticipationKeysParams
- if rangeType == internal.TimeRange {
+ if rangeType == nodekit.TimeRange {
params = api.GenerateParticipationKeysParams{
Dilution: nil,
First: int(state.Status.LastRound),
@@ -50,7 +50,7 @@ func GenerateCmd(account string, rangeType internal.RangeType, duration int, sta
}
}
- key, err := internal.GenerateKeyPair(state.Context, state.Client, account, ¶ms)
+ key, err := nodekit.GenerateKeyPair(state.Context, state.Client, account, ¶ms)
if err != nil {
return ModalEvent{
Key: nil,
diff --git a/ui/internal/test/state.go b/ui/internal/test/state.go
index 3f159e95..f6536828 100644
--- a/ui/internal/test/state.go
+++ b/ui/internal/test/state.go
@@ -3,22 +3,22 @@ package test
import (
"context"
"github.com/algorandfoundation/algorun-tui/api"
- "github.com/algorandfoundation/algorun-tui/internal"
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
mock2 "github.com/algorandfoundation/algorun-tui/internal/test/mock"
"time"
)
-func GetState(client api.ClientWithResponsesInterface) *internal.StateModel {
- sm := &internal.StateModel{
- Status: internal.StatusModel{
- State: internal.StableState,
+func GetState(client api.ClientWithResponsesInterface) *nodekit.StateModel {
+ sm := &nodekit.StateModel{
+ Status: nodekit.StatusModel{
+ State: nodekit.StableState,
Version: "v-test",
Network: "v-test-network",
Voting: false,
NeedsUpdate: false,
LastRound: 0,
},
- Metrics: internal.MetricsModel{
+ Metrics: nodekit.MetricsModel{
Enabled: true,
Window: 100,
RoundTime: time.Second * 2,
@@ -36,11 +36,11 @@ func GetState(client api.ClientWithResponsesInterface) *internal.StateModel {
Client: client,
Context: context.Background(),
}
- values := make(map[string]internal.Account)
+ values := make(map[string]nodekit.Account)
for _, key := range *sm.ParticipationKeys {
val, ok := values[key.Address]
if !ok {
- values[key.Address] = internal.Account{
+ values[key.Address] = nodekit.Account{
Address: key.Address,
Status: "Offline",
Balance: 0,
diff --git a/ui/modal/controller.go b/ui/modal/controller.go
index 06a698ed..d8eb14d2 100644
--- a/ui/modal/controller.go
+++ b/ui/modal/controller.go
@@ -1,7 +1,7 @@
package modal
import (
- "github.com/algorandfoundation/algorun-tui/internal"
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
"github.com/algorandfoundation/algorun-tui/ui/app"
"github.com/algorandfoundation/algorun-tui/ui/modals/generate"
"github.com/algorandfoundation/algorun-tui/ui/style"
@@ -28,7 +28,7 @@ func (m ViewModel) HandleMessage(msg tea.Msg) (*ViewModel, tea.Cmd) {
m.Open = true
m.exceptionModal.Message = msg.Error()
m.SetType(app.ExceptionModal)
- case internal.StateModel:
+ case nodekit.StateModel:
m.State = &msg
m.transactionModal.State = &msg
m.infoModal.State = &msg
diff --git a/ui/modal/model.go b/ui/modal/model.go
index b720886d..d48a5d3e 100644
--- a/ui/modal/model.go
+++ b/ui/modal/model.go
@@ -2,7 +2,7 @@ package modal
import (
"github.com/algorandfoundation/algorun-tui/api"
- "github.com/algorandfoundation/algorun-tui/internal"
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
"github.com/algorandfoundation/algorun-tui/ui/app"
"github.com/algorandfoundation/algorun-tui/ui/modals/confirm"
"github.com/algorandfoundation/algorun-tui/ui/modals/exception"
@@ -22,7 +22,7 @@ type ViewModel struct {
Height int
// State for Context/Client
- State *internal.StateModel
+ State *nodekit.StateModel
// Address defines the string format address of the entity
Address string
@@ -82,7 +82,7 @@ func (m *ViewModel) SetType(modal app.ModalType) {
}
}
-func New(parent string, open bool, state *internal.StateModel) *ViewModel {
+func New(parent string, open bool, state *nodekit.StateModel) *ViewModel {
return &ViewModel{
Parent: parent,
Open: open,
diff --git a/ui/modals/confirm/confirm.go b/ui/modals/confirm/confirm.go
index 62b016f5..71b41128 100644
--- a/ui/modals/confirm/confirm.go
+++ b/ui/modals/confirm/confirm.go
@@ -2,7 +2,7 @@ package confirm
import (
"github.com/algorandfoundation/algorun-tui/api"
- "github.com/algorandfoundation/algorun-tui/internal"
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
"github.com/algorandfoundation/algorun-tui/ui/app"
"github.com/algorandfoundation/algorun-tui/ui/style"
tea "github.com/charmbracelet/bubbletea"
@@ -16,10 +16,10 @@ type ViewModel struct {
Controls string
BorderColor string
ActiveKey *api.ParticipationKey
- Data *internal.StateModel
+ Data *nodekit.StateModel
}
-func New(state *internal.StateModel) *ViewModel {
+func New(state *nodekit.StateModel) *ViewModel {
return &ViewModel{
Width: 0,
Height: 0,
diff --git a/ui/modals/generate/controller.go b/ui/modals/generate/controller.go
index 2df09791..72ddf84e 100644
--- a/ui/modals/generate/controller.go
+++ b/ui/modals/generate/controller.go
@@ -1,10 +1,10 @@
package generate
import (
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
"strconv"
"time"
- "github.com/algorandfoundation/algorun-tui/internal"
"github.com/algorandfoundation/algorun-tui/ui/app"
"github.com/charmbracelet/bubbles/spinner"
"github.com/charmbracelet/bubbles/textinput"
@@ -76,7 +76,7 @@ func (m ViewModel) HandleMessage(msg tea.Msg) (*ViewModel, tea.Cmd) {
switch m.Step {
case AddressStep:
addr := m.Input.Value()
- if !internal.ValidateAddress(addr) {
+ if !nodekit.ValidateAddress(addr) {
m.InputError = "Error: invalid address"
return &m, nil
}
@@ -91,18 +91,18 @@ func (m ViewModel) HandleMessage(msg tea.Msg) (*ViewModel, tea.Cmd) {
}
m.InputTwoError = ""
m.SetStep(WaitingStep)
- var rangeType internal.RangeType
+ var rangeType nodekit.RangeType
var dur int
switch m.Range {
case Day:
dur = int(time.Hour*24) * val
- rangeType = internal.TimeRange
+ rangeType = nodekit.TimeRange
case Month:
dur = int(time.Hour*24*30) * val
- rangeType = internal.TimeRange
+ rangeType = nodekit.TimeRange
case Round:
dur = val
- rangeType = internal.RoundRange
+ rangeType = nodekit.RoundRange
}
return &m, tea.Sequence(app.EmitShowModal(app.GenerateModal), app.GenerateCmd(m.Input.Value(), rangeType, dur, m.State))
diff --git a/ui/modals/generate/model.go b/ui/modals/generate/model.go
index 3abf78f2..5bc2beb1 100644
--- a/ui/modals/generate/model.go
+++ b/ui/modals/generate/model.go
@@ -1,7 +1,7 @@
package generate
import (
- "github.com/algorandfoundation/algorun-tui/internal"
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
"github.com/charmbracelet/bubbles/cursor"
"github.com/charmbracelet/bubbles/spinner"
"github.com/charmbracelet/bubbles/textinput"
@@ -40,7 +40,7 @@ type ViewModel struct {
Controls string
BorderColor string
- State *internal.StateModel
+ State *nodekit.StateModel
cursorMode cursor.Mode
}
@@ -53,7 +53,7 @@ var DefaultControls = "( esc to cancel )"
var DefaultTitle = "Generate Consensus Participation Keys"
var DefaultBorderColor = "2"
-func New(address string, state *internal.StateModel) *ViewModel {
+func New(address string, state *nodekit.StateModel) *ViewModel {
input := textinput.New()
input2 := textinput.New()
diff --git a/ui/modals/info/info.go b/ui/modals/info/info.go
index cbe80cec..edf086c4 100644
--- a/ui/modals/info/info.go
+++ b/ui/modals/info/info.go
@@ -2,7 +2,7 @@ package info
import (
"github.com/algorandfoundation/algorun-tui/api"
- "github.com/algorandfoundation/algorun-tui/internal"
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
"github.com/algorandfoundation/algorun-tui/ui/app"
"github.com/algorandfoundation/algorun-tui/ui/style"
"github.com/algorandfoundation/algorun-tui/ui/utils"
@@ -19,10 +19,10 @@ type ViewModel struct {
BorderColor string
Active bool
Participation *api.ParticipationKey
- State *internal.StateModel
+ State *nodekit.StateModel
}
-func New(state *internal.StateModel) *ViewModel {
+func New(state *nodekit.StateModel) *ViewModel {
return &ViewModel{
Width: 0,
Height: 0,
diff --git a/ui/modals/transaction/controller.go b/ui/modals/transaction/controller.go
index 0ff7b1b1..07d1350f 100644
--- a/ui/modals/transaction/controller.go
+++ b/ui/modals/transaction/controller.go
@@ -3,7 +3,7 @@ package transaction
import (
"encoding/base64"
"github.com/algorand/go-algorand-sdk/v2/types"
- "github.com/algorandfoundation/algorun-tui/internal"
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
"github.com/algorandfoundation/algorun-tui/ui/app"
"github.com/algorandfoundation/algourl/encoder"
tea "github.com/charmbracelet/bubbletea"
@@ -43,7 +43,7 @@ func (m ViewModel) HandleMessage(msg tea.Msg) (*ViewModel, tea.Cmd) {
m.UpdateState()
return &m, cmd
}
-func (m *ViewModel) Account() *internal.Account {
+func (m *ViewModel) Account() *nodekit.Account {
if m.Participation == nil || m.State == nil || m.State.Accounts == nil {
return nil
}
diff --git a/ui/modals/transaction/model.go b/ui/modals/transaction/model.go
index dadba88b..cadeae34 100644
--- a/ui/modals/transaction/model.go
+++ b/ui/modals/transaction/model.go
@@ -3,7 +3,7 @@ package transaction
import (
"fmt"
"github.com/algorandfoundation/algorun-tui/api"
- "github.com/algorandfoundation/algorun-tui/internal"
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
"github.com/algorandfoundation/algorun-tui/ui/style"
"github.com/algorandfoundation/algourl/encoder"
)
@@ -21,7 +21,7 @@ type ViewModel struct {
Active bool
// Pointer to the State
- State *internal.StateModel
+ State *nodekit.StateModel
IsOnline bool
// Components
@@ -38,7 +38,7 @@ func (m ViewModel) FormatedAddress() string {
}
// New creates and instance of the ViewModel with a default controls.Model
-func New(state *internal.StateModel) *ViewModel {
+func New(state *nodekit.StateModel) *ViewModel {
return &ViewModel{
State: state,
Title: "Offline Transaction",
diff --git a/ui/modals/transaction/view.go b/ui/modals/transaction/view.go
index b5201a31..2e86f3e8 100644
--- a/ui/modals/transaction/view.go
+++ b/ui/modals/transaction/view.go
@@ -1,7 +1,7 @@
package transaction
import (
- "github.com/algorandfoundation/algorun-tui/internal"
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
"github.com/algorandfoundation/algorun-tui/ui/style"
"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/x/ansi"
@@ -29,7 +29,7 @@ func (m ViewModel) View() string {
}
intro := "Sign this transaction to " + verb + " your account keys:"
- link, _ := internal.ToLoraDeepLink(m.State.Status.Network, m.Active, m.Account().IncentiveEligible, *m.Participation)
+ link, _ := nodekit.ToLoraDeepLink(m.State.Status.Network, m.Active, m.Account().IncentiveEligible, *m.Participation)
loraText := lipgloss.JoinHorizontal(
lipgloss.Bottom,
style.WithHyperlink("Click here", link),
diff --git a/ui/pages/accounts/accounts_test.go b/ui/pages/accounts/accounts_test.go
index 5866a145..bca987f1 100644
--- a/ui/pages/accounts/accounts_test.go
+++ b/ui/pages/accounts/accounts_test.go
@@ -2,7 +2,7 @@ package accounts
import (
"bytes"
- "github.com/algorandfoundation/algorun-tui/internal"
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
"github.com/algorandfoundation/algorun-tui/ui/internal/test"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/x/ansi"
@@ -13,7 +13,7 @@ import (
)
func Test_New(t *testing.T) {
- m := New(&internal.StateModel{})
+ m := New(&nodekit.StateModel{})
acc := m.SelectedAccount()
if acc != nil {
@@ -42,9 +42,9 @@ func Test_New(t *testing.T) {
}
// Update syncing state
- m.Data.Status.State = internal.SyncingState
+ m.Data.Status.State = nodekit.SyncingState
m.makeRows()
- if m.Data.Status.State != internal.SyncingState {
+ if m.Data.Status.State != nodekit.SyncingState {
}
}
diff --git a/ui/pages/accounts/controller.go b/ui/pages/accounts/controller.go
index e879be29..ff618be8 100644
--- a/ui/pages/accounts/controller.go
+++ b/ui/pages/accounts/controller.go
@@ -1,7 +1,7 @@
package accounts
import (
- "github.com/algorandfoundation/algorun-tui/internal"
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
"github.com/algorandfoundation/algorun-tui/ui/app"
"github.com/algorandfoundation/algorun-tui/ui/style"
tea "github.com/charmbracelet/bubbletea"
@@ -18,7 +18,7 @@ func (m ViewModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
func (m ViewModel) HandleMessage(msg tea.Msg) (ViewModel, tea.Cmd) {
switch msg := msg.(type) {
- case internal.StateModel:
+ case nodekit.StateModel:
m.Data = &msg
m.table.SetRows(*m.makeRows())
case tea.KeyMsg:
diff --git a/ui/pages/accounts/model.go b/ui/pages/accounts/model.go
index c565a130..0a6430b0 100644
--- a/ui/pages/accounts/model.go
+++ b/ui/pages/accounts/model.go
@@ -1,18 +1,18 @@
package accounts
import (
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
"github.com/algorandfoundation/algorun-tui/ui/style"
"sort"
"strconv"
"time"
- "github.com/algorandfoundation/algorun-tui/internal"
"github.com/charmbracelet/bubbles/table"
"github.com/charmbracelet/lipgloss"
)
type ViewModel struct {
- Data *internal.StateModel
+ Data *nodekit.StateModel
Title string
Navigation string
@@ -24,7 +24,7 @@ type ViewModel struct {
table table.Model
}
-func New(state *internal.StateModel) ViewModel {
+func New(state *nodekit.StateModel) ViewModel {
m := ViewModel{
Title: "Accounts",
Width: 0,
@@ -54,8 +54,8 @@ func New(state *internal.StateModel) ViewModel {
return m
}
-func (m ViewModel) SelectedAccount() *internal.Account {
- var account *internal.Account
+func (m ViewModel) SelectedAccount() *nodekit.Account {
+ var account *nodekit.Account
var selectedRow = m.table.SelectedRow()
if selectedRow != nil {
selectedAccount := m.Data.Accounts[selectedRow[0]]
@@ -95,7 +95,7 @@ func (m ViewModel) makeRows() *[]table.Row {
}
// Override the state while syncing
- if m.Data.Status.State != internal.StableState {
+ if m.Data.Status.State != nodekit.StableState {
expires = "SYNCING"
}
diff --git a/ui/pages/keys/controller.go b/ui/pages/keys/controller.go
index 1a1f2e6c..9b4365aa 100644
--- a/ui/pages/keys/controller.go
+++ b/ui/pages/keys/controller.go
@@ -1,7 +1,7 @@
package keys
import (
- "github.com/algorandfoundation/algorun-tui/internal"
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
"github.com/algorandfoundation/algorun-tui/ui/app"
"github.com/algorandfoundation/algorun-tui/ui/style"
tea "github.com/charmbracelet/bubbletea"
@@ -19,7 +19,7 @@ func (m ViewModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
func (m ViewModel) HandleMessage(msg tea.Msg) (ViewModel, tea.Cmd) {
switch msg := msg.(type) {
// When the State changes
- case internal.StateModel:
+ case nodekit.StateModel:
m.Data = msg.ParticipationKeys
m.table.SetRows(*m.makeRows(m.Data))
m.Participation = msg.Accounts[m.Address].Participation
@@ -30,7 +30,7 @@ func (m ViewModel) HandleMessage(msg tea.Msg) (ViewModel, tea.Cmd) {
m.table.SetRows(*m.makeRows(m.Data))
// When a confirmation Modal is finished deleting
case app.DeleteFinished:
- internal.RemovePartKeyByID(m.Data, msg.Id)
+ nodekit.RemovePartKeyByID(m.Data, msg.Id)
m.table.SetRows(*m.makeRows(m.Data))
// When the user interacts with the render
case tea.KeyMsg:
diff --git a/ui/pages/keys/model.go b/ui/pages/keys/model.go
index b95bb28e..07764954 100644
--- a/ui/pages/keys/model.go
+++ b/ui/pages/keys/model.go
@@ -1,7 +1,7 @@
package keys
import (
- "github.com/algorandfoundation/algorun-tui/internal"
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
"sort"
"github.com/algorandfoundation/algorun-tui/ui/style"
@@ -127,7 +127,7 @@ func (m ViewModel) makeRows(keys *[]api.ParticipationKey) *[]table.Row {
var activeId *string
if m.Participation != nil {
- activeId = internal.FindParticipationIdForVoteKey(keys, m.Participation.VoteParticipationKey)
+ activeId = nodekit.FindParticipationIdForVoteKey(keys, m.Participation.VoteParticipationKey)
}
for _, key := range *keys {
if key.Address == m.Address {
diff --git a/ui/protocol.go b/ui/protocol.go
index a9e91e59..7a4cd55b 100644
--- a/ui/protocol.go
+++ b/ui/protocol.go
@@ -1,7 +1,7 @@
package ui
import (
- "github.com/algorandfoundation/algorun-tui/internal"
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
"github.com/algorandfoundation/algorun-tui/ui/style"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
@@ -11,7 +11,7 @@ import (
// ProtocolViewModel includes the internal.StatusModel and internal.MetricsModel
type ProtocolViewModel struct {
- Data internal.StatusModel
+ Data nodekit.StatusModel
TerminalWidth int
TerminalHeight int
IsVisible bool
@@ -32,7 +32,7 @@ func (m ProtocolViewModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
func (m ProtocolViewModel) HandleMessage(msg tea.Msg) (ProtocolViewModel, tea.Cmd) {
switch msg := msg.(type) {
// Handle a Status Update
- case internal.StatusModel:
+ case nodekit.StatusModel:
m.Data = msg
return m, nil
// Update Viewport Size
@@ -96,7 +96,7 @@ func (m ProtocolViewModel) View() string {
}
// MakeProtocolViewModel constructs a ProtocolViewModel using a given StatusModel and predefined metrics.
-func MakeProtocolViewModel(state *internal.StateModel) ProtocolViewModel {
+func MakeProtocolViewModel(state *nodekit.StateModel) ProtocolViewModel {
return ProtocolViewModel{
Data: state.Status,
TerminalWidth: 0,
diff --git a/ui/protocol_test.go b/ui/protocol_test.go
index a207be37..930dfe42 100644
--- a/ui/protocol_test.go
+++ b/ui/protocol_test.go
@@ -2,7 +2,7 @@ package ui
import (
"bytes"
- "github.com/algorandfoundation/algorun-tui/internal"
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/x/ansi"
"github.com/charmbracelet/x/exp/golden"
@@ -13,7 +13,7 @@ import (
var protocolViewSnapshots = map[string]ProtocolViewModel{
"Hidden": {
- Data: internal.StatusModel{
+ Data: nodekit.StatusModel{
State: "SYNCING",
Version: "v0.0.0-test",
Network: "test-v1",
@@ -26,7 +26,7 @@ var protocolViewSnapshots = map[string]ProtocolViewModel{
IsVisible: false,
},
"HiddenHeight": {
- Data: internal.StatusModel{
+ Data: nodekit.StatusModel{
State: "SYNCING",
Version: "v0.0.0-test",
Network: "test-v1",
@@ -39,7 +39,7 @@ var protocolViewSnapshots = map[string]ProtocolViewModel{
IsVisible: true,
},
"Visible": {
- Data: internal.StatusModel{
+ Data: nodekit.StatusModel{
State: "SYNCING",
Version: "v0.0.0-test",
Network: "test-v1",
@@ -52,7 +52,7 @@ var protocolViewSnapshots = map[string]ProtocolViewModel{
IsVisible: true,
},
"VisibleSmall": {
- Data: internal.StatusModel{
+ Data: nodekit.StatusModel{
State: "SYNCING",
Version: "v0.0.0-test",
Network: "test-v1",
@@ -65,7 +65,7 @@ var protocolViewSnapshots = map[string]ProtocolViewModel{
IsVisible: true,
},
"NoVoteOrUpgrade": {
- Data: internal.StatusModel{
+ Data: nodekit.StatusModel{
State: "SYNCING",
Version: "v0.0.0-test",
Network: "test-v1",
@@ -78,7 +78,7 @@ var protocolViewSnapshots = map[string]ProtocolViewModel{
IsVisible: true,
},
"NoVoteOrUpgradeSmall": {
- Data: internal.StatusModel{
+ Data: nodekit.StatusModel{
State: "SYNCING",
Version: "v0.0.0-test",
Network: "test-v1",
@@ -103,13 +103,13 @@ func Test_ProtocolSnapshot(t *testing.T) {
// Test_ProtocolMessages handles any additional tests like sending messages
func Test_ProtocolMessages(t *testing.T) {
- state := internal.StateModel{
- Status: internal.StatusModel{
+ state := nodekit.StateModel{
+ Status: nodekit.StatusModel{
LastRound: 1337,
NeedsUpdate: true,
- State: internal.SyncingState,
+ State: nodekit.SyncingState,
},
- Metrics: internal.MetricsModel{
+ Metrics: nodekit.MetricsModel{
RoundTime: 0,
TX: 0,
RX: 0,
@@ -134,7 +134,7 @@ func Test_ProtocolMessages(t *testing.T) {
teatest.WithCheckInterval(time.Millisecond*100),
teatest.WithDuration(time.Second*3),
)
- tm.Send(internal.StatusModel{
+ tm.Send(nodekit.StatusModel{
State: "",
Version: "",
Network: "",
diff --git a/ui/status.go b/ui/status.go
index 63eb60fd..50d0f93e 100644
--- a/ui/status.go
+++ b/ui/status.go
@@ -2,7 +2,7 @@ package ui
import (
"fmt"
- "github.com/algorandfoundation/algorun-tui/internal"
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
"github.com/algorandfoundation/algorun-tui/ui/style"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
@@ -14,7 +14,7 @@ import (
// StatusViewModel is extended from the internal.StatusModel
type StatusViewModel struct {
- Data *internal.StateModel
+ Data *nodekit.StateModel
TerminalWidth int
TerminalHeight int
IsVisible bool
@@ -34,7 +34,7 @@ func (m StatusViewModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
func (m StatusViewModel) HandleMessage(msg tea.Msg) (StatusViewModel, tea.Cmd) {
switch msg := msg.(type) {
// Is it a heartbeat of the latest round?
- case internal.StateModel:
+ case nodekit.StateModel:
m.Data = &msg
// Is it a resize event?
case tea.WindowSizeMsg:
@@ -83,7 +83,7 @@ func (m StatusViewModel) View() string {
var end string
switch m.Data.Status.State {
- case internal.StableState:
+ case nodekit.StableState:
end = style.Green.Render(strings.ToUpper(string(m.Data.Status.State))) + " "
default:
end = style.Yellow.Render(strings.ToUpper(string(m.Data.Status.State))) + " "
@@ -94,7 +94,7 @@ func (m StatusViewModel) View() string {
row1 := lipgloss.JoinHorizontal(lipgloss.Left, beginning, middle, end)
roundTime := fmt.Sprintf("%.2fs", float64(m.Data.Metrics.RoundTime)/float64(time.Second))
- if m.Data.Status.State != internal.StableState {
+ if m.Data.Status.State != nodekit.StableState {
roundTime = "--"
}
beginning = style.Blue.Render(" Round time: ") + roundTime
@@ -104,7 +104,7 @@ func (m StatusViewModel) View() string {
row2 := lipgloss.JoinHorizontal(lipgloss.Left, beginning, middle, end)
tps := fmt.Sprintf("%.2f", m.Data.Metrics.TPS)
- if m.Data.Status.State != internal.StableState {
+ if m.Data.Status.State != nodekit.StableState {
tps = "--"
}
beginning = style.Blue.Render(" TPS: ") + tps
@@ -124,7 +124,7 @@ func (m StatusViewModel) View() string {
}
// MakeStatusViewModel constructs the model to be used in a tea.Program
-func MakeStatusViewModel(state *internal.StateModel) StatusViewModel {
+func MakeStatusViewModel(state *nodekit.StateModel) StatusViewModel {
// Create the Model
m := StatusViewModel{
Data: state,
diff --git a/ui/status_test.go b/ui/status_test.go
index fc10d856..e307f4a9 100644
--- a/ui/status_test.go
+++ b/ui/status_test.go
@@ -2,7 +2,7 @@ package ui
import (
"bytes"
- "github.com/algorandfoundation/algorun-tui/internal"
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
"testing"
"time"
@@ -14,13 +14,13 @@ import (
var statusViewSnapshots = map[string]StatusViewModel{
"Syncing": {
- Data: &internal.StateModel{
- Status: internal.StatusModel{
+ Data: &nodekit.StateModel{
+ Status: nodekit.StatusModel{
LastRound: 1337,
NeedsUpdate: true,
State: "SYNCING",
},
- Metrics: internal.MetricsModel{
+ Metrics: nodekit.MetricsModel{
RoundTime: 0,
TX: 0,
},
@@ -30,13 +30,13 @@ var statusViewSnapshots = map[string]StatusViewModel{
IsVisible: true,
},
"Hidden": {
- Data: &internal.StateModel{
- Status: internal.StatusModel{
+ Data: &nodekit.StateModel{
+ Status: nodekit.StatusModel{
LastRound: 1337,
NeedsUpdate: true,
State: "SYNCING",
},
- Metrics: internal.MetricsModel{
+ Metrics: nodekit.MetricsModel{
RoundTime: 0,
TX: 0,
},
@@ -46,13 +46,13 @@ var statusViewSnapshots = map[string]StatusViewModel{
IsVisible: false,
},
"Loading": {
- Data: &internal.StateModel{
- Status: internal.StatusModel{
+ Data: &nodekit.StateModel{
+ Status: nodekit.StatusModel{
LastRound: 1337,
NeedsUpdate: true,
State: "SYNCING",
},
- Metrics: internal.MetricsModel{
+ Metrics: nodekit.MetricsModel{
RoundTime: 0,
TX: 0,
},
@@ -73,13 +73,13 @@ func Test_StatusSnapshot(t *testing.T) {
}
func Test_StatusMessages(t *testing.T) {
- state := internal.StateModel{
- Status: internal.StatusModel{
+ state := nodekit.StateModel{
+ Status: nodekit.StatusModel{
LastRound: 1337,
NeedsUpdate: true,
- State: internal.SyncingState,
+ State: nodekit.SyncingState,
},
- Metrics: internal.MetricsModel{
+ Metrics: nodekit.MetricsModel{
RoundTime: 0,
TX: 0,
RX: 0,
diff --git a/ui/viewport.go b/ui/viewport.go
index dad291f9..c5fef4fc 100644
--- a/ui/viewport.go
+++ b/ui/viewport.go
@@ -4,7 +4,7 @@ import (
"errors"
"fmt"
"github.com/algorandfoundation/algorun-tui/api"
- "github.com/algorandfoundation/algorun-tui/internal"
+ "github.com/algorandfoundation/algorun-tui/internal/nodekit"
"github.com/algorandfoundation/algorun-tui/ui/app"
"github.com/algorandfoundation/algorun-tui/ui/modal"
"github.com/algorandfoundation/algorun-tui/ui/pages/accounts"
@@ -18,7 +18,7 @@ type ViewportViewModel struct {
PageWidth, PageHeight int
TerminalWidth, TerminalHeight int
- Data *internal.StateModel
+ Data *nodekit.StateModel
// Header Components
status StatusViewModel
@@ -57,7 +57,7 @@ func (m ViewportViewModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
m.page = msg
// When the state updates
- case internal.StateModel:
+ case nodekit.StateModel:
m.Data = &msg
m.accountsPage, cmd = m.accountsPage.HandleMessage(msg)
cmds = append(cmds, cmd)
@@ -75,7 +75,7 @@ func (m ViewportViewModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg.String() {
case "g":
// Only open modal when it is closed and not syncing
- if !m.modal.Open && m.Data.Status.State == internal.StableState && m.Data.Metrics.RoundTime > 0 {
+ if !m.modal.Open && m.Data.Status.State == nodekit.StableState && m.Data.Metrics.RoundTime > 0 {
address := ""
selected := m.accountsPage.SelectedAccount()
if selected != nil {
@@ -86,7 +86,7 @@ func (m ViewportViewModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
Address: address,
Type: app.GenerateModal,
})
- } else if m.Data.Status.State != internal.StableState || m.Data.Metrics.RoundTime == 0 {
+ } else if m.Data.Status.State != nodekit.StableState || m.Data.Metrics.RoundTime == 0 {
genErr := errors.New("Please wait for more data to sync before generating a key")
m.modal, cmd = m.modal.HandleMessage(genErr)
cmds = append(cmds, cmd)
@@ -211,7 +211,7 @@ func (m ViewportViewModel) headerView() string {
}
// NewViewportViewModel handles the construction of the TUI viewport
-func NewViewportViewModel(state *internal.StateModel, client api.ClientWithResponsesInterface) (*ViewportViewModel, error) {
+func NewViewportViewModel(state *nodekit.StateModel, client api.ClientWithResponsesInterface) (*ViewportViewModel, error) {
m := ViewportViewModel{
Data: state,