mirror of
https://github.com/miguelmota/cointop
synced 2024-11-12 07:10:26 +00:00
Add command to print holdings
This commit is contained in:
parent
9d15e268c2
commit
97facbe48d
20
README.md
20
README.md
@ -240,11 +240,12 @@ go get -u github.com/miguelmota/cointop
|
||||
brew uninstall cointop && brew install cointop
|
||||
```
|
||||
|
||||
### Flatpak (Linux)
|
||||
### Snap (Ubuntu)
|
||||
|
||||
Use the `refresh` command to update snap.
|
||||
|
||||
```bash
|
||||
sudo flatpak uninstall com.github.miguelmota.Cointop
|
||||
sudo flatpak install flathub com.github.miguelmota.Cointop
|
||||
sudo snap refresh cointop
|
||||
```
|
||||
|
||||
### Copr (Fedora)
|
||||
@ -253,12 +254,17 @@ sudo flatpak install flathub com.github.miguelmota.Cointop
|
||||
sudo dnf update cointop
|
||||
```
|
||||
|
||||
### Snap (Ubuntu)
|
||||
|
||||
Use the `refresh` command to update snap.
|
||||
### AUR (Arch Linux)
|
||||
|
||||
```bash
|
||||
sudo snap refresh cointop --stable
|
||||
yay -S cointop
|
||||
```
|
||||
|
||||
### Flatpak (Linux)
|
||||
|
||||
```bash
|
||||
sudo flatpak uninstall com.github.miguelmota.Cointop
|
||||
sudo flatpak install flathub com.github.miguelmota.Cointop
|
||||
```
|
||||
|
||||
## Getting started
|
||||
|
29
cointop/cmd/clean.go
Normal file
29
cointop/cmd/clean.go
Normal file
@ -0,0 +1,29 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/miguelmota/cointop/cointop"
|
||||
"github.com/miguelmota/cointop/cointop/common/filecache"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// CleanCmd ...
|
||||
func CleanCmd() *cobra.Command {
|
||||
cacheDir := filecache.DefaultCacheDir
|
||||
|
||||
cleanCmd := &cobra.Command{
|
||||
Use: "clean",
|
||||
Short: "Clear the cache",
|
||||
Long: `The clean command clears the cache`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
// NOTE: if clean command, clean but don't run cointop
|
||||
return cointop.Clean(&cointop.CleanConfig{
|
||||
Log: true,
|
||||
CacheDir: cacheDir,
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
cleanCmd.Flags().StringVarP(&cacheDir, "cache-dir", "", cacheDir, "Cache directory")
|
||||
|
||||
return cleanCmd
|
||||
}
|
@ -1,222 +1,19 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/miguelmota/cointop/cointop"
|
||||
"github.com/miguelmota/cointop/cointop/common/filecache"
|
||||
cssh "github.com/miguelmota/cointop/cointop/ssh"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// Execute executes the program
|
||||
func Execute() {
|
||||
var version, test, clean, reset, hideMarketbar, hideChart, hideStatusbar, onlyTable, silent, noCache bool
|
||||
var refreshRate uint
|
||||
var config, cmcAPIKey, apiChoice, colorscheme, coin, currency string
|
||||
cacheDir := filecache.DefaultCacheDir
|
||||
perPage := cointop.DefaultPerPage
|
||||
|
||||
rootCmd := &cobra.Command{
|
||||
Use: "cointop",
|
||||
Short: "Cointop is an interactive terminal based app for tracking cryptocurrencies",
|
||||
Long: `
|
||||
_ _
|
||||
___ ___ (_)_ __ | |_ ___ _ __
|
||||
/ __/ _ \| | '_ \| __/ _ \| '_ \
|
||||
| (_| (_) | | | | | || (_) | |_) |
|
||||
\___\___/|_|_| |_|\__\___/| .__/
|
||||
|_|
|
||||
|
||||
Cointop is a fast and lightweight interactive terminal based UI application for tracking and monitoring cryptocurrency coin stats in real-time.
|
||||
|
||||
See git.io/cointop for more info.`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if version {
|
||||
cointop.PrintVersion()
|
||||
return nil
|
||||
}
|
||||
|
||||
if test {
|
||||
// TODO: deprecate test flag, only have test command
|
||||
doTest()
|
||||
return nil
|
||||
}
|
||||
|
||||
// NOTE: if reset flag enabled, reset and run cointop
|
||||
if reset {
|
||||
if err := cointop.Reset(&cointop.ResetConfig{
|
||||
Log: !silent,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: if clean flag enabled, clean and run cointop
|
||||
if clean {
|
||||
if err := cointop.Clean(&cointop.CleanConfig{
|
||||
Log: !silent,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var refreshRateP *uint
|
||||
if cmd.Flags().Changed("refresh-rate") {
|
||||
refreshRateP = &refreshRate
|
||||
}
|
||||
|
||||
ct, err := cointop.NewCointop(&cointop.Config{
|
||||
CacheDir: cacheDir,
|
||||
NoCache: noCache,
|
||||
ConfigFilepath: config,
|
||||
CoinMarketCapAPIKey: cmcAPIKey,
|
||||
APIChoice: apiChoice,
|
||||
Colorscheme: colorscheme,
|
||||
HideMarketbar: hideMarketbar,
|
||||
HideChart: hideChart,
|
||||
HideStatusbar: hideStatusbar,
|
||||
OnlyTable: onlyTable,
|
||||
RefreshRate: refreshRateP,
|
||||
PerPage: perPage,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ct.Run()
|
||||
},
|
||||
}
|
||||
|
||||
rootCmd.Flags().BoolVarP(&version, "version", "v", false, "Display current version")
|
||||
rootCmd.Flags().BoolVarP(&test, "test", "", false, "Run test (for Homebrew)")
|
||||
rootCmd.Flags().BoolVarP(&clean, "clean", "", false, "Wipe clean the cache")
|
||||
rootCmd.Flags().BoolVarP(&reset, "reset", "", false, "Reset the config. Make sure to backup any relevant changes first!")
|
||||
rootCmd.Flags().BoolVarP(&hideMarketbar, "hide-marketbar", "", false, "Hide the top marketbar")
|
||||
rootCmd.Flags().BoolVarP(&hideChart, "hide-chart", "", false, "Hide the chart view")
|
||||
rootCmd.Flags().BoolVarP(&hideStatusbar, "hide-statusbar", "", false, "Hide the bottom statusbar")
|
||||
rootCmd.Flags().BoolVarP(&onlyTable, "only-table", "", false, "Show only the table. Hides the chart and top and bottom bars")
|
||||
rootCmd.Flags().BoolVarP(&silent, "silent", "s", false, "Silence log ouput")
|
||||
rootCmd.Flags().BoolVarP(&noCache, "no-cache", "", false, "No cache")
|
||||
rootCmd.Flags().UintVarP(&refreshRate, "refresh-rate", "r", 60, "Refresh rate in seconds. Set to 0 to not auto-refresh")
|
||||
rootCmd.Flags().UintVarP(&perPage, "per-page", "", perPage, "Per page")
|
||||
rootCmd.Flags().StringVarP(&config, "config", "c", "", fmt.Sprintf("Config filepath. (default %s)", cointop.DefaultConfigFilepath))
|
||||
rootCmd.Flags().StringVarP(&cmcAPIKey, "coinmarketcap-api-key", "", "", "Set the CoinMarketCap API key")
|
||||
rootCmd.Flags().StringVarP(&apiChoice, "api", "", cointop.CoinGecko, "API choice. Available choices are \"coinmarketcap\" and \"coingecko\"")
|
||||
rootCmd.Flags().StringVarP(&colorscheme, "colorscheme", "", "", "Colorscheme to use (default \"cointop\"). To install standard themes, do:\n\ngit clone git@github.com:cointop-sh/colors.git ~/.config/cointop/colors\n\nSee git.io/cointop#colorschemes for more info.")
|
||||
rootCmd.Flags().StringVarP(&cacheDir, "cache-dir", "", "/tmp", "Cache directory")
|
||||
|
||||
versionCmd := &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Displays the current version",
|
||||
Long: `The version command displays the current version`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cointop.PrintVersion()
|
||||
},
|
||||
}
|
||||
|
||||
cleanCmd := &cobra.Command{
|
||||
Use: "clean",
|
||||
Short: "Clear the cache",
|
||||
Long: `The clean command clears the cache`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
// NOTE: if clean command, clean but don't run cointop
|
||||
return cointop.Clean(&cointop.CleanConfig{
|
||||
Log: true,
|
||||
CacheDir: cacheDir,
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
cleanCmd.Flags().StringVarP(&cacheDir, "cache-dir", "", cacheDir, "Cache directory")
|
||||
|
||||
resetCmd := &cobra.Command{
|
||||
Use: "reset",
|
||||
Short: "Resets the config and clear the cache",
|
||||
Long: `The reset command resets the config and clears the cache`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
// NOTE: if reset command, reset but don't run cointop
|
||||
return cointop.Reset(&cointop.ResetConfig{
|
||||
Log: true,
|
||||
CacheDir: cacheDir,
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
resetCmd.Flags().StringVarP(&cacheDir, "cache-dir", "", cacheDir, "Cache directory")
|
||||
|
||||
priceCmd := &cobra.Command{
|
||||
Use: "price",
|
||||
Short: "Displays the current price of a coin",
|
||||
Long: `The price command display the current price of a coin`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return cointop.PrintPrice(&cointop.PriceConfig{
|
||||
Coin: coin,
|
||||
Currency: currency,
|
||||
APIChoice: apiChoice,
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
testCmd := &cobra.Command{
|
||||
Use: "test",
|
||||
Short: "Runs tests",
|
||||
Long: `The test command runs tests for Homebrew`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
doTest()
|
||||
},
|
||||
}
|
||||
|
||||
priceCmd.Flags().StringVarP(&coin, "coin", "c", "bitcoin", "Full name of the coin (default \"bitcoin\")")
|
||||
priceCmd.Flags().StringVarP(¤cy, "currency", "f", "USD", "The currency to convert to (default \"USD\")")
|
||||
priceCmd.Flags().StringVarP(&apiChoice, "api", "a", cointop.CoinGecko, "API choice. Available choices are \"coinmarketcap\" and \"coingecko\"")
|
||||
|
||||
var port uint = 22
|
||||
var address string = "0.0.0.0"
|
||||
var idleTimeout uint = 60
|
||||
var executableBinary string = "cointop"
|
||||
var hostKeyFile string = cssh.DefaultHostKeyFile
|
||||
|
||||
serverCmd := &cobra.Command{
|
||||
Use: "server",
|
||||
Short: "Run cintop SSH Server",
|
||||
Long: `Run cointop SSH server`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
server := cssh.NewServer(&cssh.Config{
|
||||
Address: address,
|
||||
Port: port,
|
||||
IdleTimeout: time.Duration(int(idleTimeout)) * time.Second,
|
||||
ExecutableBinary: executableBinary,
|
||||
HostKeyFile: hostKeyFile,
|
||||
})
|
||||
|
||||
fmt.Printf("Running SSH server on port %v\n", port)
|
||||
return server.ListenAndServe()
|
||||
},
|
||||
}
|
||||
|
||||
serverCmd.Flags().UintVarP(&port, "port", "p", port, "Port")
|
||||
serverCmd.Flags().StringVarP(&address, "address", "a", address, "Address")
|
||||
serverCmd.Flags().UintVarP(&idleTimeout, "idle-timeout", "t", idleTimeout, "Idle timeout in seconds")
|
||||
serverCmd.Flags().StringVarP(&executableBinary, "binary", "b", executableBinary, "Executable binary path")
|
||||
serverCmd.Flags().StringVarP(&hostKeyFile, "host-key-file", "k", hostKeyFile, "Host key file")
|
||||
|
||||
rootCmd.AddCommand(versionCmd, cleanCmd, resetCmd, priceCmd, testCmd, serverCmd)
|
||||
rootCmd := RootCmd()
|
||||
rootCmd.AddCommand(
|
||||
VersionCmd(),
|
||||
CleanCmd(),
|
||||
ResetCmd(),
|
||||
PriceCmd(),
|
||||
HoldingsCmd(),
|
||||
ServerCmd(),
|
||||
TestCmd(),
|
||||
)
|
||||
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func doTest() {
|
||||
ct, err := cointop.NewCointop(&cointop.Config{
|
||||
NoPrompts: true,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ct.Exit()
|
||||
}
|
||||
|
42
cointop/cmd/holdings.go
Normal file
42
cointop/cmd/holdings.go
Normal file
@ -0,0 +1,42 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/miguelmota/cointop/cointop"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// HoldingsCmd ...
|
||||
func HoldingsCmd() *cobra.Command {
|
||||
var total, noCache bool
|
||||
var config string
|
||||
|
||||
holdingsCmd := &cobra.Command{
|
||||
Use: "holdings",
|
||||
Short: "Displays current holdings",
|
||||
Long: `The holdings command shows your current holdings`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ct, err := cointop.NewCointop(&cointop.Config{
|
||||
ConfigFilepath: config,
|
||||
APIChoice: cointop.CoinGecko,
|
||||
CacheDir: cointop.DefaultCacheDir,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if total {
|
||||
return ct.PrintTotalHoldings()
|
||||
}
|
||||
|
||||
return ct.PrintHoldingsTable()
|
||||
},
|
||||
}
|
||||
|
||||
holdingsCmd.Flags().BoolVarP(&total, "total", "t", false, "Show total only")
|
||||
holdingsCmd.Flags().BoolVarP(&noCache, "no-cache", "", false, "No cache")
|
||||
holdingsCmd.Flags().StringVarP(&config, "config", "c", "", fmt.Sprintf("Config filepath. (default %s)", cointop.DefaultConfigFilepath))
|
||||
|
||||
return holdingsCmd
|
||||
}
|
30
cointop/cmd/price.go
Normal file
30
cointop/cmd/price.go
Normal file
@ -0,0 +1,30 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/miguelmota/cointop/cointop"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// PriceCmd ...
|
||||
func PriceCmd() *cobra.Command {
|
||||
var apiChoice, coin, currency string
|
||||
|
||||
priceCmd := &cobra.Command{
|
||||
Use: "price",
|
||||
Short: "Displays the current price of a coin",
|
||||
Long: `The price command display the current price of a coin`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return cointop.PrintPrice(&cointop.PriceConfig{
|
||||
Coin: coin,
|
||||
Currency: currency,
|
||||
APIChoice: apiChoice,
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
priceCmd.Flags().StringVarP(&coin, "coin", "c", "bitcoin", "Full name of the coin (default \"bitcoin\")")
|
||||
priceCmd.Flags().StringVarP(¤cy, "currency", "f", "USD", "The currency to convert to (default \"USD\")")
|
||||
priceCmd.Flags().StringVarP(&apiChoice, "api", "a", cointop.CoinGecko, "API choice. Available choices are \"coinmarketcap\" and \"coingecko\"")
|
||||
|
||||
return priceCmd
|
||||
}
|
29
cointop/cmd/reset.go
Normal file
29
cointop/cmd/reset.go
Normal file
@ -0,0 +1,29 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/miguelmota/cointop/cointop"
|
||||
"github.com/miguelmota/cointop/cointop/common/filecache"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// ResetCmd ...
|
||||
func ResetCmd() *cobra.Command {
|
||||
cacheDir := filecache.DefaultCacheDir
|
||||
|
||||
resetCmd := &cobra.Command{
|
||||
Use: "reset",
|
||||
Short: "Resets the config and clear the cache",
|
||||
Long: `The reset command resets the config and clears the cache`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
// NOTE: if reset command, reset but don't run cointop
|
||||
return cointop.Reset(&cointop.ResetConfig{
|
||||
Log: true,
|
||||
CacheDir: cacheDir,
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
resetCmd.Flags().StringVarP(&cacheDir, "cache-dir", "", cacheDir, "Cache directory")
|
||||
|
||||
return resetCmd
|
||||
}
|
108
cointop/cmd/root.go
Normal file
108
cointop/cmd/root.go
Normal file
@ -0,0 +1,108 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/miguelmota/cointop/cointop"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// RootCmd ...
|
||||
func RootCmd() *cobra.Command {
|
||||
var version, test, clean, reset, hideMarketbar, hideChart, hideStatusbar, onlyTable, silent, noCache bool
|
||||
var refreshRate uint
|
||||
var config, cmcAPIKey, apiChoice, colorscheme string
|
||||
perPage := cointop.DefaultPerPage
|
||||
cacheDir := cointop.DefaultCacheDir
|
||||
|
||||
rootCmd := &cobra.Command{
|
||||
Use: "cointop",
|
||||
Short: "Cointop is an interactive terminal based app for tracking cryptocurrencies",
|
||||
Long: `
|
||||
_ _
|
||||
___ ___ (_)_ __ | |_ ___ _ __
|
||||
/ __/ _ \| | '_ \| __/ _ \| '_ \
|
||||
| (_| (_) | | | | | || (_) | |_) |
|
||||
\___\___/|_|_| |_|\__\___/| .__/
|
||||
|_|
|
||||
|
||||
Cointop is a fast and lightweight interactive terminal based UI application for tracking and monitoring cryptocurrency coin stats in real-time.
|
||||
|
||||
See git.io/cointop for more info.`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if version {
|
||||
cointop.PrintVersion()
|
||||
return nil
|
||||
}
|
||||
|
||||
if test {
|
||||
// TODO: deprecate test flag, only have test command
|
||||
doTest()
|
||||
return nil
|
||||
}
|
||||
|
||||
// NOTE: if reset flag enabled, reset and run cointop
|
||||
if reset {
|
||||
if err := cointop.Reset(&cointop.ResetConfig{
|
||||
Log: !silent,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: if clean flag enabled, clean and run cointop
|
||||
if clean {
|
||||
if err := cointop.Clean(&cointop.CleanConfig{
|
||||
Log: !silent,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var refreshRateP *uint
|
||||
if cmd.Flags().Changed("refresh-rate") {
|
||||
refreshRateP = &refreshRate
|
||||
}
|
||||
|
||||
ct, err := cointop.NewCointop(&cointop.Config{
|
||||
CacheDir: cacheDir,
|
||||
NoCache: noCache,
|
||||
ConfigFilepath: config,
|
||||
CoinMarketCapAPIKey: cmcAPIKey,
|
||||
APIChoice: apiChoice,
|
||||
Colorscheme: colorscheme,
|
||||
HideMarketbar: hideMarketbar,
|
||||
HideChart: hideChart,
|
||||
HideStatusbar: hideStatusbar,
|
||||
OnlyTable: onlyTable,
|
||||
RefreshRate: refreshRateP,
|
||||
PerPage: perPage,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ct.Run()
|
||||
},
|
||||
}
|
||||
|
||||
rootCmd.Flags().BoolVarP(&version, "version", "v", false, "Display current version")
|
||||
rootCmd.Flags().BoolVarP(&test, "test", "", false, "Run test (for Homebrew)")
|
||||
rootCmd.Flags().BoolVarP(&clean, "clean", "", false, "Wipe clean the cache")
|
||||
rootCmd.Flags().BoolVarP(&reset, "reset", "", false, "Reset the config. Make sure to backup any relevant changes first!")
|
||||
rootCmd.Flags().BoolVarP(&hideMarketbar, "hide-marketbar", "", false, "Hide the top marketbar")
|
||||
rootCmd.Flags().BoolVarP(&hideChart, "hide-chart", "", false, "Hide the chart view")
|
||||
rootCmd.Flags().BoolVarP(&hideStatusbar, "hide-statusbar", "", false, "Hide the bottom statusbar")
|
||||
rootCmd.Flags().BoolVarP(&onlyTable, "only-table", "", false, "Show only the table. Hides the chart and top and bottom bars")
|
||||
rootCmd.Flags().BoolVarP(&silent, "silent", "s", false, "Silence log ouput")
|
||||
rootCmd.Flags().BoolVarP(&noCache, "no-cache", "", false, "No cache")
|
||||
rootCmd.Flags().UintVarP(&refreshRate, "refresh-rate", "r", 60, "Refresh rate in seconds. Set to 0 to not auto-refresh")
|
||||
rootCmd.Flags().UintVarP(&perPage, "per-page", "", perPage, "Per page")
|
||||
rootCmd.Flags().StringVarP(&config, "config", "c", "", fmt.Sprintf("Config filepath. (default %s)", cointop.DefaultConfigFilepath))
|
||||
rootCmd.Flags().StringVarP(&cmcAPIKey, "coinmarketcap-api-key", "", "", "Set the CoinMarketCap API key")
|
||||
rootCmd.Flags().StringVarP(&apiChoice, "api", "", cointop.CoinGecko, "API choice. Available choices are \"coinmarketcap\" and \"coingecko\"")
|
||||
rootCmd.Flags().StringVarP(&colorscheme, "colorscheme", "", "", "Colorscheme to use (default \"cointop\"). To install standard themes, do:\n\ngit clone git@github.com:cointop-sh/colors.git ~/.config/cointop/colors\n\nSee git.io/cointop#colorschemes for more info.")
|
||||
rootCmd.Flags().StringVarP(&cacheDir, "cache-dir", "", cacheDir, "Cache directory")
|
||||
|
||||
return rootCmd
|
||||
}
|
44
cointop/cmd/server.go
Normal file
44
cointop/cmd/server.go
Normal file
@ -0,0 +1,44 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
cssh "github.com/miguelmota/cointop/cointop/ssh"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// ServerCmd ...
|
||||
func ServerCmd() *cobra.Command {
|
||||
var port uint = 22
|
||||
var address string = "0.0.0.0"
|
||||
var idleTimeout uint = 60
|
||||
var executableBinary string = "cointop"
|
||||
var hostKeyFile string = cssh.DefaultHostKeyFile
|
||||
|
||||
serverCmd := &cobra.Command{
|
||||
Use: "server",
|
||||
Short: "Run cintop SSH Server",
|
||||
Long: `Run cointop SSH server`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
server := cssh.NewServer(&cssh.Config{
|
||||
Address: address,
|
||||
Port: port,
|
||||
IdleTimeout: time.Duration(int(idleTimeout)) * time.Second,
|
||||
ExecutableBinary: executableBinary,
|
||||
HostKeyFile: hostKeyFile,
|
||||
})
|
||||
|
||||
fmt.Printf("Running SSH server on port %v\n", port)
|
||||
return server.ListenAndServe()
|
||||
},
|
||||
}
|
||||
|
||||
serverCmd.Flags().UintVarP(&port, "port", "p", port, "Port")
|
||||
serverCmd.Flags().StringVarP(&address, "address", "a", address, "Address")
|
||||
serverCmd.Flags().UintVarP(&idleTimeout, "idle-timeout", "t", idleTimeout, "Idle timeout in seconds")
|
||||
serverCmd.Flags().StringVarP(&executableBinary, "binary", "b", executableBinary, "Executable binary path")
|
||||
serverCmd.Flags().StringVarP(&hostKeyFile, "host-key-file", "k", hostKeyFile, "Host key file")
|
||||
|
||||
return serverCmd
|
||||
}
|
33
cointop/cmd/test.go
Normal file
33
cointop/cmd/test.go
Normal file
@ -0,0 +1,33 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/miguelmota/cointop/cointop"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// TestCmd ...
|
||||
func TestCmd() *cobra.Command {
|
||||
testCmd := &cobra.Command{
|
||||
Use: "test",
|
||||
Short: "Runs tests",
|
||||
Long: `The test command runs tests for Homebrew`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
doTest()
|
||||
},
|
||||
}
|
||||
|
||||
return testCmd
|
||||
}
|
||||
|
||||
// DoTest ...
|
||||
func doTest() {
|
||||
ct, err := cointop.NewCointop(&cointop.Config{
|
||||
NoPrompts: true,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ct.Exit()
|
||||
}
|
20
cointop/cmd/version.go
Normal file
20
cointop/cmd/version.go
Normal file
@ -0,0 +1,20 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/miguelmota/cointop/cointop"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// VersionCmd ...
|
||||
func VersionCmd() *cobra.Command {
|
||||
versionCmd := &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Displays the current version",
|
||||
Long: `The version command displays the current version`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cointop.PrintVersion()
|
||||
},
|
||||
}
|
||||
|
||||
return versionCmd
|
||||
}
|
@ -65,6 +65,7 @@ type State struct {
|
||||
portfolioVisible bool
|
||||
portfolioUpdateMenuVisible bool
|
||||
refreshRate time.Duration
|
||||
running bool
|
||||
searchFieldVisible bool
|
||||
selectedCoin *Coin
|
||||
selectedChartRange string
|
||||
@ -151,6 +152,9 @@ var DefaultColorscheme = "cointop"
|
||||
// DefaultConfigFilepath ...
|
||||
var DefaultConfigFilepath = "~/.config/cointop/config.toml"
|
||||
|
||||
// DefaultCacheDir ...
|
||||
var DefaultCacheDir = filecache.DefaultCacheDir
|
||||
|
||||
// NewCointop initializes cointop
|
||||
func NewCointop(config *Config) (*Cointop, error) {
|
||||
var debug bool
|
||||
@ -390,6 +394,8 @@ func (ct *Cointop) Run() error {
|
||||
if err := ct.Keybindings(g); err != nil {
|
||||
return fmt.Errorf("keybindings: %v", err)
|
||||
}
|
||||
|
||||
ct.State.running = true
|
||||
if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
|
||||
return fmt.Errorf("main loop: %v", err)
|
||||
}
|
||||
@ -397,6 +403,11 @@ func (ct *Cointop) Run() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsRunning returns true if cointop is running
|
||||
func (ct *Cointop) IsRunning() bool {
|
||||
return ct.State.running
|
||||
}
|
||||
|
||||
// PriceConfig is the config options for the price command
|
||||
type PriceConfig struct {
|
||||
Coin string
|
||||
@ -421,7 +432,7 @@ func PrintPrice(config *PriceConfig) error {
|
||||
}
|
||||
|
||||
symbol := CurrencySymbol(config.Currency)
|
||||
fmt.Fprintf(os.Stdout, "%s%s", symbol, humanize.Commaf(price))
|
||||
fmt.Fprintf(os.Stdout, "%s%s\n", symbol, humanize.Commaf(price))
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -440,7 +451,7 @@ func Clean(config *CleanConfig) error {
|
||||
|
||||
cacheCleaned := false
|
||||
|
||||
cacheDir := filecache.DefaultCacheDir
|
||||
cacheDir := DefaultCacheDir
|
||||
if config.CacheDir != "" {
|
||||
cacheDir = config.CacheDir
|
||||
}
|
||||
|
62
cointop/common/asciitable/asciitable.go
Normal file
62
cointop/common/asciitable/asciitable.go
Normal file
@ -0,0 +1,62 @@
|
||||
package asciitable
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
// Input ...
|
||||
type Input struct {
|
||||
Data [][]string
|
||||
Headers []string
|
||||
Alignment []int
|
||||
}
|
||||
|
||||
// AsciiTable ...
|
||||
type AsciiTable struct {
|
||||
table *tablewriter.Table
|
||||
tableString *strings.Builder
|
||||
}
|
||||
|
||||
// NewAsciiTable ...
|
||||
func NewAsciiTable(input *Input) *AsciiTable {
|
||||
tableString := &strings.Builder{}
|
||||
alignment := make([]int, len(input.Alignment))
|
||||
for i, value := range input.Alignment {
|
||||
switch value {
|
||||
case -1:
|
||||
alignment[i] = 3
|
||||
case 0:
|
||||
alignment[i] = 1
|
||||
case 1:
|
||||
alignment[i] = 2
|
||||
}
|
||||
}
|
||||
|
||||
table := tablewriter.NewWriter(tableString)
|
||||
table.SetAutoWrapText(false)
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table.SetHeaderAlignment(tablewriter.ALIGN_RIGHT)
|
||||
table.SetColumnAlignment(alignment)
|
||||
table.SetCenterSeparator("")
|
||||
table.SetColumnSeparator("")
|
||||
table.SetRowSeparator("")
|
||||
table.SetHeaderLine(false)
|
||||
table.SetBorder(false)
|
||||
table.SetTablePadding("\t")
|
||||
table.SetNoWhiteSpace(true)
|
||||
table.SetHeader(input.Headers)
|
||||
table.AppendBulk(input.Data)
|
||||
|
||||
return &AsciiTable{
|
||||
table: table,
|
||||
tableString: tableString,
|
||||
}
|
||||
}
|
||||
|
||||
// String ...
|
||||
func (t *AsciiTable) String() string {
|
||||
t.table.Render()
|
||||
return t.tableString.String()
|
||||
}
|
@ -358,6 +358,9 @@ func (ct *Cointop) LastPage() error {
|
||||
// IsFirstRow returns true if cursor is on first row
|
||||
func (ct *Cointop) IsFirstRow() bool {
|
||||
ct.debuglog("isFirstRow()")
|
||||
if ct.Views.Table.Backing() == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
_, y := ct.Views.Table.Backing().Origin()
|
||||
_, cy := ct.Views.Table.Backing().Cursor()
|
||||
@ -368,6 +371,9 @@ func (ct *Cointop) IsFirstRow() bool {
|
||||
// IsLastRow returns true if cursor is on last row
|
||||
func (ct *Cointop) IsLastRow() bool {
|
||||
ct.debuglog("isLastRow()")
|
||||
if ct.Views.Table.Backing() == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
_, y := ct.Views.Table.Backing().Origin()
|
||||
_, cy := ct.Views.Table.Backing().Cursor()
|
||||
@ -391,6 +397,9 @@ func (ct *Cointop) IsLastPage() bool {
|
||||
// IsPageFirstLine returns true if the cursor is on the visible first row
|
||||
func (ct *Cointop) IsPageFirstLine() bool {
|
||||
ct.debuglog("isPageFirstLine()")
|
||||
if ct.Views.Table.Backing() == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
_, cy := ct.Views.Table.Backing().Cursor()
|
||||
return cy == 0
|
||||
@ -399,6 +408,9 @@ func (ct *Cointop) IsPageFirstLine() bool {
|
||||
// IsPageMiddleLine returns true if the cursor is on the visible middle row
|
||||
func (ct *Cointop) IsPageMiddleLine() bool {
|
||||
ct.debuglog("isPageMiddleLine()")
|
||||
if ct.Views.Table.Backing() == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
_, cy := ct.Views.Table.Backing().Cursor()
|
||||
_, sy := ct.Views.Table.Backing().Size()
|
||||
@ -443,6 +455,10 @@ func (ct *Cointop) GoToGlobalIndex(idx int) error {
|
||||
// HighlightRow highlights the row at index
|
||||
func (ct *Cointop) HighlightRow(idx int) error {
|
||||
ct.debuglog("highlightRow()")
|
||||
if ct.Views.Table.Backing() == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
ct.Views.Table.Backing().SetOrigin(0, 0)
|
||||
ct.Views.Table.Backing().SetCursor(0, 0)
|
||||
ox, _ := ct.Views.Table.Backing().Origin()
|
||||
|
@ -2,11 +2,15 @@ package cointop
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/miguelmota/cointop/cointop/common/asciitable"
|
||||
"github.com/miguelmota/cointop/cointop/common/humanize"
|
||||
"github.com/miguelmota/cointop/cointop/common/pad"
|
||||
)
|
||||
|
||||
@ -303,3 +307,50 @@ func normalizeFloatString(input string) string {
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// PrintHoldingsTable prints the holdings in an ASCII table
|
||||
func (ct *Cointop) PrintHoldingsTable() error {
|
||||
ct.UpdateCoins() // fetches latest data
|
||||
holdings := ct.GetPortfolioSlice()
|
||||
total := ct.GetPortfolioTotal()
|
||||
data := make([][]string, len(holdings))
|
||||
symbol := ct.CurrencySymbol()
|
||||
|
||||
for _, entry := range holdings {
|
||||
percentHoldings := (entry.Balance / total) * 1e2
|
||||
if math.IsNaN(percentHoldings) {
|
||||
percentHoldings = 0
|
||||
}
|
||||
|
||||
data = append(data, []string{
|
||||
entry.Name,
|
||||
entry.Symbol,
|
||||
humanize.Commaf(entry.Price),
|
||||
humanize.Commaf(entry.Holdings),
|
||||
humanize.Commaf(entry.Balance),
|
||||
fmt.Sprintf("%.2f%%", entry.PercentChange24H),
|
||||
fmt.Sprintf("%.2f%%", percentHoldings),
|
||||
})
|
||||
}
|
||||
|
||||
alignment := []int{-1, -1, 1, 1, 1, 1, 1}
|
||||
headers := []string{"name", "symbol", fmt.Sprintf("%sprice", symbol), "holdings", fmt.Sprintf("%sbalance", symbol), "24h%", "%holdings"}
|
||||
table := asciitable.NewAsciiTable(&asciitable.Input{
|
||||
Data: data,
|
||||
Headers: headers,
|
||||
Alignment: alignment,
|
||||
})
|
||||
|
||||
fmt.Println(table.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrintTotalHoldings prints the total holdings amount
|
||||
func (ct *Cointop) PrintTotalHoldings() error {
|
||||
ct.UpdateCoins() // fetches latest data
|
||||
total := ct.GetPortfolioTotal()
|
||||
symbol := ct.CurrencySymbol()
|
||||
|
||||
fmt.Fprintf(os.Stdout, "%s%s\n", symbol, humanize.Commaf(total))
|
||||
return nil
|
||||
}
|
||||
|
@ -3,6 +3,10 @@ package cointop
|
||||
// Size returns window width and height
|
||||
func (ct *Cointop) size() (int, int) {
|
||||
ct.debuglog("size()")
|
||||
if ct.g == nil {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
return ct.g.Size()
|
||||
}
|
||||
|
||||
|
@ -288,6 +288,10 @@ func (ct *Cointop) GetTableCoinsSlice() []*Coin {
|
||||
// HighlightedRowIndex returns the index of the highlighted row
|
||||
func (ct *Cointop) HighlightedRowIndex() int {
|
||||
ct.debuglog("HighlightedRowIndex()")
|
||||
if ct.Views.Table.Backing() == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
_, y := ct.Views.Table.Backing().Origin()
|
||||
_, cy := ct.Views.Table.Backing().Cursor()
|
||||
idx := y + cy
|
||||
|
@ -11,7 +11,7 @@ func (ct *Cointop) Update(f func() error) {
|
||||
ct.debuglog(fmt.Sprintf("Update()"))
|
||||
|
||||
if ct.g == nil {
|
||||
panic("gocui is not initialized")
|
||||
return
|
||||
}
|
||||
|
||||
ct.g.Update(func(g *gocui.Gui) error {
|
||||
|
1
go.mod
1
go.mod
@ -15,6 +15,7 @@ require (
|
||||
github.com/miguelmota/gocui v0.4.2
|
||||
github.com/miguelmota/termbox-go v0.0.0-20191229070316-58d4fcbce2a7
|
||||
github.com/mitchellh/go-wordwrap v1.0.0
|
||||
github.com/olekukonko/tablewriter v0.0.4
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/spf13/cobra v1.0.0
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
|
2
go.sum
2
go.sum
@ -86,6 +86,8 @@ github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUb
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
|
||||
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
|
Loading…
Reference in New Issue
Block a user