v1.27.0-a #10
@ -445,7 +445,7 @@ func GetFullNodeAPIV1LotusProvider(ctx *cli.Context, ainfoCfg []string, opts ...
|
|||||||
for _, head := range heads {
|
for _, head := range heads {
|
||||||
v1api, closer, err := client.NewFullNodeRPCV1(ctx.Context, head.addr, head.header, rpcOpts...)
|
v1api, closer, err := client.NewFullNodeRPCV1(ctx.Context, head.addr, head.header, rpcOpts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("Not able to establish connection to node with addr: %s", head.addr)
|
log.Warnf("Not able to establish connection to node with addr: %s, Reason: %s", head.addr, err.Error())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fullNodes = append(fullNodes, v1api)
|
fullNodes = append(fullNodes, v1api)
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/BurntSushi/toml"
|
"github.com/BurntSushi/toml"
|
||||||
@ -176,7 +177,11 @@ func (deps *Deps) PopulateRemainingDeps(ctx context.Context, cctx *cli.Context,
|
|||||||
|
|
||||||
if deps.Full == nil {
|
if deps.Full == nil {
|
||||||
var fullCloser func()
|
var fullCloser func()
|
||||||
deps.Full, fullCloser, err = cliutil.GetFullNodeAPIV1LotusProvider(cctx, deps.Cfg.Apis.ChainApiInfo)
|
cfgApiInfo := deps.Cfg.Apis.ChainApiInfo
|
||||||
|
if v := os.Getenv("FULLNODE_API_INFO"); v != "" {
|
||||||
|
cfgApiInfo = []string{v}
|
||||||
|
}
|
||||||
|
deps.Full, fullCloser, err = cliutil.GetFullNodeAPIV1LotusProvider(cctx, cfgApiInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -267,6 +272,7 @@ func GetConfig(cctx *cli.Context, db *harmonydb.DB) (*config.LotusProviderConfig
|
|||||||
for _, k := range meta.Keys() {
|
for _, k := range meta.Keys() {
|
||||||
have = append(have, strings.Join(k, " "))
|
have = append(have, strings.Join(k, " "))
|
||||||
}
|
}
|
||||||
|
log.Infow("Using layer", "layer", layer, "config", lp)
|
||||||
}
|
}
|
||||||
_ = have // FUTURE: verify that required fields are here.
|
_ = have // FUTURE: verify that required fields are here.
|
||||||
// If config includes 3rd-party config, consider JSONSchema as a way that
|
// If config includes 3rd-party config, consider JSONSchema as a way that
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/BurntSushi/toml"
|
"github.com/BurntSushi/toml"
|
||||||
@ -155,6 +156,15 @@ var webCmd = &cli.Command{
|
|||||||
Usage: "Address to listen on",
|
Usage: "Address to listen on",
|
||||||
Value: "127.0.0.1:4701",
|
Value: "127.0.0.1:4701",
|
||||||
},
|
},
|
||||||
|
&cli.StringSliceFlag{
|
||||||
|
Name: "layers",
|
||||||
|
Usage: "list of layers to be interpreted (atop defaults). Default: base. Web will be added",
|
||||||
|
Value: cli.NewStringSlice("base"),
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "nosync",
|
||||||
|
Usage: "don't check full-node sync status",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
db, err := deps.MakeDB(cctx)
|
db, err := deps.MakeDB(cctx)
|
||||||
@ -174,7 +184,9 @@ var webCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err = cctx.Set("layers", "web"); err != nil {
|
layers := append([]string{"web"}, cctx.StringSlice("layers")...)
|
||||||
|
err = cctx.Set("layers", strings.Join(layers, ","))
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return runCmd.Action(cctx)
|
return runCmd.Action(cctx)
|
||||||
|
@ -29,7 +29,7 @@ type debug struct {
|
|||||||
|
|
||||||
func Routes(r *mux.Router, deps *deps.Deps) {
|
func Routes(r *mux.Router, deps *deps.Deps) {
|
||||||
d := debug{deps}
|
d := debug{deps}
|
||||||
r.Methods("GET").Path("chain-state-sse").HandlerFunc(d.chainStateSSE)
|
r.HandleFunc("/chain-state-sse", d.chainStateSSE)
|
||||||
}
|
}
|
||||||
|
|
||||||
type rpcInfo struct {
|
type rpcInfo struct {
|
||||||
@ -79,29 +79,24 @@ func (d *debug) chainStateSSE(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
apiInfos := map[string][]byte{} // api address -> token
|
dedup := map[string]bool{} // for dedup by address
|
||||||
// for dedup by address
|
|
||||||
for _, info := range rpcInfos {
|
|
||||||
ai := cliutil.ParseApiInfo(info.Apis.ChainApiInfo[0])
|
|
||||||
apiInfos[ai.Addr] = ai.Token
|
|
||||||
}
|
|
||||||
|
|
||||||
infos := map[string]rpcInfo{} // api address -> rpc info
|
infos := map[string]rpcInfo{} // api address -> rpc info
|
||||||
var infosLk sync.Mutex
|
var infosLk sync.Mutex
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(len(rpcInfos))
|
for _, info := range rpcInfos {
|
||||||
for addr, token := range apiInfos {
|
ai := cliutil.ParseApiInfo(info.Apis.ChainApiInfo[0])
|
||||||
addr := addr
|
if dedup[ai.Addr] {
|
||||||
ai := cliutil.APIInfo{
|
continue
|
||||||
Addr: addr,
|
|
||||||
Token: token,
|
|
||||||
}
|
}
|
||||||
go func(info string) {
|
dedup[ai.Addr] = true
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
var clayers []string
|
var clayers []string
|
||||||
for layer, a := range confNameToAddr {
|
for layer, a := range confNameToAddr {
|
||||||
if a == addr {
|
if a == ai.Addr {
|
||||||
clayers = append(clayers, layer)
|
clayers = append(clayers, layer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,8 +108,8 @@ func (d *debug) chainStateSSE(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
infosLk.Lock()
|
infosLk.Lock()
|
||||||
|
defer infosLk.Unlock()
|
||||||
infos[ai.Addr] = myinfo
|
infos[ai.Addr] = myinfo
|
||||||
infosLk.Unlock()
|
|
||||||
}()
|
}()
|
||||||
da, err := ai.DialArgs("v1")
|
da, err := ai.DialArgs("v1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -126,7 +121,7 @@ func (d *debug) chainStateSSE(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
v1api, closer, err := client.NewFullNodeRPCV1(ctx, da, ah)
|
v1api, closer, err := client.NewFullNodeRPCV1(ctx, da, ah)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("Not able to establish connection to node with addr: %s", addr)
|
log.Warnf("Not able to establish connection to node with addr: %s", ai.Addr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer closer()
|
defer closer()
|
||||||
@ -160,7 +155,7 @@ func (d *debug) chainStateSSE(w http.ResponseWriter, r *http.Request) {
|
|||||||
Version: ver.Version,
|
Version: ver.Version,
|
||||||
SyncState: syncState,
|
SyncState: syncState,
|
||||||
}
|
}
|
||||||
}(addr)
|
}()
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
|
@ -15,9 +15,7 @@ import (
|
|||||||
var templateFS embed.FS
|
var templateFS embed.FS
|
||||||
|
|
||||||
func Routes(r *mux.Router, deps *deps.Deps) error {
|
func Routes(r *mux.Router, deps *deps.Deps) error {
|
||||||
|
t, err := template.ParseFS(templateFS, "web/*")
|
||||||
t := new(template.Template)
|
|
||||||
t, err := t.ParseFS(templateFS, "web/*")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("parse templates: %w", err)
|
return xerrors.Errorf("parse templates: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,12 @@ package web
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"embed"
|
"embed"
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -19,33 +22,57 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/metrics"
|
"github.com/filecoin-project/lotus/metrics"
|
||||||
)
|
)
|
||||||
|
|
||||||
// go:embed static
|
//go:embed static
|
||||||
var static embed.FS
|
var static embed.FS
|
||||||
|
|
||||||
|
var basePath = "/static/"
|
||||||
|
|
||||||
// An dev mode hack for no-restart changes to static and templates.
|
// An dev mode hack for no-restart changes to static and templates.
|
||||||
// You still need to recomplie the binary for changes to go code.
|
// You still need to recomplie the binary for changes to go code.
|
||||||
var webDev = os.Getenv("LOTUS_WEB_DEV") == "1"
|
var webDev = os.Getenv("LOTUS_WEB_DEV") == "1"
|
||||||
|
|
||||||
func GetSrv(ctx context.Context, deps *deps.Deps) (*http.Server, error) {
|
func GetSrv(ctx context.Context, deps *deps.Deps) (*http.Server, error) {
|
||||||
mux := mux.NewRouter()
|
mx := mux.NewRouter()
|
||||||
api.Routes(mux.PathPrefix("/api").Subrouter(), deps)
|
err := hapi.Routes(mx.PathPrefix("/hapi").Subrouter(), deps)
|
||||||
err := hapi.Routes(mux.PathPrefix("/hapi").Subrouter(), deps)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
mux.NotFoundHandler = http.FileServer(http.FS(static))
|
api.Routes(mx.PathPrefix("/api").Subrouter(), deps)
|
||||||
|
|
||||||
|
basePath := basePath
|
||||||
|
|
||||||
|
var static fs.FS = static
|
||||||
if webDev {
|
if webDev {
|
||||||
mux.NotFoundHandler = http.FileServer(http.Dir("cmd/lotus-provider/web/static"))
|
basePath = "cmd/lotus-provider/web/static"
|
||||||
|
static = os.DirFS(basePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mx.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// If the request is for a directory, redirect to the index file.
|
||||||
|
if strings.HasSuffix(r.URL.Path, "/") {
|
||||||
|
r.URL.Path += "index.html"
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := static.Open(path.Join(basePath, r.URL.Path)[1:])
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusNotFound)
|
||||||
|
w.Write([]byte("404 Not Found"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
fileInfo, err := file.Stat()
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
w.Write([]byte("500 Internal Server Error"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
http.ServeContent(w, r, fileInfo.Name(), fileInfo.ModTime(), file.(io.ReadSeeker))
|
||||||
|
})
|
||||||
|
|
||||||
return &http.Server{
|
return &http.Server{
|
||||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
Handler: http.HandlerFunc(mx.ServeHTTP),
|
||||||
if strings.HasSuffix(r.URL.Path, "/") {
|
|
||||||
r.URL.Path = r.URL.Path + "index.html"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
mux.ServeHTTP(w, r)
|
|
||||||
}),
|
|
||||||
BaseContext: func(listener net.Listener) context.Context {
|
BaseContext: func(listener net.Listener) context.Context {
|
||||||
ctx, _ := tag.New(context.Background(), tag.Upsert(metrics.APIInterface, "lotus-provider"))
|
ctx, _ := tag.New(context.Background(), tag.Upsert(metrics.APIInterface, "lotus-provider"))
|
||||||
return ctx
|
return ctx
|
||||||
|
Loading…
Reference in New Issue
Block a user