forked from decred/vspd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvspd.go
131 lines (111 loc) · 4.18 KB
/
vspd.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright (c) 2020 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package main
import (
"context"
"errors"
"fmt"
"os"
"runtime"
"sync"
"github.com/decred/vspd/background"
"github.com/decred/vspd/database"
"github.com/decred/vspd/rpc"
"github.com/decred/vspd/version"
"github.com/decred/vspd/webapi"
)
// maxVoteChangeRecords defines how many vote change records will be stored for
// each ticket. The limit is in place to mitigate DoS attacks on server storage
// space. When storing a new record breaches this limit, the oldest record in
// the database is deleted.
const maxVoteChangeRecords = 10
func main() {
// Create a context that is cancelled when a shutdown request is received
// through an interrupt signal.
ctx := withShutdownCancel(context.Background())
go shutdownListener()
// Run until error is returned, or shutdown is requested.
if err := run(ctx); err != nil && !errors.Is(err, context.Canceled) {
os.Exit(1)
}
}
// run is the main startup and teardown logic performed by the main package. It
// is responsible for parsing the config, creating a dcrwallet RPC client,
// opening the database, starting the webserver, and stopping all started
// services when the context is cancelled.
func run(ctx context.Context) error {
// Load config file and parse CLI args.
cfg, err := loadConfig()
if err != nil {
// Don't use logger here because it may not be initialized.
fmt.Fprintf(os.Stderr, "Config error: %v\n", err)
return err
}
// Show version at startup.
log.Infof("Version %s (Go version %s %s/%s)", version.String(), runtime.Version(),
runtime.GOOS, runtime.GOARCH)
if cfg.VspClosed {
log.Warnf("Config --vspclosed is set. This will prevent vspd from " +
"accepting new tickets.")
}
// WaitGroup for services to signal when they have shutdown cleanly.
var shutdownWg sync.WaitGroup
defer log.Info("Shutdown complete")
// Open database.
db, err := database.Open(ctx, &shutdownWg, cfg.dbPath, cfg.BackupInterval, maxVoteChangeRecords)
if err != nil {
log.Errorf("Database error: %v", err)
requestShutdown()
shutdownWg.Wait()
return err
}
defer db.Close()
// Create RPC client for local dcrd instance (used for broadcasting and
// checking the status of fee transactions).
dcrd := rpc.SetupDcrd(cfg.DcrdUser, cfg.DcrdPass, cfg.DcrdHost, cfg.dcrdCert, nil)
defer dcrd.Close()
// Create RPC client for remote dcrwallet instance (used for voting).
wallets := rpc.SetupWallet(cfg.walletUsers, cfg.walletPasswords, cfg.walletHosts, cfg.walletCerts)
defer wallets.Close()
// Ensure all data in database is present and up-to-date.
err = db.CheckIntegrity(ctx, cfg.netParams.Params, dcrd)
if err != nil {
// vspd should still start if this fails, so just log an error.
log.Errorf("Could not check database integrity: %v", err)
}
// Create and start webapi server.
apiCfg := webapi.Config{
VSPFee: cfg.VSPFee,
NetParams: cfg.netParams.Params,
BlockExplorerURL: cfg.netParams.BlockExplorerURL,
SupportEmail: cfg.SupportEmail,
VspClosed: cfg.VspClosed,
VspClosedMsg: cfg.VspClosedMsg,
AdminPass: cfg.AdminPass,
Debug: cfg.WebServerDebug,
Designation: cfg.Designation,
MaxVoteChangeRecords: maxVoteChangeRecords,
VspdVersion: version.String(),
}
err = webapi.Start(ctx, requestShutdown, &shutdownWg, cfg.Listen, db,
dcrd, wallets, apiCfg)
if err != nil {
log.Errorf("Failed to initialize webapi: %v", err)
requestShutdown()
shutdownWg.Wait()
return err
}
// Create a dcrd client with a blockconnected notification handler.
notifHandler := background.NotificationHandler{ShutdownWg: &shutdownWg}
dcrdWithNotifs := rpc.SetupDcrd(cfg.DcrdUser, cfg.DcrdPass,
cfg.DcrdHost, cfg.dcrdCert, ¬ifHandler)
defer dcrdWithNotifs.Close()
// Start background process which will continually attempt to reconnect to
// dcrd if the connection drops.
background.Start(ctx, &shutdownWg, db, dcrd, dcrdWithNotifs, wallets, cfg.netParams.Params)
// Wait for shutdown tasks to complete before running deferred tasks and
// returning.
shutdownWg.Wait()
return ctx.Err()
}