tendermint/main.go

195 lines
4.7 KiB
Go
Raw Normal View History

2016-01-10 14:49:09 -05:00
package main
import (
2016-01-12 19:07:45 -05:00
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"strconv"
"strings"
"github.com/tendermint/go-event-meter"
"github.com/tendermint/netmon/handlers"
"github.com/tendermint/netmon/types"
"github.com/codegangsta/cli"
2016-01-10 14:49:09 -05:00
. "github.com/tendermint/go-common"
cfg "github.com/tendermint/go-config"
2016-01-12 19:07:45 -05:00
"github.com/tendermint/go-events"
pcm "github.com/tendermint/go-process"
"github.com/tendermint/go-rpc/server"
"github.com/tendermint/go-rpc/types"
"github.com/tendermint/go-wire"
2016-01-10 14:49:09 -05:00
tmcfg "github.com/tendermint/tendermint/config/tendermint"
2016-01-12 19:07:45 -05:00
ctypes "github.com/tendermint/tendermint/rpc/core/types"
tmtypes "github.com/tendermint/tendermint/types"
2016-01-10 14:49:09 -05:00
)
func init() {
config := tmcfg.GetConfig("")
config.Set("log_level", "debug")
cfg.ApplyConfig(config) // Notify modules of new config
}
func main() {
2016-01-12 19:07:45 -05:00
app := cli.NewApp()
app.Name = "netmon"
app.Usage = "netmon [command] [args...]"
app.Commands = []cli.Command{
{
Name: "config",
Usage: "Create a config from a mintnet testnet",
ArgsUsage: "[chainID] [prefix] [N]",
Action: func(c *cli.Context) {
cmdConfig(c)
},
},
{
Name: "monitor",
Usage: "Monitor a chain",
ArgsUsage: "[config file]",
Action: func(c *cli.Context) {
cmdMonitor(c)
},
},
}
app.Run(os.Args)
}
func cmdMonitor(c *cli.Context) {
args := c.Args()
if len(args) != 1 {
Exit("monitor expectes 1 arg")
}
configFile := args[0]
b, err := ioutil.ReadFile(configFile)
if err != nil {
Exit(err.Error())
}
// for now we start with one blockchain;
// eventually more can be uploaded or created through endpoints
chainConfig := new(types.BlockchainConfig)
if err := json.Unmarshal(b, chainConfig); err != nil {
2016-01-10 14:49:09 -05:00
Exit(err.Error())
}
2016-01-12 19:07:45 -05:00
chainStatus := &types.ChainStatus{Config: chainConfig}
// start the event meter and listen for new blocks on each validator
for _, v := range chainConfig.Validators {
if err := v.NewEventMeter(); err != nil {
Exit(err.Error())
}
if err := v.EventMeter().Subscribe(tmtypes.EventStringNewBlock(), func(metric *eventmeter.EventMetric, data interface{}) {
// TODO: update chain status with block and metric
// chainStatus.NewBlock(data.(tmtypes.EventDataNewBlock).Block)
}); err != nil {
Exit(err.Error())
}
}
// the main object that watches for changes and serves the rpc requests
network := handlers.NewTendermintNetwork(chainStatus)
// the routes are functions on the network object
routes := handlers.Routes(network)
// register the result objects with wire
wire.RegisterInterface(
struct{ rpctypes.Result }{},
wire.ConcreteType{&events.EventResult{}, 0x1},
wire.ConcreteType{&ctypes.TendermintResult{}, 0x2},
wire.ConcreteType{&handlers.NetMonResult{}, 0x3},
)
// serve http and ws
mux := http.NewServeMux()
wm := rpcserver.NewWebsocketManager(routes, nil) // TODO: evsw
mux.HandleFunc("/websocket", wm.WebsocketHandler)
rpcserver.RegisterRPCFuncs(mux, routes)
if _, err := rpcserver.StartHTTPServer("0.0.0.0:46670", mux); err != nil {
2016-01-10 14:49:09 -05:00
Exit(err.Error())
}
2016-01-12 19:07:45 -05:00
2016-01-10 14:49:09 -05:00
TrapSignal(func() {
2016-01-12 19:07:45 -05:00
// TODO: clean shutdown server, maybe persist last state
for _, v := range chainConfig.Validators {
v.EventMeter().Stop()
}
2016-01-10 14:49:09 -05:00
})
}
2016-01-12 19:07:45 -05:00
func cmdConfig(c *cli.Context) {
args := c.Args()
if len(args) != 3 {
Exit("config expects 3 args")
}
id, prefix := args[0], args[1]
n, err := strconv.Atoi(args[2])
if err != nil {
Exit(err.Error())
}
chain, err := ConfigFromMachines(id, prefix, n)
if err != nil {
Exit(err.Error())
}
b, err := json.Marshal(chain)
if err != nil {
Exit(err.Error())
}
fmt.Println(string(b))
}
func ConfigFromMachines(chainID, prefix string, N int) (*types.BlockchainConfig, error) {
chain := &types.BlockchainConfig{
ID: chainID,
Validators: make([]*types.ChainValidator, N),
}
for i := 0; i < N; i++ {
id := fmt.Sprintf("%s%d", prefix, i+1)
ip, success := runProcessGetResult(id+"-ip", "docker-machine", []string{"ip", id})
if !success {
return nil, fmt.Errorf(ip)
}
val := &types.Validator{
ID: id,
// TODO: pubkey
}
chainVal := &types.ChainValidator{
Validator: val,
Addr: fmt.Sprintf("%s:%d", strings.Trim(ip, "\n"), 46657),
Index: i,
}
chain.Validators[i] = chainVal
}
return chain, nil
}
func runProcessGetResult(label string, command string, args []string) (string, bool) {
outFile := NewBufferCloser(nil)
fmt.Println(Green(command), Green(args))
proc, err := pcm.StartProcess(label, command, args, nil, outFile)
if err != nil {
return "", false
}
<-proc.WaitCh
if proc.ExitState.Success() {
fmt.Println(Blue(string(outFile.Bytes())))
return string(outFile.Bytes()), true
} else {
// Error!
fmt.Println(Red(string(outFile.Bytes())))
return string(outFile.Bytes()), false
}
}