Skip to content

Commit

Permalink
api,cmd,explorer: add explorer state to endpoint, fix panic in pinned…
Browse files Browse the repository at this point in the history
… settings API with explorer disabled
  • Loading branch information
n8maninger committed May 1, 2024
1 parent 99eb753 commit c47085e
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 18 deletions.
23 changes: 20 additions & 3 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package api

import (
"context"
"errors"
"net/http"
"time"

Expand All @@ -16,6 +17,7 @@ import (
"go.sia.tech/hostd/host/settings"
"go.sia.tech/hostd/host/settings/pin"
"go.sia.tech/hostd/host/storage"
"go.sia.tech/hostd/internal/explorer"
"go.sia.tech/hostd/rhp"
"go.sia.tech/hostd/wallet"
"go.sia.tech/hostd/webhooks"
Expand Down Expand Up @@ -156,20 +158,35 @@ type (
wallet Wallet
metrics MetricManager
settings Settings
pinned PinnedSettings
sessions RHPSessionReporter

explorerDisabled bool
explorer *explorer.Explorer
pinned PinnedSettings

volumeJobs volumeJobs
checks integrityCheckJobs
}
)

func (a *api) requiresExplorer(h jape.Handler) jape.Handler {
return func(ctx jape.Context) {
if a.explorerDisabled {
ctx.Error(errors.New("explorer data is disabled"), http.StatusNotFound)
return
}
h(ctx)
}
}

// NewServer initializes the API
func NewServer(name string, hostKey types.PublicKey, opts ...ServerOption) http.Handler {
a := &api{
hostKey: hostKey,
name: name,
log: zap.NewNop(),

explorerDisabled: true,
}
for _, opt := range opts {
opt(a)
Expand Down Expand Up @@ -200,8 +217,8 @@ func NewServer(name string, hostKey types.PublicKey, opts ...ServerOption) http.
"PATCH /settings": a.handlePATCHSettings,
"POST /settings/announce": a.handlePOSTAnnounce,
"PUT /settings/ddns/update": a.handlePUTDDNSUpdate,
"GET /settings/pinned": a.handleGETPinnedSettings,
"PUT /settings/pinned": a.handlePUTPinnedSettings,
"GET /settings/pinned": a.requiresExplorer(a.handleGETPinnedSettings),
"PUT /settings/pinned": a.requiresExplorer(a.handlePUTPinnedSettings),
// metrics endpoints
"GET /metrics": a.handleGETMetrics,
"GET /metrics/:period": a.handleGETPeriodMetrics,
Expand Down
18 changes: 9 additions & 9 deletions api/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,21 @@ func (a *api) handleGETHostState(c jape.Context) {
return
}

var baseURL string
if a.explorer != nil {
baseURL = a.explorer.BaseURL()
}

a.writeResponse(c, HostState{
Name: a.name,
PublicKey: a.hostKey,
WalletAddress: a.wallet.Address(),
StartTime: startTime,
LastAnnouncement: announcement,
Explorer: ExplorerState{
Enabled: !a.explorerDisabled,
URL: baseURL,
},
BuildState: BuildState{
Network: build.NetworkName(),
Version: build.Version(),
Expand Down Expand Up @@ -201,19 +210,10 @@ func (a *api) handlePATCHSettings(c jape.Context) {
}

func (a *api) handleGETPinnedSettings(c jape.Context) {
if a.pinned == nil {
c.Error(errors.New("pinned settings disabled"), http.StatusNotFound)
return
}
c.Encode(a.pinned.Pinned(c.Request.Context()))
}

func (a *api) handlePUTPinnedSettings(c jape.Context) {
if a.pinned == nil {
c.Error(errors.New("pinned settings disabled"), http.StatusNotFound)
return
}

var req pin.PinnedSettings
if err := c.Decode(&req); err != nil {
return
Expand Down
13 changes: 12 additions & 1 deletion api/options.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package api

import "go.uber.org/zap"
import (
"go.sia.tech/hostd/internal/explorer"
"go.uber.org/zap"
)

// ServerOption is a functional option to configure an API server.
type ServerOption func(*api)
Expand Down Expand Up @@ -75,6 +78,14 @@ func ServerWithPinnedSettings(p PinnedSettings) ServerOption {
}
}

// ServerWithExplorer sets the explorer for the API server.
func ServerWithExplorer(explorer *explorer.Explorer) ServerOption {
return func(a *api) {
a.explorerDisabled = false
a.explorer = explorer
}
}

// ServerWithSettings sets the settings manager for the API server.
func ServerWithSettings(s Settings) ServerOption {
return func(a *api) {
Expand Down
7 changes: 7 additions & 0 deletions api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,20 @@ type (
BuildTime time.Time `json:"buildTime"`
}

// ExplorerState contains static information about explorer data sources.
ExplorerState struct {
Enabled bool `json:"enabled"`
URL string `json:"url"`
}

// HostState is the response body for the [GET] /state/host endpoint.
HostState struct {
Name string `json:"name,omitempty"`
PublicKey types.PublicKey `json:"publicKey"`
LastAnnouncement settings.Announcement `json:"lastAnnouncement"`
WalletAddress types.Address `json:"walletAddress"`
StartTime time.Time `json:"startTime"`
Explorer ExplorerState `json:"explorer"`
BuildState
}

Expand Down
20 changes: 18 additions & 2 deletions cmd/hostd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"go.sia.tech/hostd/api"
"go.sia.tech/hostd/build"
"go.sia.tech/hostd/config"
"go.sia.tech/hostd/internal/explorer"
"go.sia.tech/jape"
"go.sia.tech/web/hostd"
"go.uber.org/zap"
Expand Down Expand Up @@ -358,7 +359,18 @@ func main() {
}
defer rhp3WSListener.Close()

node, hostKey, err := newNode(ctx, walletKey, log)
var ex *explorer.Explorer
if !cfg.Explorer.Disable {
ex = explorer.New(cfg.Explorer.URL)
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()

if _, err := ex.SiacoinExchangeRate(ctx, "usd"); err != nil {
log.Fatal("failed to get exchange rate", zap.Error(err))
}
}

node, hostKey, err := newNode(ctx, walletKey, ex, log)
if err != nil {
log.Fatal("failed to create node", zap.Error(err))
}
Expand All @@ -378,7 +390,11 @@ func main() {
api.ServerWithSettings(node.settings),
api.ServerWithWallet(node.w),
api.ServerWithLogger(log.Named("api")),
api.ServerWithPinnedSettings(node.pinned),
}

if !cfg.Explorer.Disable {
opts = append(opts, api.ServerWithExplorer(ex))
opts = append(opts, api.ServerWithPinnedSettings(node.pinned))
}

auth := jape.BasicAuth(cfg.HTTP.Password)
Expand Down
4 changes: 1 addition & 3 deletions cmd/hostd/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func startRHP3(l net.Listener, hostKey types.PrivateKey, cs rhp3.ChainManager, t
return rhp3, nil
}

func newNode(ctx context.Context, walletKey types.PrivateKey, logger *zap.Logger) (*node, types.PrivateKey, error) {
func newNode(ctx context.Context, walletKey types.PrivateKey, ex *explorer.Explorer, logger *zap.Logger) (*node, types.PrivateKey, error) {
gatewayDir := filepath.Join(cfg.Directory, "gateway")
if err := os.MkdirAll(gatewayDir, 0700); err != nil {
return nil, types.PrivateKey{}, fmt.Errorf("failed to create gateway dir: %w", err)
Expand Down Expand Up @@ -186,8 +186,6 @@ func newNode(ctx context.Context, walletKey types.PrivateKey, logger *zap.Logger

var pm *pin.Manager
if !cfg.Explorer.Disable {
ex := explorer.New(cfg.Explorer.URL)

pm, err = pin.NewManager(
pin.WithStore(db),
pin.WithSettings(sr),
Expand Down
5 changes: 5 additions & 0 deletions internal/explorer/explorer.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ func makeRequest(ctx context.Context, method, url string, requestBody, response
return nil
}

// BaseURL returns the base URL of the Explorer.
func (e *Explorer) BaseURL() string {
return e.url
}

// SiacoinExchangeRate returns the exchange rate for the given currency.
func (e *Explorer) SiacoinExchangeRate(ctx context.Context, currency string) (rate float64, err error) {
err = makeRequest(ctx, http.MethodGet, fmt.Sprintf("%s/exchange-rate/siacoin/%s", e.url, currency), nil, &rate)
Expand Down

0 comments on commit c47085e

Please sign in to comment.