Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: daemon service for collecting metrics and state #45

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
wip: relocate
PhearZero committed Dec 12, 2024

Verified

This commit was signed with the committer’s verified signature.
PhearZero Michael J Feher
commit a47a91449b806c902d69849b0913bae3d0bfcbad
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -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

4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -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:
16 changes: 8 additions & 8 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -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,23 +64,23 @@ 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",
Voting: false,
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)
}
12 changes: 6 additions & 6 deletions cmd/status.go
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@
"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,31 +27,31 @@
// 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",
Voting: false,
NeedsUpdate: true,
LastRound: 0,
},
Metrics: internal.MetricsModel{
Metrics: nodekit.MetricsModel{
RoundTime: 0,
TPS: 0,
RX: 0,
TX: 0,
},
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) {

Check warning on line 54 in cmd/status.go

Codecov / codecov/patch

cmd/status.go#L54

Added line #L54 was not covered by tests
cobra.CheckErr(err)
p.Send(state)
}, context.Background(), client)
204 changes: 204 additions & 0 deletions daemon/cmd/root.go
Original file line number Diff line number Diff line change
@@ -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)
}

}
Binary file added daemon/fortiter.db
Binary file not shown.
20 changes: 20 additions & 0 deletions daemon/fortiter/agreements.go
Original file line number Diff line number Diff line change
@@ -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
}
65 changes: 65 additions & 0 deletions daemon/fortiter/handlers.go
Original file line number Diff line number Diff line change
@@ -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)
}
101 changes: 101 additions & 0 deletions daemon/fortiter/logspec.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
}
20 changes: 20 additions & 0 deletions daemon/fortiter/schema.go
Original file line number Diff line number Diff line change
@@ -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
);
`
41 changes: 41 additions & 0 deletions daemon/fortiter/stats.go
Original file line number Diff line number Diff line change
@@ -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
}
2 changes: 2 additions & 0 deletions daemon/generate.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
package: rpc
output: ./rpc/gen.go
19 changes: 19 additions & 0 deletions daemon/main.go
Original file line number Diff line number Diff line change
@@ -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
}
}
Empty file added daemon/migrations/.gitkeep
Empty file.
86 changes: 86 additions & 0 deletions daemon/oas3.schema.yaml
Original file line number Diff line number Diff line change
@@ -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
Binary file added daemon/public/favicon.ico
Binary file not shown.
34 changes: 34 additions & 0 deletions daemon/public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!doctype html>
<html lang="en">

<head>
<meta charset="utf-8">
<title>WebSocket</title>
</head>

<body>
<p id="output"></p>

<script>
var loc = window.location;
var uri = window.location + "ws";

console.log(uri);
ws = new WebSocket(uri)

ws.onopen = function() {
console.log('Connected')
}

ws.onmessage = function(evt) {
var out = document.getElementById('output');
out.innerHTML += evt.data + '<br>';
}

setInterval(function() {
ws.send('Hello, Server!');
}, 1000);
</script>
</body>

</html>
228 changes: 228 additions & 0 deletions daemon/rpc/gen.go
55 changes: 47 additions & 8 deletions go.mod
Original file line number Diff line number Diff line change
@@ -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
)
201 changes: 188 additions & 13 deletions go.sum

Large diffs are not rendered by default.

File renamed without changes.
2 changes: 1 addition & 1 deletion internal/accounts.go → internal/nodekit/accounts.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package internal
package nodekit

import (
"bytes"
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package internal
package nodekit

import (
"context"
2 changes: 1 addition & 1 deletion internal/block.go → internal/nodekit/block.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package internal
package nodekit

import (
"context"
2 changes: 1 addition & 1 deletion internal/block_test.go → internal/nodekit/block_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package internal
package nodekit

import (
"context"
2 changes: 1 addition & 1 deletion internal/github.go → internal/nodekit/github.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package internal
package nodekit

import (
"encoding/json"
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package internal
package nodekit

import (
"bytes"
2 changes: 1 addition & 1 deletion internal/http.go → internal/nodekit/http.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package internal
package nodekit

import "net/http"

2 changes: 1 addition & 1 deletion internal/metrics.go → internal/nodekit/metrics.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package internal
package nodekit

import (
"context"
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package internal
package nodekit

import (
"context"
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package internal
package nodekit

import (
"context"
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package internal
package nodekit

import (
"context"
2 changes: 1 addition & 1 deletion internal/rangetype.go → internal/nodekit/rangetype.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package internal
package nodekit

type RangeType string

2 changes: 1 addition & 1 deletion internal/state.go → internal/nodekit/state.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package internal
package nodekit

import (
"context"
2 changes: 1 addition & 1 deletion internal/state_test.go → internal/nodekit/state_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package internal
package nodekit

import (
"context"
2 changes: 1 addition & 1 deletion internal/status.go → internal/nodekit/status.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package internal
package nodekit

import (
"context"
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package internal
package nodekit

import (
"context"
2 changes: 1 addition & 1 deletion internal/time.go → internal/nodekit/time.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package internal
package nodekit

import "time"

6 changes: 3 additions & 3 deletions ui/app/accounts.go
Original file line number Diff line number Diff line change
@@ -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 {

Check warning on line 11 in ui/app/accounts.go

Codecov / codecov/patch

ui/app/accounts.go#L11

Added line #L11 was not covered by tests
return func() tea.Msg {
return AccountSelected(account)
}
6 changes: 3 additions & 3 deletions ui/app/app_test.go
Original file line number Diff line number Diff line change
@@ -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 {
10 changes: 5 additions & 5 deletions ui/app/keys.go
Original file line number Diff line number Diff line change
@@ -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, &params)
key, err := nodekit.GenerateKeyPair(state.Context, state.Client, account, &params)
if err != nil {
return ModalEvent{
Key: nil,
16 changes: 8 additions & 8 deletions ui/internal/test/state.go
Original file line number Diff line number Diff line change
@@ -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,
4 changes: 2 additions & 2 deletions ui/modal/controller.go
Original file line number Diff line number Diff line change
@@ -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 @@
m.Open = true
m.exceptionModal.Message = msg.Error()
m.SetType(app.ExceptionModal)
case internal.StateModel:
case nodekit.StateModel:

Check warning on line 31 in ui/modal/controller.go

Codecov / codecov/patch

ui/modal/controller.go#L31

Added line #L31 was not covered by tests
m.State = &msg
m.transactionModal.State = &msg
m.infoModal.State = &msg
6 changes: 3 additions & 3 deletions ui/modal/model.go
Original file line number Diff line number Diff line change
@@ -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,
6 changes: 3 additions & 3 deletions ui/modals/confirm/confirm.go
Original file line number Diff line number Diff line change
@@ -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,
12 changes: 6 additions & 6 deletions ui/modals/generate/controller.go
Original file line number Diff line number Diff line change
@@ -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))

6 changes: 3 additions & 3 deletions ui/modals/generate/model.go
Original file line number Diff line number Diff line change
@@ -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()

6 changes: 3 additions & 3 deletions ui/modals/info/info.go
Original file line number Diff line number Diff line change
@@ -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,
4 changes: 2 additions & 2 deletions ui/modals/transaction/controller.go
Original file line number Diff line number Diff line change
@@ -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
}
6 changes: 3 additions & 3 deletions ui/modals/transaction/model.go
Original file line number Diff line number Diff line change
@@ -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",
4 changes: 2 additions & 2 deletions ui/modals/transaction/view.go
Original file line number Diff line number Diff line change
@@ -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),
8 changes: 4 additions & 4 deletions ui/pages/accounts/accounts_test.go
Original file line number Diff line number Diff line change
@@ -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 {

}
}
4 changes: 2 additions & 2 deletions ui/pages/accounts/controller.go
Original file line number Diff line number Diff line change
@@ -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:
12 changes: 6 additions & 6 deletions ui/pages/accounts/model.go
Original file line number Diff line number Diff line change
@@ -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"
}

6 changes: 3 additions & 3 deletions ui/pages/keys/controller.go
Original file line number Diff line number Diff line change
@@ -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:
4 changes: 2 additions & 2 deletions ui/pages/keys/model.go
Original file line number Diff line number Diff line change
@@ -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 {
8 changes: 4 additions & 4 deletions ui/protocol.go
Original file line number Diff line number Diff line change
@@ -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,
24 changes: 12 additions & 12 deletions ui/protocol_test.go
Original file line number Diff line number Diff line change
@@ -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: "",
14 changes: 7 additions & 7 deletions ui/status.go
Original file line number Diff line number Diff line change
@@ -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,
28 changes: 14 additions & 14 deletions ui/status_test.go
Original file line number Diff line number Diff line change
@@ -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,
12 changes: 6 additions & 6 deletions ui/viewport.go
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@
"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 @@
PageWidth, PageHeight int
TerminalWidth, TerminalHeight int

Data *internal.StateModel
Data *nodekit.StateModel

// Header Components
status StatusViewModel
@@ -57,7 +57,7 @@
}
m.page = msg
// When the state updates
case internal.StateModel:
case nodekit.StateModel:

Check warning on line 60 in ui/viewport.go

Codecov / codecov/patch

ui/viewport.go#L60

Added line #L60 was not covered by tests
m.Data = &msg
m.accountsPage, cmd = m.accountsPage.HandleMessage(msg)
cmds = append(cmds, cmd)
@@ -75,7 +75,7 @@
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 {

Check warning on line 78 in ui/viewport.go

Codecov / codecov/patch

ui/viewport.go#L78

Added line #L78 was not covered by tests
address := ""
selected := m.accountsPage.SelectedAccount()
if selected != nil {
@@ -86,7 +86,7 @@
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 {

Check warning on line 89 in ui/viewport.go

Codecov / codecov/patch

ui/viewport.go#L89

Added line #L89 was not covered by tests
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 @@
}

// 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,