Skip to content

Commit

Permalink
Merge branch 'main' into refactor/view-transitions
Browse files Browse the repository at this point in the history
# Conflicts:
#	cmd/root.go
#	ui/pages/accounts/model.go
#	ui/viewport.go
  • Loading branch information
PhearZero committed Nov 6, 2024
2 parents c4aeb72 + 4e34d48 commit 1eefee4
Show file tree
Hide file tree
Showing 18 changed files with 211 additions and 45 deletions.
81 changes: 64 additions & 17 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"context"
"encoding/json"
"fmt"
"github.com/algorandfoundation/hack-tui/api"
"github.com/algorandfoundation/hack-tui/internal"
"github.com/algorandfoundation/hack-tui/ui"
Expand Down Expand Up @@ -39,13 +40,25 @@ var (
},
RunE: func(cmd *cobra.Command, args []string) error {
log.SetOutput(cmd.OutOrStdout())
initConfig()

if viper.GetString("server") == "" {
return fmt.Errorf(style.Red.Render("server is required"))
}
if viper.GetString("token") == "" {
return fmt.Errorf(style.Red.Render("token is required"))
}

client, err := getClient()
cobra.CheckErr(err)

ctx := context.Background()

partkeys, err := internal.GetPartKeys(ctx, client)
cobra.CheckErr(err)
if err != nil {
return fmt.Errorf(
style.Red.Render("failed to get participation keys: %s"),
err)
}

state := internal.StateModel{
Status: internal.StatusModel{
Expand Down Expand Up @@ -108,7 +121,7 @@ func check(err interface{}) {
// Handle global flags and set usage templates
func init() {
log.SetReportTimestamp(false)
initConfig()

// Configure Version
if Version == "" {
Version = "unknown (built from source)"
Expand Down Expand Up @@ -144,6 +157,15 @@ type AlgodConfig struct {
EndpointAddress string `json:"EndpointAddress"`
}

func replaceEndpointUrl(s string) string {
s = strings.Replace(s, "\n", "", 1)
s = strings.Replace(s, "0.0.0.0", "127.0.0.1", 1)
s = strings.Replace(s, "[::]", "127.0.0.1", 1)
return s
}
func hasWildcardEndpointUrl(s string) bool {
return strings.Contains(s, "0.0.0.0") || strings.Contains(s, "::")
}
func initConfig() {
// Find home directory.
home, err := os.UserHomeDir()
Expand All @@ -161,12 +183,17 @@ func initConfig() {

// Load Configurations
viper.AutomaticEnv()
err = viper.ReadInConfig()
_ = viper.ReadInConfig()

// Check for server
loadedServer := viper.GetString("server")
loadedToken := viper.GetString("token")

// Load ALGORAND_DATA/config.json
algorandData, exists := os.LookupEnv("ALGORAND_DATA")

// Load the Algorand Data Configuration
if exists && algorandData != "" {
if exists && algorandData != "" && loadedServer == "" {
// Placeholder for Struct
var algodConfig AlgodConfig

Expand All @@ -185,23 +212,43 @@ func initConfig() {
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)
// Check for endpoint address
if hasWildcardEndpointUrl(algodConfig.EndpointAddress) {
algodConfig.EndpointAddress = replaceEndpointUrl(algodConfig.EndpointAddress)
} else if algodConfig.EndpointAddress == "" {
// Assume it is not set, try to discover the port from the network file
networkPath := algorandData + "/algod.net"
networkFile, err := os.Open(networkPath)
check(err)

byteValue, err = io.ReadAll(networkFile)
check(err)

if hasWildcardEndpointUrl(string(byteValue)) {
algodConfig.EndpointAddress = replaceEndpointUrl(string(byteValue))
} else {
algodConfig.EndpointAddress = string(byteValue)
}

}
if strings.Contains(algodConfig.EndpointAddress, ":0") {
algodConfig.EndpointAddress = strings.Replace(algodConfig.EndpointAddress, ":0", ":8080", 1)
}
if loadedToken == "" {
// Handle Token Path
tokenPath := algorandData + "/algod.admin.token"

// Handle Token Path
tokenPath := algorandData + "/algod.admin.token"
tokenFile, err := os.Open(tokenPath)
check(err)

tokenFile, err := os.Open(tokenPath)
check(err)
byteValue, err = io.ReadAll(tokenFile)
check(err)

byteValue, err = io.ReadAll(tokenFile)
check(err)
viper.Set("token", strings.Replace(string(byteValue), "\n", "", 1))
}

// Set the server configuration
viper.Set("server", "http://"+algodConfig.EndpointAddress)
viper.Set("token", string(byteValue))
viper.Set("server", "http://"+strings.Replace(algodConfig.EndpointAddress, "\n", "", 1))
viper.Set("data", dataConfigPath)
}

Expand Down
54 changes: 53 additions & 1 deletion cmd/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,64 @@ func Test_ExecuteRootCommand(t *testing.T) {

func Test_InitConfig(t *testing.T) {
cwd, _ := os.Getwd()
t.Setenv("ALGORAND_DATA", cwd+"/testdata")
viper.Set("token", "")
viper.Set("server", "")
t.Setenv("ALGORAND_DATA", cwd+"/testdata/Test_InitConfig")

initConfig()
server := viper.Get("server")
if server == "" {
t.Fatal("Invalid Server")
}
if server != "http://127.0.0.1:8080" {
t.Fatal("Invalid Server")
}
}

func Test_InitConfigWithoutEndpoint(t *testing.T) {
cwd, _ := os.Getwd()
viper.Set("token", "")
viper.Set("server", "")
t.Setenv("ALGORAND_DATA", cwd+"/testdata/Test_InitConfigWithoutEndpoint")

initConfig()
server := viper.Get("server")
if server == "" {
t.Fatal("Invalid Server")
}
if server != "http://127.0.0.1:8080" {
t.Fatal("Invalid Server")
}
}

func Test_InitConfigWithAddress(t *testing.T) {
cwd, _ := os.Getwd()
viper.Set("token", "")
viper.Set("server", "")
t.Setenv("ALGORAND_DATA", cwd+"/testdata/Test_InitConfigWithAddress")

initConfig()
server := viper.Get("server")
if server == "" {
t.Fatal("Invalid Server")
}
if server != "http://255.255.255.255:8080" {
t.Fatal("Invalid Server")
}
}

func Test_InitConfigWithAddressAndDefaultPort(t *testing.T) {
cwd, _ := os.Getwd()
viper.Set("token", "")
viper.Set("server", "")
t.Setenv("ALGORAND_DATA", cwd+"/testdata/Test_InitConfigWithAddressAndDefaultPort")

initConfig()
server := viper.Get("server")
if server == "" {
t.Fatal("Invalid Server")
}
if server != "http://255.255.255.255:8080" {
t.Fatal("Invalid Server")
}
}
1 change: 1 addition & 0 deletions cmd/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ var statusCmd = &cobra.Command{
Short: "Get the node status",
Long: style.Purple(BANNER) + "\n" + style.LightBlue("View the node status"),
RunE: func(cmd *cobra.Command, args []string) error {
initConfig()
if viper.GetString("server") == "" {
return errors.New(style.Magenta("server is required"))
}
Expand Down
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions cmd/testdata/Test_InitConfigWithAddress/algod.admin.token
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
4 changes: 4 additions & 0 deletions cmd/testdata/Test_InitConfigWithAddress/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"EndpointAddress": "255.255.255.255:8080",
"OtherKey": ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"EndpointAddress": "255.255.255.255:0",
"OtherKey": ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
1 change: 1 addition & 0 deletions cmd/testdata/Test_InitConfigWithoutEndpoint/algod.net
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[::]:8080
2 changes: 2 additions & 0 deletions cmd/testdata/Test_InitConfigWithoutEndpoint/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{
}
25 changes: 15 additions & 10 deletions internal/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,18 +121,23 @@ func AccountsFromState(state *StateModel, t Time, client *api.ClientWithResponse
for _, key := range *state.ParticipationKeys {
val, ok := values[key.Address]
if !ok {

account, err := GetAccount(client, key.Address)

// TODO: handle error
if err != nil {
// TODO: Logging
panic(err)
var account = api.Account{
Address: key.Address,
Status: "Unknown",
Amount: 0,
}

var expires = t.Now()
if state.Status.State != "SYNCING" {
var err error
account, err = GetAccount(client, key.Address)
// TODO: handle error
if err != nil {
// TODO: Logging
panic(err)
}
}
now := t.Now()
var expires = now.Add(-(time.Hour * 24 * 365 * 100))
if key.EffectiveLastValid != nil {
now := t.Now()
roundDiff := max(0, *key.EffectiveLastValid-int(state.Status.LastRound))
distance := int(state.Metrics.RoundTime) * roundDiff
expires = now.Add(time.Duration(distance))
Expand Down
3 changes: 3 additions & 0 deletions internal/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ type MetricsModel struct {
TPS float64
RX int
TX int
LastTS time.Time
LastRX int
LastTX int
}

type MetricsResponse map[string]int
Expand Down
16 changes: 14 additions & 2 deletions internal/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ func (s *StateModel) Watch(cb func(model *StateModel, err error), ctx context.Co
// Fetch Keys
s.UpdateKeys()

if s.Status.State == "SYNCING" {
lastRound = s.Status.LastRound
cb(s, nil)
continue
}
// Run Round Averages and RX/TX every 5 rounds
if s.Status.LastRound%5 == 0 {
bm, err := GetBlockMetrics(ctx, client, s.Status.LastRound, s.Metrics.Window)
Expand Down Expand Up @@ -94,8 +99,15 @@ func (s *StateModel) UpdateMetricsFromRPC(ctx context.Context, client *api.Clien
}
if err == nil {
s.Metrics.Enabled = true
s.Metrics.TX = res["algod_network_sent_bytes_total"]
s.Metrics.RX = res["algod_network_received_bytes_total"]
now := time.Now()
diff := now.Sub(s.Metrics.LastTS)

s.Metrics.TX = max(0, int(float64(res["algod_network_sent_bytes_total"]-s.Metrics.LastTX)/diff.Seconds()))
s.Metrics.RX = max(0, int(float64(res["algod_network_received_bytes_total"]-s.Metrics.LastRX)/diff.Seconds()))

s.Metrics.LastTS = now
s.Metrics.LastTX = res["algod_network_sent_bytes_total"]
s.Metrics.LastRX = res["algod_network_received_bytes_total"]
}
}
func (s *StateModel) UpdateAccounts() {
Expand Down
2 changes: 1 addition & 1 deletion ui/pages/accounts/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func (m ViewModel) HandleMessage(msg tea.Msg) (ViewModel, tea.Cmd) {

switch msg := msg.(type) {
case internal.StateModel:
m.Data = msg.Accounts
m.Data = &msg
m.table.SetRows(*m.makeRows())
case tea.KeyMsg:
switch msg.String() {
Expand Down
28 changes: 18 additions & 10 deletions ui/pages/accounts/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/algorandfoundation/hack-tui/ui/style"
"sort"
"strconv"
"time"

"github.com/algorandfoundation/hack-tui/internal"
"github.com/charmbracelet/bubbles/table"
Expand All @@ -13,7 +14,7 @@ import (
type ViewModel struct {
Width int
Height int
Data map[string]internal.Account
Data *internal.StateModel

table table.Model
navigation string
Expand All @@ -24,8 +25,8 @@ func New(state *internal.StateModel) ViewModel {
m := ViewModel{
Width: 0,
Height: 0,
Data: state.Accounts,
controls: "( (g)enerate | enter )",
Data: state,
controls: "( (g)enerate )",
navigation: "| " + style.Green.Render("accounts") + " | keys |",
}

Expand All @@ -52,7 +53,7 @@ func (m ViewModel) SelectedAccount() internal.Account {
var account internal.Account
var selectedRow = m.table.SelectedRow()
if selectedRow != nil {
account = m.Data[selectedRow[0]]
account = m.Data.Accounts[selectedRow[0]]
}
return account
}
Expand All @@ -70,13 +71,20 @@ func (m ViewModel) makeColumns(width int) []table.Column {
func (m ViewModel) makeRows() *[]table.Row {
rows := make([]table.Row, 0)

for key := range m.Data {
for key := range m.Data.Accounts {
expires := m.Data.Accounts[key].Expires.String()
if m.Data.Status.State == "SYNCING" {
expires = "SYNCING"
}
if !m.Data.Accounts[key].Expires.After(time.Now().Add(-(time.Hour * 24 * 365 * 50))) {
expires = "NA"
}
rows = append(rows, table.Row{
m.Data[key].Address,
strconv.Itoa(m.Data[key].Keys),
m.Data[key].Status,
m.Data[key].Expires.String(),
strconv.Itoa(m.Data[key].Balance),
m.Data.Accounts[key].Address,
strconv.Itoa(m.Data.Accounts[key].Keys),
m.Data.Accounts[key].Status,
expires,
strconv.Itoa(m.Data.Accounts[key].Balance),
})
}
sort.SliceStable(rows, func(i, j int) bool {
Expand Down
Loading

0 comments on commit 1eefee4

Please sign in to comment.