mirror of
https://github.com/luxfi/sdk.git
synced 2026-10-30 15:19:23 +00:00
The node moved every chain route from /v1/bc/<alias> to /v1/chain/<alias> and deleted the old prefix, so every call this SDK made against a current node was a 404. The segment is constants.ChainAliasPrefix, which went from "bc" to "chain" in luxfi/constants v1.6.4. Call sites that already went through constants.Chain moved with the pin. These nine spelled the prefix out longhand instead of asking the composer, so they stayed behind: five endpoint helpers in models, the default APIEndpoint in config, the two URLs ux prints, and two doc examples that would have sent a reader at a deleted route. The wallet's test double mounted /v1/bc/P and /v1/bc/X, so it answered the route the node had dropped and would have gone on passing against a node that no longer exists. It now serves what the node serves, and the assertion that the SDK must not touch X in P-only mode checks the live path -- against the old one it could never fire again. That file has not compiled since the X/C opt-in decomplect removed isXChainNotEnabled, so none of these tests were running. Its test went with the function it covered. Chain() no longer claims the node answers both spellings. It does not. Co-authored-by: Hanzo Dev <[email protected]>
130 lines
3.7 KiB
Go
130 lines
3.7 KiB
Go
// Copyright (C) 2022, Lux Industries Inc All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
// Package ux provides user experience utilities for CLI output formatting.
|
|
package ux
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"golang.org/x/text/language"
|
|
"golang.org/x/text/message"
|
|
|
|
luxlog "github.com/luxfi/log"
|
|
"github.com/luxfi/netrunner/rpcpb"
|
|
"github.com/luxfi/sdk/constants"
|
|
"github.com/olekukonko/tablewriter"
|
|
)
|
|
|
|
var Logger *UserLog
|
|
|
|
type UserLog struct {
|
|
log luxlog.Logger
|
|
writer io.Writer
|
|
}
|
|
|
|
func NewUserLog(log luxlog.Logger, userwriter io.Writer) {
|
|
if Logger == nil {
|
|
Logger = &UserLog{
|
|
log: log,
|
|
writer: userwriter,
|
|
}
|
|
}
|
|
}
|
|
|
|
// PrintToUser prints msg directly on the screen, but also to log file
|
|
func (ul *UserLog) PrintToUser(msg string, args ...interface{}) {
|
|
formattedMsg := fmt.Sprintf(msg, args...)
|
|
fmt.Fprintln(ul.writer, formattedMsg)
|
|
ul.log.Info(formattedMsg)
|
|
}
|
|
|
|
// Info logs an info message
|
|
func (ul *UserLog) Info(msg string, args ...interface{}) {
|
|
formattedMsg := fmt.Sprintf(msg, args...)
|
|
ul.log.Info(formattedMsg)
|
|
}
|
|
|
|
// PrintLineSeparator prints a line separator
|
|
func (ul *UserLog) PrintLineSeparator(msg ...string) {
|
|
separator := "=========================================="
|
|
if len(msg) > 0 && msg[0] != "" {
|
|
separator = msg[0]
|
|
}
|
|
fmt.Fprintln(ul.writer, separator)
|
|
ul.log.Info(separator)
|
|
}
|
|
|
|
// Error logs an error message
|
|
func (ul *UserLog) Error(msg string, args ...interface{}) {
|
|
formattedMsg := fmt.Sprintf(msg, args...)
|
|
ul.log.Error(formattedMsg)
|
|
}
|
|
|
|
// RedXToUser prints a red X error message to the user
|
|
func (ul *UserLog) RedXToUser(msg string, args ...interface{}) {
|
|
formattedMsg := fmt.Sprintf("✗ %s", fmt.Sprintf(msg, args...))
|
|
fmt.Fprintln(ul.writer, formattedMsg)
|
|
ul.log.Error(formattedMsg)
|
|
}
|
|
|
|
// GreenCheckmarkToUser prints a green checkmark success message to the user
|
|
func (ul *UserLog) GreenCheckmarkToUser(msg string, args ...interface{}) {
|
|
formattedMsg := fmt.Sprintf("✓ %s", fmt.Sprintf(msg, args...))
|
|
fmt.Fprintln(ul.writer, formattedMsg)
|
|
ul.log.Info(formattedMsg)
|
|
}
|
|
|
|
// PrintWait does some dot printing to entertain the user
|
|
func PrintWait(cancel chan struct{}) {
|
|
for {
|
|
select {
|
|
case <-time.After(1 * time.Second):
|
|
fmt.Print(".")
|
|
case <-cancel:
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// PrintTableEndpoints prints the endpoints coming from the healthy call
|
|
func PrintTableEndpoints(clusterInfo *rpcpb.ClusterInfo) {
|
|
table := tablewriter.NewWriter(os.Stdout)
|
|
// In v1.0.9, headers are added as the first row via Append
|
|
header := []string{"node", "VM", "URL", "ALIAS_URL"}
|
|
_ = table.Append(header) //nolint:errcheck
|
|
|
|
nodeInfos := map[string]*rpcpb.NodeInfo{}
|
|
for _, nodeInfo := range clusterInfo.NodeInfos {
|
|
nodeInfos[nodeInfo.Name] = nodeInfo
|
|
}
|
|
for _, nodeName := range clusterInfo.NodeNames {
|
|
nodeInfo := nodeInfos[nodeName]
|
|
for blockchainID, chainInfo := range clusterInfo.CustomChains {
|
|
_ = table.Append([]string{nodeInfo.Name, chainInfo.ChainName, constants.Chain(nodeInfo.GetUri(), blockchainID) + "/rpc", constants.Chain(nodeInfo.GetUri(), chainInfo.ChainName) + "/rpc"}) //nolint:errcheck
|
|
}
|
|
}
|
|
_ = table.Render() //nolint:errcheck
|
|
}
|
|
|
|
// DefaultTable creates a default table with the given title and headers
|
|
func DefaultTable(title string, headers []string) *tablewriter.Table {
|
|
table := tablewriter.NewWriter(os.Stdout)
|
|
// In v1.0.9, headers are added as the first row via Append
|
|
if len(headers) > 0 {
|
|
_ = table.Append(headers) //nolint:errcheck
|
|
}
|
|
// Note: Title, border, and other formatting options are defaults in v1.0.9
|
|
return table
|
|
}
|
|
|
|
func ConvertToStringWithThousandSeparator(input uint64) string {
|
|
p := message.NewPrinter(language.English)
|
|
s := p.Sprintf("%d", input)
|
|
return strings.ReplaceAll(s, ",", "_")
|
|
}
|