diff --git a/cmd/geth/config.go b/cmd/geth/config.go index d3600f1416..3037a3f5ba 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/contracts/release" + "github.com/ethereum/go-ethereum/dashboard" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/params" @@ -76,10 +77,11 @@ type ethstatsConfig struct { } type gethConfig struct { - Eth eth.Config - Shh whisper.Config - Node node.Config - Ethstats ethstatsConfig + Eth eth.Config + Shh whisper.Config + Node node.Config + Ethstats ethstatsConfig + Dashboard dashboard.Config } func loadConfig(file string, cfg *gethConfig) error { @@ -110,9 +112,10 @@ func defaultNodeConfig() node.Config { func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { // Load defaults. cfg := gethConfig{ - Eth: eth.DefaultConfig, - Shh: whisper.DefaultConfig, - Node: defaultNodeConfig(), + Eth: eth.DefaultConfig, + Shh: whisper.DefaultConfig, + Node: defaultNodeConfig(), + Dashboard: dashboard.DefaultConfig, } // Load config file. @@ -134,6 +137,7 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { } utils.SetShhConfig(ctx, stack, &cfg.Shh) + utils.SetDashboardConfig(ctx, &cfg.Dashboard) return stack, cfg } @@ -153,6 +157,9 @@ func makeFullNode(ctx *cli.Context) *node.Node { utils.RegisterEthService(stack, &cfg.Eth) + if ctx.GlobalBool(utils.DashboardEnabledFlag.Name) { + utils.RegisterDashboardService(stack, &cfg.Dashboard) + } // Whisper must be explicitly enabled by specifying at least 1 whisper flag or in dev mode shhEnabled := enableWhisper(ctx) shhAutoEnabled := !ctx.GlobalIsSet(utils.WhisperEnabledFlag.Name) && ctx.GlobalIsSet(utils.DevModeFlag.Name) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 8166c9ce80..a0b15497dd 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -61,6 +61,11 @@ var ( utils.DataDirFlag, utils.KeyStoreDirFlag, utils.NoUSBFlag, + utils.DashboardEnabledFlag, + utils.DashboardAddrFlag, + utils.DashboardPortFlag, + utils.DashboardRefreshFlag, + utils.DashboardAssetsFlag, utils.EthashCacheDirFlag, utils.EthashCachesInMemoryFlag, utils.EthashCachesOnDiskFlag, diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index 80861d8525..85720fa774 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -92,6 +92,16 @@ var AppHelpFlagGroups = []flagGroup{ utils.EthashDatasetsOnDiskFlag, }, }, + { + Name: "DASHBOARD", + Flags: []cli.Flag{ + utils.DashboardEnabledFlag, + utils.DashboardAddrFlag, + utils.DashboardPortFlag, + utils.DashboardRefreshFlag, + utils.DashboardAssetsFlag, + }, + }, { Name: "TRANSACTION POOL", Flags: []cli.Flag{ diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 5ab6047e83..40049e1a9b 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -36,6 +36,7 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/dashboard" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/gasprice" @@ -177,6 +178,31 @@ var ( Name: "lightkdf", Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength", } + // Dashboard settings + DashboardEnabledFlag = cli.BoolFlag{ + Name: "dashboard", + Usage: "Enable the dashboard", + } + DashboardAddrFlag = cli.StringFlag{ + Name: "dashboard.addr", + Usage: "Dashboard listening interface", + Value: dashboard.DefaultConfig.Host, + } + DashboardPortFlag = cli.IntFlag{ + Name: "dashboard.host", + Usage: "Dashboard listening port", + Value: dashboard.DefaultConfig.Port, + } + DashboardRefreshFlag = cli.DurationFlag{ + Name: "dashboard.refresh", + Usage: "Dashboard metrics collection refresh rate", + Value: dashboard.DefaultConfig.Refresh, + } + DashboardAssetsFlag = cli.StringFlag{ + Name: "dashboard.assets", + Usage: "Developer flag to serve the dashboard from the local file system (default: \"\")", + Value: dashboard.DefaultConfig.Assets, + } // Ethash settings EthashCacheDirFlag = DirectoryFlag{ Name: "ethash.cachedir", @@ -997,6 +1023,14 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { } } +// SetDashboardConfig applies dashboard related command line flags to the config. +func SetDashboardConfig(ctx *cli.Context, cfg *dashboard.Config) { + cfg.Host = ctx.GlobalString(DashboardAddrFlag.Name) + cfg.Port = ctx.GlobalInt(DashboardPortFlag.Name) + cfg.Refresh = ctx.GlobalDuration(DashboardRefreshFlag.Name) + cfg.Assets = ctx.GlobalString(DashboardAssetsFlag.Name) +} + // RegisterEthService adds an Ethereum client to the stack. func RegisterEthService(stack *node.Node, cfg *eth.Config) { var err error @@ -1019,6 +1053,13 @@ func RegisterEthService(stack *node.Node, cfg *eth.Config) { } } +// RegisterDashboardService adds a dashboard to the stack. +func RegisterDashboardService(stack *node.Node, cfg *dashboard.Config) { + stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { + return dashboard.New(cfg) + }) +} + // RegisterShhService configures Whisper and adds it to the given node. func RegisterShhService(stack *node.Node, cfg *whisper.Config) { if err := stack.Register(func(n *node.ServiceContext) (node.Service, error) { diff --git a/dashboard/assets.go b/dashboard/assets.go new file mode 100644 index 0000000000..78f5491e51 --- /dev/null +++ b/dashboard/assets.go @@ -0,0 +1,260 @@ +// Code generated by go-bindata. +// sources: +// assets/dashboard.html +// assets/js/handlers.js +// DO NOT EDIT! + +package dashboard + +import ( + "bytes" + "compress/gzip" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + "time" +) + +func bindataRead(data []byte, name string) ([]byte, error) { + gz, err := gzip.NewReader(bytes.NewBuffer(data)) + if err != nil { + return nil, fmt.Errorf("Read %q: %v", name, err) + } + + var buf bytes.Buffer + _, err = io.Copy(&buf, gz) + clErr := gz.Close() + + if err != nil { + return nil, fmt.Errorf("Read %q: %v", name, err) + } + if clErr != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +type asset struct { + bytes []byte + info os.FileInfo +} + +type bindataFileInfo struct { + name string + size int64 + mode os.FileMode + modTime time.Time +} + +func (fi bindataFileInfo) Name() string { + return fi.name +} +func (fi bindataFileInfo) Size() int64 { + return fi.size +} +func (fi bindataFileInfo) Mode() os.FileMode { + return fi.mode +} +func (fi bindataFileInfo) ModTime() time.Time { + return fi.modTime +} +func (fi bindataFileInfo) IsDir() bool { + return false +} +func (fi bindataFileInfo) Sys() interface{} { + return nil +} + +var _dashboardHtml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5a\xdb\x6e\xdb\x3c\x12\xbe\x2f\xd0\x77\xe0\xaf\xde\x2e\xc5\xd8\x29\xb6\x45\x57\x36\xd0\xa6\x45\xb7\x40\xf7\x00\x34\x0b\xec\x5e\x19\x34\x39\x96\xe8\x50\xa4\x4a\x52\x76\xfc\xf6\x0b\x4a\x94\xe3\x93\x2c\xd9\x71\x8b\xe4\x47\xae\x6c\x69\x8e\x9c\x8f\xc3\xd1\x0c\x98\xfc\xf1\xf9\x5f\x37\xb7\xff\xfb\xf7\x17\x94\xb9\x5c\x8e\x5f\xbf\x4a\xfc\x2f\x92\x54\xa5\xa3\x08\x54\x34\x7e\xfd\x0a\x21\x84\x92\x0c\x28\x0f\xff\xab\xe7\x1c\x1c\x45\x2c\xa3\xc6\x82\x1b\x45\xa5\x9b\xe1\xf7\xd1\x1e\x3d\x73\xae\xc0\xf0\xb3\x14\x8b\x51\xf4\x5f\xfc\x9f\x8f\xf8\x46\xe7\x05\x75\x62\x2a\x21\x42\x4c\x2b\x07\xca\x8d\xa2\x6f\x5f\x46\xc0\x53\xd8\x17\x57\x34\x87\x51\xb4\x10\xb0\x2c\xb4\x71\x1b\x12\x4b\xc1\x5d\x36\xe2\xb0\x10\x0c\x70\xf5\xf0\x17\x24\x94\x70\x82\x4a\x6c\x19\x95\x30\x1a\x78\x6d\x1b\xfa\x9c\x70\x12\xc6\x5f\x35\xfa\xe2\x32\x30\x50\xe6\xe8\x33\xb5\xd9\x54\x53\xc3\x13\x52\x13\xb7\xf8\xa5\x50\x77\xc8\x80\x1c\x45\x36\xd3\xc6\xb1\xd2\x21\xc1\xb4\x8a\x90\x5b\x15\x30\x8a\x44\x4e\x53\x20\x82\xe9\x08\x65\x06\x66\xa3\xc8\xaf\xd4\x7e\x20\x04\x82\xfa\x58\x9b\x94\xcc\xe8\xc2\x0b\xc5\x9e\x8f\x1c\xd0\xbf\x2d\xca\xb8\x9a\xdb\x98\x49\x5d\xf2\x99\xa4\x06\x62\xa6\x73\x42\xe7\xf4\x9e\x48\x31\xb5\xc4\x2d\x85\x73\x60\xf0\x54\x6b\x67\x9d\xa1\x05\xb9\x8e\xaf\xe3\x77\x84\x59\x4b\xd6\xef\xe2\x5c\xa8\x98\x59\x1b\x05\xdf\xdd\x4a\x82\xcd\x00\x5c\x84\xc8\xf8\x51\xe6\x67\x5a\x39\x4c\x97\x60\x75\x0e\xe4\x6d\xfc\x2e\xbe\xaa\x2c\x6f\xbe\xfe\x75\xc6\x53\x50\x0e\x24\x48\x49\xc9\x20\xbe\x0e\xa6\x59\x69\x9d\xce\xdb\x8d\x36\x3b\x97\x84\xad\x1b\x1e\xa7\x9a\xaf\x10\x93\xd4\xda\x51\xa4\xe8\x02\xe7\x7c\x6b\xe3\x71\xb1\x68\xa8\x7e\xbb\x51\xa1\xc0\x20\x2f\xb3\xc9\xb5\xcb\x99\x53\xa1\x26\x6b\xf6\x5d\xce\x7d\xbd\x12\xe7\x1c\x5f\x23\x09\x33\x37\x61\x5a\x1e\x12\xd8\x15\x6a\x78\x91\x65\x46\x4b\x89\x7d\x56\xb4\xc9\xed\xca\x2a\xba\x98\x52\x83\x14\x5d\x4c\xaa\xad\x1e\xa1\x2a\x4c\xa3\x68\xaa\x0d\x07\xf3\x01\x5d\xfd\xed\x98\xaa\x4a\x1d\x0d\x88\xf1\x26\x6d\x62\x7f\x4e\x44\x8d\x09\x2b\x1c\x04\xe5\xe3\x44\x34\x6f\x67\x14\xcd\x28\x2e\xe8\x32\x1a\x27\x44\x8c\x51\x62\x0b\xaa\xda\xb2\xb0\xa2\x25\x84\x1e\x5b\x14\xe1\x62\xb1\x95\x48\x47\xe3\x2c\x81\x9a\x99\xb8\xf7\xc6\x3b\xe5\xfe\xc0\x18\x59\xc1\xc1\x07\x2a\x07\x55\x22\x8c\xbb\xa2\x2b\xb8\x5f\x77\x25\x82\xbd\x48\xb4\xb5\x1d\xfc\x9b\x89\x27\xa3\x4c\x70\x0e\x0a\x17\x46\x28\x87\xd6\xb4\xce\x88\x6f\xee\xaf\x4a\x17\x30\x27\xb4\xea\x92\xab\x64\x4b\xb9\x81\x7d\xb5\x2e\xdc\xc7\xe6\x5a\x5e\x8a\x71\x42\xf7\x80\xcc\x74\x0e\x01\xc9\xbf\xeb\x1c\x6a\x38\xb7\x59\x58\x06\x0b\xa3\x15\xe6\x7a\xa9\x3c\x6b\x0f\x50\x3b\x9c\x67\x99\x90\xbc\x57\xc4\x0e\xaf\xe2\xf0\xbe\x1d\xaf\x37\xde\xc0\x7b\x97\x10\x29\x7e\x89\xf6\xe1\x19\xda\x13\x52\xca\xbe\x40\xf5\xd7\xdc\x82\x29\x70\xe1\x02\xa6\xff\x04\xb7\xd4\xe6\x4e\xa8\xf4\x59\x21\xab\xd6\x6e\x87\xe0\x7b\xa7\x1e\xd6\x32\x78\x2c\xb6\x1d\xfa\x87\x4f\x19\x5d\x0e\xf6\xce\xe9\x22\x00\x7c\x7b\x5f\x68\x2d\x9f\x15\xb8\xae\x72\x39\x04\xbe\xf6\xff\x22\x09\x7b\x40\xef\x93\x4f\x55\x47\xa7\xb2\x39\x7f\xbf\xeb\xd4\x3e\x2b\x20\xa5\x4e\x6d\x08\xb7\xf7\xfd\x22\x20\xee\xe8\x7c\xf2\x00\xfa\x0f\x05\xdf\x32\x39\xac\x03\x8c\x3f\x56\xd6\x41\xfe\xac\x80\xb4\x95\xcb\x21\xec\xb5\xff\x17\x01\xf3\x80\xde\x27\x0f\x28\x93\x5a\x85\x8c\xfc\x24\x35\xbb\x63\x19\x15\xea\x59\xa1\x39\x5d\xbb\x1d\x22\xff\xb0\x8e\x8b\xa0\x7a\x44\xff\xd3\x40\xb7\x87\xc6\xa6\x7b\x38\x9b\xee\x7b\x0b\xd2\xaf\xb9\x68\xd3\xd5\xde\xc1\x54\xda\x9d\x2e\x7c\x7b\x27\x52\xea\x5b\x84\xc3\xea\x37\x1b\x0a\xa7\x8b\x89\xa2\x8b\x3e\x8d\xa7\xef\x1a\xbb\xb6\x59\x52\xed\xc8\x9a\x3f\x42\x46\xfb\xde\xf2\xc1\x9d\x53\x3a\x1d\xaf\xc8\xe9\x34\x95\xd0\xab\xcf\xa1\x55\x13\x56\xb5\x47\x8d\xd4\x81\x43\xd7\xd6\x29\xda\x9d\x6f\xdd\x48\x2b\xda\x46\xef\x42\x6e\xef\x7d\xb5\x2b\x0e\x01\xd7\xc2\x5b\xd0\x14\x9a\x11\x58\x37\xc2\x46\xa4\x59\x3d\x5c\x08\x78\xf8\xc6\xb3\x0f\xde\x7d\x87\x0a\xde\x1d\x1c\x3a\xfe\xfe\xf8\x56\x02\x13\x09\x33\xd7\x0b\xdf\xec\xfa\xf0\xb4\x00\x25\x36\xa7\x52\x8e\x7f\x38\xea\x84\x75\x82\xd9\x84\xd4\x6f\x12\x92\x5d\x5f\x28\x9f\x7f\xc1\x94\x61\x13\x20\x7d\x74\x7e\xb3\x67\xa6\x1e\x1a\xfd\x15\xf9\x3f\x36\x0f\x7f\xee\x2d\x1e\x0c\x7b\x45\x72\x43\xd5\xfd\xa4\xa0\x0a\x5a\xa7\x4e\xc7\x45\x7b\x21\xbe\x25\x9e\x0d\xc7\xff\x80\x5c\x9b\x15\x2a\xad\xdf\xc2\x01\xba\xba\xde\x93\xbc\x22\x11\xa1\x4a\x0b\x1b\x18\x0e\xcf\xaf\x8c\xf5\xb4\x0b\x57\x09\x80\xaa\x95\x4e\x9c\xd6\x72\xaa\xef\xcf\xac\x94\x0f\x08\x48\x5a\x58\xc0\x52\xa8\xbb\xfd\x73\xa6\x29\xf1\x65\xd1\xf7\xb4\xd9\x33\x77\x56\xad\x6d\xbc\xe0\x46\x17\xf5\xe7\xc5\x69\x2a\xd0\xe6\x74\xef\x4d\xb4\xab\x0e\x87\x73\x15\x71\xea\x68\x78\xd8\x30\x16\x0e\x97\x69\xe9\x9c\x56\x11\xa2\x46\x50\x0c\xf7\x05\x55\x1c\xb8\x8f\x8c\xb4\x07\x8e\xe4\xa5\x01\xc5\xb2\x73\xc3\x84\xb6\x21\x5f\x3b\x5a\x8f\xe0\xc2\x61\x77\xc6\x77\xd1\x5a\xf7\xe6\xf7\xcb\x9b\x68\xfc\x03\x9c\x13\x2a\xb5\x68\x70\x9e\xaf\xe8\x3c\x68\x3b\xdd\x19\xfe\x76\x77\x4e\xf8\xfa\x7a\x84\xa5\x9d\xac\x93\xba\x3d\xe5\x3c\xed\x37\x65\xdb\x89\x6b\x3f\x5e\x21\xfa\x19\x3c\x81\x77\xeb\x88\x0e\xdf\x08\x27\x1d\xd2\x8c\xaa\x05\xb5\xe1\x6b\xca\x9f\xc8\xdf\x85\x82\x1b\xdf\xab\x7a\xaf\x6b\xea\x85\x1d\xef\xc3\xd7\x5d\x52\xd1\x9f\xa9\x4e\x7e\x53\x53\x5d\x2a\x8e\x9c\xa1\xb3\x99\x60\x4d\xa9\x2c\x86\x05\x09\xa4\xdb\x9a\xf2\x52\x29\x5f\x2a\x65\x4f\x87\x5f\x2a\xe5\x4b\xa5\x7c\xa9\x94\x87\xac\x3d\xba\x52\x86\x63\xfa\x69\x95\xca\x2e\xfa\xb9\x5d\xed\x29\x36\x8f\xcf\x3c\xf6\x07\x19\x2d\x9c\x33\xad\x1d\x98\x8e\x99\x47\xcd\xd4\x63\xb0\x51\x94\x52\xd6\xb5\xee\x18\xde\x5f\xd7\x57\x4d\x10\x46\x9f\x9a\x7b\x35\xe8\x23\xcf\x85\x42\xb7\x90\x17\x92\x3a\x40\xd3\xd5\x43\x25\x58\xdf\x61\xd1\x52\x1b\x29\xa6\x31\xd3\x79\x34\xbe\x09\x4f\xed\xe9\x76\x34\xb0\x27\x41\x91\x90\xd6\x20\xd4\x11\xef\x0a\xe4\xae\xe2\xfd\xbd\x92\x58\x66\x44\xe1\x90\x35\xac\xf7\xad\x9d\xf9\xcf\x12\xcc\x8a\x0c\xe3\x41\xfc\x36\x3c\x54\xb7\x75\xe6\xd5\x3c\xae\x56\x38\xbe\x84\x09\xac\xb4\xf3\x76\xde\xc6\x03\x52\x50\x76\x47\x53\xe0\x8d\x41\x4f\x8a\x9b\x97\x97\x36\x5f\x65\x7d\x3c\xb7\x64\x18\x5f\xc5\x57\xeb\xc7\x8b\xe9\x6f\xbb\xf3\x35\xdf\xbd\xf2\x75\x41\x9b\x33\xa9\x1d\xb9\x8a\xdf\xc7\xd7\x4d\x08\xfd\x9b\x4b\x5a\xd8\xbb\xcd\x35\xdf\xba\xcc\xb5\x63\xa9\xc5\xd6\xdc\x92\x8c\x2a\x2e\xc1\xd8\x43\xbe\x25\x64\xaa\xf9\x6a\xfc\xfa\x55\x42\xc2\xbd\xc6\xff\x07\x00\x00\xff\xff\x29\x20\x88\x50\xe9\x28\x00\x00") + +func dashboardHtmlBytes() ([]byte, error) { + return bindataRead( + _dashboardHtml, + "dashboard.html", + ) +} + +func dashboardHtml() (*asset, error) { + bytes, err := dashboardHtmlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "dashboard.html", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _jsHandlersJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x57\xff\x6f\x9b\xc8\x13\xfd\xdd\x92\xff\x87\xf9\xf8\x23\xb5\x58\xa5\x60\xa7\x97\x6b\x64\x44\xa5\x36\x4d\xef\x7c\x4a\x2e\x55\x12\xa9\x3a\x45\x51\xb5\xc0\x00\xab\x2c\xbb\x68\x77\x49\x1a\x55\xfe\xdf\x4f\x0b\x18\x0c\xfe\x52\x7a\xca\x5d\xa4\x48\x78\x79\x6f\xde\x30\xfb\x66\x16\x4e\x53\x22\xb5\x13\x61\x4c\x0a\xa6\x95\x93\x30\x11\x10\xe6\x30\x4c\x90\x47\xe0\xc3\xf7\xf1\x08\x00\x00\x39\x09\x18\x46\x0b\x88\x09\x53\x38\x1e\xad\xc6\xa3\xf1\xc8\x75\xe1\x9c\x72\x84\xd0\x84\x80\x58\x48\xc8\x30\x13\xf2\x69\x3c\x7a\x20\x12\x42\xfd\x0d\x7c\x88\x44\x58\x64\xc8\xb5\x93\xa0\x3e\x63\x68\x2e\x3f\x3c\x2d\x23\x6b\x52\x41\x0d\xbf\xcc\x60\x32\xf5\x2a\x5a\x6f\x1d\x7c\xe0\xf8\x08\xe5\xb5\x15\xea\x6f\xf6\x3a\x23\xfd\x94\xe3\x02\x5e\x32\xca\xf1\xa5\x5d\x2d\x45\x44\x93\xc5\xfa\xbe\xf9\x63\x24\x40\xa6\x16\x70\x7b\x67\xb7\x8b\x06\xa5\x50\x9b\xe5\x0d\x68\x03\x5f\xc0\x44\x3d\x29\x8d\x99\x5b\x65\xe2\x52\x5e\x28\x9c\xd8\x5d\x68\x40\xc2\xfb\x44\x8a\x82\x47\xa7\x82\x09\xb9\x80\x89\x4c\x02\x62\xbd\x39\xb1\x61\x7e\x72\x6c\xc3\xfc\xf8\x17\x1b\x66\xce\x9b\xf9\x74\x8b\x29\x64\x84\xf2\x20\xeb\xed\x16\x29\x17\x94\xeb\x0f\xff\x9c\x39\x2c\xdb\x3d\xec\xdf\xc5\x03\xca\xed\x10\xff\x8f\xe3\xf8\x00\x7e\x3b\xd9\xa3\xa3\x99\xbd\xfe\xdf\xae\xcb\xc6\x23\x7e\xa1\x91\x4e\x17\x30\xef\x21\xaa\xed\xbd\xbd\x6b\x57\x57\xf5\xf5\xca\x1e\x8f\x56\xc6\x40\xbb\x3c\xa9\x25\x89\x63\x1a\x56\xee\xaa\x7f\x9c\x1e\xf6\x66\x8d\xda\x36\x67\xff\x46\xc7\x9d\x6d\xec\xff\xc2\xa4\xf9\x51\xee\x2e\x79\x60\x76\xe4\xa6\x12\x1e\xea\x51\x1b\x4e\xcc\xc6\xcf\x7e\x2d\x1d\x3a\xc8\xa0\x1d\xca\xdb\xd9\x70\x7f\x0e\x23\x0e\x49\x74\x1f\xf9\xb9\xdc\x39\x3f\x9e\xdb\xf3\x93\xb7\xf6\xd1\xec\xf8\xdf\x74\xe7\xcd\xe5\xc7\x4b\xb0\xee\x0b\x79\x2f\x32\xaa\xe8\x74\x01\x12\x33\xf1\x80\xa0\x34\xd1\x34\x84\x07\xc2\x0a\x54\x40\x62\x8d\x12\x22\x0c\x8a\x24\xa1\x3c\x19\x8f\x42\xc1\x95\x86\x8b\xb3\x8b\xcb\xab\xbf\xbe\x5e\xbf\xbf\xf8\x7c\x7e\xf6\xf5\x7c\x79\xb1\xbc\x01\x1f\x8e\x66\x33\xcf\x75\xbf\x7f\x77\xaa\x89\x75\x4d\xb2\x9c\xe1\x39\xcd\xa8\x5e\xad\x3c\x70\x5d\xb8\x20\xdf\x68\x56\x64\xc0\x8b\x2c\x40\x09\x22\xae\xa7\x6c\x99\x34\xa8\x12\xaf\xd6\x1a\x37\x57\xef\x3f\x7d\x5a\x9e\xee\x15\xa9\x6d\x3e\x44\xa5\x86\xee\x94\xf9\x7c\x75\x79\x7a\x76\x7d\x7d\x79\xb5\x57\x28\x97\x22\x44\xa5\x84\x1c\x22\xd5\x80\x7b\x62\xe3\x51\x5c\xf0\x50\x53\xc1\xa1\xc8\x23\xa2\xab\xbe\x55\x56\xa6\x92\xa9\xe9\xc2\x6a\x8b\x5c\x17\x3e\x51\xc6\x40\xa7\x08\x11\x51\x69\x20\x88\x8c\xe0\x91\xea\x14\x72\xa2\x74\x19\xb3\x42\xd2\xd8\x50\x9d\x0c\xb5\xa4\xa1\x82\xff\xf9\x3e\x14\x3c\xc2\x98\x72\x8c\xa6\x9b\x6d\xed\xba\x70\xca\x90\x48\xa0\x1c\x42\xa2\xb0\x1f\x9b\x28\x10\x39\x72\x8c\x20\xc0\x58\x48\x6c\x99\xbd\x13\xd0\x31\xe2\x4e\x35\x25\xc0\x87\xdb\x3b\xaf\x85\xf6\xe7\xd1\x21\xec\xce\xb0\xeb\x39\x73\x3b\xbb\x2b\xaf\x87\x09\xec\x63\xb5\xbc\xf6\x24\x07\x1f\x36\x0a\x56\x5b\xd4\xeb\x22\xdb\xcd\xeb\x82\x9b\x75\xaf\x53\xd7\xa5\x06\xaa\x20\x17\x4a\xd1\x80\x21\x68\x01\x09\x6a\x20\x5c\xe8\x14\x8d\xac\x52\x24\x41\x78\x4c\x29\x43\x88\x29\x63\x94\x27\x65\xf5\x89\x94\xe4\x49\x41\xf0\x04\x79\xa1\x52\x6b\x6a\x83\x12\x40\xb9\xd2\x48\xa2\x8e\x40\x5e\xe8\x92\x90\x52\xa5\xcd\x23\x68\x51\xfe\x0c\x30\xa1\x9c\x9b\x68\xc6\xdb\x4d\xc0\x96\x6a\x8e\x1b\xcb\x3c\x10\x35\x0f\x52\x3e\xa9\xc3\x90\x27\x3a\x85\xd7\x30\xf7\x80\xc2\x3b\x1f\x66\xf0\xe2\xc5\xce\x46\x7e\x77\x68\xe7\xeb\x38\x1e\xbc\x7e\x4d\x3b\x3e\xfb\x81\x63\x9c\x82\xab\x94\xc6\xda\xaa\x30\xb7\xf4\xce\xd1\x34\x43\x47\x15\x81\xd2\x92\xf2\xa4\x7f\xa3\xc9\xf7\x78\x3a\xf5\xba\x32\x87\xdc\xf6\x9c\x3a\x83\x9c\xba\x43\xb0\x9c\x9d\xc3\x92\xde\x1b\xad\xb1\xdc\xce\x80\xab\xfd\xed\x54\x4d\x17\x6b\x7a\xa8\x79\x76\x60\x24\xea\x42\xf2\x7a\x61\xb5\x31\x8f\x2a\x6c\x6f\xe8\x94\x0d\xb5\x7f\xe6\x18\xdc\x0f\x2d\x04\xbe\xef\xef\xf2\xdf\x4f\xb9\xaa\x2a\xd6\x4f\x19\x64\x37\x65\xd8\x5e\xff\x8c\xdc\x00\xf2\x81\x6d\xdc\xcc\xb8\x9c\x12\x6d\xe1\xb7\x0c\xdd\xbb\xb3\xc7\xd1\x07\x8b\xf2\x3c\x12\xc3\x8a\xd8\xd7\xda\x72\xf7\xc0\x7a\x36\x71\x9a\x5e\xd9\x0e\xf5\x0c\xdd\xb1\x6a\xbf\x32\x7f\x2b\x3f\x4a\xcd\x51\x41\xcd\x67\xa8\x32\x03\x39\x15\x2c\x2a\x87\x70\x58\x48\x89\x5c\x97\x2f\x50\x85\x5a\x8f\xe6\xe6\xa4\xad\x5e\xdc\x15\xca\x07\x94\xeb\x2f\x84\x8f\x65\xef\x00\x81\x0c\x75\x2a\x22\x13\x4e\x62\x28\x38\xc7\x50\x43\x91\x0b\x5e\xe3\x81\x09\xa5\xaa\x00\xed\x7d\x1f\xd6\x6f\x14\x56\xd3\x32\x35\xbc\xfa\x1a\xf8\x82\xc1\xb5\x08\xef\x51\x5b\x93\x47\xb5\x70\xdd\x09\xbc\x02\x26\x42\x62\x28\x4e\x2a\x94\x86\x57\x30\x71\x49\x4e\x27\xd3\xe6\xcc\xac\x02\x38\x82\xaf\x4f\xaf\x0d\x15\x7c\x40\xae\x3b\xdd\x59\x9e\xae\x2a\x01\x1f\xfe\xb8\xbe\xfc\xd3\xc9\x89\x54\x58\xc1\xca\x1d\xda\xac\x32\x8d\xc1\x2a\xa1\xbe\x0f\xbc\x60\x6c\xab\xcb\x3b\x03\xa8\x33\x84\xcc\xdf\xd6\x3b\x53\x6f\x50\x35\x79\x87\x4c\x28\xec\xd5\x06\x14\xea\x1b\x9a\xa1\x28\xb4\xd5\xd4\xcf\x86\x37\xb3\xd9\x6c\xea\xc1\xca\x6b\x37\xf8\x4c\x69\x12\x30\xaa\x52\x20\xf0\x88\x81\x2a\xcb\x07\x35\xc3\xbc\xbb\xd5\x27\xf0\xfb\xcf\xcb\x5a\x72\x3c\x6a\x22\x5a\x53\xef\xef\x00\x00\x00\xff\xff\x34\xdc\x83\x8a\xc5\x10\x00\x00") + +func jsHandlersJsBytes() ([]byte, error) { + return bindataRead( + _jsHandlersJs, + "js/handlers.js", + ) +} + +func jsHandlersJs() (*asset, error) { + bytes, err := jsHandlersJsBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "js/handlers.js", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +// Asset loads and returns the asset for the given name. +// It returns an error if the asset could not be found or +// could not be loaded. +func Asset(name string) ([]byte, error) { + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) + } + return a.bytes, nil + } + return nil, fmt.Errorf("Asset %s not found", name) +} + +// MustAsset is like Asset but panics when Asset would return an error. +// It simplifies safe initialization of global variables. +func MustAsset(name string) []byte { + a, err := Asset(name) + if err != nil { + panic("asset: Asset(" + name + "): " + err.Error()) + } + + return a +} + +// AssetInfo loads and returns the asset info for the given name. +// It returns an error if the asset could not be found or +// could not be loaded. +func AssetInfo(name string) (os.FileInfo, error) { + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) + } + return a.info, nil + } + return nil, fmt.Errorf("AssetInfo %s not found", name) +} + +// AssetNames returns the names of the assets. +func AssetNames() []string { + names := make([]string, 0, len(_bindata)) + for name := range _bindata { + names = append(names, name) + } + return names +} + +// _bindata is a table, holding each asset generator, mapped to its name. +var _bindata = map[string]func() (*asset, error){ + "dashboard.html": dashboardHtml, + "js/handlers.js": jsHandlersJs, +} + +// AssetDir returns the file names below a certain +// directory embedded in the file by go-bindata. +// For example if you run go-bindata on data/... and data contains the +// following hierarchy: +// data/ +// foo.txt +// img/ +// a.png +// b.png +// then AssetDir("data") would return []string{"foo.txt", "img"} +// AssetDir("data/img") would return []string{"a.png", "b.png"} +// AssetDir("foo.txt") and AssetDir("notexist") would return an error +// AssetDir("") will return []string{"data"}. +func AssetDir(name string) ([]string, error) { + node := _bintree + if len(name) != 0 { + cannonicalName := strings.Replace(name, "\\", "/", -1) + pathList := strings.Split(cannonicalName, "/") + for _, p := range pathList { + node = node.Children[p] + if node == nil { + return nil, fmt.Errorf("Asset %s not found", name) + } + } + } + if node.Func != nil { + return nil, fmt.Errorf("Asset %s not found", name) + } + rv := make([]string, 0, len(node.Children)) + for childName := range node.Children { + rv = append(rv, childName) + } + return rv, nil +} + +type bintree struct { + Func func() (*asset, error) + Children map[string]*bintree +} +var _bintree = &bintree{nil, map[string]*bintree{ + "dashboard.html": &bintree{dashboardHtml, map[string]*bintree{}}, + "js": &bintree{nil, map[string]*bintree{ + "handlers.js": &bintree{jsHandlersJs, map[string]*bintree{}}, + }}, +}} + +// RestoreAsset restores an asset under the given directory +func RestoreAsset(dir, name string) error { + data, err := Asset(name) + if err != nil { + return err + } + info, err := AssetInfo(name) + if err != nil { + return err + } + err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) + if err != nil { + return err + } + err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) + if err != nil { + return err + } + err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) + if err != nil { + return err + } + return nil +} + +// RestoreAssets restores an asset under the given directory recursively +func RestoreAssets(dir, name string) error { + children, err := AssetDir(name) + // File + if err != nil { + return RestoreAsset(dir, name) + } + // Dir + for _, child := range children { + err = RestoreAssets(dir, filepath.Join(name, child)) + if err != nil { + return err + } + } + return nil +} + +func _filePath(dir, name string) string { + cannonicalName := strings.Replace(name, "\\", "/", -1) + return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) +} + diff --git a/dashboard/assets/dashboard.html b/dashboard/assets/dashboard.html new file mode 100644 index 0000000000..5f25bf2512 --- /dev/null +++ b/dashboard/assets/dashboard.html @@ -0,0 +1,179 @@ + + +
+ + + + +