Files
remark42/backend/app/main.go
T
Dmitry VerkhoturovandGitHub ba7c3aed94 refactor: modernise Go code with go fix and manual improvements (#2027)
Apply go fix ./... analysers (Go 1.26) across backend and examples:
- interface{} → any (type alias, no behaviour change)
- for i := 0; i < N; i++ → for range N / for i := range N
- slices.Contains / slices.ContainsFunc replacing manual loops
- strings.SplitSeq replacing strings.Split in range (avoids allocation)
- strings.CutPrefix replacing HasPrefix+TrimPrefix
- min() replacing manual if/else
- fmt.Appendf replacing []byte(fmt.Sprintf(...))
- strings.Builder replacing string += concatenation
- wg.Go(func(){}) replacing wg.Add(1)/go/wg.Done() pattern
- removed redundant ii := i loop variable copies (unnecessary since Go 1.22)

omitempty on struct-typed JSON fields: go fix removed omitempty from
struct-typed fields (time.Time, PostInfo, UserDetailEntry) because
encoding/json's omitempty never applied to struct types — it was always
a no-op. Kept as bare tags (no omitzero replacement) to preserve the
existing serialisation behaviour.
2026-03-25 16:42:37 -05:00

110 lines
3.2 KiB
Go

package main
import (
"errors"
"fmt"
"os"
"os/signal"
"runtime"
"syscall"
log "github.com/go-pkgz/lgr"
"github.com/jessevdk/go-flags"
"github.com/umputun/remark42/backend/app/cmd"
)
// Opts with all cli commands and flags
type Opts struct {
ServerCmd cmd.ServerCommand `command:"server"`
ImportCmd cmd.ImportCommand `command:"import"`
BackupCmd cmd.BackupCommand `command:"backup"`
RestoreCmd cmd.RestoreCommand `command:"restore"`
AvatarCmd cmd.AvatarCommand `command:"avatar"`
CleanupCmd cmd.CleanupCommand `command:"cleanup"`
RemapCmd cmd.RemapCommand `command:"remap"`
RemarkURL string `long:"url" env:"REMARK_URL" required:"true" description:"url to remark"`
// SharedSecret is only used in server command, but defined for all commands for historical reasons
SharedSecret string `long:"secret" env:"SECRET" required:"true" description:"the shared secret key used to sign JWT, should be a random, long, hard-to-guess string"`
Dbg bool `long:"dbg" env:"DEBUG" description:"debug mode"`
}
var revision = "unknown"
func main() {
fmt.Printf("remark42 %s\n", revision)
var opts Opts
p := flags.NewParser(&opts, flags.Default)
p.CommandHandler = func(command flags.Commander, args []string) error {
setupLog(opts.Dbg)
// commands implements CommonOptionsCommander to allow passing set of extra options defined for all commands
c := command.(cmd.CommonOptionsCommander)
c.SetCommon(cmd.CommonOpts{
RemarkURL: opts.RemarkURL,
SharedSecret: opts.SharedSecret,
Revision: revision,
})
logDeprecatedParams(c.HandleDeprecatedFlags())
err := c.Execute(args)
if err != nil {
log.Printf("[ERROR] failed with %+v", err)
}
return err
}
if _, err := p.Parse(); err != nil {
var flagsErr *flags.Error
if errors.As(err, &flagsErr) && flagsErr.Type == flags.ErrHelp {
os.Exit(0)
}
os.Exit(1)
}
}
func setupLog(dbg bool) {
if dbg {
log.Setup(log.Debug, log.CallerFile, log.CallerFunc, log.Msec, log.LevelBraces)
return
}
log.Setup(log.Msec, log.LevelBraces)
}
// logs usual and "collision" deprecated parameters
func logDeprecatedParams(params []cmd.DeprecatedFlag) {
for _, entry := range params {
var deprecationNote string
if entry.Collision {
deprecationNote = fmt.Sprintf("[ERROR] deprecated --%s and new --%s options are set to different values, old one is ignored: please remove it", entry.Old, entry.New)
} else {
deprecationNote = fmt.Sprintf("[WARN] --%s is deprecated since v%s and will be removed in the future", entry.Old, entry.Version)
if entry.New != "" {
deprecationNote += fmt.Sprintf(", please use --%s instead", entry.New)
}
}
log.Print(deprecationNote)
}
}
// getDump reads runtime stack and returns as a string
func getDump() string {
maxSize := 5 * 1024 * 1024
stacktrace := make([]byte, maxSize)
length := min(runtime.Stack(stacktrace, true), maxSize)
return string(stacktrace[:length])
}
//nolint:gochecknoinits // can't avoid it in this place
func init() {
// catch SIGQUIT and print stack traces
sigChan := make(chan os.Signal, 1)
go func() {
for range sigChan {
log.Printf("[INFO] SIGQUIT detected, dump:\n%s", getDump())
}
}()
signal.Notify(sigChan, syscall.SIGQUIT)
}