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
|
package certstream
// The certstream package provides the main entry point for the certstream-server-go application.
// It initializes the webserver and the watcher for the certificate transparency logs.
// It also handles signals for graceful shutdown of the server.
import (
"log"
"os"
"os/signal"
"syscall"
"github.com/d-Rickyy-b/certstream-server-go/internal/certificatetransparency"
"github.com/d-Rickyy-b/certstream-server-go/internal/config"
"github.com/d-Rickyy-b/certstream-server-go/internal/metrics"
"github.com/d-Rickyy-b/certstream-server-go/internal/web"
)
type Certstream struct {
webserver *web.WebServer
metricsServer *web.WebServer
watcher *certificatetransparency.Watcher
config config.Config
}
// NewCertstreamServer creates a new Certstream server from a config struct.
func NewCertstreamServer(config config.Config) (*Certstream, error) {
cs := Certstream{}
cs.config = config
// Initialize the webserver used for the websocket server
webserver := web.NewWebsocketServer(config.Webserver.ListenAddr, config.Webserver.ListenPort, config.Webserver.CertPath, config.Webserver.CertKeyPath)
cs.webserver = webserver
// Setup metrics server
cs.setupMetrics(webserver)
return &cs, nil
}
// NewCertstreamFromConfigFile creates a new Certstream server from a config file.
func NewCertstreamFromConfigFile(configPath string) (*Certstream, error) {
conf, err := config.ReadConfig(configPath)
if err != nil {
return nil, err
}
return NewCertstreamServer(conf)
}
// setupMetrics configures the webserver to handle prometheus metrics according to the config.
func (cs *Certstream) setupMetrics(webserver *web.WebServer) {
if cs.config.Prometheus.Enabled {
// If prometheus is enabled, and interface is either unconfigured or same as webserver config, use existing webserver
if (cs.config.Prometheus.ListenAddr == "" || cs.config.Prometheus.ListenAddr == cs.config.Webserver.ListenAddr) &&
(cs.config.Prometheus.ListenPort == 0 || cs.config.Prometheus.ListenPort == cs.config.Webserver.ListenPort) {
log.Println("Starting prometheus server on same interface as webserver")
webserver.RegisterPrometheus(cs.config.Prometheus.MetricsURL, metrics.WritePrometheus)
} else {
log.Println("Starting prometheus server on new interface")
cs.metricsServer = web.NewMetricsServer(cs.config.Prometheus.ListenAddr, cs.config.Prometheus.ListenPort, cs.config.Prometheus.CertPath, cs.config.Prometheus.CertKeyPath)
cs.metricsServer.RegisterPrometheus(cs.config.Prometheus.MetricsURL, metrics.WritePrometheus)
}
}
}
// Start starts the webserver and the watcher.
// This is a blocking function that will run until the server is stopped.
func (cs *Certstream) Start() {
log.Printf("Starting certstream-server-go v%s\n", config.Version)
// handle signals in a separate goroutine
signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
go signalHandler(signals, cs.Stop)
// If there is no watcher initialized, create a new one
if cs.watcher == nil {
cs.watcher = &certificatetransparency.Watcher{}
}
// Start webserver and metrics server
if cs.webserver == nil {
log.Fatalln("Webserver not initialized! Exiting...")
}
go cs.webserver.Start()
if cs.metricsServer != nil {
go cs.metricsServer.Start()
}
// Start the watcher - this is a blocking function
cs.watcher.Start()
}
// Stop stops the watcher and the webserver.
func (cs *Certstream) Stop() {
if cs.watcher != nil {
cs.watcher.Stop()
}
if cs.webserver != nil {
cs.webserver.Stop()
}
if cs.metricsServer != nil {
cs.metricsServer.Stop()
}
}
// signalHandler listens for signals in order to gracefully shut down the server.
// Executes the callback function when a signal is received.
func signalHandler(signals chan os.Signal, callback func()) {
log.Println("Listening for signals...")
sig := <-signals
log.Printf("Received signal %v. Shutting down...\n", sig)
callback()
os.Exit(0)
}
|