/
livepeer_cli.go
169 lines (152 loc) · 5.18 KB
/
livepeer_cli.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package main
import (
"bufio"
"fmt"
"math/rand"
"net/http"
"os"
"strconv"
"time"
"github.com/ethereum/go-ethereum/log"
"github.com/livepeer/go-livepeer/core"
"gopkg.in/urfave/cli.v1"
)
func main() {
app := cli.NewApp()
app.Name = "livepeer-cli"
app.Usage = "interact with local Livepeer node"
app.Flags = []cli.Flag{
cli.StringFlag{
Name: "http",
Usage: "local cli port",
Value: "7935",
},
cli.StringFlag{
Name: "host",
Usage: "host for the Livepeer node",
Value: "localhost",
},
cli.IntFlag{
Name: "loglevel",
Value: 4,
Usage: "log level to emit to the screen",
},
}
app.Action = func(c *cli.Context) error {
if c.Bool("version") {
fmt.Println("Version: " + core.LivepeerVersion)
}
// Set up the logger to print everything and the random generator
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(c.Int("loglevel")), log.StreamHandler(os.Stdout, log.TerminalFormat(true))))
rand.Seed(time.Now().UnixNano())
// Start the wizard and relinquish control
w := &wizard{
endpoint: fmt.Sprintf("http://%v:%v/status", c.String("host"), c.String("http")),
httpPort: c.String("http"),
host: c.String("host"),
in: bufio.NewReader(os.Stdin),
}
w.orchestrator = w.isOrchestrator()
w.testnet = w.onTestnet()
w.run()
return nil
}
app.Version = core.LivepeerVersion
app.Run(os.Args)
}
type wizard struct {
endpoint string // Local livepeer node
httpPort string
host string
orchestrator bool
testnet bool
in *bufio.Reader // Wrapper around stdin to allow reading user input
}
type wizardOpt struct {
desc string
invoke func()
testnet bool
orchestrator bool
notOrchestrator bool
}
func (w *wizard) initializeOptions() []wizardOpt {
options := []wizardOpt{
{desc: "Get node status", invoke: func() { w.stats(w.orchestrator) }},
{desc: "View protocol parameters", invoke: w.protocolStats},
{desc: "List registered orchestrators", invoke: func() { w.registeredOrchestratorStats() }},
{desc: "Invoke \"initialize round\"", invoke: w.initializeRound},
{desc: "Invoke \"bond\"", invoke: w.bond},
{desc: "Invoke \"unbond\"", invoke: w.unbond},
{desc: "Invoke \"rebond\"", invoke: w.rebond},
{desc: "Invoke \"withdraw stake\" (LPT)", invoke: w.withdrawStake},
{desc: "Invoke \"withdraw fees\" (ETH)", invoke: w.withdrawFees},
{desc: "Invoke \"claim\" (for rewards and fees)", invoke: w.claimRewardsAndFees},
{desc: "Invoke \"transfer\" (LPT)", invoke: w.transferTokens},
{desc: "Invoke \"reward\"", invoke: w.callReward, orchestrator: true},
{desc: "Invoke multi-step \"become an orchestrator\"", invoke: w.activateOrchestrator, orchestrator: true},
{desc: "Set orchestrator config", invoke: w.setOrchestratorConfig, orchestrator: true},
{desc: "Set broadcast config", invoke: w.setBroadcastConfig, notOrchestrator: true},
{desc: "Set Eth gas price", invoke: w.setGasPrice},
{desc: "Get test LPT", invoke: w.requestTokens, testnet: true},
{desc: "Get test ETH", invoke: func() {
fmt.Print("For Rinkeby Eth, go to the Rinkeby faucet (https://faucet.rinkeby.io/).")
w.read()
}, testnet: true},
}
return options
}
func (w *wizard) filterOptions(options []wizardOpt) []wizardOpt {
filtered := make([]wizardOpt, 0, len(options))
for _, opt := range options {
if opt.testnet && !w.testnet {
continue
}
if !opt.orchestrator && !opt.notOrchestrator || w.orchestrator && opt.orchestrator || !w.orchestrator && opt.notOrchestrator {
filtered = append(filtered, opt)
}
}
return filtered
}
func (w *wizard) run() {
// Make sure there is a local node running
_, err := http.Get(w.endpoint)
if err != nil {
log.Error(fmt.Sprintf("Cannot find local node. Is your node running on http:%v?", w.httpPort))
return
}
fmt.Println("+-----------------------------------------------------------+")
fmt.Println("| Welcome to livepeer-cli, your Livepeer command line tool |")
fmt.Println("| |")
fmt.Println("| This tool lets you interact with a local Livepeer node |")
fmt.Println("| and participate in the Livepeer protocol without the |")
fmt.Println("| hassle that it would normally entail. |")
fmt.Println("| |")
fmt.Println("+-----------------------------------------------------------+")
fmt.Println()
w.stats(w.orchestrator)
options := w.filterOptions(w.initializeOptions())
// Basics done, loop ad infinitum about what to do
for {
fmt.Println()
fmt.Println("What would you like to do? (default = stats)")
for i, opt := range options {
fmt.Printf("%d. %s\n", i+1, opt.desc)
}
w.doCLIOpt(w.read(), options)
}
}
func (w *wizard) doCLIOpt(choice string, options []wizardOpt) {
index, err := strconv.ParseInt(choice, 10, 64)
index--
if err == nil && index >= 0 && index < int64(len(options)) {
options[index].invoke()
return
}
log.Error("That's not something I can do")
}
var RinkebyNetworkId = "4"
var DevenvNetworkId = "54321"
func (w *wizard) onTestnet() bool {
nID := httpGet(fmt.Sprintf("http://%v:%v/EthNetworkID", w.host, w.httpPort))
return nID == RinkebyNetworkId || nID == DevenvNetworkId
}