pcmt/run.go

177 lines
4.6 KiB
Go
Raw Normal View History

package main
import (
2023-03-22 22:56:25 +01:00
"context"
2023-04-19 05:30:52 +02:00
"errors"
"flag"
"fmt"
"net/http"
2023-03-22 22:56:25 +01:00
"os"
"os/signal"
"syscall"
2023-03-22 22:56:25 +01:00
"time"
// ent pure go sqlite3 driver instead of "github.com/mattn/go-sqlite3".
_ "github.com/xiaoqidun/entps"
"git.dotya.ml/mirre-mt/pcmt/app"
"git.dotya.ml/mirre-mt/pcmt/config"
"git.dotya.ml/mirre-mt/pcmt/ent"
2023-04-19 05:30:52 +02:00
"git.dotya.ml/mirre-mt/pcmt/slogging"
)
const (
2023-04-19 21:22:00 +02:00
banner = `
`
slug = `Password Compromise Monitoring Tool
https://git.dotya.ml/mirre-mt/pcmt
2023-04-19 23:36:12 +02:00
____________________________________`
licenseHeader = `pcmt - Password Compromise Monitoring Tool
Copyright (C) git.dotya.ml/wanderer
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation version 3 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.`
)
var (
2023-04-19 21:41:51 +02:00
addr = flag.String("addr", ":3000", "TCP address:port to listen at")
configFlag = flag.String("config", "config.dhall", "Default path of the config file")
devel = flag.Bool("devel", false, "Run the application in dev mode, connect to a local browser-sync instance for hot-reloading")
2023-04-19 23:36:12 +02:00
license = flag.Bool("license", false, "Print licensing information and exit")
2023-04-19 21:41:51 +02:00
version = "dev"
log *slogging.Logger
2023-04-19 05:30:52 +02:00
ErrCouldNotInitialiseLogger = errors.New("Could not initialise logger")
)
func run() error {
flag.Parse()
2023-04-19 23:36:12 +02:00
if *license {
fmt.Fprintln(os.Stderr, licenseHeader)
os.Exit(0)
}
printHeader()
2023-04-19 05:30:52 +02:00
err := slogging.Init(true)
if err != nil {
return ErrCouldNotInitialiseLogger
}
log = slogging.GetLogger()
// TODO: allow different configuration formats (toml, ni)
// TODO: rename main.go to pcmt.go
// TODO: add .golangci-lint
// TODO: add flake.nix
// TODO: connect to postgres
// TODO: design user schemas, models.
// TODO: SBOM: https://actuated.dev/blog/sbom-in-github-actions
// TODO: SBOM: https://www.docker.com/blog/generate-sboms-with-buildkit/
conf, err := config.LoadConfig(*configFlag)
if err != nil {
2023-04-19 05:30:52 +02:00
log.Errorf("error loading config file at '%s', bailing", *configFlag)
return err
}
// for "github.com/xiaoqidun/entps".
connstr := "file:ent?mode=memory&cache=shared&_fk=1"
2023-04-19 21:41:51 +02:00
2023-04-19 05:30:52 +02:00
log.Infof("connecting to db at '%s'", connstr)
2023-04-19 21:41:51 +02:00
db, err := ent.Open("sqlite3", connstr)
if err != nil {
return fmt.Errorf("failed to open a connection to sqlite: %v", err)
}
defer db.Close()
2023-04-19 05:30:52 +02:00
log.Info("attempting to automatically migrate db schema")
// Run the auto migration tool.
if err = db.Schema.Create(context.Background()); err != nil {
return fmt.Errorf("failed creating schema resources: %v", err)
}
a := &app.App{}
2023-04-19 05:30:52 +02:00
err = a.Init(version, log, conf, db)
if err != nil {
return err
}
a.PrintConfiguration()
2023-03-22 23:03:21 +01:00
a.SetupRoutes()
a.SetEchoSettings()
// a.SetConfig(conf)
a.SetEmbeds(templates, assets)
if *devel {
a.SetDevel()
}
// // TODO: add check for prometheus config setting.
// if true {
// // import "github.com/labstack/echo-contrib/prometheus"
// p := prometheus.NewPrometheus("echo", nil)
// p.Use(e)
// }
e := a.E()
2023-03-22 22:56:25 +01:00
go func() {
if err = e.Start(*addr); err != nil && err != http.ErrServerClosed {
2023-04-19 05:30:52 +02:00
log.Info("shutting down the server")
2023-03-22 22:56:25 +01:00
}
}()
quit := make(chan os.Signal, 1)
signal.Notify(quit, os.Interrupt)
signal.Notify(quit, syscall.SIGTERM)
signal.Notify(quit, syscall.SIGHUP)
2023-03-22 22:56:25 +01:00
<-quit
2023-04-19 05:30:52 +02:00
shutdownTimeout := 10 * time.Second
2023-04-19 21:41:51 +02:00
2023-04-19 05:30:52 +02:00
ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
2023-03-22 22:56:25 +01:00
defer func() {
2023-04-19 05:30:52 +02:00
log.Infof("Interrupt received, gracefully shutting down the server (timeout %s)", shutdownTimeout)
2023-03-22 22:56:25 +01:00
cancel()
2023-04-19 05:30:52 +02:00
log.Info("Bye!")
2023-03-22 22:56:25 +01:00
}()
if err = e.Shutdown(ctx); err != nil {
2023-04-19 05:30:52 +02:00
log.Error("There was an error shutting the server down")
return err
}
return nil
}
func printHeader() {
2023-04-19 21:22:00 +02:00
fmt.Fprintf(os.Stderr,
2023-04-19 23:36:12 +02:00
"\033[34m%s%s\033[0m\n\n\n",
2023-04-19 21:22:00 +02:00
banner,
slug,
)
}