173 lines
4.5 KiB
Go
173 lines
4.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
"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"
|
|
"git.dotya.ml/mirre-mt/pcmt/slogging"
|
|
)
|
|
|
|
const (
|
|
banner = `
|
|
██████╗ ██████╗███╗ ███╗████████╗
|
|
██╔══██╗██╔════╝████╗ ████║╚══██╔══╝
|
|
██████╔╝██║ ██╔████╔██║ ██║
|
|
██╔═══╝ ██║ ██║╚██╔╝██║ ██║
|
|
██║ ╚██████╗██║ ╚═╝ ██║ ██║
|
|
╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝
|
|
`
|
|
slug = `Password Compromise Monitoring Tool
|
|
https://git.dotya.ml/mirre-mt/pcmt
|
|
____________________________________
|
|
`
|
|
|
|
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 (
|
|
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")
|
|
version = "dev"
|
|
log *slogging.Logger
|
|
|
|
ErrCouldNotInitialiseLogger = errors.New("Could not initialise logger")
|
|
)
|
|
|
|
func run() error {
|
|
printHeader()
|
|
|
|
flag.Parse()
|
|
|
|
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 {
|
|
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"
|
|
|
|
log.Infof("connecting to db at '%s'", connstr)
|
|
|
|
db, err := ent.Open("sqlite3", connstr)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to open a connection to sqlite: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
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{}
|
|
|
|
err = a.Init(version, log, conf, db)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
a.PrintConfiguration()
|
|
|
|
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()
|
|
go func() {
|
|
if err = e.Start(*addr); err != nil && err != http.ErrServerClosed {
|
|
log.Info("shutting down the server")
|
|
}
|
|
}()
|
|
|
|
quit := make(chan os.Signal, 1)
|
|
|
|
signal.Notify(quit, os.Interrupt)
|
|
signal.Notify(quit, syscall.SIGTERM)
|
|
signal.Notify(quit, syscall.SIGHUP)
|
|
<-quit
|
|
|
|
shutdownTimeout := 10 * time.Second
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
|
|
defer func() {
|
|
log.Infof("Interrupt received, gracefully shutting down the server (timeout %s)", shutdownTimeout)
|
|
cancel()
|
|
log.Info("Bye!")
|
|
}()
|
|
|
|
if err = e.Shutdown(ctx); err != nil {
|
|
log.Error("There was an error shutting the server down")
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func printHeader() {
|
|
fmt.Fprintf(os.Stderr,
|
|
"%s\n\n\033[34m%s%s\033[0m\n\n\n",
|
|
licenseHeader,
|
|
banner,
|
|
slug,
|
|
)
|
|
}
|