Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SQLite3 backup #463

Merged
merged 10 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ type (
BroadcastV2TransactionSet(index types.ChainIndex, txns []types.V2Transaction)
}

// The SQLite3Store provides an interface for backing up a SQLite3 database
SQLite3Store interface {
Backup(ctx context.Context, destPath string) error
}

// A ChainManager retrieves the current blockchain state
ChainManager interface {
Tip() types.ChainIndex
Expand Down Expand Up @@ -164,6 +169,8 @@ type (
webhooks Webhooks
sessions RHPSessionReporter

sqlite3Store SQLite3Store

syncer Syncer
chain ChainManager
accounts AccountManager
Expand Down Expand Up @@ -294,8 +301,9 @@ func NewServer(name string, hostKey types.PublicKey, cm ChainManager, s Syncer,
"GET /wallet/pending": a.handleGETWalletPending,
"POST /wallet/send": a.handlePOSTWalletSend,
// system endpoints
"GET /system/dir": a.handleGETSystemDir,
"PUT /system/dir": a.handlePUTSystemDir,
"GET /system/dir": a.handleGETSystemDir,
"PUT /system/dir": a.handlePUTSystemDir,
"POST /system/sqlite3/backup": a.handlePOSTSystemSQLite3Backup,
// webhook endpoints
"GET /webhooks": a.handleGETWebhooks,
"POST /webhooks": a.handlePOSTWebhooks,
Expand Down
6 changes: 6 additions & 0 deletions api/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,12 @@ func (c *Client) LocalDir(path string) (resp SystemDirResponse, err error) {
return
}

// BackupSQLite3 creates a backup of the SQLite3 database at the specified path
// on the local filesystem.
func (c *Client) BackupSQLite3(destPath string) error {
return c.c.POST("/system/sqlite3/backup", BackupRequest{destPath}, nil)
}

// MkDir creates a new directory on the host.
func (c *Client) MkDir(path string) error {
req := CreateDirRequest{
Expand Down
14 changes: 14 additions & 0 deletions api/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ func (a *api) handleGETPeriodMetrics(jc jape.Context) {
return
} else if start.After(time.Now()) {
jc.Error(errors.New("start time cannot be in the future"), http.StatusBadRequest)
return
}

start, err := metrics.Normalize(start, interval)
Expand Down Expand Up @@ -579,6 +580,19 @@ func (a *api) handlePUTSystemDir(jc jape.Context) {
a.checkServerError(jc, "failed to create dir", os.MkdirAll(req.Path, 0775))
}

func (a *api) handlePOSTSystemSQLite3Backup(jc jape.Context) {
if a.sqlite3Store == nil {
jc.Error(errors.New("sqlite3 store not available"), http.StatusNotFound)
n8maninger marked this conversation as resolved.
Show resolved Hide resolved
return
}

var req BackupRequest
if err := jc.Decode(&req); err != nil {
return
}
a.checkServerError(jc, "failed to backup", a.sqlite3Store.Backup(jc.Request.Context(), req.Path))
}

func (a *api) handleGETTPoolFee(jc jape.Context) {
a.writeResponse(jc, TPoolResp(a.chain.RecommendedFee()))
}
Expand Down
34 changes: 22 additions & 12 deletions api/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,44 +12,54 @@ import (
// ServerOption is a functional option to configure an API server.
type ServerOption func(*api)

// ServerWithAlerts sets the alerts manager for the API server.
func ServerWithAlerts(al Alerts) ServerOption {
// WithAlerts sets the alerts manager for the API server.
func WithAlerts(al Alerts) ServerOption {
return func(a *api) {
a.alerts = al
}
}

// ServerWithWebhooks sets the webhooks manager for the API server.
func ServerWithWebhooks(w Webhooks) ServerOption {
// WithSQLite3Store sets the SQLite3 store for the API server.
//
// This option is not required since it is only used for backups and there
// may be other stores in the future.
func WithSQLite3Store(s SQLite3Store) ServerOption {
return func(a *api) {
a.sqlite3Store = s
}
}

// WithWebhooks sets the webhooks manager for the API server.
func WithWebhooks(w Webhooks) ServerOption {
return func(a *api) {
a.webhooks = w
}
}

// ServerWithPinnedSettings sets the pinned settings for the API server.
func ServerWithPinnedSettings(p PinnedSettings) ServerOption {
// WithPinnedSettings sets the pinned settings for the API server.
func WithPinnedSettings(p PinnedSettings) ServerOption {
return func(a *api) {
a.pinned = p
}
}

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

// ServerWithRHPSessionReporter sets the RHP session reporter for the API server.
func ServerWithRHPSessionReporter(rsr RHPSessionReporter) ServerOption {
// WithRHPSessionReporter sets the RHP session reporter for the API server.
func WithRHPSessionReporter(rsr RHPSessionReporter) ServerOption {
return func(a *api) {
a.sessions = rsr
}
}

// ServerWithLogger sets the logger for the API server.
func ServerWithLogger(log *zap.Logger) ServerOption {
// WithLogger sets the logger for the API server.
func WithLogger(log *zap.Logger) ServerOption {
return func(a *api) {
a.log = log
}
Expand Down
5 changes: 5 additions & 0 deletions api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,11 @@ type (
Path string `json:"path"`
}

// A BackupRequest is the request body for the [POST] /system/backup endpoint.
BackupRequest struct {
Path string `json:"path"`
}

// VerifySectorResponse is the response body for the [GET] /sectors/:root/verify endpoint.
VerifySectorResponse struct {
storage.SectorReference
Expand Down
2 changes: 1 addition & 1 deletion cmd/hostd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ func setDataDirectory() {
cfg.Directory = readInput("Enter data directory")
}

func buildConfig() {
func runConfigCmd() {
// write the config file
configPath := "hostd.yml"
if str := os.Getenv(configFileEnvVar); str != "" {
Expand Down
Loading
Loading